diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index aa0b2b96c4e..b953e5fc9db 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,8 +10,7 @@ Include the following checklist in your PR: * [ ] Any changes that could be relevant to users [have been recorded in the changelog](https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#changelog). * [ ] The documentation has been updated, if necessary. * [ ] [Manual QA notes](https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#qa-notes) have been included. - -Bonus points for added automated tests! +* [ ] Tests have been added. (*Ask for help if you don’t know how to write them! Ask for an exemption if tests are too complex for too little coverage!*) --- @@ -20,4 +19,5 @@ Bonus points for added automated tests! Include the following checklist in your PR: * [ ] Patches conform to the [coding conventions](https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#other-conventions). +* [ ] Is this a PR that fixes CI? If so, it will need to be backported to older cabal release branches (ask maintainers for directions). diff --git a/.github/workflows/bootstrap.skip.yml b/.github/workflows/bootstrap.skip.yml new file mode 100644 index 00000000000..3a47870b533 --- /dev/null +++ b/.github/workflows/bootstrap.skip.yml @@ -0,0 +1,39 @@ +name: Bootstrap Skip + +# This Workflow is special and contains a workaround for a known limitation of GitHub CI. +# +# The problem: We don't want to run the "bootstrap" jobs on PRs which contain only changes +# to the docs, since these jobs take a long time to complete without providing any benefit. +# We therefore use path-filtering in the workflow triggers for the bootstrap jobs, namely +# "paths-ignore: doc/**". But the "Bootstrap post job" is a required job, therefore a PR cannot +# be merged unless the "Bootstrap post job" completes succesfully, which it doesn't do if we +# filter it out. +# +# The solution: We use a second job with the same name which always returns the exit code 0. +# The logic implemented for "required" workflows accepts if 1) at least one job with that name +# runs through, AND 2) If multiple jobs of that name exist, then all jobs of that name have to +# finish successfully. +on: + push: + paths: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' + branches: + - master + pull_request: + paths: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' + release: + types: + - created + +jobs: + bootstrap-post-job: + if: always() + name: Bootstrap post job + runs-on: ubuntu-latest + steps: + - run: exit 0 diff --git a/.github/workflows/bootstrap.yml b/.github/workflows/bootstrap.yml index c1734736e4c..7f101dd1b9b 100644 --- a/.github/workflows/bootstrap.yml +++ b/.github/workflows/bootstrap.yml @@ -5,11 +5,22 @@ concurrency: group: ${{ github.ref }}-${{ github.workflow }} cancel-in-progress: true +# Note: This workflow file contains the required job "Bootstrap post job". We are using path filtering +# here to ignore PRs which only change documentation. This can cause a problem, see the workflow file +# "bootstrap.skip.yml" for a description of the problem and the solution provided in that file. on: push: + paths-ignore: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' branches: - master pull_request: + paths-ignore: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' release: types: - created @@ -19,13 +30,19 @@ jobs: strategy: matrix: os: [ubuntu-latest] - ghc: ["8.10.7", "9.0.2", "9.2.7", "9.4.4"] + ghc: ["8.10.7", "9.0.2", "9.2.8", "9.4.8", "9.6.4", "9.8.1"] include: - os: macos-latest - ghc: "9.2.7" + ghc: "9.2.8" name: Bootstrap ${{ matrix.os }} ghc-${{ matrix.ghc }} runs-on: ${{ matrix.os }} steps: + - name: Work around XDG directories existence (haskell-actions/setup#62) + if: ${{ runner.os == 'macOS' }} + run: | + rm -rf ~/.config/cabal + rm -rf ~/.cache/cabal + - uses: actions/cache@v3 name: Cache the downloads id: bootstrap-cache @@ -66,3 +83,20 @@ jobs: with: name: cabal-${{ matrix.os }}-${{ matrix.ghc }}-bootstrapped path: _build/artifacts/* + + # We use this job as a summary of the workflow + # It will fail if any of the previous jobs does it + # This way we can use it exclusively in branch protection rules + # and abstract away the concrete jobs of the workflow, including their names + bootstrap-post-job: + if: always() + name: Bootstrap post job + runs-on: ubuntu-latest + # IMPORTANT! Any job added to the workflow should be added here too + needs: [bootstrap] + + steps: + - run: | + echo "jobs info: ${{ toJSON(needs) }}" + - if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: exit 1 diff --git a/.github/workflows/changelogs.yml b/.github/workflows/changelogs.yml index c0ec46a6d1b..152c4a86e6c 100644 --- a/.github/workflows/changelogs.yml +++ b/.github/workflows/changelogs.yml @@ -48,12 +48,14 @@ jobs: ghcup set ghc recommended - name: Update Hackage index run: cabal v2-update - # Cannot install it from tarball due to + # Cannot install it directly from remote tarball due to # https://github.com/haskell/cabal/issues/7360 - - uses: actions/checkout@v4 - with: - repository: "fgaz/changelog-d" - path: "changelog-d" + - name: Fetch changelog-d + run: | + changelog_d_latest="$(curl https://codeberg.org/api/v1/repos/fgaz/changelog-d/branches/master | jq -r .commit.id)" + echo "Using changelog-d revision $changelog_d_latest" + curl "https://codeberg.org/fgaz/changelog-d/archive/$changelog_d_latest.tar.gz" -o changelog-d.tar.gz + tar -xf changelog-d.tar.gz - name: Install changelog-d run: | pushd changelog-d diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 84e639e7d1c..d54310be613 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: haskell-actions/run-fourmolu@v9 + - uses: haskell-actions/run-fourmolu@v10 with: version: "0.12.0.0" pattern: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fa12e98b878..1bae4d3d71b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,10 +9,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: haskell/actions/hlint-setup@v2 + - uses: haskell-actions/hlint-setup@v2 with: version: "3.5" - - uses: haskell/actions/hlint-run@v2 + - uses: haskell-actions/hlint-run@v2 with: path: "." - fail-on: suggestion \ No newline at end of file + fail-on: suggestion diff --git a/.github/workflows/quick-jobs.yml b/.github/workflows/quick-jobs.yml index 9426ed79724..0759f911631 100644 --- a/.github/workflows/quick-jobs.yml +++ b/.github/workflows/quick-jobs.yml @@ -18,73 +18,74 @@ jobs: meta: name: Meta checks runs-on: ubuntu-latest + env: + cabal_build: >- + cabal build --builddir=dist-newstyle-meta --project-file=cabal.project.meta + gen-cabal-macros + gen-paths-module + gen-spdx + gen-spdx-exc # This job is not run in a container, any recent GHC should be fine steps: - - name: Set PATH - # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#adding-a-system-path + # SKIP installation of ghc and cabal and use the preinstalled versions. + # - name: ghcup + # run: | + # ghcup --version + # ghcup config set cache true + # ghcup install ghc recommended + # ghcup set ghc recommended + - name: Haskell versions run: | - echo "$HOME/.cabal/bin" >> $GITHUB_PATH - - uses: actions/cache@v3 - with: - path: ~/.cabal/store - key: linux-store-meta - # See https://github.com/haskell/cabal/pull/8739 - - name: Sudo chmod to permit ghcup to update its cache - run: | - if [[ "${{ runner.os }}" == "Linux" ]]; then - sudo ls -lah /usr/local/.ghcup/cache - sudo mkdir -p /usr/local/.ghcup/cache - sudo ls -lah /usr/local/.ghcup/cache - sudo chown -R $USER /usr/local/.ghcup - sudo chmod -R 777 /usr/local/.ghcup - fi - - name: ghcup - run: | - ghcup --version - ghcup config set cache true - ghcup install ghc recommended - ghcup set ghc recommended + ghc --version + cabal --version - name: Update Hackage index run: cabal v2-update - - name: Install alex - run: cabal v2-install alex --constraint='alex ==3.2.7.3' - uses: actions/checkout@v4 + - name: Generate build plan for correct cache key + run: ${{ env.cabal_build }} --dry-run + - name: Restore cached dependencies + uses: actions/cache/restore@v4 + id: cache + with: + path: ~/.local/state/cabal + key: linux-store-meta-${{ hashfiles('dist-newstyle-meta/cache/plan.json') }} + restore-keys: linux-store-meta- + - name: Build tools + run: ${{ env.cabal_build }} - name: Regenerate files run: | - make -B lexer make -B spdx make -B templates - name: Check that diff is clean run: | git status > /dev/null git diff-files -p --exit-code + - name: Cache dependencies + uses: actions/cache/save@v4 + if: always() && steps.cache.outputs.cache-hit != 'true' + with: + path: ~/.local/state/cabal + key: ${{ steps.cache.outputs.cache-primary-key }} + doctest: name: Doctest Cabal runs-on: ubuntu-latest steps: - - name: Set PATH + # It is complicated to get a proper cache key for the dependencies of a package + # (here: doctest) that we just `cabal install`. + # So, as a heuristics we update the cache once per day. + # Updating it with each run would be an alternative, but we a short of cache space, + # and this would generate too many new caches. + - name: Use date as cache key run: | - echo "$HOME/.cabal/bin" >> $GITHUB_PATH - - uses: actions/cache@v3 + echo "DATE=$(date +'%Y-%m-%d')" >> "${GITHUB_ENV}" + - name: Restore cached dependencies + uses: actions/cache/restore@v4 + id: cache with: - path: ~/.cabal/store - key: linux-store-doctest - # See https://github.com/haskell/cabal/pull/8739 - - name: Sudo chmod to permit ghcup to update its cache - run: | - if [[ "${{ runner.os }}" == "Linux" ]]; then - sudo ls -lah /usr/local/.ghcup/cache - sudo mkdir -p /usr/local/.ghcup/cache - sudo ls -lah /usr/local/.ghcup/cache - sudo chown -R $USER /usr/local/.ghcup - sudo chmod -R 777 /usr/local/.ghcup - fi - - name: ghcup - run: | - ghcup --version - ghcup config set cache true - ghcup install ghc --set recommended - ghcup install cabal --set latest + path: ~/.local/state/cabal + key: linux-store-doctest-${{ env.DATE }} + restore-keys: linux-store-doctest - name: Update Hackage index run: cabal v2-update - uses: actions/checkout@v4 @@ -92,3 +93,50 @@ jobs: run: make doctest-install - name: Doctest run: make doctest + - name: Cache dependencies + if: always() && steps.cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ~/.local/state/cabal + key: ${{ steps.cache.outputs.cache-primary-key }} + + buildinfo: + name: Check Field Syntax Reference + runs-on: ubuntu-latest + env: + cabal_build: cabal build buildinfo-reference-generator + steps: + - name: Update Hackage index + run: cabal v2-update + - uses: actions/checkout@v4 + - name: Generate build plan for correct cache key + run: ${{ env.cabal_build }} --dry-run + - name: Restore cached dependencies + uses: actions/cache/restore@v4 + id: cache + with: + path: ~/.local/state/cabal + key: linux-store-buildinfo-doc-diff-${{ hashfiles('dist-newstyle/cache/plan.json') }} + restore-keys: linux-store-buildinfo-doc-diff + - name: Build buildinfo-reference-generator + run: ${{ env.cabal_build }} + - name: Are buildinfo docs up to date? + run: make doc/buildinfo-fields-reference.rst + - name: Cache dependencies + uses: actions/cache/save@v4 + if: always() && steps.cache.outputs.cache-hit != 'true' + with: + path: ~/.local/state/cabal + key: ${{ steps.cache.outputs.cache-primary-key }} + + release-project: + name: Check Release Project + runs-on: ubuntu-latest + steps: + - name: Update Hackage Index + run: cabal v2-update + - uses: actions/checkout@v4 + - name: Check Release with Pinned Hackage + run: cabal build all --dry-run --project-file=cabal.project.release + - name: Check Release with Latest Hackage + run: cabal build all --dry-run --project-file=cabal.project.release --index-state="hackage.haskell.org HEAD" diff --git a/.github/workflows/users-guide.yml b/.github/workflows/users-guide.yml index ac6d65baedb..8047ede1031 100644 --- a/.github/workflows/users-guide.yml +++ b/.github/workflows/users-guide.yml @@ -54,7 +54,7 @@ jobs: submodules: recursive - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/validate.skip.yml b/.github/workflows/validate.skip.yml new file mode 100644 index 00000000000..af608e92d49 --- /dev/null +++ b/.github/workflows/validate.skip.yml @@ -0,0 +1,39 @@ +name: Validate Skip + +# This Workflow is special and contains a workaround for a known limitation of GitHub CI. +# +# The problem: We don't want to run the "validate" jobs on PRs which contain only changes +# to the docs, since these jobs take a long time to complete without providing any benefit. +# We therefore use path-filtering in the workflow triggers for the validate jobs, namely +# "paths-ignore: doc/**". But the "Validate post job" is a required job, therefore a PR cannot +# be merged unless the "Validate post job" completes succesfully, which it doesn't do if we +# filter it out. +# +# The solution: We use a second job with the same name which always returns the exit code 0. +# The logic implemented for "required" workflows accepts if 1) at least one job with that name +# runs through, AND 2) If multiple jobs of that name exist, then all jobs of that name have to +# finish successfully. +on: + push: + paths: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' + branches: + - master + pull_request: + paths: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' + release: + types: + - created + +jobs: + validate-post-job: + if: always() + name: Validate post job + runs-on: ubuntu-latest + steps: + - run: exit 0 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b1fc53a2352..be841c46c12 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -11,24 +11,53 @@ concurrency: group: ${{ github.ref }}-${{ github.workflow }} cancel-in-progress: true +# Note: This workflow file contains the required job "Validate post job". We are using path filtering +# here to ignore PRs which only change documentation. This can cause a problem, see the workflow file +# "validate.skip.yml" for a description of the problem and the solution provided in that file. on: push: + paths-ignore: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' branches: - master pull_request: + paths-ignore: + - 'doc/**' + - '**/README.md' + - 'CONTRIBUTING.md' release: types: - created + workflow_call: + + # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions + workflow_dispatch: + inputs: + allow-newer: + description: allow-newer line + required: true + type: string + constraints: + description: constraints line + required: true + type: string env: # We choose a stable ghc version across all os's # which will be used to do the next release - GHC_FOR_RELEASE: '9.2.7' + GHC_FOR_RELEASE: '9.2.8' # Ideally we should use the version about to be released for hackage tests and benchmarks - GHC_FOR_SOLVER_BENCHMARKS: '9.2.7' - GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.2.7' + GHC_FOR_SOLVER_BENCHMARKS: '9.2.8' + GHC_FOR_COMPLETE_HACKAGE_TESTS: '9.2.8' COMMON_FLAGS: '-j 2 -v' + # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions + ALLOWNEWER: ${{ github.event.inputs.allow-newer }} + CONSTRAINTS: ${{ github.event.inputs.constraints }} + + jobs: validate: name: Validate ${{ matrix.os }} ghc-${{ matrix.ghc }} @@ -38,7 +67,8 @@ jobs: strategy: matrix: os: ["ubuntu-latest", "macos-latest", "windows-latest"] - ghc: ["9.6.1", "9.4.4", "9.2.7", "9.0.2", "8.10.7", "8.8.4", "8.6.5", "8.4.4"] + # If you remove something from here.. then add it to the old-ghcs job. + ghc: ["9.8.1", "9.6.3", "9.4.8", "9.2.8", "9.0.2", "8.10.7", "8.8.4", "8.6.5"] exclude: # corrupts GHA cache or the fabric of reality itself, see https://github.com/haskell/cabal/issues/8356 - os: "windows-latest" @@ -55,8 +85,21 @@ jobs: steps: + - name: Work around XDG directories existence (haskell-actions/setup#62) + if: ${{ runner.os == 'macOS' }} + run: | + rm -rf ~/.config/cabal + rm -rf ~/.cache/cabal + - uses: actions/checkout@v4 + # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions + - name: Manually supplied constraints/allow-newer + if: ${{ github.event_name == 'workflow_dispatch' }} + run: | + echo 'allow-newer:' ${ALLOWNEWER} >> cabal.project.validate + echo 'constraints:' ${CONSTRAINTS} >> cabal.project.validate + # See the following link for a breakdown of the following step # https://github.com/haskell/actions/issues/7#issuecomment-745697160 - uses: actions/cache@v3 @@ -68,11 +111,11 @@ jobs: key: ${{ runner.os }}-${{ matrix.ghc }}-${{ github.sha }} restore-keys: ${{ runner.os }}-${{ matrix.ghc }}- - - uses: haskell/actions/setup@v2 + - uses: haskell-actions/setup@v2 id: setup-haskell with: ghc-version: ${{ matrix.ghc }} - cabal-version: '3.10.1.0' + cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133 - name: Work around git problem https://bugs.launchpad.net/ubuntu/+source/git/+bug/1993586 (cabal PR #8546) run: | @@ -106,11 +149,6 @@ jobs: fi echo "FLAGS=$FLAGS" >> $GITHUB_ENV - - name: Allow newer dependencies when built with latest GHC - if: ${{ matrix.ghc }} == '9.6.1' - run: | - echo "allow-newer: rere:base, rere:transformers" >> cabal.project.validate - - name: Validate print-config run: sh validate.sh $FLAGS -s print-config @@ -161,7 +199,6 @@ jobs: # Have to disable *-suite validation: # - the Windows@9.6.1 problem is tracked at https://github.com/haskell/cabal/issues/8858 # - but curently can't run it with GHC 9.6, tracking: https://github.com/haskell/cabal/issues/8883 - if: (runner.os != 'Windows') || (matrix.ghc != '9.6.1') run: sh validate.sh $FLAGS -s lib-suite - name: Validate cli-tests @@ -169,9 +206,20 @@ jobs: - name: Validate cli-suite # Have to disable *-suite validation, see above the comment for lib-suite - if: (runner.os != 'Windows') || (matrix.ghc != '9.6.1') run: sh validate.sh $FLAGS -s cli-suite + - name: Validate solver-benchmarks-tests + run: | + if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then + sh validate.sh $FLAGS -s solver-benchmarks-tests + fi + + - name: Validate solver-benchmarks-run + run: | + if [[ ${{ matrix.ghc }} == ${{ env.GHC_FOR_SOLVER_BENCHMARKS }} ]]; then + sh validate.sh $FLAGS -s solver-benchmarks-run + fi + validate-old-ghcs: name: Validate old ghcs ${{ matrix.extra-ghc }} runs-on: ubuntu-latest @@ -189,7 +237,7 @@ jobs: # they are not available in ppa/hvr. The ghcup installation # needs `sudo` which is not available in the xenial container ghc: ["8.8.4"] - extra-ghc: ["7.10.3", "7.8.4", "7.6.3", "7.4.2", "7.2.2", "7.0.4"] + extra-ghc: ["8.4.4", "8.2.2", "8.0.2", "7.10.3", "7.8.4", "7.6.3", "7.4.2", "7.2.2", "7.0.4"] steps: @@ -210,11 +258,14 @@ jobs: apt-get update apt-get install -y ghc-${{ matrix.extra-ghc }}-dyn - - uses: haskell/actions/setup@v2 + - uses: haskell-actions/setup@v2.6 + # From 2.7 the setup action uses node20, + # which is not supported by the phadej/ghc:8.8.4-xenial container. id: setup-haskell with: ghc-version: ${{ matrix.ghc }} - cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133 + # Make sure this bindist works in this old environment + cabal-version: 3.10.1.0 # As we are reusing the cached build dir from the previous step # the generated artifacts are available here, @@ -235,6 +286,68 @@ jobs: EXTRA_GHC: "/opt/ghc/${{ matrix.extra-ghc }}/bin/ghc-${{ matrix.extra-ghc }}" run: sh validate.sh ${{ env.COMMON_FLAGS }} --lib-only -s lib-suite-extras --extra-hc ${{ env.EXTRA_GHC }} + build-alpine: + name: Build statically linked using alpine + runs-on: "ubuntu-latest" + container: "alpine:3.19" + steps: + - name: Install extra dependencies + shell: sh + run: | + apk add bash curl sudo jq pkgconfig \ + zlib-dev zlib-static binutils-gold curl \ + gcc g++ gmp-dev libc-dev libffi-dev make \ + musl-dev ncurses-dev perl tar xz + + - uses: actions/checkout@v4 + + # See https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#hackage-revisions + - name: Manually supplied constraints/allow-newer + if: ${{ github.event_name == 'workflow_dispatch' }} + run: | + echo 'allow-newer:' ${ALLOWNEWER} >> cabal.project.validate + echo 'constraints:' ${CONSTRAINTS} >> cabal.project.validate + + # See the following link for a breakdown of the following step + # https://github.com/haskell/actions/issues/7#issuecomment-745697160 + - uses: actions/cache@v3 + with: + # validate.sh uses a special build dir + path: | + ${{ steps.setup-haskell.outputs.cabal-store }} + dist-* + key: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}-${{ github.sha }} + restore-keys: ${{ runner.os }}-${{ env.GHC_FOR_RELEASE }}- + + - uses: haskell-actions/setup@v2 + id: setup-haskell + with: + ghc-version: ${{ env.GHC_FOR_RELEASE }} + cabal-version: latest # latest is mandatory for cabal-testsuite, see https://github.com/haskell/cabal/issues/8133 + + - name: Enable statically linked executables + run: | + echo 'executable-static: true' >> cabal.project.validate + + - name: Build + run: sh validate.sh $FLAGS -s build + + - name: Tar cabal head executable + run: | + CABAL_EXEC=$(cabal list-bin --builddir=dist-newstyle-validate-ghc-${{ env.GHC_FOR_RELEASE }} --project-file=cabal.project.validate cabal-install:exe:cabal) + # We have to tar the executable to preserve executable permissions + # see https://github.com/actions/upload-artifact/issues/38 + export CABAL_EXEC_TAR="cabal-head-${{ runner.os }}-static-x86_64.tar.gz" + tar -czvf $CABAL_EXEC_TAR -C $(dirname "$CABAL_EXEC") $(basename "$CABAL_EXEC") + echo "CABAL_EXEC_TAR=$CABAL_EXEC_TAR" >> $GITHUB_ENV + + - name: Upload cabal-install executable to workflow artifacts + uses: actions/upload-artifact@v3 + with: + name: cabal-${{ runner.os }}-static-x86_64 + path: ${{ env.CABAL_EXEC_TAR }} + + # The previous jobs use a released version of cabal to build cabal HEAD itself # This one uses the cabal HEAD generated executable in the previous step # to build itself again, as sanity check @@ -251,6 +364,12 @@ jobs: ghc: ${{ fromJSON (needs.validate.outputs.GHC_FOR_RELEASE) }} steps: + - name: Work around XDG directories existence (haskell-actions/setup#62) + if: ${{ runner.os == 'macOS' }} + run: | + rm -rf ~/.config/cabal + rm -rf ~/.cache/cabal + - uses: actions/checkout@v4 # See https://github.com/haskell/cabal/pull/8739 @@ -263,7 +382,7 @@ jobs: sudo chown -R $USER /usr/local/.ghcup sudo chmod -R 777 /usr/local/.ghcup fi - - uses: haskell/actions/setup@v2 + - uses: haskell-actions/setup@v2 id: setup-haskell with: ghc-version: ${{ matrix.ghc }} @@ -292,7 +411,7 @@ jobs: if: github.ref == 'refs/heads/master' # IMPORTANT! Any job added to the workflow should be added here too - needs: [validate, validate-old-ghcs, dogfooding] + needs: [validate, validate-old-ghcs, build-alpine, dogfooding] steps: - uses: actions/download-artifact@v3 @@ -303,6 +422,10 @@ jobs: with: name: cabal-Linux-x86_64 + - uses: actions/download-artifact@v3 + with: + name: cabal-Linux-static-x86_64 + - uses: actions/download-artifact@v3 with: name: cabal-macOS-x86_64 @@ -317,6 +440,7 @@ jobs: files: | cabal-head-Windows-x86_64.tar.gz cabal-head-Linux-x86_64.tar.gz + cabal-head-Linux-static-x86_64.tar.gz cabal-head-macOS-x86_64.tar.gz # We use this job as a summary of the workflow @@ -328,7 +452,7 @@ jobs: name: Validate post job runs-on: ubuntu-latest # IMPORTANT! Any job added to the workflow should be added here too - needs: [validate, validate-old-ghcs, dogfooding] + needs: [validate, validate-old-ghcs, build-alpine, dogfooding] steps: - run: | diff --git a/.github/workflows/whitespace.yml b/.github/workflows/whitespace.yml new file mode 100644 index 00000000000..46088d3d351 --- /dev/null +++ b/.github/workflows/whitespace.yml @@ -0,0 +1,14 @@ +name: Whitespace + +on: + pull_request: + push: + branches: ["master"] + +jobs: + whitespace: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: andreasabel/fix-whitespace-action@v1 diff --git a/.gitignore b/.gitignore index e9ec3b6322f..3e0b65c8085 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,17 @@ progress.txt # test files register.sh +# listed explicitly to show which files are generated but ignored +testdb/intree/cabal.project-test +testdb/intree/store/**/bin/alex +testdb/intree/store/**/cabal-hash.txt +testdb/intree/store/**/share/AlexTemplate.hs +testdb/intree/store/**/share/AlexWrappers.hs +testdb/intree/store/**/share/doc/LICENSE +testdb/intree/store/*/incoming/alex-*.lock +testdb/intree/store/*/package.db/package.cache +testdb/intree/store/*/package.db/package.cache.lock + # windows test artifacts cabal-testsuite/**/*.exe cabal-testsuite/**/*.bat @@ -73,6 +84,8 @@ cabal-testsuite/**/haddocks # python artifacts from documentation builds *.pyc .python-sphinx-virtualenv/ +venv +.venv /doc/.skjold_cache/ # macOS folder metadata @@ -83,3 +96,8 @@ bench.html # Emacs .projectile + +## Release Scripts + +# ignore the downloaded binary files +scripts/release/binary-downloads/ diff --git a/.gitlab/ci.sh b/.gitlab/ci.sh index c856f9f2cb9..973c6775d46 100755 --- a/.gitlab/ci.sh +++ b/.gitlab/ci.sh @@ -57,6 +57,22 @@ if [ "$(getconf LONG_BIT)" = "32" -o "${PLATFORM:=xxx}" = "x86_64-linux-centos7" echo 'constraints: lukko -ofd-locking' >> cabal.project.release.local fi +# In February 2024, cabal started using zlib-0.7.0.0, which uses pkg-config by +# default. The GitLab CI environment doesn't (yet) supply pkg-config, and zlib +# does just fine without it on modern GHCs. That said, the CI environment +# probably *should* have pkg-config installed. See +# https://github.com/haskell/cabal/issues/9774. +echo 'constraints: zlib -pkg-config' >> cabal.project.release.local +# Furthermore, on Windows, zlib claims that libz is shipped with GHC, so it just +# uses @extra-libraries: z@ if pkg-config is False. If you are reading this +# comment, however, this didn't work. Thus we switch to using the bundled libz, +# as was done in zlib <0.7.0.0. +case "$(uname)" in + MSYS_*|MINGW*) + echo 'constraints: zlib +bundled-c-zlib' >> cabal.project.release.local + ;; +esac + args=( -w "ghc-$GHC_VERSION" --disable-profiling diff --git a/.hlint.yaml b/.hlint.yaml index f425ae527a8..e38cc7be72e 100644 --- a/.hlint.yaml +++ b/.hlint.yaml @@ -94,9 +94,10 @@ - ignore: {name: "Use when"} # 1 hint - arguments: + - --ignore-glob=Cabal-syntax/src/Distribution/Fields/Lexer.hs - --ignore-glob=cabal-testsuite/PackageTests/CmmSources/src/Demo.hs - --ignore-glob=cabal-testsuite/PackageTests/CmmSourcesDyn/src/Demo.hs - - --ignore-glob=Cabal-syntax/src/Distribution/Fields/Lexer.hs + - --ignore-glob=cabal-testsuite/PackageTests/CmmSourcesExe/src/Demo.hs - --ignore-glob=templates/Paths_pkg.template.hs - --ignore-glob=templates/SPDX.LicenseExceptionId.template.hs - --ignore-glob=templates/SPDX.LicenseId.template.hs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb2700d377a..5ca5544106b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,20 +38,26 @@ cabal build cabal-tests # etc... Running tests ------------- -**Using Github Actions.** +**Using GitHub Actions.** If you are not in a hurry, the most convenient way to run tests on Cabal is to make a branch on GitHub and then open a pull request; our -continuous integration service on Github Actions builds and +continuous integration service on GitHub Actions builds and tests your code. Title your PR with WIP so we know that it does not need code review. -Some tips for using Github Actions effectively: +Some tips for using GitHub Actions effectively: -* Github Actions builds take a long time. Use them when you are pretty +* GitHub Actions builds take a long time. Use them when you are pretty sure everything is OK; otherwise, try to run relevant tests locally first. -* Watch over your jobs on the [Github Actions website](http://github.org/haskell/cabal/actions). +* If you are only changing documentation in the `docs/` subdirectory, + or if you change `README.md` or `CONTRIBUTING.md`, then we only run a + small subset of the CI jobs. You can therefore open small PRs with + improvements to the documentation without feeling guilty about wasted + resources! + +* Watch over your jobs on the [GitHub Actions website](http://github.org/haskell/cabal/actions). If you know a build of yours is going to fail (because one job has already failed), be nice to others and cancel the rest of the jobs, so that other commits on the build queue can be processed. @@ -75,9 +81,9 @@ failures: a specific operating system? If so, try reproducing the problem on the specific configuration. -4. Is the test failing on a Github Actions per-GHC build. +4. Is the test failing on a GitHub Actions per-GHC build. In this case, if you click on "Branch", you can get access to - the precise binaries that were built by Github Actions that are being + the precise binaries that were built by GitHub Actions that are being tested. If you have an Ubuntu system, you can download the binaries and run them directly. @@ -136,7 +142,7 @@ and should be written in the body of the ticket or PR under their own heading, l For instance: > \#\# QA Notes -> +> > Calling `cabal haddock-project` should produce documentation for the whole cabal project with the following defaults enabled: > * Documentation lives in ./haddocks > * The file `./haddocks/index.html` should exist @@ -149,8 +155,20 @@ Code Style --------------- We use automated formatting with Fourmolu to enforce a unified style across the code bases. It is checked in the CI process. -After installing Fourmolu 0.12, you can automatically format the code bases with `make style` at the top level of the project. -You can also use `make style-modified` to only format modified files. +After installing Fourmolu 0.12, there are some makefile targets to help formatting +the code base. + + +* `make style` - Format the `Cabal`, `Cabal-syntax` and `cabal-install` directories. +* `make style-modified` - Format files modified in the current tree. +* `make style-commit COMMIT=` - Format files modified between HEAD and the given reference. + +Whitespace Conventions +---------------------- + +We use automated whitespace convention checking. Violations can be fixed by +running [fix-whitespace](https://hackage.haskell.org/package/fix-whitespace). If +you push a fix of a whitespace violation, please do so in a _separate commit_. Other Conventions ----------------- @@ -176,7 +194,7 @@ Other Conventions * Our GHC support window is five years for the Cabal library and three years for cabal-install: that is, the Cabal library must be buildable out-of-the-box with the dependencies that shipped with GHC - for at least five years. The Travis CI checks this, so most + for at least five years. GitHub Actions checks this, so most developers submit a PR to see if their code works on all these versions of GHC. `cabal-install` must also be buildable on all supported GHCs, although it does not have to be buildable @@ -218,7 +236,7 @@ GitHub Ticket Conventions Each major `Cabal`/`cabal-install` release (e.g. 3.4, 3.6, etc.) has a corresponding GitHub Project and milestone. A ticket is included in a release's -project if the release managers are tenatively planning on including a fix for +project if the release managers are tentatively planning on including a fix for the ticket in the release, i.e. if they are actively seeking someone to work on the ticket. @@ -247,6 +265,28 @@ If your pull request consists of several commits, consider using `squash+merge me` instead of `merge me`: the Mergify bot will squash all the commits into one and concatenate the commit messages of the commits before merging. +There is also a `merge+no rebase` label. Use this very sparingly, as not rebasing +severely complicates Git history. It is intended for special circumstances, as when +the PR branch cannot or should not be modified. If you have any questions about it, +please ask us. + +### Pull Requests & Issues + +A pull request *fixes* a problem that is *described* in an issue. Make sure to +file an issue before opening a pull request. In the issue you can illustrate +your proposed design, UX considerations, tradeoffs etc. and work them out with +other contributors. The PR itself is for implementation. + +If a PR becomes out of sync with its issue, go back to the issue, update +it, and continue the conversation there. Telltale signs of Issue/PR diverging +are, for example: the PR growing bigger in scope; lengthy discussions +about things that are *not* implementation choices; a change in design. + +If your PR is trivial you can omit this process (but explain in the PR why you +think it does not warrant an issue). Feel free to open a new issue (or new +issues) when appropriate. + + Changelog --------- @@ -319,6 +359,25 @@ Currently, [@emilypi](https://github.com/emilypi), [@fgaz](https://github.com/fg `haskell.org/cabal`, and [@Mikolaj](https://github.com/Mikolaj) is the point of contact for getting permissions. +Preview Releases +---------------- + +We make preview releases available to facilitate testing of development builds. + +Artifacts can be found on the [`cabal-head` release page](https://github.com/haskell/cabal/releases/tag/cabal-head). +The Validate CI pipeline generates tarballs with a `cabal` executable. The executable gets uploaded to this release by the pipelines that run on `master`. + +We currently make available builds for: + - Linux, dynamically linked (requiring `zlib`, `gmp`, `glibc`) + - Linux, statically linked + - MacOS + - Windows + +The statically linked Linux executables are built using Alpine. +To reproduce these locally, set up an Alpine build environment using GHCup, +and then build by calling `cabal build cabal-install --enable-executable-static`. + + API Documentation ----------------- @@ -327,3 +386,35 @@ Auto-generated API documentation for the `master` branch of Cabal is automatical ## Issue triage [![Open Source Helpers](https://www.codetriage.com/haskell/cabal/badges/users.svg)](https://www.codetriage.com/haskell/cabal) You can contribute by triaging issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to [subscribe to cabal on CodeTriage](https://www.codetriage.com/haskell/cabal). + +Hackage Revisions +----------------- + +We are reactive rather than proactive with revising bounds on our dependencies +for code already released on Hackage. If you would benefit from a version bump, +please, open a ticket and get familiar with +[our revision policy](https://github.com/haskell/cabal/issues/9531#issuecomment-1866930240). + +The burden of proof that the bump is harmless remains with you, but we have a CI +setup to show that our main pipeline ("Validate") is fine with the bump. To use +it, someone with enough permissions needs to go on the +[Validate workflow page](https://github.com/haskell/cabal/actions/workflows/validate.yml) +and dispatch it manually by clicking "Run workflow". + +Running workflow manually as discussed above requires you to supply two inputs: + +> allow-newer line +> constraints line + +Going via an example, imagine that Cabal only allows `tar` or version less then +or equal to 0.6, and you want to bump it to 0.6. Then, to show that Validate +succeeds with `tar` 0.6, you should input + +- `tar` to the "allow-newer line" +- `tar ==0.6` to the "constraints line" + +Hopefully, running the Validate pipeline with these inputs succeeds and you +supply the link to the run in the ticket about bumping the bound and making a revision. + +If interested in technical details, refer to the parts of `validate.yml` that +mention `hackage-revisions`. diff --git a/Cabal-QuickCheck/src/Test/QuickCheck/Instances/Cabal.hs b/Cabal-QuickCheck/src/Test/QuickCheck/Instances/Cabal.hs index 2976d34b557..e5b5077d414 100644 --- a/Cabal-QuickCheck/src/Test/QuickCheck/Instances/Cabal.hs +++ b/Cabal-QuickCheck/src/Test/QuickCheck/Instances/Cabal.hs @@ -3,7 +3,9 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module Test.QuickCheck.Instances.Cabal () where +#if !MIN_VERSION_base(4,18,0) import Control.Applicative (liftA2) +#endif import Data.Bits (shiftR) import Data.Char (isAlphaNum, isDigit, toLower) import Data.List (intercalate, (\\)) diff --git a/Cabal-described/src/Distribution/Described.hs b/Cabal-described/src/Distribution/Described.hs index d095040a87c..3bfd8c2e3a4 100644 --- a/Cabal-described/src/Distribution/Described.hs +++ b/Cabal-described/src/Distribution/Described.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} module Distribution.Described ( @@ -38,8 +39,10 @@ module Distribution.Described ( ) where import Prelude - (Bool (..), Char, Either (..), Enum (..), Eq (..), Ord (..), Show (..), String, elem, fmap, foldr, id, map, maybe, otherwise, return, undefined, ($), - (.)) + ( Bool (..), Char, Either (..), Enum (..), Eq (..), Ord (..), Show (..), String + , elem, fmap, foldr, id, map, maybe, otherwise, return, reverse, undefined + , ($), (.), (<$>) + ) import Data.Functor.Identity (Identity (..)) import Data.Maybe (fromMaybe) @@ -65,6 +68,7 @@ import Distribution.Utils.GrammarRegex -- Types import Distribution.Compat.Newtype import Distribution.Compiler (CompilerFlavor, CompilerId, knownCompilerFlavors) +import Distribution.PackageDescription.FieldGrammar (CompatFilePath, CompatLicenseFile) import Distribution.FieldGrammar.Newtypes import Distribution.ModuleName (ModuleName) import Distribution.System (Arch, OS, knownArches, knownOSs) @@ -95,9 +99,10 @@ import Distribution.Types.SourceRepo (RepoType) import Distribution.Types.TestType (TestType) import Distribution.Types.UnitId (UnitId) import Distribution.Types.UnqualComponentName (UnqualComponentName) +import Distribution.Utils.Path (LicenseFile, PackageDir, SourceDir, SymbolicPath) import Distribution.Verbosity (Verbosity) import Distribution.Version (Version, VersionRange) -import Language.Haskell.Extension (Extension, Language) +import Language.Haskell.Extension (Extension, Language, knownLanguages) -- | Class describing the pretty/parsec format of a. class (Pretty a, Parsec a) => Described a where @@ -419,7 +424,7 @@ instance Described IncludeRenaming where mr = describe (Proxy :: Proxy ModuleRenaming) instance Described Language where - describe _ = REUnion ["Haskell98", "Haskell2010"] + describe _ = REUnion $ (REString . show) <$> reverse knownLanguages instance Described LegacyExeDependency where describe _ = RETodo @@ -575,3 +580,15 @@ instance Described TestedWith where instance Described FilePathNT where describe _ = describe ([] :: [Token]) + +instance Described (SymbolicPath PackageDir SourceDir) where + describe _ = describe ([] :: [Token]) + +instance Described (SymbolicPath PackageDir LicenseFile) where + describe _ = describe ([] :: [Token]) + +instance Described CompatLicenseFile where + describe _ = describe ([] :: [Token]) + +instance Described CompatFilePath where + describe _ = describe ([] :: [Token]) diff --git a/Cabal-described/src/Distribution/Utils/CharSet.hs b/Cabal-described/src/Distribution/Utils/CharSet.hs index 45bfbb1300b..9243615c7fa 100644 --- a/Cabal-described/src/Distribution/Utils/CharSet.hs +++ b/Cabal-described/src/Distribution/Utils/CharSet.hs @@ -240,3 +240,8 @@ alphanum = foldl' (flip insert) empty [ c | c <- [ minBound .. maxBound ], isAlp upper :: CharSet upper = foldl' (flip insert) empty [ c | c <- [ minBound .. maxBound ], isUpper c ] {-# NOINLINE upper #-} + +-- $setup +-- Use -XOverloadedStrings to avoid the error: Couldn't match type ‘[Char]’ with ‘CharSet’ +-- >>> :set -XOverloadedStrings +-- >>> import Prelude (length) diff --git a/Cabal-syntax/Cabal-syntax.cabal b/Cabal-syntax/Cabal-syntax.cabal index 8a230ba5e2a..73fb7c1bb17 100644 --- a/Cabal-syntax/Cabal-syntax.cabal +++ b/Cabal-syntax/Cabal-syntax.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: Cabal-syntax version: 3.11.0.0 -copyright: 2003-2023, Cabal Development Team (see AUTHORS file) +copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team @@ -15,7 +15,7 @@ description: category: Distribution build-type: Simple -extra-source-files: +extra-doc-files: README.md ChangeLog.md source-repository head @@ -32,10 +32,10 @@ library base >= 4.9 && < 5, binary >= 0.7 && < 0.9, bytestring >= 0.10.0.0 && < 0.13, - containers >= 0.5.0.0 && < 0.7, + containers >= 0.5.0.0 && < 0.8, deepseq >= 1.3.0.1 && < 1.6, directory >= 1.2 && < 1.4, - filepath >= 1.3.0.1 && < 1.5, + filepath >= 1.3.0.1 && < 1.6, mtl >= 2.1 && < 2.4, parsec >= 3.1.13.0 && < 3.2, pretty >= 1.1.1 && < 1.2, @@ -45,11 +45,6 @@ library -- See also https://github.com/ekmett/transformers-compat/issues/35 transformers (>= 0.3 && < 0.4) || (>=0.4.1.0 && <0.7) - if os(windows) - build-depends: Win32 >= 2.3.0.0 && < 2.14 - else - build-depends: unix >= 2.6.0.0 && < 2.9 - ghc-options: -Wall -fno-ignore-asserts -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates if impl(ghc >= 8.0) @@ -58,6 +53,9 @@ library if impl(ghc >= 8.0) && impl(ghc < 8.8) ghc-options: -Wnoncanonical-monadfail-instances + if impl(ghc >= 8.10) + ghc-options: -Wunused-packages + build-tool-depends: alex:alex exposed-modules: diff --git a/Cabal-syntax/ChangeLog.md b/Cabal-syntax/ChangeLog.md index 58c8379eb44..7706be32368 100644 --- a/Cabal-syntax/ChangeLog.md +++ b/Cabal-syntax/ChangeLog.md @@ -1 +1 @@ -Please see See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.10.2.0.md +Please see See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.10.3.0.md diff --git a/Cabal-syntax/LICENSE b/Cabal-syntax/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/Cabal-syntax/LICENSE +++ b/Cabal-syntax/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/Cabal-syntax/src/Distribution/CabalSpecVersion.hs b/Cabal-syntax/src/Distribution/CabalSpecVersion.hs index 6290fa9166e..eb029b5ffc9 100644 --- a/Cabal-syntax/src/Distribution/CabalSpecVersion.hs +++ b/Cabal-syntax/src/Distribution/CabalSpecVersion.hs @@ -32,7 +32,8 @@ data CabalSpecVersion CabalSpecV3_4 | CabalSpecV3_6 | CabalSpecV3_8 - -- 3.10: no changes + | -- 3.10: no changes + CabalSpecV3_12 deriving (Eq, Ord, Show, Read, Enum, Bounded, Typeable, Data, Generic) instance Binary CabalSpecVersion @@ -43,6 +44,7 @@ instance NFData CabalSpecVersion where rnf = genericRnf -- -- @since 3.0.0.0 showCabalSpecVersion :: CabalSpecVersion -> String +showCabalSpecVersion CabalSpecV3_12 = "3.12" showCabalSpecVersion CabalSpecV3_8 = "3.8" showCabalSpecVersion CabalSpecV3_6 = "3.6" showCabalSpecVersion CabalSpecV3_4 = "3.4" @@ -63,13 +65,14 @@ showCabalSpecVersion CabalSpecV1_2 = "1.2" showCabalSpecVersion CabalSpecV1_0 = "1.0" cabalSpecLatest :: CabalSpecVersion -cabalSpecLatest = CabalSpecV3_8 +cabalSpecLatest = CabalSpecV3_12 -- | Parse 'CabalSpecVersion' from version digits. -- -- It may fail if for recent versions the version is not exact. cabalSpecFromVersionDigits :: [Int] -> Maybe CabalSpecVersion cabalSpecFromVersionDigits v + | v == [3, 12] = Just CabalSpecV3_12 | v == [3, 8] = Just CabalSpecV3_8 | v == [3, 6] = Just CabalSpecV3_6 | v == [3, 4] = Just CabalSpecV3_4 @@ -92,6 +95,7 @@ cabalSpecFromVersionDigits v -- | @since 3.4.0.0 cabalSpecToVersionDigits :: CabalSpecVersion -> [Int] +cabalSpecToVersionDigits CabalSpecV3_12 = [3, 12] cabalSpecToVersionDigits CabalSpecV3_8 = [3, 8] cabalSpecToVersionDigits CabalSpecV3_6 = [3, 6] cabalSpecToVersionDigits CabalSpecV3_4 = [3, 4] diff --git a/Cabal-syntax/src/Distribution/Fields/Field.hs b/Cabal-syntax/src/Distribution/Fields/Field.hs index c119ca5f1c0..c7d63533e52 100644 --- a/Cabal-syntax/src/Distribution/Fields/Field.hs +++ b/Cabal-syntax/src/Distribution/Fields/Field.hs @@ -2,6 +2,7 @@ {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} +{-# LANGUAGE StandaloneDeriving #-} -- | Cabal-like file AST types: 'Field', 'Section' etc -- @@ -51,6 +52,9 @@ data Field ann | Section !(Name ann) [SectionArg ann] [Field ann] deriving (Eq, Show, Functor, Foldable, Traversable) +-- | @since 3.12.0.0 +deriving instance Ord ann => Ord (Field ann) + -- | Section of field name fieldName :: Field ann -> Name ann fieldName (Field n _) = n @@ -73,6 +77,9 @@ fieldUniverse f@(Field _ _) = [f] data FieldLine ann = FieldLine !ann !ByteString deriving (Eq, Show, Functor, Foldable, Traversable) +-- | @since 3.12.0.0 +deriving instance Ord ann => Ord (FieldLine ann) + -- | @since 3.0.0.0 fieldLineAnn :: FieldLine ann -> ann fieldLineAnn (FieldLine ann _) = ann @@ -91,6 +98,9 @@ data SectionArg ann SecArgOther !ann !ByteString deriving (Eq, Show, Functor, Foldable, Traversable) +-- | @since 3.12.0.0 +deriving instance Ord ann => Ord (SectionArg ann) + -- | Extract annotation from 'SectionArg'. sectionArgAnn :: SectionArg ann -> ann sectionArgAnn (SecArgName ann _) = ann @@ -109,6 +119,9 @@ type FieldName = ByteString data Name ann = Name !ann !FieldName deriving (Eq, Show, Functor, Foldable, Traversable) +-- | @since 3.12.0.0 +deriving instance Ord ann => Ord (Name ann) + mkName :: ann -> FieldName -> Name ann mkName ann bs = Name ann (B.map Char.toLower bs) diff --git a/Cabal-syntax/src/Distribution/PackageDescription/Parsec.hs b/Cabal-syntax/src/Distribution/PackageDescription/Parsec.hs index bee6965c127..cd299b87675 100644 --- a/Cabal-syntax/src/Distribution/PackageDescription/Parsec.hs +++ b/Cabal-syntax/src/Distribution/PackageDescription/Parsec.hs @@ -88,7 +88,10 @@ parseGenericPackageDescription bs = do Just csv -> return (Just csv) Nothing -> parseFatalFailure zeroPos $ - "Unsupported cabal-version " ++ prettyShow v ++ ". See https://github.com/haskell/cabal/issues/4899." + "Unsupported cabal format version in cabal-version field: " + ++ prettyShow v + ++ ".\n" + ++ cabalFormatVersionsDesc _ -> pure Nothing case readFields' bs'' of @@ -175,8 +178,8 @@ parseGenericPackageDescription' scannedVer lexWarnings utf8WarnPos fs = do -- if it were at the beginning, scanner would found it when (v >= CabalSpecV2_2) $ parseFailure pos $ - "cabal-version should be at the beginning of the file starting with spec version 2.2. " - ++ "See https://github.com/haskell/cabal/issues/4899" + "cabal-version should be at the beginning of the file starting with spec version 2.2.\n" + ++ cabalFormatVersionsDesc return v @@ -234,6 +237,10 @@ parseGenericPackageDescription' scannedVer lexWarnings utf8WarnPos fs = do ++ "' must use section syntax. See the Cabal user guide for details." maybeWarnCabalVersion _ _ = return () +-- See #4899 +cabalFormatVersionsDesc :: String +cabalFormatVersionsDesc = "Current cabal-version values are listed at https://cabal.readthedocs.io/en/stable/file-format-changelog.html." + goSections :: CabalSpecVersion -> [Field Position] -> SectionParser () goSections specVer = traverse_ process where diff --git a/Cabal-syntax/src/Distribution/System.hs b/Cabal-syntax/src/Distribution/System.hs index 041d13a3be7..e1e75aa2315 100644 --- a/Cabal-syntax/src/Distribution/System.hs +++ b/Cabal-syntax/src/Distribution/System.hs @@ -181,14 +181,14 @@ buildOS = classifyOS Permissive System.Info.os -- ------------------------------------------------------------ --- | These are the known Arches: I386, X86_64, PPC, PPC64, Sparc, --- Arm, AArch64, Mips, SH, IA64, S390, S390X, Alpha, Hppa, Rs6000, --- M68k, Vax, RISCV64, LoongArch64, JavaScript and Wasm32. +-- | These are the known Arches: I386, X86_64, PPC, PPC64, PPC64LE, Sparc, +-- Sparc64, Arm, AArch64, Mips, SH, IA64, S390, S390X, Alpha, Hppa, +-- Rs6000, M68k, Vax, RISCV64, LoongArch64, JavaScript and Wasm32. -- -- The following aliases can also be used: -- * PPC alias: powerpc --- * PPC64 alias : powerpc64, powerpc64le --- * Sparc aliases: sparc64, sun4 +-- * PPC64 alias : powerpc64 +-- * PPC64LE alias : powerpc64le -- * Mips aliases: mipsel, mipseb -- * Arm aliases: armeb, armel -- * AArch64 aliases: arm64 @@ -197,7 +197,9 @@ data Arch | X86_64 | PPC | PPC64 + | PPC64LE | Sparc + | Sparc64 | Arm | AArch64 | Mips @@ -227,7 +229,9 @@ knownArches = , X86_64 , PPC , PPC64 + , PPC64LE , Sparc + , Sparc64 , Arm , AArch64 , Mips @@ -250,8 +254,8 @@ archAliases :: ClassificationStrictness -> Arch -> [String] archAliases Strict _ = [] archAliases Compat _ = [] archAliases _ PPC = ["powerpc"] -archAliases _ PPC64 = ["powerpc64", "powerpc64le"] -archAliases _ Sparc = ["sparc64", "sun4"] +archAliases _ PPC64 = ["powerpc64"] +archAliases _ PPC64LE = ["powerpc64le"] archAliases _ Mips = ["mipsel", "mipseb"] archAliases _ Arm = ["armeb", "armel"] archAliases _ AArch64 = ["arm64"] diff --git a/Cabal-syntax/src/Distribution/Types/Benchmark.hs b/Cabal-syntax/src/Distribution/Types/Benchmark.hs index be0911432ec..13e5fe104e5 100644 --- a/Cabal-syntax/src/Distribution/Types/Benchmark.hs +++ b/Cabal-syntax/src/Distribution/Types/Benchmark.hs @@ -48,24 +48,12 @@ instance Monoid Benchmark where instance Semigroup Benchmark where a <> b = Benchmark - { benchmarkName = combine' benchmarkName + { benchmarkName = combineNames a b benchmarkName "benchmark" , benchmarkInterface = combine benchmarkInterface , benchmarkBuildInfo = combine benchmarkBuildInfo } where combine field = field a `mappend` field b - combine' field = case ( unUnqualComponentName $ field a - , unUnqualComponentName $ field b - ) of - ("", _) -> field b - (_, "") -> field a - (x, y) -> - error $ - "Ambiguous values for test field: '" - ++ x - ++ "' and '" - ++ y - ++ "'" emptyBenchmark :: Benchmark emptyBenchmark = mempty diff --git a/Cabal-syntax/src/Distribution/Types/Component.hs b/Cabal-syntax/src/Distribution/Types/Component.hs index 6a6027bd258..fee1201fba9 100644 --- a/Cabal-syntax/src/Distribution/Types/Component.hs +++ b/Cabal-syntax/src/Distribution/Types/Component.hs @@ -29,7 +29,10 @@ data Component | CExe Executable | CTest TestSuite | CBench Benchmark - deriving (Show, Eq, Read) + deriving (Generic, Show, Eq, Read) + +instance Binary Component +instance Structured Component instance Semigroup Component where CLib l <> CLib l' = CLib (l <> l') diff --git a/Cabal-syntax/src/Distribution/Types/CondTree.hs b/Cabal-syntax/src/Distribution/Types/CondTree.hs index 5fe25e649d7..08a4d691faf 100644 --- a/Cabal-syntax/src/Distribution/Types/CondTree.hs +++ b/Cabal-syntax/src/Distribution/Types/CondTree.hs @@ -21,6 +21,7 @@ module Distribution.Types.CondTree , traverseCondBranchC , extractCondition , simplifyCondTree + , simplifyCondBranch , ignoreConditions ) where @@ -169,7 +170,7 @@ extractCondition p = go in ((c `cAnd` ct) `cOr` (CNot c `cAnd` ce)) `cAnd` goList cs --- | Flattens a CondTree using a partial flag assignment. When a condition +-- | Flattens a CondTree using a partial flag assignment. When a condition -- cannot be evaluated, both branches are ignored. simplifyCondTree :: (Semigroup a, Semigroup d) @@ -177,13 +178,20 @@ simplifyCondTree -> CondTree v d a -> (d, a) simplifyCondTree env (CondNode a d ifs) = - foldl (<>) (d, a) $ mapMaybe simplifyIf ifs - where - simplifyIf (CondBranch cnd t me) = - case simplifyCondition cnd env of - (Lit True, _) -> Just $ simplifyCondTree env t - (Lit False, _) -> fmap (simplifyCondTree env) me - _ -> Nothing + foldl (<>) (d, a) $ mapMaybe (simplifyCondBranch env) ifs + +-- | Realizes a 'CondBranch' using partial flag assignment. When a condition +-- cannot be evaluated, returns 'Nothing'. +simplifyCondBranch + :: (Semigroup a, Semigroup d) + => (v -> Either v Bool) + -> CondBranch v d a + -> Maybe (d, a) +simplifyCondBranch env (CondBranch cnd t me) = + case simplifyCondition cnd env of + (Lit True, _) -> Just $ simplifyCondTree env t + (Lit False, _) -> fmap (simplifyCondTree env) me + _ -> Nothing -- | Flatten a CondTree. This will resolve the CondTree by taking all -- possible paths into account. Note that since branches represent exclusive diff --git a/Cabal-syntax/src/Distribution/Types/Executable.hs b/Cabal-syntax/src/Distribution/Types/Executable.hs index 618f91dc5f3..bf70702f41c 100644 --- a/Cabal-syntax/src/Distribution/Types/Executable.hs +++ b/Cabal-syntax/src/Distribution/Types/Executable.hs @@ -40,25 +40,13 @@ instance Monoid Executable where instance Semigroup Executable where a <> b = Executable - { exeName = combine' exeName - , modulePath = combine modulePath + { exeName = combineNames a b exeName "executable" + , modulePath = combineNames a b modulePath "modulePath" , exeScope = combine exeScope , buildInfo = combine buildInfo } where combine field = field a `mappend` field b - combine' field = case ( unUnqualComponentName $ field a - , unUnqualComponentName $ field b - ) of - ("", _) -> field b - (_, "") -> field a - (x, y) -> - error $ - "Ambiguous values for executable field: '" - ++ x - ++ "' and '" - ++ y - ++ "'" emptyExecutable :: Executable emptyExecutable = mempty diff --git a/Cabal-syntax/src/Distribution/Types/ForeignLib.hs b/Cabal-syntax/src/Distribution/Types/ForeignLib.hs index 9d714f9895f..19336af203d 100644 --- a/Cabal-syntax/src/Distribution/Types/ForeignLib.hs +++ b/Cabal-syntax/src/Distribution/Types/ForeignLib.hs @@ -28,6 +28,7 @@ import Distribution.Types.ForeignLibType import Distribution.Types.UnqualComponentName import Distribution.Version +import Data.Monoid import qualified Distribution.Compat.CharParsing as P import qualified Text.PrettyPrint as Disp import qualified Text.Read as Read @@ -140,29 +141,18 @@ instance NFData ForeignLib where rnf = genericRnf instance Semigroup ForeignLib where a <> b = ForeignLib - { foreignLibName = combine' foreignLibName + { foreignLibName = combineNames a b foreignLibName "foreign library" , foreignLibType = combine foreignLibType , foreignLibOptions = combine foreignLibOptions , foreignLibBuildInfo = combine foreignLibBuildInfo - , foreignLibVersionInfo = combine'' foreignLibVersionInfo - , foreignLibVersionLinux = combine'' foreignLibVersionLinux + , foreignLibVersionInfo = chooseLast foreignLibVersionInfo + , foreignLibVersionLinux = chooseLast foreignLibVersionLinux , foreignLibModDefFile = combine foreignLibModDefFile } where combine field = field a `mappend` field b - combine' field = case ( unUnqualComponentName $ field a - , unUnqualComponentName $ field b - ) of - ("", _) -> field b - (_, "") -> field a - (x, y) -> - error $ - "Ambiguous values for executable field: '" - ++ x - ++ "' and '" - ++ y - ++ "'" - combine'' field = field b + -- chooseLast: the second field overrides the first, unless it is Nothing + chooseLast field = getLast (Last (field a) <> Last (field b)) instance Monoid ForeignLib where mempty = diff --git a/Cabal-syntax/src/Distribution/Types/TestSuite.hs b/Cabal-syntax/src/Distribution/Types/TestSuite.hs index 5e72965b815..6b3107cae71 100644 --- a/Cabal-syntax/src/Distribution/Types/TestSuite.hs +++ b/Cabal-syntax/src/Distribution/Types/TestSuite.hs @@ -51,25 +51,13 @@ instance Monoid TestSuite where instance Semigroup TestSuite where a <> b = TestSuite - { testName = combine' testName + { testName = combineNames a b testName "test" , testInterface = combine testInterface , testBuildInfo = combine testBuildInfo , testCodeGenerators = combine testCodeGenerators } where combine field = field a `mappend` field b - combine' field = case ( unUnqualComponentName $ field a - , unUnqualComponentName $ field b - ) of - ("", _) -> field b - (_, "") -> field a - (x, y) -> - error $ - "Ambiguous values for test field: '" - ++ x - ++ "' and '" - ++ y - ++ "'" emptyTestSuite :: TestSuite emptyTestSuite = mempty diff --git a/Cabal-syntax/src/Distribution/Types/UnqualComponentName.hs b/Cabal-syntax/src/Distribution/Types/UnqualComponentName.hs index a13fc917633..3879cdd2169 100644 --- a/Cabal-syntax/src/Distribution/Types/UnqualComponentName.hs +++ b/Cabal-syntax/src/Distribution/Types/UnqualComponentName.hs @@ -9,11 +9,11 @@ module Distribution.Types.UnqualComponentName , mkUnqualComponentName , packageNameToUnqualComponentName , unqualComponentNameToPackageName + , combineNames ) where import Distribution.Compat.Prelude import Distribution.Utils.ShortText -import Prelude () import Distribution.Parsec import Distribution.Pretty @@ -105,3 +105,34 @@ packageNameToUnqualComponentName = UnqualComponentName . unPackageNameST -- @since 2.0.0.2 unqualComponentNameToPackageName :: UnqualComponentName -> PackageName unqualComponentNameToPackageName = mkPackageNameST . unUnqualComponentNameST + +-- | Combine names in targets if one name is empty or both names are equal +-- (partial function). +-- Useful in 'Semigroup' and similar instances. +combineNames + :: (Monoid b, Eq b, Show b) + => a + -> a + -> (a -> b) + -> String + -> b +combineNames a b tacc tt + -- One empty or the same. + | nb == mempty + || na == nb = + na + | na == mempty = + nb + -- Both non-empty, different. + | otherwise = + error $ + "Ambiguous values for " + ++ tt + ++ " field: '" + ++ show na + ++ "' and '" + ++ show nb + ++ "'" + where + (na, nb) = (tacc a, tacc b) +{-# INLINEABLE combineNames #-} diff --git a/Cabal-syntax/src/Language/Haskell/Extension.hs b/Cabal-syntax/src/Language/Haskell/Extension.hs index f1b3e644311..448b1d777c7 100644 --- a/Cabal-syntax/src/Language/Haskell/Extension.hs +++ b/Cabal-syntax/src/Language/Haskell/Extension.hs @@ -54,6 +54,9 @@ data Language | -- | The GHC2021 collection of language extensions. -- GHC2021 + | -- | The GHC2024 collection of language extensions. + -- + GHC2024 | -- | An unknown language, identified by its name. UnknownLanguage String deriving (Generic, Show, Read, Eq, Ord, Typeable, Data) @@ -63,9 +66,9 @@ instance Structured Language instance NFData Language where rnf = genericRnf --- | List of known (supported) languages for GHC +-- | List of known (supported) languages for GHC, oldest first. knownLanguages :: [Language] -knownLanguages = [Haskell98, Haskell2010, GHC2021] +knownLanguages = [Haskell98, Haskell2010, GHC2021, GHC2024] instance Pretty Language where pretty (UnknownLanguage other) = Disp.text other @@ -540,6 +543,11 @@ data KnownExtension AlternativeLayoutRuleTransitional | -- | Undocumented parsing-related extensions introduced in GHC 7.2. RelaxedLayout + | -- | Allow the use of type abstraction syntax. + TypeAbstractions + | -- | Allow the use of built-in syntax for list, tuple and sum type constructors + -- rather than being exclusive to data constructors. + ListTuplePuns deriving (Generic, Show, Read, Eq, Ord, Enum, Bounded, Typeable, Data) instance Binary KnownExtension diff --git a/Cabal-tests/Cabal-tests.cabal b/Cabal-tests/Cabal-tests.cabal index bb42abc7fc7..7e9f5e5dbda 100644 --- a/Cabal-tests/Cabal-tests.cabal +++ b/Cabal-tests/Cabal-tests.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: Cabal-tests version: 3 -copyright: 2003-2023, Cabal Development Team (see AUTHORS file) +copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team @@ -18,6 +18,12 @@ source-repository head location: https://github.com/haskell/cabal/ subdir: Cabal-tests +-- Common utilities which can be used by all tests. +library + hs-source-dirs: lib + exposed-modules: Test.Utils.TempTestDir + build-depends: base, directory, Cabal + -- Small, fast running tests. test-suite unit-tests type: exitcode-stdio-1.0 @@ -29,6 +35,7 @@ test-suite unit-tests UnitTests.Distribution.Compat.Graph UnitTests.Distribution.Compat.Time UnitTests.Distribution.Described + UnitTests.Distribution.PackageDescription.Check UnitTests.Distribution.PkgconfigVersion UnitTests.Distribution.Simple.Command UnitTests.Distribution.Simple.Glob @@ -58,9 +65,10 @@ test-suite unit-tests , Cabal-described , Cabal-syntax , Cabal-QuickCheck + , Cabal-tests , containers , deepseq - , Diff >=0.4 && <0.5 + , Diff >=0.4 && <0.6 , directory , filepath , integer-logarithms >=1.0.2 && <1.1 @@ -68,7 +76,7 @@ test-suite unit-tests , QuickCheck >=2.14 && <2.15 , rere >=0.1 && <0.3 , tagged - , tasty >=1.2.3 && <1.5 + , tasty >=1.2.3 && <1.6 , tasty-hunit , tasty-quickcheck , temporary @@ -84,14 +92,14 @@ test-suite parser-tests main-is: ParserTests.hs build-depends: base - , base-compat >=0.11.0 && <0.13 + , base-compat >=0.11.0 && <0.14 , bytestring , Cabal-syntax , Cabal-tree-diff - , Diff >=0.4 && <0.5 + , Diff >=0.4 && <0.6 , directory , filepath - , tasty >=1.2.3 && <1.5 + , tasty >=1.2.3 && <1.6 , tasty-golden >=2.3.1.1 && <2.4 , tasty-hunit , tasty-quickcheck @@ -109,10 +117,10 @@ test-suite check-tests , bytestring , Cabal , Cabal-syntax - , Diff >=0.4 && <0.5 + , Diff >=0.4 && <0.6 , directory , filepath - , tasty >=1.2.3 && <1.5 + , tasty >=1.2.3 && <1.6 , tasty-expected-failure , tasty-golden >=2.3.1.1 && <2.4 @@ -155,12 +163,12 @@ test-suite hackage-tests , filepath build-depends: - base-compat >=0.11.0 && <0.13 - , base-orphans >=0.6 && <0.9 + base-compat >=0.11.0 && <0.14 + , base-orphans >=0.6 && <0.10 , clock >=0.8 && <0.9 - , optparse-applicative >=0.13.2.0 && <0.17 + , optparse-applicative >=0.13.2.0 && <0.19 , stm >=2.4.5.0 && <2.6 - , tar >=0.5.0.3 && <0.6 + , tar >=0.5.0.3 && <0.7 , tree-diff >=0.1 && <0.4 ghc-options: -Wall -rtsopts -threaded @@ -178,7 +186,7 @@ test-suite rpmvercmp build-depends: QuickCheck - , tasty >=1.2.3 && <1.5 + , tasty >=1.2.3 && <1.6 , tasty-hunit , tasty-quickcheck @@ -197,10 +205,10 @@ test-suite no-thunks-test base , bytestring , Cabal-syntax - , tasty >=1.2.3 && <1.5 + , tasty >=1.2.3 && <1.6 , tasty-hunit -- this is test is buildable on old GHCs -- but it doesn't do anything. if impl(ghc >=8.6) - build-depends: nothunks >=0.1.1.0 && <0.2 + build-depends: nothunks >=0.1.1.0 && <0.3 diff --git a/Cabal-tests/LICENSE b/Cabal-tests/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/Cabal-tests/LICENSE +++ b/Cabal-tests/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/Cabal/src/Distribution/Utils/TempTestDir.hs b/Cabal-tests/lib/Test/Utils/TempTestDir.hs similarity index 98% rename from Cabal/src/Distribution/Utils/TempTestDir.hs rename to Cabal-tests/lib/Test/Utils/TempTestDir.hs index f4a2edf05f1..79e8635889f 100644 --- a/Cabal/src/Distribution/Utils/TempTestDir.hs +++ b/Cabal-tests/lib/Test/Utils/TempTestDir.hs @@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} -module Distribution.Utils.TempTestDir +module Test.Utils.TempTestDir ( withTestDir , removeDirectoryRecursiveHack ) where diff --git a/Cabal-tests/tests/CheckTests.hs b/Cabal-tests/tests/CheckTests.hs index ad9a93feebe..aa2f1e9b041 100644 --- a/Cabal-tests/tests/CheckTests.hs +++ b/Cabal-tests/tests/CheckTests.hs @@ -3,7 +3,6 @@ module Main ) where import Test.Tasty -import Test.Tasty.ExpectedFailure import Test.Tasty.Golden.Advanced (goldenTest) import Data.Algorithm.Diff (PolyDiff (..), getGroupedDiff) @@ -71,7 +70,7 @@ checkTest fp = cabalGoldenTest fp correct $ do -- Note: parser warnings are reported by `cabal check`, but not by -- D.PD.Check functionality. unlines (map (showPWarning fp) ws) ++ - unlines (map show (checkPackage gpd Nothing)) + unlines (map show (checkPackage gpd)) Left (_, errs) -> unlines $ map (("ERROR: " ++) . showPError fp) $ NE.toList errs where input = "tests" "ParserTests" "regressions" fp diff --git a/Cabal-tests/tests/HackageTests.hs b/Cabal-tests/tests/HackageTests.hs index df27938d221..9bff0ce05cc 100644 --- a/Cabal-tests/tests/HackageTests.hs +++ b/Cabal-tests/tests/HackageTests.hs @@ -196,7 +196,7 @@ parseCheckTest fpath bs = do Parsec.parseGenericPackageDescription bs case parsec of Right gpd -> do - let checks = checkPackage gpd Nothing + let checks = checkPackage gpd let w [] = 0 w _ = 1 diff --git a/Cabal-tests/tests/ParserTests/errors/forward-compat.errors b/Cabal-tests/tests/ParserTests/errors/forward-compat.errors index b027e266d20..d0d64f6abc2 100644 --- a/Cabal-tests/tests/ParserTests/errors/forward-compat.errors +++ b/Cabal-tests/tests/ParserTests/errors/forward-compat.errors @@ -1,2 +1,3 @@ VERSION: Just (mkVersion [99999,9]) -forward-compat.cabal:0:0: Unsupported cabal-version 99999.9. See https://github.com/haskell/cabal/issues/4899. +forward-compat.cabal:0:0: Unsupported cabal format version in cabal-version field: 99999.9. +Current cabal-version values are listed at https://cabal.readthedocs.io/en/stable/file-format-changelog.html. diff --git a/Cabal-tests/tests/ParserTests/errors/forward-compat2.errors b/Cabal-tests/tests/ParserTests/errors/forward-compat2.errors index 5270a2d53a3..fdbb38897e1 100644 --- a/Cabal-tests/tests/ParserTests/errors/forward-compat2.errors +++ b/Cabal-tests/tests/ParserTests/errors/forward-compat2.errors @@ -1,2 +1,3 @@ VERSION: Just (mkVersion [2,2]) -forward-compat2.cabal:5:1: cabal-version should be at the beginning of the file starting with spec version 2.2. See https://github.com/haskell/cabal/issues/4899 +forward-compat2.cabal:5:1: cabal-version should be at the beginning of the file starting with spec version 2.2. +Current cabal-version values are listed at https://cabal.readthedocs.io/en/stable/file-format-changelog.html. diff --git a/Cabal-tests/tests/ParserTests/errors/forward-compat3.errors b/Cabal-tests/tests/ParserTests/errors/forward-compat3.errors index 1affcf1174e..2d48094c986 100644 --- a/Cabal-tests/tests/ParserTests/errors/forward-compat3.errors +++ b/Cabal-tests/tests/ParserTests/errors/forward-compat3.errors @@ -1,2 +1,3 @@ VERSION: Just (mkVersion [99999,99]) -forward-compat3.cabal:0:0: Unsupported cabal-version 99999.99. See https://github.com/haskell/cabal/issues/4899. +forward-compat3.cabal:0:0: Unsupported cabal format version in cabal-version field: 99999.99. +Current cabal-version values are listed at https://cabal.readthedocs.io/en/stable/file-format-changelog.html. diff --git a/Cabal-tests/tests/ParserTests/regressions/all-upper-bound.check b/Cabal-tests/tests/ParserTests/regressions/all-upper-bound.check index 0da0e871ebb..2d3e1b0e332 100644 --- a/Cabal-tests/tests/ParserTests/regressions/all-upper-bound.check +++ b/Cabal-tests/tests/ParserTests/regressions/all-upper-bound.check @@ -1,6 +1,6 @@ -These packages miss upper bounds: +[missing-upper-bounds] On library, these packages miss upper bounds: + - somelib - alphalib - betalib - deltalib - - somelib -Please add them, using `cabal gen-bounds` for suggestions. For more information see: https://pvp.haskell.org/ +Please add them. There is more information at https://pvp.haskell.org/ diff --git a/Cabal-tests/tests/ParserTests/regressions/assoc-cpp-options.check b/Cabal-tests/tests/ParserTests/regressions/assoc-cpp-options.check index ed0edf29738..3ceb8ca855f 100644 --- a/Cabal-tests/tests/ParserTests/regressions/assoc-cpp-options.check +++ b/Cabal-tests/tests/ParserTests/regressions/assoc-cpp-options.check @@ -1 +1 @@ -'cpp-options: -traditional' is not a portable C-preprocessor flag. +[cpp-options] 'cpp-options: -traditional' is not a portable C-preprocessor flag. diff --git a/Cabal-tests/tests/ParserTests/regressions/bad-glob-syntax.check b/Cabal-tests/tests/ParserTests/regressions/bad-glob-syntax.check index 5b7a0a12552..75b74ffb41d 100644 --- a/Cabal-tests/tests/ParserTests/regressions/bad-glob-syntax.check +++ b/Cabal-tests/tests/ParserTests/regressions/bad-glob-syntax.check @@ -1,2 +1,2 @@ -In the 'extra-source-files' field: invalid file glob 'foo/blah-*.hs'. Wildcards '*' may only totally replace the file's base name, not only parts of it. -In the 'extra-source-files' field: invalid file glob 'foo/*/bar'. A wildcard '**' is only allowed as the final parent directory. Stars must not otherwise appear in the parent directories. +[glob-syntax-error] In the 'extra-source-files' field: invalid file glob 'foo/*/bar'. A wildcard '**' is only allowed as the final parent directory. Stars must not otherwise appear in the parent directories. +[glob-syntax-error] In the 'extra-source-files' field: invalid file glob 'foo/blah-*.hs'. Wildcards '*' may only totally replace the file's base name, not only parts of it. diff --git a/Cabal-tests/tests/ParserTests/regressions/cc-options-with-optimization.check b/Cabal-tests/tests/ParserTests/regressions/cc-options-with-optimization.check index 16cfdb25554..092e0018bac 100644 --- a/Cabal-tests/tests/ParserTests/regressions/cc-options-with-optimization.check +++ b/Cabal-tests/tests/ParserTests/regressions/cc-options-with-optimization.check @@ -1 +1 @@ -'cc-options: -O[n]' is generally not needed. When building with optimisations Cabal automatically adds '-O2' for C code. Setting it yourself interferes with the --disable-optimization flag. +[option-opt-c] 'cc-options: -O[n]' is generally not needed. When building with optimisations Cabal automatically adds '-O2' for C code. Setting it yourself interferes with the --disable-optimization flag. diff --git a/Cabal-tests/tests/ParserTests/regressions/cxx-options-with-optimization.check b/Cabal-tests/tests/ParserTests/regressions/cxx-options-with-optimization.check index 822bea388f5..04edbcc84dc 100644 --- a/Cabal-tests/tests/ParserTests/regressions/cxx-options-with-optimization.check +++ b/Cabal-tests/tests/ParserTests/regressions/cxx-options-with-optimization.check @@ -1 +1 @@ -'cxx-options: -O[n]' is generally not needed. When building with optimisations Cabal automatically adds '-O2' for C++ code. Setting it yourself interferes with the --disable-optimization flag. +[option-opt-c] 'cxx-options: -O[n]' is generally not needed. When building with optimisations Cabal automatically adds '-O2' for C++ code. Setting it yourself interferes with the --disable-optimization flag. diff --git a/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.cabal b/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.cabal index 5a019b281d2..eb0a14724dc 100644 --- a/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.cabal +++ b/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.cabal @@ -24,7 +24,7 @@ Flag UseBinary Description: Use the binary package for serializing keys. Library - build-depends: base >= 3 + build-depends: base < 3 if flag(UseBinary) build-depends: binary <10 CPP-Options: -DUSE_BINARY @@ -34,7 +34,7 @@ Library exposed-modules: Codec.Crypto.RSA Executable test_rsa - build-depends: base >= 3 + build-depends: base < 3 CPP-Options: -DRSA_TEST Main-Is: Test.hs Other-Modules: Codec.Crypto.RSA @@ -52,7 +52,7 @@ Executable warnings -- Increasing indentation is also possible if we use braces to delimit field contents. Executable warnings2 - build-depends: { base <5 } + build-depends: { base < 5 } main-is: { warnings2.hs } Other-Modules: FooBar @@ -62,9 +62,9 @@ flag splitBase Executable warnings3 if flag(splitBase) - build-depends: base >= 3 + build-depends: base < 3 else - build-depends: base < 3 + build-depends: base < 5 Main-Is: warnings3.hs Other-Modules: diff --git a/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.check b/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.check index 8fa4aa3b13e..3758134dd5d 100644 --- a/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.check +++ b/Cabal-tests/tests/ParserTests/regressions/decreasing-indentation.check @@ -1,2 +1,2 @@ decreasing-indentation.cabal:38:3: Inconsistent indentation. Indentation jumps at lines 38, 49, 56, 57, 69 -No 'main-is' field found for executable warnings +[no-main-is] No 'main-is' field found for executable warnings diff --git a/Cabal-tests/tests/ParserTests/regressions/denormalised-paths.check b/Cabal-tests/tests/ParserTests/regressions/denormalised-paths.check index 84eade4e941..341645e243d 100644 --- a/Cabal-tests/tests/ParserTests/regressions/denormalised-paths.check +++ b/Cabal-tests/tests/ParserTests/regressions/denormalised-paths.check @@ -1,11 +1,14 @@ -The 'subdir' field of a source-repository is not a good relative path: "trailing same directory segment: ." -The paths 'files/<>/*.txt', 'c/**/*.c', 'C:foo/bar', '||s' are invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". -'hs-source-dirs: ../../assoc/src' is a relative path outside of the source tree. This will not work when generating a tarball with 'sdist'. -'extra-source-files: files/**/*.txt/' is not a good relative path: "trailing slash" -'extra-source-files: files/../foo.txt' is not a good relative path: "parent directory segment: .." -'license-file: LICENSE2/' is not a good relative path: "trailing slash" -'license-file: .' is not a good relative path: "trailing dot segment" -'hs-source-dirs: src/.' is not a good relative path: "trailing same directory segment: ." -'hs-source-dirs: src/../src' is not a good relative path: "parent directory segment: .." -'hs-source-dirs: src/../../assoc/src' is not a good relative path: "parent directory segment: .." -'hs-source-dirs: ../../assoc/src' is not a good relative path: "parent directory segment: .." +[relative-path-outside] 'hs-source-dirs: ../../assoc/src' is a relative path outside of the source tree. This will not work when generating a tarball with 'sdist'. +[repo-malformed-subdir] The 'subdir' field of a source-repository is not a good relative path: "trailing same directory segment: ." +[malformed-relative-path] 'extra-source-files: files/**/*.txt/' is not a good relative path: "trailing slash" +[malformed-relative-path] 'extra-source-files: files/../foo.txt' is not a good relative path: "parent directory segment: .." +[malformed-relative-path] 'hs-source-dirs: ../../assoc/src' is not a good relative path: "parent directory segment: .." +[malformed-relative-path] 'hs-source-dirs: src/.' is not a good relative path: "trailing same directory segment: ." +[malformed-relative-path] 'hs-source-dirs: src/../../assoc/src' is not a good relative path: "parent directory segment: .." +[malformed-relative-path] 'hs-source-dirs: src/../src' is not a good relative path: "parent directory segment: .." +[malformed-relative-path] 'license-file: .' is not a good relative path: "trailing dot segment" +[malformed-relative-path] 'license-file: LICENSE2/' is not a good relative path: "trailing slash" +[invalid-path-win] The path 'C:foo/bar' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". +[invalid-path-win] The path 'c/**/*.c' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". +[invalid-path-win] The path 'files/<>/*.txt' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". +[invalid-path-win] The path '||s' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". diff --git a/Cabal-tests/tests/ParserTests/regressions/extensions-paths-5054.check b/Cabal-tests/tests/ParserTests/regressions/extensions-paths-5054.check index d6a6dac2aa2..a78df59976a 100644 --- a/Cabal-tests/tests/ParserTests/regressions/extensions-paths-5054.check +++ b/Cabal-tests/tests/ParserTests/regressions/extensions-paths-5054.check @@ -1 +1 @@ -Packages using RebindableSyntax with OverloadedStrings or OverloadedLists in default-extensions, in conjunction with the autogenerated module Paths_*, are known to cause compile failures with Cabal < 2.2. To use these default-extensions with a Paths_* autogen module, specify at least 'cabal-version: 2.2'. +[rebindable-clash-paths] Packages using RebindableSyntax with OverloadedStrings or OverloadedLists in default-extensions, in conjunction with the autogenerated module Paths_*, are known to cause compile failures with Cabal < 2.2. To use these default-extensions with a Paths_* autogen module, specify at least 'cabal-version: 2.2'. diff --git a/Cabal-tests/tests/ParserTests/regressions/ghc-option-j.check b/Cabal-tests/tests/ParserTests/regressions/ghc-option-j.check index 3643c13a0ec..cd88496c706 100644 --- a/Cabal-tests/tests/ParserTests/regressions/ghc-option-j.check +++ b/Cabal-tests/tests/ParserTests/regressions/ghc-option-j.check @@ -1,2 +1,2 @@ -'ghc-options: -j[N]' can make sense for specific user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. -'ghc-shared-options: -j[N]' can make sense for specific user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +[unneeded-j] 'ghc-options: -j[N]' can make sense for a particular user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +[unneeded-j] 'ghc-shared-options: -j[N]' can make sense for a particular user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. diff --git a/Cabal-tests/tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal b/Cabal-tests/tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal index 5ecfcd13e79..e4495d5116a 100644 --- a/Cabal-tests/tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal +++ b/Cabal-tests/tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal @@ -1,147 +1,147 @@ -name: haddock-api -version: 2.18.1 -synopsis: A documentation-generation tool for Haskell libraries -description: Haddock is a documentation-generation tool for Haskell - libraries -license: BSD3 -license-file: LICENSE -author: Simon Marlow, David Waern -maintainer: Alex Biehl , Simon Hengel , Mateusz Kowalczyk -homepage: http://www.haskell.org/haddock/ -bug-reports: https://github.com/haskell/haddock/issues -copyright: (c) Simon Marlow, David Waern -category: Documentation -build-type: Simple -cabal-version: >= 1.10 - -extra-source-files: - CHANGES.md - -data-dir: - resources -data-files: - html/solarized.css - html/haddock-util.js - html/highlight.js - html/Classic.theme/haskell_icon.gif - html/Classic.theme/minus.gif - html/Classic.theme/plus.gif - html/Classic.theme/xhaddock.css - html/Ocean.std-theme/hslogo-16.png - html/Ocean.std-theme/minus.gif - html/Ocean.std-theme/ocean.css - html/Ocean.std-theme/plus.gif - html/Ocean.std-theme/synopsis.png - latex/haddock.sty - -library - default-language: Haskell2010 - - -- this package typically supports only single major versions - build-depends: base ^>= 4.10.0 - , Cabal ^>= 2.0.0 - , ghc ^>= 8.2 - , ghc-paths ^>= 0.1.0.9 - , haddock-library == 1.4.4.* - , xhtml ^>= 3000.2.2 - - -- Versions for the dependencies below are transitively pinned by - -- the non-reinstallable `ghc` package and hence need no version - -- bounds - build-depends: array - , bytestring - , containers - , deepseq - , directory - , filepath - , ghc-boot - , transformers - - hs-source-dirs: src - - ghc-options: -funbox-strict-fields -Wall -fwarn-tabs -O2 - ghc-options: -Wall - if impl(ghc >= 8.0) - ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances - - exposed-modules: - Documentation.Haddock - - other-modules: - Haddock - Haddock.Interface - Haddock.Interface.Rename - Haddock.Interface.Create - Haddock.Interface.AttachInstances - Haddock.Interface.LexParseRn - Haddock.Interface.ParseModuleHeader - Haddock.Interface.Specialize - Haddock.Parser - Haddock.Utils - Haddock.Backends.Xhtml - Haddock.Backends.Xhtml.Decl - Haddock.Backends.Xhtml.DocMarkup - Haddock.Backends.Xhtml.Layout - Haddock.Backends.Xhtml.Names - Haddock.Backends.Xhtml.Themes - Haddock.Backends.Xhtml.Types - Haddock.Backends.Xhtml.Utils - Haddock.Backends.LaTeX - Haddock.Backends.HaddockDB - Haddock.Backends.Hoogle - Haddock.Backends.Hyperlinker - Haddock.Backends.Hyperlinker.Ast - Haddock.Backends.Hyperlinker.Parser - Haddock.Backends.Hyperlinker.Renderer - Haddock.Backends.Hyperlinker.Types - Haddock.Backends.Hyperlinker.Utils - Haddock.ModuleTree - Haddock.Types - Haddock.Doc - Haddock.Version - Haddock.InterfaceFile - Haddock.Options - Haddock.GhcUtils - Haddock.Syb - Haddock.Convert - Paths_haddock_api - - autogen-modules: - Paths_haddock_api - -test-suite spec - type: exitcode-stdio-1.0 - default-language: Haskell2010 - main-is: Spec.hs - ghc-options: -Wall - - hs-source-dirs: - test - , src - - -- NB: We only use a small subset of lib:haddock-api here, which - -- explains why this component has a smaller build-depends set - other-modules: - Haddock.Backends.Hyperlinker.ParserSpec - Haddock.Backends.Hyperlinker.Parser - Haddock.Backends.Hyperlinker.Types - - build-depends: - ghc ^>= 8.2 - , hspec ^>= 2.4.4 - , QuickCheck ^>= 2.10 - - -- Versions for the dependencies below are transitively pinned by - -- the non-reinstallable `ghc` package and hence need no version - -- bounds - build-depends: - base - , containers - - build-tool-depends: - hspec-discover:hspec-discover ^>= 2.4.4 - -source-repository head - type: git - subdir: haddock-api - location: https://github.com/haskell/haddock.git +name: haddock-api +version: 2.18.1 +synopsis: A documentation-generation tool for Haskell libraries +description: Haddock is a documentation-generation tool for Haskell + libraries +license: BSD3 +license-file: LICENSE +author: Simon Marlow, David Waern +maintainer: Alex Biehl , Simon Hengel , Mateusz Kowalczyk +homepage: http://www.haskell.org/haddock/ +bug-reports: https://github.com/haskell/haddock/issues +copyright: (c) Simon Marlow, David Waern +category: Documentation +build-type: Simple +cabal-version: >= 1.10 + +extra-source-files: + CHANGES.md + +data-dir: + resources +data-files: + html/solarized.css + html/haddock-util.js + html/highlight.js + html/Classic.theme/haskell_icon.gif + html/Classic.theme/minus.gif + html/Classic.theme/plus.gif + html/Classic.theme/xhaddock.css + html/Ocean.std-theme/hslogo-16.png + html/Ocean.std-theme/minus.gif + html/Ocean.std-theme/ocean.css + html/Ocean.std-theme/plus.gif + html/Ocean.std-theme/synopsis.png + latex/haddock.sty + +library + default-language: Haskell2010 + + -- this package typically supports only single major versions + build-depends: base ^>= 4.10.0 + , Cabal ^>= 2.0.0 + , ghc ^>= 8.2 + , ghc-paths ^>= 0.1.0.9 + , haddock-library == 1.4.4.* + , xhtml ^>= 3000.2.2 + + -- Versions for the dependencies below are transitively pinned by + -- the non-reinstallable `ghc` package and hence need no version + -- bounds + build-depends: array + , bytestring + , containers + , deepseq + , directory + , filepath + , ghc-boot + , transformers + + hs-source-dirs: src + + ghc-options: -funbox-strict-fields -Wall -fwarn-tabs -O2 + ghc-options: -Wall + if impl(ghc >= 8.0) + ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances + + exposed-modules: + Documentation.Haddock + + other-modules: + Haddock + Haddock.Interface + Haddock.Interface.Rename + Haddock.Interface.Create + Haddock.Interface.AttachInstances + Haddock.Interface.LexParseRn + Haddock.Interface.ParseModuleHeader + Haddock.Interface.Specialize + Haddock.Parser + Haddock.Utils + Haddock.Backends.Xhtml + Haddock.Backends.Xhtml.Decl + Haddock.Backends.Xhtml.DocMarkup + Haddock.Backends.Xhtml.Layout + Haddock.Backends.Xhtml.Names + Haddock.Backends.Xhtml.Themes + Haddock.Backends.Xhtml.Types + Haddock.Backends.Xhtml.Utils + Haddock.Backends.LaTeX + Haddock.Backends.HaddockDB + Haddock.Backends.Hoogle + Haddock.Backends.Hyperlinker + Haddock.Backends.Hyperlinker.Ast + Haddock.Backends.Hyperlinker.Parser + Haddock.Backends.Hyperlinker.Renderer + Haddock.Backends.Hyperlinker.Types + Haddock.Backends.Hyperlinker.Utils + Haddock.ModuleTree + Haddock.Types + Haddock.Doc + Haddock.Version + Haddock.InterfaceFile + Haddock.Options + Haddock.GhcUtils + Haddock.Syb + Haddock.Convert + Paths_haddock_api + + autogen-modules: + Paths_haddock_api + +test-suite spec + type: exitcode-stdio-1.0 + default-language: Haskell2010 + main-is: Spec.hs + ghc-options: -Wall + + hs-source-dirs: + test + , src + + -- NB: We only use a small subset of lib:haddock-api here, which + -- explains why this component has a smaller build-depends set + other-modules: + Haddock.Backends.Hyperlinker.ParserSpec + Haddock.Backends.Hyperlinker.Parser + Haddock.Backends.Hyperlinker.Types + + build-depends: + ghc ^>= 8.2 + , hspec ^>= 2.4.4 + , QuickCheck ^>= 2.10 + + -- Versions for the dependencies below are transitively pinned by + -- the non-reinstallable `ghc` package and hence need no version + -- bounds + build-depends: + base + , containers + + build-tool-depends: + hspec-discover:hspec-discover ^>= 2.4.4 + +source-repository head + type: git + subdir: haddock-api + location: https://github.com/haskell/haddock.git diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.cabal b/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.cabal index 3b435bdd17d..800ff470e51 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.cabal +++ b/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.cabal @@ -4,7 +4,8 @@ version: 6288 build-type: Simple synopsis: default-language optionality category: Test -description: Field is introduced in 1.10, defaulted in 3.4 +description: Field is introduced in 1.10, defaulted in 3.4, + suggested in cabal 3.12. license: BSD3 license-file: LICENSE maintainer: Cabal Contributors diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.check b/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.check index 5246b90363e..64c183826b5 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.check +++ b/Cabal-tests/tests/ParserTests/regressions/issue-6288-d.check @@ -1 +1 @@ -Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +[no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6288-f.check b/Cabal-tests/tests/ParserTests/regressions/issue-6288-f.check index e69de29bb2d..424bf39bd42 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-6288-f.check +++ b/Cabal-tests/tests/ParserTests/regressions/issue-6288-f.check @@ -0,0 +1 @@ +[add-language] Without `default-language`, cabal will default to Haskell98, which is probably not what you want. Please add `default-language` to all targets. diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-774.check b/Cabal-tests/tests/ParserTests/regressions/issue-774.check index 27bea8fc70b..83f13c20c87 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-774.check +++ b/Cabal-tests/tests/ParserTests/regressions/issue-774.check @@ -1,6 +1,6 @@ issue-774.cabal:13:22: Packages with 'cabal-version: 1.12' or later should specify a specific version of the Cabal spec of the form 'cabal-version: x.y'. Use 'cabal-version: 1.12'. -No 'category' field. -No 'maintainer' field. -The 'license' field is missing or is NONE. -'ghc-options: -rtsopts' has no effect for libraries. It should only be used for executables. -'ghc-options: -with-rtsopts' has no effect for libraries. It should only be used for executables. +[option-rtsopts] 'ghc-options: -rtsopts' has no effect for libraries. It should only be used for executables. +[option-with-rtsopts] 'ghc-options: -with-rtsopts' has no effect for libraries. It should only be used for executables. +[no-category] No 'category' field. +[no-maintainer] No 'maintainer' field. +[license-none] The 'license' field is missing or is NONE. diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.cabal b/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.cabal index 477ec159ca9..3c63ca27a21 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.cabal +++ b/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.cabal @@ -1,26 +1,27 @@ -cabal-version: 3.4 -name: issue -version: 7776 -build-type: Simple -synopsis: duplicate-module check -category: Test -description: - With duplicate modules guarded by exclusive conditions, it should be buildable but should show a warning. - It *could* be smart enough to don't show the warning but we have to teach it about -license: BSD-3-Clause -license-file: LICENSE -maintainer: Cabal Contributors - --- Example taken from ghc-source-gen -library - exposed-modules: Foo - if impl(ghc<8.10) - other-modules: - GHC.Hs.Type - hs-source-dirs: - compat - if impl(ghc>=8.10) && impl(ghc<9.0) - other-modules: - GHC.Hs.Type - hs-source-dirs: +cabal-version: 3.4 +name: issue +version: 7776 +build-type: Simple +synopsis: duplicate-module check +category: Test +description: + With duplicate modules guarded by exclusive conditions, it should be buildable but should show a warning. + It *could* be smart enough to don't show the warning but we have to teach it about +license: BSD-3-Clause +license-file: LICENSE +maintainer: Cabal Contributors + +-- Example taken from ghc-source-gen +library + exposed-modules: Foo + if impl(ghc<8.10) + other-modules: + GHC.Hs.Type + hs-source-dirs: + compat + if impl(ghc>=8.10) && impl(ghc<9.0) + other-modules: + GHC.Hs.Type + hs-source-dirs: compat-8.10 + default-language: Haskell2010 diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.check b/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.check index f19bdb4a795..34e46f90787 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.check +++ b/Cabal-tests/tests/ParserTests/regressions/issue-7776-a.check @@ -1 +1 @@ -Potential duplicate modules (subject to conditionals) in library: GHC.Hs.Type +[maybe-duplicate-modules] Potential duplicate modules (subject to conditionals) in library: GHC.Hs.Type diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.cabal b/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.cabal index c3cde22e1e8..0a92165b208 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.cabal +++ b/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.cabal @@ -1,27 +1,29 @@ -cabal-version: 3.4 -name: issue -version: 7776 -build-type: Simple -synopsis: duplicate-module check -category: Test -description: With duplicate modules, even with overlapping conditions, it should be buildable but should show a warning. -license: BSD-3-Clause -license-file: LICENSE -maintainer: Cabal Contributors - --- Example taken from hashable-1.3.0 -library - exposed-modules: Foo - -- the base lower bound makes the package not buildable with ghc < 6.8 - -- but cabal is not smart enough to know it :-P - build-depends: base >= 4.5 && < 4.15 - -benchmark benchmarks - main-is: Benchmarks.hs - other-modules: - Data.Hashable.RandomSource - type: exitcode-stdio-1.0 - if impl(ghc >= 6.8) - Ghc-options: -fwarn-tabs - else - other-modules: Data.Hashable.RandomSource +cabal-version: 3.4 +name: issue +version: 7776 +build-type: Simple +synopsis: duplicate-module check +category: Test +description: With duplicate modules, even with overlapping conditions, it should be buildable but should show a warning. +license: BSD-3-Clause +license-file: LICENSE +maintainer: Cabal Contributors + +-- Example taken from hashable-1.3.0 +library + exposed-modules: Foo + -- the base lower bound makes the package not buildable with ghc < 6.8 + -- but cabal is not smart enough to know it :-P + build-depends: base >= 4.5 && < 4.15 + default-language: Haskell2010 + +benchmark benchmarks + main-is: Benchmarks.hs + other-modules: + Data.Hashable.RandomSource + type: exitcode-stdio-1.0 + if impl(ghc >= 6.8) + Ghc-options: -fwarn-tabs + else + other-modules: Data.Hashable.RandomSource + default-language: Haskell2010 diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.check b/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.check index d3839c3621d..197325be283 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.check +++ b/Cabal-tests/tests/ParserTests/regressions/issue-7776-b.check @@ -1 +1 @@ -Potential duplicate modules (subject to conditionals) in benchmark: Data.Hashable.RandomSource +[maybe-duplicate-modules] Potential duplicate modules (subject to conditionals) in benchmark: Data.Hashable.RandomSource diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.cabal b/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.cabal index 75d40d451dd..8ef8aa6af54 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.cabal +++ b/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.cabal @@ -1,19 +1,20 @@ -cabal-version: 3.4 -name: issue -version: 7776 -build-type: Simple -synopsis: duplicate-module check -category: Test -description: With duplicate modules not guarded by any condition, it should throw an error. -license: BSD-3-Clause -license-file: LICENSE -maintainer: Cabal Contributors - -library - exposed-modules: Foo - other-modules: - GHC.Hs.Type - hs-source-dirs: - compat - other-modules: - GHC.Hs.Type +cabal-version: 3.4 +name: issue +version: 7776 +build-type: Simple +synopsis: duplicate-module check +category: Test +description: With duplicate modules not guarded by any condition, it should throw an error. +license: BSD-3-Clause +license-file: LICENSE +maintainer: Cabal Contributors + +library + exposed-modules: Foo + other-modules: + GHC.Hs.Type + hs-source-dirs: + compat + other-modules: + GHC.Hs.Type + default-language: Haskell2010 diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.check b/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.check index 911df91c797..1e360807071 100644 --- a/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.check +++ b/Cabal-tests/tests/ParserTests/regressions/issue-7776-c.check @@ -1 +1 @@ -Duplicate modules in library: GHC.Hs.Type +[duplicate-modules] Duplicate modules in library: GHC.Hs.Type diff --git a/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.check b/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.check index 281f2cd1c09..4dc5b5ed527 100644 --- a/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.check +++ b/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.check @@ -1,6 +1,6 @@ multiple-libs-2.cabal:17:3: The field "visibility" is available only since the Cabal specification version 3.0. This field will be ignored. -No 'category' field. -No 'maintainer' field. -No 'description' field. -The 'license' field is missing or is NONE. -The dependency 'build-depends: base' does not specify an upper bound on the version number. Each major release of the 'base' package changes the API in various ways and most packages will need some changes to compile with it. The recommended practice is to specify an upper bound on the version of the 'base' package. This ensures your package will continue to build when a new major version of the 'base' package is released. If you are not sure what upper bound to use then use the next major version. For example if you have tested your package with 'base' version 4.5 and 4.6 then use 'build-depends: base >= 4.5 && < 4.7'. +[no-category] No 'category' field. +[no-maintainer] No 'maintainer' field. +[no-description] No 'description' field. +[license-none] The 'license' field is missing or is NONE. +[missing-bounds-important] The dependency 'build-depends: base' does not specify an upper bound on the version number. Each major release of the 'base' package changes the API in various ways and most packages will need some changes to compile with it. The recommended practice is to specify an upper bound on the version of the 'base' package. This ensures your package will continue to build when a new major version of the 'base' package is released. If you are not sure what upper bound to use then use the next major version. For example if you have tested your package with 'base' version 4.5 and 4.6 then use 'build-depends: base >= 4.5 && < 4.7'. diff --git a/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.check b/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.check index aa57fe96240..6414561ee0c 100644 --- a/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.check +++ b/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.check @@ -1,6 +1,6 @@ -No 'category' field. -No 'maintainer' field. -No 'description' field. -The 'license' field is missing or is NONE. -Suspicious flag names: 無. To avoid ambiguity in command line interfaces, flag shouldn't start with a dash. Also for better compatibility, flag names shouldn't contain non-ascii characters. -Non ascii custom fields: x-無. For better compatibility, custom field names shouldn't contain non-ascii characters. +[no-category] No 'category' field. +[no-maintainer] No 'maintainer' field. +[no-description] No 'description' field. +[license-none] The 'license' field is missing or is NONE. +[suspicious-flag] Suspicious flag names: 無. To avoid ambiguity in command line interfaces, a flag shouldn't start with a dash. Also for better compatibility, flag names shouldn't contain non-ascii characters. +[non-ascii] Non ascii custom fields: x-無. For better compatibility, custom field names shouldn't contain non-ascii characters. diff --git a/Cabal-tests/tests/ParserTests/regressions/pre-1.6-glob.check b/Cabal-tests/tests/ParserTests/regressions/pre-1.6-glob.check index 3c69e99a323..6f653531c14 100644 --- a/Cabal-tests/tests/ParserTests/regressions/pre-1.6-glob.check +++ b/Cabal-tests/tests/ParserTests/regressions/pre-1.6-glob.check @@ -1 +1 @@ -In the 'extra-source-files' field: invalid file glob 'foo/*.hs'. Using star wildcards requires 'cabal-version: >= 1.6'. Alternatively if you require compatibility with earlier Cabal versions then list all the files explicitly. +[glob-syntax-error] In the 'extra-source-files' field: invalid file glob 'foo/*.hs'. Using star wildcards requires 'cabal-version: >= 1.6'. Alternatively if you require compatibility with earlier Cabal versions then list all the files explicitly. diff --git a/Cabal-tests/tests/ParserTests/regressions/pre-2.4-globstar.check b/Cabal-tests/tests/ParserTests/regressions/pre-2.4-globstar.check index 331d5a0ade9..00cf186a699 100644 --- a/Cabal-tests/tests/ParserTests/regressions/pre-2.4-globstar.check +++ b/Cabal-tests/tests/ParserTests/regressions/pre-2.4-globstar.check @@ -1,3 +1,3 @@ -In the 'data-files' field: invalid file glob 'foo/**/*.dat'. Using the double-star syntax requires 'cabal-version: 2.4' or greater. Alternatively, for compatibility with earlier Cabal versions, list the included directories explicitly. -In the 'extra-source-files' field: invalid file glob 'foo/**/*.hs'. Using the double-star syntax requires 'cabal-version: 2.4' or greater. Alternatively, for compatibility with earlier Cabal versions, list the included directories explicitly. -In the 'extra-doc-files' field: invalid file glob 'foo/**/*.html'. Using the double-star syntax requires 'cabal-version: 2.4' or greater. Alternatively, for compatibility with earlier Cabal versions, list the included directories explicitly. +[glob-syntax-error] In the 'data-files' field: invalid file glob 'foo/**/*.dat'. Using the double-star syntax requires 'cabal-version: 2.4' or greater. Alternatively, for compatibility with earlier Cabal versions, list the included directories explicitly. +[glob-syntax-error] In the 'extra-doc-files' field: invalid file glob 'foo/**/*.html'. Using the double-star syntax requires 'cabal-version: 2.4' or greater. Alternatively, for compatibility with earlier Cabal versions, list the included directories explicitly. +[glob-syntax-error] In the 'extra-source-files' field: invalid file glob 'foo/**/*.hs'. Using the double-star syntax requires 'cabal-version: 2.4' or greater. Alternatively, for compatibility with earlier Cabal versions, list the included directories explicitly. diff --git a/Cabal-tests/tests/ParserTests/regressions/pre-3.8-globstar-literal.check b/Cabal-tests/tests/ParserTests/regressions/pre-3.8-globstar-literal.check index 73250aca7aa..98c6eebac9e 100644 --- a/Cabal-tests/tests/ParserTests/regressions/pre-3.8-globstar-literal.check +++ b/Cabal-tests/tests/ParserTests/regressions/pre-3.8-globstar-literal.check @@ -1 +1 @@ -In the 'extra-source-files' field: invalid file glob 'foo/**/bar'. Prior to 'cabal-version: 3.8' if a wildcard '**' is used as a parent directory, the file's base name must be a wildcard '*'. +[glob-syntax-error] In the 'extra-source-files' field: invalid file glob 'foo/**/bar'. Prior to 'cabal-version: 3.8' if a wildcard '**' is used as a parent directory, the file's base name must be a wildcard '*'. diff --git a/Cabal-tests/tests/ParserTests/regressions/public-multilib-1.check b/Cabal-tests/tests/ParserTests/regressions/public-multilib-1.check index 3d4f13970d7..c1ca12187d8 100644 --- a/Cabal-tests/tests/ParserTests/regressions/public-multilib-1.check +++ b/Cabal-tests/tests/ParserTests/regressions/public-multilib-1.check @@ -1,2 +1,2 @@ -No 'maintainer' field. -No 'description' field. +[no-maintainer] No 'maintainer' field. +[no-description] No 'description' field. diff --git a/Cabal-tests/tests/ParserTests/regressions/public-multilib-2.check b/Cabal-tests/tests/ParserTests/regressions/public-multilib-2.check index 3d4f13970d7..c1ca12187d8 100644 --- a/Cabal-tests/tests/ParserTests/regressions/public-multilib-2.check +++ b/Cabal-tests/tests/ParserTests/regressions/public-multilib-2.check @@ -1,2 +1,2 @@ -No 'maintainer' field. -No 'description' field. +[no-maintainer] No 'maintainer' field. +[no-description] No 'description' field. diff --git a/Cabal-tests/tests/UnitTests.hs b/Cabal-tests/tests/UnitTests.hs index cf4128c05c9..cc0099175a8 100644 --- a/Cabal-tests/tests/UnitTests.hs +++ b/Cabal-tests/tests/UnitTests.hs @@ -15,6 +15,7 @@ import Distribution.Compat.Time import qualified UnitTests.Distribution.Compat.Time import qualified UnitTests.Distribution.Compat.Graph +import qualified UnitTests.Distribution.PackageDescription.Check import qualified UnitTests.Distribution.Simple.Command import qualified UnitTests.Distribution.Simple.Glob import qualified UnitTests.Distribution.Simple.Program.GHC @@ -62,6 +63,8 @@ tests mtimeChangeCalibrated = UnitTests.Distribution.Utils.Json.tests , testGroup "Distribution.Utils.NubList" UnitTests.Distribution.Utils.NubList.tests + , testGroup "Distribution.PackageDescription.Check" + UnitTests.Distribution.PackageDescription.Check.tests , testGroup "Distribution.Utils.ShortText" UnitTests.Distribution.Utils.ShortText.tests , testGroup "Distribution.System" diff --git a/Cabal-tests/tests/UnitTests/Distribution/PackageDescription/Check.hs b/Cabal-tests/tests/UnitTests/Distribution/PackageDescription/Check.hs new file mode 100644 index 00000000000..58f75602644 --- /dev/null +++ b/Cabal-tests/tests/UnitTests/Distribution/PackageDescription/Check.hs @@ -0,0 +1,37 @@ +-- For the deprecated import of Distribution.Compat.Prelude.Internal +{-# OPTIONS_GHC -Wwarn=deprecations #-} + +module UnitTests.Distribution.PackageDescription.Check (tests) where + +import Distribution.Compat.Prelude.Internal +import Prelude () + +import Distribution.PackageDescription.Check + +import Test.Tasty +import Test.Tasty.HUnit + +-- instances +import Test.QuickCheck.Instances.Cabal () + + +tests :: [TestTree] +tests = + [ testCase "Unique ignore strings" (uniqueNames @?= True) + , testCase "Short ignore identifiers" (longerThan @?= []) + , testCase "Parsimonious '-' use" (usingTooManyDashes @?= []) + ] + where + allExplanationIdStrings :: [CheckExplanationIDString] + allExplanationIdStrings = map ppCheckExplanationId [minBound..maxBound] + + uniqueNames :: Bool + uniqueNames = length allExplanationIdStrings == length (nub allExplanationIdStrings) + + longerThan :: [CheckExplanationIDString] + longerThan = filter ((>25). length) allExplanationIdStrings + + usingTooManyDashes :: [CheckExplanationIDString] + usingTooManyDashes = filter ((>2) . length . filter (=='-')) + allExplanationIdStrings + diff --git a/Cabal-tests/tests/UnitTests/Distribution/SPDX.hs b/Cabal-tests/tests/UnitTests/Distribution/SPDX.hs index 2f598553eba..c0b339e83af 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/SPDX.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/SPDX.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-deprecations #-} module UnitTests.Distribution.SPDX (spdxTests) where @@ -12,14 +11,6 @@ import Distribution.Pretty (prettyShow) import Test.Tasty import Test.Tasty.QuickCheck -#if MIN_VERSION_binary(0,7,0) -import qualified Data.Binary as Binary -import qualified Data.Binary.Get as Binary -import qualified Data.Binary.Put as Binary -import qualified Data.ByteString.Lazy as LBS -import GHC.Generics (to, from) -#endif - import Test.QuickCheck.Instances.Cabal () spdxTests :: [TestTree] @@ -43,29 +34,6 @@ licenseExceptionIdRoundtrip x = counterexample (prettyShow x) $ Right x === eitherParsec (prettyShow x) -#if MIN_VERSION_binary(0,7,0) -licenseExceptionIdBinaryPut :: LicenseExceptionId -> Property -licenseExceptionIdBinaryPut x = - Binary.runPut (Binary.put x) - === - Binary.runPut (Binary.gput (from x)) - -licenseExceptionIdBinaryGet :: Word8 -> Property -licenseExceptionIdBinaryGet w0 = - stripMsg id (Binary.runGetOrFail Binary.get bs) - === - stripMsg to (Binary.runGetOrFail Binary.gget bs) - where - bs = LBS.pack [w0] - - stripMsg - :: (a -> LicenseExceptionId) - -> Either (x, y, String) (x, y, a) - -> Either (x, y) (x, y, LicenseExceptionId) - stripMsg _ (Left (x,y,_)) = Left (x,y) - stripMsg f (Right (x,y,t)) = Right (x,y,f t) -#endif - licenseRefRoundtrip :: LicenseRef -> Property licenseRefRoundtrip x = counterexample (prettyShow x) $ diff --git a/Cabal-tests/tests/UnitTests/Distribution/Simple/Glob.hs b/Cabal-tests/tests/UnitTests/Distribution/Simple/Glob.hs index 22e3af46843..fce1ffbc050 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Simple/Glob.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Simple/Glob.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE LambdaCase #-} module UnitTests.Distribution.Simple.Glob ( tests ) where @@ -54,7 +55,7 @@ compatibilityTests version = [ testCase "literal match" $ testMatches "foo/a" [GlobMatch "foo/a"] , testCase "literal no match on prefix" $ - testMatches "foo/c.html" [] + testMatches "foo/c.html" [GlobMatchesDirectory "foo/c.html"] , testCase "literal no match on suffix" $ testMatches "foo/a.html" [GlobMatch "foo/a.html"] , testCase "literal no prefix" $ @@ -64,7 +65,7 @@ compatibilityTests version = , testCase "glob" $ testMatches "*.html" [GlobMatch "a.html", GlobMatch "b.html"] , testCase "glob in subdir" $ - testMatches "foo/*.html" [GlobMatch "foo/a.html", GlobMatch "foo/b.html"] + testMatches "foo/*.html" [GlobMatchesDirectory "foo/c.html", GlobMatch "foo/b.html", GlobMatch "foo/a.html"] , testCase "glob multiple extensions" $ testMatches "foo/*.html.gz" [GlobMatch "foo/a.html.gz", GlobMatch "foo/b.html.gz"] , testCase "glob in deep subdir" $ @@ -101,13 +102,16 @@ testMatchesVersion version pat expected = do where isEqual = (==) `on` (sort . fmap (fmap normalise)) checkPure globPat = do - let actual = mapMaybe (fileGlobMatches globPat) sampleFileNames - unless (sort expected == sort actual) $ + let actual = mapMaybe (\p -> (p <$) <$> fileGlobMatches version globPat p) sampleFileNames + -- We drop directory matches from the expected results since the pure + -- check can't identify that kind of match. + expected' = filter (\case GlobMatchesDirectory _ -> False; _ -> True) expected + unless (sort expected' == sort actual) $ assertFailure $ "Unexpected result (pure matcher): " ++ show actual checkIO globPat = withSystemTempDirectory "globstar-sample" $ \tmpdir -> do makeSampleFiles tmpdir - actual <- runDirFileGlob Verbosity.normal tmpdir globPat + actual <- runDirFileGlob Verbosity.normal (Just version) tmpdir globPat unless (isEqual actual expected) $ assertFailure $ "Unexpected result (impure matcher): " ++ show actual diff --git a/Cabal-tests/tests/UnitTests/Distribution/Simple/Program/GHC.hs b/Cabal-tests/tests/UnitTests/Distribution/Simple/Program/GHC.hs index 8244285915f..d66b2eb4316 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Simple/Program/GHC.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Simple/Program/GHC.hs @@ -53,12 +53,12 @@ tests = testGroup "Distribution.Simple.Program.GHC" , compilerCompat = [] , compilerLanguages = [] , compilerExtensions = [] - , compilerProperties = Map.singleton "Support parallel --make" "YES" + , compilerProperties = Map.singleton "Support parallel --make" "YES" }) (Platform X86_64 Linux) (mempty { ghcOptNumJobs = Flag (NumJobs (Just 4)) }) assertListEquals flags ["-j4", "-clear-package-db"] - ] + ] ] assertListEquals :: (Eq a, Show a) => [a] -> [a] -> Assertion @@ -191,34 +191,3 @@ options_9_0_affects :: [String] options_9_0_affects = [ "-fcmm-static-pred" ] - -------------------------------------------------------------------------------- --- GHC-9.2 -------------------------------------------------------------------------------- - -options_9_2_all :: [String] -options_9_2_all = - [ "-dynohi" - , "-ddump-c-backend" - , "-ddump-stg-from-core" - , "-ddump-stg" - , "-ddump-faststrings" - , "--run" - , "-ffamily-application-cache" - , "-fno-family-application-cache" - ] ++ options_9_2_affects - -options_9_2_affects :: [String] -options_9_2_affects = - [ "-fprof-callers" - , "-funfolding-case-threshold" - , "-funfolding-case-scaling" - , "-fdistinct-constructor-tables" - , "-finfo-table-map" - , "-fexpose-internal-symbols" - , "-finline-generics" - , "-finline-generics-aggressively" - , "-fno-expose-internal-symbols" - , "-fno-inline-generics" - , "-fno-inline-generics-aggressively" - ] diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs index 900aedc0ca3..a6142498ae2 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs @@ -10,10 +10,8 @@ import Test.Tasty.HUnit (testCase, (@?=), Assertion) import Distribution.SPDX.License (License) import Distribution.Types.VersionRange (VersionRange) -#if MIN_VERSION_base(4,7,0) import Distribution.Types.GenericPackageDescription (GenericPackageDescription) import Distribution.Types.LocalBuildInfo (LocalBuildInfo) -#endif import UnitTests.Orphans () @@ -25,16 +23,25 @@ tests = testGroup "Distribution.Utils.Structured" , testCase "SPDX.License" $ md5Check (Proxy :: Proxy License) 0xd3d4a09f517f9f75bc3d16370d5a853a -- The difference is in encoding of newtypes -#if MIN_VERSION_base(4,7,0) - , testCase "GenericPackageDescription" $ - md5Check (Proxy :: Proxy GenericPackageDescription) 0x6ad1e12c6f88291e9b8c131d239eda70 - , testCase "LocalBuildInfo" $ - md5Check (Proxy :: Proxy LocalBuildInfo) 0xbc7ac84a9bc43345c812af222c3e5ba0 -#endif + , testCase "GenericPackageDescription" $ md5CheckGenericPackageDescription (Proxy :: Proxy GenericPackageDescription) + , testCase "LocalBuildInfo" $ md5CheckLocalBuildInfo (Proxy :: Proxy LocalBuildInfo) ] --- -------------------------------------------------------------------- -- --- utils - md5Check :: Structured a => Proxy a -> Integer -> Assertion md5Check proxy md5Int = structureHash proxy @?= md5FromInteger md5Int + +md5CheckGenericPackageDescription :: Proxy GenericPackageDescription -> Assertion +md5CheckGenericPackageDescription proxy = md5Check proxy +#if MIN_VERSION_base(4,19,0) + 0x7559521b9eb2e2fa4a608a86c629dc17 +#else + 0xa78ea118e2e29b5809d359c9431df3ba +#endif + +md5CheckLocalBuildInfo :: Proxy LocalBuildInfo -> Assertion +md5CheckLocalBuildInfo proxy = md5Check proxy +#if MIN_VERSION_base(4,19,0) + 0x8a8e81b52a34b8610acdcd0b9d488940 +#else + 0xb53fbd58281a6f329f7b659d91fcd86e +#endif diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal index da7eeda354c..eb3b6e055f9 100644 --- a/Cabal/Cabal.cabal +++ b/Cabal/Cabal.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: Cabal version: 3.11.0.0 -copyright: 2003-2023, Cabal Development Team (see AUTHORS file) +copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team @@ -21,7 +21,7 @@ build-type: Simple -- If we use a new Cabal feature, this needs to be changed to Custom so -- we can bootstrap. -extra-source-files: +extra-doc-files: README.md ChangeLog.md source-repository head @@ -41,13 +41,13 @@ library containers >= 0.5.0.0 && < 0.8, deepseq >= 1.3.0.1 && < 1.6, directory >= 1.2 && < 1.4, - filepath >= 1.3.0.1 && < 1.5, + filepath >= 1.3.0.1 && < 1.6, pretty >= 1.1.1 && < 1.2, process >= 1.2.1.0 && < 1.7, time >= 1.4.0.1 && < 1.13 if os(windows) - build-depends: Win32 >= 2.3.0.0 && < 2.14 + build-depends: Win32 >= 2.3.0.0 && < 2.15 else build-depends: unix >= 2.6.0.0 && < 2.9 @@ -59,6 +59,9 @@ library if impl(ghc >= 8.0) && impl(ghc < 8.8) ghc-options: -Wnoncanonical-monadfail-instances + if impl(ghc >= 8.10) + ghc-options: -Wunused-packages + exposed-modules: Distribution.Backpack.Configure Distribution.Backpack.ComponentsGraph @@ -88,6 +91,7 @@ library Distribution.Simple Distribution.Simple.Bench Distribution.Simple.Build + Distribution.Simple.Build.Inputs Distribution.Simple.Build.Macros Distribution.Simple.Build.PackageInfoModule Distribution.Simple.Build.PathsModule @@ -104,6 +108,7 @@ library Distribution.Simple.GHCJS Distribution.Simple.Haddock Distribution.Simple.Glob + Distribution.Simple.Glob.Internal Distribution.Simple.HaskellSuite Distribution.Simple.Hpc Distribution.Simple.Install @@ -113,6 +118,7 @@ library Distribution.Simple.PackageDescription Distribution.Simple.PackageIndex Distribution.Simple.PreProcess + Distribution.Simple.PreProcess.Types Distribution.Simple.PreProcess.Unlit Distribution.Simple.Program Distribution.Simple.Program.Ar @@ -146,6 +152,7 @@ library Distribution.Types.DumpBuildInfo Distribution.Types.PackageName.Magic Distribution.Types.ComponentLocalBuildInfo + Distribution.Types.LocalBuildConfig Distribution.Types.LocalBuildInfo Distribution.Types.TargetInfo Distribution.Types.GivenComponent @@ -153,7 +160,6 @@ library Distribution.Utils.Json Distribution.Utils.NubList Distribution.Utils.Progress - Distribution.Utils.TempTestDir Distribution.Verbosity Distribution.Verbosity.Internal @@ -305,7 +311,6 @@ library -- See also https://github.com/ekmett/transformers-compat/issues/35 transformers (>= 0.3 && < 0.4) || (>=0.4.1.0 && <0.7), mtl >= 2.1 && < 2.4, - text (>= 1.2.3.0 && < 1.3) || (>= 2.0 && < 2.2), parsec >= 3.1.13.0 && < 3.2 other-modules: @@ -322,9 +327,20 @@ library Distribution.Compat.SnocList Distribution.GetOpt Distribution.Lex + Distribution.PackageDescription.Check.Common + Distribution.PackageDescription.Check.Conditional + Distribution.PackageDescription.Check.Monad + Distribution.PackageDescription.Check.Paths + Distribution.PackageDescription.Check.Target + Distribution.PackageDescription.Check.Warning Distribution.Simple.Build.Macros.Z Distribution.Simple.Build.PackageInfoModule.Z Distribution.Simple.Build.PathsModule.Z + Distribution.Simple.GHC.Build + Distribution.Simple.GHC.Build.ExtraSources + Distribution.Simple.GHC.Build.Link + Distribution.Simple.GHC.Build.Modules + Distribution.Simple.GHC.Build.Utils Distribution.Simple.GHC.EnvironmentParser Distribution.Simple.GHC.Internal Distribution.Simple.GHC.ImplInfo diff --git a/Cabal/ChangeLog.md b/Cabal/ChangeLog.md index 34d046cc098..08d6aa838dc 100644 --- a/Cabal/ChangeLog.md +++ b/Cabal/ChangeLog.md @@ -1,3 +1,6 @@ +# 3.10.3.0 [Hécate](mailto:hecate+github@glitchbra.in) January 2024 +* See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.10.3.0.md + # 3.10.2.1 [Hécate](mailto:hecate+github@glitchbra.in) October 2023 * See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.10.2.1.md diff --git a/Cabal/LICENSE b/Cabal/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/Cabal/LICENSE +++ b/Cabal/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/Cabal/src/Distribution/Backpack/Configure.hs b/Cabal/src/Distribution/Backpack/Configure.hs index 54a66833715..8e9eb18ae6a 100644 --- a/Cabal/src/Distribution/Backpack/Configure.hs +++ b/Cabal/src/Distribution/Backpack/Configure.hs @@ -85,7 +85,7 @@ configureComponentLocalBuildInfos cid_flag pkg_descr (prePkgDeps, promisedPkgDeps) - flagAssignment + flags instantiate_with installedPackageSet comp = do @@ -123,7 +123,7 @@ configureComponentLocalBuildInfos graph1 <- toConfiguredComponents use_external_internal_deps - flagAssignment + flags deterministic ipid_flag cid_flag diff --git a/Cabal/src/Distribution/Make.hs b/Cabal/src/Distribution/Make.hs index 716033e42a3..82334d550f0 100644 --- a/Cabal/src/Distribution/Make.hs +++ b/Cabal/src/Distribution/Make.hs @@ -88,8 +88,9 @@ defaultMainArgs :: [String] -> IO () defaultMainArgs = defaultMainHelper defaultMainHelper :: [String] -> IO () -defaultMainHelper args = - case commandsRun (globalCommand commands) commands args of +defaultMainHelper args = do + command <- commandsRun (globalCommand commands) commands args + case command of CommandHelp help -> printHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs diff --git a/Cabal/src/Distribution/PackageDescription/Check.hs b/Cabal/src/Distribution/PackageDescription/Check.hs index 2c9806a1ae5..43f8bf0d2a4 100644 --- a/Cabal/src/Distribution/PackageDescription/Check.hs +++ b/Cabal/src/Distribution/PackageDescription/Check.hs @@ -1,10 +1,8 @@ -{-# LANGUAGE LambdaCase #-} - ------------------------------------------------------------------------------ +{-# LANGUAGE ScopedTypeVariables #-} -- | -- Module : Distribution.PackageDescription.Check --- Copyright : Lennart Kolmodin 2008 +-- Copyright : Lennart Kolmodin 2008, Francesco Ariis 2022 -- License : BSD3 -- -- Maintainer : cabal-devel@haskell.org @@ -25,64 +23,63 @@ module Distribution.PackageDescription.Check ( -- * Package Checking CheckExplanation (..) + , CheckExplanationID + , CheckExplanationIDString , PackageCheck (..) , checkPackage , checkConfiguredPackage , wrapParseWarning , ppPackageCheck + , ppCheckExplanationId , isHackageDistError + , filterPackageChecksById + , filterPackageChecksByIdString -- ** Checking package contents , checkPackageFiles + , checkPackageFilesGPD , checkPackageContent , CheckPackageContentOps (..) - , checkPackageFileNames ) where -import Data.Foldable (foldrM) import Distribution.Compat.Prelude import Prelude () -import Data.List (delete, group) +import Data.List (group) import Distribution.CabalSpecVersion import Distribution.Compat.Lens import Distribution.Compiler import Distribution.License -import Distribution.ModuleName (ModuleName) import Distribution.Package import Distribution.PackageDescription -import Distribution.PackageDescription.Configuration -import Distribution.Parsec.Warning (PWarning, showPWarning) +import Distribution.PackageDescription.Check.Common +import Distribution.PackageDescription.Check.Conditional +import Distribution.PackageDescription.Check.Monad +import Distribution.PackageDescription.Check.Paths +import Distribution.PackageDescription.Check.Target +import Distribution.PackageDescription.Check.Warning +import Distribution.Parsec.Warning (PWarning) import Distribution.Pretty (prettyShow) -import Distribution.Simple.BuildPaths (autogenPackageInfoModuleName, autogenPathsModuleName) -import Distribution.Simple.BuildToolDepends -import Distribution.Simple.CCompiler import Distribution.Simple.Glob + ( Glob + , GlobResult (..) + , globMatches + , parseFileGlob + , runDirFileGlob + ) import Distribution.Simple.Utils hiding (findPackageDesc, notice) -import Distribution.System -import Distribution.Types.ComponentRequestedSpec -import Distribution.Types.PackageName.Magic import Distribution.Utils.Generic (isAscii) import Distribution.Utils.Path + ( LicenseFile + , PackageDir + , SymbolicPath + , getSymbolicPath + ) import Distribution.Verbosity import Distribution.Version -import Language.Haskell.Extension -import System.FilePath - ( makeRelative - , normalise - , splitDirectories - , splitExtension - , splitPath - , takeExtension - , takeFileName - , (<.>) - , () - ) +import System.FilePath (splitExtension, takeFileName, (<.>), ()) -import qualified Control.Monad as CM import qualified Data.ByteString.Lazy as BS -import qualified Data.Map as Map -import qualified Distribution.Compat.DList as DList import qualified Distribution.SPDX as SPDX import qualified System.Directory as System @@ -92,1358 +89,552 @@ import qualified System.FilePath.Windows as FilePath.Windows (isValid) import qualified Data.Set as Set import qualified Distribution.Utils.ShortText as ShortText -import qualified Distribution.Types.BuildInfo.Lens as L import qualified Distribution.Types.GenericPackageDescription.Lens as L -import qualified Distribution.Types.PackageDescription.Lens as L + +import Control.Monad -- $setup -- >>> import Control.Arrow ((&&&)) --- ------------------------------------------------------------ - --- * Warning messages - --- ------------------------------------------------------------ - --- | Which stanza does `CheckExplanation` refer to? -data CEType = CETLibrary | CETExecutable | CETTest | CETBenchmark - deriving (Eq, Ord, Show) - --- | Pretty printing `CEType`. -ppCE :: CEType -> String -ppCE CETLibrary = "library" -ppCE CETExecutable = "executable" -ppCE CETTest = "test suite" -ppCE CETBenchmark = "benchmark" - --- | Which field does `CheckExplanation` refer to? -data CEField - = CEFCategory - | CEFMaintainer - | CEFSynopsis - | CEFDescription - | CEFSynOrDesc - deriving (Eq, Ord, Show) - --- | Pretty printing `CEField`. -ppCEField :: CEField -> String -ppCEField CEFCategory = "category" -ppCEField CEFMaintainer = "maintainer" -ppCEField CEFSynopsis = "synopsis" -ppCEField CEFDescription = "description" -ppCEField CEFSynOrDesc = "synopsis' or 'description" - --- | Explanations of 'PackageCheck`'s errors/warnings. -data CheckExplanation - = ParseWarning FilePath PWarning - | NoNameField - | NoVersionField - | NoTarget - | UnnamedInternal - | DuplicateSections [UnqualComponentName] - | IllegalLibraryName PackageDescription - | NoModulesExposed Library - | SignaturesCabal2 - | AutogenNotExposed - | AutogenIncludesNotIncluded - | NoMainIs Executable - | NoHsLhsMain - | MainCCabal1_18 - | AutogenNoOther CEType UnqualComponentName - | AutogenIncludesNotIncludedExe - | TestsuiteTypeNotKnown TestType - | TestsuiteNotSupported TestType - | BenchmarkTypeNotKnown BenchmarkType - | BenchmarkNotSupported BenchmarkType - | NoHsLhsMainBench - | InvalidNameWin PackageDescription - | ZPrefix - | NoBuildType - | NoCustomSetup - | UnknownCompilers [String] - | UnknownLanguages [String] - | UnknownExtensions [String] - | LanguagesAsExtension [String] - | DeprecatedExtensions [(Extension, Maybe Extension)] - | MissingField CEField - | SynopsisTooLong - | ShortDesc - | InvalidTestWith [Dependency] - | ImpossibleInternalDep [Dependency] - | ImpossibleInternalExe [ExeDependency] - | MissingInternalExe [ExeDependency] - | NONELicense - | NoLicense - | AllRightsReservedLicense - | LicenseMessParse PackageDescription - | UnrecognisedLicense String - | UncommonBSD4 - | UnknownLicenseVersion License [Version] - | NoLicenseFile - | UnrecognisedSourceRepo String - | MissingType - | MissingLocation - | MissingModule - | MissingTag - | SubdirRelPath - | SubdirGoodRelPath String - | OptFasm String - | OptViaC String - | OptHpc String - | OptProf String - | OptO String - | OptHide String - | OptMake String - | OptONot String - | OptOOne String - | OptOTwo String - | OptSplitSections String - | OptSplitObjs String - | OptWls String - | OptExts String - | OptRts String - | OptWithRts String - | COptONumber String String - | COptCPP String - | OptAlternatives String String [(String, String)] - | RelativeOutside String FilePath - | AbsolutePath String FilePath - | BadRelativePAth String FilePath String - | DistPoint (Maybe String) FilePath - | GlobSyntaxError String String - | RecursiveGlobInRoot String FilePath - | InvalidOnWin [FilePath] - | FilePathTooLong FilePath - | FilePathNameTooLong FilePath - | FilePathSplitTooLong FilePath - | FilePathEmpty - | CVTestSuite - | CVDefaultLanguage - | CVDefaultLanguageComponent - | CVExtraDocFiles - | CVMultiLib - | CVReexported - | CVMixins - | CVExtraFrameworkDirs - | CVDefaultExtensions - | CVExtensionsDeprecated - | CVSources - | CVExtraDynamic [[String]] - | CVVirtualModules - | CVSourceRepository - | CVExtensions CabalSpecVersion [Extension] - | CVCustomSetup - | CVExpliticDepsCustomSetup - | CVAutogenPaths - | CVAutogenPackageInfo - | GlobNoMatch String String - | GlobExactMatch String String FilePath - | GlobNoDir String String FilePath - | UnknownOS [String] - | UnknownArch [String] - | UnknownCompiler [String] - | BaseNoUpperBounds - | MissingUpperBounds [PackageName] - | SuspiciousFlagName [String] - | DeclaredUsedFlags (Set FlagName) (Set FlagName) - | NonASCIICustomField [String] - | RebindableClashPaths - | RebindableClashPackageInfo - | WErrorUnneeded String - | JUnneeded String - | FDeferTypeErrorsUnneeded String - | DynamicUnneeded String - | ProfilingUnneeded String - | UpperBoundSetup String - | DuplicateModule String [ModuleName] - | PotentialDupModule String [ModuleName] - | BOMStart FilePath - | NotPackageName FilePath String - | NoDesc - | MultiDesc [String] - | UnknownFile String (SymbolicPath PackageDir LicenseFile) - | MissingSetupFile - | MissingConfigureScript - | UnknownDirectory String FilePath - | MissingSourceControl - | MissingExpectedDocFiles Bool [FilePath] - | WrongFieldForExpectedDocFiles Bool String [FilePath] - deriving (Eq, Ord, Show) - --- | Wraps `ParseWarning` into `PackageCheck`. -wrapParseWarning :: FilePath -> PWarning -> PackageCheck -wrapParseWarning fp pw = PackageDistSuspicious (ParseWarning fp pw) - --- TODO: as Jul 2022 there is no severity indication attached PWarnType. --- Once that is added, we can output something more appropriate --- than PackageDistSuspicious for every parse warning. --- (see: Cabal-syntax/src/Distribution/Parsec/Warning.hs) - --- | Pretty printing `CheckExplanation`. -ppExplanation :: CheckExplanation -> String -ppExplanation (ParseWarning fp pp) = showPWarning fp pp -ppExplanation NoNameField = "No 'name' field." -ppExplanation NoVersionField = "No 'version' field." -ppExplanation NoTarget = - "No executables, libraries, tests, or benchmarks found. Nothing to do." -ppExplanation UnnamedInternal = - "Found one or more unnamed internal libraries. Only the non-internal" - ++ " library can have the same name as the package." -ppExplanation (DuplicateSections duplicateNames) = - "Duplicate sections: " - ++ commaSep (map unUnqualComponentName duplicateNames) - ++ ". The name of every library, executable, test suite," - ++ " and benchmark section in the package must be unique." -ppExplanation (IllegalLibraryName pkg) = - "Illegal internal library name " - ++ prettyShow (packageName pkg) - ++ ". Internal libraries cannot have the same name as the package." - ++ " Maybe you wanted a non-internal library?" - ++ " If so, rewrite the section stanza" - ++ " from 'library: '" - ++ prettyShow (packageName pkg) - ++ "' to 'library'." -ppExplanation (NoModulesExposed lib) = - showLibraryName (libName lib) ++ " does not expose any modules" -ppExplanation SignaturesCabal2 = - "To use the 'signatures' field the package needs to specify " - ++ "at least 'cabal-version: 2.0'." -ppExplanation AutogenNotExposed = - "An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'." -ppExplanation AutogenIncludesNotIncluded = - "An include in 'autogen-includes' is neither in 'includes' or " - ++ "'install-includes'." -ppExplanation (NoMainIs exe) = - "No 'main-is' field found for executable " ++ prettyShow (exeName exe) -ppExplanation NoHsLhsMain = - "The 'main-is' field must specify a '.hs' or '.lhs' file " - ++ "(even if it is generated by a preprocessor), " - ++ "or it may specify a C/C++/obj-C source file." -ppExplanation MainCCabal1_18 = - "The package uses a C/C++/obj-C source file for the 'main-is' field. " - ++ "To use this feature you need to specify 'cabal-version: 1.18' or" - ++ " higher." -ppExplanation (AutogenNoOther ct ucn) = - "On " - ++ ppCE ct - ++ " '" - ++ prettyShow ucn - ++ "' an 'autogen-module'" - ++ " is not on 'other-modules'" -ppExplanation AutogenIncludesNotIncludedExe = - "An include in 'autogen-includes' is not in 'includes'." -ppExplanation (TestsuiteTypeNotKnown tt) = - quote (prettyShow tt) - ++ " is not a known type of test suite. " - ++ "Either remove the 'type' field or use a known type. " - ++ "The known test suite types are: " - ++ commaSep (map prettyShow knownTestTypes) -ppExplanation (TestsuiteNotSupported tt) = - quote (prettyShow tt) - ++ " is not a supported test suite version. " - ++ "Either remove the 'type' field or use a known type. " - ++ "The known test suite types are: " - ++ commaSep (map prettyShow knownTestTypes) -ppExplanation (BenchmarkTypeNotKnown tt) = - quote (prettyShow tt) - ++ " is not a known type of benchmark. " - ++ "Either remove the 'type' field or use a known type. " - ++ "The known benchmark types are: " - ++ commaSep (map prettyShow knownBenchmarkTypes) -ppExplanation (BenchmarkNotSupported tt) = - quote (prettyShow tt) - ++ " is not a supported benchmark version. " - ++ "Either remove the 'type' field or use a known type. " - ++ "The known benchmark types are: " - ++ commaSep (map prettyShow knownBenchmarkTypes) -ppExplanation NoHsLhsMainBench = - "The 'main-is' field must specify a '.hs' or '.lhs' file " - ++ "(even if it is generated by a preprocessor)." -ppExplanation (InvalidNameWin pkg) = - "The package name '" - ++ prettyShow (packageName pkg) - ++ "' is " - ++ "invalid on Windows. Many tools need to convert package names to " - ++ "file names so using this name would cause problems." -ppExplanation ZPrefix = - "Package names with the prefix 'z-' are reserved by Cabal and " - ++ "cannot be used." -ppExplanation NoBuildType = - "No 'build-type' specified. If you do not need a custom Setup.hs or " - ++ "./configure script then use 'build-type: Simple'." -ppExplanation NoCustomSetup = - "Ignoring the 'custom-setup' section because the 'build-type' is " - ++ "not 'Custom'. Use 'build-type: Custom' if you need to use a " - ++ "custom Setup.hs script." -ppExplanation (UnknownCompilers unknownCompilers) = - "Unknown compiler " - ++ commaSep (map quote unknownCompilers) - ++ " in 'tested-with' field." -ppExplanation (UnknownLanguages unknownLanguages) = - "Unknown languages: " ++ commaSep unknownLanguages -ppExplanation (UnknownExtensions unknownExtensions) = - "Unknown extensions: " ++ commaSep unknownExtensions -ppExplanation (LanguagesAsExtension languagesUsedAsExtensions) = - "Languages listed as extensions: " - ++ commaSep languagesUsedAsExtensions - ++ ". Languages must be specified in either the 'default-language' " - ++ " or the 'other-languages' field." -ppExplanation (DeprecatedExtensions ourDeprecatedExtensions) = - "Deprecated extensions: " - ++ commaSep (map (quote . prettyShow . fst) ourDeprecatedExtensions) - ++ ". " - ++ unwords - [ "Instead of '" - ++ prettyShow ext - ++ "' use '" - ++ prettyShow replacement - ++ "'." - | (ext, Just replacement) <- ourDeprecatedExtensions - ] -ppExplanation (MissingField cef) = - "No '" ++ ppCEField cef ++ "' field." -ppExplanation SynopsisTooLong = - "The 'synopsis' field is rather long (max 80 chars is recommended)." -ppExplanation ShortDesc = - "The 'description' field should be longer than the 'synopsis' field. " - ++ "It's useful to provide an informative 'description' to allow " - ++ "Haskell programmers who have never heard about your package to " - ++ "understand the purpose of your package. " - ++ "The 'description' field content is typically shown by tooling " - ++ "(e.g. 'cabal info', Haddock, Hackage) below the 'synopsis' which " - ++ "serves as a headline. " - ++ "Please refer to for more details." -ppExplanation (InvalidTestWith testedWithImpossibleRanges) = - "Invalid 'tested-with' version range: " - ++ commaSep (map prettyShow testedWithImpossibleRanges) - ++ ". To indicate that you have tested a package with multiple " - ++ "different versions of the same compiler use multiple entries, " - ++ "for example 'tested-with: GHC==6.10.4, GHC==6.12.3' and not " - ++ "'tested-with: GHC==6.10.4 && ==6.12.3'." -ppExplanation (ImpossibleInternalDep depInternalLibWithImpossibleVersion) = - "The package has an impossible version range for a dependency on an " - ++ "internal library: " - ++ commaSep (map prettyShow depInternalLibWithImpossibleVersion) - ++ ". This version range does not include the current package, and must " - ++ "be removed as the current package's library will always be used." -ppExplanation (ImpossibleInternalExe depInternalExecWithImpossibleVersion) = - "The package has an impossible version range for a dependency on an " - ++ "internal executable: " - ++ commaSep (map prettyShow depInternalExecWithImpossibleVersion) - ++ ". This version range does not include the current package, and must " - ++ "be removed as the current package's executable will always be used." -ppExplanation (MissingInternalExe depInternalExeWithImpossibleVersion) = - "The package depends on a missing internal executable: " - ++ commaSep (map prettyShow depInternalExeWithImpossibleVersion) -ppExplanation NONELicense = "The 'license' field is missing or is NONE." -ppExplanation NoLicense = "The 'license' field is missing." -ppExplanation AllRightsReservedLicense = - "The 'license' is AllRightsReserved. Is that really what you want?" -ppExplanation (LicenseMessParse pkg) = - "Unfortunately the license " - ++ quote (prettyShow (license pkg)) - ++ " messes up the parser in earlier Cabal versions so you need to " - ++ "specify 'cabal-version: >= 1.4'. Alternatively if you require " - ++ "compatibility with earlier Cabal versions then use 'OtherLicense'." -ppExplanation (UnrecognisedLicense l) = - quote ("license: " ++ l) - ++ " is not a recognised license. The " - ++ "known licenses are: " - ++ commaSep (map prettyShow knownLicenses) -ppExplanation UncommonBSD4 = - "Using 'license: BSD4' is almost always a misunderstanding. 'BSD4' " - ++ "refers to the old 4-clause BSD license with the advertising " - ++ "clause. 'BSD3' refers the new 3-clause BSD license." -ppExplanation (UnknownLicenseVersion lic known) = - "'license: " - ++ prettyShow lic - ++ "' is not a known " - ++ "version of that license. The known versions are " - ++ commaSep (map prettyShow known) - ++ ". If this is not a mistake and you think it should be a known " - ++ "version then please file a ticket." -ppExplanation NoLicenseFile = "A 'license-file' is not specified." -ppExplanation (UnrecognisedSourceRepo kind) = - quote kind - ++ " is not a recognised kind of source-repository. " - ++ "The repo kind is usually 'head' or 'this'" -ppExplanation MissingType = - "The source-repository 'type' is a required field." -ppExplanation MissingLocation = - "The source-repository 'location' is a required field." -ppExplanation MissingModule = - "For a CVS source-repository, the 'module' is a required field." -ppExplanation MissingTag = - "For the 'this' kind of source-repository, the 'tag' is a required " - ++ "field. It should specify the tag corresponding to this version " - ++ "or release of the package." -ppExplanation SubdirRelPath = - "The 'subdir' field of a source-repository must be a relative path." -ppExplanation (SubdirGoodRelPath err) = - "The 'subdir' field of a source-repository is not a good relative path: " - ++ show err -ppExplanation (OptFasm fieldName) = - "'" - ++ fieldName - ++ ": -fasm' is unnecessary and will not work on CPU " - ++ "architectures other than x86, x86-64, ppc or sparc." -ppExplanation (OptViaC fieldName) = - "'" - ++ fieldName - ++ ": -fvia-C' is usually unnecessary. If your package " - ++ "needs -via-C for correctness rather than performance then it " - ++ "is using the FFI incorrectly and will probably not work with GHC " - ++ "6.10 or later." -ppExplanation (OptHpc fieldName) = - "'" - ++ fieldName - ++ ": -fhpc' is not necessary. Use the configure flag " - ++ " --enable-coverage instead." -ppExplanation (OptProf fieldName) = - "'" - ++ fieldName - ++ ": -prof' is not necessary and will lead to problems " - ++ "when used on a library. Use the configure flag " - ++ "--enable-library-profiling and/or --enable-profiling." -ppExplanation (OptO fieldName) = - "'" - ++ fieldName - ++ ": -o' is not needed. " - ++ "The output files are named automatically." -ppExplanation (OptHide fieldName) = - "'" - ++ fieldName - ++ ": -hide-package' is never needed. " - ++ "Cabal hides all packages." -ppExplanation (OptMake fieldName) = - "'" - ++ fieldName - ++ ": --make' is never needed. Cabal uses this automatically." -ppExplanation (OptONot fieldName) = - "'" - ++ fieldName - ++ ": -O0' is not needed. " - ++ "Use the --disable-optimization configure flag." -ppExplanation (OptOOne fieldName) = - "'" - ++ fieldName - ++ ": -O' is not needed. " - ++ "Cabal automatically adds the '-O' flag. " - ++ "Setting it yourself interferes with the --disable-optimization flag." -ppExplanation (OptOTwo fieldName) = - "'" - ++ fieldName - ++ ": -O2' is rarely needed. " - ++ "Check that it is giving a real benefit " - ++ "and not just imposing longer compile times on your users." -ppExplanation (OptSplitSections fieldName) = - "'" - ++ fieldName - ++ ": -split-sections' is not needed. " - ++ "Use the --enable-split-sections configure flag." -ppExplanation (OptSplitObjs fieldName) = - "'" - ++ fieldName - ++ ": -split-objs' is not needed. " - ++ "Use the --enable-split-objs configure flag." -ppExplanation (OptWls fieldName) = - "'" - ++ fieldName - ++ ": -optl-Wl,-s' is not needed and is not portable to" - ++ " all operating systems. Cabal 1.4 and later automatically strip" - ++ " executables. Cabal also has a flag --disable-executable-stripping" - ++ " which is necessary when building packages for some Linux" - ++ " distributions and using '-optl-Wl,-s' prevents that from working." -ppExplanation (OptExts fieldName) = - "Instead of '" - ++ fieldName - ++ ": -fglasgow-exts' it is preferable to use " - ++ "the 'extensions' field." -ppExplanation (OptRts fieldName) = - "'" - ++ fieldName - ++ ": -rtsopts' has no effect for libraries. It should " - ++ "only be used for executables." -ppExplanation (OptWithRts fieldName) = - "'" - ++ fieldName - ++ ": -with-rtsopts' has no effect for libraries. It " - ++ "should only be used for executables." -ppExplanation (COptONumber prefix label) = - "'" - ++ prefix - ++ ": -O[n]' is generally not needed. When building with " - ++ " optimisations Cabal automatically adds '-O2' for " - ++ label - ++ " code. Setting it yourself interferes with the" - ++ " --disable-optimization flag." -ppExplanation (COptCPP opt) = - "'cpp-options: " ++ opt ++ "' is not a portable C-preprocessor flag." -ppExplanation (OptAlternatives badField goodField flags) = - "Instead of " - ++ quote (badField ++ ": " ++ unwords badFlags) - ++ " use " - ++ quote (goodField ++ ": " ++ unwords goodFlags) - where - (badFlags, goodFlags) = unzip flags -ppExplanation (RelativeOutside field path) = - quote (field ++ ": " ++ path) - ++ " is a relative path outside of the source tree. " - ++ "This will not work when generating a tarball with 'sdist'." -ppExplanation (AbsolutePath field path) = - quote (field ++ ": " ++ path) - ++ " specifies an absolute path, but the " - ++ quote field - ++ " field must use relative paths." -ppExplanation (BadRelativePAth field path err) = - quote (field ++ ": " ++ path) - ++ " is not a good relative path: " - ++ show err -ppExplanation (DistPoint mfield path) = - incipit - ++ " points inside the 'dist' " - ++ "directory. This is not reliable because the location of this " - ++ "directory is configurable by the user (or package manager). In " - ++ "addition the layout of the 'dist' directory is subject to change " - ++ "in future versions of Cabal." - where - -- mfiled Nothing -> the path is inside `ghc-options` - incipit = - maybe - ("'ghc-options' path " ++ quote path) - (\field -> quote (field ++ ": " ++ path)) - mfield -ppExplanation (GlobSyntaxError field expl) = - "In the '" ++ field ++ "' field: " ++ expl -ppExplanation (RecursiveGlobInRoot field glob) = - "In the '" - ++ field - ++ "': glob '" - ++ glob - ++ "' starts at project root directory, this might " - ++ "include `.git/`, ``dist-newstyle/``, or other large directories!" -ppExplanation (InvalidOnWin paths) = - "The " - ++ quotes paths - ++ " invalid on Windows, which " - ++ "would cause portability problems for this package. Windows file " - ++ "names cannot contain any of the characters \":*?<>|\" and there " - ++ "a few reserved names including \"aux\", \"nul\", \"con\", " - ++ "\"prn\", \"com1-9\", \"lpt1-9\" and \"clock$\"." - where - quotes [failed] = "path " ++ quote failed ++ " is" - quotes failed = - "paths " - ++ intercalate ", " (map quote failed) - ++ " are" -ppExplanation (FilePathTooLong path) = - "The following file name is too long to store in a portable POSIX " - ++ "format tar archive. The maximum length is 255 ASCII characters.\n" - ++ "The file in question is:\n " - ++ path -ppExplanation (FilePathNameTooLong path) = - "The following file name is too long to store in a portable POSIX " - ++ "format tar archive. The maximum length for the name part (including " - ++ "extension) is 100 ASCII characters. The maximum length for any " - ++ "individual directory component is 155.\n" - ++ "The file in question is:\n " - ++ path -ppExplanation (FilePathSplitTooLong path) = - "The following file name is too long to store in a portable POSIX " - ++ "format tar archive. While the total length is less than 255 ASCII " - ++ "characters, there are unfortunately further restrictions. It has to " - ++ "be possible to split the file path on a directory separator into " - ++ "two parts such that the first part fits in 155 characters or less " - ++ "and the second part fits in 100 characters or less. Basically you " - ++ "have to make the file name or directory names shorter, or you could " - ++ "split a long directory name into nested subdirectories with shorter " - ++ "names.\nThe file in question is:\n " - ++ path -ppExplanation FilePathEmpty = - "Encountered a file with an empty name, something is very wrong! " - ++ "Files with an empty name cannot be stored in a tar archive or in " - ++ "standard file systems." -ppExplanation CVTestSuite = - "The 'test-suite' section is new in Cabal 1.10. " - ++ "Unfortunately it messes up the parser in older Cabal versions " - ++ "so you must specify at least 'cabal-version: >= 1.8', but note " - ++ "that only Cabal 1.10 and later can actually run such test suites." -ppExplanation CVDefaultLanguage = - "To use the 'default-language' field the package needs to specify " - ++ "at least 'cabal-version: >= 1.10'." -ppExplanation CVDefaultLanguageComponent = - "Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' " - ++ "must specify the 'default-language' field for each component (e.g. " - ++ "Haskell98 or Haskell2010). If a component uses different languages " - ++ "in different modules then list the other ones in the " - ++ "'other-languages' field." -ppExplanation CVExtraDocFiles = - "To use the 'extra-doc-files' field the package needs to specify " - ++ "'cabal-version: 1.18' or higher." -ppExplanation CVMultiLib = - "To use multiple 'library' sections or a named library section " - ++ "the package needs to specify at least 'cabal-version: 2.0'." -ppExplanation CVReexported = - "To use the 'reexported-module' field the package needs to specify " - ++ "'cabal-version: 1.22' or higher." -ppExplanation CVMixins = - "To use the 'mixins' field the package needs to specify " - ++ "at least 'cabal-version: 2.0'." -ppExplanation CVExtraFrameworkDirs = - "To use the 'extra-framework-dirs' field the package needs to specify" - ++ " 'cabal-version: 1.24' or higher." -ppExplanation CVDefaultExtensions = - "To use the 'default-extensions' field the package needs to specify " - ++ "at least 'cabal-version: >= 1.10'." -ppExplanation CVExtensionsDeprecated = - "For packages using 'cabal-version: >= 1.10' the 'extensions' " - ++ "field is deprecated. The new 'default-extensions' field lists " - ++ "extensions that are used in all modules in the component, while " - ++ "the 'other-extensions' field lists extensions that are used in " - ++ "some modules, e.g. via the {-# LANGUAGE #-} pragma." -ppExplanation CVSources = - "The use of 'asm-sources', 'cmm-sources', 'extra-bundled-libraries' " - ++ " and 'extra-library-flavours' requires the package " - ++ " to specify at least 'cabal-version: 3.0'." -ppExplanation (CVExtraDynamic flavs) = - "The use of 'extra-dynamic-library-flavours' requires the package " - ++ " to specify at least 'cabal-version: 3.0'. The flavours are: " - ++ commaSep (concat flavs) -ppExplanation CVVirtualModules = - "The use of 'virtual-modules' requires the package " - ++ " to specify at least 'cabal-version: 2.2'." -ppExplanation CVSourceRepository = - "The 'source-repository' section is new in Cabal 1.6. " - ++ "Unfortunately it messes up the parser in earlier Cabal versions " - ++ "so you need to specify 'cabal-version: >= 1.6'." -ppExplanation (CVExtensions version extCab12) = - "Unfortunately the language extensions " - ++ commaSep (map (quote . prettyShow) extCab12) - ++ " break the parser in earlier Cabal versions so you need to " - ++ "specify 'cabal-version: >= " - ++ showCabalSpecVersion version - ++ "'. Alternatively if you require compatibility with earlier " - ++ "Cabal versions then you may be able to use an equivalent " - ++ "compiler-specific flag." -ppExplanation CVCustomSetup = - "Packages using 'cabal-version: 1.24' or higher with 'build-type: Custom' " - ++ "must use a 'custom-setup' section with a 'setup-depends' field " - ++ "that specifies the dependencies of the Setup.hs script itself. " - ++ "The 'setup-depends' field uses the same syntax as 'build-depends', " - ++ "so a simple example would be 'setup-depends: base, Cabal'." -ppExplanation CVExpliticDepsCustomSetup = - "From version 1.24 cabal supports specifying explicit dependencies " - ++ "for Custom setup scripts. Consider using 'cabal-version: 1.24' or " - ++ "higher and adding a 'custom-setup' section with a 'setup-depends' " - ++ "field that specifies the dependencies of the Setup.hs script " - ++ "itself. The 'setup-depends' field uses the same syntax as " - ++ "'build-depends', so a simple example would be 'setup-depends: base, " - ++ "Cabal'." -ppExplanation CVAutogenPaths = - "Packages using 'cabal-version: 2.0' and the autogenerated " - ++ "module Paths_* must include it also on the 'autogen-modules' field " - ++ "besides 'exposed-modules' and 'other-modules'. This specifies that " - ++ "the module does not come with the package and is generated on " - ++ "setup. Modules built with a custom Setup.hs script also go here " - ++ "to ensure that commands like sdist don't fail." -ppExplanation CVAutogenPackageInfo = - "Packages using 'cabal-version: 2.0' and the autogenerated " - ++ "module PackageInfo_* must include it in 'autogen-modules' as well as" - ++ " 'exposed-modules' and 'other-modules'. This specifies that " - ++ "the module does not come with the package and is generated on " - ++ "setup. Modules built with a custom Setup.hs script also go here " - ++ "to ensure that commands like sdist don't fail." -ppExplanation (GlobNoMatch field glob) = - "In '" - ++ field - ++ "': the pattern '" - ++ glob - ++ "' does not" - ++ " match any files." -ppExplanation (GlobExactMatch field glob file) = - "In '" - ++ field - ++ "': the pattern '" - ++ glob - ++ "' does not" - ++ " match the file '" - ++ file - ++ "' because the extensions do not" - ++ " exactly match (e.g., foo.en.html does not exactly match *.html)." - ++ " To enable looser suffix-only matching, set 'cabal-version: 2.4' or" - ++ " higher." -ppExplanation (GlobNoDir field glob dir) = - "In '" - ++ field - ++ "': the pattern '" - ++ glob - ++ "' attempts to" - ++ " match files in the directory '" - ++ dir - ++ "', but there is no" - ++ " directory by that name." -ppExplanation (UnknownOS unknownOSs) = - "Unknown operating system name " ++ commaSep (map quote unknownOSs) -ppExplanation (UnknownArch unknownArches) = - "Unknown architecture name " ++ commaSep (map quote unknownArches) -ppExplanation (UnknownCompiler unknownImpls) = - "Unknown compiler name " ++ commaSep (map quote unknownImpls) -ppExplanation (MissingUpperBounds names) = - let separator = "\n - " - in "These packages miss upper bounds:" - ++ separator - ++ (intercalate separator (unPackageName <$> names)) - ++ "\n" - ++ "Please add them, using `cabal gen-bounds` for suggestions." - ++ " For more information see: " - ++ " https://pvp.haskell.org/" -ppExplanation BaseNoUpperBounds = - "The dependency 'build-depends: base' does not specify an upper " - ++ "bound on the version number. Each major release of the 'base' " - ++ "package changes the API in various ways and most packages will " - ++ "need some changes to compile with it. The recommended practice " - ++ "is to specify an upper bound on the version of the 'base' " - ++ "package. This ensures your package will continue to build when a " - ++ "new major version of the 'base' package is released. If you are " - ++ "not sure what upper bound to use then use the next major " - ++ "version. For example if you have tested your package with 'base' " - ++ "version 4.5 and 4.6 then use 'build-depends: base >= 4.5 && < 4.7'." -ppExplanation (SuspiciousFlagName invalidFlagNames) = - "Suspicious flag names: " - ++ unwords invalidFlagNames - ++ ". " - ++ "To avoid ambiguity in command line interfaces, flag shouldn't " - ++ "start with a dash. Also for better compatibility, flag names " - ++ "shouldn't contain non-ascii characters." -ppExplanation (DeclaredUsedFlags declared used) = - "Declared and used flag sets differ: " - ++ s declared - ++ " /= " - ++ s used - ++ ". " - where - s :: Set.Set FlagName -> String - s = commaSep . map unFlagName . Set.toList -ppExplanation (NonASCIICustomField nonAsciiXFields) = - "Non ascii custom fields: " - ++ unwords nonAsciiXFields - ++ ". " - ++ "For better compatibility, custom field names " - ++ "shouldn't contain non-ascii characters." -ppExplanation RebindableClashPaths = - "Packages using RebindableSyntax with OverloadedStrings or" - ++ " OverloadedLists in default-extensions, in conjunction with the" - ++ " autogenerated module Paths_*, are known to cause compile failures" - ++ " with Cabal < 2.2. To use these default-extensions with a Paths_*" - ++ " autogen module, specify at least 'cabal-version: 2.2'." -ppExplanation RebindableClashPackageInfo = - "Packages using RebindableSyntax with OverloadedStrings or" - ++ " OverloadedLists in default-extensions, in conjunction with the" - ++ " autogenerated module PackageInfo_*, are known to cause compile failures" - ++ " with Cabal < 2.2. To use these default-extensions with a PackageInfo_*" - ++ " autogen module, specify at least 'cabal-version: 2.2'." -ppExplanation (WErrorUnneeded fieldName) = - addConditionalExp $ - "'" - ++ fieldName - ++ ": -Werror' makes the package easy to " - ++ "break with future GHC versions because new GHC versions often " - ++ "add new warnings." -ppExplanation (JUnneeded fieldName) = - addConditionalExp $ - "'" - ++ fieldName - ++ ": -j[N]' can make sense for specific user's setup," - ++ " but it is not appropriate for a distributed package." -ppExplanation (FDeferTypeErrorsUnneeded fieldName) = - addConditionalExp $ - "'" - ++ fieldName - ++ ": -fdefer-type-errors' is fine during development " - ++ "but is not appropriate for a distributed package." -ppExplanation (DynamicUnneeded fieldName) = - addConditionalExp $ - "'" - ++ fieldName - ++ ": -d*' debug flags are not appropriate " - ++ "for a distributed package." -ppExplanation (ProfilingUnneeded fieldName) = - addConditionalExp $ - "'" - ++ fieldName - ++ ": -fprof*' profiling flags are typically not " - ++ "appropriate for a distributed library package. These flags are " - ++ "useful to profile this package, but when profiling other packages " - ++ "that use this one these flags clutter the profile output with " - ++ "excessive detail. If you think other packages really want to see " - ++ "cost centres from this package then use '-fprof-auto-exported' " - ++ "which puts cost centres only on exported functions." -ppExplanation (UpperBoundSetup nm) = - "The dependency 'setup-depends: '" - ++ nm - ++ "' does not specify an " - ++ "upper bound on the version number. Each major release of the " - ++ "'" - ++ nm - ++ "' package changes the API in various ways and most " - ++ "packages will need some changes to compile with it. If you are " - ++ "not sure what upper bound to use then use the next major " - ++ "version." -ppExplanation (DuplicateModule s dupLibsLax) = - "Duplicate modules in " - ++ s - ++ ": " - ++ commaSep (map prettyShow dupLibsLax) -ppExplanation (PotentialDupModule s dupLibsStrict) = - "Potential duplicate modules (subject to conditionals) in " - ++ s - ++ ": " - ++ commaSep (map prettyShow dupLibsStrict) -ppExplanation (BOMStart pdfile) = - pdfile - ++ " starts with an Unicode byte order mark (BOM)." - ++ " This may cause problems with older cabal versions." -ppExplanation (NotPackageName pdfile expectedCabalname) = - "The filename " - ++ quote pdfile - ++ " does not match package name " - ++ "(expected: " - ++ quote expectedCabalname - ++ ")" -ppExplanation NoDesc = - "No cabal file found.\n" - ++ "Please create a package description file .cabal" -ppExplanation (MultiDesc multiple) = - "Multiple cabal files found while checking.\n" - ++ "Please use only one of: " - ++ intercalate ", " multiple -ppExplanation (UnknownFile fieldname file) = - "The '" - ++ fieldname - ++ "' field refers to the file " - ++ quote (getSymbolicPath file) - ++ " which does not exist." -ppExplanation MissingSetupFile = - "The package is missing a Setup.hs or Setup.lhs script." -ppExplanation MissingConfigureScript = - "The 'build-type' is 'Configure' but there is no 'configure' script. " - ++ "You probably need to run 'autoreconf -i' to generate it." -ppExplanation (UnknownDirectory kind dir) = - quote (kind ++ ": " ++ dir) - ++ " specifies a directory which does not exist." -ppExplanation MissingSourceControl = - "When distributing packages it is encouraged to specify source " - ++ "control information in the .cabal file using one or more " - ++ "'source-repository' sections. See the Cabal user guide for " - ++ "details." -ppExplanation (MissingExpectedDocFiles extraDocFileSupport paths) = - "Please consider including the " - ++ quotes paths - ++ " in the '" - ++ targetField - ++ "' section of the .cabal file " - ++ "if it contains useful information for users of the package." - where - quotes [p] = "file " ++ quote p - quotes ps = "files " ++ intercalate ", " (map quote ps) - targetField = - if extraDocFileSupport - then "extra-doc-files" - else "extra-source-files" -ppExplanation (WrongFieldForExpectedDocFiles extraDocFileSupport field paths) = - "Please consider moving the " - ++ quotes paths - ++ " from the '" - ++ field - ++ "' section of the .cabal file " - ++ "to the section '" - ++ targetField - ++ "'." - where - quotes [p] = "file " ++ quote p - quotes ps = "files " ++ intercalate ", " (map quote ps) - targetField = - if extraDocFileSupport - then "extra-doc-files" - else "extra-source-files" - --- | Results of some kind of failed package check. +-- ☞ N.B. -- --- There are a range of severities, from merely dubious to totally insane. --- All of them come with a human readable explanation. In future we may augment --- them with more machine readable explanations, for example to help an IDE --- suggest automatic corrections. -data PackageCheck - = -- | This package description is no good. There's no way it's going to - -- build sensibly. This should give an error at configure time. - PackageBuildImpossible {explanation :: CheckExplanation} - | -- | A problem that is likely to affect building the package, or an - -- issue that we'd like every package author to be aware of, even if - -- the package is never distributed. - PackageBuildWarning {explanation :: CheckExplanation} - | -- | An issue that might not be a problem for the package author but - -- might be annoying or detrimental when the package is distributed to - -- users. We should encourage distributed packages to be free from these - -- issues, but occasionally there are justifiable reasons so we cannot - -- ban them entirely. - PackageDistSuspicious {explanation :: CheckExplanation} - | -- | Like PackageDistSuspicious but will only display warnings - -- rather than causing abnormal exit when you run 'cabal check'. - PackageDistSuspiciousWarn {explanation :: CheckExplanation} - | -- | An issue that is OK in the author's environment but is almost - -- certain to be a portability problem for other environments. We can - -- quite legitimately refuse to publicly distribute packages with these - -- problems. - PackageDistInexcusable {explanation :: CheckExplanation} - deriving (Eq, Ord) - --- | Would Hackage refuse a package because of this error? -isHackageDistError :: PackageCheck -> Bool -isHackageDistError = \case - (PackageBuildImpossible{}) -> True - (PackageBuildWarning{}) -> True - (PackageDistInexcusable{}) -> True - (PackageDistSuspicious{}) -> False - (PackageDistSuspiciousWarn{}) -> False - --- | Pretty printing 'PackageCheck'. -ppPackageCheck :: PackageCheck -> String -ppPackageCheck e = ppExplanation (explanation e) - -instance Show PackageCheck where - show notice = ppPackageCheck notice - -check :: Bool -> PackageCheck -> Maybe PackageCheck -check False _ = Nothing -check True pc = Just pc - -checkSpecVersion - :: PackageDescription - -> CabalSpecVersion - -> Bool - -> PackageCheck - -> Maybe PackageCheck -checkSpecVersion pkg specver cond pc - | specVersion pkg >= specver = Nothing - | otherwise = check cond pc +-- Part of the tools/scaffold used to perform check is found in +-- Distribution.PackageDescription.Check.Types. Summary of that module (for +-- how we use it here): +-- 1. we work inside a 'CheckM m a' monad (where `m` is an abstraction to +-- run non-pure checks); +-- 2. 'checkP', 'checkPre' functions perform checks (respectively pure and +-- non-pure); +-- 3. 'PackageCheck' and 'CheckExplanation' are types for warning severity +-- and description. -- ------------------------------------------------------------ - --- * Standard checks - +-- Checking interface -- ------------------------------------------------------------ +-- | 'checkPackagePrim' is the most general way to invoke package checks. +-- We pass to it two interfaces (one to check contents of packages, the +-- other to inspect working tree for orphan files) and before that a +-- Boolean to indicate whether we want pure checks or not. Based on these +-- parameters, some checks will be performed, some omitted. +-- Generality over @m@ means we could do non pure checks in monads other +-- than IO (e.g. a virtual filesystem, like a zip file, a VCS filesystem, +-- etc). +checkPackagePrim + :: Monad m + => Bool -- Perform pure checks? + -> Maybe (CheckPackageContentOps m) -- Package content interface. + -> Maybe (CheckPreDistributionOps m) -- Predist checks interface. + -> GenericPackageDescription -- GPD to check. + -> m [PackageCheck] +checkPackagePrim b mco mpdo gpd = do + let cm = checkGenericPackageDescription gpd + ci = CheckInterface b mco mpdo + ctx = pristineCheckCtx ci gpd + execCheckM cm ctx + -- | Check for common mistakes and problems in package descriptions. -- -- This is the standard collection of checks covering all aspects except -- for checks that require looking at files within the package. For those -- see 'checkPackageFiles'. +checkPackage :: GenericPackageDescription -> [PackageCheck] +checkPackage gpd = runIdentity $ checkPackagePrim True Nothing Nothing gpd + +-- | This function is an oddity due to the historical +-- GenericPackageDescription/PackageDescription split. It is only maintained +-- not to break interface, use `checkPackage` if possible. +checkConfiguredPackage :: PackageDescription -> [PackageCheck] +checkConfiguredPackage pd = checkPackage (pd2gpd pd) + +-- | Sanity check things that requires looking at files in the package. +-- This is a generalised version of 'checkPackageFiles' that can work in any +-- monad for which you can provide 'CheckPackageContentOps' operations. -- --- It requires the 'GenericPackageDescription' and optionally a particular --- configuration of that package. If you pass 'Nothing' then we just check --- a version of the generic description using 'flattenPackageDescription'. -checkPackage - :: GenericPackageDescription - -> Maybe PackageDescription - -> [PackageCheck] -checkPackage gpkg mpkg = - checkConfiguredPackage pkg - ++ checkConditionals gpkg - ++ checkPackageVersions gpkg - ++ checkDevelopmentOnlyFlags gpkg - ++ checkFlagNames gpkg - ++ checkUnusedFlags gpkg - ++ checkUnicodeXFields gpkg - ++ checkPathsModuleExtensions pkg - ++ checkPackageInfoModuleExtensions pkg - ++ checkSetupVersions gpkg - ++ checkDuplicateModules gpkg +-- The point of this extra generality is to allow doing checks in some virtual +-- file system, for example a tarball in memory. +checkPackageContent + :: Monad m + => CheckPackageContentOps m + -> GenericPackageDescription + -> m [PackageCheck] +checkPackageContent pops gpd = checkPackagePrim False (Just pops) Nothing gpd + +-- | Sanity checks that require IO. 'checkPackageFiles' looks at the files +-- in the package and expects to find the package unpacked at the given +-- filepath. +checkPackageFilesGPD + :: Verbosity -- Glob warn message verbosity. + -> GenericPackageDescription + -> FilePath -- Package root. + -> IO [PackageCheck] +checkPackageFilesGPD verbosity gpd root = + checkPackagePrim False (Just checkFilesIO) (Just checkPreIO) gpd where - pkg = fromMaybe (flattenPackageDescription gpkg) mpkg + checkFilesIO = + CheckPackageContentOps + { doesFileExist = System.doesFileExist . relative + , doesDirectoryExist = System.doesDirectoryExist . relative + , getDirectoryContents = System.Directory.getDirectoryContents . relative + , getFileContents = BS.readFile . relative + } --- TODO: make this variant go away --- we should always know the GenericPackageDescription -checkConfiguredPackage :: PackageDescription -> [PackageCheck] -checkConfiguredPackage pkg = - checkSanity pkg - ++ checkFields pkg - ++ checkLicense pkg - ++ checkSourceRepos pkg - ++ checkAllGhcOptions pkg - ++ checkCCOptions pkg - ++ checkCxxOptions pkg - ++ checkCPPOptions pkg - ++ checkPaths pkg - ++ checkCabalVersion pkg + checkPreIO = + CheckPreDistributionOps + { runDirFileGlobM = \fp g -> runDirFileGlob verbosity (Just . specVersion $ packageDescription gpd) (root fp) g + , getDirectoryContentsM = System.Directory.getDirectoryContents . relative + } --- ------------------------------------------------------------ + relative path = root path --- * Basic sanity checks +-- | Same as 'checkPackageFilesGPD', but working with 'PackageDescription'. +-- +-- This function is included for legacy reasons, use 'checkPackageFilesGPD' +-- if you are working with 'GenericPackageDescription'. +checkPackageFiles + :: Verbosity -- Glob warn message verbosity. + -> PackageDescription + -> FilePath -- Package root. + -> IO [PackageCheck] +checkPackageFiles verbosity pd oot = + checkPackageFilesGPD verbosity (pd2gpd pd) oot -- ------------------------------------------------------------ +-- Package description +-- ------------------------------------------------------------ --- | Check that this package description is sane. -checkSanity :: PackageDescription -> [PackageCheck] -checkSanity pkg = - catMaybes - [ check (null . unPackageName . packageName $ pkg) $ - PackageBuildImpossible NoNameField - , check (nullVersion == packageVersion pkg) $ - PackageBuildImpossible NoVersionField - , check - ( all - ($ pkg) - [ null . executables - , null . testSuites - , null . benchmarks - , null . allLibraries - , null . foreignLibs +-- Here lies the meat of the module. Starting from 'GenericPackageDescription', +-- we walk the data while doing a number of checks. +-- +-- Where applicable we do a full pattern match (if the data changes, code will +-- break: a gentle reminder to add more checks). +-- Pattern matching variables convention: matching accessor + underscore. +-- This way it is easier to see which one we are missing if we run into +-- an “GPD should have 20 arguments but has been given only 19” error. + +-- | 'GenericPackageDescription' checks. Remember that for historical quirks +-- in the cabal codebase we have both `GenericPackageDescription` and +-- `PackageDescription` and that PD is both a *field* of GPD and a concept +-- of its own (i.e. a fully realised GPD). +-- In this case we are checking (correctly) GPD, so for target info/checks +-- you should walk condLibrary_ etc. and *not* the (empty) target info in +-- PD. See 'pd2gpd' for a convenient hack when you only have +-- 'PackageDescription'. +checkGenericPackageDescription + :: Monad m + => GenericPackageDescription + -> CheckM m () +checkGenericPackageDescription + gpd@( GenericPackageDescription + packageDescription_ + _gpdScannedVersion_ + genPackageFlags_ + condLibrary_ + condSubLibraries_ + condForeignLibs_ + condExecutables_ + condTestSuites_ + condBenchmarks_ + ) = + do + -- § Description and names. + checkPackageDescription packageDescription_ + -- Targets should be present... + let condAllLibraries = + maybeToList condLibrary_ + ++ (map snd condSubLibraries_) + checkP + ( and + [ null condExecutables_ + , null condTestSuites_ + , null condBenchmarks_ + , null condAllLibraries + , null condForeignLibs_ ] ) - $ PackageBuildImpossible NoTarget - , check (any (== LMainLibName) (map libName $ subLibraries pkg)) $ - PackageBuildImpossible UnnamedInternal - , check (not (null duplicateNames)) $ - PackageBuildImpossible (DuplicateSections duplicateNames) - , -- NB: but it's OK for executables to have the same name! - -- TODO shouldn't need to compare on the string level - check - ( any - (== prettyShow (packageName pkg)) - (prettyShow <$> subLibNames) + (PackageBuildImpossible NoTarget) + -- ... and have unique names (names are not under conditional, it is + -- appropriate to check here. + (nsubs, nexes, ntests, nbenchs) <- + asksCM + ( ( \n -> + ( pnSubLibs n + , pnExecs n + , pnTests n + , pnBenchs n + ) + ) + . ccNames + ) + let names = concat [nsubs, nexes, ntests, nbenchs] + dupes = dups names + checkP + (not . null $ dups names) + (PackageBuildImpossible $ DuplicateSections dupes) + -- PackageDescription checks. + checkPackageDescription packageDescription_ + -- Flag names. + mapM_ checkFlagName genPackageFlags_ + + -- § Feature checks. + checkSpecVer + CabalSpecV2_0 + (not . null $ condSubLibraries_) + (PackageDistInexcusable CVMultiLib) + checkSpecVer + CabalSpecV1_8 + (not . null $ condTestSuites_) + (PackageDistInexcusable CVTestSuite) + + -- § Conditional targets + + -- Extract dependencies from libraries, to be passed along for + -- PVP checks purposes. + pName <- + asksCM + ( packageNameToUnqualComponentName + . pkgName + . pnPackageId + . ccNames + ) + let ads = + maybe [] ((: []) . extractAssocDeps pName) condLibrary_ + ++ map (uncurry extractAssocDeps) condSubLibraries_ + + case condLibrary_ of + Just cl -> + checkCondTarget + genPackageFlags_ + (checkLibrary False ads) + (const id) + (mempty, cl) + Nothing -> return () + mapM_ + ( checkCondTarget + genPackageFlags_ + (checkLibrary False ads) + (\u l -> l{libName = maybeToLibraryName (Just u)}) ) - $ PackageBuildImpossible (IllegalLibraryName pkg) - ] - -- TODO: check for name clashes case insensitively: windows file systems cannot - -- cope. - - ++ concatMap (checkLibrary pkg) (allLibraries pkg) - ++ concatMap (checkExecutable pkg) (executables pkg) - ++ concatMap (checkTestSuite pkg) (testSuites pkg) - ++ concatMap (checkBenchmark pkg) (benchmarks pkg) - where - -- The public 'library' gets special dispensation, because it - -- is common practice to export a library and name the executable - -- the same as the package. - subLibNames = mapMaybe (libraryNameString . libName) $ subLibraries pkg - exeNames = map exeName $ executables pkg - testNames = map testName $ testSuites pkg - bmNames = map benchmarkName $ benchmarks pkg - duplicateNames = dups $ subLibNames ++ exeNames ++ testNames ++ bmNames - -checkLibrary :: PackageDescription -> Library -> [PackageCheck] -checkLibrary pkg lib = - catMaybes - [ -- TODO: This check is bogus if a required-signature was passed through - check (null (explicitLibModules lib) && null (reexportedModules lib)) $ - PackageDistSuspiciousWarn (NoModulesExposed lib) - , -- check use of signatures sections - checkVersion CabalSpecV2_0 (not (null (signatures lib))) $ - PackageDistInexcusable SignaturesCabal2 - , -- check that all autogen-modules appear on other-modules or exposed-modules - check - (not $ and $ map (flip elem (explicitLibModules lib)) (libModulesAutogen lib)) - $ PackageBuildImpossible AutogenNotExposed - , -- check that all autogen-includes appear on includes or install-includes - check - (not $ and $ map (flip elem (allExplicitIncludes lib)) (view L.autogenIncludes lib)) - $ PackageBuildImpossible AutogenIncludesNotIncluded - ] - where - checkVersion :: CabalSpecVersion -> Bool -> PackageCheck -> Maybe PackageCheck - checkVersion ver cond pc - | specVersion pkg >= ver = Nothing - | otherwise = check cond pc - -allExplicitIncludes :: L.HasBuildInfo a => a -> [FilePath] -allExplicitIncludes x = view L.includes x ++ view L.installIncludes x - -checkExecutable :: PackageDescription -> Executable -> [PackageCheck] -checkExecutable pkg exe = - catMaybes - [ check (null (modulePath exe)) $ - PackageBuildImpossible (NoMainIs exe) - , -- This check does not apply to scripts. - check - ( package pkg /= fakePackageId - && not (null (modulePath exe)) - && not (fileExtensionSupportedLanguage $ modulePath exe) + condSubLibraries_ + mapM_ + ( checkCondTarget + genPackageFlags_ + checkForeignLib + (const id) ) - $ PackageBuildImpossible NoHsLhsMain - , checkSpecVersion - pkg - CabalSpecV1_18 - ( fileExtensionSupportedLanguage (modulePath exe) - && takeExtension (modulePath exe) `notElem` [".hs", ".lhs"] + condForeignLibs_ + mapM_ + ( checkCondTarget + genPackageFlags_ + (checkExecutable ads) + (const id) ) - $ PackageDistInexcusable MainCCabal1_18 - , -- check that all autogen-modules appear on other-modules - check - (not $ and $ map (flip elem (exeModules exe)) (exeModulesAutogen exe)) - $ PackageBuildImpossible (AutogenNoOther CETExecutable (exeName exe)) - , -- check that all autogen-includes appear on includes - check - (not $ and $ map (flip elem (view L.includes exe)) (view L.autogenIncludes exe)) - $ PackageBuildImpossible AutogenIncludesNotIncludedExe - ] - -checkTestSuite :: PackageDescription -> TestSuite -> [PackageCheck] -checkTestSuite pkg test = - catMaybes - [ case testInterface test of - TestSuiteUnsupported tt@(TestTypeUnknown _ _) -> - Just $ - PackageBuildWarning (TestsuiteTypeNotKnown tt) - TestSuiteUnsupported tt -> - Just $ - PackageBuildWarning (TestsuiteNotSupported tt) - _ -> Nothing - , check mainIsWrongExt $ - PackageBuildImpossible NoHsLhsMain - , checkSpecVersion pkg CabalSpecV1_18 (mainIsNotHsExt && not mainIsWrongExt) $ - PackageDistInexcusable MainCCabal1_18 - , -- check that all autogen-modules appear on other-modules - check - (not $ and $ map (flip elem (testModules test)) (testModulesAutogen test)) - $ PackageBuildImpossible (AutogenNoOther CETTest (testName test)) - , -- check that all autogen-includes appear on includes - check - (not $ and $ map (flip elem (view L.includes test)) (view L.autogenIncludes test)) - $ PackageBuildImpossible AutogenIncludesNotIncludedExe - ] - where - mainIsWrongExt = case testInterface test of - TestSuiteExeV10 _ f -> not $ fileExtensionSupportedLanguage f - _ -> False - - mainIsNotHsExt = case testInterface test of - TestSuiteExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"] - _ -> False - -checkBenchmark :: PackageDescription -> Benchmark -> [PackageCheck] -checkBenchmark _pkg bm = - catMaybes - [ case benchmarkInterface bm of - BenchmarkUnsupported tt@(BenchmarkTypeUnknown _ _) -> - Just $ - PackageBuildWarning (BenchmarkTypeNotKnown tt) - BenchmarkUnsupported tt -> - Just $ - PackageBuildWarning (BenchmarkNotSupported tt) - _ -> Nothing - , check mainIsWrongExt $ - PackageBuildImpossible NoHsLhsMainBench - , -- check that all autogen-modules appear on other-modules - check - (not $ and $ map (flip elem (benchmarkModules bm)) (benchmarkModulesAutogen bm)) - $ PackageBuildImpossible (AutogenNoOther CETBenchmark (benchmarkName bm)) - , -- check that all autogen-includes appear on includes - check - (not $ and $ map (flip elem (view L.includes bm)) (view L.autogenIncludes bm)) - $ PackageBuildImpossible AutogenIncludesNotIncludedExe - ] - where - mainIsWrongExt = case benchmarkInterface bm of - BenchmarkExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"] - _ -> False - --- ------------------------------------------------------------ - --- * Additional pure checks - --- ------------------------------------------------------------ - -checkFields :: PackageDescription -> [PackageCheck] -checkFields pkg = - catMaybes - [ check (not . FilePath.Windows.isValid . prettyShow . packageName $ pkg) $ - PackageDistInexcusable (InvalidNameWin pkg) - , check (isPrefixOf "z-" . prettyShow . packageName $ pkg) $ - PackageDistInexcusable ZPrefix - , check (isNothing (buildTypeRaw pkg) && specVersion pkg < CabalSpecV2_2) $ - PackageBuildWarning NoBuildType - , check (isJust (setupBuildInfo pkg) && buildType pkg /= Custom) $ - PackageBuildWarning NoCustomSetup - , check (not (null unknownCompilers)) $ - PackageBuildWarning (UnknownCompilers unknownCompilers) - , check (not (null unknownLanguages)) $ - PackageBuildWarning (UnknownLanguages unknownLanguages) - , check (not (null unknownExtensions)) $ - PackageBuildWarning (UnknownExtensions unknownExtensions) - , check (not (null languagesUsedAsExtensions)) $ - PackageBuildWarning (LanguagesAsExtension languagesUsedAsExtensions) - , check (not (null ourDeprecatedExtensions)) $ - PackageDistSuspicious (DeprecatedExtensions ourDeprecatedExtensions) - , check (ShortText.null (category pkg)) $ - PackageDistSuspicious (MissingField CEFCategory) - , check (ShortText.null (maintainer pkg)) $ - PackageDistSuspicious (MissingField CEFMaintainer) - , check (ShortText.null (synopsis pkg) && ShortText.null (description pkg)) $ - PackageDistInexcusable (MissingField CEFSynOrDesc) - , check (ShortText.null (description pkg) && not (ShortText.null (synopsis pkg))) $ - PackageDistSuspicious (MissingField CEFDescription) - , check (ShortText.null (synopsis pkg) && not (ShortText.null (description pkg))) $ - PackageDistSuspicious (MissingField CEFSynopsis) - , -- TODO: recommend the bug reports URL, author and homepage fields - -- TODO: recommend not using the stability field - -- TODO: recommend specifying a source repo - - check (ShortText.length (synopsis pkg) > 80) $ - PackageDistSuspicious SynopsisTooLong - , -- See also https://github.com/haskell/cabal/pull/3479 - check - ( not (ShortText.null (description pkg)) - && ShortText.length (description pkg) <= ShortText.length (synopsis pkg) + condExecutables_ + mapM_ + ( checkCondTarget + genPackageFlags_ + (checkTestSuite ads) + (\u l -> l{testName = u}) ) - $ PackageDistSuspicious ShortDesc - , -- check use of impossible constraints "tested-with: GHC== 6.10 && ==6.12" - check (not (null testedWithImpossibleRanges)) $ - PackageDistInexcusable (InvalidTestWith testedWithImpossibleRanges) - , -- for more details on why the following was commented out, - -- check https://github.com/haskell/cabal/pull/7470#issuecomment-875878507 - -- , check (not (null depInternalLibraryWithExtraVersion)) $ - -- PackageBuildWarning $ - -- "The package has an extraneous version range for a dependency on an " - -- ++ "internal library: " - -- ++ commaSep (map prettyShow depInternalLibraryWithExtraVersion) - -- ++ ". This version range includes the current package but isn't needed " - -- ++ "as the current package's library will always be used." - - check (not (null depInternalLibraryWithImpossibleVersion)) $ - PackageBuildImpossible - (ImpossibleInternalDep depInternalLibraryWithImpossibleVersion) - , -- , check (not (null depInternalExecutableWithExtraVersion)) $ - -- PackageBuildWarning $ - -- "The package has an extraneous version range for a dependency on an " - -- ++ "internal executable: " - -- ++ commaSep (map prettyShow depInternalExecutableWithExtraVersion) - -- ++ ". This version range includes the current package but isn't needed " - -- ++ "as the current package's executable will always be used." - - check (not (null depInternalExecutableWithImpossibleVersion)) $ - PackageBuildImpossible - (ImpossibleInternalExe depInternalExecutableWithImpossibleVersion) - , check (not (null depMissingInternalExecutable)) $ - PackageBuildImpossible (MissingInternalExe depMissingInternalExecutable) - ] - where - unknownCompilers = [name | (OtherCompiler name, _) <- testedWith pkg] - unknownLanguages = - [ name | bi <- allBuildInfo pkg, UnknownLanguage name <- allLanguages bi - ] - unknownExtensions = - [ name | bi <- allBuildInfo pkg, UnknownExtension name <- allExtensions bi, name `notElem` map prettyShow knownLanguages - ] - ourDeprecatedExtensions = - nub $ - catMaybes - [ find ((== ext) . fst) deprecatedExtensions - | bi <- allBuildInfo pkg - , ext <- allExtensions bi + condTestSuites_ + mapM_ + ( checkCondTarget + genPackageFlags_ + (checkBenchmark ads) + (\u l -> l{benchmarkName = u}) + ) + condBenchmarks_ + + -- For unused flags it is clearer and more convenient to fold the + -- data rather than walk it, an exception to the rule. + checkP + (decFlags /= usedFlags) + (PackageDistSuspicious $ DeclaredUsedFlags decFlags usedFlags) + + -- Duplicate modules. + mapM_ tellP (checkDuplicateModules gpd) + where + -- todo is this caught at parse time? + checkFlagName :: Monad m => PackageFlag -> CheckM m () + checkFlagName pf = + let fn = unFlagName . flagName $ pf + + invalidFlagName ('-' : _) = True -- starts with dash + invalidFlagName cs = any (not . isAscii) cs -- non ASCII + in checkP + (invalidFlagName fn) + (PackageDistInexcusable $ SuspiciousFlagName [fn]) + + decFlags :: Set.Set FlagName + decFlags = toSetOf (L.genPackageFlags . traverse . L.flagName) gpd + + usedFlags :: Set.Set FlagName + usedFlags = + mconcat + [ toSetOf (L.condLibrary . traverse . traverseCondTreeV . L._PackageFlag) gpd + , toSetOf (L.condSubLibraries . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd + , toSetOf (L.condForeignLibs . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd + , toSetOf (L.condExecutables . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd + , toSetOf (L.condTestSuites . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd + , toSetOf (L.condBenchmarks . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd ] - languagesUsedAsExtensions = - [ name | bi <- allBuildInfo pkg, UnknownExtension name <- allExtensions bi, name `elem` map prettyShow knownLanguages - ] - - testedWithImpossibleRanges = - [ Dependency (mkPackageName (prettyShow compiler)) vr mainLibSet - | (compiler, vr) <- testedWith pkg - , isNoVersion vr - ] - internalExecutables = map exeName $ executables pkg - - internalLibDeps = - [ dep - | bi <- allBuildInfo pkg - , dep@(Dependency name _ _) <- targetBuildDepends bi - , name == packageName pkg - ] - - internalExeDeps = - [ dep - | bi <- allBuildInfo pkg - , dep <- getAllToolDependencies pkg bi - , isInternal pkg dep - ] - - -- depInternalLibraryWithExtraVersion = - -- [ dep - -- | dep@(Dependency _ versionRange _) <- internalLibDeps - -- , not $ isAnyVersion versionRange - -- , packageVersion pkg `withinRange` versionRange - -- ] - - depInternalLibraryWithImpossibleVersion = - [ dep - | dep@(Dependency _ versionRange _) <- internalLibDeps - , not $ packageVersion pkg `withinRange` versionRange - ] - - -- depInternalExecutableWithExtraVersion = - -- [ dep - -- | dep@(ExeDependency _ _ versionRange) <- internalExeDeps - -- , not $ isAnyVersion versionRange - -- , packageVersion pkg `withinRange` versionRange - -- ] - - depInternalExecutableWithImpossibleVersion = - [ dep - | dep@(ExeDependency _ _ versionRange) <- internalExeDeps - , not $ packageVersion pkg `withinRange` versionRange - ] +checkPackageDescription :: Monad m => PackageDescription -> CheckM m () +checkPackageDescription + pkg@( PackageDescription + specVersion_ + package_ + licenseRaw_ + licenseFiles_ + _copyright_ + maintainer_ + _author_ + _stability_ + testedWith_ + _homepage_ + _pkgUrl_ + _bugReports_ + sourceRepos_ + synopsis_ + description_ + category_ + customFieldsPD_ + buildTypeRaw_ + setupBuildInfo_ + _library_ + _subLibraries_ + _executables_ + _foreignLibs_ + _testSuites_ + _benchmarks_ + dataFiles_ + dataDir_ + extraSrcFiles_ + extraTmpFiles_ + extraDocFiles_ + ) = do + -- § Sanity checks. + checkPackageId package_ + -- TODO `name` is caught at parse level, remove this test. + let pn = packageName package_ + checkP + (null . unPackageName $ pn) + (PackageBuildImpossible NoNameField) + -- TODO `version` is caught at parse level, remove this test. + checkP + (nullVersion == packageVersion package_) + (PackageBuildImpossible NoVersionField) + -- But it is OK for executables to have the same name. + nsubs <- asksCM (pnSubLibs . ccNames) + checkP + (any (== prettyShow pn) (prettyShow <$> nsubs)) + (PackageBuildImpossible $ IllegalLibraryName pn) + + -- § Fields check. + checkNull + category_ + (PackageDistSuspicious MissingFieldCategory) + checkNull + maintainer_ + (PackageDistSuspicious MissingFieldMaintainer) + checkP + (ShortText.null synopsis_ && not (ShortText.null description_)) + (PackageDistSuspicious MissingFieldSynopsis) + checkP + (ShortText.null description_ && not (ShortText.null synopsis_)) + (PackageDistSuspicious MissingFieldDescription) + checkP + (all ShortText.null [synopsis_, description_]) + (PackageDistInexcusable MissingFieldSynOrDesc) + checkP + (ShortText.length synopsis_ > 80) + (PackageDistSuspicious SynopsisTooLong) + checkP + ( not (ShortText.null description_) + && ShortText.length description_ <= ShortText.length synopsis_ + ) + (PackageDistSuspicious ShortDesc) + + -- § Paths. + mapM_ (checkPath False "extra-source-files" PathKindGlob) extraSrcFiles_ + mapM_ (checkPath False "extra-tmp-files" PathKindFile) extraTmpFiles_ + mapM_ (checkPath False "extra-doc-files" PathKindGlob) extraDocFiles_ + mapM_ (checkPath False "data-files" PathKindGlob) dataFiles_ + checkPath True "data-dir" PathKindDirectory dataDir_ + let licPaths = map getSymbolicPath licenseFiles_ + mapM_ (checkPath False "license-file" PathKindFile) licPaths + mapM_ checkLicFileExist licenseFiles_ + + -- § Globs. + dataGlobs <- mapM (checkGlob "data-files") dataFiles_ + extraGlobs <- mapM (checkGlob "extra-source-files") extraSrcFiles_ + docGlobs <- mapM (checkGlob "extra-doc-files") extraDocFiles_ + -- We collect globs to feed them to checkMissingDocs. + + -- § Missing documentation. + checkMissingDocs + (catMaybes dataGlobs) + (catMaybes extraGlobs) + (catMaybes docGlobs) + + -- § Datafield checks. + checkSetupBuildInfo setupBuildInfo_ + mapM_ checkTestedWith testedWith_ + either + checkNewLicense + (checkOldLicense $ null licenseFiles_) + licenseRaw_ + checkSourceRepos sourceRepos_ + mapM_ checkCustomField customFieldsPD_ + + -- Feature checks. + checkSpecVer + CabalSpecV1_18 + (not . null $ extraDocFiles_) + (PackageDistInexcusable CVExtraDocFiles) + checkSpecVer + CabalSpecV1_6 + (not . null $ sourceRepos_) + (PackageDistInexcusable CVSourceRepository) + checkP + ( specVersion_ >= CabalSpecV1_24 + && isNothing setupBuildInfo_ + && buildTypeRaw_ == Just Custom + ) + (PackageBuildWarning CVCustomSetup) + checkSpecVer + CabalSpecV1_24 + ( isNothing setupBuildInfo_ + && buildTypeRaw_ == Just Custom + ) + (PackageDistSuspiciousWarn CVExpliticDepsCustomSetup) + checkP + (isNothing buildTypeRaw_ && specVersion_ < CabalSpecV2_2) + (PackageBuildWarning NoBuildType) + checkP + (isJust setupBuildInfo_ && buildType pkg /= Custom) + (PackageBuildWarning NoCustomSetup) + + -- Contents. + checkConfigureExists (buildType pkg) + checkSetupExists (buildType pkg) + checkCabalFile (packageName pkg) + mapM_ (checkGlobFile specVersion_ "." "extra-source-files") extraSrcFiles_ + mapM_ (checkGlobFile specVersion_ "." "extra-doc-files") extraDocFiles_ + mapM_ (checkGlobFile specVersion_ dataDir_ "data-files") dataFiles_ + where + checkNull + :: Monad m + => ShortText.ShortText + -> PackageCheck + -> CheckM m () + checkNull st c = checkP (ShortText.null st) c + + checkTestedWith + :: Monad m + => (CompilerFlavor, VersionRange) + -> CheckM m () + checkTestedWith (OtherCompiler n, _) = + tellP (PackageBuildWarning $ UnknownCompilers [n]) + checkTestedWith (compiler, versionRange) = + checkVersionRange compiler versionRange + + checkVersionRange + :: Monad m + => CompilerFlavor + -> VersionRange + -> CheckM m () + checkVersionRange cmp vr = + when + (isNoVersion vr) + ( let dep = + [ Dependency + (mkPackageName (prettyShow cmp)) + vr + mainLibSet + ] + in tellP (PackageDistInexcusable (InvalidTestWith dep)) + ) - depMissingInternalExecutable = - [ dep - | dep@(ExeDependency _ eName _) <- internalExeDeps - , not $ eName `elem` internalExecutables +checkSetupBuildInfo :: Monad m => Maybe SetupBuildInfo -> CheckM m () +checkSetupBuildInfo Nothing = return () +checkSetupBuildInfo (Just (SetupBuildInfo ds _)) = do + let uqs = map mkUnqualComponentName ["base", "Cabal"] + (is, rs) <- partitionDeps [] uqs ds + let ick = PackageDistInexcusable . UpperBoundSetup + rck = + PackageDistSuspiciousWarn + . MissingUpperBounds CETSetup + checkPVP ick is + checkPVPs rck rs + +checkPackageId :: Monad m => PackageIdentifier -> CheckM m () +checkPackageId (PackageIdentifier pkgName_ _pkgVersion_) = do + checkP + (not . FilePath.Windows.isValid . prettyShow $ pkgName_) + (PackageDistInexcusable $ InvalidNameWin pkgName_) + checkP (isPrefixOf "z-" . prettyShow $ pkgName_) $ + (PackageDistInexcusable ZPrefix) + +checkNewLicense :: Monad m => SPDX.License -> CheckM m () +checkNewLicense lic = do + checkP + (lic == SPDX.NONE) + (PackageDistInexcusable NONELicense) + +checkOldLicense + :: Monad m + => Bool -- Flag: no license file? + -> License + -> CheckM m () +checkOldLicense nullLicFiles lic = do + checkP + (lic == UnspecifiedLicense) + (PackageDistInexcusable NoLicense) + checkP + (lic == AllRightsReserved) + (PackageDistSuspicious AllRightsReservedLicense) + checkSpecVer + CabalSpecV1_4 + (lic `notElem` compatLicenses) + (PackageDistInexcusable (LicenseMessParse lic)) + checkP + (lic == BSD4) + (PackageDistSuspicious UncommonBSD4) + case lic of + UnknownLicense l -> + tellP (PackageBuildWarning (UnrecognisedLicense l)) + _ -> return () + checkP + ( lic + `notElem` [ AllRightsReserved + , UnspecifiedLicense + , PublicDomain + ] + && + -- AllRightsReserved and PublicDomain are not strictly + -- licenses so don't need license files. + nullLicFiles + ) + $ (PackageDistSuspicious NoLicenseFile) + case unknownLicenseVersion lic of + Just knownVersions -> + tellP + (PackageDistSuspicious $ UnknownLicenseVersion lic knownVersions) + _ -> return () + where + compatLicenses = + [ GPL Nothing + , LGPL Nothing + , AGPL Nothing + , BSD3 + , BSD4 + , PublicDomain + , AllRightsReserved + , UnspecifiedLicense + , OtherLicense ] -checkLicense :: PackageDescription -> [PackageCheck] -checkLicense pkg = case licenseRaw pkg of - Right l -> checkOldLicense pkg l - Left l -> checkNewLicense pkg l - -checkNewLicense :: PackageDescription -> SPDX.License -> [PackageCheck] -checkNewLicense _pkg lic = - catMaybes - [ check (lic == SPDX.NONE) $ - PackageDistInexcusable NONELicense - ] - -checkOldLicense :: PackageDescription -> License -> [PackageCheck] -checkOldLicense pkg lic = - catMaybes - [ check (lic == UnspecifiedLicense) $ - PackageDistInexcusable NoLicense - , check (lic == AllRightsReserved) $ - PackageDistSuspicious AllRightsReservedLicense - , checkVersion CabalSpecV1_4 (lic `notElem` compatLicenses) $ - PackageDistInexcusable (LicenseMessParse pkg) - , case lic of - UnknownLicense l -> Just $ PackageBuildWarning (UnrecognisedLicense l) - _ -> Nothing - , check (lic == BSD4) $ - PackageDistSuspicious UncommonBSD4 - , case unknownLicenseVersion lic of - Just knownVersions -> - Just $ - PackageDistSuspicious (UnknownLicenseVersion lic knownVersions) - _ -> Nothing - , check - ( lic - `notElem` [ AllRightsReserved - , UnspecifiedLicense - , PublicDomain - ] - -- AllRightsReserved and PublicDomain are not strictly - -- licenses so don't need license files. - && null (licenseFiles pkg) - ) - $ PackageDistSuspicious NoLicenseFile - ] - where unknownLicenseVersion (GPL (Just v)) | v `notElem` knownVersions = Just knownVersions where @@ -1462,1773 +653,432 @@ checkOldLicense pkg lic = knownVersions = [v' | Apache (Just v') <- knownLicenses] unknownLicenseVersion _ = Nothing - checkVersion :: CabalSpecVersion -> Bool -> PackageCheck -> Maybe PackageCheck - checkVersion ver cond pc - | specVersion pkg >= ver = Nothing - | otherwise = check cond pc - - compatLicenses = - [ GPL Nothing - , LGPL Nothing - , AGPL Nothing - , BSD3 - , BSD4 - , PublicDomain - , AllRightsReserved - , UnspecifiedLicense - , OtherLicense - ] - -checkSourceRepos :: PackageDescription -> [PackageCheck] -checkSourceRepos pkg = - catMaybes $ - concat - [ [ case repoKind repo of - RepoKindUnknown kind -> - Just $ - PackageDistInexcusable $ - UnrecognisedSourceRepo kind - _ -> Nothing - , check (isNothing (repoType repo)) $ - PackageDistInexcusable MissingType - , check (isNothing (repoLocation repo)) $ - PackageDistInexcusable MissingLocation - , check (repoType repo == Just (KnownRepoType CVS) && isNothing (repoModule repo)) $ - PackageDistInexcusable MissingModule - , check (repoKind repo == RepoThis && isNothing (repoTag repo)) $ - PackageDistInexcusable MissingTag - , check (maybe False isAbsoluteOnAnyPlatform (repoSubdir repo)) $ - PackageDistInexcusable SubdirRelPath - , do - subdir <- repoSubdir repo - err <- isGoodRelativeDirectoryPath subdir - return $ PackageDistInexcusable (SubdirGoodRelPath err) - ] - | repo <- sourceRepos pkg - ] - --- TODO: check location looks like a URL for some repo types. - --- | Checks GHC options from all ghc-*-options fields in the given --- PackageDescription and reports commonly misused or non-portable flags -checkAllGhcOptions :: PackageDescription -> [PackageCheck] -checkAllGhcOptions pkg = - checkGhcOptions "ghc-options" (hcOptions GHC) pkg - ++ checkGhcOptions "ghc-prof-options" (hcProfOptions GHC) pkg - ++ checkGhcOptions "ghc-shared-options" (hcSharedOptions GHC) pkg - --- | Extracts GHC options belonging to the given field from the given --- PackageDescription using given function and checks them for commonly misused --- or non-portable flags -checkGhcOptions :: String -> (BuildInfo -> [String]) -> PackageDescription -> [PackageCheck] -checkGhcOptions fieldName getOptions pkg = - catMaybes - [ checkFlags ["-fasm"] $ - PackageDistInexcusable (OptFasm fieldName) - , checkFlags ["-fvia-C"] $ - PackageDistSuspicious (OptViaC fieldName) - , checkFlags ["-fhpc"] $ - PackageDistInexcusable (OptHpc fieldName) - , checkFlags ["-prof"] $ - PackageBuildWarning (OptProf fieldName) - , unlessScript . checkFlags ["-o"] $ - PackageBuildWarning (OptO fieldName) - , checkFlags ["-hide-package"] $ - PackageBuildWarning (OptHide fieldName) - , checkFlags ["--make"] $ - PackageBuildWarning (OptMake fieldName) - , checkNonTestAndBenchmarkFlags ["-O0", "-Onot"] $ - PackageDistSuspicious (OptONot fieldName) - , checkTestAndBenchmarkFlags ["-O0", "-Onot"] $ - PackageDistSuspiciousWarn (OptONot fieldName) - , checkFlags ["-O", "-O1"] $ - PackageDistInexcusable (OptOOne fieldName) - , checkFlags ["-O2"] $ - PackageDistSuspiciousWarn (OptOTwo fieldName) - , checkFlags ["-split-sections"] $ - PackageBuildWarning (OptSplitSections fieldName) - , checkFlags ["-split-objs"] $ - PackageBuildWarning (OptSplitObjs fieldName) - , checkFlags ["-optl-Wl,-s", "-optl-s"] $ - PackageDistInexcusable (OptWls fieldName) - , checkFlags ["-fglasgow-exts"] $ - PackageDistSuspicious (OptExts fieldName) - , check ("-rtsopts" `elem` lib_ghc_options) $ - PackageBuildWarning (OptRts fieldName) - , check (any (\opt -> "-with-rtsopts" `isPrefixOf` opt) lib_ghc_options) $ - PackageBuildWarning (OptWithRts fieldName) - , checkAlternatives - fieldName - "extensions" - [ (flag, prettyShow extension) | flag <- ghc_options_no_rtsopts, Just extension <- [ghcExtension flag] - ] - , checkAlternatives - fieldName - "extensions" - [(flag, extension) | flag@('-' : 'X' : extension) <- ghc_options_no_rtsopts] - , checkAlternatives fieldName "cpp-options" $ - [(flag, flag) | flag@('-' : 'D' : _) <- ghc_options_no_rtsopts] - ++ [(flag, flag) | flag@('-' : 'U' : _) <- ghc_options_no_rtsopts] - , checkAlternatives - fieldName - "include-dirs" - [(flag, dir) | flag@('-' : 'I' : dir) <- ghc_options_no_rtsopts] - , checkAlternatives - fieldName - "extra-libraries" - [(flag, lib) | flag@('-' : 'l' : lib) <- ghc_options_no_rtsopts] - , checkAlternatives - fieldName - "extra-libraries-static" - [(flag, lib) | flag@('-' : 'l' : lib) <- ghc_options_no_rtsopts] - , checkAlternatives - fieldName - "extra-lib-dirs" - [(flag, dir) | flag@('-' : 'L' : dir) <- ghc_options_no_rtsopts] - , checkAlternatives - fieldName - "extra-lib-dirs-static" - [(flag, dir) | flag@('-' : 'L' : dir) <- ghc_options_no_rtsopts] - , checkAlternatives - fieldName - "frameworks" - [ (flag, fmwk) - | (flag@"-framework", fmwk) <- - zip ghc_options_no_rtsopts (safeTail ghc_options_no_rtsopts) - ] - , checkAlternatives - fieldName - "extra-framework-dirs" - [ (flag, dir) - | (flag@"-framework-path", dir) <- - zip ghc_options_no_rtsopts (safeTail ghc_options_no_rtsopts) - ] - ] - where - all_ghc_options = concatMap getOptions (allBuildInfo pkg) - ghc_options_no_rtsopts = rmRtsOpts all_ghc_options - lib_ghc_options = - concatMap - (getOptions . libBuildInfo) - (allLibraries pkg) - test_ghc_options = - concatMap - (getOptions . testBuildInfo) - (testSuites pkg) - benchmark_ghc_options = - concatMap - (getOptions . benchmarkBuildInfo) - (benchmarks pkg) - test_and_benchmark_ghc_options = - test_ghc_options - ++ benchmark_ghc_options - non_test_and_benchmark_ghc_options = - concatMap - getOptions - ( allBuildInfo - ( pkg - { testSuites = [] - , benchmarks = [] - } - ) - ) - - checkFlags :: [String] -> PackageCheck -> Maybe PackageCheck - checkFlags flags = check (any (`elem` flags) all_ghc_options) - - unlessScript :: Maybe PackageCheck -> Maybe PackageCheck - unlessScript pc - | packageId pkg == fakePackageId = Nothing - | otherwise = pc - - checkTestAndBenchmarkFlags :: [String] -> PackageCheck -> Maybe PackageCheck - checkTestAndBenchmarkFlags flags = check (any (`elem` flags) test_and_benchmark_ghc_options) - - checkNonTestAndBenchmarkFlags :: [String] -> PackageCheck -> Maybe PackageCheck - checkNonTestAndBenchmarkFlags flags = check (any (`elem` flags) non_test_and_benchmark_ghc_options) - - ghcExtension ('-' : 'f' : name) = case name of - "allow-overlapping-instances" -> enable OverlappingInstances - "no-allow-overlapping-instances" -> disable OverlappingInstances - "th" -> enable TemplateHaskell - "no-th" -> disable TemplateHaskell - "ffi" -> enable ForeignFunctionInterface - "no-ffi" -> disable ForeignFunctionInterface - "fi" -> enable ForeignFunctionInterface - "no-fi" -> disable ForeignFunctionInterface - "monomorphism-restriction" -> enable MonomorphismRestriction - "no-monomorphism-restriction" -> disable MonomorphismRestriction - "mono-pat-binds" -> enable MonoPatBinds - "no-mono-pat-binds" -> disable MonoPatBinds - "allow-undecidable-instances" -> enable UndecidableInstances - "no-allow-undecidable-instances" -> disable UndecidableInstances - "allow-incoherent-instances" -> enable IncoherentInstances - "no-allow-incoherent-instances" -> disable IncoherentInstances - "arrows" -> enable Arrows - "no-arrows" -> disable Arrows - "generics" -> enable Generics - "no-generics" -> disable Generics - "implicit-prelude" -> enable ImplicitPrelude - "no-implicit-prelude" -> disable ImplicitPrelude - "implicit-params" -> enable ImplicitParams - "no-implicit-params" -> disable ImplicitParams - "bang-patterns" -> enable BangPatterns - "no-bang-patterns" -> disable BangPatterns - "scoped-type-variables" -> enable ScopedTypeVariables - "no-scoped-type-variables" -> disable ScopedTypeVariables - "extended-default-rules" -> enable ExtendedDefaultRules - "no-extended-default-rules" -> disable ExtendedDefaultRules - _ -> Nothing - ghcExtension "-cpp" = enable CPP - ghcExtension _ = Nothing - - enable e = Just (EnableExtension e) - disable e = Just (DisableExtension e) - - rmRtsOpts :: [String] -> [String] - rmRtsOpts ("-with-rtsopts" : _ : xs) = rmRtsOpts xs - rmRtsOpts (x : xs) = x : rmRtsOpts xs - rmRtsOpts [] = [] - -checkCCOptions :: PackageDescription -> [PackageCheck] -checkCCOptions = checkCLikeOptions "C" "cc-options" ccOptions - -checkCxxOptions :: PackageDescription -> [PackageCheck] -checkCxxOptions = checkCLikeOptions "C++" "cxx-options" cxxOptions - -checkCLikeOptions :: String -> String -> (BuildInfo -> [String]) -> PackageDescription -> [PackageCheck] -checkCLikeOptions label prefix accessor pkg = - catMaybes - [ checkAlternatives - prefix - "include-dirs" - [(flag, dir) | flag@('-' : 'I' : dir) <- all_cLikeOptions] - , checkAlternatives - prefix - "extra-libraries" - [(flag, lib) | flag@('-' : 'l' : lib) <- all_cLikeOptions] - , checkAlternatives - prefix - "extra-lib-dirs" - [(flag, dir) | flag@('-' : 'L' : dir) <- all_cLikeOptions] - , checkAlternatives - "ld-options" - "extra-libraries" - [(flag, lib) | flag@('-' : 'l' : lib) <- all_ldOptions] - , checkAlternatives - "ld-options" - "extra-lib-dirs" - [(flag, dir) | flag@('-' : 'L' : dir) <- all_ldOptions] - , checkCCFlags ["-O", "-Os", "-O0", "-O1", "-O2", "-O3"] $ - PackageDistSuspicious (COptONumber prefix label) - ] +checkSourceRepos :: Monad m => [SourceRepo] -> CheckM m () +checkSourceRepos rs = do + mapM_ repoCheck rs + checkMissingVcsInfo rs where - all_cLikeOptions = - [ opts | bi <- allBuildInfo pkg, opts <- accessor bi - ] - all_ldOptions = - [ opts | bi <- allBuildInfo pkg, opts <- ldOptions bi - ] - - checkCCFlags :: [String] -> PackageCheck -> Maybe PackageCheck - checkCCFlags flags = check (any (`elem` flags) all_cLikeOptions) - -checkCPPOptions :: PackageDescription -> [PackageCheck] -checkCPPOptions pkg = - catMaybes - [ checkAlternatives - "cpp-options" - "include-dirs" - [(flag, dir) | flag@('-' : 'I' : dir) <- all_cppOptions] - ] - ++ [ PackageBuildWarning (COptCPP opt) - | opt <- all_cppOptions - , -- "-I" is handled above, we allow only -DNEWSTUFF and -UOLDSTUFF - not $ any (`isPrefixOf` opt) ["-D", "-U", "-I"] - ] - where - all_cppOptions = [opts | bi <- allBuildInfo pkg, opts <- cppOptions bi] - -checkAlternatives - :: String - -> String - -> [(String, String)] - -> Maybe PackageCheck -checkAlternatives badField goodField flags = - check (not (null badFlags)) $ - PackageBuildWarning (OptAlternatives badField goodField flags) - where - (badFlags, _) = unzip flags - -data PathKind - = PathKindFile - | PathKindDirectory - | PathKindGlob - deriving (Eq) - -checkPaths :: PackageDescription -> [PackageCheck] -checkPaths pkg = - checkPackageFileNamesWithGlob - [ (kind == PathKindGlob, path) - | (path, _, kind) <- relPaths ++ absPaths - ] - ++ [ PackageBuildWarning (RelativeOutside field path) - | (path, field, _) <- relPaths ++ absPaths - , isOutsideTree path - ] - ++ [ PackageDistInexcusable (AbsolutePath field path) - | (path, field, _) <- relPaths - , isAbsoluteOnAnyPlatform path - ] - ++ [ PackageDistInexcusable (BadRelativePAth field path err) - | (path, field, kind) <- relPaths - , -- these are not paths, but globs... - err <- maybeToList $ case kind of - PathKindFile -> isGoodRelativeFilePath path - PathKindGlob -> isGoodRelativeGlob path - PathKindDirectory -> isGoodRelativeDirectoryPath path - ] - ++ [ PackageDistInexcusable $ DistPoint (Just field) path - | (path, field, _) <- relPaths ++ absPaths - , isInsideDist path - ] - ++ [ PackageDistInexcusable (DistPoint Nothing path) - | bi <- allBuildInfo pkg - , (GHC, flags) <- perCompilerFlavorToList $ options bi - , path <- flags - , isInsideDist path - ] - ++ [ PackageDistInexcusable $ - GlobSyntaxError "data-files" (explainGlobSyntaxError pat err) - | (Left err, pat) <- zip globsDataFiles $ dataFiles pkg - ] - ++ [ PackageDistInexcusable - (GlobSyntaxError "extra-source-files" (explainGlobSyntaxError pat err)) - | (Left err, pat) <- zip globsExtraSrcFiles $ extraSrcFiles pkg - ] - ++ [ PackageDistInexcusable $ - GlobSyntaxError "extra-doc-files" (explainGlobSyntaxError pat err) - | (Left err, pat) <- zip globsExtraDocFiles $ extraDocFiles pkg - ] - ++ [ PackageDistSuspiciousWarn $ - RecursiveGlobInRoot "data-files" pat - | (Right glob, pat) <- zip globsDataFiles $ dataFiles pkg - , isRecursiveInRoot glob - ] - ++ [ PackageDistSuspiciousWarn $ - RecursiveGlobInRoot "extra-source-files" pat - | (Right glob, pat) <- zip globsExtraSrcFiles $ extraSrcFiles pkg - , isRecursiveInRoot glob - ] - ++ [ PackageDistSuspiciousWarn $ - RecursiveGlobInRoot "extra-doc-files" pat - | (Right glob, pat) <- zip globsExtraDocFiles $ extraDocFiles pkg - , isRecursiveInRoot glob - ] - where - isOutsideTree path = case splitDirectories path of - ".." : _ -> True - "." : ".." : _ -> True - _ -> False - isInsideDist path = case map lowercase (splitDirectories path) of - "dist" : _ -> True - "." : "dist" : _ -> True - _ -> False - - -- paths that must be relative - relPaths :: [(FilePath, String, PathKind)] - relPaths = - [(path, "extra-source-files", PathKindGlob) | path <- extraSrcFiles pkg] - ++ [(path, "extra-tmp-files", PathKindFile) | path <- extraTmpFiles pkg] - ++ [(path, "extra-doc-files", PathKindGlob) | path <- extraDocFiles pkg] - ++ [(path, "data-files", PathKindGlob) | path <- dataFiles pkg] - ++ [(path, "data-dir", PathKindDirectory) | path <- [dataDir pkg]] - ++ [(path, "license-file", PathKindFile) | path <- map getSymbolicPath $ licenseFiles pkg] - ++ concat - [ [(path, "asm-sources", PathKindFile) | path <- asmSources bi] - ++ [(path, "cmm-sources", PathKindFile) | path <- cmmSources bi] - ++ [(path, "c-sources", PathKindFile) | path <- cSources bi] - ++ [(path, "cxx-sources", PathKindFile) | path <- cxxSources bi] - ++ [(path, "js-sources", PathKindFile) | path <- jsSources bi] - ++ [(path, "install-includes", PathKindFile) | path <- installIncludes bi] - ++ [(path, "hs-source-dirs", PathKindDirectory) | path <- map getSymbolicPath $ hsSourceDirs bi] - | bi <- allBuildInfo pkg - ] - - -- paths that are allowed to be absolute - absPaths :: [(FilePath, String, PathKind)] - absPaths = - concat - [ [(path, "includes", PathKindFile) | path <- includes bi] - ++ [(path, "include-dirs", PathKindDirectory) | path <- includeDirs bi] - ++ [(path, "extra-lib-dirs", PathKindDirectory) | path <- extraLibDirs bi] - ++ [(path, "extra-lib-dirs-static", PathKindDirectory) | path <- extraLibDirsStatic bi] - | bi <- allBuildInfo pkg - ] - globsDataFiles :: [Either GlobSyntaxError Glob] - globsDataFiles = parseFileGlob (specVersion pkg) <$> dataFiles pkg - globsExtraSrcFiles :: [Either GlobSyntaxError Glob] - globsExtraSrcFiles = parseFileGlob (specVersion pkg) <$> extraSrcFiles pkg - globsExtraDocFiles :: [Either GlobSyntaxError Glob] - globsExtraDocFiles = parseFileGlob (specVersion pkg) <$> extraDocFiles pkg - --- TODO: check sets of paths that would be interpreted differently between Unix --- and windows, ie case-sensitive or insensitive. Things that might clash, or --- conversely be distinguished. - --- TODO: use the tar path checks on all the above paths - --- | Check that the package declares the version in the @\"cabal-version\"@ --- field correctly. -checkCabalVersion :: PackageDescription -> [PackageCheck] -checkCabalVersion pkg = - catMaybes - [ -- check use of test suite sections - checkVersion CabalSpecV1_8 (not (null $ testSuites pkg)) $ - PackageDistInexcusable CVTestSuite - , -- check use of default-language field - -- note that we do not need to do an equivalent check for the - -- other-language field since that one does not change behaviour - checkVersion CabalSpecV1_10 (any isJust (buildInfoField defaultLanguage)) $ - PackageBuildWarning CVDefaultLanguage - , check - ( specVersion pkg >= CabalSpecV1_10 - && specVersion pkg < CabalSpecV3_4 - && any isNothing (buildInfoField defaultLanguage) - ) - $ PackageBuildWarning CVDefaultLanguageComponent - , checkVersion - CabalSpecV1_18 - (not . null $ extraDocFiles pkg) - $ PackageDistInexcusable CVExtraDocFiles - , checkVersion - CabalSpecV2_0 - (not (null (subLibraries pkg))) - $ PackageDistInexcusable CVMultiLib - , -- check use of reexported-modules sections - checkVersion - CabalSpecV1_22 - (any (not . null . reexportedModules) (allLibraries pkg)) - $ PackageDistInexcusable CVReexported - , -- check use of thinning and renaming - checkVersion CabalSpecV2_0 usesBackpackIncludes $ - PackageDistInexcusable CVMixins - , -- check use of 'extra-framework-dirs' field - checkVersion CabalSpecV1_24 (any (not . null) (buildInfoField extraFrameworkDirs)) $ - -- Just a warning, because this won't break on old Cabal versions. - PackageDistSuspiciousWarn CVExtraFrameworkDirs - , -- check use of default-extensions field - -- don't need to do the equivalent check for other-extensions - checkVersion CabalSpecV1_10 (any (not . null) (buildInfoField defaultExtensions)) $ - PackageBuildWarning CVDefaultExtensions - , -- check use of extensions field - check - ( specVersion pkg >= CabalSpecV1_10 - && any (not . null) (buildInfoField oldExtensions) - ) - $ PackageBuildWarning CVExtensionsDeprecated - , checkVersion - CabalSpecV3_0 - ( any - (not . null) - ( concatMap - buildInfoField - [ asmSources - , cmmSources - , extraBundledLibs - , extraLibFlavours - ] - ) - ) - $ PackageDistInexcusable CVSources - , checkVersion CabalSpecV3_0 (any (not . null) $ buildInfoField extraDynLibFlavours) $ - PackageDistInexcusable - (CVExtraDynamic $ buildInfoField extraDynLibFlavours) - , checkVersion - CabalSpecV2_2 - ( any - (not . null) - (buildInfoField virtualModules) - ) - $ PackageDistInexcusable CVVirtualModules - , -- check use of "source-repository" section - checkVersion CabalSpecV1_6 (not (null (sourceRepos pkg))) $ - PackageDistInexcusable CVSourceRepository - , -- check for new language extensions - checkVersion CabalSpecV1_2 (not (null mentionedExtensionsThatNeedCabal12)) $ - PackageDistInexcusable - (CVExtensions CabalSpecV1_2 mentionedExtensionsThatNeedCabal12) - , checkVersion CabalSpecV1_4 (not (null mentionedExtensionsThatNeedCabal14)) $ - PackageDistInexcusable - (CVExtensions CabalSpecV1_4 mentionedExtensionsThatNeedCabal14) - , check - ( specVersion pkg >= CabalSpecV1_24 - && isNothing (setupBuildInfo pkg) - && buildType pkg == Custom - ) - $ PackageBuildWarning CVCustomSetup - , check - ( specVersion pkg < CabalSpecV1_24 - && isNothing (setupBuildInfo pkg) - && buildType pkg == Custom - ) - $ PackageDistSuspiciousWarn CVExpliticDepsCustomSetup - , check - ( specVersion pkg >= CabalSpecV2_0 - && elem (autogenPathsModuleName pkg) allModuleNames - && not (elem (autogenPathsModuleName pkg) allModuleNamesAutogen) - ) - $ PackageDistInexcusable CVAutogenPaths - , check - ( specVersion pkg >= CabalSpecV2_0 - && elem (autogenPackageInfoModuleName pkg) allModuleNames - && not (elem (autogenPackageInfoModuleName pkg) allModuleNamesAutogen) + -- Single repository checks. + repoCheck :: Monad m => SourceRepo -> CheckM m () + repoCheck + ( SourceRepo + repoKind_ + repoType_ + repoLocation_ + repoModule_ + _repoBranch_ + repoTag_ + repoSubdir_ + ) = do + case repoKind_ of + RepoKindUnknown kind -> + tellP + (PackageDistInexcusable $ UnrecognisedSourceRepo kind) + _ -> return () + checkP + (isNothing repoType_) + (PackageDistInexcusable MissingType) + checkP + (isNothing repoLocation_) + (PackageDistInexcusable MissingLocation) + checkP + ( repoType_ == Just (KnownRepoType CVS) + && isNothing repoModule_ + ) + (PackageDistInexcusable MissingModule) + checkP + (repoKind_ == RepoThis && isNothing repoTag_) + (PackageDistInexcusable MissingTag) + checkP + (any isAbsoluteOnAnyPlatform repoSubdir_) + (PackageDistInexcusable SubdirRelPath) + case join . fmap isGoodRelativeDirectoryPath $ repoSubdir_ of + Just err -> + tellP + (PackageDistInexcusable $ SubdirGoodRelPath err) + Nothing -> return () + +checkMissingVcsInfo :: Monad m => [SourceRepo] -> CheckM m () +checkMissingVcsInfo rs = + let rdirs = concatMap repoTypeDirname knownRepoTypes + in checkPkg + ( \ops -> do + us <- or <$> traverse (doesDirectoryExist ops) rdirs + return (null rs && us) ) - $ PackageDistInexcusable CVAutogenPackageInfo - ] + (PackageDistSuspicious MissingSourceControl) where - -- Perform a check on packages that use a version of the spec less than - -- the version given. This is for cases where a new Cabal version adds - -- a new feature and we want to check that it is not used prior to that - -- version. - checkVersion :: CabalSpecVersion -> Bool -> PackageCheck -> Maybe PackageCheck - checkVersion ver cond pc - | specVersion pkg >= ver = Nothing - | otherwise = check cond pc - - buildInfoField field = map field (allBuildInfo pkg) - - usesBackpackIncludes = any (not . null . mixins) (allBuildInfo pkg) - - mentionedExtensions = - [ ext | bi <- allBuildInfo pkg, ext <- allExtensions bi - ] - mentionedExtensionsThatNeedCabal12 = - nub (filter (`elem` compatExtensionsExtra) mentionedExtensions) - - -- As of Cabal-1.4 we can add new extensions without worrying about - -- breaking old versions of cabal. - mentionedExtensionsThatNeedCabal14 = - nub (filter (`notElem` compatExtensions) mentionedExtensions) - - -- The known extensions in Cabal-1.2.3 - compatExtensions = - map - EnableExtension - [ OverlappingInstances - , UndecidableInstances - , IncoherentInstances - , RecursiveDo - , ParallelListComp - , MultiParamTypeClasses - , FunctionalDependencies - , Rank2Types - , RankNTypes - , PolymorphicComponents - , ExistentialQuantification - , ScopedTypeVariables - , ImplicitParams - , FlexibleContexts - , FlexibleInstances - , EmptyDataDecls - , CPP - , BangPatterns - , TypeSynonymInstances - , TemplateHaskell - , ForeignFunctionInterface - , Arrows - , Generics - , NamedFieldPuns - , PatternGuards - , GeneralizedNewtypeDeriving - , ExtensibleRecords - , RestrictedTypeSynonyms - , HereDocuments - ] - ++ map - DisableExtension - [MonomorphismRestriction, ImplicitPrelude] - ++ compatExtensionsExtra - - -- The extra known extensions in Cabal-1.2.3 vs Cabal-1.1.6 - -- (Cabal-1.1.6 came with ghc-6.6. Cabal-1.2 came with ghc-6.8) - compatExtensionsExtra = - map - EnableExtension - [ KindSignatures - , MagicHash - , TypeFamilies - , StandaloneDeriving - , UnicodeSyntax - , PatternSignatures - , UnliftedFFITypes - , LiberalTypeSynonyms - , TypeOperators - , RecordWildCards - , RecordPuns - , DisambiguateRecordFields - , OverloadedStrings - , GADTs - , RelaxedPolyRec - , ExtendedDefaultRules - , UnboxedTuples - , DeriveDataTypeable - , ConstrainedClassMethods - ] - ++ map - DisableExtension - [MonoPatBinds] - - allModuleNames = - ( case library pkg of - Nothing -> [] - (Just lib) -> explicitLibModules lib - ) - ++ concatMap otherModules (allBuildInfo pkg) - - allModuleNamesAutogen = concatMap autogenModules (allBuildInfo pkg) + repoTypeDirname :: KnownRepoType -> [FilePath] + repoTypeDirname Darcs = ["_darcs"] + repoTypeDirname Git = [".git"] + repoTypeDirname SVN = [".svn"] + repoTypeDirname CVS = ["CVS"] + repoTypeDirname Mercurial = [".hg"] + repoTypeDirname GnuArch = [".arch-params"] + repoTypeDirname Bazaar = [".bzr"] + repoTypeDirname Monotone = ["_MTN"] + repoTypeDirname Pijul = [".pijul"] -- ------------------------------------------------------------ - --- * Checks on the GenericPackageDescription - +-- Package and distribution checks -- ------------------------------------------------------------ --- | Check the build-depends fields for any weirdness or bad practice. -checkPackageVersions :: GenericPackageDescription -> [PackageCheck] -checkPackageVersions pkg = - -- if others is empty, - -- the error will still fire but listing no dependencies. - -- so we have to check - if length others > 0 - then PackageDistSuspiciousWarn (MissingUpperBounds others) : baseErrors - else baseErrors - where - baseErrors = PackageDistInexcusable BaseNoUpperBounds <$ bases - deps = toDependencyVersionsMap allNonInternalBuildDepends pkg - -- base gets special treatment (it's more critical) - (bases, others) = - partition (("base" ==) . unPackageName) $ - [ name - | (name, vr) <- Map.toList deps - , not (hasUpperBound vr) - ] - - -- Get the combined build-depends entries of all components. - allNonInternalBuildDepends :: PackageDescription -> [Dependency] - allNonInternalBuildDepends = targetBuildDepends CM.<=< allNonInternalBuildInfo - - allNonInternalBuildInfo :: PackageDescription -> [BuildInfo] - allNonInternalBuildInfo pkg_descr = - [bi | lib <- allLibraries pkg_descr, let bi = libBuildInfo lib] - ++ [bi | flib <- foreignLibs pkg_descr, let bi = foreignLibBuildInfo flib] - ++ [bi | exe <- executables pkg_descr, let bi = buildInfo exe] - -checkConditionals :: GenericPackageDescription -> [PackageCheck] -checkConditionals pkg = - catMaybes - [ check (not $ null unknownOSs) $ - PackageDistInexcusable (UnknownOS unknownOSs) - , check (not $ null unknownArches) $ - PackageDistInexcusable (UnknownArch unknownArches) - , check (not $ null unknownImpls) $ - PackageDistInexcusable (UnknownCompiler unknownImpls) - ] - where - unknownOSs = [os | OS (OtherOS os) <- conditions] - unknownArches = [arch | Arch (OtherArch arch) <- conditions] - unknownImpls = [impl | Impl (OtherCompiler impl) _ <- conditions] - conditions = - concatMap fvs (maybeToList (condLibrary pkg)) - ++ concatMap (fvs . snd) (condSubLibraries pkg) - ++ concatMap (fvs . snd) (condForeignLibs pkg) - ++ concatMap (fvs . snd) (condExecutables pkg) - ++ concatMap (fvs . snd) (condTestSuites pkg) - ++ concatMap (fvs . snd) (condBenchmarks pkg) - fvs (CondNode _ _ ifs) = concatMap compfv ifs -- free variables - compfv (CondBranch c ct mct) = condfv c ++ fvs ct ++ maybe [] fvs mct - condfv c = case c of - Var v -> [v] - Lit _ -> [] - CNot c1 -> condfv c1 - COr c1 c2 -> condfv c1 ++ condfv c2 - CAnd c1 c2 -> condfv c1 ++ condfv c2 - -checkFlagNames :: GenericPackageDescription -> [PackageCheck] -checkFlagNames gpd - | null invalidFlagNames = [] - | otherwise = - [PackageDistInexcusable (SuspiciousFlagName invalidFlagNames)] - where - invalidFlagNames = - [ fn - | flag <- genPackageFlags gpd - , let fn = unFlagName (flagName flag) - , invalidFlagName fn +-- | Find a package description file in the given directory. Looks for +-- @.cabal@ files. Like 'Distribution.Simple.Utils.findPackageDesc', +-- but generalized over monads. +findPackageDesc :: Monad m => CheckPackageContentOps m -> m [FilePath] +findPackageDesc ops = do + let dir = "." + files <- getDirectoryContents ops dir + -- to make sure we do not mistake a ~/.cabal/ dir for a .cabal + -- file we filter to exclude dirs and null base file names: + cabalFiles <- + filterM + (doesFileExist ops) + [ dir file + | file <- files + , let (name, ext) = splitExtension file + , not (null name) && ext == ".cabal" ] - -- starts with dash - invalidFlagName ('-' : _) = True - -- mon ascii letter - invalidFlagName cs = any (not . isAscii) cs - -checkUnusedFlags :: GenericPackageDescription -> [PackageCheck] -checkUnusedFlags gpd - | declared == used = [] - | otherwise = - [PackageDistSuspicious (DeclaredUsedFlags declared used)] - where - declared :: Set.Set FlagName - declared = toSetOf (L.genPackageFlags . traverse . L.flagName) gpd - - used :: Set.Set FlagName - used = - mconcat - [ toSetOf (L.condLibrary . traverse . traverseCondTreeV . L._PackageFlag) gpd - , toSetOf (L.condSubLibraries . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd - , toSetOf (L.condForeignLibs . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd - , toSetOf (L.condExecutables . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd - , toSetOf (L.condTestSuites . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd - , toSetOf (L.condBenchmarks . traverse . _2 . traverseCondTreeV . L._PackageFlag) gpd - ] - -checkUnicodeXFields :: GenericPackageDescription -> [PackageCheck] -checkUnicodeXFields gpd - | null nonAsciiXFields = [] - | otherwise = - [PackageDistInexcusable (NonASCIICustomField nonAsciiXFields)] - where - nonAsciiXFields :: [String] - nonAsciiXFields = [n | (n, _) <- xfields, any (not . isAscii) n] - - xfields :: [(String, String)] - xfields = - DList.runDList $ - mconcat - [ toDListOf (L.packageDescription . L.customFieldsPD . traverse) gpd - , toDListOf (L.traverseBuildInfos . L.customFieldsBI . traverse) gpd - ] - --- | cabal-version <2.2 + Paths_module + default-extensions: doesn't build. -checkPathsModuleExtensions :: PackageDescription -> [PackageCheck] -checkPathsModuleExtensions = checkAutogenModuleExtensions autogenPathsModuleName RebindableClashPaths - --- | cabal-version <2.2 + PackageInfo_module + default-extensions: doesn't build. -checkPackageInfoModuleExtensions :: PackageDescription -> [PackageCheck] -checkPackageInfoModuleExtensions = checkAutogenModuleExtensions autogenPackageInfoModuleName RebindableClashPackageInfo - --- | cabal-version <2.2 + *_module + default-extensions: doesn't build. -checkAutogenModuleExtensions - :: (PackageDescription -> ModuleName) - -> CheckExplanation - -> PackageDescription - -> [PackageCheck] -checkAutogenModuleExtensions autogenModuleName rebindableClashExplanation pd - | specVersion pd >= CabalSpecV2_2 = [] - | any checkBI (allBuildInfo pd) || any checkLib (allLibraries pd) = - return (PackageBuildImpossible rebindableClashExplanation) - | otherwise = [] - where - mn = autogenModuleName pd - - checkLib :: Library -> Bool - checkLib l = mn `elem` exposedModules l && checkExts (l ^. L.defaultExtensions) - - checkBI :: BuildInfo -> Bool - checkBI bi = - (mn `elem` otherModules bi || mn `elem` autogenModules bi) - && checkExts (bi ^. L.defaultExtensions) - - checkExts exts = rebind `elem` exts && (strings `elem` exts || lists `elem` exts) - where - rebind = EnableExtension RebindableSyntax - strings = EnableExtension OverloadedStrings - lists = EnableExtension OverloadedLists - --- | Checks GHC options from all ghc-*-options fields from the given BuildInfo --- and reports flags that are OK during development process, but are --- unacceptable in a distributed package -checkDevelopmentOnlyFlagsBuildInfo :: BuildInfo -> [PackageCheck] -checkDevelopmentOnlyFlagsBuildInfo bi = - checkDevelopmentOnlyFlagsOptions "ghc-options" (hcOptions GHC bi) - ++ checkDevelopmentOnlyFlagsOptions "ghc-prof-options" (hcProfOptions GHC bi) - ++ checkDevelopmentOnlyFlagsOptions "ghc-shared-options" (hcSharedOptions GHC bi) - --- | Checks the given list of flags belonging to the given field and reports --- flags that are OK during development process, but are unacceptable in a --- distributed package -checkDevelopmentOnlyFlagsOptions :: String -> [String] -> [PackageCheck] -checkDevelopmentOnlyFlagsOptions fieldName ghcOptions = - catMaybes - [ check has_Werror $ - PackageDistInexcusable (WErrorUnneeded fieldName) - , check has_J $ - PackageDistInexcusable (JUnneeded fieldName) - , checkFlags ["-fdefer-type-errors"] $ - PackageDistInexcusable (FDeferTypeErrorsUnneeded fieldName) - , -- -dynamic is not a debug flag - check - ( any - (\opt -> "-d" `isPrefixOf` opt && opt /= "-dynamic") - ghcOptions - ) - $ PackageDistInexcusable (DynamicUnneeded fieldName) - , checkFlags - [ "-fprof-auto" - , "-fprof-auto-top" - , "-fprof-auto-calls" - , "-fprof-cafs" - , "-fno-prof-count-entries" - , "-auto-all" - , "-auto" - , "-caf-all" - ] - $ PackageDistSuspicious (ProfilingUnneeded fieldName) - ] - where - has_Werror = "-Werror" `elem` ghcOptions - has_J = - any - ( \o -> case o of - "-j" -> True - ('-' : 'j' : d : _) -> isDigit d - _ -> False - ) - ghcOptions - checkFlags :: [String] -> PackageCheck -> Maybe PackageCheck - checkFlags flags = check (any (`elem` flags) ghcOptions) - -checkDevelopmentOnlyFlags :: GenericPackageDescription -> [PackageCheck] -checkDevelopmentOnlyFlags pkg = - concatMap - checkDevelopmentOnlyFlagsBuildInfo - [ bi - | (conditions, bi) <- allConditionalBuildInfo - , not (any guardedByManualFlag conditions) - ] + return cabalFiles + +checkCabalFile :: Monad m => PackageName -> CheckM m () +checkCabalFile pn = do + -- liftInt is a bit more messy than stricter interface, but since + -- each of the following check is exclusive, we can simplify the + -- condition flow. + liftInt + ciPackageOps + ( \ops -> do + -- 1. Get .cabal files. + ds <- findPackageDesc ops + case ds of + [] -> return [PackageBuildImpossible NoDesc] + -- No .cabal file. + [d] -> do + bc <- bomf ops d + return (catMaybes [bc, noMatch d]) + -- BOM + no matching .cabal checks. + _ -> return [PackageBuildImpossible $ MultiDesc ds] + ) where - guardedByManualFlag = definitelyFalse - - -- We've basically got three-values logic here: True, False or unknown - -- hence this pattern to propagate the unknown cases properly. - definitelyFalse (Var (PackageFlag n)) = maybe False not (Map.lookup n manualFlags) - definitelyFalse (Var _) = False - definitelyFalse (Lit b) = not b - definitelyFalse (CNot c) = definitelyTrue c - definitelyFalse (COr c1 c2) = definitelyFalse c1 && definitelyFalse c2 - definitelyFalse (CAnd c1 c2) = definitelyFalse c1 || definitelyFalse c2 - - definitelyTrue (Var (PackageFlag n)) = fromMaybe False (Map.lookup n manualFlags) - definitelyTrue (Var _) = False - definitelyTrue (Lit b) = b - definitelyTrue (CNot c) = definitelyFalse c - definitelyTrue (COr c1 c2) = definitelyTrue c1 || definitelyTrue c2 - definitelyTrue (CAnd c1 c2) = definitelyTrue c1 && definitelyTrue c2 - - manualFlags = - Map.fromList - [ (flagName flag, flagDefault flag) - | flag <- genPackageFlags pkg - , flagManual flag - ] - - allConditionalBuildInfo :: [([Condition ConfVar], BuildInfo)] - allConditionalBuildInfo = - concatMap - (collectCondTreePaths libBuildInfo) - (maybeToList (condLibrary pkg)) - ++ concatMap - (collectCondTreePaths libBuildInfo . snd) - (condSubLibraries pkg) - ++ concatMap - (collectCondTreePaths buildInfo . snd) - (condExecutables pkg) - ++ concatMap - (collectCondTreePaths testBuildInfo . snd) - (condTestSuites pkg) - ++ concatMap - (collectCondTreePaths benchmarkBuildInfo . snd) - (condBenchmarks pkg) - - -- get all the leaf BuildInfo, paired up with the path (in the tree sense) - -- of if-conditions that guard it - collectCondTreePaths - :: (a -> b) - -> CondTree v c a - -> [([Condition v], b)] - collectCondTreePaths mapData = go [] - where - go conditions condNode = - -- the data at this level in the tree: - (reverse conditions, mapData (condTreeData condNode)) - : concat - [ go (condition : conditions) ifThen - | (CondBranch condition ifThen _) <- condTreeComponents condNode - ] - ++ concat - [ go (condition : conditions) elseThen - | (CondBranch condition _ (Just elseThen)) <- condTreeComponents condNode - ] - --- ------------------------------------------------------------ - --- * Checks involving files in the package + -- Multiple .cabal files. --- ------------------------------------------------------------ - --- | Sanity check things that requires IO. It looks at the files in the --- package and expects to find the package unpacked in at the given file path. -checkPackageFiles :: Verbosity -> PackageDescription -> FilePath -> IO [PackageCheck] -checkPackageFiles verbosity pkg root = do - contentChecks <- checkPackageContent checkFilesIO pkg - preDistributionChecks <- checkPackageFilesPreDistribution verbosity pkg root - -- Sort because different platforms will provide files from - -- `getDirectoryContents` in different orders, and we'd like to be - -- stable for test output. - return (sort contentChecks ++ sort preDistributionChecks) - where - checkFilesIO = - CheckPackageContentOps - { doesFileExist = System.doesFileExist . relative - , doesDirectoryExist = System.doesDirectoryExist . relative - , getDirectoryContents = System.Directory.getDirectoryContents . relative - , getFileContents = BS.readFile . relative - } - relative path = root path - --- | A record of operations needed to check the contents of packages. --- Used by 'checkPackageContent'. -data CheckPackageContentOps m = CheckPackageContentOps - { doesFileExist :: FilePath -> m Bool - , doesDirectoryExist :: FilePath -> m Bool - , getDirectoryContents :: FilePath -> m [FilePath] - , getFileContents :: FilePath -> m BS.ByteString - } + bomf + :: Monad m + => CheckPackageContentOps m + -> FilePath + -> m (Maybe PackageCheck) + bomf wops wfp = do + b <- BS.isPrefixOf bomUtf8 <$> getFileContents wops wfp + if b + then (return . Just) (PackageDistInexcusable $ BOMStart wfp) + else return Nothing --- | Sanity check things that requires looking at files in the package. --- This is a generalised version of 'checkPackageFiles' that can work in any --- monad for which you can provide 'CheckPackageContentOps' operations. --- --- The point of this extra generality is to allow doing checks in some virtual --- file system, for example a tarball in memory. -checkPackageContent - :: (Monad m, Applicative m) - => CheckPackageContentOps m - -> PackageDescription - -> m [PackageCheck] -checkPackageContent ops pkg = do - cabalBomError <- checkCabalFileBOM ops - cabalNameError <- checkCabalFileName ops pkg - licenseErrors <- checkLicensesExist ops pkg - setupError <- checkSetupExists ops pkg - configureError <- checkConfigureExists ops pkg - localPathErrors <- checkLocalPathsExist ops pkg - vcsLocation <- checkMissingVcsInfo ops pkg - - return $ - licenseErrors - ++ catMaybes [cabalBomError, cabalNameError, setupError, configureError] - ++ localPathErrors - ++ vcsLocation - -checkCabalFileBOM - :: Monad m - => CheckPackageContentOps m - -> m (Maybe PackageCheck) -checkCabalFileBOM ops = do - epdfile <- findPackageDesc ops - case epdfile of - -- MASSIVE HACK. If the Cabal file doesn't exist, that is - -- a very strange situation to be in, because the driver code - -- in 'Distribution.Setup' ought to have noticed already! - -- But this can be an issue, see #3552 and also when - -- --cabal-file is specified. So if you can't find the file, - -- just don't bother with this check. - Left _ -> return Nothing - Right pdfile -> - (flip check pc . BS.isPrefixOf bomUtf8) - `liftM` getFileContents ops pdfile - where - pc = PackageDistInexcusable (BOMStart pdfile) - where bomUtf8 :: BS.ByteString bomUtf8 = BS.pack [0xef, 0xbb, 0xbf] -- U+FEFF encoded as UTF8 - -checkCabalFileName + noMatch :: FilePath -> Maybe PackageCheck + noMatch wd = + let expd = unPackageName pn <.> "cabal" + in if takeFileName wd /= expd + then Just (PackageDistInexcusable $ NotPackageName wd expd) + else Nothing + +checkLicFileExist :: Monad m - => CheckPackageContentOps m - -> PackageDescription - -> m (Maybe PackageCheck) -checkCabalFileName ops pkg = do - -- findPackageDesc already takes care to detect missing/multiple - -- .cabal files; we don't include this check in 'findPackageDesc' in - -- order not to short-cut other checks which call 'findPackageDesc' - epdfile <- findPackageDesc ops - case epdfile of - -- see "MASSIVE HACK" note in 'checkCabalFileBOM' - Left _ -> return Nothing - Right pdfile - | takeFileName pdfile == expectedCabalname -> return Nothing - | otherwise -> - return $ - Just $ - PackageDistInexcusable - (NotPackageName pdfile expectedCabalname) - where - pkgname = unPackageName . packageName $ pkg - expectedCabalname = pkgname <.> "cabal" - --- | Find a package description file in the given directory. Looks for --- @.cabal@ files. Like 'Distribution.Simple.Utils.findPackageDesc', --- but generalized over monads. -findPackageDesc - :: Monad m - => CheckPackageContentOps m - -> m (Either PackageCheck FilePath) - -- ^ .cabal -findPackageDesc ops = - do - let dir = "." - files <- getDirectoryContents ops dir - -- to make sure we do not mistake a ~/.cabal/ dir for a .cabal - -- file we filter to exclude dirs and null base file names: - cabalFiles <- - filterM - (doesFileExist ops) - [ dir file - | file <- files - , let (name, ext) = splitExtension file - , not (null name) && ext == ".cabal" - ] - case cabalFiles of - [] -> return (Left $ PackageBuildImpossible NoDesc) - [cabalFile] -> return (Right cabalFile) - multiple -> - return - ( Left $ - PackageBuildImpossible - (MultiDesc multiple) - ) + => SymbolicPath PackageDir LicenseFile + -> CheckM m () +checkLicFileExist sp = do + let fp = getSymbolicPath sp + checkPkg + (\ops -> not <$> doesFileExist ops fp) + (PackageBuildWarning $ UnknownFile "license-file" sp) + +checkConfigureExists :: Monad m => BuildType -> CheckM m () +checkConfigureExists Configure = + checkPkg + (\ops -> not <$> doesFileExist ops "configure") + (PackageBuildWarning MissingConfigureScript) +checkConfigureExists _ = return () + +checkSetupExists :: Monad m => BuildType -> CheckM m () +checkSetupExists Simple = return () +checkSetupExists _ = + checkPkg + ( \ops -> do + ba <- doesFileExist ops "Setup.hs" + bb <- doesFileExist ops "Setup.lhs" + return (not $ ba || bb) + ) + (PackageDistInexcusable MissingSetupFile) -checkLicensesExist - :: (Monad m, Applicative m) - => CheckPackageContentOps m - -> PackageDescription - -> m [PackageCheck] -checkLicensesExist ops pkg = do - exists <- traverse (doesFileExist ops . getSymbolicPath) (licenseFiles pkg) - return - [ PackageBuildWarning (UnknownFile fieldname file) - | (file, False) <- zip (licenseFiles pkg) exists - ] - where - fieldname - | length (licenseFiles pkg) == 1 = "license-file" - | otherwise = "license-files" +-- The following functions are similar to 'CheckPackageContentOps m' ones, +-- but, as they inspect the files included in the package, but are primarily +-- looking for files in the working tree that may have been missed or other +-- similar problems that can only be detected pre-distribution. +-- +-- Because Hackage necessarily checks the uploaded tarball, it is too late to +-- check these on the server; these checks only make sense in the development +-- and package-creation environment. +-- This most likely means we need to use IO, but a dictionary +-- 'CheckPreDistributionOps m' is provided in case in the future such +-- information can come from somewhere else (e.g. VCS filesystem). +-- +-- Note: this really shouldn't return any 'Inexcusable' warnings, +-- because that will make us say that Hackage would reject the package. +-- But, because Hackage doesn't yet run these tests, that will be a lie! -checkSetupExists +checkGlobFile :: Monad m - => CheckPackageContentOps m - -> PackageDescription - -> m (Maybe PackageCheck) -checkSetupExists ops pkg = do - let simpleBuild = buildType pkg == Simple - hsexists <- doesFileExist ops "Setup.hs" - lhsexists <- doesFileExist ops "Setup.lhs" - return $ - check (not simpleBuild && not hsexists && not lhsexists) $ - PackageDistInexcusable MissingSetupFile - -checkConfigureExists - :: Monad m - => CheckPackageContentOps m - -> PackageDescription - -> m (Maybe PackageCheck) -checkConfigureExists ops pd - | buildType pd == Configure = do - exists <- doesFileExist ops "configure" - return $ - check (not exists) $ - PackageBuildWarning MissingConfigureScript - | otherwise = return Nothing - -checkLocalPathsExist - :: Monad m - => CheckPackageContentOps m - -> PackageDescription - -> m [PackageCheck] -checkLocalPathsExist ops pkg = do - let dirs = - [ (dir, kind) - | bi <- allBuildInfo pkg - , (dir, kind) <- - [(dir, "extra-lib-dirs") | dir <- extraLibDirs bi] - ++ [(dir, "extra-lib-dirs-static") | dir <- extraLibDirsStatic bi] - ++ [ (dir, "extra-framework-dirs") - | dir <- extraFrameworkDirs bi - ] - ++ [(dir, "include-dirs") | dir <- includeDirs bi] - ++ [(getSymbolicPath dir, "hs-source-dirs") | dir <- hsSourceDirs bi] - , isRelativeOnAnyPlatform dir - ] - missing <- filterM (liftM not . doesDirectoryExist ops . fst) dirs - return - [ PackageBuildWarning (UnknownDirectory kind dir) - | (dir, kind) <- missing - ] - -checkMissingVcsInfo - :: (Monad m, Applicative m) - => CheckPackageContentOps m - -> PackageDescription - -> m [PackageCheck] -checkMissingVcsInfo ops pkg | null (sourceRepos pkg) = do - vcsInUse <- liftM or $ traverse (doesDirectoryExist ops) repoDirnames - if vcsInUse - then return [PackageDistSuspicious MissingSourceControl] - else return [] + => CabalSpecVersion + -> FilePath -- Glob pattern. + -> FilePath -- Folder to check. + -> CabalField -- .cabal field we are checking. + -> CheckM m () +checkGlobFile cv ddir title fp = do + let adjDdir = if null ddir then "." else ddir + dir + | title == "data-files" = adjDdir + | otherwise = "." + + case parseFileGlob cv fp of + -- We just skip over parse errors here; they're reported elsewhere. + Left _ -> return () + Right parsedGlob -> do + liftInt ciPreDistOps $ \po -> do + rs <- runDirFileGlobM po dir parsedGlob + return $ checkGlobResult title fp rs + +-- | Checks for matchless globs and too strict matching (<2.4 spec). +checkGlobResult + :: CabalField -- .cabal field we are checking + -> FilePath -- Glob pattern (to show the user + -- which pattern is the offending + -- one). + -> [GlobResult FilePath] -- List of glob results. + -> [PackageCheck] +checkGlobResult title fp rs = dirCheck ++ catMaybes (map getWarning rs) where - repoDirnames = - [ dirname | repo <- knownRepoTypes, dirname <- repoTypeDirname repo - ] -checkMissingVcsInfo _ _ = return [] - -repoTypeDirname :: KnownRepoType -> [FilePath] -repoTypeDirname Darcs = ["_darcs"] -repoTypeDirname Git = [".git"] -repoTypeDirname SVN = [".svn"] -repoTypeDirname CVS = ["CVS"] -repoTypeDirname Mercurial = [".hg"] -repoTypeDirname GnuArch = [".arch-params"] -repoTypeDirname Bazaar = [".bzr"] -repoTypeDirname Monotone = ["_MTN"] -repoTypeDirname Pijul = [".pijul"] + dirCheck + | all (not . withoutNoMatchesWarning) rs = + [PackageDistSuspiciousWarn $ GlobNoMatch title fp] + | otherwise = [] + + -- If there's a missing directory in play, since globs in Cabal packages + -- don't (currently) support disjunction, that will always mean there are + -- no matches. The no matches error in this case is strictly less + -- informative than the missing directory error. + withoutNoMatchesWarning (GlobMatch _) = True + withoutNoMatchesWarning (GlobWarnMultiDot _) = False + withoutNoMatchesWarning (GlobMissingDirectory _) = True + withoutNoMatchesWarning (GlobMatchesDirectory _) = True + + getWarning :: GlobResult FilePath -> Maybe PackageCheck + getWarning (GlobMatch _) = Nothing + -- Before Cabal 2.4, the extensions of globs had to match the file + -- exactly. This has been relaxed in 2.4 to allow matching only the + -- suffix. This warning detects when pre-2.4 package descriptions + -- are omitting files purely because of the stricter check. + getWarning (GlobWarnMultiDot file) = + Just $ PackageDistSuspiciousWarn (GlobExactMatch title fp file) + getWarning (GlobMissingDirectory dir) = + Just $ PackageDistSuspiciousWarn (GlobNoDir title fp dir) + -- GlobMatchesDirectory is handled elsewhere if relevant; + -- we can discard it here. + getWarning (GlobMatchesDirectory _) = Nothing -- ------------------------------------------------------------ - --- * Checks involving files in the package - +-- Other exports -- ------------------------------------------------------------ --- | Check the names of all files in a package for portability problems. This --- should be done for example when creating or validating a package tarball. -checkPackageFileNames :: [FilePath] -> [PackageCheck] -checkPackageFileNames = checkPackageFileNamesWithGlob . zip (repeat True) - -checkPackageFileNamesWithGlob :: [(Bool, FilePath)] -> [PackageCheck] -checkPackageFileNamesWithGlob files = - catMaybes $ - checkWindowsPaths files - : [ checkTarPath file - | (_, file) <- files - ] - -checkWindowsPaths :: [(Bool, FilePath)] -> Maybe PackageCheck -checkWindowsPaths paths = - case filter (not . FilePath.Windows.isValid . escape) paths of - [] -> Nothing - ps -> - Just $ - PackageDistInexcusable (InvalidOnWin $ map snd ps) - where - -- force a relative name to catch invalid file names like "f:oo" which - -- otherwise parse as file "oo" in the current directory on the 'f' drive. - escape (isGlob, path) = - (".\\" ++) - -- glob paths will be expanded before being dereferenced, so asterisks - -- shouldn't count against them. - $ - map (\c -> if c == '*' && isGlob then 'x' else c) path - --- | Check a file name is valid for the portable POSIX tar format. --- --- The POSIX tar format has a restriction on the length of file names. It is --- unfortunately not a simple restriction like a maximum length. The exact --- restriction is that either the whole path be 100 characters or less, or it --- be possible to split the path on a directory separator such that the first --- part is 155 characters or less and the second part 100 characters or less. -checkTarPath :: FilePath -> Maybe PackageCheck -checkTarPath path - | length path > 255 = Just longPath - | otherwise = case pack nameMax (reverse (splitPath path)) of - Left err -> Just err - Right [] -> Nothing - Right (h : rest) -> case pack prefixMax remainder of - Left err -> Just err - Right [] -> Nothing - Right (_ : _) -> Just noSplit - where - -- drop the '/' between the name and prefix: - remainder = safeInit h : rest - where - nameMax, prefixMax :: Int - nameMax = 100 - prefixMax = 155 - - pack _ [] = Left emptyName - pack maxLen (c : cs) - | n > maxLen = Left longName - | otherwise = Right (pack' maxLen n cs) - where - n = length c - - pack' maxLen n (c : cs) - | n' <= maxLen = pack' maxLen n' cs - where - n' = n + length c - pack' _ _ cs = cs - - longPath = PackageDistInexcusable (FilePathTooLong path) - longName = PackageDistInexcusable (FilePathNameTooLong path) - noSplit = PackageDistInexcusable (FilePathSplitTooLong path) - emptyName = PackageDistInexcusable FilePathEmpty +-- | Wraps `ParseWarning` into `PackageCheck`. +wrapParseWarning :: FilePath -> PWarning -> PackageCheck +wrapParseWarning fp pw = PackageDistSuspicious (ParseWarning fp pw) --- -------------------------------------------------------------- +-- TODO: as Jul 2022 there is no severity indication attached PWarnType. +-- Once that is added, we can output something more appropriate +-- than PackageDistSuspicious for every parse warning. +-- (see: Cabal-syntax/src/Distribution/Parsec/Warning.hs) --- * Checks for missing content and other pre-distribution checks +-- ------------------------------------------------------------ +-- Ancillaries +-- ------------------------------------------------------------ --- -------------------------------------------------------------- +-- Gets a list of dependencies from a Library target to pass to PVP related +-- functions. We are not doing checks here: this is not imprecise, as the +-- library itself *will* be checked for PVP errors. +-- Same for branch merging, +-- each of those branch will be checked one by one. +extractAssocDeps + :: UnqualComponentName -- Name of the target library + -> CondTree ConfVar [Dependency] Library + -> AssocDep +extractAssocDeps n ct = + let a = ignoreConditions ct + in -- Merging is fine here, remember the specific + -- library dependencies will be checked branch + -- by branch. + (n, snd a) + +-- | August 2022: this function is an oddity due to the historical +-- GenericPackageDescription/PackageDescription split (check +-- Distribution.Types.PackageDescription for a description of the relationship +-- between GPD and PD. +-- It is only maintained not to break interface, should be deprecated in the +-- future in favour of `checkPackage` when PD and GPD are refactored sensibly. +pd2gpd :: PackageDescription -> GenericPackageDescription +pd2gpd pd = gpd + where + gpd :: GenericPackageDescription + gpd = + emptyGenericPackageDescription + { packageDescription = pd + , condLibrary = fmap t2c (library pd) + , condSubLibraries = map (t2cName ln id) (subLibraries pd) + , condForeignLibs = + map + (t2cName foreignLibName id) + (foreignLibs pd) + , condExecutables = + map + (t2cName exeName id) + (executables pd) + , condTestSuites = + map + (t2cName testName remTest) + (testSuites pd) + , condBenchmarks = + map + (t2cName benchmarkName remBench) + (benchmarks pd) + } --- | Similar to 'checkPackageContent', 'checkPackageFilesPreDistribution' --- inspects the files included in the package, but is primarily looking for --- files in the working tree that may have been missed or other similar --- problems that can only be detected pre-distribution. --- --- Because Hackage necessarily checks the uploaded tarball, it is too late to --- check these on the server; these checks only make sense in the development --- and package-creation environment. Hence we can use IO, rather than needing --- to pass a 'CheckPackageContentOps' dictionary around. -checkPackageFilesPreDistribution :: Verbosity -> PackageDescription -> FilePath -> IO [PackageCheck] --- Note: this really shouldn't return any 'Inexcusable' warnings, --- because that will make us say that Hackage would reject the package. --- But, because Hackage doesn't run these tests, that will be a lie! -checkPackageFilesPreDistribution = checkGlobFiles + -- From target to simple, unconditional CondTree. + t2c :: a -> CondTree ConfVar [Dependency] a + t2c a = CondNode a [] [] + + -- From named target to unconditional CondTree. Notice we have + -- a function to extract the name *and* a function to modify + -- the target. This is needed for 'initTargetAnnotation' to work + -- properly and to contain all the quirks inside 'pd2gpd'. + t2cName + :: (a -> UnqualComponentName) + -> (a -> a) + -> a + -> (UnqualComponentName, CondTree ConfVar [Dependency] a) + t2cName nf mf a = (nf a, t2c . mf $ a) + + ln :: Library -> UnqualComponentName + ln wl = case libName wl of + (LSubLibName u) -> u + LMainLibName -> mkUnqualComponentName "main-library" + + remTest :: TestSuite -> TestSuite + remTest t = t{testName = mempty} + + remBench :: Benchmark -> Benchmark + remBench b = b{benchmarkName = mempty} + +-- checkMissingDocs will check that we don’t have an interesting file +-- (changes.txt, Changelog.md, NEWS, etc.) in our work-tree which is not +-- present in our .cabal file. +checkMissingDocs + :: Monad m + => [Glob] -- data-files globs. + -> [Glob] -- extra-source-files globs. + -> [Glob] -- extra-doc-files globs. + -> CheckM m () +checkMissingDocs dgs esgs edgs = do + extraDocSupport <- (>= CabalSpecV1_18) <$> asksCM ccSpecVersion + + -- Everything in this block uses CheckPreDistributionOps interface. + liftInt + ciPreDistOps + ( \ops -> do + -- 1. Get root files, see if they are interesting to us. + rootContents <- getDirectoryContentsM ops "." + -- Recall getDirectoryContentsM arg is relative to root path. + let des = filter isDesirableExtraDocFile rootContents + + -- 2. Realise Globs. + let realGlob t = + concatMap globMatches + <$> mapM (runDirFileGlobM ops "") t + rgs <- realGlob dgs + res <- realGlob esgs + red <- realGlob edgs + + -- 3. Check if anything in 1. is missing in 2. + let mcs = checkDoc extraDocSupport des (rgs ++ res ++ red) + + -- 4. Check if files are present but in the wrong field. + let pcsData = checkDocMove extraDocSupport "data-files" des rgs + pcsSource = + if extraDocSupport + then + checkDocMove + extraDocSupport + "extra-source-files" + des + res + else [] + pcs = pcsData ++ pcsSource --- | Discover problems with the package's wildcards. -checkGlobFiles - :: Verbosity - -> PackageDescription - -> FilePath - -> IO [PackageCheck] -checkGlobFiles verbosity pkg root = do - -- Get the desirable doc files from package’s directory - rootContents <- System.Directory.getDirectoryContents root - docFiles0 <- - filterM - System.doesFileExist - [ file - | file <- rootContents - , isDesirableExtraDocFile desirableDocFiles file - ] - -- Check the globs - (warnings, unlisted) <- foldrM checkGlob ([], docFiles0) allGlobs - - return $ - if null unlisted - then -- No missing desirable file - warnings - else -- Some missing desirable files - - warnings - ++ let unlisted' = (root ) <$> unlisted - in [ PackageDistSuspiciousWarn - (MissingExpectedDocFiles extraDocFilesSupport unlisted') - ] + return (mcs ++ pcs) + ) where - -- `extra-doc-files` is supported only from version 1.18 - extraDocFilesSupport = specVersion pkg >= CabalSpecV1_18 - adjustedDataDir = if null (dataDir pkg) then root else root dataDir pkg - -- Cabal fields with globs - allGlobs :: [(String, Bool, FilePath, FilePath)] - allGlobs = - concat - [ (,,,) "extra-source-files" (not extraDocFilesSupport) root - <$> extraSrcFiles pkg - , (,,,) "extra-doc-files" True root <$> extraDocFiles pkg - , (,,,) "data-files" False adjustedDataDir <$> dataFiles pkg - ] - - -- For each field with globs (see allGlobs), look for: - -- • errors (missing directory, no match) - -- • omitted documentation files (changelog) - checkGlob - :: (String, Bool, FilePath, FilePath) - -> ([PackageCheck], [FilePath]) - -> IO ([PackageCheck], [FilePath]) - checkGlob (field, isDocField, dir, glob) acc@(warnings, docFiles1) = - -- Note: we just skip over parse errors here; they're reported elsewhere. - case parseFileGlob (specVersion pkg) glob of - Left _ -> return acc - Right parsedGlob -> do - results <- runDirFileGlob verbosity (root dir) parsedGlob - let acc0 = (warnings, True, docFiles1, []) - return $ case foldr checkGlobResult acc0 results of - (individualWarn, noMatchesWarn, docFiles1', wrongPaths) -> - let wrongFieldWarnings = - [ PackageDistSuspiciousWarn - ( WrongFieldForExpectedDocFiles - extraDocFilesSupport - field - wrongPaths - ) - | not (null wrongPaths) - ] - in ( if noMatchesWarn - then - [PackageDistSuspiciousWarn (GlobNoMatch field glob)] - ++ individualWarn - ++ wrongFieldWarnings - else individualWarn ++ wrongFieldWarnings - , docFiles1' - ) - where - checkGlobResult - :: GlobResult FilePath - -> ([PackageCheck], Bool, [FilePath], [FilePath]) - -> ([PackageCheck], Bool, [FilePath], [FilePath]) - checkGlobResult result (ws, noMatchesWarn, docFiles2, wrongPaths) = - let noMatchesWarn' = - noMatchesWarn - && not (suppressesNoMatchesWarning result) - in case getWarning field glob result of - -- No match: add warning and do no further check - Left w -> - ( w : ws - , noMatchesWarn' - , docFiles2 - , wrongPaths - ) - -- Match: check doc files - Right path -> - let path' = makeRelative root (normalise path) - (docFiles2', wrongPaths') = - checkDoc - isDocField - path' - docFiles2 - wrongPaths - in ( ws - , noMatchesWarn' - , docFiles2' - , wrongPaths' - ) - - -- Check whether a path is a desirable doc: if so, check if it is in the - -- field "extra-doc-files". checkDoc - :: Bool -- Is it "extra-doc-files" ? - -> FilePath -- Path to test - -> [FilePath] -- Pending doc files to check - -> [FilePath] -- Previous wrong paths - -> ([FilePath], [FilePath]) -- Updated paths - checkDoc isDocField path docFiles wrongFieldPaths = - if path `elem` docFiles - then -- Found desirable doc file - - ( delete path docFiles - , if isDocField then wrongFieldPaths else path : wrongFieldPaths - ) - else -- Not a desirable doc file + :: Bool -- Cabal spec ≥ 1.18? + -> [FilePath] -- Desirables. + -> [FilePath] -- Actuals. + -> [PackageCheck] + checkDoc b ds as = + let fds = map ("." ) $ filter (flip notElem as) ds + in if null fds + then [] + else + [ PackageDistSuspiciousWarn $ + MissingExpectedDocFiles b fds + ] - ( docFiles - , wrongFieldPaths - ) + checkDocMove + :: Bool -- Cabal spec ≥ 1.18? + -> CabalField -- Name of the field. + -> [FilePath] -- Desirables. + -> [FilePath] -- Actuals. + -> [PackageCheck] + checkDocMove b field ds as = + let fds = filter (flip elem as) ds + in if null fds + then [] + else + [ PackageDistSuspiciousWarn $ + WrongFieldForExpectedDocFiles b field fds + ] - -- Predicate for desirable documentation file on Hackage server - isDesirableExtraDocFile :: ([FilePath], [FilePath]) -> FilePath -> Bool - isDesirableExtraDocFile (basenames, extensions) path = - basename `elem` basenames && ext `elem` extensions - where - (basename, ext) = splitExtension (map toLower path) +-- Predicate for desirable documentation file on Hackage server. +isDesirableExtraDocFile :: FilePath -> Bool +isDesirableExtraDocFile path = + basename `elem` desirableChangeLog + && ext `elem` desirableChangeLogExtensions + where + (basename, ext) = splitExtension (map toLower path) -- Changelog patterns (basenames & extensions) -- Source: hackage-server/src/Distribution/Server/Packages/ChangeLog.hs - desirableChangeLog = - [ "news" - , "changelog" - , "change_log" - , "changes" - ] + desirableChangeLog = ["news", "changelog", "change_log", "changes"] desirableChangeLogExtensions = ["", ".txt", ".md", ".markdown", ".rst"] - -- [TODO] Check readme. Observations: - -- • Readme is not necessary if package description is good. - -- • Some readmes exists only for repository browsing. - -- • There is currently no reliable way to check what a good - -- description is; there will be complains if the criterion is - -- based on the length or number of words (can of worms). - -- -- Readme patterns - -- -- Source: hackage-server/src/Distribution/Server/Packages/Readme.hs - -- desirableReadme = ["readme"] - desirableDocFiles = (desirableChangeLog, desirableChangeLogExtensions) - - -- If there's a missing directory in play, since our globs don't - -- (currently) support disjunction, that will always mean there are no - -- matches. The no matches error in this case is strictly less informative - -- than the missing directory error, so sit on it. - suppressesNoMatchesWarning (GlobMatch _) = True - suppressesNoMatchesWarning (GlobWarnMultiDot _) = False - suppressesNoMatchesWarning (GlobMissingDirectory _) = True - - getWarning - :: String - -> FilePath - -> GlobResult FilePath - -> Either PackageCheck FilePath - getWarning _ _ (GlobMatch path) = - Right path - -- Before Cabal 2.4, the extensions of globs had to match the file - -- exactly. This has been relaxed in 2.4 to allow matching only the - -- suffix. This warning detects when pre-2.4 package descriptions are - -- omitting files purely because of the stricter check. - getWarning field glob (GlobWarnMultiDot file) = - Left (PackageDistSuspiciousWarn (GlobExactMatch field glob file)) - getWarning field glob (GlobMissingDirectory dir) = - Left (PackageDistSuspiciousWarn (GlobNoDir field glob dir)) - --- | Check that setup dependencies, have proper bounds. --- In particular, @base@ and @Cabal@ upper bounds are mandatory. -checkSetupVersions :: GenericPackageDescription -> [PackageCheck] -checkSetupVersions pkg = - [ emitError nameStr - | (name, vr) <- Map.toList deps - , not (hasUpperBound vr) - , let nameStr = unPackageName name - , nameStr `elem` criticalPkgs - ] - where - criticalPkgs = ["Cabal", "base"] - deps = toDependencyVersionsMap (foldMap setupDepends . setupBuildInfo) pkg - emitError nm = - PackageDistInexcusable (UpperBoundSetup nm) - -checkDuplicateModules :: GenericPackageDescription -> [PackageCheck] -checkDuplicateModules pkg = - concatMap checkLib (maybe id (:) (condLibrary pkg) . map snd $ condSubLibraries pkg) - ++ concatMap checkExe (map snd $ condExecutables pkg) - ++ concatMap checkTest (map snd $ condTestSuites pkg) - ++ concatMap checkBench (map snd $ condBenchmarks pkg) - where - -- the duplicate modules check is has not been thoroughly vetted for backpack - checkLib = checkDups "library" (\l -> explicitLibModules l ++ map moduleReexportName (reexportedModules l)) - checkExe = checkDups "executable" exeModules - checkTest = checkDups "test suite" testModules - checkBench = checkDups "benchmark" benchmarkModules - checkDups s getModules t = - let sumPair (x, x') (y, y') = (x + x' :: Int, y + y' :: Int) - mergePair (x, x') (y, y') = (x + x', max y y') - maxPair (x, x') (y, y') = (max x x', max y y') - libMap = - foldCondTree - Map.empty - (\(_, v) -> Map.fromListWith sumPair . map (\x -> (x, (1, 1))) $ getModules v) - (Map.unionWith mergePair) -- if a module may occur in nonexclusive branches count it twice strictly and once loosely. - (Map.unionWith maxPair) -- a module occurs the max of times it might appear in exclusive branches - t - dupLibsStrict = Map.keys $ Map.filter ((> 1) . fst) libMap - dupLibsLax = Map.keys $ Map.filter ((> 1) . snd) libMap - in if not (null dupLibsLax) - then - [ PackageBuildImpossible - (DuplicateModule s dupLibsLax) - ] - else - if not (null dupLibsStrict) - then - [ PackageDistSuspicious - (PotentialDupModule s dupLibsStrict) - ] - else [] - --- ------------------------------------------------------------ - --- * Utils - --- ------------------------------------------------------------ - -toDependencyVersionsMap :: (PackageDescription -> [Dependency]) -> GenericPackageDescription -> Map PackageName VersionRange -toDependencyVersionsMap selectDependencies pkg = case typicalPkg pkg of - Right (pkgs', _) -> - let - self :: PackageName - self = pkgName $ package pkgs' - in - Map.fromListWith intersectVersionRanges $ - [ (pname, vr) - | Dependency pname vr _ <- selectDependencies pkgs' - , pname /= self - ] - -- Just in case finalizePD fails for any reason, - -- or if the package doesn't depend on the base package at all, - -- no deps is no checks. - _ -> Map.empty - -quote :: String -> String -quote s = "'" ++ s ++ "'" - -commaSep :: [String] -> String -commaSep = intercalate ", " +-- [TODO] Check readme. Observations: +-- • Readme is not necessary if package description is good. +-- • Some readmes exists only for repository browsing. +-- • There is currently no reliable way to check what a good +-- description is; there will be complains if the criterion +-- is based on the length or number of words (can of worms). +-- -- Readme patterns +-- -- Source: hackage-server/src/Distribution/Server/Packages/Readme.hs +-- desirableReadme = ["readme"] + +-- Remove duplicates from list. dups :: Ord a => [a] -> [a] dups xs = [x | (x : _ : _) <- group (sort xs)] - -fileExtensionSupportedLanguage :: FilePath -> Bool -fileExtensionSupportedLanguage path = - isHaskell || isC - where - extension = takeExtension path - isHaskell = extension `elem` [".hs", ".lhs"] - isC = isJust (filenameCDialect extension) - --- | Whether a path is a good relative path. We aren't worried about perfect --- cross-platform compatibility here; this function just checks the paths in --- the (local) @.cabal@ file, while only Hackage needs the portability. --- --- >>> let test fp = putStrLn $ show (isGoodRelativeDirectoryPath fp) ++ "; " ++ show (isGoodRelativeFilePath fp) --- --- Note that "foo./bar.hs" would be invalid on Windows. --- --- >>> traverse_ test ["foo/bar/quu", "a/b.hs", "foo./bar.hs"] --- Nothing; Nothing --- Nothing; Nothing --- Nothing; Nothing --- --- Trailing slash is not allowed for files, for directories it is ok. --- --- >>> test "foo/" --- Nothing; Just "trailing slash" --- --- Leading @./@ is fine, but @.@ and @./@ are not valid files. --- --- >>> traverse_ test [".", "./", "./foo/bar"] --- Nothing; Just "trailing dot segment" --- Nothing; Just "trailing slash" --- Nothing; Nothing --- --- Lastly, not good file nor directory cases: --- --- >>> traverse_ test ["", "/tmp/src", "foo//bar", "foo/.", "foo/./bar", "foo/../bar"] --- Just "empty path"; Just "empty path" --- Just "posix absolute path"; Just "posix absolute path" --- Just "empty path segment"; Just "empty path segment" --- Just "trailing same directory segment: ."; Just "trailing same directory segment: ." --- Just "same directory segment: ."; Just "same directory segment: ." --- Just "parent directory segment: .."; Just "parent directory segment: .." --- --- For the last case, 'isGoodRelativeGlob' doesn't warn: --- --- >>> traverse_ (print . isGoodRelativeGlob) ["foo/../bar"] --- Just "parent directory segment: .." -isGoodRelativeFilePath :: FilePath -> Maybe String -isGoodRelativeFilePath = state0 - where - -- initial state - state0 [] = Just "empty path" - state0 (c : cs) - | c == '.' = state1 cs - | c == '/' = Just "posix absolute path" - | otherwise = state5 cs - - -- after initial . - state1 [] = Just "trailing dot segment" - state1 (c : cs) - | c == '.' = state4 cs - | c == '/' = state2 cs - | otherwise = state5 cs - - -- after ./ or after / between segments - state2 [] = Just "trailing slash" - state2 (c : cs) - | c == '.' = state3 cs - | c == '/' = Just "empty path segment" - | otherwise = state5 cs - - -- after non-first segment's . - state3 [] = Just "trailing same directory segment: ." - state3 (c : cs) - | c == '.' = state4 cs - | c == '/' = Just "same directory segment: ." - | otherwise = state5 cs - - -- after .. - state4 [] = Just "trailing parent directory segment: .." - state4 (c : cs) - | c == '.' = state5 cs - | c == '/' = Just "parent directory segment: .." - | otherwise = state5 cs - - -- in a segment which is ok. - state5 [] = Nothing - state5 (c : cs) - | c == '.' = state5 cs - | c == '/' = state2 cs - | otherwise = state5 cs - --- | See 'isGoodRelativeFilePath'. --- --- This is barebones function. We check whether the glob is a valid file --- by replacing stars @*@ with @x@ses. -isGoodRelativeGlob :: FilePath -> Maybe String -isGoodRelativeGlob = isGoodRelativeFilePath . map f - where - f '*' = 'x' - f c = c - --- | See 'isGoodRelativeFilePath'. -isGoodRelativeDirectoryPath :: FilePath -> Maybe String -isGoodRelativeDirectoryPath = state0 - where - -- initial state - state0 [] = Just "empty path" - state0 (c : cs) - | c == '.' = state5 cs - | c == '/' = Just "posix absolute path" - | otherwise = state4 cs - - -- after initial ./ or after / between segments - state1 [] = Nothing - state1 (c : cs) - | c == '.' = state2 cs - | c == '/' = Just "empty path segment" - | otherwise = state4 cs - - -- after non-first setgment's . - state2 [] = Just "trailing same directory segment: ." - state2 (c : cs) - | c == '.' = state3 cs - | c == '/' = Just "same directory segment: ." - | otherwise = state4 cs - - -- after .. - state3 [] = Just "trailing parent directory segment: .." - state3 (c : cs) - | c == '.' = state4 cs - | c == '/' = Just "parent directory segment: .." - | otherwise = state4 cs - - -- in a segment which is ok. - state4 [] = Nothing - state4 (c : cs) - | c == '.' = state4 cs - | c == '/' = state1 cs - | otherwise = state4 cs - - -- after initial . - state5 [] = Nothing -- "." - state5 (c : cs) - | c == '.' = state3 cs - | c == '/' = state1 cs - | otherwise = state4 cs - --- [Note: Good relative paths] --- --- Using @kleene@ we can define an extended regex: --- --- @ --- import Algebra.Lattice --- import Kleene --- import Kleene.ERE (ERE (..), intersections) --- --- data C = CDot | CSlash | CChar --- deriving (Eq, Ord, Enum, Bounded, Show) --- --- reservedR :: ERE C --- reservedR = notChar CSlash --- --- pathPieceR :: ERE C --- pathPieceR = intersections --- [ plus reservedR --- , ERENot (string [CDot]) --- , ERENot (string [CDot,CDot]) --- ] --- --- filePathR :: ERE C --- filePathR = optional (string [CDot, CSlash]) <> pathPieceR <> star (char CSlash <> pathPieceR) --- --- dirPathR :: ERE C --- dirPathR = (char CDot \/ filePathR) <> optional (char CSlash) --- --- plus :: ERE C -> ERE C --- plus r = r <> star r --- --- optional :: ERE C -> ERE C --- optional r = mempty \/ r --- @ --- --- Results in following state machine for @filePathR@ --- --- @ --- 0 -> \x -> if --- | x <= CDot -> 1 --- | otherwise -> 5 --- 1 -> \x -> if --- | x <= CDot -> 4 --- | x <= CSlash -> 2 --- | otherwise -> 5 --- 2 -> \x -> if --- | x <= CDot -> 3 --- | otherwise -> 5 --- 3 -> \x -> if --- | x <= CDot -> 4 --- | otherwise -> 5 --- 4 -> \x -> if --- | x <= CDot -> 5 --- | otherwise -> 5 --- 5+ -> \x -> if --- | x <= CDot -> 5 --- | x <= CSlash -> 2 --- | otherwise -> 5 --- @ --- --- and @dirPathR@: --- --- @ --- 0 -> \x -> if --- | x <= CDot -> 5 --- | otherwise -> 4 --- 1+ -> \x -> if --- | x <= CDot -> 2 --- | otherwise -> 4 --- 2 -> \x -> if --- | x <= CDot -> 3 --- | otherwise -> 4 --- 3 -> \x -> if --- | x <= CDot -> 4 --- | otherwise -> 4 --- 4+ -> \x -> if --- | x <= CDot -> 4 --- | x <= CSlash -> 1 --- | otherwise -> 4 --- 5+ -> \x -> if --- | x <= CDot -> 3 --- | x <= CSlash -> 1 --- | otherwise -> 4 --- @ - --- --- TODO: What we really want to do is test if there exists any --- configuration in which the base version is unbounded above. --- However that's a bit tricky because there are many possible --- configurations. As a cheap easy and safe approximation we will --- pick a single "typical" configuration and check if that has an --- open upper bound. To get a typical configuration we finalise --- using no package index and the current platform. -typicalPkg - :: GenericPackageDescription - -> Either [Dependency] (PackageDescription, FlagAssignment) -typicalPkg = - finalizePD - mempty - defaultComponentRequestedSpec - (const True) - buildPlatform - ( unknownCompilerInfo - (CompilerId buildCompilerFlavor nullVersion) - NoAbiTag - ) - [] - -addConditionalExp :: String -> String -addConditionalExp expl = - expl - ++ " Alternatively, if you want to use this, make it conditional based " - ++ "on a Cabal configuration flag (with 'manual: True' and 'default: " - ++ "False') and enable that flag during development." diff --git a/Cabal/src/Distribution/PackageDescription/Check/Common.hs b/Cabal/src/Distribution/PackageDescription/Check/Common.hs new file mode 100644 index 00000000000..4c528831430 --- /dev/null +++ b/Cabal/src/Distribution/PackageDescription/Check/Common.hs @@ -0,0 +1,149 @@ +-- | +-- Module : Distribution.PackageDescription.Check.Common +-- Copyright : Francesco Ariis 2022 +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Common types/functions to various check modules which are *no* part of +-- Distribution.PackageDescription.Check.Monad. +module Distribution.PackageDescription.Check.Common + ( AssocDep + , CabalField + , PathKind (..) + , checkCustomField + , partitionDeps + , checkPVP + , checkPVPs + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.Compat.NonEmptySet (toNonEmpty) +import Distribution.Package +import Distribution.PackageDescription +import Distribution.PackageDescription.Check.Monad +import Distribution.Utils.Generic (isAscii) +import Distribution.Version + +import Control.Monad + +-- Type of FilePath. +data PathKind + = PathKindFile + | PathKindDirectory + | PathKindGlob + deriving (Eq) + +-- | .cabal field we are referring to. As now it is just a synonym to help +-- reading the code, in the future it might take advantage of typification +-- in Cabal-syntax. +type CabalField = String + +checkCustomField :: Monad m => (String, String) -> CheckM m () +checkCustomField (n, _) = + checkP + (any (not . isAscii) n) + (PackageDistInexcusable $ NonASCIICustomField [n]) + +-- ------------------------------------------------------------ +-- PVP types/functions +-- ------------------------------------------------------------ + +-- A library name / dependencies association list. Ultimately to be +-- fed to PVP check. +type AssocDep = (UnqualComponentName, [Dependency]) + +-- Convenience function to partition important dependencies by name. To +-- be used together with checkPVP. Important: usually “base” or “Cabal”, +-- as the error is slightly different. +-- Note that `partitionDeps` will also filter out dependencies which are +-- already present in a inherithed fashion (e.g. an exe which imports the +-- main library will not need to specify upper bounds on shared dependencies, +-- hence we do not return those). +-- +partitionDeps + :: Monad m + => [AssocDep] -- Possibly inherited dependencies, i.e. + -- dependencies from internal/main libs. + -> [UnqualComponentName] -- List of package names ("base", "Cabal"…) + -> [Dependency] -- Dependencies to check. + -> CheckM m ([Dependency], [Dependency]) +partitionDeps ads ns ds = do + -- Shared dependencies from “intra .cabal” libraries. + let + -- names of our dependencies + dqs = map unqualName ds + -- shared targets that match + fads = filter (flip elem dqs . fst) ads + -- the names of such targets + inNam = nub $ map fst fads :: [UnqualComponentName] + -- the dependencies of such targets + inDep = concatMap snd fads :: [Dependency] + + -- We exclude from checks: + -- 1. dependencies which are shared with main library / a + -- sublibrary; and of course + -- 2. the names of main library / sub libraries themselves. + -- + -- So in myPackage.cabal + -- library + -- build-depends: text < 5 + -- ⁝ + -- build-depends: myPackage, ← no warning, internal + -- text, ← no warning, inherited + -- monadacme ← warning! + let fFun d = + notElem (unqualName d) inNam + && notElem + (unqualName d) + (map unqualName inDep) + ds' = filter fFun ds + + return $ partition (flip elem ns . unqualName) ds' + where + -- Return *sublibrary* name if exists (internal), + -- otherwise package name. + unqualName :: Dependency -> UnqualComponentName + unqualName (Dependency n _ nel) = + case head (toNonEmpty nel) of + (LSubLibName ln) -> ln + _ -> packageNameToUnqualComponentName n + +-- PVP dependency check (one warning message per dependency, usually +-- for important dependencies like base). +checkPVP + :: Monad m + => (String -> PackageCheck) -- Warn message dependend on name + -- (e.g. "base", "Cabal"). + -> [Dependency] + -> CheckM m () +checkPVP ckf ds = do + let ods = checkPVPPrim ds + mapM_ (tellP . ckf . unPackageName . depPkgName) ods + +-- PVP dependency check for a list of dependencies. Some code duplication +-- is sadly needed to provide more ergonimic error messages. +checkPVPs + :: Monad m + => ( [String] + -> PackageCheck -- Grouped error message, depends on a + -- set of names. + ) + -> [Dependency] -- Deps to analyse. + -> CheckM m () +checkPVPs cf ds + | null ns = return () + | otherwise = tellP (cf ns) + where + ods = checkPVPPrim ds + ns = map (unPackageName . depPkgName) ods + +-- Returns dependencies without upper bounds. +checkPVPPrim :: [Dependency] -> [Dependency] +checkPVPPrim ds = filter withoutUpper ds + where + withoutUpper :: Dependency -> Bool + withoutUpper (Dependency _ ver _) = not . hasUpperBound $ ver diff --git a/Cabal/src/Distribution/PackageDescription/Check/Conditional.hs b/Cabal/src/Distribution/PackageDescription/Check/Conditional.hs new file mode 100644 index 00000000000..da05b2c80b9 --- /dev/null +++ b/Cabal/src/Distribution/PackageDescription/Check/Conditional.hs @@ -0,0 +1,265 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +-- | +-- Module : Distribution.PackageDescription.Check.Conditional +-- Copyright : Lennart Kolmodin 2008, Francesco Ariis 2023 +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Checks on conditional targets (libraries, executables, etc. that are +-- still inside a CondTree and related checks that can only be performed +-- here (variables, duplicated modules). +module Distribution.PackageDescription.Check.Conditional + ( checkCondTarget + , checkDuplicateModules + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.Compiler +import Distribution.ModuleName (ModuleName) +import Distribution.Package +import Distribution.PackageDescription +import Distribution.PackageDescription.Check.Monad +import Distribution.System + +import qualified Data.Map as Map + +import Control.Monad + +-- As a prerequisite to some checks, we transform a target CondTree into +-- a CondTree of “target + useful context”. +-- This is slightly clearer, is easier to walk without resorting to +-- list comprehensions, allows us in the future to apply some sensible +-- “optimisations” to checks (exclusive branches, etc.). + +-- | @nf@ function is needed to appropriately name some targets which need +-- to be spoonfed (otherwise name appears as ""). +initTargetAnnotation + :: Monoid a + => (UnqualComponentName -> a -> a) -- Naming function for targets. + -> UnqualComponentName + -> TargetAnnotation a +initTargetAnnotation nf n = TargetAnnotation (nf n mempty) False + +-- | We “build up” target from various slices. +updateTargetAnnotation + :: Monoid a + => a -- A target (lib, exe, test, …) + -> TargetAnnotation a + -> TargetAnnotation a +updateTargetAnnotation t ta = ta{taTarget = taTarget ta <> t} + +-- | Before walking a target 'CondTree', we need to annotate it with +-- information relevant to the checks (read 'TaraAnn' and 'checkCondTarget' +-- doc for more info). +annotateCondTree + :: forall a + . (Eq a, Monoid a) + => [PackageFlag] -- User flags. + -> TargetAnnotation a + -> CondTree ConfVar [Dependency] a + -> CondTree ConfVar [Dependency] (TargetAnnotation a) +annotateCondTree fs ta (CondNode a c bs) = + let ta' = updateTargetAnnotation a ta + bs' = map (annotateBranch ta') bs + bs'' = crossAnnotateBranches defTrueFlags bs' + in CondNode ta' c bs'' + where + annotateBranch + :: TargetAnnotation a + -> CondBranch ConfVar [Dependency] a + -> CondBranch + ConfVar + [Dependency] + (TargetAnnotation a) + annotateBranch wta (CondBranch k t mf) = + let uf = isPkgFlagCond k + wta' = wta{taPackageFlag = taPackageFlag wta || uf} + atf = annotateCondTree fs + in CondBranch + k + (atf wta' t) + (atf wta <$> mf) + -- Note how we are passing the *old* wta + -- in the `else` branch, since we are not + -- under that flag. + + -- We only want to pick up variables that are flags and that are + -- \*off* by default. + isPkgFlagCond :: Condition ConfVar -> Bool + isPkgFlagCond (Lit _) = False + isPkgFlagCond (Var (PackageFlag f)) = elem f defOffFlags + isPkgFlagCond (Var _) = False + isPkgFlagCond (CNot cn) = not (isPkgFlagCond cn) + isPkgFlagCond (CAnd ca cb) = isPkgFlagCond ca || isPkgFlagCond cb + isPkgFlagCond (COr ca cb) = isPkgFlagCond ca && isPkgFlagCond cb + + -- Package flags that are off by default *and* that are manual. + defOffFlags = + map flagName $ + filter + ( \f -> + not (flagDefault f) + && flagManual f + ) + fs + + defTrueFlags :: [PackageFlag] + defTrueFlags = filter flagDefault fs + +-- Propagate contextual information in CondTree branches. This is +-- needed as CondTree is a rosetree and not a binary tree. +crossAnnotateBranches + :: forall a + . (Eq a, Monoid a) + => [PackageFlag] -- `default: true` flags. + -> [CondBranch ConfVar [Dependency] (TargetAnnotation a)] + -> [CondBranch ConfVar [Dependency] (TargetAnnotation a)] +crossAnnotateBranches fs bs = map crossAnnBranch bs + where + crossAnnBranch + :: CondBranch ConfVar [Dependency] (TargetAnnotation a) + -> CondBranch ConfVar [Dependency] (TargetAnnotation a) + crossAnnBranch wr = + let + rs = filter (/= wr) bs + ts = mapMaybe realiseBranch rs + in + updateTargetAnnBranch (mconcat ts) wr + + realiseBranch :: CondBranch ConfVar [Dependency] (TargetAnnotation a) -> Maybe a + realiseBranch b = + let + -- We are only interested in True by default package flags. + realiseBranchFunction :: ConfVar -> Either ConfVar Bool + realiseBranchFunction (PackageFlag n) | elem n (map flagName fs) = Right True + realiseBranchFunction _ = Right False + ms = simplifyCondBranch realiseBranchFunction (fmap taTarget b) + in + fmap snd ms + + updateTargetAnnBranch + :: a + -> CondBranch ConfVar [Dependency] (TargetAnnotation a) + -> CondBranch ConfVar [Dependency] (TargetAnnotation a) + updateTargetAnnBranch a (CondBranch k t mt) = + let updateTargetAnnTree (CondNode ka c wbs) = + (CondNode (updateTargetAnnotation a ka) c wbs) + in CondBranch k (updateTargetAnnTree t) (updateTargetAnnTree <$> mt) + +-- | A conditional target is a library, exe, benchmark etc., destructured +-- in a CondTree. Traversing method: we render the branches, pass a +-- relevant context, collect checks. +checkCondTarget + :: forall m a + . (Monad m, Eq a, Monoid a) + => [PackageFlag] -- User flags. + -> (a -> CheckM m ()) -- Check function (a = target). + -> (UnqualComponentName -> a -> a) + -- Naming function (some targets + -- need to have their name + -- spoonfed to them. + -> (UnqualComponentName, CondTree ConfVar [Dependency] a) + -- Target name/condtree. + -> CheckM m () +checkCondTarget fs cf nf (unqualName, ct) = + wTree $ annotateCondTree fs (initTargetAnnotation nf unqualName) ct + where + -- Walking the tree. Remember that CondTree is not a binary + -- tree but a /rose/tree. + wTree + :: CondTree ConfVar [Dependency] (TargetAnnotation a) + -> CheckM m () + wTree (CondNode ta _ bs) + -- There are no branches ([] == True) *or* every branch + -- is “simple” (i.e. missing a 'condBranchIfFalse' part). + -- This is convenient but not necessarily correct in all + -- cases; a more precise way would be to check incompatibility + -- among simple branches conditions (or introduce a principled + -- `cond` construct in `.cabal` files. + | all isSimple bs = do + localCM (initCheckCtx ta) (cf $ taTarget ta) + mapM_ wBranch bs + -- If there are T/F conditions, there is no need to check + -- the intermediate 'TargetAnnotation' too. + | otherwise = do + mapM_ wBranch bs + + isSimple + :: CondBranch ConfVar [Dependency] (TargetAnnotation a) + -> Bool + isSimple (CondBranch _ _ Nothing) = True + isSimple (CondBranch _ _ (Just _)) = False + + wBranch + :: CondBranch ConfVar [Dependency] (TargetAnnotation a) + -> CheckM m () + wBranch (CondBranch k t mf) = do + checkCondVars k + wTree t + maybe (return ()) wTree mf + +-- | Condvar checking (misspelled OS in if conditions, etc). +checkCondVars :: Monad m => Condition ConfVar -> CheckM m () +checkCondVars cond = + let (_, vs) = simplifyCondition cond (\v -> Left v) + in -- Using simplifyCondition is convenient and correct, + -- if checks become more complex we can always walk + -- 'Condition'. + mapM_ vcheck vs + where + vcheck :: Monad m => ConfVar -> CheckM m () + vcheck (OS (OtherOS os)) = + tellP (PackageDistInexcusable $ UnknownOS [os]) + vcheck (Arch (OtherArch arch)) = + tellP (PackageDistInexcusable $ UnknownArch [arch]) + vcheck (Impl (OtherCompiler os) _) = + tellP (PackageDistInexcusable $ UnknownCompiler [os]) + vcheck _ = return () + +-- Checking duplicated modules cannot unfortunately be done in the +-- “tree checking”. This is because of the monoidal instance in some targets, +-- where e.g. merged dependencies are `nub`’d, hence losing information for +-- this particular check. +checkDuplicateModules :: GenericPackageDescription -> [PackageCheck] +checkDuplicateModules pkg = + concatMap checkLib (maybe id (:) (condLibrary pkg) . map snd $ condSubLibraries pkg) + ++ concatMap checkExe (map snd $ condExecutables pkg) + ++ concatMap checkTest (map snd $ condTestSuites pkg) + ++ concatMap checkBench (map snd $ condBenchmarks pkg) + where + -- the duplicate modules check is has not been thoroughly vetted for backpack + checkLib = checkDups "library" (\l -> explicitLibModules l ++ map moduleReexportName (reexportedModules l)) + checkExe = checkDups "executable" exeModules + checkTest = checkDups "test suite" testModules + checkBench = checkDups "benchmark" benchmarkModules + checkDups :: String -> (a -> [ModuleName]) -> CondTree v c a -> [PackageCheck] + checkDups s getModules t = + let sumPair (x, x') (y, y') = (x + x' :: Int, y + y' :: Int) + mergePair (x, x') (y, y') = (x + x', max y y') + maxPair (x, x') (y, y') = (max x x', max y y') + libMap = + foldCondTree + Map.empty + (\(_, v) -> Map.fromListWith sumPair . map (\x -> (x, (1, 1))) $ getModules v) + (Map.unionWith mergePair) -- if a module may occur in nonexclusive branches count it twice strictly and once loosely. + (Map.unionWith maxPair) -- a module occurs the max of times it might appear in exclusive branches + t + dupLibsStrict = Map.keys $ Map.filter ((> 1) . fst) libMap + dupLibsLax = Map.keys $ Map.filter ((> 1) . snd) libMap + in if not (null dupLibsLax) + then + [ PackageBuildImpossible + (DuplicateModule s dupLibsLax) + ] + else + if not (null dupLibsStrict) + then + [ PackageDistSuspicious + (PotentialDupModule s dupLibsStrict) + ] + else [] diff --git a/Cabal/src/Distribution/PackageDescription/Check/Monad.hs b/Cabal/src/Distribution/PackageDescription/Check/Monad.hs new file mode 100644 index 00000000000..23d37570800 --- /dev/null +++ b/Cabal/src/Distribution/PackageDescription/Check/Monad.hs @@ -0,0 +1,371 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE ScopedTypeVariables #-} + +-- | +-- Module : Distribution.PackageDescription.Check.Monad +-- Copyright : Francesco Ariis 2022 +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Primitives for package checking: check types and monadic interface. +-- Having these primitives in a different module allows us to appropriately +-- limit/manage the interface to suit checking needs. +module Distribution.PackageDescription.Check.Monad + ( -- * Types and constructors + CheckM (..) + , execCheckM + , CheckInterface (..) + , CheckPackageContentOps (..) + , CheckPreDistributionOps (..) + , TargetAnnotation (..) + , PackageCheck (..) + , CheckExplanation (..) + , CEType (..) + , WarnLang (..) + , CheckCtx (..) + , pristineCheckCtx + , initCheckCtx + , PNames (..) + + -- * Operations + , ppPackageCheck + , isHackageDistError + , asksCM + , localCM + , checkP + , checkPkg + , liftInt + , tellP + , checkSpecVer + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.CabalSpecVersion (CabalSpecVersion) +import Distribution.Package (packageName) +import Distribution.PackageDescription.Check.Warning +import Distribution.Simple.BuildToolDepends (desugarBuildToolSimple) +import Distribution.Simple.Glob (Glob, GlobResult) +import Distribution.Types.ExeDependency (ExeDependency) +import Distribution.Types.GenericPackageDescription +import Distribution.Types.LegacyExeDependency (LegacyExeDependency) +import Distribution.Types.PackageDescription (package, specVersion) +import Distribution.Types.PackageId (PackageIdentifier) +import Distribution.Types.UnqualComponentName + +import qualified Control.Monad.Reader as Reader +import qualified Control.Monad.Trans.Class as Trans +import qualified Control.Monad.Writer as Writer +import qualified Data.ByteString.Lazy as BS +import qualified Data.Set as Set + +import Control.Monad + +-- Monadic interface for for Distribution.PackageDescription.Check. +-- +-- Monadic checking allows us to have a fine grained control on checks +-- (e.g. omitting warning checks in certain situations). + +-- * Interfaces + +-- + +-- | Which interface to we have available/should we use? (to perform: pure +-- checks, package checks, pre-distribution checks.) +data CheckInterface m = CheckInterface + { ciPureChecks :: Bool + , -- Perform pure checks? + ciPackageOps :: Maybe (CheckPackageContentOps m) + , -- If you want to perform package contents + -- checks, provide an interface. + ciPreDistOps :: Maybe (CheckPreDistributionOps m) + -- If you want to work-tree checks, provide + -- an interface. + } + +-- | A record of operations needed to check the contents of packages. +-- Abstracted over `m` to provide flexibility (could be IO, a .tar.gz +-- file, etc). +data CheckPackageContentOps m = CheckPackageContentOps + { doesFileExist :: FilePath -> m Bool + , doesDirectoryExist :: FilePath -> m Bool + , getDirectoryContents :: FilePath -> m [FilePath] + , getFileContents :: FilePath -> m BS.ByteString + } + +-- | A record of operations needed to check contents *of the work tree* +-- (compare it with 'CheckPackageContentOps'). This is still `m` abstracted +-- in case in the future we can obtain the same infos other than from IO +-- (e.g. a VCS work tree). +data CheckPreDistributionOps m = CheckPreDistributionOps + { runDirFileGlobM :: FilePath -> Glob -> m [GlobResult FilePath] + , getDirectoryContentsM :: FilePath -> m [FilePath] + } + +-- | Context to perform checks (will be the Reader part in your monad). +data CheckCtx m = CheckCtx + { ccInterface :: CheckInterface m + , -- Interface for checks. + + -- Contextual infos for checks. + ccFlag :: Bool + , -- Are we under a user flag? + + -- Convenience bits that we prefer to carry + -- in our Reader monad instead of passing it + -- via ->, as they are often useful and often + -- in deeply nested places in the GPD tree. + ccSpecVersion :: CabalSpecVersion + , -- Cabal version. + ccDesugar :: LegacyExeDependency -> Maybe ExeDependency + , -- A desugaring function from + -- Distribution.Simple.BuildToolDepends + -- (desugarBuildToolSimple). Again since it + -- eats PackageName and a list of executable + -- names, it is more convenient to pass it + -- via Reader. + ccNames :: PNames + -- Various names (id, libs, execs, tests, + -- benchs), convenience. + } + +-- | Creates a pristing 'CheckCtx'. With pristine we mean everything that +-- can be deduced by GPD but *not* user flags information. +pristineCheckCtx + :: Monad m + => CheckInterface m + -> GenericPackageDescription + -> CheckCtx m +pristineCheckCtx ci gpd = + let ens = map fst (condExecutables gpd) + in CheckCtx + ci + False + (specVersion . packageDescription $ gpd) + (desugarBuildToolSimple (packageName gpd) ens) + (initPNames gpd) + +-- | Adds useful bits to 'CheckCtx' (as now, whether we are operating under +-- a user off-by-default flag). +initCheckCtx :: Monad m => TargetAnnotation a -> CheckCtx m -> CheckCtx m +initCheckCtx t c = c{ccFlag = taPackageFlag t} + +-- | 'TargetAnnotation' collects contextual information on the target we are +-- realising: a buildup of the various slices of the target (a library, +-- executable, etc. — is a monoid) whether we are under an off-by-default +-- package flag. +data TargetAnnotation a = TargetAnnotation + { taTarget :: a + , -- The target we are building (lib, exe, etc.) + taPackageFlag :: Bool + -- Whether we are under an off-by-default package flag. + } + deriving (Show, Eq, Ord) + +-- | A collection os names, shipping tuples around is annoying. +data PNames = PNames + { pnPackageId :: PackageIdentifier -- Package ID… + -- … and a bunch of lib, exe, test, bench names. + , pnSubLibs :: [UnqualComponentName] + , pnExecs :: [UnqualComponentName] + , pnTests :: [UnqualComponentName] + , pnBenchs :: [UnqualComponentName] + } + +-- | Init names from a GPD. +initPNames :: GenericPackageDescription -> PNames +initPNames gpd = + PNames + (package . packageDescription $ gpd) + (map fst $ condSubLibraries gpd) + (map fst $ condExecutables gpd) + (map fst $ condTestSuites gpd) + (map fst $ condBenchmarks gpd) + +-- | Check monad, carrying a context, collecting 'PackageCheck's. +-- Using Set for writer (automatic sort) is useful for output stability +-- on different platforms. +-- It is nothing more than a monad stack with Reader+Writer. +-- `m` is the monad that could be used to do package/file checks. +newtype CheckM m a + = CheckM + ( Reader.ReaderT + (CheckCtx m) + ( Writer.WriterT + (Set.Set PackageCheck) + m + ) + a + ) + deriving (Functor, Applicative, Monad) + +-- Not autoderiving MonadReader and MonadWriter gives us better +-- control on the interface of CheckM. + +-- | Execute a CheckM monad, leaving `m [PackageCheck]` which can be +-- run in the appropriate `m` environment (IO, pure, …). +execCheckM :: Monad m => CheckM m () -> CheckCtx m -> m [PackageCheck] +execCheckM (CheckM rwm) ctx = + let wm = Reader.runReaderT rwm ctx + m = Writer.execWriterT wm + in Set.toList <$> m + +-- | As 'checkP' but always succeeding. +tellP :: Monad m => PackageCheck -> CheckM m () +tellP = checkP True + +-- | Add a package warning withoutu performing any check. +tellCM :: Monad m => PackageCheck -> CheckM m () +tellCM ck = do + cf <- asksCM ccFlag + unless + (cf && canSkip ck) + -- Do not push this message if the warning is not severe *and* + -- we are under a non-default package flag. + (CheckM . Writer.tell $ Set.singleton ck) + where + -- Check if we can skip this error if we are under a + -- non-default user flag. + canSkip :: PackageCheck -> Bool + canSkip wck = not (isSevereLocal wck) || isErrAllowable wck + + isSevereLocal :: PackageCheck -> Bool + isSevereLocal (PackageBuildImpossible _) = True + isSevereLocal (PackageBuildWarning _) = True + isSevereLocal (PackageDistSuspicious _) = False + isSevereLocal (PackageDistSuspiciousWarn _) = False + isSevereLocal (PackageDistInexcusable _) = True + + -- There are some errors which, even though severe, will + -- be allowed by Hackage *if* under a non-default flag. + isErrAllowable :: PackageCheck -> Bool + isErrAllowable c = case extractCheckExplantion c of + (WErrorUnneeded _) -> True + (JUnneeded _) -> True + (FDeferTypeErrorsUnneeded _) -> True + (DynamicUnneeded _) -> True + (ProfilingUnneeded _) -> True + _ -> False + +-- | Lift a monadic computation to CM. +liftCM :: Monad m => m a -> CheckM m a +liftCM ma = CheckM . Trans.lift . Trans.lift $ ma + +-- | Lift a monadic action via an interface. Missing interface, no action. +liftInt + :: forall m i + . Monad m + => (CheckInterface m -> Maybe (i m)) + -- Check interface, may or may not exist. If it does not, + -- the check simply will not be performed. + -> (i m -> m [PackageCheck]) + -- The actual check to perform with the above-mentioned + -- interface. Note the [] around `PackageCheck`, this is + -- meant to perform/collect multiple checks. + -> CheckM m () +liftInt acc f = do + ops <- asksCM (acc . ccInterface) + maybe (return ()) l ops + where + l :: i m -> CheckM m () + l wi = do + cks <- liftCM (f wi) + mapM_ (check True) cks + +-- | Most basic check function. You do not want to export this, rather export +-- “smart” functions (checkP, checkPkg) to enforce relevant properties. +check + :: Monad m + => Bool -- Is there something to warn about? + -> PackageCheck -- Warn message. + -> CheckM m () +check True ck = tellCM ck +check False _ = return () + +-- | Pure check not requiring IO or other interfaces. +checkP + :: Monad m + => Bool -- Is there something to warn about? + -> PackageCheck -- Warn message. + -> CheckM m () +checkP b ck = do + pb <- asksCM (ciPureChecks . ccInterface) + when pb (check b ck) + +-- Check with 'CheckPackageContentOps' operations (i.e. package file checks). +-- +checkPkg + :: forall m + . Monad m + => (CheckPackageContentOps m -> m Bool) + -- Actual check to perform with CPC interface + -> PackageCheck + -- Warn message. + -> CheckM m () +checkPkg f ck = checkInt ciPackageOps f ck + +-- | Generalised version for checks that need an interface. We pass a Reader +-- accessor to such interface ‘i’, a check function. +checkIntDep + :: forall m i + . Monad m + => (CheckInterface m -> Maybe (i m)) + -- Check interface, may or may not exist. If it does not, + -- the check simply will not be performed. + -> (i m -> m (Maybe PackageCheck)) + -- The actual check to perform (single check). + -> CheckM m () +checkIntDep acc mck = do + po <- asksCM (acc . ccInterface) + maybe (return ()) (lc . mck) po + where + lc :: Monad m => m (Maybe PackageCheck) -> CheckM m () + lc wmck = do + b <- liftCM wmck + maybe (return ()) (check True) b + +-- | As 'checkIntDep', but 'PackageCheck' does not depend on the monadic +-- computation. +checkInt + :: forall m i + . Monad m + => (CheckInterface m -> Maybe (i m)) + -- Where to get the interface (if available). + -> (i m -> m Bool) + -- Condition to check + -> PackageCheck + -- Warning message to add (does not depend on `m`). + -> CheckM m () +checkInt acc f ck = + checkIntDep + acc + ( \ops -> do + b <- f ops + if b + then return $ Just ck + else return Nothing + ) + +-- | `local` (from Control.Monad.Reader) for CheckM. +localCM :: Monad m => (CheckCtx m -> CheckCtx m) -> CheckM m () -> CheckM m () +localCM cf (CheckM im) = CheckM $ Reader.local cf im + +-- | `ask` (from Control.Monad.Reader) for CheckM. +asksCM :: Monad m => (CheckCtx m -> a) -> CheckM m a +asksCM f = CheckM $ Reader.asks f + +-- As checkP, but with an additional condition: the check will be performed +-- only if our spec version is < `vc`. +checkSpecVer + :: Monad m + => CabalSpecVersion -- Perform this check only if our + -- spec version is < than this. + -> Bool -- Check condition. + -> PackageCheck -- Check message. + -> CheckM m () +checkSpecVer vc cond c = do + vp <- asksCM ccSpecVersion + unless (vp >= vc) (checkP cond c) diff --git a/Cabal/src/Distribution/PackageDescription/Check/Paths.hs b/Cabal/src/Distribution/PackageDescription/Check/Paths.hs new file mode 100644 index 00000000000..5b2df1f18fa --- /dev/null +++ b/Cabal/src/Distribution/PackageDescription/Check/Paths.hs @@ -0,0 +1,417 @@ +-- | +-- Module : Distribution.PackageDescription.Check.Paths +-- Copyright : Lennart Kolmodin 2008, Francesco Ariis 2023 +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Functions to check filepaths, directories, globs, etc. +module Distribution.PackageDescription.Check.Paths + ( checkGlob + , checkPath + , fileExtensionSupportedLanguage + , isGoodRelativeDirectoryPath + , isGoodRelativeFilePath + , isGoodRelativeGlob + , isInsideDist + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.PackageDescription.Check.Common +import Distribution.PackageDescription.Check.Monad +import Distribution.Simple.CCompiler +import Distribution.Simple.Glob + ( Glob + , explainGlobSyntaxError + , isRecursiveInRoot + , parseFileGlob + ) +import Distribution.Simple.Utils hiding (findPackageDesc, notice) +import System.FilePath (splitDirectories, splitPath, takeExtension) + +import qualified System.FilePath.Windows as FilePath.Windows (isValid) + +fileExtensionSupportedLanguage :: FilePath -> Bool +fileExtensionSupportedLanguage path = + isHaskell || isC + where + extension = takeExtension path + isHaskell = extension `elem` [".hs", ".lhs"] + isC = isJust (filenameCDialect extension) + +-- Boolean: are absolute paths allowed? +checkPath + :: Monad m + => Bool -- Can be absolute path? + -> CabalField -- .cabal field that we are checking. + -> PathKind -- Path type. + -> FilePath -- Path. + -> CheckM m () +checkPath isAbs title kind path = do + checkP + (isOutsideTree path) + (PackageBuildWarning $ RelativeOutside title path) + checkP + (isInsideDist path) + (PackageDistInexcusable $ DistPoint (Just title) path) + checkPackageFileNamesWithGlob kind path + + -- Skip if "can be absolute path". + checkP + (not isAbs && isAbsoluteOnAnyPlatform path) + (PackageDistInexcusable $ AbsolutePath title path) + case grl path kind of + Just e -> + checkP + (not isAbs) + (PackageDistInexcusable $ BadRelativePath title path e) + Nothing -> return () + checkWindowsPath (kind == PathKindGlob) path + where + isOutsideTree wpath = case splitDirectories wpath of + ".." : _ -> True + "." : ".." : _ -> True + _ -> False + + -- These are not paths, but globs... + grl wfp PathKindFile = isGoodRelativeFilePath wfp + grl wfp PathKindGlob = isGoodRelativeGlob wfp + grl wfp PathKindDirectory = isGoodRelativeDirectoryPath wfp + +-- | Is a 'FilePath' inside `dist`, `dist-newstyle` and friends? +isInsideDist :: FilePath -> Bool +isInsideDist path = + case map lowercase (splitDirectories path) of + "dist" : _ -> True + "." : "dist" : _ -> True + "dist-newstyle" : _ -> True + "." : "dist-newstyle" : _ -> True + _ -> False + +checkPackageFileNamesWithGlob + :: Monad m + => PathKind + -> FilePath -- Filepath or possibly a glob pattern. + -> CheckM m () +checkPackageFileNamesWithGlob kind fp = do + checkWindowsPath (kind == PathKindGlob) fp + checkTarPath fp + +checkWindowsPath + :: Monad m + => Bool -- Is it a glob pattern? + -> FilePath -- Path. + -> CheckM m () +checkWindowsPath isGlob path = + checkP + (not . FilePath.Windows.isValid $ escape isGlob path) + (PackageDistInexcusable $ InvalidOnWin [path]) + where + -- Force a relative name to catch invalid file names like "f:oo" which + -- otherwise parse as file "oo" in the current directory on the 'f' drive. + escape :: Bool -> String -> String + escape wisGlob wpath = + (".\\" ++) + -- Glob paths will be expanded before being dereferenced, so asterisks + -- shouldn't count against them. + $ + map (\c -> if c == '*' && wisGlob then 'x' else c) wpath + +-- | Check a file name is valid for the portable POSIX tar format. +-- +-- The POSIX tar format has a restriction on the length of file names. It is +-- unfortunately not a simple restriction like a maximum length. The exact +-- restriction is that either the whole path be 100 characters or less, or it +-- be possible to split the path on a directory separator such that the first +-- part is 155 characters or less and the second part 100 characters or less. +checkTarPath :: Monad m => FilePath -> CheckM m () +checkTarPath path + | length path > 255 = tellP longPath + | otherwise = case pack nameMax (reverse (splitPath path)) of + Left err -> tellP err + Right [] -> return () + Right (h : rest) -> case pack prefixMax remainder of + Left err -> tellP err + Right [] -> return () + Right (_ : _) -> tellP noSplit + where + -- drop the '/' between the name and prefix: + remainder = safeInit h : rest + where + nameMax, prefixMax :: Int + nameMax = 100 + prefixMax = 155 + + pack _ [] = Left emptyName + pack maxLen (c : cs) + | n > maxLen = Left longName + | otherwise = Right (pack' maxLen n cs) + where + n = length c + + pack' maxLen n (c : cs) + | n' <= maxLen = pack' maxLen n' cs + where + n' = n + length c + pack' _ _ cs = cs + + longPath = PackageDistInexcusable (FilePathTooLong path) + longName = PackageDistInexcusable (FilePathNameTooLong path) + noSplit = PackageDistInexcusable (FilePathSplitTooLong path) + emptyName = PackageDistInexcusable FilePathEmpty + +-- `checkGlob` checks glob patterns and returns good ones for further +-- processing. +checkGlob + :: Monad m + => CabalField -- .cabal field we are checking. + -> FilePath -- glob filepath pattern + -> CheckM m (Maybe Glob) +checkGlob title pat = do + ver <- asksCM ccSpecVersion + + -- Glob sanity check. + case parseFileGlob ver pat of + Left e -> do + tellP + ( PackageDistInexcusable $ + GlobSyntaxError title (explainGlobSyntaxError pat e) + ) + return Nothing + Right wglob -> do + -- \* Miscellaneous checks on sane glob. + -- Checks for recursive glob in root. + checkP + (isRecursiveInRoot wglob) + ( PackageDistSuspiciousWarn $ + RecursiveGlobInRoot title pat + ) + return (Just wglob) + +-- | Whether a path is a good relative path. We aren't worried about perfect +-- cross-platform compatibility here; this function just checks the paths in +-- the (local) @.cabal@ file, while only Hackage needs the portability. +-- +-- >>> let test fp = putStrLn $ show (isGoodRelativeDirectoryPath fp) ++ "; " ++ show (isGoodRelativeFilePath fp) +-- +-- Note that "foo./bar.hs" would be invalid on Windows. +-- +-- >>> traverse_ test ["foo/bar/quu", "a/b.hs", "foo./bar.hs"] +-- Nothing; Nothing +-- Nothing; Nothing +-- Nothing; Nothing +-- +-- Trailing slash is not allowed for files, for directories it is ok. +-- +-- >>> test "foo/" +-- Nothing; Just "trailing slash" +-- +-- Leading @./@ is fine, but @.@ and @./@ are not valid files. +-- +-- >>> traverse_ test [".", "./", "./foo/bar"] +-- Nothing; Just "trailing dot segment" +-- Nothing; Just "trailing slash" +-- Nothing; Nothing +-- +-- Lastly, not good file nor directory cases: +-- +-- >>> traverse_ test ["", "/tmp/src", "foo//bar", "foo/.", "foo/./bar", "foo/../bar"] +-- Just "empty path"; Just "empty path" +-- Just "posix absolute path"; Just "posix absolute path" +-- Just "empty path segment"; Just "empty path segment" +-- Just "trailing same directory segment: ."; Just "trailing same directory segment: ." +-- Just "same directory segment: ."; Just "same directory segment: ." +-- Just "parent directory segment: .."; Just "parent directory segment: .." +-- +-- For the last case, 'isGoodRelativeGlob' doesn't warn: +-- +-- >>> traverse_ (print . isGoodRelativeGlob) ["foo/../bar"] +-- Just "parent directory segment: .." +isGoodRelativeFilePath :: FilePath -> Maybe String +isGoodRelativeFilePath = state0 + where + -- initial state + state0 [] = Just "empty path" + state0 (c : cs) + | c == '.' = state1 cs + | c == '/' = Just "posix absolute path" + | otherwise = state5 cs + + -- after initial . + state1 [] = Just "trailing dot segment" + state1 (c : cs) + | c == '.' = state4 cs + | c == '/' = state2 cs + | otherwise = state5 cs + + -- after ./ or after / between segments + state2 [] = Just "trailing slash" + state2 (c : cs) + | c == '.' = state3 cs + | c == '/' = Just "empty path segment" + | otherwise = state5 cs + + -- after non-first segment's . + state3 [] = Just "trailing same directory segment: ." + state3 (c : cs) + | c == '.' = state4 cs + | c == '/' = Just "same directory segment: ." + | otherwise = state5 cs + + -- after .. + state4 [] = Just "trailing parent directory segment: .." + state4 (c : cs) + | c == '.' = state5 cs + | c == '/' = Just "parent directory segment: .." + | otherwise = state5 cs + + -- in a segment which is ok. + state5 [] = Nothing + state5 (c : cs) + | c == '.' = state5 cs + | c == '/' = state2 cs + | otherwise = state5 cs + +-- | See 'isGoodRelativeFilePath'. +-- +-- This is barebones function. We check whether the glob is a valid file +-- by replacing stars @*@ with @x@ses. +isGoodRelativeGlob :: FilePath -> Maybe String +isGoodRelativeGlob = isGoodRelativeFilePath . map f + where + f '*' = 'x' + f c = c + +-- | See 'isGoodRelativeFilePath'. +isGoodRelativeDirectoryPath :: FilePath -> Maybe String +isGoodRelativeDirectoryPath = state0 + where + -- initial state + state0 [] = Just "empty path" + state0 (c : cs) + | c == '.' = state5 cs + | c == '/' = Just "posix absolute path" + | otherwise = state4 cs + + -- after initial ./ or after / between segments + state1 [] = Nothing + state1 (c : cs) + | c == '.' = state2 cs + | c == '/' = Just "empty path segment" + | otherwise = state4 cs + + -- after non-first setgment's . + state2 [] = Just "trailing same directory segment: ." + state2 (c : cs) + | c == '.' = state3 cs + | c == '/' = Just "same directory segment: ." + | otherwise = state4 cs + + -- after .. + state3 [] = Just "trailing parent directory segment: .." + state3 (c : cs) + | c == '.' = state4 cs + | c == '/' = Just "parent directory segment: .." + | otherwise = state4 cs + + -- in a segment which is ok. + state4 [] = Nothing + state4 (c : cs) + | c == '.' = state4 cs + | c == '/' = state1 cs + | otherwise = state4 cs + + -- after initial . + state5 [] = Nothing -- "." + state5 (c : cs) + | c == '.' = state3 cs + | c == '/' = state1 cs + | otherwise = state4 cs + +-- [Note: Good relative paths] +-- +-- Using @kleene@ we can define an extended regex: +-- +-- @ +-- import Algebra.Lattice +-- import Kleene +-- import Kleene.ERE (ERE (..), intersections) +-- +-- data C = CDot | CSlash | CChar +-- deriving (Eq, Ord, Enum, Bounded, Show) +-- +-- reservedR :: ERE C +-- reservedR = notChar CSlash +-- +-- pathPieceR :: ERE C +-- pathPieceR = intersections +-- [ plus reservedR +-- , ERENot (string [CDot]) +-- , ERENot (string [CDot,CDot]) +-- ] +-- +-- filePathR :: ERE C +-- filePathR = optional (string [CDot, CSlash]) <> pathPieceR <> star (char CSlash <> pathPieceR) +-- +-- dirPathR :: ERE C +-- dirPathR = (char CDot \/ filePathR) <> optional (char CSlash) +-- +-- plus :: ERE C -> ERE C +-- plus r = r <> star r +-- +-- optional :: ERE C -> ERE C +-- optional r = mempty \/ r +-- @ +-- +-- Results in following state machine for @filePathR@ +-- +-- @ +-- 0 -> \x -> if +-- | x <= CDot -> 1 +-- | otherwise -> 5 +-- 1 -> \x -> if +-- | x <= CDot -> 4 +-- | x <= CSlash -> 2 +-- | otherwise -> 5 +-- 2 -> \x -> if +-- | x <= CDot -> 3 +-- | otherwise -> 5 +-- 3 -> \x -> if +-- | x <= CDot -> 4 +-- | otherwise -> 5 +-- 4 -> \x -> if +-- | x <= CDot -> 5 +-- | otherwise -> 5 +-- 5+ -> \x -> if +-- | x <= CDot -> 5 +-- | x <= CSlash -> 2 +-- | otherwise -> 5 +-- @ +-- +-- and @dirPathR@: +-- +-- @ +-- 0 -> \x -> if +-- | x <= CDot -> 5 +-- | otherwise -> 4 +-- 1+ -> \x -> if +-- | x <= CDot -> 2 +-- | otherwise -> 4 +-- 2 -> \x -> if +-- | x <= CDot -> 3 +-- | otherwise -> 4 +-- 3 -> \x -> if +-- | x <= CDot -> 4 +-- | otherwise -> 4 +-- 4+ -> \x -> if +-- | x <= CDot -> 4 +-- | x <= CSlash -> 1 +-- | otherwise -> 4 +-- 5+ -> \x -> if +-- | x <= CDot -> 3 +-- | x <= CSlash -> 1 +-- | otherwise -> 4 +-- @ diff --git a/Cabal/src/Distribution/PackageDescription/Check/Target.hs b/Cabal/src/Distribution/PackageDescription/Check/Target.hs new file mode 100644 index 00000000000..a610b5875a5 --- /dev/null +++ b/Cabal/src/Distribution/PackageDescription/Check/Target.hs @@ -0,0 +1,1066 @@ +-- | +-- Module : Distribution.PackageDescription.Check.Target +-- Copyright : Lennart Kolmodin 2008, Francesco Ariis 2023 +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Fully-realised target (library, executable, …) checking functions. +module Distribution.PackageDescription.Check.Target + ( checkLibrary + , checkForeignLib + , checkExecutable + , checkTestSuite + , checkBenchmark + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.CabalSpecVersion +import Distribution.Compat.Lens +import Distribution.Compiler +import Distribution.ModuleName (ModuleName) +import Distribution.Package +import Distribution.PackageDescription +import Distribution.PackageDescription.Check.Common +import Distribution.PackageDescription.Check.Monad +import Distribution.PackageDescription.Check.Paths +import Distribution.Pretty (prettyShow) +import Distribution.Simple.BuildPaths + ( autogenPackageInfoModuleName + , autogenPathsModuleName + ) +import Distribution.Simple.Utils hiding (findPackageDesc, notice) +import Distribution.Types.PackageName.Magic +import Distribution.Utils.Path +import Distribution.Version +import Language.Haskell.Extension +import System.FilePath (takeExtension) + +import Control.Monad + +import qualified Distribution.Types.BuildInfo.Lens as L + +checkLibrary + :: Monad m + => Bool -- Is this a sublibrary? + -> [AssocDep] -- “Inherited” dependencies for PVP checks. + -> Library + -> CheckM m () +checkLibrary + isSub + ads + lib@( Library + libName_ + _exposedModules_ + reexportedModules_ + signatures_ + _libExposed_ + _libVisibility_ + libBuildInfo_ + ) = do + checkP + (libName_ == LMainLibName && isSub) + (PackageBuildImpossible UnnamedInternal) + -- TODO: bogus if a required-signature was passed through. + checkP + (null (explicitLibModules lib) && null reexportedModules_) + (PackageDistSuspiciousWarn (NoModulesExposed libName_)) + -- TODO parse-caught check, can safely remove. + checkSpecVer + CabalSpecV2_0 + (not . null $ signatures_) + (PackageDistInexcusable SignaturesCabal2) + -- autogen/includes checks. + checkP + ( not $ + all + (flip elem (explicitLibModules lib)) + (libModulesAutogen lib) + ) + (PackageBuildImpossible AutogenNotExposed) + -- check that all autogen-includes appear on includes or + -- install-includes. + checkP + ( not $ + all + (flip elem (allExplicitIncludes lib)) + (view L.autogenIncludes lib) + ) + $ (PackageBuildImpossible AutogenIncludesNotIncluded) + + -- § Build infos. + checkBuildInfo + (CETLibrary libName_) + (explicitLibModules lib) + ads + libBuildInfo_ + + -- Feature checks. + -- check use of reexported-modules sections + checkSpecVer + CabalSpecV1_22 + (not . null $ reexportedModules_) + (PackageDistInexcusable CVReexported) + where + allExplicitIncludes :: L.HasBuildInfo a => a -> [FilePath] + allExplicitIncludes x = + view L.includes x + ++ view L.installIncludes x + +checkForeignLib :: Monad m => ForeignLib -> CheckM m () +checkForeignLib + ( ForeignLib + foreignLibName_ + _foreignLibType_ + _foreignLibOptions_ + foreignLibBuildInfo_ + _foreignLibVersionInfo_ + _foreignLibVersionLinux_ + _foreignLibModDefFile_ + ) = do + checkBuildInfo + (CETForeignLibrary foreignLibName_) + [] + [] + foreignLibBuildInfo_ + +checkExecutable + :: Monad m + => [AssocDep] -- “Inherited” dependencies for PVP checks. + -> Executable + -> CheckM m () +checkExecutable + ads + exe@( Executable + exeName_ + modulePath_ + _exeScope_ + buildInfo_ + ) = do + -- Target type/name (exe). + let cet = CETExecutable exeName_ + + -- § Exe specific checks + checkP + (null modulePath_) + (PackageBuildImpossible (NoMainIs exeName_)) + -- This check does not apply to scripts. + pid <- asksCM (pnPackageId . ccNames) + checkP + ( pid /= fakePackageId + && not (null modulePath_) + && not (fileExtensionSupportedLanguage $ modulePath_) + ) + (PackageBuildImpossible NoHsLhsMain) + + -- § Features check + checkSpecVer + CabalSpecV1_18 + ( fileExtensionSupportedLanguage modulePath_ + && takeExtension modulePath_ `notElem` [".hs", ".lhs"] + ) + (PackageDistInexcusable MainCCabal1_18) + + -- Alas exeModules ad exeModulesAutogen (exported from + -- Distribution.Types.Executable) take `Executable` as a parameter. + checkP + (not $ all (flip elem (exeModules exe)) (exeModulesAutogen exe)) + (PackageBuildImpossible $ AutogenNoOther cet) + checkP + ( not $ + all + (flip elem (view L.includes exe)) + (view L.autogenIncludes exe) + ) + (PackageBuildImpossible AutogenIncludesNotIncludedExe) + + -- § Build info checks. + checkBuildInfo cet [] ads buildInfo_ + +checkTestSuite + :: Monad m + => [AssocDep] -- “Inherited” dependencies for PVP checks. + -> TestSuite + -> CheckM m () +checkTestSuite + ads + ts@( TestSuite + testName_ + testInterface_ + testBuildInfo_ + _testCodeGenerators_ + ) = do + -- Target type/name (test). + let cet = CETTest testName_ + + -- § TS specific checks. + -- TODO caught by the parser, can remove safely + case testInterface_ of + TestSuiteUnsupported tt@(TestTypeUnknown _ _) -> + tellP (PackageBuildWarning $ TestsuiteTypeNotKnown tt) + TestSuiteUnsupported tt -> + tellP (PackageBuildWarning $ TestsuiteNotSupported tt) + _ -> return () + checkP + mainIsWrongExt + (PackageBuildImpossible NoHsLhsMain) + checkP + ( not $ + all + (flip elem (testModules ts)) + (testModulesAutogen ts) + ) + (PackageBuildImpossible $ AutogenNoOther cet) + checkP + ( not $ + all + (flip elem (view L.includes ts)) + (view L.autogenIncludes ts) + ) + (PackageBuildImpossible AutogenIncludesNotIncludedExe) + + -- § Feature checks. + checkSpecVer + CabalSpecV1_18 + (mainIsNotHsExt && not mainIsWrongExt) + (PackageDistInexcusable MainCCabal1_18) + + -- § Build info checks. + checkBuildInfo cet [] ads testBuildInfo_ + where + mainIsWrongExt = + case testInterface_ of + TestSuiteExeV10 _ f -> not (fileExtensionSupportedLanguage f) + _ -> False + + mainIsNotHsExt = + case testInterface_ of + TestSuiteExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"] + _ -> False + +checkBenchmark + :: Monad m + => [AssocDep] -- “Inherited” dependencies for PVP checks. + -> Benchmark + -> CheckM m () +checkBenchmark + ads + bm@( Benchmark + benchmarkName_ + benchmarkInterface_ + benchmarkBuildInfo_ + ) = do + -- Target type/name (benchmark). + let cet = CETBenchmark benchmarkName_ + + -- § Interface & bm specific tests. + case benchmarkInterface_ of + BenchmarkUnsupported tt@(BenchmarkTypeUnknown _ _) -> + tellP (PackageBuildWarning $ BenchmarkTypeNotKnown tt) + BenchmarkUnsupported tt -> + tellP (PackageBuildWarning $ BenchmarkNotSupported tt) + _ -> return () + checkP + mainIsWrongExt + (PackageBuildImpossible NoHsLhsMainBench) + + checkP + ( not $ + all + (flip elem (benchmarkModules bm)) + (benchmarkModulesAutogen bm) + ) + (PackageBuildImpossible $ AutogenNoOther cet) + + checkP + ( not $ + all + (flip elem (view L.includes bm)) + (view L.autogenIncludes bm) + ) + (PackageBuildImpossible AutogenIncludesNotIncludedExe) + + -- § BuildInfo checks. + checkBuildInfo cet [] ads benchmarkBuildInfo_ + where + -- Cannot abstract with similar function in checkTestSuite, + -- they are different. + mainIsWrongExt = + case benchmarkInterface_ of + BenchmarkExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"] + _ -> False + +-- ------------------------------------------------------------ +-- Build info +-- ------------------------------------------------------------ + +-- Check a great deal of things in buildInfo. +-- With 'checkBuildInfo' we cannot follow the usual “pattern match +-- everything” method, for the number of BuildInfo fields (almost 50) +-- but more importantly because accessing options, etc. is done +-- with functions from 'Distribution.Types.BuildInfo' (e.g. 'hcOptions'). +-- Duplicating the effort here means risk of diverging definitions for +-- little gain (most likely if a field is added to BI, the relevant +-- function will be tweaked in Distribution.Types.BuildInfo too). +checkBuildInfo + :: Monad m + => CEType -- Name and type of the target. + -> [ModuleName] -- Additional module names which cannot be + -- extracted from BuildInfo (mainly: exposed + -- library modules). + -> [AssocDep] -- Inherited “internal” (main lib, named + -- internal libs) dependencies. + -> BuildInfo + -> CheckM m () +checkBuildInfo cet ams ads bi = do + -- For the sake of clarity, we split che checks in various + -- (top level) functions, even if we are not actually going + -- deeper in the traversal. + + checkBuildInfoOptions (cet2bit cet) bi + checkBuildInfoPathsContent bi + checkBuildInfoPathsWellFormedness bi + + sv <- asksCM ccSpecVersion + checkBuildInfoFeatures bi sv + + checkAutogenModules ams bi + + -- PVP: we check for base and all other deps. + (ids, rds) <- + partitionDeps + ads + [mkUnqualComponentName "base"] + (mergeDependencies $ targetBuildDepends bi) + let ick = const (PackageDistInexcusable BaseNoUpperBounds) + rck = PackageDistSuspiciousWarn . MissingUpperBounds cet + checkPVP ick ids + unless + (isInternalTarget cet) + (checkPVPs rck rds) + + -- Custom fields well-formedness (ASCII). + mapM_ checkCustomField (customFieldsBI bi) + + -- Content. + mapM_ (checkLocalPathExist "extra-lib-dirs") (extraLibDirs bi) + mapM_ + (checkLocalPathExist "extra-lib-dirs-static") + (extraLibDirsStatic bi) + mapM_ + (checkLocalPathExist "extra-framework-dirs") + (extraFrameworkDirs bi) + mapM_ (checkLocalPathExist "include-dirs") (includeDirs bi) + mapM_ + (checkLocalPathExist "hs-source-dirs" . getSymbolicPath) + (hsSourceDirs bi) + +-- Well formedness of BI contents (no `Haskell2015`, no deprecated +-- extensions etc). +checkBuildInfoPathsContent :: Monad m => BuildInfo -> CheckM m () +checkBuildInfoPathsContent bi = do + mapM_ checkLang (allLanguages bi) + mapM_ checkExt (allExtensions bi) + mapM_ checkIntDep (targetBuildDepends bi) + df <- asksCM ccDesugar + -- This way we can use the same function for legacy&non exedeps. + let ds = buildToolDepends bi ++ catMaybes (map df $ buildTools bi) + mapM_ checkBTDep ds + where + checkLang :: Monad m => Language -> CheckM m () + checkLang (UnknownLanguage n) = + tellP (PackageBuildWarning (UnknownLanguages [n])) + checkLang _ = return () + + checkExt :: Monad m => Extension -> CheckM m () + checkExt (UnknownExtension n) + | n `elem` map prettyShow knownLanguages = + tellP (PackageBuildWarning (LanguagesAsExtension [n])) + | otherwise = + tellP (PackageBuildWarning (UnknownExtensions [n])) + checkExt n = do + let dss = filter (\(a, _) -> a == n) deprecatedExtensions + checkP + (not . null $ dss) + (PackageDistSuspicious $ DeprecatedExtensions dss) + + checkIntDep :: Monad m => Dependency -> CheckM m () + checkIntDep d@(Dependency name vrange _) = do + mpn <- + asksCM + ( packageNameToUnqualComponentName + . pkgName + . pnPackageId + . ccNames + ) + lns <- asksCM (pnSubLibs . ccNames) + pVer <- asksCM (pkgVersion . pnPackageId . ccNames) + let allLibNs = mpn : lns + when + ( mpn == packageNameToUnqualComponentName name + -- Make sure it is not a library with the + -- same name from another package. + && packageNameToUnqualComponentName name `elem` allLibNs + ) + ( checkP + (not $ pVer `withinRange` vrange) + (PackageBuildImpossible $ ImpossibleInternalDep [d]) + ) + + checkBTDep :: Monad m => ExeDependency -> CheckM m () + checkBTDep ed@(ExeDependency n name vrange) = do + exns <- asksCM (pnExecs . ccNames) + pVer <- asksCM (pkgVersion . pnPackageId . ccNames) + pNam <- asksCM (pkgName . pnPackageId . ccNames) + checkP + ( n == pNam + && name `notElem` exns -- internal + -- not present + ) + (PackageBuildImpossible $ MissingInternalExe [ed]) + when + (name `elem` exns) + ( checkP + (not $ pVer `withinRange` vrange) + (PackageBuildImpossible $ ImpossibleInternalExe [ed]) + ) + +-- Paths well-formedness check for BuildInfo. +checkBuildInfoPathsWellFormedness :: Monad m => BuildInfo -> CheckM m () +checkBuildInfoPathsWellFormedness bi = do + mapM_ (checkPath False "asm-sources" PathKindFile) (asmSources bi) + mapM_ (checkPath False "cmm-sources" PathKindFile) (cmmSources bi) + mapM_ (checkPath False "c-sources" PathKindFile) (cSources bi) + mapM_ (checkPath False "cxx-sources" PathKindFile) (cxxSources bi) + mapM_ (checkPath False "js-sources" PathKindFile) (jsSources bi) + mapM_ + (checkPath False "install-includes" PathKindFile) + (installIncludes bi) + mapM_ + (checkPath False "hs-source-dirs" PathKindDirectory . getSymbolicPath) + (hsSourceDirs bi) + -- Possibly absolute paths. + mapM_ (checkPath True "includes" PathKindFile) (includes bi) + mapM_ + (checkPath True "include-dirs" PathKindDirectory) + (includeDirs bi) + mapM_ + (checkPath True "extra-lib-dirs" PathKindDirectory) + (extraLibDirs bi) + mapM_ + (checkPath True "extra-lib-dirs-static" PathKindDirectory) + (extraLibDirsStatic bi) + mapM_ checkOptionPath (perCompilerFlavorToList $ options bi) + where + checkOptionPath + :: Monad m + => (CompilerFlavor, [FilePath]) + -> CheckM m () + checkOptionPath (GHC, paths) = + mapM_ + ( \path -> + checkP + (isInsideDist path) + (PackageDistInexcusable $ DistPoint Nothing path) + ) + paths + checkOptionPath _ = return () + +-- Checks for features that can be present in BuildInfo only with certain +-- CabalSpecVersion. +checkBuildInfoFeatures + :: Monad m + => BuildInfo + -> CabalSpecVersion + -> CheckM m () +checkBuildInfoFeatures bi sv = do + -- Default language can be used only w/ spec ≥ 1.10 + checkSpecVer + CabalSpecV1_10 + (isJust $ defaultLanguage bi) + (PackageBuildWarning CVDefaultLanguage) + -- CheckSpecVer sv. + checkDefaultLanguage + -- Check use of 'extra-framework-dirs' field. + checkSpecVer + CabalSpecV1_24 + (not . null $ extraFrameworkDirs bi) + (PackageDistSuspiciousWarn CVExtraFrameworkDirs) + -- Check use of default-extensions field don't need to do the + -- equivalent check for other-extensions. + checkSpecVer + CabalSpecV1_10 + (not . null $ defaultExtensions bi) + (PackageBuildWarning CVDefaultExtensions) + -- Check use of extensions field + checkP + (sv >= CabalSpecV1_10 && (not . null $ oldExtensions bi)) + (PackageBuildWarning CVExtensionsDeprecated) + + -- asm-sources, cmm-sources and friends only w/ spec ≥ 1.10 + checkCVSources (asmSources bi) + checkCVSources (cmmSources bi) + checkCVSources (extraBundledLibs bi) + checkCVSources (extraLibFlavours bi) + + -- extra-dynamic-library-flavours requires ≥ 3.0 + checkSpecVer + CabalSpecV3_0 + (not . null $ extraDynLibFlavours bi) + (PackageDistInexcusable $ CVExtraDynamic [extraDynLibFlavours bi]) + -- virtual-modules requires ≥ 2.2 + checkSpecVer CabalSpecV2_2 (not . null $ virtualModules bi) $ + (PackageDistInexcusable CVVirtualModules) + -- Check use of thinning and renaming. + checkSpecVer + CabalSpecV2_0 + (not . null $ mixins bi) + (PackageDistInexcusable CVMixins) + + checkBuildInfoExtensions bi + where + checkCVSources :: Monad m => [FilePath] -> CheckM m () + checkCVSources cvs = + checkSpecVer + CabalSpecV3_0 + (not . null $ cvs) + (PackageDistInexcusable CVSources) + + checkDefaultLanguage :: Monad m => CheckM m () + checkDefaultLanguage = do + -- < 1.10 has no `default-language` field. + when + (sv >= CabalSpecV1_10 && isNothing (defaultLanguage bi)) + -- < 3.4 mandatory, after just a suggestion. + ( if sv < CabalSpecV3_4 + then tellP (PackageBuildWarning CVDefaultLanguageComponent) + else tellP (PackageDistInexcusable CVDefaultLanguageComponentSoft) + ) + +-- Tests for extensions usage which can break Cabal < 1.4. +checkBuildInfoExtensions :: Monad m => BuildInfo -> CheckM m () +checkBuildInfoExtensions bi = do + let exts = allExtensions bi + extCabal1_2 = nub $ filter (`elem` compatExtensionsExtra) exts + extCabal1_4 = nub $ filter (`notElem` compatExtensions) exts + -- As of Cabal-1.4 we can add new extensions without worrying + -- about breaking old versions of cabal. + checkSpecVer + CabalSpecV1_2 + (not . null $ extCabal1_2) + ( PackageDistInexcusable $ + CVExtensions CabalSpecV1_2 extCabal1_2 + ) + checkSpecVer + CabalSpecV1_4 + (not . null $ extCabal1_4) + ( PackageDistInexcusable $ + CVExtensions CabalSpecV1_4 extCabal1_4 + ) + where + -- The known extensions in Cabal-1.2.3 + compatExtensions :: [Extension] + compatExtensions = + map + EnableExtension + [ OverlappingInstances + , UndecidableInstances + , IncoherentInstances + , RecursiveDo + , ParallelListComp + , MultiParamTypeClasses + , FunctionalDependencies + , Rank2Types + , RankNTypes + , PolymorphicComponents + , ExistentialQuantification + , ScopedTypeVariables + , ImplicitParams + , FlexibleContexts + , FlexibleInstances + , EmptyDataDecls + , CPP + , BangPatterns + , TypeSynonymInstances + , TemplateHaskell + , ForeignFunctionInterface + , Arrows + , Generics + , NamedFieldPuns + , PatternGuards + , GeneralizedNewtypeDeriving + , ExtensibleRecords + , RestrictedTypeSynonyms + , HereDocuments + ] + ++ map + DisableExtension + [MonomorphismRestriction, ImplicitPrelude] + ++ compatExtensionsExtra + + -- The extra known extensions in Cabal-1.2.3 vs Cabal-1.1.6 + -- (Cabal-1.1.6 came with ghc-6.6. Cabal-1.2 came with ghc-6.8) + compatExtensionsExtra :: [Extension] + compatExtensionsExtra = + map + EnableExtension + [ KindSignatures + , MagicHash + , TypeFamilies + , StandaloneDeriving + , UnicodeSyntax + , PatternSignatures + , UnliftedFFITypes + , LiberalTypeSynonyms + , TypeOperators + , RecordWildCards + , RecordPuns + , DisambiguateRecordFields + , OverloadedStrings + , GADTs + , RelaxedPolyRec + , ExtendedDefaultRules + , UnboxedTuples + , DeriveDataTypeable + , ConstrainedClassMethods + ] + ++ map + DisableExtension + [MonoPatBinds] + +-- Autogenerated modules (Paths_, PackageInfo_) checks. We could pass this +-- function something more specific than the whole BuildInfo, but it would be +-- a tuple of [ModuleName] lists, error prone. +checkAutogenModules + :: Monad m + => [ModuleName] -- Additional modules not present + -- in BuildInfo (e.g. exposed library + -- modules). + -> BuildInfo + -> CheckM m () +checkAutogenModules ams bi = do + pkgId <- asksCM (pnPackageId . ccNames) + let + -- It is an unfortunate reality that autogenPathsModuleName + -- and autogenPackageInfoModuleName work on PackageDescription + -- while not needing it all, but just the `package` bit. + minimalPD = emptyPackageDescription{package = pkgId} + autoPathsName = autogenPathsModuleName minimalPD + autoInfoModuleName = autogenPackageInfoModuleName minimalPD + + -- Autogenerated module + some default extension build failure. + autogenCheck autoPathsName CVAutogenPaths + rebindableClashCheck autoPathsName RebindableClashPaths + + -- Paths_* module + some default extension build failure. + autogenCheck autoInfoModuleName CVAutogenPackageInfo + rebindableClashCheck autoInfoModuleName RebindableClashPackageInfo + + -- PackageInfo_* module + cabal-version < 3.12 + -- See Mikolaj’s comments on #9481 on why this has to be + -- PackageBuildImpossible and not merely PackageDistInexcusable. + checkSpecVer + CabalSpecV3_12 + (elem autoInfoModuleName allModsForAuto) + (PackageBuildImpossible CVAutogenPackageInfoGuard) + where + allModsForAuto :: [ModuleName] + allModsForAuto = ams ++ otherModules bi + + autogenCheck + :: Monad m + => ModuleName + -> CheckExplanation + -> CheckM m () + autogenCheck name warning = do + sv <- asksCM ccSpecVersion + checkP + ( sv >= CabalSpecV2_0 + && elem name allModsForAuto + && notElem name (autogenModules bi) + ) + (PackageDistInexcusable warning) + + rebindableClashCheck + :: Monad m + => ModuleName + -> CheckExplanation + -> CheckM m () + rebindableClashCheck name warning = do + checkSpecVer + CabalSpecV2_2 + ( ( name `elem` otherModules bi + || name `elem` autogenModules bi + ) + && checkExts + ) + (PackageBuildImpossible warning) + + -- Do we have some peculiar extensions active which would interfere + -- (cabal-version <2.2) with Paths_modules? + checkExts :: Bool + checkExts = + let exts = defaultExtensions bi + in rebind `elem` exts + && (strings `elem` exts || lists `elem` exts) + where + rebind = EnableExtension RebindableSyntax + strings = EnableExtension OverloadedStrings + lists = EnableExtension OverloadedLists + +checkLocalPathExist + :: Monad m + => String -- .cabal field where we found the error. + -> FilePath + -> CheckM m () +checkLocalPathExist title dir = + checkPkg + ( \ops -> do + dn <- not <$> doesDirectoryExist ops dir + let rp = not (isAbsoluteOnAnyPlatform dir) + return (rp && dn) + ) + (PackageBuildWarning $ UnknownDirectory title dir) + +-- PVP -- + +-- Sometimes we read (or end up with) “straddle” deps declarations +-- like this: +-- +-- build-depends: base > 3, base < 4 +-- +-- `mergeDependencies` reduces that to base > 3 && < 4, _while_ maintaining +-- dependencies order in the list (better UX). +mergeDependencies :: [Dependency] -> [Dependency] +mergeDependencies [] = [] +mergeDependencies l@(d : _) = + let (sames, diffs) = partition ((== depName d) . depName) l + merged = + Dependency + (depPkgName d) + ( foldl intersectVersionRanges anyVersion $ + map depVerRange sames + ) + (depLibraries d) + in merged : mergeDependencies diffs + where + depName :: Dependency -> String + depName wd = unPackageName . depPkgName $ wd + +-- Is this an internal target? We do not perform PVP checks on those, +-- see https://github.com/haskell/cabal/pull/8361#issuecomment-1577547091 +isInternalTarget :: CEType -> Bool +isInternalTarget (CETLibrary{}) = False +isInternalTarget (CETForeignLibrary{}) = False +isInternalTarget (CETExecutable{}) = False +isInternalTarget (CETTest{}) = True +isInternalTarget (CETBenchmark{}) = True +isInternalTarget (CETSetup{}) = False + +-- ------------------------------------------------------------ +-- Options +-- ------------------------------------------------------------ + +-- Target type for option checking. +data BITarget = BITLib | BITTestBench | BITOther + deriving (Eq, Show) + +cet2bit :: CEType -> BITarget +cet2bit (CETLibrary{}) = BITLib +cet2bit (CETForeignLibrary{}) = BITLib +cet2bit (CETExecutable{}) = BITOther +cet2bit (CETTest{}) = BITTestBench +cet2bit (CETBenchmark{}) = BITTestBench +cet2bit CETSetup = BITOther + +-- General check on all options (ghc, C, C++, …) for common inaccuracies. +checkBuildInfoOptions :: Monad m => BITarget -> BuildInfo -> CheckM m () +checkBuildInfoOptions t bi = do + checkGHCOptions "ghc-options" t (hcOptions GHC bi) + checkGHCOptions "ghc-prof-options" t (hcProfOptions GHC bi) + checkGHCOptions "ghc-shared-options" t (hcSharedOptions GHC bi) + let ldOpts = ldOptions bi + checkCLikeOptions LangC "cc-options" (ccOptions bi) ldOpts + checkCLikeOptions LangCPlusPlus "cxx-options" (cxxOptions bi) ldOpts + checkCPPOptions (cppOptions bi) + +-- | Checks GHC options for commonly misused or non-portable flags. +checkGHCOptions + :: Monad m + => CabalField -- .cabal field name where we found the error. + -> BITarget -- Target type. + -> [String] -- Options (alas in String form). + -> CheckM m () +checkGHCOptions title t opts = do + checkGeneral + case t of + BITLib -> sequence_ [checkLib, checkNonTestBench] + BITTestBench -> checkTestBench + BITOther -> checkNonTestBench + where + checkFlags :: Monad m => [String] -> PackageCheck -> CheckM m () + checkFlags fs ck = checkP (any (`elem` fs) opts) ck + + checkFlagsP + :: Monad m + => (String -> Bool) + -> (String -> PackageCheck) + -> CheckM m () + checkFlagsP p ckc = + case filter p opts of + [] -> return () + (_ : _) -> tellP (ckc title) + + checkGeneral = do + checkFlags + ["-fasm"] + (PackageDistInexcusable $ OptFasm title) + checkFlags + ["-fhpc"] + (PackageDistInexcusable $ OptHpc title) + checkFlags + ["-prof"] + (PackageBuildWarning $ OptProf title) + -- Does not apply to scripts. + -- Why do we need this? See #8963. + pid <- asksCM (pnPackageId . ccNames) + unless (pid == fakePackageId) $ + checkFlags + ["-o"] + (PackageBuildWarning $ OptO title) + checkFlags + ["-hide-package"] + (PackageBuildWarning $ OptHide title) + checkFlags + ["--make"] + (PackageBuildWarning $ OptMake title) + checkFlags + ["-O", "-O1"] + (PackageDistInexcusable $ OptOOne title) + checkFlags + ["-O2"] + (PackageDistSuspiciousWarn $ OptOTwo title) + checkFlags + ["-split-sections"] + (PackageBuildWarning $ OptSplitSections title) + checkFlags + ["-split-objs"] + (PackageBuildWarning $ OptSplitObjs title) + checkFlags + ["-optl-Wl,-s", "-optl-s"] + (PackageDistInexcusable $ OptWls title) + checkFlags + ["-fglasgow-exts"] + (PackageDistSuspicious $ OptExts title) + let ghcNoRts = rmRtsOpts opts + checkAlternatives + title + "extensions" + [ (flag, prettyShow extension) + | flag <- ghcNoRts + , Just extension <- [ghcExtension flag] + ] + checkAlternatives + title + "extensions" + [ (flag, extension) + | flag@('-' : 'X' : extension) <- ghcNoRts + ] + checkAlternatives + title + "cpp-options" + ( [(flag, flag) | flag@('-' : 'D' : _) <- ghcNoRts] + ++ [(flag, flag) | flag@('-' : 'U' : _) <- ghcNoRts] + ) + checkAlternatives + title + "include-dirs" + [(flag, dir) | flag@('-' : 'I' : dir) <- ghcNoRts] + checkAlternatives + title + "extra-libraries" + [(flag, lib) | flag@('-' : 'l' : lib) <- ghcNoRts] + checkAlternatives + title + "extra-libraries-static" + [(flag, lib) | flag@('-' : 'l' : lib) <- ghcNoRts] + checkAlternatives + title + "extra-lib-dirs" + [(flag, dir) | flag@('-' : 'L' : dir) <- ghcNoRts] + checkAlternatives + title + "extra-lib-dirs-static" + [(flag, dir) | flag@('-' : 'L' : dir) <- ghcNoRts] + checkAlternatives + title + "frameworks" + [ (flag, fmwk) + | (flag@"-framework", fmwk) <- + zip ghcNoRts (safeTail ghcNoRts) + ] + checkAlternatives + title + "extra-framework-dirs" + [ (flag, dir) + | (flag@"-framework-path", dir) <- + zip ghcNoRts (safeTail ghcNoRts) + ] + -- Old `checkDevelopmentOnlyFlagsOptions` section + checkFlags + ["-Werror"] + (PackageDistInexcusable $ WErrorUnneeded title) + checkFlags + ["-fdefer-type-errors"] + (PackageDistInexcusable $ FDeferTypeErrorsUnneeded title) + checkFlags + [ "-fprof-auto" + , "-fprof-auto-top" + , "-fprof-auto-calls" + , "-fprof-cafs" + , "-fno-prof-count-entries" + , "-auto-all" + , "-auto" + , "-caf-all" + ] + (PackageDistSuspicious $ ProfilingUnneeded title) + checkFlagsP + ( \opt -> + "-d" `isPrefixOf` opt + && opt /= "-dynamic" + ) + (PackageDistInexcusable . DynamicUnneeded) + checkFlagsP + ( \opt -> case opt of + "-j" -> True + ('-' : 'j' : d : _) -> isDigit d + _ -> False + ) + (PackageDistInexcusable . JUnneeded) + + checkLib = do + checkP + ("-rtsopts" `elem` opts) + (PackageBuildWarning $ OptRts title) + checkP + (any (\opt -> "-with-rtsopts" `isPrefixOf` opt) opts) + (PackageBuildWarning $ OptWithRts title) + + checkTestBench = do + checkFlags + ["-O0", "-Onot"] + (PackageDistSuspiciousWarn $ OptONot title) + + checkNonTestBench = do + checkFlags + ["-O0", "-Onot"] + (PackageDistSuspicious $ OptONot title) + + ghcExtension ('-' : 'f' : name) = case name of + "allow-overlapping-instances" -> enable OverlappingInstances + "no-allow-overlapping-instances" -> disable OverlappingInstances + "th" -> enable TemplateHaskell + "no-th" -> disable TemplateHaskell + "ffi" -> enable ForeignFunctionInterface + "no-ffi" -> disable ForeignFunctionInterface + "fi" -> enable ForeignFunctionInterface + "no-fi" -> disable ForeignFunctionInterface + "monomorphism-restriction" -> enable MonomorphismRestriction + "no-monomorphism-restriction" -> disable MonomorphismRestriction + "mono-pat-binds" -> enable MonoPatBinds + "no-mono-pat-binds" -> disable MonoPatBinds + "allow-undecidable-instances" -> enable UndecidableInstances + "no-allow-undecidable-instances" -> disable UndecidableInstances + "allow-incoherent-instances" -> enable IncoherentInstances + "no-allow-incoherent-instances" -> disable IncoherentInstances + "arrows" -> enable Arrows + "no-arrows" -> disable Arrows + "generics" -> enable Generics + "no-generics" -> disable Generics + "implicit-prelude" -> enable ImplicitPrelude + "no-implicit-prelude" -> disable ImplicitPrelude + "implicit-params" -> enable ImplicitParams + "no-implicit-params" -> disable ImplicitParams + "bang-patterns" -> enable BangPatterns + "no-bang-patterns" -> disable BangPatterns + "scoped-type-variables" -> enable ScopedTypeVariables + "no-scoped-type-variables" -> disable ScopedTypeVariables + "extended-default-rules" -> enable ExtendedDefaultRules + "no-extended-default-rules" -> disable ExtendedDefaultRules + _ -> Nothing + ghcExtension "-cpp" = enable CPP + ghcExtension _ = Nothing + + enable e = Just (EnableExtension e) + disable e = Just (DisableExtension e) + + rmRtsOpts :: [String] -> [String] + rmRtsOpts ("-with-rtsopts" : _ : xs) = rmRtsOpts xs + rmRtsOpts (x : xs) = x : rmRtsOpts xs + rmRtsOpts [] = [] + +checkCLikeOptions + :: Monad m + => WarnLang -- Language we are warning about (C or C++). + -> CabalField -- Field where we found the error. + -> [String] -- Options in string form. + -> [String] -- Link options in String form. + -> CheckM m () +checkCLikeOptions label prefix opts ldOpts = do + checkAlternatives + prefix + "include-dirs" + [(flag, dir) | flag@('-' : 'I' : dir) <- opts] + checkAlternatives + prefix + "extra-libraries" + [(flag, lib) | flag@('-' : 'l' : lib) <- opts] + checkAlternatives + prefix + "extra-lib-dirs" + [(flag, dir) | flag@('-' : 'L' : dir) <- opts] + + checkAlternatives + "ld-options" + "extra-libraries" + [(flag, lib) | flag@('-' : 'l' : lib) <- ldOpts] + checkAlternatives + "ld-options" + "extra-lib-dirs" + [(flag, dir) | flag@('-' : 'L' : dir) <- ldOpts] + + checkP + (any (`elem` ["-O", "-Os", "-O0", "-O1", "-O2", "-O3"]) opts) + (PackageDistSuspicious $ COptONumber prefix label) + +checkAlternatives + :: Monad m + => CabalField -- Wrong field. + -> CabalField -- Appropriate field. + -> [(String, String)] -- List of good and bad flags. + -> CheckM m () +checkAlternatives badField goodField flags = do + let (badFlags, _) = unzip flags + checkP + (not $ null badFlags) + (PackageBuildWarning $ OptAlternatives badField goodField flags) + +checkCPPOptions + :: Monad m + => [String] -- Options in String form. + -> CheckM m () +checkCPPOptions opts = do + checkAlternatives + "cpp-options" + "include-dirs" + [(flag, dir) | flag@('-' : 'I' : dir) <- opts] + mapM_ + ( \opt -> + checkP + (not $ any (`isPrefixOf` opt) ["-D", "-U", "-I"]) + (PackageBuildWarning (COptCPP opt)) + ) + opts diff --git a/Cabal/src/Distribution/PackageDescription/Check/Warning.hs b/Cabal/src/Distribution/PackageDescription/Check/Warning.hs new file mode 100644 index 00000000000..6f21d5d0da6 --- /dev/null +++ b/Cabal/src/Distribution/PackageDescription/Check/Warning.hs @@ -0,0 +1,1481 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ScopedTypeVariables #-} + +-- | +-- Module : Distribution.PackageDescription.Check.Warning +-- Copyright : Francesco Ariis 2022 +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Warning types, messages, severity and associated functions. +module Distribution.PackageDescription.Check.Warning + ( -- * Types and constructors + PackageCheck (..) + , CheckExplanation (..) + , CheckExplanationID + , CheckExplanationIDString + , CEType (..) + , WarnLang (..) + + -- * Operations + , ppPackageCheck + , ppCheckExplanationId + , isHackageDistError + , extractCheckExplantion + , filterPackageChecksById + , filterPackageChecksByIdString + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.CabalSpecVersion (CabalSpecVersion, showCabalSpecVersion) +import Distribution.License (License, knownLicenses) +import Distribution.ModuleName (ModuleName) +import Distribution.Parsec.Warning (PWarning, showPWarning) +import Distribution.Pretty (prettyShow) +import Distribution.Types.BenchmarkType (BenchmarkType, knownBenchmarkTypes) +import Distribution.Types.Dependency (Dependency (..)) +import Distribution.Types.ExeDependency (ExeDependency) +import Distribution.Types.Flag (FlagName, unFlagName) +import Distribution.Types.LibraryName (LibraryName (..), showLibraryName) +import Distribution.Types.PackageName (PackageName) +import Distribution.Types.TestType (TestType, knownTestTypes) +import Distribution.Types.UnqualComponentName +import Distribution.Types.Version (Version) +import Distribution.Utils.Path + ( LicenseFile + , PackageDir + , SymbolicPath + , getSymbolicPath + ) +import Language.Haskell.Extension (Extension) + +import qualified Data.Either as Either +import qualified Data.List as List +import qualified Data.Set as Set + +-- ------------------------------------------------------------ +-- Check types and explanations +-- ------------------------------------------------------------ + +-- | Results of some kind of failed package check. +-- +-- There are a range of severities, from merely dubious to totally insane. +-- All of them come with a human readable explanation. In future we may augment +-- them with more machine readable explanations, for example to help an IDE +-- suggest automatic corrections. +data PackageCheck + = -- | This package description is no good. There's no way it's going to + -- build sensibly. This should give an error at configure time. + PackageBuildImpossible {explanation :: CheckExplanation} + | -- | A problem that is likely to affect building the package, or an + -- issue that we'd like every package author to be aware of, even if + -- the package is never distributed. + PackageBuildWarning {explanation :: CheckExplanation} + | -- | An issue that might not be a problem for the package author but + -- might be annoying or detrimental when the package is distributed to + -- users. We should encourage distributed packages to be free from these + -- issues, but occasionally there are justifiable reasons so we cannot + -- ban them entirely. + PackageDistSuspicious {explanation :: CheckExplanation} + | -- | Like PackageDistSuspicious but will only display warnings + -- rather than causing abnormal exit when you run 'cabal check'. + PackageDistSuspiciousWarn {explanation :: CheckExplanation} + | -- | An issue that is OK in the author's environment but is almost + -- certain to be a portability problem for other environments. We can + -- quite legitimately refuse to publicly distribute packages with these + -- problems. + PackageDistInexcusable {explanation :: CheckExplanation} + deriving (Eq, Ord) + +-- | Pretty printing 'PackageCheck'. +ppPackageCheck :: PackageCheck -> String +ppPackageCheck e = + let ex = explanation e + in "[" + ++ (ppCheckExplanationId . checkExplanationId) ex + ++ "] " + ++ ppExplanation ex + +-- | Broken 'Show' instance (not bijective with Read), alas external packages +-- depend on it. +instance Show PackageCheck where + show notice = ppPackageCheck notice + +-- | Would Hackage refuse a package because of this error? +isHackageDistError :: PackageCheck -> Bool +isHackageDistError = \case + (PackageBuildImpossible{}) -> True + (PackageBuildWarning{}) -> True + (PackageDistInexcusable{}) -> True + (PackageDistSuspicious{}) -> False + (PackageDistSuspiciousWarn{}) -> False + +-- | Filter Package Check by CheckExplanationID. +filterPackageChecksById + :: [PackageCheck] + -- ^ Original checks. + -> [CheckExplanationID] + -- ^ IDs to omit. + -> [PackageCheck] +filterPackageChecksById cs is = filter ff cs + where + ff :: PackageCheck -> Bool + ff c = + flip notElem is + . checkExplanationId + . extractCheckExplantion + $ c + +-- | Filter Package Check by Check explanation /string/. +filterPackageChecksByIdString + :: [PackageCheck] + -- ^ Original checks. + -> [CheckExplanationIDString] + -- ^ IDs to omit, in @String@ format. + -> ([PackageCheck], [CheckExplanationIDString]) +-- Filtered checks plus unrecognised id strings. +filterPackageChecksByIdString cs ss = + let (es, is) = Either.partitionEithers $ map readExplanationID ss + in (filterPackageChecksById cs is, es) + +-- | Explanations of 'PackageCheck`'s errors/warnings. +data CheckExplanation + = ParseWarning FilePath PWarning + | NoNameField + | NoVersionField + | NoTarget + | UnnamedInternal + | DuplicateSections [UnqualComponentName] + | IllegalLibraryName PackageName + | NoModulesExposed LibraryName + | SignaturesCabal2 + | AutogenNotExposed + | AutogenIncludesNotIncluded + | NoMainIs UnqualComponentName + | NoHsLhsMain + | MainCCabal1_18 + | AutogenNoOther CEType + | AutogenIncludesNotIncludedExe + | TestsuiteTypeNotKnown TestType + | TestsuiteNotSupported TestType + | BenchmarkTypeNotKnown BenchmarkType + | BenchmarkNotSupported BenchmarkType + | NoHsLhsMainBench + | InvalidNameWin PackageName + | ZPrefix + | NoBuildType + | NoCustomSetup + | UnknownCompilers [String] + | UnknownLanguages [String] + | UnknownExtensions [String] + | LanguagesAsExtension [String] + | DeprecatedExtensions [(Extension, Maybe Extension)] + | MissingFieldCategory + | MissingFieldMaintainer + | MissingFieldSynopsis + | MissingFieldDescription + | MissingFieldSynOrDesc + | SynopsisTooLong + | ShortDesc + | InvalidTestWith [Dependency] + | ImpossibleInternalDep [Dependency] + | ImpossibleInternalExe [ExeDependency] + | MissingInternalExe [ExeDependency] + | NONELicense + | NoLicense + | AllRightsReservedLicense + | LicenseMessParse License + | UnrecognisedLicense String + | UncommonBSD4 + | UnknownLicenseVersion License [Version] + | NoLicenseFile + | UnrecognisedSourceRepo String + | MissingType + | MissingLocation + | MissingModule + | MissingTag + | SubdirRelPath + | SubdirGoodRelPath String + | OptFasm String + | OptHpc String + | OptProf String + | OptO String + | OptHide String + | OptMake String + | OptONot String + | OptOOne String + | OptOTwo String + | OptSplitSections String + | OptSplitObjs String + | OptWls String + | OptExts String + | OptRts String + | OptWithRts String + | COptONumber String WarnLang + | COptCPP String + | OptAlternatives String String [(String, String)] + | RelativeOutside String FilePath + | AbsolutePath String FilePath + | BadRelativePath String FilePath String + | DistPoint (Maybe String) FilePath + | GlobSyntaxError String String + | RecursiveGlobInRoot String FilePath + | InvalidOnWin [FilePath] + | FilePathTooLong FilePath + | FilePathNameTooLong FilePath + | FilePathSplitTooLong FilePath + | FilePathEmpty + | CVTestSuite + | CVDefaultLanguage + | CVDefaultLanguageComponent + | CVDefaultLanguageComponentSoft + | CVExtraDocFiles + | CVMultiLib + | CVReexported + | CVMixins + | CVExtraFrameworkDirs + | CVDefaultExtensions + | CVExtensionsDeprecated + | CVSources + | CVExtraDynamic [[String]] + | CVVirtualModules + | CVSourceRepository + | CVExtensions CabalSpecVersion [Extension] + | CVCustomSetup + | CVExpliticDepsCustomSetup + | CVAutogenPaths + | CVAutogenPackageInfo + | CVAutogenPackageInfoGuard + | GlobNoMatch String String + | GlobExactMatch String String FilePath + | GlobNoDir String String FilePath + | UnknownOS [String] + | UnknownArch [String] + | UnknownCompiler [String] + | BaseNoUpperBounds + | MissingUpperBounds CEType [String] + | SuspiciousFlagName [String] + | DeclaredUsedFlags (Set.Set FlagName) (Set.Set FlagName) + | NonASCIICustomField [String] + | RebindableClashPaths + | RebindableClashPackageInfo + | WErrorUnneeded String + | JUnneeded String + | FDeferTypeErrorsUnneeded String + | DynamicUnneeded String + | ProfilingUnneeded String + | UpperBoundSetup String + | DuplicateModule String [ModuleName] + | PotentialDupModule String [ModuleName] + | BOMStart FilePath + | NotPackageName FilePath String + | NoDesc + | MultiDesc [String] + | UnknownFile String (SymbolicPath PackageDir LicenseFile) + | MissingSetupFile + | MissingConfigureScript + | UnknownDirectory String FilePath + | MissingSourceControl + | MissingExpectedDocFiles Bool [FilePath] + | WrongFieldForExpectedDocFiles Bool String [FilePath] + deriving (Eq, Ord, Show) + +-- TODO Some checks have a constructor in list form +-- (e.g. `SomeWarn [n]`), CheckM m () correctly catches warnings in +-- different stanzas in different checks (so it is not one soup). +-- +-- Ideally [SomeWar [a], SomeWar [b]] would be translated into +-- SomeWar [a,b] in the few cases where it is appropriate for UX +-- and left separated otherwise. +-- To achieve this the Writer part of CheckM could be modified +-- to be a ad hoc monoid. + +-- Convenience. +extractCheckExplantion :: PackageCheck -> CheckExplanation +extractCheckExplantion (PackageBuildImpossible e) = e +extractCheckExplantion (PackageBuildWarning e) = e +extractCheckExplantion (PackageDistSuspicious e) = e +extractCheckExplantion (PackageDistSuspiciousWarn e) = e +extractCheckExplantion (PackageDistInexcusable e) = e + +-- | Identifier for the speficic 'CheckExplanation'. This ensures `--ignore` +-- can output a warning on unrecognised values. +-- ☞ N.B.: should be kept in sync with 'CheckExplanation'. +data CheckExplanationID + = CIParseWarning + | CINoNameField + | CINoVersionField + | CINoTarget + | CIUnnamedInternal + | CIDuplicateSections + | CIIllegalLibraryName + | CINoModulesExposed + | CISignaturesCabal2 + | CIAutogenNotExposed + | CIAutogenIncludesNotIncluded + | CINoMainIs + | CINoHsLhsMain + | CIMainCCabal1_18 + | CIAutogenNoOther + | CIAutogenIncludesNotIncludedExe + | CITestsuiteTypeNotKnown + | CITestsuiteNotSupported + | CIBenchmarkTypeNotKnown + | CIBenchmarkNotSupported + | CINoHsLhsMainBench + | CIInvalidNameWin + | CIZPrefix + | CINoBuildType + | CINoCustomSetup + | CIUnknownCompilers + | CIUnknownLanguages + | CIUnknownExtensions + | CILanguagesAsExtension + | CIDeprecatedExtensions + | CIMissingFieldCategory + | CIMissingFieldMaintainer + | CIMissingFieldSynopsis + | CIMissingFieldDescription + | CIMissingFieldSynOrDesc + | CISynopsisTooLong + | CIShortDesc + | CIInvalidTestWith + | CIImpossibleInternalDep + | CIImpossibleInternalExe + | CIMissingInternalExe + | CINONELicense + | CINoLicense + | CIAllRightsReservedLicense + | CILicenseMessParse + | CIUnrecognisedLicense + | CIUncommonBSD4 + | CIUnknownLicenseVersion + | CINoLicenseFile + | CIUnrecognisedSourceRepo + | CIMissingType + | CIMissingLocation + | CIMissingModule + | CIMissingTag + | CISubdirRelPath + | CISubdirGoodRelPath + | CIOptFasm + | CIOptHpc + | CIOptProf + | CIOptO + | CIOptHide + | CIOptMake + | CIOptONot + | CIOptOOne + | CIOptOTwo + | CIOptSplitSections + | CIOptSplitObjs + | CIOptWls + | CIOptExts + | CIOptRts + | CIOptWithRts + | CICOptONumber + | CICOptCPP + | CIOptAlternatives + | CIRelativeOutside + | CIAbsolutePath + | CIBadRelativePath + | CIDistPoint + | CIGlobSyntaxError + | CIRecursiveGlobInRoot + | CIInvalidOnWin + | CIFilePathTooLong + | CIFilePathNameTooLong + | CIFilePathSplitTooLong + | CIFilePathEmpty + | CICVTestSuite + | CICVDefaultLanguage + | CICVDefaultLanguageComponent + | CICVDefaultLanguageComponentSoft + | CICVExtraDocFiles + | CICVMultiLib + | CICVReexported + | CICVMixins + | CICVExtraFrameworkDirs + | CICVDefaultExtensions + | CICVExtensionsDeprecated + | CICVSources + | CICVExtraDynamic + | CICVVirtualModules + | CICVSourceRepository + | CICVExtensions + | CICVCustomSetup + | CICVExpliticDepsCustomSetup + | CICVAutogenPaths + | CICVAutogenPackageInfo + | CICVAutogenPackageInfoGuard + | CIGlobNoMatch + | CIGlobExactMatch + | CIGlobNoDir + | CIUnknownOS + | CIUnknownArch + | CIUnknownCompiler + | CIBaseNoUpperBounds + | CIMissingUpperBounds + | CISuspiciousFlagName + | CIDeclaredUsedFlags + | CINonASCIICustomField + | CIRebindableClashPaths + | CIRebindableClashPackageInfo + | CIWErrorUnneeded + | CIJUnneeded + | CIFDeferTypeErrorsUnneeded + | CIDynamicUnneeded + | CIProfilingUnneeded + | CIUpperBoundSetup + | CIDuplicateModule + | CIPotentialDupModule + | CIBOMStart + | CINotPackageName + | CINoDesc + | CIMultiDesc + | CIUnknownFile + | CIMissingSetupFile + | CIMissingConfigureScript + | CIUnknownDirectory + | CIMissingSourceControl + | CIMissingExpectedDocFiles + | CIWrongFieldForExpectedDocFiles + deriving (Eq, Ord, Show, Enum, Bounded) + +checkExplanationId :: CheckExplanation -> CheckExplanationID +checkExplanationId (ParseWarning{}) = CIParseWarning +checkExplanationId (NoNameField{}) = CINoNameField +checkExplanationId (NoVersionField{}) = CINoVersionField +checkExplanationId (NoTarget{}) = CINoTarget +checkExplanationId (UnnamedInternal{}) = CIUnnamedInternal +checkExplanationId (DuplicateSections{}) = CIDuplicateSections +checkExplanationId (IllegalLibraryName{}) = CIIllegalLibraryName +checkExplanationId (NoModulesExposed{}) = CINoModulesExposed +checkExplanationId (SignaturesCabal2{}) = CISignaturesCabal2 +checkExplanationId (AutogenNotExposed{}) = CIAutogenNotExposed +checkExplanationId (AutogenIncludesNotIncluded{}) = CIAutogenIncludesNotIncluded +checkExplanationId (NoMainIs{}) = CINoMainIs +checkExplanationId (NoHsLhsMain{}) = CINoHsLhsMain +checkExplanationId (MainCCabal1_18{}) = CIMainCCabal1_18 +checkExplanationId (AutogenNoOther{}) = CIAutogenNoOther +checkExplanationId (AutogenIncludesNotIncludedExe{}) = CIAutogenIncludesNotIncludedExe +checkExplanationId (TestsuiteTypeNotKnown{}) = CITestsuiteTypeNotKnown +checkExplanationId (TestsuiteNotSupported{}) = CITestsuiteNotSupported +checkExplanationId (BenchmarkTypeNotKnown{}) = CIBenchmarkTypeNotKnown +checkExplanationId (BenchmarkNotSupported{}) = CIBenchmarkNotSupported +checkExplanationId (NoHsLhsMainBench{}) = CINoHsLhsMainBench +checkExplanationId (InvalidNameWin{}) = CIInvalidNameWin +checkExplanationId (ZPrefix{}) = CIZPrefix +checkExplanationId (NoBuildType{}) = CINoBuildType +checkExplanationId (NoCustomSetup{}) = CINoCustomSetup +checkExplanationId (UnknownCompilers{}) = CIUnknownCompilers +checkExplanationId (UnknownLanguages{}) = CIUnknownLanguages +checkExplanationId (UnknownExtensions{}) = CIUnknownExtensions +checkExplanationId (LanguagesAsExtension{}) = CILanguagesAsExtension +checkExplanationId (DeprecatedExtensions{}) = CIDeprecatedExtensions +checkExplanationId (MissingFieldCategory{}) = CIMissingFieldCategory +checkExplanationId (MissingFieldMaintainer{}) = CIMissingFieldMaintainer +checkExplanationId (MissingFieldSynopsis{}) = CIMissingFieldSynopsis +checkExplanationId (MissingFieldDescription{}) = CIMissingFieldDescription +checkExplanationId (MissingFieldSynOrDesc{}) = CIMissingFieldSynOrDesc +checkExplanationId (SynopsisTooLong{}) = CISynopsisTooLong +checkExplanationId (ShortDesc{}) = CIShortDesc +checkExplanationId (InvalidTestWith{}) = CIInvalidTestWith +checkExplanationId (ImpossibleInternalDep{}) = CIImpossibleInternalDep +checkExplanationId (ImpossibleInternalExe{}) = CIImpossibleInternalExe +checkExplanationId (MissingInternalExe{}) = CIMissingInternalExe +checkExplanationId (NONELicense{}) = CINONELicense +checkExplanationId (NoLicense{}) = CINoLicense +checkExplanationId (AllRightsReservedLicense{}) = CIAllRightsReservedLicense +checkExplanationId (LicenseMessParse{}) = CILicenseMessParse +checkExplanationId (UnrecognisedLicense{}) = CIUnrecognisedLicense +checkExplanationId (UncommonBSD4{}) = CIUncommonBSD4 +checkExplanationId (UnknownLicenseVersion{}) = CIUnknownLicenseVersion +checkExplanationId (NoLicenseFile{}) = CINoLicenseFile +checkExplanationId (UnrecognisedSourceRepo{}) = CIUnrecognisedSourceRepo +checkExplanationId (MissingType{}) = CIMissingType +checkExplanationId (MissingLocation{}) = CIMissingLocation +checkExplanationId (MissingModule{}) = CIMissingModule +checkExplanationId (MissingTag{}) = CIMissingTag +checkExplanationId (SubdirRelPath{}) = CISubdirRelPath +checkExplanationId (SubdirGoodRelPath{}) = CISubdirGoodRelPath +checkExplanationId (OptFasm{}) = CIOptFasm +checkExplanationId (OptHpc{}) = CIOptHpc +checkExplanationId (OptProf{}) = CIOptProf +checkExplanationId (OptO{}) = CIOptO +checkExplanationId (OptHide{}) = CIOptHide +checkExplanationId (OptMake{}) = CIOptMake +checkExplanationId (OptONot{}) = CIOptONot +checkExplanationId (OptOOne{}) = CIOptOOne +checkExplanationId (OptOTwo{}) = CIOptOTwo +checkExplanationId (OptSplitSections{}) = CIOptSplitSections +checkExplanationId (OptSplitObjs{}) = CIOptSplitObjs +checkExplanationId (OptWls{}) = CIOptWls +checkExplanationId (OptExts{}) = CIOptExts +checkExplanationId (OptRts{}) = CIOptRts +checkExplanationId (OptWithRts{}) = CIOptWithRts +checkExplanationId (COptONumber{}) = CICOptONumber +checkExplanationId (COptCPP{}) = CICOptCPP +checkExplanationId (OptAlternatives{}) = CIOptAlternatives +checkExplanationId (RelativeOutside{}) = CIRelativeOutside +checkExplanationId (AbsolutePath{}) = CIAbsolutePath +checkExplanationId (BadRelativePath{}) = CIBadRelativePath +checkExplanationId (DistPoint{}) = CIDistPoint +checkExplanationId (GlobSyntaxError{}) = CIGlobSyntaxError +checkExplanationId (RecursiveGlobInRoot{}) = CIRecursiveGlobInRoot +checkExplanationId (InvalidOnWin{}) = CIInvalidOnWin +checkExplanationId (FilePathTooLong{}) = CIFilePathTooLong +checkExplanationId (FilePathNameTooLong{}) = CIFilePathNameTooLong +checkExplanationId (FilePathSplitTooLong{}) = CIFilePathSplitTooLong +checkExplanationId (FilePathEmpty{}) = CIFilePathEmpty +checkExplanationId (CVTestSuite{}) = CICVTestSuite +checkExplanationId (CVDefaultLanguage{}) = CICVDefaultLanguage +checkExplanationId (CVDefaultLanguageComponent{}) = CICVDefaultLanguageComponent +checkExplanationId (CVDefaultLanguageComponentSoft{}) = CICVDefaultLanguageComponentSoft +checkExplanationId (CVExtraDocFiles{}) = CICVExtraDocFiles +checkExplanationId (CVMultiLib{}) = CICVMultiLib +checkExplanationId (CVReexported{}) = CICVReexported +checkExplanationId (CVMixins{}) = CICVMixins +checkExplanationId (CVExtraFrameworkDirs{}) = CICVExtraFrameworkDirs +checkExplanationId (CVDefaultExtensions{}) = CICVDefaultExtensions +checkExplanationId (CVExtensionsDeprecated{}) = CICVExtensionsDeprecated +checkExplanationId (CVSources{}) = CICVSources +checkExplanationId (CVExtraDynamic{}) = CICVExtraDynamic +checkExplanationId (CVVirtualModules{}) = CICVVirtualModules +checkExplanationId (CVSourceRepository{}) = CICVSourceRepository +checkExplanationId (CVExtensions{}) = CICVExtensions +checkExplanationId (CVCustomSetup{}) = CICVCustomSetup +checkExplanationId (CVExpliticDepsCustomSetup{}) = CICVExpliticDepsCustomSetup +checkExplanationId (CVAutogenPaths{}) = CICVAutogenPaths +checkExplanationId (CVAutogenPackageInfo{}) = CICVAutogenPackageInfo +checkExplanationId (CVAutogenPackageInfoGuard{}) = CICVAutogenPackageInfoGuard +checkExplanationId (GlobNoMatch{}) = CIGlobNoMatch +checkExplanationId (GlobExactMatch{}) = CIGlobExactMatch +checkExplanationId (GlobNoDir{}) = CIGlobNoDir +checkExplanationId (UnknownOS{}) = CIUnknownOS +checkExplanationId (UnknownArch{}) = CIUnknownArch +checkExplanationId (UnknownCompiler{}) = CIUnknownCompiler +checkExplanationId (BaseNoUpperBounds{}) = CIBaseNoUpperBounds +checkExplanationId (MissingUpperBounds{}) = CIMissingUpperBounds +checkExplanationId (SuspiciousFlagName{}) = CISuspiciousFlagName +checkExplanationId (DeclaredUsedFlags{}) = CIDeclaredUsedFlags +checkExplanationId (NonASCIICustomField{}) = CINonASCIICustomField +checkExplanationId (RebindableClashPaths{}) = CIRebindableClashPaths +checkExplanationId (RebindableClashPackageInfo{}) = CIRebindableClashPackageInfo +checkExplanationId (WErrorUnneeded{}) = CIWErrorUnneeded +checkExplanationId (JUnneeded{}) = CIJUnneeded +checkExplanationId (FDeferTypeErrorsUnneeded{}) = CIFDeferTypeErrorsUnneeded +checkExplanationId (DynamicUnneeded{}) = CIDynamicUnneeded +checkExplanationId (ProfilingUnneeded{}) = CIProfilingUnneeded +checkExplanationId (UpperBoundSetup{}) = CIUpperBoundSetup +checkExplanationId (DuplicateModule{}) = CIDuplicateModule +checkExplanationId (PotentialDupModule{}) = CIPotentialDupModule +checkExplanationId (BOMStart{}) = CIBOMStart +checkExplanationId (NotPackageName{}) = CINotPackageName +checkExplanationId (NoDesc{}) = CINoDesc +checkExplanationId (MultiDesc{}) = CIMultiDesc +checkExplanationId (UnknownFile{}) = CIUnknownFile +checkExplanationId (MissingSetupFile{}) = CIMissingSetupFile +checkExplanationId (MissingConfigureScript{}) = CIMissingConfigureScript +checkExplanationId (UnknownDirectory{}) = CIUnknownDirectory +checkExplanationId (MissingSourceControl{}) = CIMissingSourceControl +checkExplanationId (MissingExpectedDocFiles{}) = CIMissingExpectedDocFiles +checkExplanationId (WrongFieldForExpectedDocFiles{}) = CIWrongFieldForExpectedDocFiles + +type CheckExplanationIDString = String + +-- A one-word identifier for each CheckExplanation +-- +-- ☞ N.B: if you modify anything here, remeber to change the documentation +-- in @doc/cabal-commands.rst@! +ppCheckExplanationId :: CheckExplanationID -> CheckExplanationIDString +ppCheckExplanationId CIParseWarning = "parser-warning" +ppCheckExplanationId CINoNameField = "no-name-field" +ppCheckExplanationId CINoVersionField = "no-version-field" +ppCheckExplanationId CINoTarget = "no-target" +ppCheckExplanationId CIUnnamedInternal = "unnamed-internal-library" +ppCheckExplanationId CIDuplicateSections = "duplicate-sections" +ppCheckExplanationId CIIllegalLibraryName = "illegal-library-name" +ppCheckExplanationId CINoModulesExposed = "no-modules-exposed" +ppCheckExplanationId CISignaturesCabal2 = "signatures" +ppCheckExplanationId CIAutogenNotExposed = "autogen-not-exposed" +ppCheckExplanationId CIAutogenIncludesNotIncluded = "autogen-not-included" +ppCheckExplanationId CINoMainIs = "no-main-is" +ppCheckExplanationId CINoHsLhsMain = "unknown-extension-main" +ppCheckExplanationId CIMainCCabal1_18 = "c-like-main" +ppCheckExplanationId CIAutogenNoOther = "autogen-other-modules" +ppCheckExplanationId CIAutogenIncludesNotIncludedExe = "autogen-exe" +ppCheckExplanationId CITestsuiteTypeNotKnown = "unknown-testsuite-type" +ppCheckExplanationId CITestsuiteNotSupported = "unsupported-testsuite" +ppCheckExplanationId CIBenchmarkTypeNotKnown = "unknown-bench" +ppCheckExplanationId CIBenchmarkNotSupported = "unsupported-bench" +ppCheckExplanationId CINoHsLhsMainBench = "bench-unknown-extension" +ppCheckExplanationId CIInvalidNameWin = "invalid-name-win" +ppCheckExplanationId CIZPrefix = "reserved-z-prefix" +ppCheckExplanationId CINoBuildType = "no-build-type" +ppCheckExplanationId CINoCustomSetup = "undeclared-custom-setup" +ppCheckExplanationId CIUnknownCompilers = "unknown-compiler-tested" +ppCheckExplanationId CIUnknownLanguages = "unknown-languages" +ppCheckExplanationId CIUnknownExtensions = "unknown-extension" +ppCheckExplanationId CILanguagesAsExtension = "languages-as-extensions" +ppCheckExplanationId CIDeprecatedExtensions = "deprecated-extensions" +ppCheckExplanationId CIMissingFieldCategory = "no-category" +ppCheckExplanationId CIMissingFieldMaintainer = "no-maintainer" +ppCheckExplanationId CIMissingFieldSynopsis = "no-synopsis" +ppCheckExplanationId CIMissingFieldDescription = "no-description" +ppCheckExplanationId CIMissingFieldSynOrDesc = "no-syn-desc" +ppCheckExplanationId CISynopsisTooLong = "long-synopsis" +ppCheckExplanationId CIShortDesc = "short-description" +ppCheckExplanationId CIInvalidTestWith = "invalid-range-tested" +ppCheckExplanationId CIImpossibleInternalDep = "impossible-dep" +ppCheckExplanationId CIImpossibleInternalExe = "impossible-dep-exe" +ppCheckExplanationId CIMissingInternalExe = "no-internal-exe" +ppCheckExplanationId CINONELicense = "license-none" +ppCheckExplanationId CINoLicense = "no-license" +ppCheckExplanationId CIAllRightsReservedLicense = "all-rights-reserved" +ppCheckExplanationId CILicenseMessParse = "license-parse" +ppCheckExplanationId CIUnrecognisedLicense = "unknown-license" +ppCheckExplanationId CIUncommonBSD4 = "bsd4-license" +ppCheckExplanationId CIUnknownLicenseVersion = "unknown-license-version" +ppCheckExplanationId CINoLicenseFile = "no-license-file" +ppCheckExplanationId CIUnrecognisedSourceRepo = "unrecognised-repo-type" +ppCheckExplanationId CIMissingType = "repo-no-type" +ppCheckExplanationId CIMissingLocation = "repo-no-location" +ppCheckExplanationId CIMissingModule = "repo-no-module" +ppCheckExplanationId CIMissingTag = "repo-no-tag" +ppCheckExplanationId CISubdirRelPath = "repo-relative-dir" +ppCheckExplanationId CISubdirGoodRelPath = "repo-malformed-subdir" +ppCheckExplanationId CIOptFasm = "option-fasm" +ppCheckExplanationId CIOptHpc = "option-fhpc" +ppCheckExplanationId CIOptProf = "option-prof" +ppCheckExplanationId CIOptO = "option-o" +ppCheckExplanationId CIOptHide = "option-hide-package" +ppCheckExplanationId CIOptMake = "option-make" +ppCheckExplanationId CIOptONot = "option-optimize" +ppCheckExplanationId CIOptOOne = "option-o1" +ppCheckExplanationId CIOptOTwo = "option-o2" +ppCheckExplanationId CIOptSplitSections = "option-split-section" +ppCheckExplanationId CIOptSplitObjs = "option-split-objs" +ppCheckExplanationId CIOptWls = "option-optl-wl" +ppCheckExplanationId CIOptExts = "use-extension" +ppCheckExplanationId CIOptRts = "option-rtsopts" +ppCheckExplanationId CIOptWithRts = "option-with-rtsopts" +ppCheckExplanationId CICOptONumber = "option-opt-c" +ppCheckExplanationId CICOptCPP = "cpp-options" +ppCheckExplanationId CIOptAlternatives = "misplaced-c-opt" +ppCheckExplanationId CIRelativeOutside = "relative-path-outside" +ppCheckExplanationId CIAbsolutePath = "absolute-path" +ppCheckExplanationId CIBadRelativePath = "malformed-relative-path" +ppCheckExplanationId CIDistPoint = "unreliable-dist-path" +ppCheckExplanationId CIGlobSyntaxError = "glob-syntax-error" +ppCheckExplanationId CIRecursiveGlobInRoot = "recursive-glob" +ppCheckExplanationId CIInvalidOnWin = "invalid-path-win" +ppCheckExplanationId CIFilePathTooLong = "long-path" +ppCheckExplanationId CIFilePathNameTooLong = "long-name" +ppCheckExplanationId CIFilePathSplitTooLong = "name-not-portable" +ppCheckExplanationId CIFilePathEmpty = "empty-path" +ppCheckExplanationId CICVTestSuite = "test-cabal-ver" +ppCheckExplanationId CICVDefaultLanguage = "default-language" +ppCheckExplanationId CICVDefaultLanguageComponent = "no-default-language" +ppCheckExplanationId CICVDefaultLanguageComponentSoft = "add-language" +ppCheckExplanationId CICVExtraDocFiles = "extra-doc-files" +ppCheckExplanationId CICVMultiLib = "multilib" +ppCheckExplanationId CICVReexported = "reexported-modules" +ppCheckExplanationId CICVMixins = "mixins" +ppCheckExplanationId CICVExtraFrameworkDirs = "extra-framework-dirs" +ppCheckExplanationId CICVDefaultExtensions = "default-extensions" +ppCheckExplanationId CICVExtensionsDeprecated = "extensions-field" +ppCheckExplanationId CICVSources = "unsupported-sources" +ppCheckExplanationId CICVExtraDynamic = "extra-dynamic" +ppCheckExplanationId CICVVirtualModules = "virtual-modules" +ppCheckExplanationId CICVSourceRepository = "source-repository" +ppCheckExplanationId CICVExtensions = "incompatible-extension" +ppCheckExplanationId CICVCustomSetup = "no-setup-depends" +ppCheckExplanationId CICVExpliticDepsCustomSetup = "dependencies-setup" +ppCheckExplanationId CICVAutogenPaths = "no-autogen-paths" +ppCheckExplanationId CICVAutogenPackageInfo = "no-autogen-pinfo" +ppCheckExplanationId CICVAutogenPackageInfoGuard = "autogen-guard" +ppCheckExplanationId CIGlobNoMatch = "no-glob-match" +ppCheckExplanationId CIGlobExactMatch = "glob-no-extension" +ppCheckExplanationId CIGlobNoDir = "glob-missing-dir" +ppCheckExplanationId CIUnknownOS = "unknown-os" +ppCheckExplanationId CIUnknownArch = "unknown-arch" +ppCheckExplanationId CIUnknownCompiler = "unknown-compiler" +ppCheckExplanationId CIBaseNoUpperBounds = "missing-bounds-important" +ppCheckExplanationId CIMissingUpperBounds = "missing-upper-bounds" +ppCheckExplanationId CISuspiciousFlagName = "suspicious-flag" +ppCheckExplanationId CIDeclaredUsedFlags = "unused-flag" +ppCheckExplanationId CINonASCIICustomField = "non-ascii" +ppCheckExplanationId CIRebindableClashPaths = "rebindable-clash-paths" +ppCheckExplanationId CIRebindableClashPackageInfo = "rebindable-clash-info" +ppCheckExplanationId CIWErrorUnneeded = "werror" +ppCheckExplanationId CIJUnneeded = "unneeded-j" +ppCheckExplanationId CIFDeferTypeErrorsUnneeded = "fdefer-type-errors" +ppCheckExplanationId CIDynamicUnneeded = "debug-flag" +ppCheckExplanationId CIProfilingUnneeded = "fprof-flag" +ppCheckExplanationId CIUpperBoundSetup = "missing-bounds-setup" +ppCheckExplanationId CIDuplicateModule = "duplicate-modules" +ppCheckExplanationId CIPotentialDupModule = "maybe-duplicate-modules" +ppCheckExplanationId CIBOMStart = "bom" +ppCheckExplanationId CINotPackageName = "name-no-match" +ppCheckExplanationId CINoDesc = "no-cabal-file" +ppCheckExplanationId CIMultiDesc = "multiple-cabal-file" +ppCheckExplanationId CIUnknownFile = "unknown-file" +ppCheckExplanationId CIMissingSetupFile = "missing-setup" +ppCheckExplanationId CIMissingConfigureScript = "missing-conf-script" +ppCheckExplanationId CIUnknownDirectory = "unknown-directory" +ppCheckExplanationId CIMissingSourceControl = "no-repository" +ppCheckExplanationId CIMissingExpectedDocFiles = "no-docs" +ppCheckExplanationId CIWrongFieldForExpectedDocFiles = "doc-place" + +-- String: the unrecognised 'CheckExplanationIDString' itself. +readExplanationID + :: CheckExplanationIDString + -> Either String CheckExplanationID +readExplanationID s = maybe (Left s) Right (lookup s idsDict) + where + idsDict :: [(CheckExplanationIDString, CheckExplanationID)] + idsDict = map (\i -> (ppCheckExplanationId i, i)) [minBound .. maxBound] + +-- | Which stanza does `CheckExplanation` refer to? +data CEType + = CETLibrary LibraryName + | CETForeignLibrary UnqualComponentName + | CETExecutable UnqualComponentName + | CETTest UnqualComponentName + | CETBenchmark UnqualComponentName + | CETSetup + deriving (Eq, Ord, Show) + +-- | Pretty printing `CEType`. +ppCET :: CEType -> String +ppCET cet = case cet of + CETLibrary ln -> showLibraryName ln + CETForeignLibrary n -> "foreign library" ++ qn n + CETExecutable n -> "executable" ++ qn n + CETTest n -> "test suite" ++ qn n + CETBenchmark n -> "benchmark" ++ qn n + CETSetup -> "custom-setup" + where + qn :: UnqualComponentName -> String + qn wn = (" " ++) . quote . prettyShow $ wn + +-- | Which language are we referring to in our warning message? +data WarnLang = LangC | LangCPlusPlus + deriving (Eq, Ord, Show) + +-- | Pretty printing `WarnLang`. +ppWarnLang :: WarnLang -> String +ppWarnLang LangC = "C" +ppWarnLang LangCPlusPlus = "C++" + +-- | Pretty printing `CheckExplanation`. +ppExplanation :: CheckExplanation -> String +ppExplanation (ParseWarning fp pp) = showPWarning fp pp +ppExplanation NoNameField = "No 'name' field." +ppExplanation NoVersionField = "No 'version' field." +ppExplanation NoTarget = + "No executables, libraries, tests, or benchmarks found. Nothing to do." +ppExplanation UnnamedInternal = + "Found one or more unnamed internal libraries. Only the non-internal" + ++ " library can have the same name as the package." +ppExplanation (DuplicateSections duplicateNames) = + "Duplicate sections: " + ++ commaSep (map unUnqualComponentName duplicateNames) + ++ ". The name of every library, executable, test suite," + ++ " and benchmark section in the package must be unique." +ppExplanation (IllegalLibraryName pname) = + "Illegal internal library name " + ++ prettyShow pname + ++ ". Internal libraries cannot have the same name as the package." + ++ " Maybe you wanted a non-internal library?" + ++ " If so, rewrite the section stanza" + ++ " from 'library: '" + ++ prettyShow pname + ++ "' to 'library'." +ppExplanation (NoModulesExposed lName) = + showLibraryName lName ++ " does not expose any modules" +ppExplanation SignaturesCabal2 = + "To use the 'signatures' field the package needs to specify " + ++ "at least 'cabal-version: 2.0'." +ppExplanation AutogenNotExposed = + "An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'." +ppExplanation AutogenIncludesNotIncluded = + "An include in 'autogen-includes' is neither in 'includes' nor " + ++ "'install-includes'." +ppExplanation (NoMainIs eName) = + "No 'main-is' field found for executable " ++ prettyShow eName +ppExplanation NoHsLhsMain = + "The 'main-is' field must specify a '.hs' or '.lhs' file " + ++ "(even if it is generated by a preprocessor), " + ++ "or it may specify a C/C++/obj-C source file." +ppExplanation MainCCabal1_18 = + "The package uses a C/C++/obj-C source file for the 'main-is' field. " + ++ "To use this feature you need to specify 'cabal-version: 1.18' or" + ++ " higher." +ppExplanation (AutogenNoOther ct) = + "On " + ++ ppCET ct + ++ " an 'autogen-module'" + ++ " is not on 'other-modules'" +ppExplanation AutogenIncludesNotIncludedExe = + "An include in 'autogen-includes' is not in 'includes'." +ppExplanation (TestsuiteTypeNotKnown tt) = + quote (prettyShow tt) + ++ " is not a known type of test suite. " + ++ "Either remove the 'type' field or use a known type. " + ++ "The known test suite types are: " + ++ commaSep (map prettyShow knownTestTypes) +ppExplanation (TestsuiteNotSupported tt) = + quote (prettyShow tt) + ++ " is not a supported test suite version. " + ++ "Either remove the 'type' field or use a known type. " + ++ "The known test suite types are: " + ++ commaSep (map prettyShow knownTestTypes) +ppExplanation (BenchmarkTypeNotKnown tt) = + quote (prettyShow tt) + ++ " is not a known type of benchmark. " + ++ "Either remove the 'type' field or use a known type. " + ++ "The known benchmark types are: " + ++ commaSep (map prettyShow knownBenchmarkTypes) +ppExplanation (BenchmarkNotSupported tt) = + quote (prettyShow tt) + ++ " is not a supported benchmark version. " + ++ "Either remove the 'type' field or use a known type. " + ++ "The known benchmark types are: " + ++ commaSep (map prettyShow knownBenchmarkTypes) +ppExplanation NoHsLhsMainBench = + "The 'main-is' field must specify a '.hs' or '.lhs' file " + ++ "(even if it is generated by a preprocessor)." +ppExplanation (InvalidNameWin pkg) = + "The package name '" + ++ prettyShow pkg + ++ "' is " + ++ "invalid on Windows. Many tools need to convert package names to " + ++ "file names, so using this name would cause problems." +ppExplanation ZPrefix = + "Package names with the prefix 'z-' are reserved by Cabal and " + ++ "cannot be used." +ppExplanation NoBuildType = + "No 'build-type' specified. If you do not need a custom Setup.hs or " + ++ "./configure script then use 'build-type: Simple'." +ppExplanation NoCustomSetup = + "Ignoring the 'custom-setup' section because the 'build-type' is " + ++ "not 'Custom'. Use 'build-type: Custom' if you need to use a " + ++ "custom Setup.hs script." +ppExplanation (UnknownCompilers unknownCompilers) = + "Unknown compiler " + ++ commaSep (map quote unknownCompilers) + ++ " in 'tested-with' field." +ppExplanation (UnknownLanguages unknownLanguages) = + "Unknown languages: " ++ commaSep unknownLanguages +ppExplanation (UnknownExtensions unknownExtensions) = + "Unknown extensions: " ++ commaSep unknownExtensions +ppExplanation (LanguagesAsExtension languagesUsedAsExtensions) = + "Languages listed as extensions: " + ++ commaSep languagesUsedAsExtensions + ++ ". Languages must be specified in either the 'default-language' " + ++ " or the 'other-languages' field." +ppExplanation (DeprecatedExtensions ourDeprecatedExtensions) = + "Deprecated extensions: " + ++ commaSep (map (quote . prettyShow . fst) ourDeprecatedExtensions) + ++ ". " + ++ unwords + [ "Instead of '" + ++ prettyShow ext + ++ "' use '" + ++ prettyShow replacement + ++ "'." + | (ext, Just replacement) <- ourDeprecatedExtensions + ] +ppExplanation MissingFieldCategory = "No 'category' field." +ppExplanation MissingFieldMaintainer = "No 'maintainer' field." +ppExplanation MissingFieldSynopsis = "No 'synopsis' field." +ppExplanation MissingFieldDescription = "No 'description' field." +ppExplanation MissingFieldSynOrDesc = "No 'synopsis' or 'description' field." +ppExplanation SynopsisTooLong = + "The 'synopsis' field is rather long (max 80 chars is recommended)." +ppExplanation ShortDesc = + "The 'description' field should be longer than the 'synopsis' field. " + ++ "It's useful to provide an informative 'description' to allow " + ++ "Haskell programmers who have never heard about your package to " + ++ "understand the purpose of your package. " + ++ "The 'description' field content is typically shown by tooling " + ++ "(e.g. 'cabal info', Haddock, Hackage) below the 'synopsis' which " + ++ "serves as a headline. " + ++ "Please refer to for more details." +ppExplanation (InvalidTestWith testedWithImpossibleRanges) = + "Invalid 'tested-with' version range: " + ++ commaSep (map prettyShow testedWithImpossibleRanges) + ++ ". To indicate that you have tested a package with multiple " + ++ "different versions of the same compiler use multiple entries, " + ++ "for example 'tested-with: GHC==6.10.4, GHC==6.12.3' and not " + ++ "'tested-with: GHC==6.10.4 && ==6.12.3'." +ppExplanation (ImpossibleInternalDep depInternalLibWithImpossibleVersion) = + "The package has an impossible version range for a dependency on an " + ++ "internal library: " + ++ commaSep (map prettyShow depInternalLibWithImpossibleVersion) + ++ ". This version range does not include the current package, and must " + ++ "be removed as the current package's library will always be used." +ppExplanation (ImpossibleInternalExe depInternalExecWithImpossibleVersion) = + "The package has an impossible version range for a dependency on an " + ++ "internal executable: " + ++ commaSep (map prettyShow depInternalExecWithImpossibleVersion) + ++ ". This version range does not include the current package, and must " + ++ "be removed as the current package's executable will always be used." +ppExplanation (MissingInternalExe depInternalExeWithImpossibleVersion) = + "The package depends on a missing internal executable: " + ++ commaSep (map prettyShow depInternalExeWithImpossibleVersion) +ppExplanation NONELicense = "The 'license' field is missing or is NONE." +ppExplanation NoLicense = "The 'license' field is missing." +ppExplanation AllRightsReservedLicense = + "The 'license' is AllRightsReserved. Is that really what you want?" +ppExplanation (LicenseMessParse lic) = + "Unfortunately the license " + ++ quote (prettyShow lic) + ++ " messes up the parser in earlier Cabal versions so you need to " + ++ "specify 'cabal-version: >= 1.4'. Alternatively if you require " + ++ "compatibility with earlier Cabal versions then use 'OtherLicense'." +ppExplanation (UnrecognisedLicense l) = + quote ("license: " ++ l) + ++ " is not a recognised license. The " + ++ "known licenses are: " + ++ commaSep (map prettyShow knownLicenses) +ppExplanation UncommonBSD4 = + "Using 'license: BSD4' is almost always a misunderstanding. 'BSD4' " + ++ "refers to the old 4-clause BSD license with the advertising " + ++ "clause. 'BSD3' refers the new 3-clause BSD license." +ppExplanation (UnknownLicenseVersion lic known) = + "'license: " + ++ prettyShow lic + ++ "' is not a known " + ++ "version of that license. The known versions are " + ++ commaSep (map prettyShow known) + ++ ". If this is not a mistake and you think it should be a known " + ++ "version then please file a ticket." +ppExplanation NoLicenseFile = "A 'license-file' is not specified." +ppExplanation (UnrecognisedSourceRepo kind) = + quote kind + ++ " is not a recognised kind of source-repository. " + ++ "The repo kind is usually 'head' or 'this'" +ppExplanation MissingType = + "The source-repository 'type' is a required field." +ppExplanation MissingLocation = + "The source-repository 'location' is a required field." +ppExplanation MissingModule = + "For a CVS source-repository, the 'module' is a required field." +ppExplanation MissingTag = + "For the 'this' kind of source-repository, the 'tag' is a required " + ++ "field. It should specify the tag corresponding to this version " + ++ "or release of the package." +ppExplanation SubdirRelPath = + "The 'subdir' field of a source-repository must be a relative path." +ppExplanation (SubdirGoodRelPath err) = + "The 'subdir' field of a source-repository is not a good relative path: " + ++ show err +ppExplanation (OptFasm fieldName) = + "'" + ++ fieldName + ++ ": -fasm' is unnecessary and will not work on CPU " + ++ "architectures other than x86, x86-64, ppc or sparc." +ppExplanation (OptHpc fieldName) = + "'" + ++ fieldName + ++ ": -fhpc' is not necessary. Use the configure flag " + ++ " --enable-coverage instead." +ppExplanation (OptProf fieldName) = + "'" + ++ fieldName + ++ ": -prof' is not necessary and will lead to problems " + ++ "when used on a library. Use the configure flag " + ++ "--enable-library-profiling and/or --enable-profiling." +ppExplanation (OptO fieldName) = + "'" + ++ fieldName + ++ ": -o' is not needed. " + ++ "The output files are named automatically." +ppExplanation (OptHide fieldName) = + "'" + ++ fieldName + ++ ": -hide-package' is never needed. " + ++ "Cabal hides all packages." +ppExplanation (OptMake fieldName) = + "'" + ++ fieldName + ++ ": --make' is never needed. Cabal uses this automatically." +ppExplanation (OptONot fieldName) = + "'" + ++ fieldName + ++ ": -O0' is not needed. " + ++ "Use the --disable-optimization configure flag." +ppExplanation (OptOOne fieldName) = + "'" + ++ fieldName + ++ ": -O' is not needed. " + ++ "Cabal automatically adds the '-O' flag. " + ++ "Setting it yourself interferes with the --disable-optimization flag." +ppExplanation (OptOTwo fieldName) = + "'" + ++ fieldName + ++ ": -O2' is rarely needed. " + ++ "Check that it is giving a real benefit " + ++ "and not just imposing longer compile times on your users." +ppExplanation (OptSplitSections fieldName) = + "'" + ++ fieldName + ++ ": -split-sections' is not needed. " + ++ "Use the --enable-split-sections configure flag." +ppExplanation (OptSplitObjs fieldName) = + "'" + ++ fieldName + ++ ": -split-objs' is not needed. " + ++ "Use the --enable-split-objs configure flag." +ppExplanation (OptWls fieldName) = + "'" + ++ fieldName + ++ ": -optl-Wl,-s' is not needed and is not portable to" + ++ " all operating systems. Cabal 1.4 and later automatically strip" + ++ " executables. Cabal also has a flag --disable-executable-stripping" + ++ " which is necessary when building packages for some Linux" + ++ " distributions and using '-optl-Wl,-s' prevents that from working." +ppExplanation (OptExts fieldName) = + "Instead of '" + ++ fieldName + ++ ": -fglasgow-exts' it is preferable to use " + ++ "the 'extensions' field." +ppExplanation (OptRts fieldName) = + "'" + ++ fieldName + ++ ": -rtsopts' has no effect for libraries. It should " + ++ "only be used for executables." +ppExplanation (OptWithRts fieldName) = + "'" + ++ fieldName + ++ ": -with-rtsopts' has no effect for libraries. It " + ++ "should only be used for executables." +ppExplanation (COptONumber prefix label) = + "'" + ++ prefix + ++ ": -O[n]' is generally not needed. When building with " + ++ " optimisations Cabal automatically adds '-O2' for " + ++ ppWarnLang label + ++ " code. Setting it yourself interferes with the" + ++ " --disable-optimization flag." +ppExplanation (COptCPP opt) = + "'cpp-options: " ++ opt ++ "' is not a portable C-preprocessor flag." +ppExplanation (OptAlternatives badField goodField flags) = + "Instead of " + ++ quote (badField ++ ": " ++ unwords badFlags) + ++ " use " + ++ quote (goodField ++ ": " ++ unwords goodFlags) + where + (badFlags, goodFlags) = unzip flags +ppExplanation (RelativeOutside field path) = + quote (field ++ ": " ++ path) + ++ " is a relative path outside of the source tree. " + ++ "This will not work when generating a tarball with 'sdist'." +ppExplanation (AbsolutePath field path) = + quote (field ++ ": " ++ path) + ++ " specifies an absolute path, but the " + ++ quote field + ++ " field must use relative paths." +ppExplanation (BadRelativePath field path err) = + quote (field ++ ": " ++ path) + ++ " is not a good relative path: " + ++ show err +ppExplanation (DistPoint mfield path) = + incipit + ++ " points inside the 'dist' " + ++ "directory. This is not reliable because the location of this " + ++ "directory is configurable by the user (or package manager). In " + ++ "addition, the layout of the 'dist' directory is subject to change " + ++ "in future versions of Cabal." + where + -- mfiled Nothing -> the path is inside `ghc-options` + incipit = + maybe + ("'ghc-options' path " ++ quote path) + (\field -> quote (field ++ ": " ++ path)) + mfield +ppExplanation (GlobSyntaxError field expl) = + "In the '" ++ field ++ "' field: " ++ expl +ppExplanation (RecursiveGlobInRoot field glob) = + "In the '" + ++ field + ++ "': glob '" + ++ glob + ++ "' starts at project root directory, this might " + ++ "include `.git/`, ``dist-newstyle/``, or other large directories!" +ppExplanation (InvalidOnWin paths) = + "The " + ++ quotes paths + ++ " invalid on Windows, which " + ++ "would cause portability problems for this package. Windows file " + ++ "names cannot contain any of the characters \":*?<>|\" and there " + ++ "a few reserved names including \"aux\", \"nul\", \"con\", " + ++ "\"prn\", \"com1-9\", \"lpt1-9\" and \"clock$\"." + where + quotes [failed] = "path " ++ quote failed ++ " is" + quotes failed = + "paths " + ++ commaSep (map quote failed) + ++ " are" +ppExplanation (FilePathTooLong path) = + "The following file name is too long to store in a portable POSIX " + ++ "format tar archive. The maximum length is 255 ASCII characters.\n" + ++ "The file in question is:\n " + ++ path +ppExplanation (FilePathNameTooLong path) = + "The following file name is too long to store in a portable POSIX " + ++ "format tar archive. The maximum length for the name part (including " + ++ "extension) is 100 ASCII characters. The maximum length for any " + ++ "individual directory component is 155.\n" + ++ "The file in question is:\n " + ++ path +ppExplanation (FilePathSplitTooLong path) = + "The following file name is too long to store in a portable POSIX " + ++ "format tar archive. While the total length is less than 255 ASCII " + ++ "characters, there are unfortunately further restrictions. It has to " + ++ "be possible to split the file path on a directory separator into " + ++ "two parts such that the first part fits in 155 characters or less " + ++ "and the second part fits in 100 characters or less. Basically you " + ++ "have to make the file name or directory names shorter, or you could " + ++ "split a long directory name into nested subdirectories with shorter " + ++ "names.\nThe file in question is:\n " + ++ path +ppExplanation FilePathEmpty = + "Encountered a file with an empty name, something is very wrong! " + ++ "Files with an empty name cannot be stored in a tar archive or in " + ++ "standard file systems." +ppExplanation CVTestSuite = + "The 'test-suite' section is new in Cabal 1.10. " + ++ "Unfortunately it messes up the parser in older Cabal versions " + ++ "so you must specify at least 'cabal-version: >= 1.8', but note " + ++ "that only Cabal 1.10 and later can actually run such test suites." +ppExplanation CVDefaultLanguage = + "To use the 'default-language' field the package needs to specify " + ++ "at least 'cabal-version: >= 1.10'." +ppExplanation CVDefaultLanguageComponent = + "Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' " + ++ "must specify the 'default-language' field for each component (e.g. " + ++ "Haskell98 or Haskell2010). If a component uses different languages " + ++ "in different modules then list the other ones in the " + ++ "'other-languages' field." +ppExplanation CVDefaultLanguageComponentSoft = + "Without `default-language`, cabal will default to Haskell98, which is " + ++ "probably not what you want. Please add `default-language` to all " + ++ "targets." +ppExplanation CVExtraDocFiles = + "To use the 'extra-doc-files' field the package needs to specify " + ++ "'cabal-version: 1.18' or higher." +ppExplanation CVMultiLib = + "To use multiple 'library' sections or a named library section " + ++ "the package needs to specify at least 'cabal-version: 2.0'." +ppExplanation CVReexported = + "To use the 'reexported-module' field the package needs to specify " + ++ "'cabal-version: 1.22' or higher." +ppExplanation CVMixins = + "To use the 'mixins' field the package needs to specify " + ++ "at least 'cabal-version: 2.0'." +ppExplanation CVExtraFrameworkDirs = + "To use the 'extra-framework-dirs' field the package needs to specify" + ++ " 'cabal-version: 1.24' or higher." +ppExplanation CVDefaultExtensions = + "To use the 'default-extensions' field the package needs to specify " + ++ "at least 'cabal-version: >= 1.10'." +ppExplanation CVExtensionsDeprecated = + "For packages using 'cabal-version: >= 1.10' the 'extensions' " + ++ "field is deprecated. The new 'default-extensions' field lists " + ++ "extensions that are used in all modules in the component, while " + ++ "the 'other-extensions' field lists extensions that are used in " + ++ "some modules, e.g. via the {-# LANGUAGE #-} pragma." +ppExplanation CVSources = + "The use of 'asm-sources', 'cmm-sources', 'extra-bundled-libraries' " + ++ " and 'extra-library-flavours' requires the package " + ++ " to specify at least 'cabal-version: 3.0'." +ppExplanation (CVExtraDynamic flavs) = + "The use of 'extra-dynamic-library-flavours' requires the package " + ++ " to specify at least 'cabal-version: 3.0'. The flavours are: " + ++ commaSep (concat flavs) +ppExplanation CVVirtualModules = + "The use of 'virtual-modules' requires the package " + ++ " to specify at least 'cabal-version: 2.2'." +ppExplanation CVSourceRepository = + "The 'source-repository' section is new in Cabal 1.6. " + ++ "Unfortunately it messes up the parser in earlier Cabal versions " + ++ "so you need to specify 'cabal-version: >= 1.6'." +ppExplanation (CVExtensions version extCab12) = + "Unfortunately the language extensions " + ++ commaSep (map (quote . prettyShow) extCab12) + ++ " break the parser in earlier Cabal versions so you need to " + ++ "specify 'cabal-version: >= " + ++ showCabalSpecVersion version + ++ "'. Alternatively if you require compatibility with earlier " + ++ "Cabal versions then you may be able to use an equivalent " + ++ "compiler-specific flag." +ppExplanation CVCustomSetup = + "Packages using 'cabal-version: 1.24' or higher with 'build-type: Custom' " + ++ "must use a 'custom-setup' section with a 'setup-depends' field " + ++ "that specifies the dependencies of the Setup.hs script itself. " + ++ "The 'setup-depends' field uses the same syntax as 'build-depends', " + ++ "so a simple example would be 'setup-depends: base, Cabal'." +ppExplanation CVExpliticDepsCustomSetup = + "From version 1.24 cabal supports specifying explicit dependencies " + ++ "for Custom setup scripts. Consider using 'cabal-version: 1.24' or " + ++ "higher and adding a 'custom-setup' section with a 'setup-depends' " + ++ "field that specifies the dependencies of the Setup.hs script " + ++ "itself. The 'setup-depends' field uses the same syntax as " + ++ "'build-depends', so a simple example would be 'setup-depends: base, " + ++ "Cabal'." +ppExplanation CVAutogenPaths = + "Packages using 'cabal-version: 2.0' and the autogenerated " + ++ "module Paths_* must include it also on the 'autogen-modules' field " + ++ "besides 'exposed-modules' and 'other-modules'. This specifies that " + ++ "the module does not come with the package and is generated on " + ++ "setup. Modules built with a custom Setup.hs script also go here " + ++ "to ensure that commands like sdist don't fail." +ppExplanation CVAutogenPackageInfo = + "Packages using 'cabal-version: 2.0' and the autogenerated " + ++ "module PackageInfo_* must include it in 'autogen-modules' as well as" + ++ " 'exposed-modules' and 'other-modules'. This specifies that " + ++ "the module does not come with the package and is generated on " + ++ "setup. Modules built with a custom Setup.hs script also go here " + ++ "to ensure that commands like sdist don't fail." +ppExplanation CVAutogenPackageInfoGuard = + "To use the autogenerated module PackageInfo_* you need to specify " + ++ "`cabal-version: 3.12` or higher." +ppExplanation (GlobNoMatch field glob) = + "In '" + ++ field + ++ "': the pattern '" + ++ glob + ++ "' does not" + ++ " match any files." +ppExplanation (GlobExactMatch field glob file) = + "In '" + ++ field + ++ "': the pattern '" + ++ glob + ++ "' does not" + ++ " match the file '" + ++ file + ++ "' because the extensions do not" + ++ " exactly match (e.g., foo.en.html does not exactly match *.html)." + ++ " To enable looser suffix-only matching, set 'cabal-version: 2.4' or" + ++ " higher." +ppExplanation (GlobNoDir field glob dir) = + "In '" + ++ field + ++ "': the pattern '" + ++ glob + ++ "' attempts to" + ++ " match files in the directory '" + ++ dir + ++ "', but there is no" + ++ " directory by that name." +ppExplanation (UnknownOS unknownOSs) = + "Unknown operating system name " ++ commaSep (map quote unknownOSs) +ppExplanation (UnknownArch unknownArches) = + "Unknown architecture name " ++ commaSep (map quote unknownArches) +ppExplanation (UnknownCompiler unknownImpls) = + "Unknown compiler name " ++ commaSep (map quote unknownImpls) +ppExplanation BaseNoUpperBounds = + "The dependency 'build-depends: base' does not specify an upper " + ++ "bound on the version number. Each major release of the 'base' " + ++ "package changes the API in various ways and most packages will " + ++ "need some changes to compile with it. The recommended practice " + ++ "is to specify an upper bound on the version of the 'base' " + ++ "package. This ensures your package will continue to build when a " + ++ "new major version of the 'base' package is released. If you are " + ++ "not sure what upper bound to use then use the next major " + ++ "version. For example if you have tested your package with 'base' " + ++ "version 4.5 and 4.6 then use 'build-depends: base >= 4.5 && < 4.7'." +ppExplanation (MissingUpperBounds ct names) = + let separator = "\n - " + in "On " + ++ ppCET ct + ++ ", " + ++ "these packages miss upper bounds:" + ++ separator + ++ List.intercalate separator names + ++ "\n" + ++ "Please add them. There is more information at https://pvp.haskell.org/" +ppExplanation (SuspiciousFlagName invalidFlagNames) = + "Suspicious flag names: " + ++ unwords invalidFlagNames + ++ ". " + ++ "To avoid ambiguity in command line interfaces, a flag shouldn't " + ++ "start with a dash. Also for better compatibility, flag names " + ++ "shouldn't contain non-ascii characters." +ppExplanation (DeclaredUsedFlags declared used) = + "Declared and used flag sets differ: " + ++ s declared + ++ " /= " + ++ s used + ++ ". " + where + s :: Set.Set FlagName -> String + s = commaSep . map unFlagName . Set.toList +ppExplanation (NonASCIICustomField nonAsciiXFields) = + "Non ascii custom fields: " + ++ unwords nonAsciiXFields + ++ ". " + ++ "For better compatibility, custom field names " + ++ "shouldn't contain non-ascii characters." +ppExplanation RebindableClashPaths = + "Packages using RebindableSyntax with OverloadedStrings or" + ++ " OverloadedLists in default-extensions, in conjunction with the" + ++ " autogenerated module Paths_*, are known to cause compile failures" + ++ " with Cabal < 2.2. To use these default-extensions with a Paths_*" + ++ " autogen module, specify at least 'cabal-version: 2.2'." +ppExplanation RebindableClashPackageInfo = + "Packages using RebindableSyntax with OverloadedStrings or" + ++ " OverloadedLists in default-extensions, in conjunction with the" + ++ " autogenerated module PackageInfo_*, are known to cause compile failures" + ++ " with Cabal < 2.2. To use these default-extensions with a PackageInfo_*" + ++ " autogen module, specify at least 'cabal-version: 2.2'." +ppExplanation (WErrorUnneeded fieldName) = + addConditionalExp $ + "'" + ++ fieldName + ++ ": -Werror' makes the package easy to " + ++ "break with future GHC versions because new GHC versions often " + ++ "add new warnings." +ppExplanation (JUnneeded fieldName) = + addConditionalExp $ + "'" + ++ fieldName + ++ ": -j[N]' can make sense for a particular user's setup," + ++ " but it is not appropriate for a distributed package." +ppExplanation (FDeferTypeErrorsUnneeded fieldName) = + addConditionalExp $ + "'" + ++ fieldName + ++ ": -fdefer-type-errors' is fine during development " + ++ "but is not appropriate for a distributed package." +ppExplanation (DynamicUnneeded fieldName) = + addConditionalExp $ + "'" + ++ fieldName + ++ ": -d*' debug flags are not appropriate " + ++ "for a distributed package." +ppExplanation (ProfilingUnneeded fieldName) = + addConditionalExp $ + "'" + ++ fieldName + ++ ": -fprof*' profiling flags are typically not " + ++ "appropriate for a distributed library package. These flags are " + ++ "useful to profile this package, but when profiling other packages " + ++ "that use this one these flags clutter the profile output with " + ++ "excessive detail. If you think other packages really want to see " + ++ "cost centres from this package then use '-fprof-auto-exported' " + ++ "which puts cost centres only on exported functions." +ppExplanation (UpperBoundSetup nm) = + "The dependency 'setup-depends: '" + ++ nm + ++ "' does not specify an " + ++ "upper bound on the version number. Each major release of the " + ++ "'" + ++ nm + ++ "' package changes the API in various ways and most " + ++ "packages will need some changes to compile with it. If you are " + ++ "not sure what upper bound to use then use the next major " + ++ "version." +ppExplanation (DuplicateModule s dupLibsLax) = + "Duplicate modules in " + ++ s + ++ ": " + ++ commaSep (map prettyShow dupLibsLax) +ppExplanation (PotentialDupModule s dupLibsStrict) = + "Potential duplicate modules (subject to conditionals) in " + ++ s + ++ ": " + ++ commaSep (map prettyShow dupLibsStrict) +ppExplanation (BOMStart pdfile) = + pdfile + ++ " starts with an Unicode byte order mark (BOM)." + ++ " This may cause problems with older cabal versions." +ppExplanation (NotPackageName pdfile expectedCabalname) = + "The filename " + ++ quote pdfile + ++ " does not match package name " + ++ "(expected: " + ++ quote expectedCabalname + ++ ")" +ppExplanation NoDesc = + "No cabal file found.\n" + ++ "Please create a package description file .cabal" +ppExplanation (MultiDesc multiple) = + "Multiple cabal files found while checking.\n" + ++ "Please use only one of: " + ++ commaSep multiple +ppExplanation (UnknownFile fieldname file) = + "The '" + ++ fieldname + ++ "' field refers to the file " + ++ quote (getSymbolicPath file) + ++ " which does not exist." +ppExplanation MissingSetupFile = + "The package is missing a Setup.hs or Setup.lhs script." +ppExplanation MissingConfigureScript = + "The 'build-type' is 'Configure' but there is no 'configure' script. " + ++ "You probably need to run 'autoreconf -i' to generate it." +ppExplanation (UnknownDirectory kind dir) = + quote (kind ++ ": " ++ dir) + ++ " specifies a directory which does not exist." +ppExplanation MissingSourceControl = + "When distributing packages, it is encouraged to specify source " + ++ "control information in the .cabal file using one or more " + ++ "'source-repository' sections. See the Cabal user guide for " + ++ "details." +ppExplanation (MissingExpectedDocFiles extraDocFileSupport paths) = + "Please consider including the " + ++ quotes paths + ++ " in the '" + ++ targetField + ++ "' section of the .cabal file " + ++ "if it contains useful information for users of the package." + where + quotes [p] = "file " ++ quote p + quotes ps = "files " ++ commaSep (map quote ps) + targetField = + if extraDocFileSupport + then "extra-doc-files" + else "extra-source-files" +ppExplanation (WrongFieldForExpectedDocFiles extraDocFileSupport field paths) = + "Please consider moving the " + ++ quotes paths + ++ " from the '" + ++ field + ++ "' section of the .cabal file " + ++ "to the section '" + ++ targetField + ++ "'." + where + quotes [p] = "file " ++ quote p + quotes ps = "files " ++ commaSep (map quote ps) + targetField = + if extraDocFileSupport + then "extra-doc-files" + else "extra-source-files" + +-- * Formatting utilities + +commaSep :: [String] -> String +commaSep = List.intercalate ", " + +quote :: String -> String +quote s = "'" ++ s ++ "'" + +addConditionalExp :: String -> String +addConditionalExp expl = + expl + ++ " Alternatively, if you want to use this, make it conditional based " + ++ "on a Cabal configuration flag (with 'manual: True' and 'default: " + ++ "False') and enable that flag during development." diff --git a/Cabal/src/Distribution/Simple.hs b/Cabal/src/Distribution/Simple.hs index 024a445f1dc..58e9f4046b0 100644 --- a/Cabal/src/Distribution/Simple.hs +++ b/Cabal/src/Distribution/Simple.hs @@ -168,7 +168,8 @@ defaultMainWithHooksNoReadArgs hooks pkg_descr = defaultMainHelper :: UserHooks -> Args -> IO () defaultMainHelper hooks args = topHandler $ do args' <- expandResponse args - case commandsRun (globalCommand commands) commands args' of + command <- commandsRun (globalCommand commands) commands args' + case command of CommandHelp help -> printHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs @@ -742,8 +743,7 @@ simpleUserHooks = -- -- * 'postConf' runs @.\/configure@, if present. -- --- * the pre-hooks 'preBuild', 'preClean', 'preCopy', 'preInst', --- 'preReg' and 'preUnreg' read additional build information from +-- * the pre-hooks, except for pre-conf, read additional build information from -- /package/@.buildinfo@, if present. -- -- Thus @configure@ can use local system information to generate @@ -752,7 +752,8 @@ autoconfUserHooks :: UserHooks autoconfUserHooks = simpleUserHooks { postConf = defaultPostConf - , preBuild = readHookWithArgs buildVerbosity buildDistPref -- buildCabalFilePath, + , preBuild = readHookWithArgs buildVerbosity buildDistPref + , preRepl = readHookWithArgs replVerbosity replDistPref , preCopy = readHookWithArgs copyVerbosity copyDistPref , preClean = readHook cleanVerbosity cleanDistPref , preInst = readHook installVerbosity installDistPref @@ -760,6 +761,8 @@ autoconfUserHooks = , preHaddock = readHookWithArgs haddockVerbosity haddockDistPref , preReg = readHook regVerbosity regDistPref , preUnreg = readHook regVerbosity regDistPref + , preTest = readHookWithArgs testVerbosity testDistPref + , preBench = readHookWithArgs benchmarkVerbosity benchmarkDistPref } where defaultPostConf diff --git a/Cabal/src/Distribution/Simple/Build.hs b/Cabal/src/Distribution/Simple/Build.hs index 893ca24e187..bc6ac7ae6be 100644 --- a/Cabal/src/Distribution/Simple/Build.hs +++ b/Cabal/src/Distribution/Simple/Build.hs @@ -1,5 +1,7 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TupleSections #-} ----------------------------------------------------------------------------- @@ -18,13 +20,22 @@ -- compiler-specific actions. It does do some non-compiler specific bits like -- running pre-processors. module Distribution.Simple.Build - ( build + ( -- * Build + build + + -- * Repl , repl , startInterpreter - , initialBuildSteps - , createInternalPackageDB - , componentInitialBuildSteps + + -- * Build preparation + , preBuildComponent + , AutogenFile (..) + , AutogenFileContents + , writeBuiltinAutogenFiles , writeAutogenFiles + + -- * Internal package database creation + , createInternalPackageDB ) where import Distribution.Compat.Prelude @@ -61,6 +72,7 @@ import qualified Distribution.Simple.Program.HcPkg as HcPkg import Distribution.InstalledPackageInfo (InstalledPackageInfo) import qualified Distribution.InstalledPackageInfo as IPI +import Distribution.ModuleName (ModuleName) import qualified Distribution.ModuleName as ModuleName import Distribution.PackageDescription import Distribution.Simple.Compiler @@ -84,6 +96,7 @@ import Distribution.Simple.ShowBuildInfo import Distribution.Simple.Test.LibV09 import Distribution.Simple.Utils import Distribution.Utils.Json +import Distribution.Utils.ShortText (ShortText, fromShortText, toShortText) import Distribution.Pretty import Distribution.System @@ -94,6 +107,7 @@ import Distribution.Compat.Graph (IsNode (..)) import Control.Monad import qualified Data.ByteString.Lazy as LBS +import qualified Data.Map as Map import Distribution.Simple.Errors import System.Directory (doesFileExist, getCurrentDirectory, removeFile) import System.FilePath (takeDirectory, (<.>), ()) @@ -137,10 +151,10 @@ build pkg_descr lbi flags suffixes = do -- Now do the actual building (\f -> foldM_ f (installedPkgs lbi) componentsToBuild) $ \index target -> do + preBuildComponent verbosity lbi target let comp = targetComponent target clbi = targetCLBI target - componentInitialBuildSteps distPref pkg_descr lbi clbi verbosity - let bi = componentBuildInfo comp + bi = componentBuildInfo comp progs' = addInternalBuildTools pkg_descr lbi bi (withPrograms lbi) lbi' = lbi @@ -158,10 +172,9 @@ build pkg_descr lbi flags suffixes = do NoFlag -> return $ case buildNumJobs flags of Flag n -> NumJobs n NoFlag -> Serial - mb_ipi <- buildComponent - verbosity + flags par_strat pkg_descr lbi' @@ -299,9 +312,9 @@ repl pkg_descr lbi flags suffixes args = do let clbi = targetCLBI subtarget comp = targetComponent subtarget lbi' = lbiForComponent comp lbi - componentInitialBuildSteps distPref pkg_descr lbi clbi verbosity + preBuildComponent verbosity lbi subtarget buildComponent - verbosity + mempty{buildVerbosity = toFlag verbosity} NoFlag pkg_descr lbi' @@ -316,9 +329,8 @@ repl pkg_descr lbi flags suffixes args = do let clbi = targetCLBI target comp = targetComponent target lbi' = lbiForComponent comp lbi - replFlags = replReplOptions flags - componentInitialBuildSteps distPref pkg_descr lbi clbi verbosity - replComponent replFlags verbosity pkg_descr lbi' suffixes comp clbi distPref + preBuildComponent verbosity lbi target + replComponent flags verbosity pkg_descr lbi' suffixes comp clbi distPref -- | Start an interpreter without loading any package files. startInterpreter @@ -335,7 +347,7 @@ startInterpreter verbosity programDb comp platform packageDBs = _ -> dieWithException verbosity REPLNotSupported buildComponent - :: Verbosity + :: BuildFlags -> Flag ParStrat -> PackageDescription -> LocalBuildInfo @@ -344,137 +356,12 @@ buildComponent -> ComponentLocalBuildInfo -> FilePath -> IO (Maybe InstalledPackageInfo) +buildComponent flags _ _ _ _ (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) _ _ = + dieWithException (fromFlag $ buildVerbosity flags) $ NoSupportBuildingTestSuite tt +buildComponent flags _ _ _ _ (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) _ _ = + dieWithException (fromFlag $ buildVerbosity flags) $ NoSupportBuildingBenchMark tt buildComponent - verbosity - numJobs - pkg_descr - lbi - suffixes - comp@(CLib lib) - clbi - distPref = do - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - setupMessage' - verbosity - "Building" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - let libbi = libBuildInfo lib - lib' = - lib - { libBuildInfo = - flip addExtraAsmSources extras $ - flip addExtraCmmSources extras $ - flip addExtraCxxSources extras $ - flip addExtraCSources extras $ - flip addExtraJsSources extras $ - libbi - } - - buildLib verbosity numJobs pkg_descr lbi lib' clbi - - let oneComponentRequested (OneComponentRequestedSpec _) = True - oneComponentRequested _ = False - -- Don't register inplace if we're only building a single component; - -- it's not necessary because there won't be any subsequent builds - -- that need to tag us - if (not (oneComponentRequested (componentEnabledSpec lbi))) - then do - -- Register the library in-place, so exes can depend - -- on internally defined libraries. - pwd <- getCurrentDirectory - let - -- The in place registration uses the "-inplace" suffix, not an ABI hash - installedPkgInfo = - inplaceInstalledPackageInfo - pwd - distPref - pkg_descr - -- NB: Use a fake ABI hash to avoid - -- needing to recompute it every build. - (mkAbiHash "inplace") - lib' - lbi - clbi - - debug verbosity $ "Registering inplace:\n" ++ (IPI.showInstalledPackageInfo installedPkgInfo) - registerPackage - verbosity - (compiler lbi) - (withPrograms lbi) - (withPackageDB lbi) - installedPkgInfo - HcPkg.defaultRegisterOptions - { HcPkg.registerMultiInstance = True - } - return (Just installedPkgInfo) - else return Nothing -buildComponent - verbosity - numJobs - pkg_descr - lbi - suffixes - comp@(CFLib flib) - clbi - _distPref = do - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - setupMessage' - verbosity - "Building" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - buildFLib verbosity numJobs pkg_descr lbi flib clbi - return Nothing -buildComponent - verbosity - numJobs - pkg_descr - lbi - suffixes - comp@(CExe exe) - clbi - _ = do - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - setupMessage' - verbosity - "Building" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - let ebi = buildInfo exe - exe' = exe{buildInfo = addExtraCSources ebi extras} - buildExe verbosity numJobs pkg_descr lbi exe' clbi - return Nothing -buildComponent - verbosity - numJobs - pkg_descr - lbi - suffixes - comp@(CTest test@TestSuite{testInterface = TestSuiteExeV10{}}) - clbi - _distPref = do - let exe = testSuiteExeV10AsExe test - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - (genDir, generatedExtras) <- generateCode (testCodeGenerators test) (testName test) pkg_descr (testBuildInfo test) lbi clbi verbosity - setupMessage' - verbosity - "Building" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - let ebi = buildInfo exe - exe' = exe{buildInfo = addSrcDir (addExtraOtherModules (addExtraCSources ebi extras) generatedExtras) genDir} -- todo extend hssrcdirs - buildExe verbosity numJobs pkg_descr lbi exe' clbi - return Nothing -buildComponent - verbosity + flags numJobs pkg_descr lbi0 @@ -487,83 +374,138 @@ buildComponent -- be used, except to construct the CLBIs for the -- library and stub executable that will actually be -- built. - distPref = do - pwd <- getCurrentDirectory - let (pkg, lib, libClbi, lbi, ipi, exe, exeClbi) = - testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi -- TODO find cpphs processed files - (genDir, generatedExtras) <- generateCode (testCodeGenerators test) (testName test) pkg_descr (testBuildInfo test) lbi clbi verbosity - setupMessage' - verbosity - "Building" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - let libbi = libBuildInfo lib - lib' = lib{libBuildInfo = addSrcDir (addExtraOtherModules libbi generatedExtras) genDir} - buildLib verbosity numJobs pkg lbi lib' libClbi - -- NB: need to enable multiple instances here, because on 7.10+ - -- the package name is the same as the library, and we still - -- want the registration to go through. - registerPackage - verbosity - (compiler lbi) - (withPrograms lbi) - (withPackageDB lbi) - ipi - HcPkg.defaultRegisterOptions - { HcPkg.registerMultiInstance = True - } - let ebi = buildInfo exe - -- NB: The stub executable is linked against the test-library - -- which already contains all `other-modules`, so we need - -- to remove those from the stub-exe's build-info - exe' = exe{buildInfo = (addExtraCSources ebi extras){otherModules = []}} - buildExe verbosity numJobs pkg_descr lbi exe' exeClbi - return Nothing -- Can't depend on test suite -buildComponent - verbosity - _ - _ - _ - _ - (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) - _ - _ = - dieWithException verbosity $ NoSupportBuildingTestSuite tt + distPref = + do + let verbosity = fromFlag $ buildVerbosity flags + pwd <- getCurrentDirectory + let (pkg, lib, libClbi, lbi, ipi, exe, exeClbi) = + testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd + preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes + extras <- preprocessExtras verbosity comp lbi -- TODO find cpphs processed files + (genDir, generatedExtras) <- generateCode (testCodeGenerators test) (testName test) pkg_descr (testBuildInfo test) lbi clbi verbosity + setupMessage' + verbosity + "Building" + (packageId pkg_descr) + (componentLocalName clbi) + (maybeComponentInstantiatedWith clbi) + let libbi = libBuildInfo lib + lib' = lib{libBuildInfo = addSrcDir (addExtraOtherModules libbi generatedExtras) genDir} + buildLib flags numJobs pkg lbi lib' libClbi + -- NB: need to enable multiple instances here, because on 7.10+ + -- the package name is the same as the library, and we still + -- want the registration to go through. + registerPackage + verbosity + (compiler lbi) + (withPrograms lbi) + (withPackageDB lbi) + ipi + HcPkg.defaultRegisterOptions + { HcPkg.registerMultiInstance = True + } + let ebi = buildInfo exe + -- NB: The stub executable is linked against the test-library + -- which already contains all `other-modules`, so we need + -- to remove those from the stub-exe's build-info + exe' = exe{buildInfo = (addExtraCSources ebi extras){otherModules = []}} + buildExe verbosity numJobs pkg_descr lbi exe' exeClbi + return Nothing -- Can't depend on test suite buildComponent - verbosity + flags numJobs pkg_descr lbi suffixes - comp@(CBench bm@Benchmark{benchmarkInterface = BenchmarkExeV10{}}) + comp clbi - _distPref = do - let exe = benchmarkExeV10asExe bm - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - setupMessage' - verbosity - "Building" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - let ebi = buildInfo exe - exe' = exe{buildInfo = addExtraCSources ebi extras} - buildExe verbosity numJobs pkg_descr lbi exe' clbi - return Nothing -buildComponent - verbosity - _ - _ - _ - _ - (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) - _ - _ = - dieWithException verbosity $ NoSupportBuildingBenchMark tt + distPref = + do + let verbosity = fromFlag $ buildVerbosity flags + preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes + extras <- preprocessExtras verbosity comp lbi + setupMessage' + verbosity + "Building" + (packageId pkg_descr) + (componentLocalName clbi) + (maybeComponentInstantiatedWith clbi) + case comp of + CLib lib -> do + let libbi = libBuildInfo lib + lib' = + lib + { libBuildInfo = + flip addExtraAsmSources extras $ + flip addExtraCmmSources extras $ + flip addExtraCxxSources extras $ + flip addExtraCSources extras $ + flip addExtraJsSources extras $ + libbi + } + + buildLib flags numJobs pkg_descr lbi lib' clbi + + let oneComponentRequested (OneComponentRequestedSpec _) = True + oneComponentRequested _ = False + -- Don't register inplace if we're only building a single component; + -- it's not necessary because there won't be any subsequent builds + -- that need to tag us + if (not (oneComponentRequested (componentEnabledSpec lbi))) + then do + -- Register the library in-place, so exes can depend + -- on internally defined libraries. + pwd <- getCurrentDirectory + let + -- The in place registration uses the "-inplace" suffix, not an ABI hash + installedPkgInfo = + inplaceInstalledPackageInfo + pwd + distPref + pkg_descr + -- NB: Use a fake ABI hash to avoid + -- needing to recompute it every build. + (mkAbiHash "inplace") + lib' + lbi + clbi + debug verbosity $ "Registering inplace:\n" ++ (IPI.showInstalledPackageInfo installedPkgInfo) + registerPackage + verbosity + (compiler lbi) + (withPrograms lbi) + (withPackageDB lbi) + installedPkgInfo + HcPkg.defaultRegisterOptions + { HcPkg.registerMultiInstance = True + } + return (Just installedPkgInfo) + else return Nothing + CFLib flib -> do + buildFLib verbosity numJobs pkg_descr lbi flib clbi + return Nothing + CExe exe -> do + let ebi = buildInfo exe + exe' = exe{buildInfo = addExtraCSources ebi extras} + buildExe verbosity numJobs pkg_descr lbi exe' clbi + return Nothing + CTest test@TestSuite{testInterface = TestSuiteExeV10{}} -> do + let exe = testSuiteExeV10AsExe test + (genDir, generatedExtras) <- generateCode (testCodeGenerators test) (testName test) pkg_descr (testBuildInfo test) lbi clbi verbosity + let ebi = buildInfo exe + exe' = exe{buildInfo = addSrcDir (addExtraOtherModules (addExtraCSources ebi extras) generatedExtras) genDir} -- todo extend hssrcdirs + buildExe verbosity numJobs pkg_descr lbi exe' clbi + return Nothing + CBench bm@Benchmark{benchmarkInterface = BenchmarkExeV10{}} -> do + let exe = benchmarkExeV10asExe bm + let ebi = buildInfo exe + exe' = exe{buildInfo = addExtraCSources ebi extras} + buildExe verbosity numJobs pkg_descr lbi exe' clbi + return Nothing +#if __GLASGOW_HASKELL__ < 811 +-- silence pattern-match warnings prior to GHC 9.0 + _ -> error "impossible" +#endif generateCode :: [String] @@ -645,7 +587,7 @@ addSrcDir bi extra = bi{hsSourceDirs = new} new = ordNub (unsafeMakeSymbolicPath extra : hsSourceDirs bi) replComponent - :: ReplOptions + :: ReplFlags -> Verbosity -> PackageDescription -> LocalBuildInfo @@ -654,60 +596,10 @@ replComponent -> ComponentLocalBuildInfo -> FilePath -> IO () -replComponent - replFlags - verbosity - pkg_descr - lbi - suffixes - comp@(CLib lib) - clbi - _ = do - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - let libbi = libBuildInfo lib - lib' = lib{libBuildInfo = libbi{cSources = cSources libbi ++ extras}} - replLib replFlags verbosity pkg_descr lbi lib' clbi -replComponent - replFlags - verbosity - pkg_descr - lbi - suffixes - comp@(CFLib flib) - clbi - _ = do - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - replFLib replFlags verbosity pkg_descr lbi flib clbi -replComponent - replFlags - verbosity - pkg_descr - lbi - suffixes - comp@(CExe exe) - clbi - _ = do - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - let ebi = buildInfo exe - exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}} - replExe replFlags verbosity pkg_descr lbi exe' clbi -replComponent - replFlags - verbosity - pkg_descr - lbi - suffixes - comp@(CTest test@TestSuite{testInterface = TestSuiteExeV10{}}) - clbi - _distPref = do - let exe = testSuiteExeV10AsExe test - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - let ebi = buildInfo exe - exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}} - replExe replFlags verbosity pkg_descr lbi exe' clbi +replComponent _ verbosity _ _ _ (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) _ _ = + dieWithException verbosity $ NoSupportBuildingTestSuite tt +replComponent _ verbosity _ _ _ (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) _ _ = + dieWithException verbosity $ NoSupportBuildingBenchMark tt replComponent replFlags verbosity @@ -726,42 +618,44 @@ replComponent extras <- preprocessExtras verbosity comp lbi let libbi = libBuildInfo lib lib' = lib{libBuildInfo = libbi{cSources = cSources libbi ++ extras}} - replLib replFlags verbosity pkg lbi lib' libClbi -replComponent - _ - verbosity - _ - _ - _ - (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) - _ - _ = - dieWithException verbosity $ NoSupportBuildingTestSuite tt + replLib replFlags pkg lbi lib' libClbi replComponent replFlags verbosity pkg_descr lbi suffixes - comp@(CBench bm@Benchmark{benchmarkInterface = BenchmarkExeV10{}}) + comp clbi - _distPref = do - let exe = benchmarkExeV10asExe bm - preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes - extras <- preprocessExtras verbosity comp lbi - let ebi = buildInfo exe - exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}} - replExe replFlags verbosity pkg_descr lbi exe' clbi -replComponent - _ - verbosity - _ - _ - _ - (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) - _ _ = - dieWithException verbosity $ NoSupportBuildingBenchMark tt + do + preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes + extras <- preprocessExtras verbosity comp lbi + case comp of + CLib lib -> do + let libbi = libBuildInfo lib + lib' = lib{libBuildInfo = libbi{cSources = cSources libbi ++ extras}} + replLib replFlags pkg_descr lbi lib' clbi + CFLib flib -> + replFLib replFlags pkg_descr lbi flib clbi + CExe exe -> do + let ebi = buildInfo exe + exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}} + replExe replFlags pkg_descr lbi exe' clbi + CTest test@TestSuite{testInterface = TestSuiteExeV10{}} -> do + let exe = testSuiteExeV10AsExe test + let ebi = buildInfo exe + exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}} + replExe replFlags pkg_descr lbi exe' clbi + CBench bm@Benchmark{benchmarkInterface = BenchmarkExeV10{}} -> do + let exe = benchmarkExeV10asExe bm + let ebi = buildInfo exe + exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}} + replExe replFlags pkg_descr lbi exe' clbi +#if __GLASGOW_HASKELL__ < 811 +-- silence pattern-match warnings prior to GHC 9.0 + _ -> error "impossible" +#endif ---------------------------------------------------- -- Shared code for buildComponent and replComponent @@ -904,9 +798,7 @@ testSuiteLibV09AsLibAndExe -- Executable can't be indefinite, so dependencies must -- be definite packages. componentIncludes = - zip - (map (DefiniteUnitId . unsafeMkDefUnitId . fst) deps) - (repeat defaultRenaming) + map ((,defaultRenaming) . DefiniteUnitId . unsafeMkDefUnitId . fst) deps } testSuiteLibV09AsLibAndExe _ TestSuite{} _ _ _ _ = error "testSuiteLibV09AsLibAndExe: wrong kind" @@ -944,20 +836,21 @@ addInternalBuildTools pkg lbi bi progs = -- TODO: build separate libs in separate dirs so that we can build -- multiple libs, e.g. for 'LibTest' library-style test suites buildLib - :: Verbosity + :: BuildFlags -> Flag ParStrat -> PackageDescription -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO () -buildLib verbosity numJobs pkg_descr lbi lib clbi = - case compilerFlavor (compiler lbi) of - GHC -> GHC.buildLib verbosity numJobs pkg_descr lbi lib clbi - GHCJS -> GHCJS.buildLib verbosity numJobs pkg_descr lbi lib clbi - UHC -> UHC.buildLib verbosity pkg_descr lbi lib clbi - HaskellSuite{} -> HaskellSuite.buildLib verbosity pkg_descr lbi lib clbi - _ -> dieWithException verbosity BuildingNotSupportedWithCompiler +buildLib flags numJobs pkg_descr lbi lib clbi = + let verbosity = fromFlag $ buildVerbosity flags + in case compilerFlavor (compiler lbi) of + GHC -> GHC.buildLib flags numJobs pkg_descr lbi lib clbi + GHCJS -> GHCJS.buildLib verbosity numJobs pkg_descr lbi lib clbi + UHC -> UHC.buildLib verbosity pkg_descr lbi lib clbi + HaskellSuite{} -> HaskellSuite.buildLib verbosity pkg_descr lbi lib clbi + _ -> dieWithException verbosity BuildingNotSupportedWithCompiler -- | Build a foreign library -- @@ -992,127 +885,165 @@ buildExe verbosity numJobs pkg_descr lbi exe clbi = _ -> dieWithException verbosity BuildingNotSupportedWithCompiler replLib - :: ReplOptions - -> Verbosity + :: ReplFlags -> PackageDescription -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO () -replLib replFlags verbosity pkg_descr lbi lib clbi = - case compilerFlavor (compiler lbi) of - -- 'cabal repl' doesn't need to support 'ghc --make -j', so we just pass - -- NoFlag as the numJobs parameter. - GHC -> GHC.replLib replFlags verbosity NoFlag pkg_descr lbi lib clbi - GHCJS -> GHCJS.replLib (replOptionsFlags replFlags) verbosity NoFlag pkg_descr lbi lib clbi - _ -> dieWithException verbosity REPLNotSupported +replLib replFlags pkg_descr lbi lib clbi = + let verbosity = fromFlag $ replVerbosity replFlags + opts = replReplOptions replFlags + in case compilerFlavor (compiler lbi) of + -- 'cabal repl' doesn't need to support 'ghc --make -j', so we just pass + -- NoFlag as the numJobs parameter. + GHC -> GHC.replLib replFlags NoFlag pkg_descr lbi lib clbi + GHCJS -> GHCJS.replLib (replOptionsFlags opts) verbosity NoFlag pkg_descr lbi lib clbi + _ -> dieWithException verbosity REPLNotSupported replExe - :: ReplOptions - -> Verbosity + :: ReplFlags -> PackageDescription -> LocalBuildInfo -> Executable -> ComponentLocalBuildInfo -> IO () -replExe replFlags verbosity pkg_descr lbi exe clbi = - case compilerFlavor (compiler lbi) of - GHC -> GHC.replExe replFlags verbosity NoFlag pkg_descr lbi exe clbi - GHCJS -> GHCJS.replExe (replOptionsFlags replFlags) verbosity NoFlag pkg_descr lbi exe clbi - _ -> dieWithException verbosity REPLNotSupported +replExe flags pkg_descr lbi exe clbi = + let verbosity = fromFlag $ replVerbosity flags + in case compilerFlavor (compiler lbi) of + GHC -> GHC.replExe flags NoFlag pkg_descr lbi exe clbi + GHCJS -> GHCJS.replExe (replOptionsFlags $ replReplOptions flags) verbosity NoFlag pkg_descr lbi exe clbi + _ -> dieWithException verbosity REPLNotSupported replFLib - :: ReplOptions - -> Verbosity + :: ReplFlags -> PackageDescription -> LocalBuildInfo -> ForeignLib -> ComponentLocalBuildInfo -> IO () -replFLib replFlags verbosity pkg_descr lbi exe clbi = - case compilerFlavor (compiler lbi) of - GHC -> GHC.replFLib replFlags verbosity NoFlag pkg_descr lbi exe clbi - _ -> dieWithException verbosity REPLNotSupported - --- | Runs 'componentInitialBuildSteps' on every configured component. -initialBuildSteps - :: FilePath - -- ^ "dist" prefix - -> PackageDescription - -- ^ mostly information from the .cabal file +replFLib flags pkg_descr lbi exe clbi = + let verbosity = fromFlag $ replVerbosity flags + in case compilerFlavor (compiler lbi) of + GHC -> GHC.replFLib flags NoFlag pkg_descr lbi exe clbi + _ -> dieWithException verbosity REPLNotSupported + +-- | Pre-build steps for a component: creates the autogenerated files +-- for a particular configured component. +preBuildComponent + :: Verbosity -> LocalBuildInfo -- ^ Configuration information - -> Verbosity - -- ^ The verbosity to use + -> TargetInfo -> IO () -initialBuildSteps distPref pkg_descr lbi verbosity = - withAllComponentsInBuildOrder pkg_descr lbi $ \_comp clbi -> - componentInitialBuildSteps distPref pkg_descr lbi clbi verbosity - --- | Creates the autogenerated files for a particular configured component. -componentInitialBuildSteps - :: FilePath - -- ^ "dist" prefix +preBuildComponent verbosity lbi tgt = do + let pkg_descr = localPkgDescr lbi + clbi = targetCLBI tgt + createDirectoryIfMissingVerbose verbosity True (componentBuildDir lbi clbi) + writeBuiltinAutogenFiles verbosity pkg_descr lbi clbi + +-- | Generate and write to disk all built-in autogenerated files +-- for the specified component. These files will be put in the +-- autogenerated module directory for this component +-- (see 'autogenComponentsModuleDir'). +-- +-- This includes: +-- +-- - @Paths_.hs@, +-- - @PackageInfo_.hs@, +-- - Backpack signature files for components that are not fully instantiated, +-- - @cabal_macros.h@. +writeBuiltinAutogenFiles + :: Verbosity -> PackageDescription - -- ^ mostly information from the .cabal file -> LocalBuildInfo - -- ^ Configuration information -> ComponentLocalBuildInfo - -> Verbosity - -- ^ The verbosity to use -> IO () -componentInitialBuildSteps _distPref pkg_descr lbi clbi verbosity = do - createDirectoryIfMissingVerbose verbosity True (componentBuildDir lbi clbi) +writeBuiltinAutogenFiles verbosity pkg lbi clbi = + writeAutogenFiles verbosity lbi clbi $ builtinAutogenFiles pkg lbi clbi - writeAutogenFiles verbosity pkg_descr lbi clbi - --- | Generate and write out the Paths_.hs, PackageInfo_.hs, and cabal_macros.h files +-- | Built-in autogenerated files and their contents. This includes: +-- +-- - @Paths_.hs@, +-- - @PackageInfo_.hs@, +-- - Backpack signature files for components that are not fully instantiated, +-- - @cabal_macros.h@. +builtinAutogenFiles + :: PackageDescription + -> LocalBuildInfo + -> ComponentLocalBuildInfo + -> Map AutogenFile AutogenFileContents +builtinAutogenFiles pkg lbi clbi = + Map.insert pathsFile pathsContents $ + Map.insert packageInfoFile packageInfoContents $ + Map.insert cppHeaderFile cppHeaderContents $ + emptySignatureModules clbi + where + pathsFile = AutogenModule (autogenPathsModuleName pkg) (Suffix "hs") + pathsContents = toUTF8LBS $ generatePathsModule pkg lbi clbi + packageInfoFile = AutogenModule (autogenPackageInfoModuleName pkg) (Suffix "hs") + packageInfoContents = toUTF8LBS $ generatePackageInfoModule pkg lbi + cppHeaderFile = AutogenFile $ toShortText cppHeaderName + cppHeaderContents = toUTF8LBS $ generateCabalMacrosHeader pkg lbi clbi + +-- | An empty @".hsig"@ Backpack signature module for each requirement, so that +-- GHC has a source file to look at it when it needs to typecheck +-- a signature. It's harmless to generate these modules, even when +-- there is a real @hsig@ file written by the user, since +-- include path ordering ensures that the real @hsig@ file +-- will always be picked up before the autogenerated one. +emptySignatureModules + :: ComponentLocalBuildInfo + -> Map AutogenFile AutogenFileContents +emptySignatureModules clbi = + case clbi of + LibComponentLocalBuildInfo{componentInstantiatedWith = insts} -> + Map.fromList + [ ( AutogenModule modName (Suffix "hsig") + , emptyHsigFile modName + ) + | (modName, _) <- insts + ] + _ -> Map.empty + where + emptyHsigFile :: ModuleName -> AutogenFileContents + emptyHsigFile modName = + toUTF8LBS $ + "{-# OPTIONS_GHC -w #-}\n" + ++ "{-# LANGUAGE NoImplicitPrelude #-}\n" + ++ "signature " + ++ prettyShow modName + ++ " where" + +data AutogenFile + = AutogenModule !ModuleName !Suffix + | AutogenFile !ShortText + deriving (Show, Eq, Ord) + +-- | A representation of the contents of an autogenerated file. +type AutogenFileContents = LBS.ByteString + +-- | Write the given autogenerated files in the autogenerated modules +-- directory for the component. writeAutogenFiles :: Verbosity - -> PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo + -> Map AutogenFile AutogenFileContents -> IO () -writeAutogenFiles verbosity pkg lbi clbi = do - createDirectoryIfMissingVerbose verbosity True (autogenComponentModulesDir lbi clbi) - - let pathsModulePath = - autogenComponentModulesDir lbi clbi - ModuleName.toFilePath (autogenPathsModuleName pkg) <.> "hs" - pathsModuleDir = takeDirectory pathsModulePath - -- Ensure that the directory exists! - createDirectoryIfMissingVerbose verbosity True pathsModuleDir - rewriteFileEx verbosity pathsModulePath (generatePathsModule pkg lbi clbi) - - let packageInfoModulePath = - autogenComponentModulesDir lbi clbi - ModuleName.toFilePath (autogenPackageInfoModuleName pkg) <.> "hs" - packageInfoModuleDir = takeDirectory packageInfoModulePath - -- Ensure that the directory exists! - createDirectoryIfMissingVerbose verbosity True packageInfoModuleDir - rewriteFileEx verbosity packageInfoModulePath (generatePackageInfoModule pkg lbi) - - -- TODO: document what we're doing here, and move it to its own function - case clbi of - LibComponentLocalBuildInfo{componentInstantiatedWith = insts} -> - -- Write out empty hsig files for all requirements, so that GHC - -- has a source file to look at it when it needs to typecheck - -- a signature. It's harmless to write these out even when - -- there is a real hsig file written by the user, since - -- include path ordering ensures that the real hsig file - -- will always be picked up before the autogenerated one. - for_ (map fst insts) $ \mod_name -> do - let sigPath = - autogenComponentModulesDir lbi clbi - ModuleName.toFilePath mod_name <.> "hsig" - createDirectoryIfMissingVerbose verbosity True (takeDirectory sigPath) - rewriteFileEx verbosity sigPath $ - "{-# OPTIONS_GHC -w #-}\n" - ++ "{-# LANGUAGE NoImplicitPrelude #-}\n" - ++ "signature " - ++ prettyShow mod_name - ++ " where" - _ -> return () - - let cppHeaderPath = autogenComponentModulesDir lbi clbi cppHeaderName - rewriteFileEx verbosity cppHeaderPath (generateCabalMacrosHeader pkg lbi clbi) +writeAutogenFiles verbosity lbi clbi autogenFiles = do + -- Ensure that the overall autogenerated files directory exists. + createDirectoryIfMissingVerbose verbosity True autogenDir + for_ (Map.assocs autogenFiles) $ \(file, contents) -> do + let path = case file of + AutogenModule modName (Suffix ext) -> + autogenDir ModuleName.toFilePath modName <.> ext + AutogenFile fileName -> + autogenDir fromShortText fileName + dir = takeDirectory path + -- Ensure that the directory subtree for this autogenerated file exists. + createDirectoryIfMissingVerbose verbosity True dir + -- Write the contents of the file. + rewriteFileLBS verbosity path contents + where + autogenDir = autogenComponentModulesDir lbi clbi diff --git a/Cabal/src/Distribution/Simple/Build/Inputs.hs b/Cabal/src/Distribution/Simple/Build/Inputs.hs new file mode 100644 index 00000000000..48b3b60a12b --- /dev/null +++ b/Cabal/src/Distribution/Simple/Build/Inputs.hs @@ -0,0 +1,74 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE PatternSynonyms #-} + +module Distribution.Simple.Build.Inputs + ( -- * Inputs of actions for building components + PreBuildComponentInputs (..) + + -- * Queries over the component being built + , buildVerbosity + , buildComponent + , buildIsLib + , buildCLBI + , buildBI + , buildCompiler + + -- * Re-exports + , BuildingWhat (..) + , LocalBuildInfo (..) + , TargetInfo (..) + , buildingWhatVerbosity + , buildingWhatDistPref + ) +where + +import Distribution.Simple.Compiler +import Distribution.Simple.Setup (BuildingWhat (..), buildingWhatDistPref, buildingWhatVerbosity) +import Distribution.Types.BuildInfo +import Distribution.Types.Component +import Distribution.Types.ComponentLocalBuildInfo +import Distribution.Types.LocalBuildInfo +import Distribution.Types.TargetInfo +import Distribution.Verbosity + +-- | The information required for a build computation which is available right +-- before building each component, i.e. the pre-build component inputs. +data PreBuildComponentInputs = PreBuildComponentInputs + { buildingWhat :: BuildingWhat + -- ^ What kind of build are we doing? + , localBuildInfo :: LocalBuildInfo + -- ^ Information about the package + , targetInfo :: TargetInfo + -- ^ Information about an individual component + } + +-- | Get the @'Verbosity'@ from the context the component being built is in. +buildVerbosity :: PreBuildComponentInputs -> Verbosity +buildVerbosity = buildingWhatVerbosity . buildingWhat + +-- | Get the @'Component'@ being built. +buildComponent :: PreBuildComponentInputs -> Component +buildComponent = targetComponent . targetInfo + +-- | Is the @'Component'@ being built a @'Library'@? +buildIsLib :: PreBuildComponentInputs -> Bool +buildIsLib = do + component <- buildComponent + let isLib + | CLib{} <- component = True + | otherwise = False + return isLib +{-# INLINE buildIsLib #-} + +-- | Get the @'ComponentLocalBuildInfo'@ for the component being built. +buildCLBI :: PreBuildComponentInputs -> ComponentLocalBuildInfo +buildCLBI = targetCLBI . targetInfo + +-- | Get the @'BuildInfo'@ of the component being built. +buildBI :: PreBuildComponentInputs -> BuildInfo +buildBI = componentBuildInfo . buildComponent + +-- | Get the @'Compiler'@ being used to build the component. +buildCompiler :: PreBuildComponentInputs -> Compiler +buildCompiler = compiler . localBuildInfo diff --git a/Cabal/src/Distribution/Simple/Build/Macros/Z.hs b/Cabal/src/Distribution/Simple/Build/Macros/Z.hs index 77e0ca4a94d..b43407f1b2a 100644 --- a/Cabal/src/Distribution/Simple/Build/Macros/Z.hs +++ b/Cabal/src/Distribution/Simple/Build/Macros/Z.hs @@ -3,8 +3,8 @@ module Distribution.Simple.Build.Macros.Z (render, Z(..), ZPackage (..), ZTool (..)) where import Distribution.ZinzaPrelude data Z - = Z {zPackages :: ([ZPackage]), - zTools :: ([ZTool]), + = Z {zPackages :: [ZPackage], + zTools :: [ZTool], zPackageKey :: String, zComponentId :: String, zPackageVersion :: Version, diff --git a/Cabal/src/Distribution/Simple/BuildPaths.hs b/Cabal/src/Distribution/Simple/BuildPaths.hs index 386a6e7fc82..b4adc37d3e7 100644 --- a/Cabal/src/Distribution/Simple/BuildPaths.hs +++ b/Cabal/src/Distribution/Simple/BuildPaths.hs @@ -58,6 +58,7 @@ import Distribution.PackageDescription import Distribution.Pretty import Distribution.Simple.Errors import Distribution.Simple.LocalBuildInfo +import Distribution.Simple.PreProcess.Types (builtinHaskellSuffixes) import Distribution.Simple.Setup.Common (defaultDistPref) import Distribution.Simple.Setup.Haddock (HaddockTarget (..)) import Distribution.Simple.Utils @@ -189,7 +190,7 @@ getSourceFiles -> IO [(ModuleName.ModuleName, FilePath)] getSourceFiles verbosity dirs modules = flip traverse modules $ \m -> fmap ((,) m) $ - findFileWithExtension ["hs", "lhs", "hsig", "lhsig"] dirs (ModuleName.toFilePath m) + findFileWithExtension builtinHaskellSuffixes dirs (ModuleName.toFilePath m) >>= maybe (notFound m) (return . normalise) where notFound module_ = diff --git a/Cabal/src/Distribution/Simple/BuildTarget.hs b/Cabal/src/Distribution/Simple/BuildTarget.hs index 89b6e275113..06b387c04ae 100644 --- a/Cabal/src/Distribution/Simple/BuildTarget.hs +++ b/Cabal/src/Distribution/Simple/BuildTarget.hs @@ -1,5 +1,7 @@ {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- @@ -1041,64 +1043,68 @@ checkBuildTargets -> IO [TargetInfo] checkBuildTargets _ pkg_descr lbi [] = return (allTargetsInBuildOrder' pkg_descr lbi) -checkBuildTargets verbosity pkg_descr lbi targets = do - let (enabled, disabled) = - partitionEithers - [ case componentDisabledReason (componentEnabledSpec lbi) comp of - Nothing -> Left target' - Just reason -> Right (cname, reason) - | target <- targets - , let target'@(cname, _) = swizzleTarget target - , let comp = getComponent pkg_descr cname - ] - - case disabled of - [] -> return () - ((cname, reason) : _) -> dieWithException verbosity $ CheckBuildTargets $ formatReason (showComponentName cname) reason - - for_ [(c, t) | (c, Just t) <- enabled] $ \(c, t) -> - warn verbosity $ - "Ignoring '" - ++ either prettyShow id t - ++ ". The whole " - ++ showComponentName c - ++ " will be processed. (Support for " - ++ "module and file targets has not been implemented yet.)" - - -- Pick out the actual CLBIs for each of these cnames - enabled' <- for enabled $ \(cname, _) -> do - case componentNameTargets' pkg_descr lbi cname of - [] -> error "checkBuildTargets: nothing enabled" - [target] -> return target - _targets -> error "checkBuildTargets: multiple copies enabled" - - return enabled' - where - swizzleTarget (BuildTargetComponent c) = (c, Nothing) - swizzleTarget (BuildTargetModule c m) = (c, Just (Left m)) - swizzleTarget (BuildTargetFile c f) = (c, Just (Right f)) - - formatReason cn DisabledComponent = - "Cannot process the " - ++ cn - ++ " because the component is marked " - ++ "as disabled in the .cabal file." - formatReason cn DisabledAllTests = - "Cannot process the " - ++ cn - ++ " because test suites are not " - ++ "enabled. Run configure with the flag --enable-tests" - formatReason cn DisabledAllBenchmarks = - "Cannot process the " - ++ cn - ++ " because benchmarks are not " - ++ "enabled. Re-run configure with the flag --enable-benchmarks" - formatReason cn (DisabledAllButOne cn') = - "Cannot process the " - ++ cn - ++ " because this package was " - ++ "configured only to build " - ++ cn' - ++ ". Re-run configure " - ++ "with the argument " - ++ cn +checkBuildTargets + verbosity + pkg_descr + lbi@(LocalBuildInfo{componentEnabledSpec = enabledComps}) + targets = do + let (enabled, disabled) = + partitionEithers + [ case componentDisabledReason enabledComps comp of + Nothing -> Left target' + Just reason -> Right (cname, reason) + | target <- targets + , let target'@(cname, _) = swizzleTarget target + , let comp = getComponent pkg_descr cname + ] + + case disabled of + [] -> return () + ((cname, reason) : _) -> dieWithException verbosity $ CheckBuildTargets $ formatReason (showComponentName cname) reason + + for_ [(c, t) | (c, Just t) <- enabled] $ \(c, t) -> + warn verbosity $ + "Ignoring '" + ++ either prettyShow id t + ++ ". The whole " + ++ showComponentName c + ++ " will be processed. (Support for " + ++ "module and file targets has not been implemented yet.)" + + -- Pick out the actual CLBIs for each of these cnames + enabled' <- for enabled $ \(cname, _) -> do + case componentNameTargets' pkg_descr lbi cname of + [] -> error "checkBuildTargets: nothing enabled" + [target] -> return target + _targets -> error "checkBuildTargets: multiple copies enabled" + + return enabled' + where + swizzleTarget (BuildTargetComponent c) = (c, Nothing) + swizzleTarget (BuildTargetModule c m) = (c, Just (Left m)) + swizzleTarget (BuildTargetFile c f) = (c, Just (Right f)) + + formatReason cn DisabledComponent = + "Cannot process the " + ++ cn + ++ " because the component is marked " + ++ "as disabled in the .cabal file." + formatReason cn DisabledAllTests = + "Cannot process the " + ++ cn + ++ " because test suites are not " + ++ "enabled. Run configure with the flag --enable-tests" + formatReason cn DisabledAllBenchmarks = + "Cannot process the " + ++ cn + ++ " because benchmarks are not " + ++ "enabled. Re-run configure with the flag --enable-benchmarks" + formatReason cn (DisabledAllButOne cn') = + "Cannot process the " + ++ cn + ++ " because this package was " + ++ "configured only to build " + ++ cn' + ++ ". Re-run configure " + ++ "with the argument " + ++ cn diff --git a/Cabal/src/Distribution/Simple/BuildToolDepends.hs b/Cabal/src/Distribution/Simple/BuildToolDepends.hs index 486cd2049d9..01592a0970e 100644 --- a/Cabal/src/Distribution/Simple/BuildToolDepends.hs +++ b/Cabal/src/Distribution/Simple/BuildToolDepends.hs @@ -13,7 +13,34 @@ import qualified Data.Map as Map import Distribution.Package import Distribution.PackageDescription --- | Desugar a "build-tools" entry into proper a executable dependency if +-- | Same as 'desugarBuildTool', but requires atomic informations (package +-- name, executable names) instead of a whole 'PackageDescription'. +desugarBuildToolSimple + :: PackageName + -> [UnqualComponentName] + -> LegacyExeDependency + -> Maybe ExeDependency +desugarBuildToolSimple pname exeNames (LegacyExeDependency name reqVer) + | foundLocal = Just $ ExeDependency pname toolName reqVer + | otherwise = Map.lookup name allowMap + where + toolName = mkUnqualComponentName name + foundLocal = toolName `elem` exeNames + allowlist = + [ "hscolour" + , "haddock" + , "happy" + , "alex" + , "hsc2hs" + , "c2hs" + , "cpphs" + , "greencard" + , "hspec-discover" + ] + allowMap = Map.fromList $ flip map allowlist $ \n -> + (n, ExeDependency (mkPackageName n) (mkUnqualComponentName n) reqVer) + +-- | Desugar a "build-tools" entry into a proper executable dependency if -- possible. -- -- An entry can be so desugared in two cases: @@ -31,26 +58,10 @@ desugarBuildTool -> LegacyExeDependency -> Maybe ExeDependency desugarBuildTool pkg led = - if foundLocal - then Just $ ExeDependency (packageName pkg) toolName reqVer - else Map.lookup name whiteMap - where - LegacyExeDependency name reqVer = led - toolName = mkUnqualComponentName name - foundLocal = toolName `elem` map exeName (executables pkg) - whitelist = - [ "hscolour" - , "haddock" - , "happy" - , "alex" - , "hsc2hs" - , "c2hs" - , "cpphs" - , "greencard" - , "hspec-discover" - ] - whiteMap = Map.fromList $ flip map whitelist $ \n -> - (n, ExeDependency (mkPackageName n) (mkUnqualComponentName n) reqVer) + desugarBuildToolSimple + (packageName pkg) + (map exeName $ executables pkg) + led -- | Get everything from "build-tool-depends", along with entries from -- "build-tools" that we know how to desugar. diff --git a/Cabal/src/Distribution/Simple/Command.hs b/Cabal/src/Distribution/Simple/Command.hs index f55a510c8bd..2da6486cba6 100644 --- a/Cabal/src/Distribution/Simple/Command.hs +++ b/Cabal/src/Distribution/Simple/Command.hs @@ -47,6 +47,8 @@ module Distribution.Simple.Command -- ** Running commands , commandsRun + , commandsRunWithFallback + , defaultCommandFallback -- * Option Fields , OptionField (..) @@ -627,70 +629,93 @@ commandAddAction command action = let flags = mkflags (commandDefaultFlags command) in action flags args +-- Print suggested command if edit distance is < 5 +badCommand :: [Command action] -> String -> CommandParse a +badCommand commands' cname = + case eDists of + [] -> CommandErrors [unErr] + (s : _) -> + CommandErrors + [ unErr + , "Maybe you meant `" ++ s ++ "`?\n" + ] + where + eDists = + map fst . List.sortBy (comparing snd) $ + [ (cname', dist) + | -- Note that this is not commandNames, so close suggestions will show + -- hidden commands + (Command cname' _ _ _) <- commands' + , let dist = editDistance cname' cname + , dist < 5 + ] + unErr = "unrecognised command: " ++ cname ++ " (try --help)" + commandsRun :: CommandUI a -> [Command action] -> [String] - -> CommandParse (a, CommandParse action) + -> IO (CommandParse (a, CommandParse action)) commandsRun globalCommand commands args = + commandsRunWithFallback globalCommand commands defaultCommandFallback args + +defaultCommandFallback + :: [Command action] + -> String + -> [String] + -> IO (CommandParse action) +defaultCommandFallback commands' name _cmdArgs = pure $ badCommand commands' name + +commandsRunWithFallback + :: CommandUI a + -> [Command action] + -> ([Command action] -> String -> [String] -> IO (CommandParse action)) + -> [String] + -> IO (CommandParse (a, CommandParse action)) +commandsRunWithFallback globalCommand commands defaultCommand args = case commandParseArgs globalCommand True args of - CommandHelp help -> CommandHelp help - CommandList opts -> CommandList (opts ++ commandNames) - CommandErrors errs -> CommandErrors errs + CommandHelp help -> pure $ CommandHelp help + CommandList opts -> pure $ CommandList (opts ++ commandNames) + CommandErrors errs -> pure $ CommandErrors errs CommandReadyToGo (mkflags, args') -> case args' of - ("help" : cmdArgs) -> handleHelpCommand cmdArgs + ("help" : cmdArgs) -> handleHelpCommand flags cmdArgs (name : cmdArgs) -> case lookupCommand name of [Command _ _ action _] -> - CommandReadyToGo (flags, action cmdArgs) - _ -> CommandReadyToGo (flags, badCommand name) - [] -> CommandReadyToGo (flags, noCommand) + pure $ CommandReadyToGo (flags, action cmdArgs) + _ -> do + final_cmd <- defaultCommand commands' name cmdArgs + return $ CommandReadyToGo (flags, final_cmd) + [] -> pure $ CommandReadyToGo (flags, noCommand) where flags = mkflags (commandDefaultFlags globalCommand) where lookupCommand cname = [ cmd | cmd@(Command cname' _ _ _) <- commands', cname' == cname ] - noCommand = CommandErrors ["no command given (try --help)\n"] - -- Print suggested command if edit distance is < 5 - badCommand :: String -> CommandParse a - badCommand cname = - case eDists of - [] -> CommandErrors [unErr] - (s : _) -> - CommandErrors - [ unErr - , "Maybe you meant `" ++ s ++ "`?\n" - ] - where - eDists = - map fst . List.sortBy (comparing snd) $ - [ (cname', dist) - | (Command cname' _ _ _) <- commands' - , let dist = editDistance cname' cname - , dist < 5 - ] - unErr = "unrecognised command: " ++ cname ++ " (try --help)" + noCommand = CommandErrors ["no command given (try --help)\n"] commands' = commands ++ [commandAddAction helpCommandUI undefined] commandNames = [name | (Command name _ _ NormalCommand) <- commands'] -- A bit of a hack: support "prog help" as a synonym of "prog --help" -- furthermore, support "prog help command" as "prog command --help" - handleHelpCommand cmdArgs = + handleHelpCommand flags cmdArgs = case commandParseArgs helpCommandUI True cmdArgs of - CommandHelp help -> CommandHelp help - CommandList list -> CommandList (list ++ commandNames) - CommandErrors _ -> CommandHelp globalHelp - CommandReadyToGo (_, []) -> CommandHelp globalHelp + CommandHelp help -> pure $ CommandHelp help + CommandList list -> pure $ CommandList (list ++ commandNames) + CommandErrors _ -> pure $ CommandHelp globalHelp + CommandReadyToGo (_, []) -> pure $ CommandHelp globalHelp CommandReadyToGo (_, (name : cmdArgs')) -> case lookupCommand name of [Command _ _ action _] -> case action ("--help" : cmdArgs') of - CommandHelp help -> CommandHelp help - CommandList _ -> CommandList [] - _ -> CommandHelp globalHelp - _ -> badCommand name + CommandHelp help -> pure $ CommandHelp help + CommandList _ -> pure $ CommandList [] + _ -> pure $ CommandHelp globalHelp + _ -> do + fall_back <- defaultCommand commands' name ("--help" : cmdArgs') + return $ CommandReadyToGo (flags, fall_back) where globalHelp = commandHelp globalCommand diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs index f35f98f4fcb..d6bffddf365 100644 --- a/Cabal/src/Distribution/Simple/Configure.hs +++ b/Cabal/src/Distribution/Simple/Configure.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} @@ -44,6 +45,7 @@ module Distribution.Simple.Configure , localBuildInfoFile , getInstalledPackages , getInstalledPackagesMonitorFiles + , getInstalledPackagesById , getPackageDBContents , configCompilerEx , configCompilerAuxEx @@ -56,6 +58,7 @@ module Distribution.Simple.Configure , platformDefines ) where +import Control.Monad import Distribution.Compat.Prelude import Prelude () @@ -78,16 +81,18 @@ import Distribution.Simple.BuildTarget import Distribution.Simple.BuildToolDepends import Distribution.Simple.Compiler import Distribution.Simple.LocalBuildInfo -import Distribution.Simple.PackageIndex (InstalledPackageIndex) +import Distribution.Simple.PackageIndex (InstalledPackageIndex, lookupUnitId) import qualified Distribution.Simple.PackageIndex as PackageIndex import Distribution.Simple.PreProcess import Distribution.Simple.Program +import Distribution.Simple.Program.Db (lookupProgramByName, modifyProgramSearchPath, prependProgramSearchPath) import Distribution.Simple.Setup.Common as Setup import Distribution.Simple.Setup.Config as Setup import Distribution.Simple.Utils import Distribution.System import Distribution.Types.ComponentRequestedSpec import Distribution.Types.GivenComponent +import qualified Distribution.Types.LocalBuildConfig as LBC import Distribution.Types.LocalBuildInfo import Distribution.Types.PackageVersionConstraint import Distribution.Utils.LogProgress @@ -407,14 +412,32 @@ configure :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo -configure (pkg_descr0, pbi) cfg = do +configure (g_pkg_descr, hookedBuildInfo) cfg = do + -- Cabal pre-configure + (lbc1, comp, platform, enabledComps) <- preConfigurePackage cfg g_pkg_descr + + -- Cabal package-wide configure + (lbc2, pbd2, pkg_info) <- + finalizeAndConfigurePackage cfg lbc1 g_pkg_descr comp platform enabledComps + + -- Cabal per-component configure + externalPkgDeps <- finalCheckPackage g_pkg_descr pbd2 hookedBuildInfo pkg_info + configureComponents lbc2 pbd2 pkg_info externalPkgDeps + +preConfigurePackage + :: ConfigFlags + -> GenericPackageDescription + -> IO (LBC.LocalBuildConfig, Compiler, Platform, ComponentRequestedSpec) +preConfigurePackage cfg g_pkg_descr = do + let verbosity = fromFlag (configVerbosity cfg) + -- Determine the component we are configuring, if a user specified -- one on the command line. We use a fake, flattened version of -- the package since at this point, we're not really sure what -- components we *can* configure. @Nothing@ means that we should -- configure everything (the old behavior). (mb_cname :: Maybe ComponentName) <- do - let flat_pkg_descr = flattenPackageDescription pkg_descr0 + let flat_pkg_descr = flattenPackageDescription g_pkg_descr targets <- readBuildTargets verbosity flat_pkg_descr (configArgs cfg) -- TODO: bleat if you use the module/file syntax let targets' = [cname | BuildTargetComponent cname <- targets] @@ -424,14 +447,13 @@ configure (pkg_descr0, pbi) cfg = do [] -> dieWithException verbosity NoValidComponent _ -> dieWithException verbosity ConfigureEitherSingleOrAll - let use_external_internal_deps = isJust mb_cname case mb_cname of - Nothing -> setupMessage verbosity "Configuring" (packageId pkg_descr0) + Nothing -> setupMessage verbosity "Configuring" (packageId g_pkg_descr) Just cname -> setupMessage' verbosity "Configuring" - (packageId pkg_descr0) + (packageId g_pkg_descr) cname (Just (configInstantiateWith cfg)) @@ -439,51 +461,6 @@ configure (pkg_descr0, pbi) cfg = do when (isJust (flagToMaybe (configCID cfg)) && isNothing mb_cname) $ dieWithException verbosity ConfigCIDValidForPreComponent - checkDeprecatedFlags verbosity cfg - checkExactConfiguration verbosity pkg_descr0 cfg - - -- Where to build the package - let buildDir :: FilePath -- e.g. dist/build - -- fromFlag OK due to Distribution.Simple calling - -- findDistPrefOrDefault to fill it in - buildDir = fromFlag (configDistPref cfg) "build" - createDirectoryIfMissingVerbose (lessVerbose verbosity) True buildDir - - -- What package database(s) to use - let packageDbs :: PackageDBStack - packageDbs = - interpretPackageDbFlags - (fromFlag (configUserInstall cfg)) - (configPackageDBs cfg) - - -- comp: the compiler we're building with - -- compPlatform: the platform we're building for - -- programDb: location and args of all programs we're - -- building with - ( comp :: Compiler - , compPlatform :: Platform - , programDb :: ProgramDb - ) <- - configCompilerEx - (flagToMaybe (configHcFlavor cfg)) - (flagToMaybe (configHcPath cfg)) - (flagToMaybe (configHcPkg cfg)) - (mkProgramDb cfg (configPrograms cfg)) - (lessVerbose verbosity) - - -- The InstalledPackageIndex of all installed packages - installedPackageSet :: InstalledPackageIndex <- - getInstalledPackages - (lessVerbose verbosity) - comp - packageDbs - programDb - - -- The set of package names which are "shadowed" by internal - -- packages, and which component they map to - let internalPackageSet :: Set LibraryName - internalPackageSet = getInternalLibraries pkg_descr0 - -- Make a data structure describing what components are enabled. let enabled :: ComponentRequestedSpec enabled = case mb_cname of @@ -508,221 +485,43 @@ configure (pkg_descr0, pbi) cfg = do ) $ dieWithException verbosity SanityCheckForEnableComponents - -- Some sanity checks related to dynamic/static linking. - when (fromFlag (configDynExe cfg) && fromFlag (configFullyStaticExe cfg)) $ - dieWithException verbosity SanityCheckForDynamicStaticLinking - - -- allConstraints: The set of all 'Dependency's we have. Used ONLY - -- to 'configureFinalizedPackage'. - -- requiredDepsMap: A map from 'PackageName' to the specifically - -- required 'InstalledPackageInfo', due to --dependency - -- - -- NB: These constraints are to be applied to ALL components of - -- a package. Thus, it's not an error if allConstraints contains - -- more constraints than is necessary for a component (another - -- component might need it.) - -- - -- NB: The fact that we bundle all the constraints together means - -- that is not possible to configure a test-suite to use one - -- version of a dependency, and the executable to use another. - ( allConstraints :: [PackageVersionConstraint] - , requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo - ) <- - either (dieWithException verbosity) return $ - combinedConstraints - (configConstraints cfg) - (configDependencies cfg) - installedPackageSet - - let promisedDepsSet = mkPromisedDepsSet (configPromisedDependencies cfg) + checkDeprecatedFlags verbosity cfg + checkExactConfiguration verbosity g_pkg_descr cfg - -- pkg_descr: The resolved package description, that does not contain any - -- conditionals, because we have an assignment for - -- every flag, either picking them ourselves using a - -- simple naive algorithm, or having them be passed to - -- us by 'configConfigurationsFlags') - -- flags: The 'FlagAssignment' that the conditionals were - -- resolved with. - -- - -- NB: Why doesn't finalizing a package also tell us what the - -- dependencies are (e.g. when we run the naive algorithm, - -- we are checking if dependencies are satisfiable)? The - -- primary reason is that we may NOT have done any solving: - -- if the flags are all chosen for us, this step is a simple - -- matter of flattening according to that assignment. It's - -- cleaner to then configure the dependencies afterwards. - ( pkg_descr :: PackageDescription - , flags :: FlagAssignment + programDbPre <- mkProgramDb cfg (configPrograms cfg) + -- comp: the compiler we're building with + -- compPlatform: the platform we're building for + -- programDb: location and args of all programs we're + -- building with + ( comp :: Compiler + , compPlatform :: Platform + , programDb00 :: ProgramDb ) <- - configureFinalizedPackage - verbosity - cfg - enabled - allConstraints - ( dependencySatisfiable - use_external_internal_deps - (fromFlagOrDefault False (configExactConfiguration cfg)) - (fromFlagOrDefault False (configAllowDependingOnPrivateLibs cfg)) - (packageName pkg_descr0) - installedPackageSet - internalPackageSet - promisedDepsSet - requiredDepsMap - ) - comp - compPlatform - pkg_descr0 - - debug verbosity $ - "Finalized package description:\n" - ++ showPackageDescription pkg_descr - - let cabalFileDir = - maybe "." takeDirectory $ - flagToMaybe (configCabalFilePath cfg) - checkCompilerProblems verbosity comp pkg_descr enabled - checkPackageProblems - verbosity - cabalFileDir - pkg_descr0 - (updatePackageDescription pbi pkg_descr) - - -- The list of 'InstalledPackageInfo' recording the selected - -- dependencies on external packages. - -- - -- Invariant: For any package name, there is at most one package - -- in externalPackageDeps which has that name. - -- - -- NB: The dependency selection is global over ALL components - -- in the package (similar to how allConstraints and - -- requiredDepsMap are global over all components). In particular, - -- if *any* component (post-flag resolution) has an unsatisfiable - -- dependency, we will fail. This can sometimes be undesirable - -- for users, see #1786 (benchmark conflicts with executable), - -- - -- In the presence of Backpack, these package dependencies are - -- NOT complete: they only ever include the INDEFINITE - -- dependencies. After we apply an instantiation, we'll get - -- definite references which constitute extra dependencies. - -- (Why not have cabal-install pass these in explicitly? - -- For one it's deterministic; for two, we need to associate - -- them with renamings which would require a far more complicated - -- input scheme than what we have today.) - externalPkgDeps :: ([PreExistingComponent], [PromisedComponent]) <- - configureDependencies - verbosity - use_external_internal_deps - internalPackageSet - promisedDepsSet - installedPackageSet - requiredDepsMap - pkg_descr - enabled - - -- Compute installation directory templates, based on user - -- configuration. - -- - -- TODO: Move this into a helper function. - defaultDirs :: InstallDirTemplates <- - defaultInstallDirs' - use_external_internal_deps - (compilerFlavor comp) - (fromFlag (configUserInstall cfg)) - (hasLibs pkg_descr) - let installDirs :: InstallDirTemplates - installDirs = - combineInstallDirs - fromFlagOrDefault - defaultDirs - (configInstallDirs cfg) - - -- Check languages and extensions - -- TODO: Move this into a helper function. - let langlist = - nub $ - catMaybes $ - map - defaultLanguage - (enabledBuildInfos pkg_descr enabled) - let langs = unsupportedLanguages comp langlist - when (not (null langs)) $ - dieWithException verbosity $ - UnsupportedLanguages (packageId pkg_descr0) (compilerId comp) (map prettyShow langs) - let extlist = - nub $ - concatMap - allExtensions - (enabledBuildInfos pkg_descr enabled) - let exts = unsupportedExtensions comp extlist - when (not (null exts)) $ - dieWithException verbosity $ - UnsupportedLanguageExtension (packageId pkg_descr0) (compilerId comp) (map prettyShow exts) - - -- Check foreign library build requirements - let flibs = [flib | CFLib flib <- enabledComponents pkg_descr enabled] - let unsupportedFLibs = unsupportedForeignLibs comp compPlatform flibs - when (not (null unsupportedFLibs)) $ - dieWithException verbosity $ - CantFindForeignLibraries unsupportedFLibs - - -- Configure certain external build tools, see below for which ones. - let requiredBuildTools = do - bi <- enabledBuildInfos pkg_descr enabled - -- First, we collect any tool dep that we know is external. This is, - -- in practice: - -- - -- 1. `build-tools` entries on the whitelist - -- - -- 2. `build-tool-depends` that aren't from the current package. - let externBuildToolDeps = - [ LegacyExeDependency (unUnqualComponentName eName) versionRange - | buildTool@(ExeDependency _ eName versionRange) <- - getAllToolDependencies pkg_descr bi - , not $ isInternal pkg_descr buildTool - ] - -- Second, we collect any build-tools entry we don't know how to - -- desugar. We'll never have any idea how to build them, so we just - -- hope they are already on the PATH. - let unknownBuildTools = - [ buildTool - | buildTool <- buildTools bi - , Nothing == desugarBuildTool pkg_descr buildTool - ] - externBuildToolDeps ++ unknownBuildTools - - programDb' <- - configureAllKnownPrograms (lessVerbose verbosity) programDb - >>= configureRequiredPrograms verbosity requiredBuildTools + configCompilerEx + (flagToMaybe (configHcFlavor cfg)) + (flagToMaybe (configHcPath cfg)) + (flagToMaybe (configHcPkg cfg)) + programDbPre + (lessVerbose verbosity) - (pkg_descr', programDb'') <- - configurePkgconfigPackages verbosity pkg_descr programDb' enabled + -- Where to build the package + let build_dir :: FilePath -- e.g. dist/build + build_dir = configFlagsBuildDir cfg + -- NB: create this directory now so that all configure hooks get + -- to see it. (In practice, the Configure build-type needs it before + -- the postConfPackageHook runs.) + createDirectoryIfMissingVerbose (lessVerbose verbosity) True build_dir - -- Compute internal component graph - -- - -- The general idea is that we take a look at all the source level - -- components (which may build-depends on each other) and form a graph. - -- From there, we build a ComponentLocalBuildInfo for each of the - -- components, which lets us actually build each component. - -- internalPackageSet - -- use_external_internal_deps - ( buildComponents :: [ComponentLocalBuildInfo] - , packageDependsIndex :: InstalledPackageIndex - ) <- - runLogProgress verbosity $ - configureComponentLocalBuildInfos - verbosity - use_external_internal_deps - enabled - (fromFlagOrDefault False (configDeterministic cfg)) - (configIPID cfg) - (configCID cfg) - pkg_descr - externalPkgDeps - (configConfigurationsFlags cfg) - (configInstantiateWith cfg) - installedPackageSet - comp + lbc <- computeLocalBuildConfig cfg comp programDb00 + return (lbc, comp, compPlatform, enabled) +computeLocalBuildConfig + :: ConfigFlags + -> Compiler + -> ProgramDb + -> IO LBC.LocalBuildConfig +computeLocalBuildConfig cfg comp programDb = do + let verbosity = fromFlag (configVerbosity cfg) -- Decide if we're going to compile with split sections. split_sections :: Bool <- if not (fromFlag $ configSplitSections cfg) @@ -767,22 +566,16 @@ configure (pkg_descr0, pbi) cfg = do ) return False - let compilerSupportsGhciLibs :: Bool - compilerSupportsGhciLibs = - case compilerId comp of - CompilerId GHC version - | version > mkVersion [9, 3] && windows -> - False - CompilerId GHC _ -> - True - CompilerId GHCJS _ -> - True - _ -> False - where - windows = case compPlatform of - Platform _ Windows -> True - Platform _ _ -> False - + -- Basically yes/no/unknown. + let linkerSupportsRelocations :: Maybe Bool + linkerSupportsRelocations = + case lookupProgramByName "ld" programDb of + Nothing -> Nothing + Just ld -> + case Map.lookup "Supports relocatable output" $ programProperties ld of + Just "YES" -> Just True + Just "NO" -> Just False + _other -> Nothing let ghciLibByDefault = case compilerId comp of CompilerId GHC _ -> @@ -801,10 +594,12 @@ configure (pkg_descr0, pbi) cfg = do withGHCiLib_ <- case fromFlagOrDefault ghciLibByDefault (configGHCiLib cfg) of - True | not compilerSupportsGhciLibs -> do + -- NOTE: If linkerSupportsRelocations is Nothing this may still fail if the + -- linker does not support -r. + True | not (fromMaybe True linkerSupportsRelocations) -> do warn verbosity $ - "--enable-library-for-ghci is no longer supported on Windows with" - ++ " GHC 9.4 and later; ignoring..." + "--enable-library-for-ghci is not supported with the current" + ++ " linker; ignoring..." return False v -> return v @@ -843,9 +638,9 @@ configure (pkg_descr0, pbi) cfg = do ++ "is not being built. Linking will fail if any executables " ++ "depend on the library." - setProfLBI <- configureProfiling verbosity cfg comp + setProfiling <- configureProfiling verbosity cfg comp - setCoverageLBI <- configureCoverage verbosity cfg comp + setCoverage <- configureCoverage verbosity cfg comp -- Turn off library and executable stripping when `debug-info` is set -- to anything other than zero. @@ -866,42 +661,10 @@ configure (pkg_descr0, pbi) cfg = do strip_lib <- strip_libexe "library" configStripLibs strip_exe <- strip_libexe "executable" configStripExes - let reloc = fromFlagOrDefault False $ configRelocatable cfg - - let buildComponentsMap = - foldl' - ( \m clbi -> - Map.insertWith - (++) - (componentLocalName clbi) - [clbi] - m - ) - Map.empty - buildComponents - - let lbi = - (setCoverageLBI . setProfLBI) - LocalBuildInfo - { configFlags = cfg - , flagAssignment = flags - , componentEnabledSpec = enabled - , extraConfigArgs = [] -- Currently configure does not - -- take extra args, but if it - -- did they would go here. - , installDirTemplates = installDirs - , compiler = comp - , hostPlatform = compPlatform - , buildDir = buildDir - , cabalFilePath = flagToMaybe (configCabalFilePath cfg) - , componentGraph = Graph.fromDistinctList buildComponents - , componentNameMap = buildComponentsMap - , installedPkgs = packageDependsIndex - , promisedPkgs = promisedDepsSet - , pkgDescrFile = Nothing - , localPkgDescr = pkg_descr' - , withPrograms = programDb'' - , withVanillaLib = fromFlag $ configVanillaLib cfg + let buildOptions = + setCoverage . setProfiling $ + LBC.BuildOptions + { withVanillaLib = fromFlag $ configVanillaLib cfg , withSharedLib = withSharedLib_ , withStaticLib = withStaticLib_ , withDynExe = withDynExe_ @@ -919,95 +682,569 @@ configure (pkg_descr0, pbi) cfg = do , stripLibs = strip_lib , exeCoverage = False , libCoverage = False - , withPackageDB = packageDbs - , progPrefix = fromFlag $ configProgPrefix cfg - , progSuffix = fromFlag $ configProgSuffix cfg - , relocatable = reloc + , relocatable = fromFlagOrDefault False $ configRelocatable cfg } - when reloc (checkRelocatable verbosity pkg_descr lbi) + return $ + LBC.LocalBuildConfig + { extraConfigArgs = [] -- Currently configure does not + -- take extra args, but if it + -- did they would go here. + , withPrograms = programDb + , withBuildOptions = buildOptions + } + +data PackageInfo = PackageInfo + { internalPackageSet :: Set LibraryName + , promisedDepsSet :: Map (PackageName, ComponentName) ComponentId + , installedPackageSet :: InstalledPackageIndex + , requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo + } + +configurePackage + :: ConfigFlags + -> LBC.LocalBuildConfig + -> PackageDescription + -> FlagAssignment + -> ComponentRequestedSpec + -> Compiler + -> Platform + -> ProgramDb + -> PackageDBStack + -> IO (LBC.LocalBuildConfig, LBC.PackageBuildDescr) +configurePackage cfg lbc0 pkg_descr00 flags enabled comp platform programDb0 packageDbs = do + let verbosity = fromFlag (configVerbosity cfg) + + -- add extra include/lib dirs as specified in cfg + pkg_descr0 = addExtraIncludeLibDirsFromConfigFlags pkg_descr00 cfg + -- TODO: it is not clear whether this adding these dirs is necessary + -- when we are directly stating from a PackageDescription (e.g. when + -- cabal-install has determined a PackageDescription, instead of rediscovering + -- when working with a GenericPackageDescription). + -- Could this function call be moved to the end of finalizeAndConfigurePackage + -- right before calling configurePackage? - -- TODO: This is not entirely correct, because the dirs may vary - -- across libraries/executables - let dirs = absoluteInstallDirs pkg_descr lbi NoCopyDest - relative = prefixRelativeInstallDirs (packageId pkg_descr) lbi + -- Configure certain external build tools, see below for which ones. + let requiredBuildTools = do + bi <- enabledBuildInfos pkg_descr0 enabled + -- First, we collect any tool dep that we know is external. This is, + -- in practice: + -- + -- 1. `build-tools` entries on the whitelist + -- + -- 2. `build-tool-depends` that aren't from the current package. + let externBuildToolDeps = + [ LegacyExeDependency (unUnqualComponentName eName) versionRange + | buildTool@(ExeDependency _ eName versionRange) <- + getAllToolDependencies pkg_descr0 bi + , not $ isInternal pkg_descr0 buildTool + ] + -- Second, we collect any build-tools entry we don't know how to + -- desugar. We'll never have any idea how to build them, so we just + -- hope they are already on the PATH. + let unknownBuildTools = + [ buildTool + | buildTool <- buildTools bi + , Nothing == desugarBuildTool pkg_descr0 buildTool + ] + externBuildToolDeps ++ unknownBuildTools + + programDb1 <- + configureAllKnownPrograms (lessVerbose verbosity) programDb0 + >>= configureRequiredPrograms verbosity requiredBuildTools - -- PKGROOT: allowing ${pkgroot} to be passed as --prefix to - -- cabal configure, is only a hidden option. It allows packages - -- to be relocatable with their package database. This however - -- breaks when the Paths_* or other includes are used that - -- contain hard coded paths. This is still an open TODO. + (pkg_descr2, programDb2) <- + configurePkgconfigPackages verbosity pkg_descr0 programDb1 enabled + + let use_external_internal_deps = + case enabled of + OneComponentRequestedSpec{} -> True + ComponentRequestedSpec{} -> False + + -- Compute installation directory templates, based on user + -- configuration. -- - -- Allowing ${pkgroot} here, however requires less custom hooks - -- in scripts that *really* want ${pkgroot}. See haskell/cabal/#4872 - unless - ( isAbsolute (prefix dirs) - || "${pkgroot}" `isPrefixOf` prefix dirs + -- TODO: Move this into a helper function. + defaultDirs :: InstallDirTemplates <- + defaultInstallDirs' + use_external_internal_deps + (compilerFlavor comp) + (fromFlag (configUserInstall cfg)) + (hasLibs pkg_descr2) + let + installDirs = + combineInstallDirs + fromFlagOrDefault + defaultDirs + (configInstallDirs cfg) + lbc = lbc0{LBC.withPrograms = programDb2} + pbd = + LBC.PackageBuildDescr + { configFlags = cfg + , flagAssignment = flags + , componentEnabledSpec = enabled + , compiler = comp + , hostPlatform = platform + , localPkgDescr = pkg_descr2 + , installDirTemplates = installDirs + , withPackageDB = packageDbs + , pkgDescrFile = Nothing + , extraCoverageFor = [] + } + + debug verbosity $ + "Finalized package description:\n" + ++ showPackageDescription pkg_descr2 + + return (lbc, pbd) + +finalizeAndConfigurePackage + :: ConfigFlags + -> LBC.LocalBuildConfig + -> GenericPackageDescription + -> Compiler + -> Platform + -> ComponentRequestedSpec + -> IO (LBC.LocalBuildConfig, LBC.PackageBuildDescr, PackageInfo) +finalizeAndConfigurePackage cfg lbc0 g_pkg_descr comp platform enabled = do + let verbosity = fromFlag (configVerbosity cfg) + + let programDb0 = LBC.withPrograms lbc0 + -- What package database(s) to use + packageDbs :: PackageDBStack + packageDbs = + interpretPackageDbFlags + (fromFlag (configUserInstall cfg)) + (configPackageDBs cfg) + + -- The InstalledPackageIndex of all installed packages + installedPackageSet :: InstalledPackageIndex <- + getInstalledPackages + (lessVerbose verbosity) + comp + packageDbs + programDb0 + + -- The set of package names which are "shadowed" by internal + -- packages, and which component they map to + let internalPackageSet :: Set LibraryName + internalPackageSet = getInternalLibraries g_pkg_descr + + -- Some sanity checks related to dynamic/static linking. + when (fromFlag (configDynExe cfg) && fromFlag (configFullyStaticExe cfg)) $ + dieWithException verbosity SanityCheckForDynamicStaticLinking + + -- allConstraints: The set of all 'Dependency's we have. Used ONLY + -- to 'configureFinalizedPackage'. + -- requiredDepsMap: A map from 'PackageName' to the specifically + -- required 'InstalledPackageInfo', due to --dependency + -- + -- NB: These constraints are to be applied to ALL components of + -- a package. Thus, it's not an error if allConstraints contains + -- more constraints than is necessary for a component (another + -- component might need it.) + -- + -- NB: The fact that we bundle all the constraints together means + -- that is not possible to configure a test-suite to use one + -- version of a dependency, and the executable to use another. + ( allConstraints :: [PackageVersionConstraint] + , requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo + ) <- + either (dieWithException verbosity) return $ + combinedConstraints + (configConstraints cfg) + (configDependencies cfg) + installedPackageSet + + let + promisedDepsSet = mkPromisedDepsSet (configPromisedDependencies cfg) + pkg_info = + PackageInfo + { internalPackageSet + , promisedDepsSet + , installedPackageSet + , requiredDepsMap + } + + -- pkg_descr: The resolved package description, that does not contain any + -- conditionals, because we have an assignment for + -- every flag, either picking them ourselves using a + -- simple naive algorithm, or having them be passed to + -- us by 'configConfigurationsFlags') + -- flags: The 'FlagAssignment' that the conditionals were + -- resolved with. + -- + -- NB: Why doesn't finalizing a package also tell us what the + -- dependencies are (e.g. when we run the naive algorithm, + -- we are checking if dependencies are satisfiable)? The + -- primary reason is that we may NOT have done any solving: + -- if the flags are all chosen for us, this step is a simple + -- matter of flattening according to that assignment. It's + -- cleaner to then configure the dependencies afterwards. + let use_external_internal_deps = case enabled of + OneComponentRequestedSpec{} -> True + ComponentRequestedSpec{} -> False + ( pkg_descr0 :: PackageDescription + , flags :: FlagAssignment + ) <- + configureFinalizedPackage + verbosity + cfg + enabled + allConstraints + ( dependencySatisfiable + use_external_internal_deps + (fromFlagOrDefault False (configExactConfiguration cfg)) + (fromFlagOrDefault False (configAllowDependingOnPrivateLibs cfg)) + (packageName g_pkg_descr) + installedPackageSet + internalPackageSet + promisedDepsSet + requiredDepsMap + ) + comp + platform + g_pkg_descr + + (lbc, pbd) <- + configurePackage + cfg + lbc0 + pkg_descr0 + flags + enabled + comp + platform + programDb0 + packageDbs + return (lbc, pbd, pkg_info) + +addExtraIncludeLibDirsFromConfigFlags + :: PackageDescription -> ConfigFlags -> PackageDescription +addExtraIncludeLibDirsFromConfigFlags pkg_descr cfg = + let extraBi = + mempty + { extraLibDirs = configExtraLibDirs cfg + , extraLibDirsStatic = configExtraLibDirsStatic cfg + , extraFrameworkDirs = configExtraFrameworkDirs cfg + , includeDirs = configExtraIncludeDirs cfg + } + modifyLib l = + l + { libBuildInfo = + libBuildInfo l + `mappend` extraBi + } + modifyExecutable e = + e + { buildInfo = + buildInfo e + `mappend` extraBi + } + modifyForeignLib f = + f + { foreignLibBuildInfo = + foreignLibBuildInfo f + `mappend` extraBi + } + modifyTestsuite t = + t + { testBuildInfo = + testBuildInfo t + `mappend` extraBi + } + modifyBenchmark b = + b + { benchmarkBuildInfo = + benchmarkBuildInfo b + `mappend` extraBi + } + in pkg_descr + { library = modifyLib `fmap` library pkg_descr + , subLibraries = modifyLib `map` subLibraries pkg_descr + , executables = modifyExecutable `map` executables pkg_descr + , foreignLibs = modifyForeignLib `map` foreignLibs pkg_descr + , testSuites = modifyTestsuite `map` testSuites pkg_descr + , benchmarks = modifyBenchmark `map` benchmarks pkg_descr + } + +finalCheckPackage + :: GenericPackageDescription + -> LBC.PackageBuildDescr + -> HookedBuildInfo + -> PackageInfo + -> IO ([PreExistingComponent], [PromisedComponent]) +finalCheckPackage + g_pkg_descr + ( LBC.PackageBuildDescr + { configFlags = cfg + , localPkgDescr = pkg_descr + , compiler = comp + , hostPlatform = compPlatform + , componentEnabledSpec = enabled + } ) - $ dieWithException verbosity - $ ExpectedAbsoluteDirectory (prefix dirs) + hookedBuildInfo + (PackageInfo{internalPackageSet, promisedDepsSet, installedPackageSet, requiredDepsMap}) = + do + let verbosity = fromFlag (configVerbosity cfg) + use_external_internal_deps = + case enabled of + OneComponentRequestedSpec{} -> True + ComponentRequestedSpec{} -> False + + let cabalFileDir = + maybe "." takeDirectory $ + flagToMaybe (configCabalFilePath cfg) + checkCompilerProblems verbosity comp pkg_descr enabled + checkPackageProblems + verbosity + cabalFileDir + g_pkg_descr + (updatePackageDescription hookedBuildInfo pkg_descr) + -- NB: we apply the HookedBuildInfo to check it is valid, + -- but we don't propagate it. + -- Other UserHooks must separately return it again, and we + -- will re-apply it each time. + + -- Check languages and extensions + -- TODO: Move this into a helper function. + let langlist = + nub $ + catMaybes $ + map + defaultLanguage + (enabledBuildInfos pkg_descr enabled) + let langs = unsupportedLanguages comp langlist + when (not (null langs)) $ + dieWithException verbosity $ + UnsupportedLanguages (packageId g_pkg_descr) (compilerId comp) (map prettyShow langs) + let extlist = + nub $ + concatMap + allExtensions + (enabledBuildInfos pkg_descr enabled) + let exts = unsupportedExtensions comp extlist + when (not (null exts)) $ + dieWithException verbosity $ + UnsupportedLanguageExtension (packageId g_pkg_descr) (compilerId comp) (map prettyShow exts) - when ("${pkgroot}" `isPrefixOf` prefix dirs) $ - warn verbosity $ - "Using ${pkgroot} in prefix " - ++ prefix dirs - ++ " will not work if you rely on the Path_* module " - ++ " or other hard coded paths. Cabal does not yet " - ++ " support fully relocatable builds! " - ++ " See #462 #2302 #2994 #3305 #3473 #3586 #3909" - ++ " #4097 #4291 #4872" + -- Check foreign library build requirements + let flibs = [flib | CFLib flib <- enabledComponents pkg_descr enabled] + let unsupportedFLibs = unsupportedForeignLibs comp compPlatform flibs + when (not (null unsupportedFLibs)) $ + dieWithException verbosity $ + CantFindForeignLibraries unsupportedFLibs + + -- The list of 'InstalledPackageInfo' recording the selected + -- dependencies on external packages. + -- + -- Invariant: For any package name, there is at most one package + -- in externalPackageDeps which has that name. + -- + -- NB: The dependency selection is global over ALL components + -- in the package (similar to how allConstraints and + -- requiredDepsMap are global over all components). In particular, + -- if *any* component (post-flag resolution) has an unsatisfiable + -- dependency, we will fail. This can sometimes be undesirable + -- for users, see #1786 (benchmark conflicts with executable), + -- + -- In the presence of Backpack, these package dependencies are + -- NOT complete: they only ever include the INDEFINITE + -- dependencies. After we apply an instantiation, we'll get + -- definite references which constitute extra dependencies. + -- (Why not have cabal-install pass these in explicitly? + -- For one it's deterministic; for two, we need to associate + -- them with renamings which would require a far more complicated + -- input scheme than what we have today.) + configureDependencies + verbosity + use_external_internal_deps + internalPackageSet + promisedDepsSet + installedPackageSet + requiredDepsMap + pkg_descr + enabled - info verbosity $ - "Using " - ++ prettyShow currentCabalId - ++ " compiled by " - ++ prettyShow currentCompilerId - info verbosity $ "Using compiler: " ++ showCompilerId comp - info verbosity $ "Using install prefix: " ++ prefix dirs - - let dirinfo name dir isPrefixRelative = - info verbosity $ name ++ " installed in: " ++ dir ++ relNote - where - relNote = case buildOS of - Windows - | not (hasLibs pkg_descr) - && isNothing isPrefixRelative -> - " (fixed location)" - _ -> "" - - dirinfo "Executables" (bindir dirs) (bindir relative) - dirinfo "Libraries" (libdir dirs) (libdir relative) - dirinfo "Dynamic Libraries" (dynlibdir dirs) (dynlibdir relative) - dirinfo "Private executables" (libexecdir dirs) (libexecdir relative) - dirinfo "Data files" (datadir dirs) (datadir relative) - dirinfo "Documentation" (docdir dirs) (docdir relative) - dirinfo "Configuration files" (sysconfdir dirs) (sysconfdir relative) +configureComponents + :: LBC.LocalBuildConfig + -> LBC.PackageBuildDescr + -> PackageInfo + -> ([PreExistingComponent], [PromisedComponent]) + -> IO LocalBuildInfo +configureComponents + lbc@(LBC.LocalBuildConfig{withPrograms = programDb}) + pbd0@( LBC.PackageBuildDescr + { configFlags = cfg + , localPkgDescr = pkg_descr + , compiler = comp + , componentEnabledSpec = enabled + } + ) + (PackageInfo{promisedDepsSet, installedPackageSet}) + externalPkgDeps = + do + let verbosity = fromFlag (configVerbosity cfg) + use_external_internal_deps = + case enabled of + OneComponentRequestedSpec{} -> True + ComponentRequestedSpec{} -> False + + -- Compute internal component graph + -- + -- The general idea is that we take a look at all the source level + -- components (which may build-depends on each other) and form a graph. + -- From there, we build a ComponentLocalBuildInfo for each of the + -- components, which lets us actually build each component. + ( buildComponents :: [ComponentLocalBuildInfo] + , packageDependsIndex :: InstalledPackageIndex + ) <- + runLogProgress verbosity $ + configureComponentLocalBuildInfos + verbosity + use_external_internal_deps + enabled + (fromFlagOrDefault False (configDeterministic cfg)) + (configIPID cfg) + (configCID cfg) + pkg_descr + externalPkgDeps + (configConfigurationsFlags cfg) + (configInstantiateWith cfg) + installedPackageSet + comp + + let buildComponentsMap = + foldl' + ( \m clbi -> + Map.insertWith + (++) + (componentLocalName clbi) + [clbi] + m + ) + Map.empty + buildComponents + + let cbd = + LBC.ComponentBuildDescr + { componentGraph = Graph.fromDistinctList buildComponents + , componentNameMap = buildComponentsMap + , promisedPkgs = promisedDepsSet + , installedPkgs = packageDependsIndex + } - sequence_ - [ reportProgram verbosity prog configuredProg - | (prog, configuredProg) <- knownPrograms programDb'' - ] + -- For whole-package configure, we determine the + -- extraCoverageFor of the main lib and sub libs here. + extraCoverageUnitIds = case enabled of + -- Whole package configure, add package libs + ComponentRequestedSpec{} -> mapMaybe mbCompUnitId buildComponents + -- Component configure, no need to do anything + OneComponentRequestedSpec{} -> [] + mbCompUnitId LibComponentLocalBuildInfo{componentUnitId} = Just componentUnitId + mbCompUnitId _ = Nothing + + pbd = + pbd0 + { LBC.extraCoverageFor = extraCoverageUnitIds + } - return lbi - where - verbosity = fromFlag (configVerbosity cfg) + lbd = + LBC.LocalBuildDescr + { packageBuildDescr = pbd + , componentBuildDescr = cbd + } + + lbi = + NewLocalBuildInfo + { localBuildDescr = lbd + , localBuildConfig = lbc + } + + when (LBC.relocatable $ LBC.withBuildOptions lbc) $ + checkRelocatable verbosity pkg_descr lbi + + -- TODO: This is not entirely correct, because the dirs may vary + -- across libraries/executables + let dirs = absoluteInstallDirs pkg_descr lbi NoCopyDest + relative = prefixRelativeInstallDirs (packageId pkg_descr) lbi + + -- PKGROOT: allowing ${pkgroot} to be passed as --prefix to + -- cabal configure, is only a hidden option. It allows packages + -- to be relocatable with their package database. This however + -- breaks when the Paths_* or other includes are used that + -- contain hard coded paths. This is still an open TODO. + -- + -- Allowing ${pkgroot} here, however requires less custom hooks + -- in scripts that *really* want ${pkgroot}. See haskell/cabal/#4872 + unless + ( isAbsolute (prefix dirs) + || "${pkgroot}" `isPrefixOf` prefix dirs + ) + $ dieWithException verbosity + $ ExpectedAbsoluteDirectory (prefix dirs) + + when ("${pkgroot}" `isPrefixOf` prefix dirs) $ + warn verbosity $ + "Using ${pkgroot} in prefix " + ++ prefix dirs + ++ " will not work if you rely on the Path_* module " + ++ " or other hard coded paths. Cabal does not yet " + ++ " support fully relocatable builds! " + ++ " See #462 #2302 #2994 #3305 #3473 #3586 #3909" + ++ " #4097 #4291 #4872" + + info verbosity $ + "Using " + ++ prettyShow currentCabalId + ++ " compiled by " + ++ prettyShow currentCompilerId + info verbosity $ "Using compiler: " ++ showCompilerId comp + info verbosity $ "Using install prefix: " ++ prefix dirs + + let dirinfo name dir isPrefixRelative = + info verbosity $ name ++ " installed in: " ++ dir ++ relNote + where + relNote = case buildOS of + Windows + | not (hasLibs pkg_descr) + && isNothing isPrefixRelative -> + " (fixed location)" + _ -> "" + + dirinfo "Executables" (bindir dirs) (bindir relative) + dirinfo "Libraries" (libdir dirs) (libdir relative) + dirinfo "Dynamic Libraries" (dynlibdir dirs) (dynlibdir relative) + dirinfo "Private executables" (libexecdir dirs) (libexecdir relative) + dirinfo "Data files" (datadir dirs) (datadir relative) + dirinfo "Documentation" (docdir dirs) (docdir relative) + dirinfo "Configuration files" (sysconfdir dirs) (sysconfdir relative) + + sequence_ + [ reportProgram verbosity prog configuredProg + | (prog, configuredProg) <- knownPrograms programDb + ] + + return lbi mkPromisedDepsSet :: [GivenComponent] -> Map (PackageName, ComponentName) ComponentId mkPromisedDepsSet comps = Map.fromList [((pn, CLibName ln), cid) | GivenComponent pn ln cid <- comps] -mkProgramDb :: ConfigFlags -> ProgramDb -> ProgramDb -mkProgramDb cfg initialProgramDb = programDb +-- | Adds the extra program paths from the flags provided to @configure@ as +-- well as specified locations for certain known programs and their default +-- arguments. +mkProgramDb :: ConfigFlags -> ProgramDb -> IO ProgramDb +mkProgramDb cfg initialProgramDb = do + programDb <- + modifyProgramSearchPath (getProgramSearchPath initialProgramDb ++) -- We need to have the paths to programs installed by build-tool-depends before all other paths + <$> prependProgramSearchPath (fromFlagOrDefault normal (configVerbosity cfg)) searchpath initialProgramDb + pure + . userSpecifyArgss (configProgramArgs cfg) + . userSpecifyPaths (configProgramPaths cfg) + $ programDb where - programDb = - userSpecifyArgss (configProgramArgs cfg) - . userSpecifyPaths (configProgramPaths cfg) - . setProgramSearchPath searchpath - $ initialProgramDb - searchpath = - getProgramSearchPath initialProgramDb - ++ map - ProgramSearchPathDir - (fromNubList $ configProgramPathExtra cfg) + searchpath = fromNubList (configProgramPathExtra cfg) -- Note. We try as much as possible to _prepend_ rather than postpend the extra-prog-path -- so that we can override the system path. However, in a v2-build, at this point, the "system" path @@ -1182,12 +1419,9 @@ dependencySatisfiable maybeIPI = Map.lookup (depName, CLibName lib) requiredDepsMap promised = isJust $ Map.lookup (depName, CLibName lib) promisedDeps --- | Finalize a generic package description. The workhorse is --- 'finalizePD' but there's a bit of other nattering --- about necessary. +-- | Finalize a generic package description. -- --- TODO: what exactly is the business with @flaggedTests@ and --- @flaggedBenchmarks@? +-- The workhorse is 'finalizePD'. configureFinalizedPackage :: Verbosity -> ConfigFlags @@ -1209,7 +1443,7 @@ configureFinalizedPackage comp compPlatform pkg_descr0 = do - (pkg_descr0', flags) <- + (pkg_descr, flags) <- case finalizePD (configConfigurationsFlags cfg) enabled @@ -1222,10 +1456,6 @@ configureFinalizedPackage Left missing -> dieWithException verbosity $ EncounteredMissingDependency missing - -- add extra include/lib dirs as specified in cfg - -- we do it here so that those get checked too - let pkg_descr = addExtraIncludeLibDirs pkg_descr0' - unless (nullFlagAssignment flags) $ info verbosity $ "Flags chosen: " @@ -1236,53 +1466,6 @@ configureFinalizedPackage ] return (pkg_descr, flags) - where - addExtraIncludeLibDirs pkg_descr = - let extraBi = - mempty - { extraLibDirs = configExtraLibDirs cfg - , extraLibDirsStatic = configExtraLibDirsStatic cfg - , extraFrameworkDirs = configExtraFrameworkDirs cfg - , includeDirs = configExtraIncludeDirs cfg - } - modifyLib l = - l - { libBuildInfo = - libBuildInfo l - `mappend` extraBi - } - modifyExecutable e = - e - { buildInfo = - buildInfo e - `mappend` extraBi - } - modifyForeignLib f = - f - { foreignLibBuildInfo = - foreignLibBuildInfo f - `mappend` extraBi - } - modifyTestsuite t = - t - { testBuildInfo = - testBuildInfo t - `mappend` extraBi - } - modifyBenchmark b = - b - { benchmarkBuildInfo = - benchmarkBuildInfo b - `mappend` extraBi - } - in pkg_descr - { library = modifyLib `fmap` library pkg_descr - , subLibraries = modifyLib `map` subLibraries pkg_descr - , executables = modifyExecutable `map` executables pkg_descr - , foreignLibs = modifyForeignLib `map` foreignLibs pkg_descr - , testSuites = modifyTestsuite `map` testSuites pkg_descr - , benchmarks = modifyBenchmark `map` benchmarks pkg_descr - } -- | Check for use of Cabal features which require compiler support checkCompilerProblems @@ -1380,26 +1563,28 @@ configureCoverage :: Verbosity -> ConfigFlags -> Compiler - -> IO (LocalBuildInfo -> LocalBuildInfo) + -> IO (LBC.BuildOptions -> LBC.BuildOptions) configureCoverage verbosity cfg comp = do let tryExeCoverage = fromFlagOrDefault False (configCoverage cfg) tryLibCoverage = fromFlagOrDefault tryExeCoverage (mappend (configCoverage cfg) (configLibCoverage cfg)) + -- TODO: Should we also enforce something here on that --coverage-for cannot + -- include indefinite components or instantiations? if coverageSupported comp then do - let apply lbi = - lbi - { libCoverage = tryLibCoverage - , exeCoverage = tryExeCoverage + let apply buildOptions = + buildOptions + { LBC.libCoverage = tryLibCoverage + , LBC.exeCoverage = tryExeCoverage } return apply else do - let apply lbi = - lbi - { libCoverage = False - , exeCoverage = False + let apply buildOptions = + buildOptions + { LBC.libCoverage = False + , LBC.exeCoverage = False } when (tryExeCoverage || tryLibCoverage) $ warn @@ -1445,7 +1630,7 @@ configureProfiling :: Verbosity -> ConfigFlags -> Compiler - -> IO (LocalBuildInfo -> LocalBuildInfo) + -> IO (LBC.BuildOptions -> LBC.BuildOptions) configureProfiling verbosity cfg comp = do let (tryLibProfiling, tryExeProfiling) = computeEffectiveProfiling cfg @@ -1479,21 +1664,21 @@ configureProfiling verbosity cfg comp = do then do exeLevel <- checkProfileLevel tryExeProfileLevel libLevel <- checkProfileLevel tryLibProfileLevel - let apply lbi = - lbi - { withProfLib = tryLibProfiling - , withProfLibDetail = libLevel - , withProfExe = tryExeProfiling - , withProfExeDetail = exeLevel + let apply buildOptions = + buildOptions + { LBC.withProfLib = tryLibProfiling + , LBC.withProfLibDetail = libLevel + , LBC.withProfExe = tryExeProfiling + , LBC.withProfExeDetail = exeLevel } return (tryExeProfiling && not tryLibProfiling, apply) else do - let apply lbi = - lbi - { withProfLib = False - , withProfLibDetail = ProfDetailNone - , withProfExe = False - , withProfExeDetail = ProfDetailNone + let apply buildOptions = + buildOptions + { LBC.withProfLib = False + , LBC.withProfLibDetail = ProfDetailNone + , LBC.withProfExe = False + , LBC.withProfExeDetail = ProfDetailNone } when (tryExeProfiling || tryLibProfiling) $ warn @@ -1750,6 +1935,28 @@ getInstalledPackagesMonitorFiles verbosity comp packageDBs progdb platform = ++ prettyShow other return [] +-- | Looks up the 'InstalledPackageInfo' of the given 'UnitId's from the +-- 'PackageDBStack' in the 'LocalBuildInfo'. +getInstalledPackagesById + :: (Exception (VerboseException exception), Show exception, Typeable exception) + => Verbosity + -> LocalBuildInfo + -> (UnitId -> exception) + -- ^ Construct an exception that is thrown if a + -- unit-id is not found in the installed packages, + -- from the unit-id that is missing. + -> [UnitId] + -- ^ The unit ids to lookup in the installed packages + -> IO [InstalledPackageInfo] +getInstalledPackagesById verbosity LocalBuildInfo{compiler = comp, withPackageDB = pkgDb, withPrograms = progDb} mkException unitids = do + ipindex <- getInstalledPackages verbosity comp pkgDb progDb + mapM + ( \uid -> case lookupUnitId ipindex uid of + Nothing -> dieWithException verbosity (mkException uid) + Just ipkg -> return ipkg + ) + unitids + -- | The user interface specifies the package dbs to use with a combination of -- @--global@, @--user@ and @--package-db=global|user|clear|$file@. -- This function combines the global/user flag and interprets the package-db @@ -2048,15 +2255,14 @@ ccLdOptionsBuildInfo cflags ldflags ldflags_static = configCompilerAuxEx :: ConfigFlags -> IO (Compiler, Platform, ProgramDb) -configCompilerAuxEx cfg = +configCompilerAuxEx cfg = do + programDb <- mkProgramDb cfg defaultProgramDb configCompilerEx (flagToMaybe $ configHcFlavor cfg) (flagToMaybe $ configHcPath cfg) (flagToMaybe $ configHcPkg cfg) programDb (fromFlag (configVerbosity cfg)) - where - programDb = mkProgramDb cfg defaultProgramDb configCompilerEx :: Maybe CompilerFlavor @@ -2290,7 +2496,7 @@ checkPackageProblems -> IO () checkPackageProblems verbosity dir gpkg pkg = do ioChecks <- checkPackageFiles verbosity pkg dir - let pureChecks = checkPackage gpkg (Just pkg) + let pureChecks = checkPackage gpkg (errors, warnings) = partitionEithers (M.mapMaybe classEW $ pureChecks ++ ioChecks) if null errors @@ -2383,7 +2589,12 @@ checkRelocatable verbosity pkg lbi = -- @shortRelativePath prefix pkgroot@ will return a path with -- @..@s and following check will fail without @canonicalizePath@. canonicalized <- canonicalizePath libdir - unless (p `isPrefixOf` canonicalized) $ + -- The @prefix@ itself must also be canonicalized because + -- canonicalizing @libdir@ may expand symlinks which would make + -- @prefix@ no longer being a prefix of @canonical libdir@, + -- while @canonical p@ could be a prefix of @canonical libdir@ + p' <- canonicalizePath p + unless (p' `isPrefixOf` canonicalized) $ dieWithException verbosity $ LibDirDepsPrefixNotRelative libdir p | otherwise = diff --git a/Cabal/src/Distribution/Simple/ConfigureScript.hs b/Cabal/src/Distribution/Simple/ConfigureScript.hs index c4ec2fc0f95..b7a7f16da25 100644 --- a/Cabal/src/Distribution/Simple/ConfigureScript.hs +++ b/Cabal/src/Distribution/Simple/ConfigureScript.hs @@ -169,10 +169,7 @@ runConfigureScript verbosity flags lbi = do maybeHostFlag = if hp == buildPlatform then [] else ["--host=" ++ show (pretty hp)] args' = configureFile' : args ++ ["CC=" ++ ccProgShort] ++ maybeHostFlag shProg = simpleProgram "sh" - progDb = - modifyProgramSearchPath - (\p -> map ProgramSearchPathDir extraPath ++ p) - emptyProgramDb + progDb <- prependProgramSearchPath verbosity extraPath emptyProgramDb shConfiguredProg <- lookupProgram shProg `fmap` configureProgram verbosity shProg progDb diff --git a/Cabal/src/Distribution/Simple/Errors.hs b/Cabal/src/Distribution/Simple/Errors.hs index dc3e30ab9b6..2c5af36a04b 100644 --- a/Cabal/src/Distribution/Simple/Errors.hs +++ b/Cabal/src/Distribution/Simple/Errors.hs @@ -26,6 +26,7 @@ import Distribution.Pretty , prettyShow ) import Distribution.Simple.InstallDirs +import Distribution.Simple.PreProcess.Types (Suffix) import Distribution.System (OS) import Distribution.Types.BenchmarkType import Distribution.Types.LibraryName @@ -53,7 +54,7 @@ data CabalException | UnsupportedTestSuite String | UnsupportedBenchMark String | NoIncludeFileFound String - | NoModuleFound ModuleName [String] + | NoModuleFound ModuleName [Suffix] | RegMultipleInstancePkg | SuppressingChecksOnFile | NoSupportDirStylePackageDb @@ -153,7 +154,7 @@ data CabalException | RawSystemStdout String | FindFileCwd FilePath | FindFileEx FilePath - | FindModuleFileEx ModuleName [String] [FilePath] + | FindModuleFileEx ModuleName [Suffix] [FilePath] | MultipleFilesWithExtension String | NoDesc | MultiDesc [String] @@ -170,6 +171,7 @@ data CabalException | NoProgramFound String VersionRange | BadVersionDb String Version VersionRange FilePath | UnknownVersionDb String VersionRange FilePath + | MissingCoveredInstalledLibrary UnitId deriving (Show, Typeable) exceptionCode :: CabalException -> Int @@ -301,6 +303,7 @@ exceptionCode e = case e of NoProgramFound{} -> 7620 BadVersionDb{} -> 8038 UnknownVersionDb{} -> 1008 + MissingCoveredInstalledLibrary{} -> 9341 versionRequirement :: VersionRange -> String versionRequirement range @@ -323,7 +326,7 @@ exceptionMessage e = case e of "Could not find module: " ++ prettyShow m ++ " with any suffix: " - ++ show suffixes + ++ show (map prettyShow suffixes) ++ ".\n" ++ "If the module " ++ "is autogenerated it should be added to 'autogen-modules'." @@ -728,7 +731,7 @@ exceptionMessage e = case e of "Could not find module: " ++ prettyShow mod_name ++ " with any suffix: " - ++ show extensions + ++ show (map prettyShow extensions) ++ " in the search path: " ++ show searchPath MultipleFilesWithExtension buildInfoExt -> "Multiple files with extension " ++ buildInfoExt @@ -791,3 +794,7 @@ exceptionMessage e = case e of ++ " is required but the version of " ++ locationPath ++ " could not be determined." + MissingCoveredInstalledLibrary unitId -> + "Failed to find the installed unit '" + ++ prettyShow unitId + ++ "' in package database stack." diff --git a/Cabal/src/Distribution/Simple/Flag.hs b/Cabal/src/Distribution/Simple/Flag.hs index 0e75780165a..b692eb339ff 100644 --- a/Cabal/src/Distribution/Simple/Flag.hs +++ b/Cabal/src/Distribution/Simple/Flag.hs @@ -29,6 +29,7 @@ module Distribution.Simple.Flag , flagToMaybe , flagToList , maybeToFlag + , mergeListFlag , BooleanFlag (..) ) where @@ -150,6 +151,11 @@ maybeToFlag :: Maybe a -> Flag a maybeToFlag Nothing = NoFlag maybeToFlag (Just x) = Flag x +-- | Merge the elements of a list 'Flag' with another list 'Flag'. +mergeListFlag :: Flag [a] -> Flag [a] -> Flag [a] +mergeListFlag currentFlags v = + Flag $ concat (flagToList currentFlags ++ flagToList v) + -- | Types that represent boolean flags. class BooleanFlag a where asBool :: a -> Bool diff --git a/Cabal/src/Distribution/Simple/GHC.hs b/Cabal/src/Distribution/Simple/GHC.hs index 3c380a41a86..d22c7f61849 100644 --- a/Cabal/src/Distribution/Simple/GHC.hs +++ b/Cabal/src/Distribution/Simple/GHC.hs @@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TupleSections #-} @@ -55,8 +56,8 @@ module Distribution.Simple.GHC , libAbiHash , hcPkgInfo , registerPackage - , componentGhcOptions - , componentCcGhcOptions + , Internal.componentGhcOptions + , Internal.componentCcGhcOptions , getGhcAppDir , getLibDir , isDynamic @@ -81,46 +82,42 @@ module Distribution.Simple.GHC import Distribution.Compat.Prelude import Prelude () -import Control.Monad (forM_, msum) -import Data.Char (isLower) +import Control.Monad (forM_) +import Data.List (stripPrefix) import qualified Data.Map as Map import Distribution.CabalSpecVersion import Distribution.InstalledPackageInfo (InstalledPackageInfo) import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo -import Distribution.ModuleName (ModuleName) -import qualified Distribution.ModuleName as ModuleName import Distribution.Package import Distribution.PackageDescription as PD -import Distribution.PackageDescription.Utils (cabalBug) import Distribution.Pretty +import Distribution.Simple.Build.Inputs (PreBuildComponentInputs (..)) import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler import Distribution.Simple.Errors -import Distribution.Simple.Flag (Flag (..), fromFlag, fromFlagOrDefault, toFlag) +import Distribution.Simple.Flag (Flag (..), toFlag) +import qualified Distribution.Simple.GHC.Build as GHC +import Distribution.Simple.GHC.Build.Utils import Distribution.Simple.GHC.EnvironmentParser import Distribution.Simple.GHC.ImplInfo import qualified Distribution.Simple.GHC.Internal as Internal -import qualified Distribution.Simple.Hpc as Hpc import Distribution.Simple.LocalBuildInfo import Distribution.Simple.PackageIndex (InstalledPackageIndex) import qualified Distribution.Simple.PackageIndex as PackageIndex +import Distribution.Simple.PreProcess.Types import Distribution.Simple.Program -import qualified Distribution.Simple.Program.Ar as Ar import Distribution.Simple.Program.Builtin (runghcProgram) import Distribution.Simple.Program.GHC import qualified Distribution.Simple.Program.HcPkg as HcPkg -import qualified Distribution.Simple.Program.Ld as Ld import qualified Distribution.Simple.Program.Strip as Strip import Distribution.Simple.Setup.Common (extraCompilationArtifacts) -import Distribution.Simple.Setup.Config import Distribution.Simple.Setup.Repl import Distribution.Simple.Utils import Distribution.System import Distribution.Types.ComponentLocalBuildInfo -import Distribution.Types.PackageName.Magic import Distribution.Types.ParStrat +import Distribution.Types.TargetInfo import Distribution.Utils.NubList -import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version import Language.Haskell.Extension @@ -130,28 +127,21 @@ import System.Directory , doesDirectoryExist , doesFileExist , getAppUserDataDirectory - , getCurrentDirectory , getDirectoryContents - , makeRelativeToCurrentDirectory - , removeFile - , renameFile ) import System.FilePath - ( isRelative - , replaceExtension - , takeDirectory - , takeExtension + ( takeDirectory , (<.>) , () ) import qualified System.Info #ifndef mingw32_HOST_OS +import System.Directory (renameFile) import System.Posix (createSymbolicLink) #endif /* mingw32_HOST_OS */ -import qualified Data.ByteString.Lazy.Char8 as BS -import Distribution.Compat.Binary (encode) -import Distribution.Compat.ResponseFile (escapeArgs) -import qualified Distribution.InstalledPackageInfo as IPI + +import Distribution.Simple.Setup (BuildingWhat (..)) +import Distribution.Simple.Setup.Build -- ----------------------------------------------------------------------------- -- Configuring @@ -171,14 +161,14 @@ configure verbosity hcPath hcPkgPath conf0 = do (userMaybeSpecifyPath "ghc" hcPath conf0) let implInfo = ghcVersionImplInfo ghcVersion - -- Cabal currently supports ghc >= 7.0.1 && < 9.8 + -- Cabal currently supports ghc >= 7.0.1 && < 9.10 -- ... and the following odd development version - unless (ghcVersion < mkVersion [9, 8]) $ + unless (ghcVersion < mkVersion [9, 10]) $ warn verbosity $ "Unknown/unsupported 'ghc' version detected " ++ "(Cabal " ++ prettyShow cabalVersion - ++ " supports 'ghc' version < 9.8): " + ++ " supports 'ghc' version < 9.10): " ++ programPath ghcProg ++ " is version " ++ prettyShow ghcVersion @@ -246,10 +236,16 @@ configure verbosity hcPath hcPkgPath conf0 = do filterExt ext = filter ((/= EnableExtension ext) . fst) + compilerId :: CompilerId + compilerId = CompilerId GHC ghcVersion + + compilerAbiTag :: AbiTag + compilerAbiTag = maybe NoAbiTag AbiTag (Map.lookup "Project Unit Id" ghcInfoMap >>= stripPrefix (prettyShow compilerId <> "-")) + let comp = Compiler - { compilerId = CompilerId GHC ghcVersion - , compilerAbiTag = NoAbiTag + { compilerId + , compilerAbiTag , compilerCompat = [] , compilerLanguages = languages , compilerExtensions = extensions @@ -572,527 +568,28 @@ getInstalledPackagesMonitorFiles verbosity platform progdb = -- Building a library buildLib - :: Verbosity + :: BuildFlags -> Flag ParStrat -> PackageDescription -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO () -buildLib = buildOrReplLib Nothing +buildLib flags numJobs pkg lbi lib clbi = + GHC.build numJobs pkg $ + PreBuildComponentInputs (BuildNormal flags) lbi (TargetInfo clbi (CLib lib)) replLib - :: ReplOptions - -> Verbosity + :: ReplFlags -> Flag ParStrat -> PackageDescription -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO () -replLib = buildOrReplLib . Just - -buildOrReplLib - :: Maybe ReplOptions - -> Verbosity - -> Flag ParStrat - -> PackageDescription - -> LocalBuildInfo - -> Library - -> ComponentLocalBuildInfo - -> IO () -buildOrReplLib mReplFlags verbosity numJobs pkg_descr lbi lib clbi = do - let uid = componentUnitId clbi - libTargetDir = componentBuildDir lbi clbi - whenVanillaLib forceVanilla = - when (forceVanilla || withVanillaLib lbi) - whenProfLib = when (withProfLib lbi) - whenSharedLib forceShared = - when (forceShared || withSharedLib lbi) - whenStaticLib forceStatic = - when (forceStatic || withStaticLib lbi) - whenGHCiLib = when (withGHCiLib lbi) - forRepl = maybe False (const True) mReplFlags - whenReplLib = forM_ mReplFlags - replFlags = fromMaybe mempty mReplFlags - comp = compiler lbi - ghcVersion = compilerVersion comp - implInfo = getImplInfo comp - platform@(Platform hostArch hostOS) = hostPlatform lbi - hasJsSupport = hostArch == JavaScript - has_code = not (componentIsIndefinite clbi) - - relLibTargetDir <- makeRelativeToCurrentDirectory libTargetDir - - (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi) - let runGhcProg = runGHC verbosity ghcProg comp platform - - let libBi = libBuildInfo lib - - -- ensure extra lib dirs exist before passing to ghc - cleanedExtraLibDirs <- filterM doesDirectoryExist (extraLibDirs libBi) - cleanedExtraLibDirsStatic <- filterM doesDirectoryExist (extraLibDirsStatic libBi) - - let isGhcDynamic = isDynamic comp - dynamicTooSupported = supportsDynamicToo comp - doingTH = usesTemplateHaskellOrQQ libBi - forceVanillaLib = doingTH && not isGhcDynamic - forceSharedLib = doingTH && isGhcDynamic - -- TH always needs default libs, even when building for profiling - - -- Determine if program coverage should be enabled and if so, what - -- '-hpcdir' should be. - let isCoverageEnabled = libCoverage lbi - -- TODO: Historically HPC files have been put into a directory which - -- has the package name. I'm going to avoid changing this for - -- now, but it would probably be better for this to be the - -- component ID instead... - pkg_name = prettyShow (PD.package pkg_descr) - distPref = fromFlag $ configDistPref $ configFlags lbi - hpcdir way - | forRepl = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way pkg_name - | otherwise = mempty - - createDirectoryIfMissingVerbose verbosity True libTargetDir - -- TODO: do we need to put hs-boot files into place for mutually recursive - -- modules? - let cLikeSources = - fromNubListR $ - mconcat - [ toNubListR (cSources libBi) - , toNubListR (cxxSources libBi) - , toNubListR (cmmSources libBi) - , toNubListR (asmSources libBi) - , if hasJsSupport - then -- JS files are C-like with GHC's JS backend: they are - -- "compiled" into `.o` files (renamed with a header). - -- This is a difference from GHCJS, for which we only - -- pass the JS files at link time. - toNubListR (jsSources libBi) - else mempty - ] - cLikeObjs = map (`replaceExtension` objExtension) cLikeSources - baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir - vanillaOpts = - baseOpts - `mappend` mempty - { ghcOptMode = toFlag GhcModeMake - , ghcOptNumJobs = numJobs - , ghcOptInputModules = toNubListR $ allLibModules lib clbi - , ghcOptHPCDir = hpcdir Hpc.Vanilla - } - - profOpts = - vanillaOpts - `mappend` mempty - { ghcOptProfilingMode = toFlag True - , ghcOptProfilingAuto = - Internal.profDetailLevelFlag - True - (withProfLibDetail lbi) - , ghcOptHiSuffix = toFlag "p_hi" - , ghcOptObjSuffix = toFlag "p_o" - , ghcOptExtra = hcProfOptions GHC libBi - , ghcOptHPCDir = hpcdir Hpc.Prof - } - - sharedOpts = - vanillaOpts - `mappend` mempty - { ghcOptDynLinkMode = toFlag GhcDynamicOnly - , ghcOptFPic = toFlag True - , ghcOptHiSuffix = toFlag "dyn_hi" - , ghcOptObjSuffix = toFlag "dyn_o" - , ghcOptExtra = hcSharedOptions GHC libBi - , ghcOptHPCDir = hpcdir Hpc.Dyn - } - linkerOpts = - mempty - { ghcOptLinkOptions = - PD.ldOptions libBi - ++ [ "-static" - | withFullyStaticExe lbi - ] - -- Pass extra `ld-options` given - -- through to GHC's linker. - ++ maybe - [] - programOverrideArgs - (lookupProgram ldProgram (withPrograms lbi)) - , ghcOptLinkLibs = - if withFullyStaticExe lbi - then extraLibsStatic libBi - else extraLibs libBi - , ghcOptLinkLibPath = - toNubListR $ - if withFullyStaticExe lbi - then cleanedExtraLibDirsStatic - else cleanedExtraLibDirs - , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi - , ghcOptLinkFrameworkDirs = - toNubListR $ - PD.extraFrameworkDirs libBi - , ghcOptInputFiles = - toNubListR - [relLibTargetDir x | x <- cLikeObjs] - } - replOpts = - vanillaOpts - { ghcOptExtra = - Internal.filterGhciFlags - (ghcOptExtra vanillaOpts) - <> replOptionsFlags replFlags - , ghcOptNumJobs = mempty - , ghcOptInputModules = replNoLoad replFlags (ghcOptInputModules vanillaOpts) - } - `mappend` linkerOpts - `mappend` mempty - { ghcOptMode = isInteractive - , ghcOptOptimisation = toFlag GhcNoOptimisation - } - - isInteractive = toFlag GhcModeInteractive - - vanillaSharedOpts = - vanillaOpts - `mappend` mempty - { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic - , ghcOptDynHiSuffix = toFlag "dyn_hi" - , ghcOptDynObjSuffix = toFlag "dyn_o" - , ghcOptHPCDir = hpcdir Hpc.Dyn - } - - unless (forRepl || null (allLibModules lib clbi)) $ - do - let vanilla = whenVanillaLib forceVanillaLib (runGhcProg vanillaOpts) - shared = whenSharedLib forceSharedLib (runGhcProg sharedOpts) - useDynToo = - dynamicTooSupported - && (forceVanillaLib || withVanillaLib lbi) - && (forceSharedLib || withSharedLib lbi) - && null (hcSharedOptions GHC libBi) - if not has_code - then vanilla - else - if useDynToo - then do - runGhcProg vanillaSharedOpts - case (hpcdir Hpc.Dyn, hpcdir Hpc.Vanilla) of - (Flag dynDir, Flag vanillaDir) -> - -- When the vanilla and shared library builds are done - -- in one pass, only one set of HPC module interfaces - -- are generated. This set should suffice for both - -- static and dynamically linked executables. We copy - -- the modules interfaces so they are available under - -- both ways. - copyDirectoryRecursive verbosity dynDir vanillaDir - _ -> return () - else - if isGhcDynamic - then do shared; vanilla - else do vanilla; shared - whenProfLib (runGhcProg profOpts) - - let - buildExtraSources mkSrcOpts wantDyn = traverse_ $ buildExtraSource mkSrcOpts wantDyn - buildExtraSource mkSrcOpts wantDyn filename = do - let baseSrcOpts = - mkSrcOpts - verbosity - implInfo - lbi - libBi - clbi - relLibTargetDir - filename - vanillaSrcOpts - -- Dynamic GHC requires C sources to be built - -- with -fPIC for REPL to work. See #2207. - | isGhcDynamic && wantDyn = baseSrcOpts{ghcOptFPic = toFlag True} - | otherwise = baseSrcOpts - runGhcProgIfNeeded opts = do - needsRecomp <- checkNeedsRecompilation filename opts - when needsRecomp $ runGhcProg opts - profSrcOpts = - vanillaSrcOpts - `mappend` mempty - { ghcOptProfilingMode = toFlag True - , ghcOptObjSuffix = toFlag "p_o" - } - sharedSrcOpts = - vanillaSrcOpts - `mappend` mempty - { ghcOptFPic = toFlag True - , ghcOptDynLinkMode = toFlag GhcDynamicOnly - , ghcOptObjSuffix = toFlag "dyn_o" - } - odir = fromFlag (ghcOptObjDir vanillaSrcOpts) - - createDirectoryIfMissingVerbose verbosity True odir - runGhcProgIfNeeded vanillaSrcOpts - unless (forRepl || not wantDyn) $ - whenSharedLib forceSharedLib (runGhcProgIfNeeded sharedSrcOpts) - unless forRepl $ - whenProfLib (runGhcProgIfNeeded profSrcOpts) - - -- Build any C++ sources separately. - unless (not has_code || null (cxxSources libBi)) $ do - info verbosity "Building C++ Sources..." - buildExtraSources Internal.componentCxxGhcOptions True (cxxSources libBi) - - -- build any C sources - unless (not has_code || null (cSources libBi)) $ do - info verbosity "Building C Sources..." - buildExtraSources Internal.componentCcGhcOptions True (cSources libBi) - - -- build any JS sources - unless (not has_code || not hasJsSupport || null (jsSources libBi)) $ do - info verbosity "Building JS Sources..." - buildExtraSources Internal.componentJsGhcOptions False (jsSources libBi) - - -- build any ASM sources - unless (not has_code || null (asmSources libBi)) $ do - info verbosity "Building Assembler Sources..." - buildExtraSources Internal.componentAsmGhcOptions True (asmSources libBi) - - -- build any Cmm sources - unless (not has_code || null (cmmSources libBi)) $ do - info verbosity "Building C-- Sources..." - buildExtraSources Internal.componentCmmGhcOptions True (cmmSources libBi) - - -- TODO: problem here is we need the .c files built first, so we can load them - -- with ghci, but .c files can depend on .h files generated by ghc by ffi - -- exports. - whenReplLib $ \rflags -> do - when (null (allLibModules lib clbi)) $ warn verbosity "No exposed modules" - runReplOrWriteFlags verbosity ghcProg comp platform rflags replOpts libBi clbi (pkgName (PD.package pkg_descr)) - - -- link: - when has_code . unless forRepl $ do - info verbosity "Linking..." - let cLikeProfObjs = - map - (`replaceExtension` ("p_" ++ objExtension)) - cLikeSources - cLikeSharedObjs = - map - (`replaceExtension` ("dyn_" ++ objExtension)) - cLikeSources - compiler_id = compilerId (compiler lbi) - vanillaLibFilePath = relLibTargetDir mkLibName uid - profileLibFilePath = relLibTargetDir mkProfLibName uid - sharedLibFilePath = - relLibTargetDir - mkSharedLibName (hostPlatform lbi) compiler_id uid - staticLibFilePath = - relLibTargetDir - mkStaticLibName (hostPlatform lbi) compiler_id uid - ghciLibFilePath = relLibTargetDir Internal.mkGHCiLibName uid - ghciProfLibFilePath = relLibTargetDir Internal.mkGHCiProfLibName uid - libInstallPath = - libdir $ - absoluteComponentInstallDirs - pkg_descr - lbi - uid - NoCopyDest - sharedLibInstallPath = - libInstallPath - mkSharedLibName (hostPlatform lbi) compiler_id uid - - stubObjs <- - catMaybes - <$> sequenceA - [ findFileWithExtension - [objExtension] - [libTargetDir] - (ModuleName.toFilePath x ++ "_stub") - | ghcVersion < mkVersion [7, 2] -- ghc-7.2+ does not make _stub.o files - , x <- allLibModules lib clbi - ] - stubProfObjs <- - catMaybes - <$> sequenceA - [ findFileWithExtension - ["p_" ++ objExtension] - [libTargetDir] - (ModuleName.toFilePath x ++ "_stub") - | ghcVersion < mkVersion [7, 2] -- ghc-7.2+ does not make _stub.o files - , x <- allLibModules lib clbi - ] - stubSharedObjs <- - catMaybes - <$> sequenceA - [ findFileWithExtension - ["dyn_" ++ objExtension] - [libTargetDir] - (ModuleName.toFilePath x ++ "_stub") - | ghcVersion < mkVersion [7, 2] -- ghc-7.2+ does not make _stub.o files - , x <- allLibModules lib clbi - ] - - hObjs <- - Internal.getHaskellObjects - implInfo - lib - lbi - clbi - relLibTargetDir - objExtension - True - hProfObjs <- - if withProfLib lbi - then - Internal.getHaskellObjects - implInfo - lib - lbi - clbi - relLibTargetDir - ("p_" ++ objExtension) - True - else return [] - hSharedObjs <- - if withSharedLib lbi - then - Internal.getHaskellObjects - implInfo - lib - lbi - clbi - relLibTargetDir - ("dyn_" ++ objExtension) - False - else return [] - - unless (null hObjs && null cLikeObjs && null stubObjs) $ do - rpaths <- getRPaths lbi clbi - - let staticObjectFiles = - hObjs - ++ map (relLibTargetDir ) cLikeObjs - ++ stubObjs - profObjectFiles = - hProfObjs - ++ map (relLibTargetDir ) cLikeProfObjs - ++ stubProfObjs - dynamicObjectFiles = - hSharedObjs - ++ map (relLibTargetDir ) cLikeSharedObjs - ++ stubSharedObjs - -- After the relocation lib is created we invoke ghc -shared - -- with the dependencies spelled out as -package arguments - -- and ghc invokes the linker with the proper library paths - ghcSharedLinkArgs = - mempty - { ghcOptShared = toFlag True - , ghcOptDynLinkMode = toFlag GhcDynamicOnly - , ghcOptInputFiles = toNubListR dynamicObjectFiles - , ghcOptOutputFile = toFlag sharedLibFilePath - , ghcOptExtra = hcSharedOptions GHC libBi - , -- For dynamic libs, Mac OS/X needs to know the install location - -- at build time. This only applies to GHC < 7.8 - see the - -- discussion in #1660. - ghcOptDylibName = - if hostOS == OSX - && ghcVersion < mkVersion [7, 8] - then toFlag sharedLibInstallPath - else mempty - , ghcOptHideAllPackages = toFlag True - , ghcOptNoAutoLinkPackages = toFlag True - , ghcOptPackageDBs = withPackageDB lbi - , ghcOptThisUnitId = case clbi of - LibComponentLocalBuildInfo{componentCompatPackageKey = pk} -> - toFlag pk - _ -> mempty - , ghcOptThisComponentId = case clbi of - LibComponentLocalBuildInfo - { componentInstantiatedWith = insts - } -> - if null insts - then mempty - else toFlag (componentComponentId clbi) - _ -> mempty - , ghcOptInstantiatedWith = case clbi of - LibComponentLocalBuildInfo - { componentInstantiatedWith = insts - } -> - insts - _ -> [] - , ghcOptPackages = - toNubListR $ - Internal.mkGhcOptPackages mempty clbi - , ghcOptLinkLibs = extraLibs libBi - , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs - , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi - , ghcOptLinkFrameworkDirs = - toNubListR $ PD.extraFrameworkDirs libBi - , ghcOptRPaths = rpaths - } - ghcStaticLinkArgs = - mempty - { ghcOptStaticLib = toFlag True - , ghcOptInputFiles = toNubListR staticObjectFiles - , ghcOptOutputFile = toFlag staticLibFilePath - , ghcOptExtra = hcStaticOptions GHC libBi - , ghcOptHideAllPackages = toFlag True - , ghcOptNoAutoLinkPackages = toFlag True - , ghcOptPackageDBs = withPackageDB lbi - , ghcOptThisUnitId = case clbi of - LibComponentLocalBuildInfo{componentCompatPackageKey = pk} -> - toFlag pk - _ -> mempty - , ghcOptThisComponentId = case clbi of - LibComponentLocalBuildInfo - { componentInstantiatedWith = insts - } -> - if null insts - then mempty - else toFlag (componentComponentId clbi) - _ -> mempty - , ghcOptInstantiatedWith = case clbi of - LibComponentLocalBuildInfo - { componentInstantiatedWith = insts - } -> - insts - _ -> [] - , ghcOptPackages = - toNubListR $ - Internal.mkGhcOptPackages mempty clbi - , ghcOptLinkLibs = extraLibs libBi - , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs - } - - info verbosity (show (ghcOptPackages ghcSharedLinkArgs)) - - whenVanillaLib False $ do - Ar.createArLibArchive verbosity lbi vanillaLibFilePath staticObjectFiles - whenGHCiLib $ do - (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi) - Ld.combineObjectFiles - verbosity - lbi - ldProg - ghciLibFilePath - staticObjectFiles - - whenProfLib $ do - Ar.createArLibArchive verbosity lbi profileLibFilePath profObjectFiles - whenGHCiLib $ do - (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi) - Ld.combineObjectFiles - verbosity - lbi - ldProg - ghciProfLibFilePath - profObjectFiles - - whenSharedLib False $ - runGhcProg ghcSharedLinkArgs - - whenStaticLib False $ - runGhcProg ghcStaticLinkArgs +replLib flags numJobs pkg lbi lib clbi = + GHC.build numJobs pkg $ + PreBuildComponentInputs (BuildRepl flags) lbi (TargetInfo clbi (CLib lib)) -- | Start a REPL without loading any source files. startInterpreter @@ -1112,47 +609,6 @@ startInterpreter verbosity progdb comp platform packageDBs = do (ghcProg, _) <- requireProgram verbosity ghcProgram progdb runGHC verbosity ghcProg comp platform replOpts -runReplOrWriteFlags - :: Verbosity - -> ConfiguredProgram - -> Compiler - -> Platform - -> ReplOptions - -> GhcOptions - -> BuildInfo - -> ComponentLocalBuildInfo - -> PackageName - -> IO () -runReplOrWriteFlags verbosity ghcProg comp platform rflags replOpts bi clbi pkg_name = - case replOptionsFlagOutput rflags of - NoFlag -> runGHC verbosity ghcProg comp platform replOpts - Flag out_dir -> do - src_dir <- getCurrentDirectory - let uid = componentUnitId clbi - this_unit = prettyShow uid - reexported_modules = [mn | LibComponentLocalBuildInfo{} <- [clbi], IPI.ExposedModule mn (Just{}) <- componentExposedModules clbi] - hidden_modules = otherModules bi - extra_opts = - concat $ - [ ["-this-package-name", prettyShow pkg_name] - , ["-working-dir", src_dir] - ] - ++ [ ["-reexported-module", prettyShow m] | m <- reexported_modules - ] - ++ [ ["-hidden-module", prettyShow m] | m <- hidden_modules - ] - -- Create "paths" subdirectory if it doesn't exist. This is where we write - -- information about how the PATH was augmented. - createDirectoryIfMissing False (out_dir "paths") - -- Write out the PATH information into `paths` subdirectory. - writeFileAtomic (out_dir "paths" this_unit) (encode ghcProg) - -- Write out options for this component into a file ready for loading into - -- the multi-repl - writeFileAtomic (out_dir this_unit) $ - BS.pack $ - escapeArgs $ - extra_opts ++ renderGhcOptions comp platform (replOpts{ghcOptMode = NoFlag}) - -- ----------------------------------------------------------------------------- -- Building an executable or foreign library @@ -1165,19 +621,21 @@ buildFLib -> ForeignLib -> ComponentLocalBuildInfo -> IO () -buildFLib v njobs pkg lbi = gbuild v njobs pkg lbi . GBuildFLib +buildFLib v numJobs pkg lbi flib clbi = + GHC.build numJobs pkg $ + PreBuildComponentInputs (BuildNormal mempty{buildVerbosity = toFlag v}) lbi (TargetInfo clbi (CFLib flib)) replFLib - :: ReplOptions - -> Verbosity + :: ReplFlags -> Flag ParStrat -> PackageDescription -> LocalBuildInfo -> ForeignLib -> ComponentLocalBuildInfo -> IO () -replFLib replFlags v njobs pkg lbi = - gbuild v njobs pkg lbi . GReplFLib replFlags +replFLib replFlags njobs pkg lbi flib clbi = + GHC.build njobs pkg $ + PreBuildComponentInputs (BuildRepl replFlags) lbi (TargetInfo clbi (CFLib flib)) -- | Build an executable with GHC. buildExe @@ -1188,855 +646,21 @@ buildExe -> Executable -> ComponentLocalBuildInfo -> IO () -buildExe v njobs pkg lbi = gbuild v njobs pkg lbi . GBuildExe +buildExe v njobs pkg lbi exe clbi = + GHC.build njobs pkg $ + PreBuildComponentInputs (BuildNormal mempty{buildVerbosity = toFlag v}) lbi (TargetInfo clbi (CExe exe)) replExe - :: ReplOptions - -> Verbosity + :: ReplFlags -> Flag ParStrat -> PackageDescription -> LocalBuildInfo -> Executable -> ComponentLocalBuildInfo -> IO () -replExe replFlags v njobs pkg lbi = - gbuild v njobs pkg lbi . GReplExe replFlags - --- | Building an executable, starting the REPL, and building foreign --- libraries are all very similar and implemented in 'gbuild'. The --- 'GBuildMode' distinguishes between the various kinds of operation. -data GBuildMode - = GBuildExe Executable - | GReplExe ReplOptions Executable - | GBuildFLib ForeignLib - | GReplFLib ReplOptions ForeignLib - -gbuildInfo :: GBuildMode -> BuildInfo -gbuildInfo (GBuildExe exe) = buildInfo exe -gbuildInfo (GReplExe _ exe) = buildInfo exe -gbuildInfo (GBuildFLib flib) = foreignLibBuildInfo flib -gbuildInfo (GReplFLib _ flib) = foreignLibBuildInfo flib - -gbuildName :: GBuildMode -> String -gbuildName (GBuildExe exe) = unUnqualComponentName $ exeName exe -gbuildName (GReplExe _ exe) = unUnqualComponentName $ exeName exe -gbuildName (GBuildFLib flib) = unUnqualComponentName $ foreignLibName flib -gbuildName (GReplFLib _ flib) = unUnqualComponentName $ foreignLibName flib - -gbuildTargetName :: LocalBuildInfo -> GBuildMode -> String -gbuildTargetName lbi (GBuildExe exe) = exeTargetName (hostPlatform lbi) exe -gbuildTargetName lbi (GReplExe _ exe) = exeTargetName (hostPlatform lbi) exe -gbuildTargetName lbi (GBuildFLib flib) = flibTargetName lbi flib -gbuildTargetName lbi (GReplFLib _ flib) = flibTargetName lbi flib - -exeTargetName :: Platform -> Executable -> String -exeTargetName platform exe = unUnqualComponentName (exeName exe) `withExt` exeExtension platform - --- | Target name for a foreign library (the actual file name) --- --- We do not use mkLibName and co here because the naming for foreign libraries --- is slightly different (we don't use "_p" or compiler version suffices, and we --- don't want the "lib" prefix on Windows). --- --- TODO: We do use `dllExtension` and co here, but really that's wrong: they --- use the OS used to build cabal to determine which extension to use, rather --- than the target OS (but this is wrong elsewhere in Cabal as well). -flibTargetName :: LocalBuildInfo -> ForeignLib -> String -flibTargetName lbi flib = - case (os, foreignLibType flib) of - (Windows, ForeignLibNativeShared) -> nm <.> "dll" - (Windows, ForeignLibNativeStatic) -> nm <.> "lib" - (Linux, ForeignLibNativeShared) -> "lib" ++ nm <.> versionedExt - (_other, ForeignLibNativeShared) -> - "lib" ++ nm <.> dllExtension (hostPlatform lbi) - (_other, ForeignLibNativeStatic) -> - "lib" ++ nm <.> staticLibExtension (hostPlatform lbi) - (_any, ForeignLibTypeUnknown) -> cabalBug "unknown foreign lib type" - where - nm :: String - nm = unUnqualComponentName $ foreignLibName flib - - os :: OS - os = - let (Platform _ os') = hostPlatform lbi - in os' - - -- If a foreign lib foo has lib-version-info 5:1:2 or - -- lib-version-linux 3.2.1, it should be built as libfoo.so.3.2.1 - -- Libtool's version-info data is translated into library versions in a - -- nontrivial way: so refer to libtool documentation. - versionedExt :: String - versionedExt = - let nums = foreignLibVersion flib os - in foldl (<.>) "so" (map show nums) - --- | Name for the library when building. --- --- If the `lib-version-info` field or the `lib-version-linux` field of --- a foreign library target is set, we need to incorporate that --- version into the SONAME field. --- --- If a foreign library foo has lib-version-info 5:1:2, it should be --- built as libfoo.so.3.2.1. We want it to get soname libfoo.so.3. --- However, GHC does not allow overriding soname by setting linker --- options, as it sets a soname of its own (namely the output --- filename), after the user-supplied linker options. Hence, we have --- to compile the library with the soname as its filename. We rename --- the compiled binary afterwards. --- --- This method allows to adjust the name of the library at build time --- such that the correct soname can be set. -flibBuildName :: LocalBuildInfo -> ForeignLib -> String -flibBuildName lbi flib - -- On linux, if a foreign-library has version data, the first digit is used - -- to produce the SONAME. - | (os, foreignLibType flib) - == (Linux, ForeignLibNativeShared) = - let nums = foreignLibVersion flib os - in "lib" ++ nm <.> foldl (<.>) "so" (map show (take 1 nums)) - | otherwise = flibTargetName lbi flib - where - os :: OS - os = - let (Platform _ os') = hostPlatform lbi - in os' - - nm :: String - nm = unUnqualComponentName $ foreignLibName flib - -gbuildIsRepl :: GBuildMode -> Bool -gbuildIsRepl (GBuildExe _) = False -gbuildIsRepl (GReplExe _ _) = True -gbuildIsRepl (GBuildFLib _) = False -gbuildIsRepl (GReplFLib _ _) = True - -gbuildNeedDynamic :: LocalBuildInfo -> GBuildMode -> Bool -gbuildNeedDynamic lbi bm = - case bm of - GBuildExe _ -> withDynExe lbi - GReplExe _ _ -> withDynExe lbi - GBuildFLib flib -> withDynFLib flib - GReplFLib _ flib -> withDynFLib flib - where - withDynFLib flib = - case foreignLibType flib of - ForeignLibNativeShared -> - ForeignLibStandalone `notElem` foreignLibOptions flib - ForeignLibNativeStatic -> - False - ForeignLibTypeUnknown -> - cabalBug "unknown foreign lib type" - -gbuildModDefFiles :: GBuildMode -> [FilePath] -gbuildModDefFiles (GBuildExe _) = [] -gbuildModDefFiles (GReplExe _ _) = [] -gbuildModDefFiles (GBuildFLib flib) = foreignLibModDefFile flib -gbuildModDefFiles (GReplFLib _ flib) = foreignLibModDefFile flib - --- | "Main" module name when overridden by @ghc-options: -main-is ...@ --- or 'Nothing' if no @-main-is@ flag could be found. --- --- In case of 'Nothing', 'Distribution.ModuleName.main' can be assumed. -exeMainModuleName :: Executable -> Maybe ModuleName -exeMainModuleName Executable{buildInfo = bnfo} = - -- GHC honors the last occurrence of a module name updated via -main-is - -- - -- Moreover, -main-is when parsed left-to-right can update either - -- the "Main" module name, or the "main" function name, or both, - -- see also 'decodeMainIsArg'. - msum $ reverse $ map decodeMainIsArg $ findIsMainArgs ghcopts - where - ghcopts = hcOptions GHC bnfo - - findIsMainArgs [] = [] - findIsMainArgs ("-main-is" : arg : rest) = arg : findIsMainArgs rest - findIsMainArgs (_ : rest) = findIsMainArgs rest - --- | Decode argument to '-main-is' --- --- Returns 'Nothing' if argument set only the function name. --- --- This code has been stolen/refactored from GHC's DynFlags.setMainIs --- function. The logic here is deliberately imperfect as it is --- intended to be bug-compatible with GHC's parser. See discussion in --- https://github.com/haskell/cabal/pull/4539#discussion_r118981753. -decodeMainIsArg :: String -> Maybe ModuleName -decodeMainIsArg arg - | headOf main_fn isLower = - -- The arg looked like "Foo.Bar.baz" - Just (ModuleName.fromString main_mod) - | headOf arg isUpper -- The arg looked like "Foo" or "Foo.Bar" - = - Just (ModuleName.fromString arg) - | otherwise -- The arg looked like "baz" - = - Nothing - where - headOf :: String -> (Char -> Bool) -> Bool - headOf str pred' = any pred' (safeHead str) - - (main_mod, main_fn) = splitLongestPrefix arg (== '.') - - splitLongestPrefix :: String -> (Char -> Bool) -> (String, String) - splitLongestPrefix str pred' - | null r_pre = (str, []) - | otherwise = (reverse (safeTail r_pre), reverse r_suf) - where - -- 'safeTail' drops the char satisfying 'pred' - (r_suf, r_pre) = break pred' (reverse str) - --- | A collection of: --- * C input files --- * C++ input files --- * GHC input files --- * GHC input modules --- --- Used to correctly build and link sources. -data BuildSources = BuildSources - { cSourcesFiles :: [FilePath] - , cxxSourceFiles :: [FilePath] - , jsSourceFiles :: [FilePath] - , asmSourceFiles :: [FilePath] - , cmmSourceFiles :: [FilePath] - , inputSourceFiles :: [FilePath] - , inputSourceModules :: [ModuleName] - } - --- | Locate and return the 'BuildSources' required to build and link. -gbuildSources - :: Verbosity - -> PackageId - -> CabalSpecVersion - -> FilePath - -> GBuildMode - -> IO BuildSources -gbuildSources verbosity pkgId specVer tmpDir bm = - case bm of - GBuildExe exe -> exeSources exe - GReplExe _ exe -> exeSources exe - GBuildFLib flib -> return $ flibSources flib - GReplFLib _ flib -> return $ flibSources flib - where - exeSources :: Executable -> IO BuildSources - exeSources exe@Executable{buildInfo = bnfo, modulePath = modPath} = do - main <- findFileEx verbosity (tmpDir : map getSymbolicPath (hsSourceDirs bnfo)) modPath - let mainModName = fromMaybe ModuleName.main $ exeMainModuleName exe - otherModNames = exeModules exe - - -- Scripts have fakePackageId and are always Haskell but can have any extension. - if isHaskell main || pkgId == fakePackageId - then - if specVer < CabalSpecV2_0 && (mainModName `elem` otherModNames) - then do - -- The cabal manual clearly states that `other-modules` is - -- intended for non-main modules. However, there's at least one - -- important package on Hackage (happy-1.19.5) which - -- violates this. We workaround this here so that we don't - -- invoke GHC with e.g. 'ghc --make Main src/Main.hs' which - -- would result in GHC complaining about duplicate Main - -- modules. - -- - -- Finally, we only enable this workaround for - -- specVersion < 2, as 'cabal-version:>=2.0' cabal files - -- have no excuse anymore to keep doing it wrong... ;-) - warn verbosity $ - "Enabling workaround for Main module '" - ++ prettyShow mainModName - ++ "' listed in 'other-modules' illegally!" - - return - BuildSources - { cSourcesFiles = cSources bnfo - , cxxSourceFiles = cxxSources bnfo - , jsSourceFiles = jsSources bnfo - , asmSourceFiles = asmSources bnfo - , cmmSourceFiles = cmmSources bnfo - , inputSourceFiles = [main] - , inputSourceModules = - filter (/= mainModName) $ - exeModules exe - } - else - return - BuildSources - { cSourcesFiles = cSources bnfo - , cxxSourceFiles = cxxSources bnfo - , jsSourceFiles = jsSources bnfo - , asmSourceFiles = asmSources bnfo - , cmmSourceFiles = cmmSources bnfo - , inputSourceFiles = [main] - , inputSourceModules = exeModules exe - } - else - let (csf, cxxsf) - | isCxx main = (cSources bnfo, main : cxxSources bnfo) - -- if main is not a Haskell source - -- and main is not a C++ source - -- then we assume that it is a C source - | otherwise = (main : cSources bnfo, cxxSources bnfo) - in return - BuildSources - { cSourcesFiles = csf - , cxxSourceFiles = cxxsf - , jsSourceFiles = jsSources bnfo - , asmSourceFiles = asmSources bnfo - , cmmSourceFiles = cmmSources bnfo - , inputSourceFiles = [] - , inputSourceModules = exeModules exe - } - - flibSources :: ForeignLib -> BuildSources - flibSources flib@ForeignLib{foreignLibBuildInfo = bnfo} = - BuildSources - { cSourcesFiles = cSources bnfo - , cxxSourceFiles = cxxSources bnfo - , jsSourceFiles = jsSources bnfo - , asmSourceFiles = asmSources bnfo - , cmmSourceFiles = cmmSources bnfo - , inputSourceFiles = [] - , inputSourceModules = foreignLibModules flib - } - - isCxx :: FilePath -> Bool - isCxx fp = elem (takeExtension fp) [".cpp", ".cxx", ".c++"] - --- | FilePath has a Haskell extension: .hs or .lhs -isHaskell :: FilePath -> Bool -isHaskell fp = elem (takeExtension fp) [".hs", ".lhs"] - -replNoLoad :: Ord a => ReplOptions -> NubListR a -> NubListR a -replNoLoad replFlags l - | replOptionsNoLoad replFlags == Flag True = mempty - | otherwise = l - --- | Generic build function. See comment for 'GBuildMode'. -gbuild - :: Verbosity - -> Flag ParStrat - -> PackageDescription - -> LocalBuildInfo - -> GBuildMode - -> ComponentLocalBuildInfo - -> IO () -gbuild verbosity numJobs pkg_descr lbi bm clbi = do - (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi) - let replFlags = case bm of - GReplExe flags _ -> flags - GReplFLib flags _ -> flags - GBuildExe{} -> mempty - GBuildFLib{} -> mempty - comp = compiler lbi - platform = hostPlatform lbi - implInfo = getImplInfo comp - runGhcProg = runGHC verbosity ghcProg comp platform - - let bnfo = gbuildInfo bm - - -- the name that GHC really uses (e.g., with .exe on Windows for executables) - let targetName = gbuildTargetName lbi bm - let targetDir = buildDir lbi (gbuildName bm) - let tmpDir = targetDir (gbuildName bm ++ "-tmp") - createDirectoryIfMissingVerbose verbosity True targetDir - createDirectoryIfMissingVerbose verbosity True tmpDir - - -- TODO: do we need to put hs-boot files into place for mutually recursive - -- modules? FIX: what about exeName.hi-boot? - - -- Determine if program coverage should be enabled and if so, what - -- '-hpcdir' should be. - let isCoverageEnabled = exeCoverage lbi - distPref = fromFlag $ configDistPref $ configFlags lbi - hpcdir way - | gbuildIsRepl bm = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way (gbuildName bm) - | otherwise = mempty - - rpaths <- getRPaths lbi clbi - buildSources <- gbuildSources verbosity (package pkg_descr) (specVersion pkg_descr) tmpDir bm - - -- ensure extra lib dirs exist before passing to ghc - cleanedExtraLibDirs <- filterM doesDirectoryExist (extraLibDirs bnfo) - cleanedExtraLibDirsStatic <- filterM doesDirectoryExist (extraLibDirsStatic bnfo) - - let cSrcs = cSourcesFiles buildSources - cxxSrcs = cxxSourceFiles buildSources - jsSrcs = jsSourceFiles buildSources - asmSrcs = asmSourceFiles buildSources - cmmSrcs = cmmSourceFiles buildSources - inputFiles = inputSourceFiles buildSources - inputModules = inputSourceModules buildSources - isGhcDynamic = isDynamic comp - dynamicTooSupported = supportsDynamicToo comp - cLikeObjs = map (`replaceExtension` objExtension) cSrcs - cxxObjs = map (`replaceExtension` objExtension) cxxSrcs - jsObjs = if hasJsSupport then map (`replaceExtension` objExtension) jsSrcs else [] - asmObjs = map (`replaceExtension` objExtension) asmSrcs - cmmObjs = map (`replaceExtension` objExtension) cmmSrcs - needDynamic = gbuildNeedDynamic lbi bm - needProfiling = withProfExe lbi - Platform hostArch _ = hostPlatform lbi - hasJsSupport = hostArch == JavaScript - - -- build executables - baseOpts = - (componentGhcOptions verbosity lbi bnfo clbi tmpDir) - `mappend` mempty - { ghcOptMode = toFlag GhcModeMake - , ghcOptInputFiles = - toNubListR $ - if package pkg_descr == fakePackageId - then filter isHaskell inputFiles - else inputFiles - , ghcOptInputScripts = - toNubListR $ - if package pkg_descr == fakePackageId - then filter (not . isHaskell) inputFiles - else [] - , ghcOptInputModules = toNubListR inputModules - } - staticOpts = - baseOpts - `mappend` mempty - { ghcOptDynLinkMode = toFlag GhcStaticOnly - , ghcOptHPCDir = hpcdir Hpc.Vanilla - } - profOpts = - baseOpts - `mappend` mempty - { ghcOptProfilingMode = toFlag True - , ghcOptProfilingAuto = - Internal.profDetailLevelFlag - False - (withProfExeDetail lbi) - , ghcOptHiSuffix = toFlag "p_hi" - , ghcOptObjSuffix = toFlag "p_o" - , ghcOptExtra = hcProfOptions GHC bnfo - , ghcOptHPCDir = hpcdir Hpc.Prof - } - dynOpts = - baseOpts - `mappend` mempty - { ghcOptDynLinkMode = toFlag GhcDynamicOnly - , -- TODO: Does it hurt to set -fPIC for executables? - ghcOptFPic = toFlag True - , ghcOptHiSuffix = toFlag "dyn_hi" - , ghcOptObjSuffix = toFlag "dyn_o" - , ghcOptExtra = hcSharedOptions GHC bnfo - , ghcOptHPCDir = hpcdir Hpc.Dyn - } - dynTooOpts = - staticOpts - `mappend` mempty - { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic - , ghcOptDynHiSuffix = toFlag "dyn_hi" - , ghcOptDynObjSuffix = toFlag "dyn_o" - , ghcOptHPCDir = hpcdir Hpc.Dyn - } - linkerOpts = - mempty - { ghcOptLinkOptions = - PD.ldOptions bnfo - ++ [ "-static" - | withFullyStaticExe lbi - ] - -- Pass extra `ld-options` given - -- through to GHC's linker. - ++ maybe - [] - programOverrideArgs - (lookupProgram ldProgram (withPrograms lbi)) - , ghcOptLinkLibs = - if withFullyStaticExe lbi - then extraLibsStatic bnfo - else extraLibs bnfo - , ghcOptLinkLibPath = - toNubListR $ - if withFullyStaticExe lbi - then cleanedExtraLibDirsStatic - else cleanedExtraLibDirs - , ghcOptLinkFrameworks = - toNubListR $ - PD.frameworks bnfo - , ghcOptLinkFrameworkDirs = - toNubListR $ - PD.extraFrameworkDirs bnfo - , ghcOptInputFiles = - toNubListR - [tmpDir x | x <- cLikeObjs ++ cxxObjs ++ jsObjs ++ cmmObjs ++ asmObjs] - } - dynLinkerOpts = - mempty - { ghcOptRPaths = rpaths - , ghcOptInputFiles = - toNubListR - [tmpDir x | x <- cLikeObjs ++ cxxObjs ++ cmmObjs ++ asmObjs] - } - replOpts = - baseOpts - { ghcOptExtra = - Internal.filterGhciFlags - (ghcOptExtra baseOpts) - <> replOptionsFlags replFlags - , ghcOptInputModules = replNoLoad replFlags (ghcOptInputModules baseOpts) - , ghcOptInputFiles = replNoLoad replFlags (ghcOptInputFiles baseOpts) - } - -- For a normal compile we do separate invocations of ghc for - -- compiling as for linking. But for repl we have to do just - -- the one invocation, so that one has to include all the - -- linker stuff too, like -l flags and any .o files from C - -- files etc. - `mappend` linkerOpts - `mappend` mempty - { ghcOptMode = toFlag GhcModeInteractive - , ghcOptOptimisation = toFlag GhcNoOptimisation - } - commonOpts - | needProfiling = profOpts - | needDynamic = dynOpts - | otherwise = staticOpts - compileOpts - | useDynToo = dynTooOpts - | otherwise = commonOpts - withStaticExe = not needProfiling && not needDynamic - - -- For building exe's that use TH with -prof or -dynamic we actually have - -- to build twice, once without -prof/-dynamic and then again with - -- -prof/-dynamic. This is because the code that TH needs to run at - -- compile time needs to be the vanilla ABI so it can be loaded up and run - -- by the compiler. - -- With dynamic-by-default GHC the TH object files loaded at compile-time - -- need to be .dyn_o instead of .o. - doingTH = usesTemplateHaskellOrQQ bnfo - -- Should we use -dynamic-too instead of compiling twice? - useDynToo = - dynamicTooSupported - && isGhcDynamic - && doingTH - && withStaticExe - && null (hcSharedOptions GHC bnfo) - compileTHOpts - | isGhcDynamic = dynOpts - | otherwise = staticOpts - compileForTH - | gbuildIsRepl bm = False - | useDynToo = False - | isGhcDynamic = doingTH && (needProfiling || withStaticExe) - | otherwise = doingTH && (needProfiling || needDynamic) - - -- Build static/dynamic object files for TH, if needed. - when compileForTH $ - runGhcProg - compileTHOpts - { ghcOptNoLink = toFlag True - , ghcOptNumJobs = numJobs - } - - -- Do not try to build anything if there are no input files. - -- This can happen if the cabal file ends up with only cSrcs - -- but no Haskell modules. - unless - ( (null inputFiles && null inputModules) - || gbuildIsRepl bm - ) - $ runGhcProg - compileOpts - { ghcOptNoLink = toFlag True - , ghcOptNumJobs = numJobs - } - - let - buildExtraSources mkSrcOpts wantDyn = traverse_ $ buildExtraSource mkSrcOpts wantDyn - buildExtraSource mkSrcOpts wantDyn filename = do - let baseSrcOpts = - mkSrcOpts - verbosity - implInfo - lbi - bnfo - clbi - tmpDir - filename - vanillaSrcOpts = - if isGhcDynamic && wantDyn - then -- Dynamic GHC requires C/C++ sources to be built - -- with -fPIC for REPL to work. See #2207. - baseSrcOpts{ghcOptFPic = toFlag True} - else baseSrcOpts - profSrcOpts = - vanillaSrcOpts - `mappend` mempty - { ghcOptProfilingMode = toFlag True - } - sharedSrcOpts = - vanillaSrcOpts - `mappend` mempty - { ghcOptFPic = toFlag True - , ghcOptDynLinkMode = toFlag GhcDynamicOnly - } - opts - | needProfiling = profSrcOpts - | needDynamic && wantDyn = sharedSrcOpts - | otherwise = vanillaSrcOpts - -- TODO: Placing all Haskell, C, & C++ objects in a single directory - -- Has the potential for file collisions. In general we would - -- consider this a user error. However, we should strive to - -- add a warning if this occurs. - odir = fromFlag (ghcOptObjDir opts) - - createDirectoryIfMissingVerbose verbosity True odir - needsRecomp <- checkNeedsRecompilation filename opts - when needsRecomp $ - runGhcProg opts - - -- build any C++ sources - unless (null cxxSrcs) $ do - info verbosity "Building C++ Sources..." - buildExtraSources Internal.componentCxxGhcOptions True cxxSrcs - - -- build any C sources - unless (null cSrcs) $ do - info verbosity "Building C Sources..." - buildExtraSources Internal.componentCcGhcOptions True cSrcs - - -- build any JS sources - unless (not hasJsSupport || null jsSrcs) $ do - info verbosity "Building JS Sources..." - buildExtraSources Internal.componentJsGhcOptions False jsSrcs - - -- build any ASM sources - unless (null asmSrcs) $ do - info verbosity "Building Assembler Sources..." - buildExtraSources Internal.componentAsmGhcOptions True asmSrcs - - -- build any Cmm sources - unless (null cmmSrcs) $ do - info verbosity "Building C-- Sources..." - buildExtraSources Internal.componentCmmGhcOptions True cmmSrcs - - -- TODO: problem here is we need the .c files built first, so we can load them - -- with ghci, but .c files can depend on .h files generated by ghc by ffi - -- exports. - case bm of - GReplExe _ _ -> runReplOrWriteFlags verbosity ghcProg comp platform replFlags replOpts bnfo clbi (pkgName (PD.package pkg_descr)) - GReplFLib _ _ -> runReplOrWriteFlags verbosity ghcProg comp platform replFlags replOpts bnfo clbi (pkgName (PD.package pkg_descr)) - GBuildExe _ -> do - let linkOpts = - commonOpts - `mappend` linkerOpts - `mappend` mempty - { ghcOptLinkNoHsMain = toFlag (null inputFiles) - } - `mappend` (if withDynExe lbi then dynLinkerOpts else mempty) - - info verbosity "Linking..." - -- Work around old GHCs not relinking in this - -- situation, see #3294 - let target = targetDir targetName - when (compilerVersion comp < mkVersion [7, 7]) $ do - e <- doesFileExist target - when e (removeFile target) - runGhcProg linkOpts{ghcOptOutputFile = toFlag target} - GBuildFLib flib -> do - let - -- Instruct GHC to link against libHSrts. - rtsLinkOpts :: GhcOptions - rtsLinkOpts - | supportsFLinkRts = - mempty - { ghcOptLinkRts = toFlag True - } - | otherwise = - mempty - { ghcOptLinkLibs = rtsOptLinkLibs - , ghcOptLinkLibPath = toNubListR $ rtsLibPaths rtsInfo - } - where - threaded = hasThreaded (gbuildInfo bm) - supportsFLinkRts = compilerVersion comp >= mkVersion [9, 0] - rtsInfo = extractRtsInfo lbi - rtsOptLinkLibs = - [ if needDynamic - then - if threaded - then dynRtsThreadedLib (rtsDynamicInfo rtsInfo) - else dynRtsVanillaLib (rtsDynamicInfo rtsInfo) - else - if threaded - then statRtsThreadedLib (rtsStaticInfo rtsInfo) - else statRtsVanillaLib (rtsStaticInfo rtsInfo) - ] - - linkOpts :: GhcOptions - linkOpts = case foreignLibType flib of - ForeignLibNativeShared -> - commonOpts - `mappend` linkerOpts - `mappend` dynLinkerOpts - `mappend` rtsLinkOpts - `mappend` mempty - { ghcOptLinkNoHsMain = toFlag True - , ghcOptShared = toFlag True - , ghcOptFPic = toFlag True - , ghcOptLinkModDefFiles = toNubListR $ gbuildModDefFiles bm - } - ForeignLibNativeStatic -> - -- this should be caught by buildFLib - -- (and if we do implement this, we probably don't even want to call - -- ghc here, but rather Ar.createArLibArchive or something) - cabalBug "static libraries not yet implemented" - ForeignLibTypeUnknown -> - cabalBug "unknown foreign lib type" - -- We build under a (potentially) different filename to set a - -- soname on supported platforms. See also the note for - -- @flibBuildName@. - info verbosity "Linking..." - let buildName = flibBuildName lbi flib - runGhcProg linkOpts{ghcOptOutputFile = toFlag (targetDir buildName)} - renameFile (targetDir buildName) (targetDir targetName) - -data DynamicRtsInfo = DynamicRtsInfo - { dynRtsVanillaLib :: FilePath - , dynRtsThreadedLib :: FilePath - , dynRtsDebugLib :: FilePath - , dynRtsEventlogLib :: FilePath - , dynRtsThreadedDebugLib :: FilePath - , dynRtsThreadedEventlogLib :: FilePath - } - -data StaticRtsInfo = StaticRtsInfo - { statRtsVanillaLib :: FilePath - , statRtsThreadedLib :: FilePath - , statRtsDebugLib :: FilePath - , statRtsEventlogLib :: FilePath - , statRtsThreadedDebugLib :: FilePath - , statRtsThreadedEventlogLib :: FilePath - , statRtsProfilingLib :: FilePath - , statRtsThreadedProfilingLib :: FilePath - } - -data RtsInfo = RtsInfo - { rtsDynamicInfo :: DynamicRtsInfo - , rtsStaticInfo :: StaticRtsInfo - , rtsLibPaths :: [FilePath] - } - --- | Extract (and compute) information about the RTS library --- --- TODO: This hardcodes the name as @HSrts-ghc@. I don't know if we can --- find this information somewhere. We can lookup the 'hsLibraries' field of --- 'InstalledPackageInfo' but it will tell us @["HSrts", "Cffi"]@, which --- doesn't really help. -extractRtsInfo :: LocalBuildInfo -> RtsInfo -extractRtsInfo lbi = - case PackageIndex.lookupPackageName - (installedPkgs lbi) - (mkPackageName "rts") of - [(_, [rts])] -> aux rts - _otherwise -> error "No (or multiple) ghc rts package is registered" - where - aux :: InstalledPackageInfo -> RtsInfo - aux rts = - RtsInfo - { rtsDynamicInfo = - DynamicRtsInfo - { dynRtsVanillaLib = withGhcVersion "HSrts" - , dynRtsThreadedLib = withGhcVersion "HSrts_thr" - , dynRtsDebugLib = withGhcVersion "HSrts_debug" - , dynRtsEventlogLib = withGhcVersion "HSrts_l" - , dynRtsThreadedDebugLib = withGhcVersion "HSrts_thr_debug" - , dynRtsThreadedEventlogLib = withGhcVersion "HSrts_thr_l" - } - , rtsStaticInfo = - StaticRtsInfo - { statRtsVanillaLib = "HSrts" - , statRtsThreadedLib = "HSrts_thr" - , statRtsDebugLib = "HSrts_debug" - , statRtsEventlogLib = "HSrts_l" - , statRtsThreadedDebugLib = "HSrts_thr_debug" - , statRtsThreadedEventlogLib = "HSrts_thr_l" - , statRtsProfilingLib = "HSrts_p" - , statRtsThreadedProfilingLib = "HSrts_thr_p" - } - , rtsLibPaths = InstalledPackageInfo.libraryDirs rts - } - withGhcVersion = (++ ("-ghc" ++ prettyShow (compilerVersion (compiler lbi)))) - --- | Returns True if the modification date of the given source file is newer than --- the object file we last compiled for it, or if no object file exists yet. -checkNeedsRecompilation :: FilePath -> GhcOptions -> IO Bool -checkNeedsRecompilation filename opts = filename `moreRecentFile` oname - where - oname = getObjectFileName filename opts - --- | Finds the object file name of the given source file -getObjectFileName :: FilePath -> GhcOptions -> FilePath -getObjectFileName filename opts = oname - where - odir = fromFlag (ghcOptObjDir opts) - oext = fromFlagOrDefault "o" (ghcOptObjSuffix opts) - oname = odir replaceExtension filename oext - --- | Calculate the RPATHs for the component we are building. --- --- Calculates relative RPATHs when 'relocatable' is set. -getRPaths - :: LocalBuildInfo - -> ComponentLocalBuildInfo - -- ^ Component we are building - -> IO (NubListR FilePath) -getRPaths lbi clbi | supportRPaths hostOS = do - libraryPaths <- depLibraryPaths False (relocatable lbi) lbi clbi - let hostPref = case hostOS of - OSX -> "@loader_path" - _ -> "$ORIGIN" - relPath p = if isRelative p then hostPref p else p - rpaths = toNubListR (map relPath libraryPaths) - return rpaths - where - (Platform _ hostOS) = hostPlatform lbi - compid = compilerId . compiler $ lbi - - -- The list of RPath-supported operating systems below reflects the - -- platforms on which Cabal's RPATH handling is tested. It does _NOT_ - -- reflect whether the OS supports RPATH. - - -- E.g. when this comment was written, the *BSD operating systems were - -- untested with regards to Cabal RPATH handling, and were hence set to - -- 'False', while those operating systems themselves do support RPATH. - supportRPaths Linux = True - supportRPaths Windows = False - supportRPaths OSX = True - supportRPaths FreeBSD = - case compid of - CompilerId GHC ver | ver >= mkVersion [7, 10, 2] -> True - _ -> False - supportRPaths OpenBSD = False - supportRPaths NetBSD = False - supportRPaths DragonFly = False - supportRPaths Solaris = False - supportRPaths AIX = False - supportRPaths HPUX = False - supportRPaths IRIX = False - supportRPaths HaLVM = False - supportRPaths IOS = False - supportRPaths Android = False - supportRPaths Ghcjs = False - supportRPaths Wasi = False - supportRPaths Hurd = False - supportRPaths Haiku = False - supportRPaths (OtherOS _) = False --- Do _not_ add a default case so that we get a warning here when a new OS --- is added. - -getRPaths _ _ = return mempty - --- | Determine whether the given 'BuildInfo' is intended to link against the --- threaded RTS. This is used to determine which RTS to link against when --- building a foreign library with a GHC without support for @-flink-rts@. -hasThreaded :: BuildInfo -> Bool -hasThreaded bi = elem "-threaded" ghc - where - PerCompilerFlavor ghc _ = options bi +replExe replFlags njobs pkg lbi exe clbi = + GHC.build njobs pkg $ + PreBuildComponentInputs (BuildRepl replFlags) lbi (TargetInfo clbi (CExe exe)) -- | Extracts a String representing a hash of the ABI of a built -- library. It can fail if the library has not yet been built. @@ -2052,20 +676,12 @@ libAbiHash verbosity _pkg_descr lbi lib clbi = do libBi = libBuildInfo lib comp = compiler lbi platform = hostPlatform lbi - vanillaArgs0 = - (componentGhcOptions verbosity lbi libBi clbi (componentBuildDir lbi clbi)) + vanillaArgs = + (Internal.componentGhcOptions verbosity lbi libBi clbi (componentBuildDir lbi clbi)) `mappend` mempty { ghcOptMode = toFlag GhcModeAbiHash , ghcOptInputModules = toNubListR $ exposedModules lib } - vanillaArgs = - -- Package DBs unnecessary, and break ghc-cabal. See #3633 - -- BUT, put at least the global database so that 7.4 doesn't - -- break. - vanillaArgs0 - { ghcOptPackageDBs = [GlobalPackageDB] - , ghcOptPackages = mempty - } sharedArgs = vanillaArgs `mappend` mempty @@ -2094,38 +710,13 @@ libAbiHash verbosity _pkg_descr lbi lib clbi = do | otherwise = error "libAbiHash: Can't find an enabled library way" (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi) + hash <- getProgramInvocationOutput verbosity - (ghcInvocation ghcProg comp platform ghcArgs) - return (takeWhile (not . isSpace) hash) - -componentGhcOptions - :: Verbosity - -> LocalBuildInfo - -> BuildInfo - -> ComponentLocalBuildInfo - -> FilePath - -> GhcOptions -componentGhcOptions verbosity lbi = - Internal.componentGhcOptions verbosity implInfo lbi - where - comp = compiler lbi - implInfo = getImplInfo comp + =<< ghcInvocation verbosity ghcProg comp platform ghcArgs -componentCcGhcOptions - :: Verbosity - -> LocalBuildInfo - -> BuildInfo - -> ComponentLocalBuildInfo - -> FilePath - -> FilePath - -> GhcOptions -componentCcGhcOptions verbosity lbi = - Internal.componentCcGhcOptions verbosity implInfo lbi - where - comp = compiler lbi - implInfo = getImplInfo comp + return (takeWhile (not . isSpace) hash) -- ----------------------------------------------------------------------------- -- Installing @@ -2153,7 +744,7 @@ installExe exe = do createDirectoryIfMissingVerbose verbosity True binDir let exeName' = unUnqualComponentName $ exeName exe - exeFileName = exeTargetName (hostPlatform lbi) exe + exeFileName = exeTargetName (hostPlatform lbi) (exeName exe) fixedExeBaseName = progprefix ++ exeName' ++ progsuffix installBinary dest = do installExecutableFile @@ -2236,9 +827,9 @@ installLib -> IO () installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do -- copy .hi files over: - whenVanilla $ copyModuleFiles "hi" - whenProf $ copyModuleFiles "p_hi" - whenShared $ copyModuleFiles "dyn_hi" + whenVanilla $ copyModuleFiles $ Suffix "hi" + whenProf $ copyModuleFiles $ Suffix "p_hi" + whenShared $ copyModuleFiles $ Suffix "dyn_hi" -- copy extra compilation artifacts that ghc plugins may produce copyDirectoryIfExists extraCompilationArtifacts @@ -2421,15 +1012,3 @@ pkgRoot verbosity lbi = pkgRoot' createDirectoryIfMissing True rootDir return rootDir pkgRoot' (SpecificPackageDB fp) = return (takeDirectory fp) - --- ----------------------------------------------------------------------------- --- Utils - -isDynamic :: Compiler -> Bool -isDynamic = Internal.ghcLookupProperty "GHC Dynamic" - -supportsDynamicToo :: Compiler -> Bool -supportsDynamicToo = Internal.ghcLookupProperty "Support dynamic-too" - -withExt :: FilePath -> String -> FilePath -withExt fp ext = fp <.> if takeExtension fp /= ('.' : ext) then ext else "" diff --git a/Cabal/src/Distribution/Simple/GHC/Build.hs b/Cabal/src/Distribution/Simple/GHC/Build.hs new file mode 100644 index 00000000000..cc50e3bdb3c --- /dev/null +++ b/Cabal/src/Distribution/Simple/GHC/Build.hs @@ -0,0 +1,140 @@ +module Distribution.Simple.GHC.Build where + +import Distribution.Compat.Prelude +import Prelude () + +import Control.Monad.IO.Class +import qualified Data.Set as Set +import Distribution.PackageDescription as PD hiding (buildInfo) +import Distribution.Simple.Build.Inputs +import Distribution.Simple.Flag (Flag) +import Distribution.Simple.GHC.Build.ExtraSources +import Distribution.Simple.GHC.Build.Link +import Distribution.Simple.GHC.Build.Modules +import Distribution.Simple.GHC.Build.Utils (withDynFLib) +import Distribution.Simple.LocalBuildInfo +import Distribution.Simple.Program +import Distribution.Simple.Utils +import Distribution.Types.ComponentLocalBuildInfo (componentIsIndefinite) +import Distribution.Types.ParStrat +import Distribution.Utils.NubList (fromNubListR) +import System.Directory hiding (exeExtension) +import System.FilePath + +{- +Note [Build Target Dir vs Target Dir] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Where to place the build result (targetDir) and the build artifacts (buildTargetDir). + +\* For libraries, targetDir == buildTargetDir, where both the library and +artifacts are put together. + +\* For executables or foreign libs, buildTargetDir == targetDir/-tmp, where + the targetDir is the location where the target (e.g. the executable) is written to + and buildTargetDir is where the compilation artifacts (e.g. Main.o) will live + Arguably, this difference should not exist (#9498) (TODO) + +For instance, for a component `cabal-benchmarks`: + targetDir == /cabal-benchmarks + buildTargetDir == /cabal-benchmarks/cabal-benchmarks-tmp + +Or, for a library `Cabal`: + targetDir == /. + buildTargetDir == targetDir + +Furthermore, we need to account for the limit of characters in ghc +invocations that different OSes constrain us to. Cabal invocations can +rapidly reach this limit, in part, due to the long length of cabal v2 +prefixes. To minimize the likelihood, we use +`makeRelativeToCurrentDirectory` to shorten the paths used in invocations +(see da6321bb). + +However, in executables, we don't do this. It seems that we don't need to do it +for executable-like components because the linking step, instead of passing as +an argument the path to each module, it simply passes the module name, the sources dir, and --make. +RM: I believe we can use --make + module names instead of paths-to-objects +for linking libraries too (2024-01) (TODO) +-} + +-- | The main build phase of building a component. +-- Includes building Haskell modules, extra build sources, and linking. +build + :: Flag ParStrat + -> PackageDescription + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO () +build numJobs pkg_descr pbci = do + let + verbosity = buildVerbosity pbci + component = buildComponent pbci + isLib = buildIsLib pbci + lbi = localBuildInfo pbci + clbi = buildCLBI pbci + + -- Create a few directories for building the component + -- See Note [Build Target Dir vs Target Dir] + let targetDir_absolute = componentBuildDir lbi clbi + buildTargetDir_absolute + -- Libraries use the target dir for building (see above) + | isLib = targetDir_absolute + -- In other cases, use targetDir/-tmp + | targetDirName : _ <- reverse $ splitDirectories targetDir_absolute = + targetDir_absolute (targetDirName ++ "-tmp") + | otherwise = error "GHC.build: targetDir is empty" + + liftIO $ do + createDirectoryIfMissingVerbose verbosity True targetDir_absolute + createDirectoryIfMissingVerbose verbosity True buildTargetDir_absolute + + -- See Note [Build Target Dir vs Target Dir] as well + _targetDir <- liftIO $ makeRelativeToCurrentDirectory targetDir_absolute + buildTargetDir <- + -- To preserve the previous behaviour, we don't use relative dirs for + -- executables. Historically, this isn't needed to reduce the CLI limit + -- (unlike for libraries) because we link executables with the module names + -- instead of passing the path to object file -- that's something else we + -- can now fix after the refactor lands. + if isLib + then liftIO $ makeRelativeToCurrentDirectory buildTargetDir_absolute + else return buildTargetDir_absolute + + (ghcProg, _) <- liftIO $ requireProgram verbosity ghcProgram (withPrograms lbi) + + -- Determine in which ways we want to build the component + let + wantVanilla = if isLib then withVanillaLib lbi else False + -- Arguably, wantStatic should be "withFullyStaticExe lbi" for executables, + -- but it was not before the refactor. + wantStatic = if isLib then withStaticLib lbi else not (wantDynamic || wantProf) + wantDynamic = case component of + CLib{} -> withSharedLib lbi + CFLib flib -> withDynFLib flib + CExe{} -> withDynExe lbi + CTest{} -> withDynExe lbi + CBench{} -> withDynExe lbi + wantProf = if isLib then withProfLib lbi else withProfExe lbi + + -- See also Note [Building Haskell Modules accounting for TH] in Distribution.Simple.GHC.Build.Modules + -- We build static by default if no other way is wanted. + -- For executables and foreign libraries, there should only be one wanted way. + wantedWays = + Set.fromList $ + -- If building a library, we accumulate all the ways, + -- otherwise, we take just one. + (if isLib then id else take 1) $ + [ProfWay | wantProf] + -- I don't see why we shouldn't build with dynamic + -- indefinite components. + <> [DynWay | wantDynamic && not (componentIsIndefinite clbi)] + <> [StaticWay | wantStatic || wantVanilla || not (wantDynamic || wantProf)] + + liftIO $ info verbosity ("Wanted build ways: " ++ show (Set.toList wantedWays)) + + -- We need a separate build and link phase, and C sources must be compiled + -- after Haskell modules, because C sources may depend on stub headers + -- generated from compiling Haskell modules (#842, #3294). + buildOpts <- buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir_absolute wantedWays pbci + extraSources <- buildAllExtraSources ghcProg buildTargetDir pbci + linkOrLoadComponent ghcProg pkg_descr (fromNubListR extraSources) (buildTargetDir, targetDir_absolute) (wantedWays, buildOpts) pbci diff --git a/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs b/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs new file mode 100644 index 00000000000..07ad6ac31d8 --- /dev/null +++ b/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs @@ -0,0 +1,242 @@ +{-# LANGUAGE DisambiguateRecordFields #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} + +module Distribution.Simple.GHC.Build.ExtraSources where + +import Control.Monad +import Data.Foldable +import Distribution.Simple.Flag +import qualified Distribution.Simple.GHC.Internal as Internal +import Distribution.Simple.Program.GHC +import Distribution.Simple.Utils +import Distribution.Utils.NubList + +import Distribution.Types.BuildInfo +import Distribution.Types.Component +import Distribution.Types.TargetInfo + +import Distribution.Simple.GHC.Build.Utils +import Distribution.Simple.LocalBuildInfo +import Distribution.Simple.Program.Types +import Distribution.System (Arch (JavaScript), Platform (..)) +import Distribution.Types.ComponentLocalBuildInfo +import Distribution.Types.Executable +import Distribution.Verbosity (Verbosity) + +import Distribution.Simple.Build.Inputs + +-- | An action that builds all the extra build sources of a component, i.e. C, +-- C++, Js, Asm, C-- sources. +buildAllExtraSources + :: ConfiguredProgram + -- ^ The GHC configured program + -> FilePath + -- ^ The build directory for this target + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO (NubListR FilePath) + -- ^ Returns the (nubbed) list of extra sources that were built +buildAllExtraSources = + mconcat + [ buildCSources + , buildCxxSources + , buildJsSources + , buildAsmSources + , buildCmmSources + ] + +buildCSources + , buildCxxSources + , buildJsSources + , buildAsmSources + , buildCmmSources + :: ConfiguredProgram + -- ^ The GHC configured program + -> FilePath + -- ^ The build directory for this target + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO (NubListR FilePath) + -- ^ Returns the list of extra sources that were built +buildCSources = + buildExtraSources + "C Sources" + Internal.componentCcGhcOptions + True + ( \c -> + cSources (componentBuildInfo c) + ++ case c of + CExe exe | isC (modulePath exe) -> [modulePath exe] + _otherwise -> [] + ) +buildCxxSources = + buildExtraSources + "C++ Sources" + Internal.componentCxxGhcOptions + True + ( \c -> + cxxSources (componentBuildInfo c) + ++ case c of + CExe exe | isCxx (modulePath exe) -> [modulePath exe] + _otherwise -> [] + ) +buildJsSources ghcProg buildTargetDir = do + Platform hostArch _ <- hostPlatform <$> localBuildInfo + let hasJsSupport = hostArch == JavaScript + buildExtraSources + "JS Sources" + Internal.componentJsGhcOptions + False + ( \c -> + if hasJsSupport + then -- JS files are C-like with GHC's JS backend: they are + -- "compiled" into `.o` files (renamed with a header). + -- This is a difference from GHCJS, for which we only + -- pass the JS files at link time. + jsSources (componentBuildInfo c) + else mempty + ) + ghcProg + buildTargetDir +buildAsmSources = + buildExtraSources + "Assembler Sources" + Internal.componentAsmGhcOptions + True + (asmSources . componentBuildInfo) +buildCmmSources = + buildExtraSources + "C-- Sources" + Internal.componentCmmGhcOptions + True + (cmmSources . componentBuildInfo) + +-- | Create 'PreBuildComponentRules' for a given type of extra build sources +-- which are compiled via a GHC invocation with the given options. Used to +-- define built-in extra sources, such as, C, Cxx, Js, Asm, and Cmm sources. +buildExtraSources + :: String + -- ^ String describing the extra sources being built, for printing. + -> (Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions) + -- ^ Function to determine the @'GhcOptions'@ for the + -- invocation of GHC when compiling these extra sources (e.g. + -- @'Internal.componentCxxGhcOptions'@, + -- @'Internal.componentCmmGhcOptions'@) + -> Bool + -- ^ Some types of build sources should not be built in the dynamic way, namely, JS sources. + -- I'm not entirely sure this remains true after we migrate to supporting GHC's JS backend rather than GHCJS. + -- Boolean for "do we allow building these sources the dynamic way?" + -> (Component -> [FilePath]) + -- ^ View the extra sources of a component, typically from + -- the build info (e.g. @'asmSources'@, @'cSources'@). + -- @'Executable'@ components might additionally add the + -- program entry point (@main-is@ file) to the extra sources, + -- if it should be compiled as the rest of them. + -> ConfiguredProgram + -- ^ The GHC configured program + -> FilePath + -- ^ The build directory for this target + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO (NubListR FilePath) + -- ^ Returns the list of extra sources that were built +buildExtraSources description componentSourceGhcOptions wantDyn viewSources ghcProg buildTargetDir = + \PreBuildComponentInputs{buildingWhat, localBuildInfo = lbi, targetInfo} -> + let + bi = componentBuildInfo (targetComponent targetInfo) + verbosity = buildingWhatVerbosity buildingWhat + clbi = targetCLBI targetInfo + + sources = viewSources (targetComponent targetInfo) + + comp = compiler lbi + platform = hostPlatform lbi + -- Instead of keeping this logic here, we really just want to + -- receive as an input the `neededWays` from GHC/Build.build and build + -- accordingly, since we've already determined the extra needed ways + -- needed for e.g. template haskell. Although we'd have to account for 'wantDyn'. + isGhcDynamic = isDynamic comp + doingTH = usesTemplateHaskellOrQQ bi + forceSharedLib = doingTH && isGhcDynamic + runGhcProg = runGHC verbosity ghcProg comp platform + + buildAction sourceFile = do + let baseSrcOpts = + componentSourceGhcOptions + verbosity + lbi + bi + clbi + buildTargetDir + sourceFile + vanillaSrcOpts + -- Dynamic GHC requires C sources to be built + -- with -fPIC for REPL to work. See #2207. + | isGhcDynamic && wantDyn = baseSrcOpts{ghcOptFPic = toFlag True} + | otherwise = baseSrcOpts + profSrcOpts = + vanillaSrcOpts + `mappend` mempty + { ghcOptProfilingMode = toFlag True + } + sharedSrcOpts = + vanillaSrcOpts + `mappend` mempty + { ghcOptFPic = toFlag True + , ghcOptDynLinkMode = toFlag GhcDynamicOnly + } + -- TODO: Placing all Haskell, C, & C++ objects in a single directory + -- Has the potential for file collisions. In general we would + -- consider this a user error. However, we should strive to + -- add a warning if this occurs. + odir = fromFlag (ghcOptObjDir vanillaSrcOpts) + compileIfNeeded opts = do + needsRecomp <- checkNeedsRecompilation sourceFile opts + when needsRecomp $ runGhcProg opts + + -- TODO: This whole section can be streamlined to the + -- wantedWays+neededWays logic used in Build/Modules.hs + createDirectoryIfMissingVerbose verbosity True odir + case targetComponent targetInfo of + -- For libraries, we compile extra objects in the three ways: vanilla, shared, and profiled. + -- We suffix shared objects with .dyn_o and profiled ones with .p_o. + CLib _lib + -- Unless for repl, in which case we only need the vanilla way + | BuildRepl _ <- buildingWhat -> + compileIfNeeded vanillaSrcOpts + | otherwise -> + do + compileIfNeeded vanillaSrcOpts + when (wantDyn && (forceSharedLib || withSharedLib lbi)) $ + compileIfNeeded sharedSrcOpts{ghcOptObjSuffix = toFlag "dyn_o"} + when (withProfLib lbi) $ + compileIfNeeded profSrcOpts{ghcOptObjSuffix = toFlag "p_o"} + + -- For foreign libraries, we determine with which options to build the + -- objects (vanilla vs shared vs profiled) + CFLib flib + | withProfExe lbi -> -- It doesn't sound right to query "ProfExe" for a foreign library... + compileIfNeeded profSrcOpts + | withDynFLib flib && wantDyn -> + compileIfNeeded sharedSrcOpts + | otherwise -> + compileIfNeeded vanillaSrcOpts + -- For the remaining component types (Exec, Test, Bench), we also + -- determine with which options to build the objects (vanilla vs shared vs + -- profiled), but predicate is the same for the three kinds. + _exeLike + | withProfExe lbi -> + compileIfNeeded profSrcOpts + | withDynExe lbi && wantDyn -> + compileIfNeeded sharedSrcOpts + | otherwise -> + compileIfNeeded vanillaSrcOpts + in + -- build any sources + if (null sources || componentIsIndefinite clbi) + then return mempty + else do + info verbosity ("Building " ++ description ++ "...") + traverse_ buildAction sources + return (toNubListR sources) diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Link.hs b/Cabal/src/Distribution/Simple/GHC/Build/Link.hs new file mode 100644 index 00000000000..f25c60c887d --- /dev/null +++ b/Cabal/src/Distribution/Simple/GHC/Build/Link.hs @@ -0,0 +1,663 @@ +{-# LANGUAGE LambdaCase #-} + +module Distribution.Simple.GHC.Build.Link where + +import Distribution.Compat.Prelude +import Prelude () + +import Control.Exception (assert) +import Control.Monad (forM_) +import Control.Monad.IO.Class +import qualified Data.ByteString.Lazy.Char8 as BS +import qualified Data.Set as Set +import Distribution.Compat.Binary (encode) +import Distribution.Compat.ResponseFile +import Distribution.InstalledPackageInfo (InstalledPackageInfo) +import qualified Distribution.InstalledPackageInfo as IPI +import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo +import qualified Distribution.ModuleName as ModuleName +import Distribution.Package +import Distribution.PackageDescription as PD +import Distribution.PackageDescription.Utils (cabalBug) +import Distribution.Pretty +import Distribution.Simple.Build.Inputs +import Distribution.Simple.BuildPaths +import Distribution.Simple.Compiler +import Distribution.Simple.GHC.Build.Modules +import Distribution.Simple.GHC.Build.Utils (exeTargetName, flibBuildName, flibTargetName, withDynFLib) +import Distribution.Simple.GHC.ImplInfo +import qualified Distribution.Simple.GHC.Internal as Internal +import Distribution.Simple.LocalBuildInfo +import qualified Distribution.Simple.PackageIndex as PackageIndex +import Distribution.Simple.PreProcess.Types +import Distribution.Simple.Program +import qualified Distribution.Simple.Program.Ar as Ar +import Distribution.Simple.Program.GHC +import qualified Distribution.Simple.Program.Ld as Ld +import Distribution.Simple.Setup.Common +import Distribution.Simple.Setup.Repl +import Distribution.Simple.Utils +import Distribution.System +import Distribution.Types.ComponentLocalBuildInfo +import Distribution.Utils.NubList +import Distribution.Verbosity +import Distribution.Version +import System.Directory +import System.FilePath + +-- | Links together the object files of the Haskell modules and extra sources +-- using the context in which the component is being built. +-- +-- If the build kind is 'BuildRepl', we load the component into GHCi instead of linking. +linkOrLoadComponent + :: ConfiguredProgram + -- ^ The configured GHC program that will be used for linking + -> PackageDescription + -- ^ The package description containing the component being built + -> [FilePath] + -- ^ The full list of extra build sources (all C, C++, Js, + -- Asm, and Cmm sources), which were compiled to object + -- files. + -> (FilePath, FilePath) + -- ^ The build target dir, and the target dir. + -- See Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build + -> (Set.Set BuildWay, BuildWay -> GhcOptions) + -- ^ The set of build ways wanted based on the user opts, and a function to + -- convert a build way into the set of ghc options that were used to build + -- that way. + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO () +linkOrLoadComponent ghcProg pkg_descr extraSources (buildTargetDir, targetDir) (wantedWays, buildOpts) pbci = do + let + verbosity = buildVerbosity pbci + target = targetInfo pbci + component = buildComponent pbci + what = buildingWhat pbci + lbi = localBuildInfo pbci + bi = buildBI pbci + clbi = buildCLBI pbci + + -- ensure extra lib dirs exist before passing to ghc + cleanedExtraLibDirs <- liftIO $ filterM doesDirectoryExist (extraLibDirs bi) + cleanedExtraLibDirsStatic <- liftIO $ filterM doesDirectoryExist (extraLibDirsStatic bi) + + let + extraSourcesObjs = map (`replaceExtension` objExtension) extraSources + + -- TODO: Shouldn't we use withStaticLib for libraries and something else + -- for foreign libs in the three cases where we use `withFullyStaticExe` below? + linkerOpts rpaths = + mempty + { ghcOptLinkOptions = + PD.ldOptions bi + ++ [ "-static" + | withFullyStaticExe lbi + ] + -- Pass extra `ld-options` given + -- through to GHC's linker. + ++ maybe + [] + programOverrideArgs + (lookupProgram ldProgram (withPrograms lbi)) + , ghcOptLinkLibs = + if withFullyStaticExe lbi + then extraLibsStatic bi + else extraLibs bi + , ghcOptLinkLibPath = + toNubListR $ + if withFullyStaticExe lbi + then cleanedExtraLibDirsStatic + else cleanedExtraLibDirs + , ghcOptLinkFrameworks = toNubListR $ PD.frameworks bi + , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs bi + , ghcOptInputFiles = toNubListR [buildTargetDir x | x <- extraSourcesObjs] + , ghcOptNoLink = Flag False + , ghcOptRPaths = rpaths + } + case what of + BuildRepl replFlags -> liftIO $ do + let + -- For repl we use the vanilla (static) ghc options + staticOpts = buildOpts StaticWay + replOpts = + staticOpts + { -- Repl options use Static as the base, but doesn't need to pass -static. + -- However, it maybe should, for uniformity. + ghcOptDynLinkMode = NoFlag + , ghcOptExtra = + Internal.filterGhciFlags + (ghcOptExtra staticOpts) + <> replOptionsFlags (replReplOptions replFlags) + , ghcOptInputModules = replNoLoad (replReplOptions replFlags) (ghcOptInputModules staticOpts) + , ghcOptInputFiles = replNoLoad (replReplOptions replFlags) (ghcOptInputFiles staticOpts) + } + -- For a normal compile we do separate invocations of ghc for + -- compiling as for linking. But for repl we have to do just + -- the one invocation, so that one has to include all the + -- linker stuff too, like -l flags and any .o files from C + -- files etc. + -- + -- TODO: The repl doesn't use the runtime paths from linkerOpts + -- (ghcOptRPaths), which looks like a bug. After the refactor we + -- can fix this. + `mappend` linkerOpts mempty + `mappend` mempty + { ghcOptMode = toFlag GhcModeInteractive + , ghcOptOptimisation = toFlag GhcNoOptimisation + } + + -- TODO: problem here is we need the .c files built first, so we can load them + -- with ghci, but .c files can depend on .h files generated by ghc by ffi + -- exports. + when (case component of CLib lib -> null (allLibModules lib clbi); _ -> False) $ + warn verbosity "No exposed modules" + runReplOrWriteFlags ghcProg lbi replFlags replOpts (pkgName (PD.package pkg_descr)) target + _otherwise -> + let + runGhcProg = runGHC verbosity ghcProg comp platform + platform = hostPlatform lbi + comp = compiler lbi + in + when (not $ componentIsIndefinite clbi) $ do + -- If not building dynamically, we don't pass any runtime paths. + rpaths <- if DynWay `Set.member` wantedWays then getRPaths pbci else return (toNubListR []) + liftIO $ do + info verbosity "Linking..." + let linkExeLike name = linkExecutable (linkerOpts rpaths) (wantedWays, buildOpts) targetDir name runGhcProg lbi + case component of + CLib lib -> linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths wantedWays + CFLib flib -> linkFLib flib bi lbi (linkerOpts rpaths) (wantedWays, buildOpts) targetDir runGhcProg + CExe exe -> linkExeLike (exeName exe) + CTest test -> linkExeLike (testName test) + CBench bench -> linkExeLike (benchmarkName bench) + +-- | Link a library component +linkLibrary + :: FilePath + -- ^ The library target build directory + -> [FilePath] + -- ^ The list of extra lib dirs that exist (aka "cleaned") + -> PackageDescription + -- ^ The package description containing this library + -> Verbosity + -> (GhcOptions -> IO ()) + -- ^ Run the configured Ghc program + -> Library + -> LocalBuildInfo + -> ComponentLocalBuildInfo + -> [FilePath] + -- ^ Extra build sources (that were compiled to objects) + -> NubListR FilePath + -- ^ A list with the runtime-paths (rpaths), or empty if not linking dynamically + -> Set.Set BuildWay + -- ^ Wanted build ways and corresponding build options + -> IO () +linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths wantedWays = do + let + compiler_id = compilerId comp + comp = compiler lbi + ghcVersion = compilerVersion comp + implInfo = getImplInfo comp + uid = componentUnitId clbi + libBi = libBuildInfo lib + Platform _hostArch hostOS = hostPlatform lbi + vanillaLibFilePath = buildTargetDir mkLibName uid + profileLibFilePath = buildTargetDir mkProfLibName uid + sharedLibFilePath = + buildTargetDir + mkSharedLibName (hostPlatform lbi) compiler_id uid + staticLibFilePath = + buildTargetDir + mkStaticLibName (hostPlatform lbi) compiler_id uid + ghciLibFilePath = buildTargetDir Internal.mkGHCiLibName uid + ghciProfLibFilePath = buildTargetDir Internal.mkGHCiProfLibName uid + libInstallPath = + libdir $ + absoluteComponentInstallDirs + pkg_descr + lbi + uid + NoCopyDest + sharedLibInstallPath = + libInstallPath + mkSharedLibName (hostPlatform lbi) compiler_id uid + + getObjFiles way = + mconcat + [ Internal.getHaskellObjects + implInfo + lib + lbi + clbi + buildTargetDir + (buildWayPrefix way ++ objExtension) + True + , pure $ + map (buildTargetDir ) $ + map ((`replaceExtension` (buildWayPrefix way ++ objExtension))) extraSources + , catMaybes + <$> sequenceA + [ findFileWithExtension + [Suffix $ buildWayPrefix way ++ objExtension] + [buildTargetDir] + (ModuleName.toFilePath x ++ "_stub") + | ghcVersion < mkVersion [7, 2] -- ghc-7.2+ does not make _stub.o files + , x <- allLibModules lib clbi + ] + ] + + -- I'm fairly certain that, just like the executable, we can keep just the + -- module input list, and point to the right sources dir (as is already + -- done), and GHC will pick up the right suffix (p_ for profile, dyn_ when + -- -shared...). The downside to doing this is that GHC would have to + -- reconstruct the module graph again. + -- That would mean linking the lib would be just like the executable, and + -- we could more easily merge the two. + -- + -- Right now, instead, we pass the path to each object file. + ghcBaseLinkArgs = + mempty + { -- TODO: This basically duplicates componentGhcOptions. + -- I think we want to do the same as we do for executables: re-use the + -- base options, and link by module names, not object paths. + ghcOptExtra = hcStaticOptions GHC libBi + , ghcOptHideAllPackages = toFlag True + , ghcOptNoAutoLinkPackages = toFlag True + , ghcOptPackageDBs = withPackageDB lbi + , ghcOptThisUnitId = case clbi of + LibComponentLocalBuildInfo{componentCompatPackageKey = pk} -> + toFlag pk + _ -> mempty + , ghcOptThisComponentId = case clbi of + LibComponentLocalBuildInfo + { componentInstantiatedWith = insts + } -> + if null insts + then mempty + else toFlag (componentComponentId clbi) + _ -> mempty + , ghcOptInstantiatedWith = case clbi of + LibComponentLocalBuildInfo + { componentInstantiatedWith = insts + } -> + insts + _ -> [] + , ghcOptPackages = + toNubListR $ + Internal.mkGhcOptPackages mempty clbi + } + + -- After the relocation lib is created we invoke ghc -shared + -- with the dependencies spelled out as -package arguments + -- and ghc invokes the linker with the proper library paths + ghcSharedLinkArgs dynObjectFiles = + ghcBaseLinkArgs + { ghcOptShared = toFlag True + , ghcOptDynLinkMode = toFlag GhcDynamicOnly + , ghcOptInputFiles = toNubListR dynObjectFiles + , ghcOptOutputFile = toFlag sharedLibFilePath + , -- For dynamic libs, Mac OS/X needs to know the install location + -- at build time. This only applies to GHC < 7.8 - see the + -- discussion in #1660. + ghcOptDylibName = + if hostOS == OSX + && ghcVersion < mkVersion [7, 8] + then toFlag sharedLibInstallPath + else mempty + , ghcOptLinkLibs = extraLibs libBi + , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs + , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi + , ghcOptLinkFrameworkDirs = + toNubListR $ PD.extraFrameworkDirs libBi + , ghcOptRPaths = rpaths + } + ghcStaticLinkArgs staticObjectFiles = + ghcBaseLinkArgs + { ghcOptStaticLib = toFlag True + , ghcOptInputFiles = toNubListR staticObjectFiles + , ghcOptOutputFile = toFlag staticLibFilePath + , ghcOptLinkLibs = extraLibs libBi + , -- TODO: Shouldn't this use cleanedExtraLibDirsStatic instead? + ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs + } + + staticObjectFiles <- getObjFiles StaticWay + profObjectFiles <- getObjFiles ProfWay + dynamicObjectFiles <- getObjFiles DynWay + + let + linkWay = \case + ProfWay -> do + Ar.createArLibArchive verbosity lbi profileLibFilePath profObjectFiles + when (withGHCiLib lbi) $ do + (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi) + Ld.combineObjectFiles + verbosity + lbi + ldProg + ghciProfLibFilePath + profObjectFiles + DynWay -> do + runGhcProg $ ghcSharedLinkArgs dynamicObjectFiles + StaticWay -> do + when (withVanillaLib lbi) $ do + Ar.createArLibArchive verbosity lbi vanillaLibFilePath staticObjectFiles + when (withGHCiLib lbi) $ do + (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi) + Ld.combineObjectFiles + verbosity + lbi + ldProg + ghciLibFilePath + staticObjectFiles + when (withStaticLib lbi) $ do + runGhcProg $ ghcStaticLinkArgs staticObjectFiles + + -- ROMES: Why exactly branch on staticObjectFiles, rather than any other build + -- kind that we might have wanted instead? + -- This would be simpler by not adding every object to the invocation, and + -- rather using module names. + unless (null staticObjectFiles) $ do + info verbosity (show (ghcOptPackages (Internal.componentGhcOptions verbosity lbi libBi clbi buildTargetDir))) + traverse_ linkWay wantedWays + +-- | Link the executable resulting from building this component, be it an +-- executable, test, or benchmark component. +linkExecutable + :: (GhcOptions) + -- ^ The linker-specific GHC options + -> (Set.Set BuildWay, BuildWay -> GhcOptions) + -- ^ The wanted build ways and corresponding GhcOptions that were + -- used to compile the modules in that way. + -> FilePath + -- ^ The target dir (2024-01:note: not the same as build target + -- dir, see Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build) + -> UnqualComponentName + -- ^ Name of executable-like target + -> (GhcOptions -> IO ()) + -- ^ Run the configured GHC program + -> LocalBuildInfo + -> IO () +linkExecutable linkerOpts (wantedWays, buildOpts) targetDir targetName runGhcProg lbi = do + -- When building an executable, we should only "want" one build way. + assert (Set.size wantedWays == 1) $ + forM_ wantedWays $ \way -> do + let baseOpts = buildOpts way + linkOpts = + baseOpts + `mappend` linkerOpts + `mappend` mempty + { -- If there are no input Haskell files we pass -no-hs-main, and + -- assume there is a main function in another non-haskell object + ghcOptLinkNoHsMain = toFlag (ghcOptInputFiles baseOpts == mempty && ghcOptInputScripts baseOpts == mempty) + } + comp = compiler lbi + + -- Work around old GHCs not relinking in this + -- situation, see #3294 + let target = targetDir exeTargetName (hostPlatform lbi) targetName + when (compilerVersion comp < mkVersion [7, 7]) $ do + e <- doesFileExist target + when e (removeFile target) + runGhcProg linkOpts{ghcOptOutputFile = toFlag target} + +-- | Link a foreign library component +linkFLib + :: ForeignLib + -> BuildInfo + -> LocalBuildInfo + -> (GhcOptions) + -- ^ The linker-specific GHC options + -> (Set.Set BuildWay, BuildWay -> GhcOptions) + -- ^ The wanted build ways and corresponding GhcOptions that were + -- used to compile the modules in that way. + -> FilePath + -- ^ The target dir (2024-01:note: not the same as build target + -- dir, see Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build) + -> (GhcOptions -> IO ()) + -- ^ Run the configured GHC program + -> IO () +linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = do + let + comp = compiler lbi + + -- Instruct GHC to link against libHSrts. + rtsLinkOpts :: GhcOptions + rtsLinkOpts + | supportsFLinkRts = + mempty + { ghcOptLinkRts = toFlag True + } + | otherwise = + mempty + { ghcOptLinkLibs = rtsOptLinkLibs + , ghcOptLinkLibPath = toNubListR $ rtsLibPaths rtsInfo + } + where + threaded = hasThreaded bi + supportsFLinkRts = compilerVersion comp >= mkVersion [9, 0] + rtsInfo = extractRtsInfo lbi + rtsOptLinkLibs = + [ if withDynFLib flib + then + if threaded + then dynRtsThreadedLib (rtsDynamicInfo rtsInfo) + else dynRtsVanillaLib (rtsDynamicInfo rtsInfo) + else + if threaded + then statRtsThreadedLib (rtsStaticInfo rtsInfo) + else statRtsVanillaLib (rtsStaticInfo rtsInfo) + ] + + linkOpts :: BuildWay -> GhcOptions + linkOpts way = case foreignLibType flib of + ForeignLibNativeShared -> + (buildOpts way) + `mappend` linkerOpts + `mappend` rtsLinkOpts + `mappend` mempty + { ghcOptLinkNoHsMain = toFlag True + , ghcOptShared = toFlag True + , ghcOptFPic = toFlag True + , ghcOptLinkModDefFiles = toNubListR $ foreignLibModDefFile flib + } + ForeignLibNativeStatic -> + -- this should be caught by buildFLib + -- (and if we do implement this, we probably don't even want to call + -- ghc here, but rather Ar.createArLibArchive or something) + cabalBug "static libraries not yet implemented" + ForeignLibTypeUnknown -> + cabalBug "unknown foreign lib type" + -- We build under a (potentially) different filename to set a + -- soname on supported platforms. See also the note for + -- @flibBuildName@. + let buildName = flibBuildName lbi flib + -- There should not be more than one wanted way when building an flib + assert (Set.size wantedWays == 1) $ + forM_ wantedWays $ \way -> do + runGhcProg (linkOpts way){ghcOptOutputFile = toFlag (targetDir buildName)} + renameFile (targetDir buildName) (targetDir flibTargetName lbi flib) + +-- | Calculate the RPATHs for the component we are building. +-- +-- Calculates relative RPATHs when 'relocatable' is set. +getRPaths + :: PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO (NubListR FilePath) +getRPaths pbci = do + let + lbi = localBuildInfo pbci + bi = buildBI pbci + clbi = buildCLBI pbci + + (Platform _ hostOS) = hostPlatform lbi + compid = compilerId . compiler $ lbi + + -- The list of RPath-supported operating systems below reflects the + -- platforms on which Cabal's RPATH handling is tested. It does _NOT_ + -- reflect whether the OS supports RPATH. + + -- E.g. when this comment was written, the *BSD operating systems were + -- untested with regards to Cabal RPATH handling, and were hence set to + -- 'False', while those operating systems themselves do support RPATH. + supportRPaths Linux = True + supportRPaths Windows = False + supportRPaths OSX = True + supportRPaths FreeBSD = + case compid of + CompilerId GHC ver | ver >= mkVersion [7, 10, 2] -> True + _ -> False + supportRPaths OpenBSD = False + supportRPaths NetBSD = False + supportRPaths DragonFly = False + supportRPaths Solaris = False + supportRPaths AIX = False + supportRPaths HPUX = False + supportRPaths IRIX = False + supportRPaths HaLVM = False + supportRPaths IOS = False + supportRPaths Android = False + supportRPaths Ghcjs = False + supportRPaths Wasi = False + supportRPaths Hurd = True + supportRPaths Haiku = False + supportRPaths (OtherOS _) = False + -- Do _not_ add a default case so that we get a warning here when a new OS + -- is added. + + if supportRPaths hostOS + then do + libraryPaths <- liftIO $ depLibraryPaths False (relocatable lbi) lbi clbi + let hostPref = case hostOS of + OSX -> "@loader_path" + _ -> "$ORIGIN" + relPath p = if isRelative p then hostPref p else p + rpaths = toNubListR (map relPath libraryPaths) <> toNubListR (extraLibDirs bi) + return rpaths + else return mempty + +data DynamicRtsInfo = DynamicRtsInfo + { dynRtsVanillaLib :: FilePath + , dynRtsThreadedLib :: FilePath + , dynRtsDebugLib :: FilePath + , dynRtsEventlogLib :: FilePath + , dynRtsThreadedDebugLib :: FilePath + , dynRtsThreadedEventlogLib :: FilePath + } + +data StaticRtsInfo = StaticRtsInfo + { statRtsVanillaLib :: FilePath + , statRtsThreadedLib :: FilePath + , statRtsDebugLib :: FilePath + , statRtsEventlogLib :: FilePath + , statRtsThreadedDebugLib :: FilePath + , statRtsThreadedEventlogLib :: FilePath + , statRtsProfilingLib :: FilePath + , statRtsThreadedProfilingLib :: FilePath + } + +data RtsInfo = RtsInfo + { rtsDynamicInfo :: DynamicRtsInfo + , rtsStaticInfo :: StaticRtsInfo + , rtsLibPaths :: [FilePath] + } + +-- | Extract (and compute) information about the RTS library +-- +-- TODO: This hardcodes the name as @HSrts-ghc@. I don't know if we can +-- find this information somewhere. We can lookup the 'hsLibraries' field of +-- 'InstalledPackageInfo' but it will tell us @["HSrts", "Cffi"]@, which +-- doesn't really help. +extractRtsInfo :: LocalBuildInfo -> RtsInfo +extractRtsInfo lbi = + case PackageIndex.lookupPackageName + (installedPkgs lbi) + (mkPackageName "rts") of + [(_, [rts])] -> aux rts + _otherwise -> error "No (or multiple) ghc rts package is registered" + where + aux :: InstalledPackageInfo -> RtsInfo + aux rts = + RtsInfo + { rtsDynamicInfo = + DynamicRtsInfo + { dynRtsVanillaLib = withGhcVersion "HSrts" + , dynRtsThreadedLib = withGhcVersion "HSrts_thr" + , dynRtsDebugLib = withGhcVersion "HSrts_debug" + , dynRtsEventlogLib = withGhcVersion "HSrts_l" + , dynRtsThreadedDebugLib = withGhcVersion "HSrts_thr_debug" + , dynRtsThreadedEventlogLib = withGhcVersion "HSrts_thr_l" + } + , rtsStaticInfo = + StaticRtsInfo + { statRtsVanillaLib = "HSrts" + , statRtsThreadedLib = "HSrts_thr" + , statRtsDebugLib = "HSrts_debug" + , statRtsEventlogLib = "HSrts_l" + , statRtsThreadedDebugLib = "HSrts_thr_debug" + , statRtsThreadedEventlogLib = "HSrts_thr_l" + , statRtsProfilingLib = "HSrts_p" + , statRtsThreadedProfilingLib = "HSrts_thr_p" + } + , rtsLibPaths = InstalledPackageInfo.libraryDirs rts + } + withGhcVersion = (++ ("-ghc" ++ prettyShow (compilerVersion (compiler lbi)))) + +-- | Determine whether the given 'BuildInfo' is intended to link against the +-- threaded RTS. This is used to determine which RTS to link against when +-- building a foreign library with a GHC without support for @-flink-rts@. +hasThreaded :: BuildInfo -> Bool +hasThreaded bi = elem "-threaded" ghc + where + PerCompilerFlavor ghc _ = options bi + +-- | Load a target component into a repl, or write to disk a script which runs +-- GHCi with the GHC options Cabal elaborated to load the component interactively. +runReplOrWriteFlags + :: ConfiguredProgram + -> LocalBuildInfo + -> ReplFlags + -> GhcOptions + -> PackageName + -> TargetInfo + -> IO () +runReplOrWriteFlags ghcProg lbi rflags ghcOpts pkg_name target = + let bi = componentBuildInfo $ targetComponent target + clbi = targetCLBI target + comp = compiler lbi + platform = hostPlatform lbi + in case replOptionsFlagOutput (replReplOptions rflags) of + NoFlag -> runGHC (fromFlag $ replVerbosity rflags) ghcProg comp platform ghcOpts + Flag out_dir -> do + src_dir <- getCurrentDirectory + let uid = componentUnitId clbi + this_unit = prettyShow uid + reexported_modules = [mn | LibComponentLocalBuildInfo{} <- [clbi], IPI.ExposedModule mn (Just{}) <- componentExposedModules clbi] + hidden_modules = otherModules bi + extra_opts = + concat $ + [ ["-this-package-name", prettyShow pkg_name] + , ["-working-dir", src_dir] + ] + ++ [ ["-reexported-module", prettyShow m] | m <- reexported_modules + ] + ++ [ ["-hidden-module", prettyShow m] | m <- hidden_modules + ] + -- Create "paths" subdirectory if it doesn't exist. This is where we write + -- information about how the PATH was augmented. + createDirectoryIfMissing False (out_dir "paths") + -- Write out the PATH information into `paths` subdirectory. + writeFileAtomic (out_dir "paths" this_unit) (encode ghcProg) + -- Write out options for this component into a file ready for loading into + -- the multi-repl + writeFileAtomic (out_dir this_unit) $ + BS.pack $ + escapeArgs $ + extra_opts ++ renderGhcOptions comp platform (ghcOpts{ghcOptMode = NoFlag}) + +replNoLoad :: Ord a => ReplOptions -> NubListR a -> NubListR a +replNoLoad replFlags l + | replOptionsNoLoad replFlags == Flag True = mempty + | otherwise = l diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs b/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs new file mode 100644 index 00000000000..0a6c408ee4b --- /dev/null +++ b/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs @@ -0,0 +1,352 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE TupleSections #-} + +module Distribution.Simple.GHC.Build.Modules (buildHaskellModules, BuildWay (..), buildWayPrefix) where + +import Control.Monad.IO.Class +import Distribution.Compat.Prelude + +import Data.List (sortOn, (\\)) +import qualified Data.Set as Set +import Distribution.CabalSpecVersion +import Distribution.ModuleName (ModuleName) +import qualified Distribution.PackageDescription as PD +import Distribution.Pretty +import Distribution.Simple.Build.Inputs +import Distribution.Simple.Compiler +import Distribution.Simple.GHC.Build.Utils +import qualified Distribution.Simple.GHC.Internal as Internal +import qualified Distribution.Simple.Hpc as Hpc +import Distribution.Simple.LocalBuildInfo +import Distribution.Simple.Program.GHC +import Distribution.Simple.Program.Types +import Distribution.Simple.Setup.Common +import Distribution.Simple.Utils +import Distribution.Types.Benchmark +import Distribution.Types.BenchmarkInterface +import Distribution.Types.BuildInfo +import Distribution.Types.Executable +import Distribution.Types.ForeignLib +import Distribution.Types.PackageName.Magic +import Distribution.Types.ParStrat +import Distribution.Types.TestSuite +import Distribution.Types.TestSuiteInterface +import Distribution.Utils.NubList +import System.FilePath + +{- +Note [Building Haskell Modules accounting for TH] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are multiple ways in which we may want to build our Haskell modules: + * The static way (-static) + * The dynamic/shared way (-dynamic) + * The profiled way (-prof) + +For libraries, we may /want/ to build modules in all three ways, or in any combination, depending on user options. +For executables, we just /want/ to build the executable in the requested way. + +In practice, however, we may /need/ to build modules in additional ways beyonds the ones that were requested. +This can happen because of Template Haskell. + +When we're using Template Haskell, we /need/ to additionally build modules with +the used GHC's default/vanilla ABI. This is because the code that TH needs to +run at compile time needs to be the vanilla ABI so it can be loaded up and run +by the compiler. With dynamic-by-default GHC the TH object files loaded at +compile-time need to be .dyn_o instead of .o. + + * If the GHC is dynamic by default, that means we may need to also build + the dynamic way in addition the wanted way. + + * If the GHC is static by default, we may need to build statically additionally. + +Of course, if the /wanted/ way is the way additionally /needed/ for TH, we don't need to do extra work. + +If it turns out that in the end we need to build both statically and +dynamically, we want to make use of GHC's -static -dynamic-too capability, which +builds modules in the two ways in a single invocation. + +If --dynamic-too is not supported by the GHC, then we need to be careful about +the order in which modules are built. Specifically, we must first build the +modules for TH with the vanilla ABI, and only afterwards the desired +(non-default) ways. + +A few examples: + +To build an executable with profiling, with a dynamic by default GHC, and TH is used: + * Build dynamic (needed) objects + * Build profiled objects + +To build a library with profiling and dynamically, with a static by default GHC, and TH is used: + * Build dynamic (wanted) and static (needed) objects together with --dynamic-too + * Build profiled objects + +To build an executable statically, with a static by default GHC, regardless of whether TH is used: + * Simply build static objects + +-} + +-- | Compile the Haskell modules of the component being built. +buildHaskellModules + :: Flag ParStrat + -- ^ The parallelism strategy (e.g. num of jobs) + -> ConfiguredProgram + -- ^ The GHC configured program + -> PD.PackageDescription + -- ^ The package description + -> FilePath + -- ^ The path to the build directory for this target, which + -- has already been created. + -> Set.Set BuildWay + -- ^ The set of wanted build ways according to user options + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO (BuildWay -> GhcOptions) + -- ^ Returns a mapping from build ways to the 'GhcOptions' used in the + -- invocation used to compile the component in that 'BuildWay'. + -- This can be useful in, eg, a linker invocation, in which we want to use the + -- same options and list the same inputs as those used for building. +buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = do + -- See Note [Building Haskell Modules accounting for TH] + + let + verbosity = buildVerbosity pbci + isLib = buildIsLib pbci + clbi = buildCLBI pbci + lbi = localBuildInfo pbci + bi = buildBI pbci + what = buildingWhat pbci + comp = buildCompiler pbci + + -- If this component will be loaded into a repl, we don't compile the modules at all. + forRepl + | BuildRepl{} <- what = True + | otherwise = False + + -- TODO: do we need to put hs-boot files into place for mutually recursive + -- modules? FIX: what about exeName.hi-boot? + + -- Determine if program coverage should be enabled and if so, what + -- '-hpcdir' should be. + let isCoverageEnabled = if isLib then libCoverage lbi else exeCoverage lbi + hpcdir way + | forRepl = mempty -- HPC is not supported in ghci + | isCoverageEnabled = Flag $ Hpc.mixDir (buildTargetDir extraCompilationArtifacts) way + | otherwise = mempty + + (inputFiles, inputModules) <- componentInputs buildTargetDir pkg_descr pbci + + let + runGhcProg = runGHC verbosity ghcProg comp platform + platform = hostPlatform lbi + + -- See Note [Building Haskell Modules accounting for TH] + doingTH = usesTemplateHaskellOrQQ bi + + -- We define the base opts which are shared across different build ways in + -- 'buildHaskellModules' + baseOpts way = + (Internal.componentGhcOptions verbosity lbi bi clbi buildTargetDir) + `mappend` mempty + { ghcOptMode = toFlag GhcModeMake + , -- Previously we didn't pass -no-link when building libs, + -- but I think that could result in a bug (e.g. if a lib module is + -- called Main and exports main). So we really want nolink when + -- building libs too (TODO). + ghcOptNoLink = if isLib then NoFlag else toFlag True + , ghcOptNumJobs = numJobs + , ghcOptInputModules = toNubListR inputModules + , ghcOptInputFiles = + toNubListR $ + if PD.package pkg_descr == fakePackageId + then filter isHaskell inputFiles + else inputFiles + , ghcOptInputScripts = + toNubListR $ + if PD.package pkg_descr == fakePackageId + then filter (not . isHaskell) inputFiles + else [] + , ghcOptExtra = buildWayExtraHcOptions way GHC bi + , ghcOptHiSuffix = optSuffixFlag (buildWayPrefix way) "hi" + , ghcOptObjSuffix = optSuffixFlag (buildWayPrefix way) "o" + , ghcOptHPCDir = hpcdir (buildWayHpcWay way) -- maybe this should not be passed for vanilla? + } + where + optSuffixFlag "" _ = NoFlag + optSuffixFlag pre x = toFlag (pre ++ x) + + -- For libs we don't pass -static when building static, leaving it + -- implicit. We should just always pass -static, but we don't want to + -- change behaviour when doing the refactor. + staticOpts = (baseOpts StaticWay){ghcOptDynLinkMode = if isLib then NoFlag else toFlag GhcStaticOnly} + dynOpts = + (baseOpts DynWay) + { ghcOptDynLinkMode = toFlag GhcDynamicOnly -- use -dynamic + , -- TODO: Does it hurt to set -fPIC for executables? + ghcOptFPic = toFlag True -- use -fPIC + } + profOpts = + (baseOpts ProfWay) + { ghcOptProfilingMode = toFlag True + , ghcOptProfilingAuto = + Internal.profDetailLevelFlag + (if isLib then True else False) + ((if isLib then withProfLibDetail else withProfExeDetail) lbi) + } + -- Options for building both static and dynamic way at the same time, using + -- the GHC flag -static and -dynamic-too + dynTooOpts = + (baseOpts StaticWay) + { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic -- use -dynamic-too + , ghcOptDynHiSuffix = toFlag (buildWayPrefix DynWay ++ "hi") + , ghcOptDynObjSuffix = toFlag (buildWayPrefix DynWay ++ "o") + , ghcOptHPCDir = hpcdir Hpc.Dyn + -- Should we pass hcSharedOpts in the -dynamic-too ghc invocation? + -- (Note that `baseOtps StaticWay = hcStaticOptions`, not hcSharedOpts) + } + + -- Determines how to build for each way, also serves as the base options + -- for loading modules in 'linkOrLoadComponent' + buildOpts way = case way of + StaticWay -> staticOpts + DynWay -> dynOpts + ProfWay -> profOpts + + defaultGhcWay = if isDynamic comp then DynWay else StaticWay + + -- If there aren't modules, or if we're loading the modules in repl, don't build. + unless (forRepl || (null inputFiles && null inputModules)) $ liftIO $ do + -- See Note [Building Haskell Modules accounting for TH] + let + neededWays = + wantedWays + <> Set.fromList + -- TODO: You also don't need to build the GHC way when doing TH if + -- you are using an external interpreter!! + [defaultGhcWay | doingTH && defaultGhcWay `Set.notMember` wantedWays] + + -- If we need both static and dynamic, use dynamic-too instead of + -- compiling twice (if we support it) + useDynamicToo = + StaticWay `Set.member` neededWays + && DynWay `Set.member` neededWays + && supportsDynamicToo comp + && null (hcSharedOptions GHC bi) + + -- The ways we'll build, in order + orderedBuilds + -- If we can use dynamic-too, do it first. The default GHC way can only + -- be static or dynamic, so, if we build both right away, any modules + -- possibly needed by TH later (e.g. if building profiled) are already built. + | useDynamicToo = + [buildStaticAndDynamicToo] + ++ (runGhcProg . buildOpts <$> Set.toList neededWays \\ [StaticWay, DynWay]) + -- Otherwise, we need to ensure the defaultGhcWay is built first + | otherwise = + runGhcProg . buildOpts <$> sortOn (\w -> if w == defaultGhcWay then 0 else fromEnum w + 1) (Set.toList neededWays) + + buildStaticAndDynamicToo = do + runGhcProg dynTooOpts + case (hpcdir Hpc.Dyn, hpcdir Hpc.Vanilla) of + (Flag dynDir, Flag vanillaDir) -> + -- When the vanilla and shared library builds are done + -- in one pass, only one set of HPC module interfaces + -- are generated. This set should suffice for both + -- static and dynamically linked executables. We copy + -- the modules interfaces so they are available under + -- both ways. + copyDirectoryRecursive verbosity dynDir vanillaDir + _ -> return () + in + -- REVIEW:ADD? info verbosity "Building Haskell Sources..." + sequence_ orderedBuilds + return buildOpts + +data BuildWay = StaticWay | DynWay | ProfWay + deriving (Eq, Ord, Show, Enum) + +-- | Returns the object/interface extension prefix for the given build way (e.g. "dyn_" for 'DynWay') +buildWayPrefix :: BuildWay -> String +buildWayPrefix = \case + StaticWay -> "" + ProfWay -> "p_" + DynWay -> "dyn_" + +-- | Returns the corresponding 'Hpc.Way' for a 'BuildWay' +buildWayHpcWay :: BuildWay -> Hpc.Way +buildWayHpcWay = \case + StaticWay -> Hpc.Vanilla + ProfWay -> Hpc.Prof + DynWay -> Hpc.Dyn + +-- | Returns a function to extract the extra haskell compiler options from a +-- 'BuildInfo' and 'CompilerFlavor' +buildWayExtraHcOptions :: BuildWay -> CompilerFlavor -> BuildInfo -> [String] +buildWayExtraHcOptions = \case + StaticWay -> hcStaticOptions + ProfWay -> hcProfOptions + DynWay -> hcSharedOptions + +-- | Returns a pair of the Haskell input files and Haskell modules of the +-- component being built. +-- +-- The "input files" are either the path to the main Haskell module, or a repl +-- script (that does not necessarily have an extension). +componentInputs + :: FilePath + -- ^ Target build dir + -> PD.PackageDescription + -> PreBuildComponentInputs + -- ^ The context and component being built in it. + -> IO ([FilePath], [ModuleName]) + -- ^ The Haskell input files, and the Haskell modules +componentInputs buildTargetDir pkg_descr pbci = do + let + verbosity = buildVerbosity pbci + component = buildComponent pbci + clbi = buildCLBI pbci + + case component of + CLib lib -> + pure ([], allLibModules lib clbi) + CFLib flib -> + pure ([], foreignLibModules flib) + CExe Executable{buildInfo = bi', modulePath} -> + exeLikeInputs verbosity bi' modulePath + CTest TestSuite{testBuildInfo = bi', testInterface = TestSuiteExeV10 _ mainFile} -> + exeLikeInputs verbosity bi' mainFile + CBench Benchmark{benchmarkBuildInfo = bi', benchmarkInterface = BenchmarkExeV10 _ mainFile} -> + exeLikeInputs verbosity bi' mainFile + CTest TestSuite{} -> error "testSuiteExeV10AsExe: wrong kind" + CBench Benchmark{} -> error "benchmarkExeV10asExe: wrong kind" + where + exeLikeInputs verbosity bnfo modulePath = liftIO $ do + main <- findExecutableMain verbosity buildTargetDir (bnfo, modulePath) + let mainModName = exeMainModuleName bnfo + otherModNames = otherModules bnfo + + -- Scripts have fakePackageId and are always Haskell but can have any extension. + if isHaskell main || PD.package pkg_descr == fakePackageId + then + if PD.specVersion pkg_descr < CabalSpecV2_0 && (mainModName `elem` otherModNames) + then do + -- The cabal manual clearly states that `other-modules` is + -- intended for non-main modules. However, there's at least one + -- important package on Hackage (happy-1.19.5) which + -- violates this. We workaround this here so that we don't + -- invoke GHC with e.g. 'ghc --make Main src/Main.hs' which + -- would result in GHC complaining about duplicate Main + -- modules. + -- + -- Finally, we only enable this workaround for + -- specVersion < 2, as 'cabal-version:>=2.0' cabal files + -- have no excuse anymore to keep doing it wrong... ;-) + warn verbosity $ + "Enabling workaround for Main module '" + ++ prettyShow mainModName + ++ "' listed in 'other-modules' illegally!" + return ([main], filter (/= mainModName) otherModNames) + else return ([main], otherModNames) + else return ([], otherModNames) diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs b/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs new file mode 100644 index 00000000000..e5161e343da --- /dev/null +++ b/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs @@ -0,0 +1,217 @@ +module Distribution.Simple.GHC.Build.Utils where + +import Distribution.Compat.Prelude +import Prelude () + +import Control.Monad (msum) +import Data.Char (isLower) +import Distribution.ModuleName (ModuleName) +import qualified Distribution.ModuleName as ModuleName +import Distribution.PackageDescription as PD +import Distribution.PackageDescription.Utils (cabalBug) +import Distribution.Simple.BuildPaths +import Distribution.Simple.Compiler +import qualified Distribution.Simple.GHC.Internal as Internal +import Distribution.Simple.Program.GHC +import Distribution.Simple.Setup.Common +import Distribution.Simple.Utils +import Distribution.System +import Distribution.Types.LocalBuildInfo +import Distribution.Utils.Path (getSymbolicPath) +import Distribution.Verbosity +import System.FilePath + ( replaceExtension + , takeExtension + , (<.>) + , () + ) + +-- | Find the path to the entry point of an executable (typically specified in +-- @main-is@, and found in @hs-source-dirs@). +findExecutableMain + :: Verbosity + -> FilePath + -- ^ Build directory + -> (BuildInfo, FilePath) + -- ^ The build info and module path of an executable-like component (Exe, Test, Bench) + -> IO FilePath + -- ^ The path to the main source file. +findExecutableMain verbosity bdir (bnfo, modPath) = + findFileEx verbosity (bdir : map getSymbolicPath (hsSourceDirs bnfo)) modPath + +-- | Does this compiler support the @-dynamic-too@ option +supportsDynamicToo :: Compiler -> Bool +supportsDynamicToo = Internal.ghcLookupProperty "Support dynamic-too" + +-- | Is this compiler's RTS dynamically linked? +isDynamic :: Compiler -> Bool +isDynamic = Internal.ghcLookupProperty "GHC Dynamic" + +-- | Should we dynamically link the foreign library, based on its 'foreignLibType'? +withDynFLib :: ForeignLib -> Bool +withDynFLib flib = + case foreignLibType flib of + ForeignLibNativeShared -> + ForeignLibStandalone `notElem` foreignLibOptions flib + ForeignLibNativeStatic -> + False + ForeignLibTypeUnknown -> + cabalBug "unknown foreign lib type" + +-- | Is this file a C++ source file, i.e. ends with .cpp, .cxx, or .c++? +isCxx :: FilePath -> Bool +isCxx fp = elem (takeExtension fp) [".cpp", ".cxx", ".c++"] + +-- | Is this a C source file, i.e. ends with .c? +isC :: FilePath -> Bool +isC fp = elem (takeExtension fp) [".c"] + +-- | FilePath has a Haskell extension: .hs or .lhs +isHaskell :: FilePath -> Bool +isHaskell fp = elem (takeExtension fp) [".hs", ".lhs"] + +-- | Returns True if the modification date of the given source file is newer than +-- the object file we last compiled for it, or if no object file exists yet. +checkNeedsRecompilation :: FilePath -> GhcOptions -> IO Bool +checkNeedsRecompilation filename opts = filename `moreRecentFile` oname + where + oname = getObjectFileName filename opts + +-- | Finds the object file name of the given source file +getObjectFileName :: FilePath -> GhcOptions -> FilePath +getObjectFileName filename opts = oname + where + odir = fromFlag (ghcOptObjDir opts) + oext = fromFlagOrDefault "o" (ghcOptObjSuffix opts) + oname = odir replaceExtension filename oext + +-- | Target name for a foreign library (the actual file name) +-- +-- We do not use mkLibName and co here because the naming for foreign libraries +-- is slightly different (we don't use "_p" or compiler version suffices, and we +-- don't want the "lib" prefix on Windows). +-- +-- TODO: We do use `dllExtension` and co here, but really that's wrong: they +-- use the OS used to build cabal to determine which extension to use, rather +-- than the target OS (but this is wrong elsewhere in Cabal as well). +flibTargetName :: LocalBuildInfo -> ForeignLib -> String +flibTargetName lbi flib = + case (os, foreignLibType flib) of + (Windows, ForeignLibNativeShared) -> nm <.> "dll" + (Windows, ForeignLibNativeStatic) -> nm <.> "lib" + (Linux, ForeignLibNativeShared) -> "lib" ++ nm <.> versionedExt + (_other, ForeignLibNativeShared) -> + "lib" ++ nm <.> dllExtension (hostPlatform lbi) + (_other, ForeignLibNativeStatic) -> + "lib" ++ nm <.> staticLibExtension (hostPlatform lbi) + (_any, ForeignLibTypeUnknown) -> cabalBug "unknown foreign lib type" + where + nm :: String + nm = unUnqualComponentName $ foreignLibName flib + + os :: OS + Platform _ os = hostPlatform lbi + + -- If a foreign lib foo has lib-version-info 5:1:2 or + -- lib-version-linux 3.2.1, it should be built as libfoo.so.3.2.1 + -- Libtool's version-info data is translated into library versions in a + -- nontrivial way: so refer to libtool documentation. + versionedExt :: String + versionedExt = + let nums = foreignLibVersion flib os + in foldl (<.>) "so" (map show nums) + +-- | Name for the library when building. +-- +-- If the `lib-version-info` field or the `lib-version-linux` field of +-- a foreign library target is set, we need to incorporate that +-- version into the SONAME field. +-- +-- If a foreign library foo has lib-version-info 5:1:2, it should be +-- built as libfoo.so.3.2.1. We want it to get soname libfoo.so.3. +-- However, GHC does not allow overriding soname by setting linker +-- options, as it sets a soname of its own (namely the output +-- filename), after the user-supplied linker options. Hence, we have +-- to compile the library with the soname as its filename. We rename +-- the compiled binary afterwards. +-- +-- This method allows to adjust the name of the library at build time +-- such that the correct soname can be set. +flibBuildName :: LocalBuildInfo -> ForeignLib -> String +flibBuildName lbi flib + -- On linux, if a foreign-library has version data, the first digit is used + -- to produce the SONAME. + | (os, foreignLibType flib) + == (Linux, ForeignLibNativeShared) = + let nums = foreignLibVersion flib os + in "lib" ++ nm <.> foldl (<.>) "so" (map show (take 1 nums)) + | otherwise = flibTargetName lbi flib + where + os :: OS + Platform _ os = hostPlatform lbi + + nm :: String + nm = unUnqualComponentName $ foreignLibName flib + +-- | Gets the target name (name of actual executable file) from the name of an +-- executable-like component ('Executable', 'TestSuite', 'Benchmark'). +exeTargetName :: Platform -> UnqualComponentName -> String +exeTargetName platform name = unUnqualComponentName name `withExt` exeExtension platform + where + withExt :: FilePath -> String -> FilePath + withExt fp ext = fp <.> if takeExtension fp /= ('.' : ext) then ext else "" + +-- | "Main" module name when overridden by @ghc-options: -main-is ...@ +-- or 'Nothing' if no @-main-is@ flag could be found. +-- +-- In case of 'Nothing', 'Distribution.ModuleName.main' can be assumed. +exeMainModuleName + :: BuildInfo + -- ^ The build info of the executable-like component (Exe, Test, Bench) + -> ModuleName +exeMainModuleName bnfo = + -- GHC honors the last occurrence of a module name updated via -main-is + -- + -- Moreover, -main-is when parsed left-to-right can update either + -- the "Main" module name, or the "main" function name, or both, + -- see also 'decodeMainIsArg'. + fromMaybe ModuleName.main $ msum $ reverse $ map decodeMainIsArg $ findIsMainArgs ghcopts + where + ghcopts = hcOptions GHC bnfo + + findIsMainArgs [] = [] + findIsMainArgs ("-main-is" : arg : rest) = arg : findIsMainArgs rest + findIsMainArgs (_ : rest) = findIsMainArgs rest + +-- | Decode argument to '-main-is' +-- +-- Returns 'Nothing' if argument set only the function name. +-- +-- This code has been stolen/refactored from GHC's DynFlags.setMainIs +-- function. The logic here is deliberately imperfect as it is +-- intended to be bug-compatible with GHC's parser. See discussion in +-- https://github.com/haskell/cabal/pull/4539#discussion_r118981753. +decodeMainIsArg :: String -> Maybe ModuleName +decodeMainIsArg arg + | headOf main_fn isLower = + -- The arg looked like "Foo.Bar.baz" + Just (ModuleName.fromString main_mod) + | headOf arg isUpper -- The arg looked like "Foo" or "Foo.Bar" + = + Just (ModuleName.fromString arg) + | otherwise -- The arg looked like "baz" + = + Nothing + where + headOf :: String -> (Char -> Bool) -> Bool + headOf str pred' = any pred' (safeHead str) + + (main_mod, main_fn) = splitLongestPrefix arg (== '.') + + splitLongestPrefix :: String -> (Char -> Bool) -> (String, String) + splitLongestPrefix str pred' + | null r_pre = (str, []) + | otherwise = (reverse (safeTail r_pre), reverse r_suf) + where + -- 'safeTail' drops the char satisfying 'pred' + (r_suf, r_pre) = break pred' (reverse str) diff --git a/Cabal/src/Distribution/Simple/GHC/ImplInfo.hs b/Cabal/src/Distribution/Simple/GHC/ImplInfo.hs index df1a811bfb6..f575697819b 100644 --- a/Cabal/src/Distribution/Simple/GHC/ImplInfo.hs +++ b/Cabal/src/Distribution/Simple/GHC/ImplInfo.hs @@ -38,6 +38,8 @@ data GhcImplInfo = GhcImplInfo -- ^ -XHaskell2010 and -XHaskell98 flags , supportsGHC2021 :: Bool -- ^ -XGHC2021 flag + , supportsGHC2024 :: Bool + -- ^ -XGHC2024 flag , reportsNoExt :: Bool -- ^ --supported-languages gives Ext and NoExt , alwaysNondecIndent :: Bool @@ -88,6 +90,7 @@ ghcVersionImplInfo ver = GhcImplInfo { supportsHaskell2010 = v >= [7] , supportsGHC2021 = v >= [9, 1] + , supportsGHC2024 = v >= [9, 9] , reportsNoExt = v >= [7] , alwaysNondecIndent = v < [7, 1] , flagGhciScript = v >= [7, 2] @@ -114,6 +117,7 @@ ghcjsVersionImplInfo _ghcjsver ghcver = GhcImplInfo { supportsHaskell2010 = True , supportsGHC2021 = True + , supportsGHC2024 = ghcv >= [9, 9] , reportsNoExt = True , alwaysNondecIndent = False , flagGhciScript = True diff --git a/Cabal/src/Distribution/Simple/GHC/Internal.hs b/Cabal/src/Distribution/Simple/GHC/Internal.hs index 4c9bce31f8e..43e329fa66b 100644 --- a/Cabal/src/Distribution/Simple/GHC/Internal.hs +++ b/Cabal/src/Distribution/Simple/GHC/Internal.hs @@ -114,7 +114,9 @@ configureToolchain _implInfo ghcProg ghcInfo = . addKnownProgram ldProgram { programFindLocation = findProg ldProgramName extraLdPath - , programPostConf = configureLd + , programPostConf = \v cp -> + -- Call any existing configuration first and then add any new configuration + configureLd v =<< programPostConf ldProgram v cp } . addKnownProgram arProgram @@ -256,6 +258,13 @@ getLanguages -> IO [(Language, String)] getLanguages _ implInfo _ -- TODO: should be using --supported-languages rather than hard coding + | supportsGHC2024 implInfo = + return + [ (GHC2024, "-XGHC2024") + , (GHC2021, "-XGHC2021") + , (Haskell2010, "-XHaskell2010") + , (Haskell98, "-XHaskell98") + ] | supportsGHC2021 implInfo = return [ (GHC2021, "-XGHC2021") @@ -331,14 +340,13 @@ getExtensions verbosity implInfo ghcProg = do componentCcGhcOptions :: Verbosity - -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions -componentCcGhcOptions verbosity _implInfo lbi bi clbi odir filename = +componentCcGhcOptions verbosity lbi bi clbi odir filename = mempty { -- Respect -v0, but don't crank up verbosity on GHC if -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! @@ -381,14 +389,13 @@ componentCcGhcOptions verbosity _implInfo lbi bi clbi odir filename = componentCxxGhcOptions :: Verbosity - -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions -componentCxxGhcOptions verbosity _implInfo lbi bi clbi odir filename = +componentCxxGhcOptions verbosity lbi bi clbi odir filename = mempty { -- Respect -v0, but don't crank up verbosity on GHC if -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! @@ -431,14 +438,13 @@ componentCxxGhcOptions verbosity _implInfo lbi bi clbi odir filename = componentAsmGhcOptions :: Verbosity - -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions -componentAsmGhcOptions verbosity _implInfo lbi bi clbi odir filename = +componentAsmGhcOptions verbosity lbi bi clbi odir filename = mempty { -- Respect -v0, but don't crank up verbosity on GHC if -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! @@ -476,14 +482,13 @@ componentAsmGhcOptions verbosity _implInfo lbi bi clbi odir filename = componentJsGhcOptions :: Verbosity - -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions -componentJsGhcOptions verbosity _implInfo lbi bi clbi odir filename = +componentJsGhcOptions verbosity lbi bi clbi odir filename = mempty { -- Respect -v0, but don't crank up verbosity on GHC if -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! @@ -509,87 +514,87 @@ componentJsGhcOptions verbosity _implInfo lbi bi clbi odir filename = componentGhcOptions :: Verbosity - -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> GhcOptions -componentGhcOptions verbosity implInfo lbi bi clbi odir = - mempty - { -- Respect -v0, but don't crank up verbosity on GHC if - -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! - ghcOptVerbosity = toFlag (min verbosity normal) - , ghcOptCabal = toFlag True - , ghcOptThisUnitId = case clbi of - LibComponentLocalBuildInfo{componentCompatPackageKey = pk} -> - toFlag pk - _ | not (unitIdForExes implInfo) -> mempty - ExeComponentLocalBuildInfo{componentUnitId = uid} -> - toFlag (unUnitId uid) - TestComponentLocalBuildInfo{componentUnitId = uid} -> - toFlag (unUnitId uid) - BenchComponentLocalBuildInfo{componentUnitId = uid} -> - toFlag (unUnitId uid) - FLibComponentLocalBuildInfo{componentUnitId = uid} -> - toFlag (unUnitId uid) - , ghcOptThisComponentId = case clbi of - LibComponentLocalBuildInfo - { componentComponentId = cid - , componentInstantiatedWith = insts - } -> - if null insts - then mempty - else toFlag cid - _ -> mempty - , ghcOptInstantiatedWith = case clbi of - LibComponentLocalBuildInfo{componentInstantiatedWith = insts} -> - insts - _ -> [] - , ghcOptNoCode = toFlag $ componentIsIndefinite clbi - , ghcOptHideAllPackages = toFlag True - , ghcOptWarnMissingHomeModules = toFlag $ flagWarnMissingHomeModules implInfo - , ghcOptPackageDBs = withPackageDB lbi - , ghcOptPackages = toNubListR $ mkGhcOptPackages mempty clbi - , ghcOptSplitSections = toFlag (splitSections lbi) - , ghcOptSplitObjs = toFlag (splitObjs lbi) - , ghcOptSourcePathClear = toFlag True - , ghcOptSourcePath = - toNubListR $ - map getSymbolicPath (hsSourceDirs bi) - ++ [odir] - ++ [autogenComponentModulesDir lbi clbi] - ++ [autogenPackageModulesDir lbi] - , ghcOptCppIncludePath = - toNubListR $ - [ autogenComponentModulesDir lbi clbi - , autogenPackageModulesDir lbi - , odir - ] - -- includes relative to the package - ++ includeDirs bi - -- potential includes generated by `configure' - -- in the build directory - ++ [buildDir lbi dir | dir <- includeDirs bi] - , ghcOptCppOptions = cppOptions bi - , ghcOptCppIncludes = - toNubListR $ - [autogenComponentModulesDir lbi clbi cppHeaderName] - , ghcOptFfiIncludes = toNubListR $ includes bi - , ghcOptObjDir = toFlag odir - , ghcOptHiDir = toFlag odir - , ghcOptHieDir = bool NoFlag (toFlag $ odir extraCompilationArtifacts "hie") $ flagHie implInfo - , ghcOptStubDir = toFlag odir - , ghcOptOutputDir = toFlag odir - , ghcOptOptimisation = toGhcOptimisation (withOptimization lbi) - , ghcOptDebugInfo = toFlag (withDebugInfo lbi) - , ghcOptExtra = hcOptions GHC bi - , ghcOptExtraPath = toNubListR $ exe_paths - , ghcOptLanguage = toFlag (fromMaybe Haskell98 (defaultLanguage bi)) - , -- Unsupported extensions have already been checked by configure - ghcOptExtensions = toNubListR $ usedExtensions bi - , ghcOptExtensionMap = Map.fromList . compilerExtensions $ (compiler lbi) - } +componentGhcOptions verbosity lbi bi clbi odir = + let implInfo = getImplInfo $ compiler lbi + in mempty + { -- Respect -v0, but don't crank up verbosity on GHC if + -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! + ghcOptVerbosity = toFlag (min verbosity normal) + , ghcOptCabal = toFlag True + , ghcOptThisUnitId = case clbi of + LibComponentLocalBuildInfo{componentCompatPackageKey = pk} -> + toFlag pk + _ | not (unitIdForExes implInfo) -> mempty + ExeComponentLocalBuildInfo{componentUnitId = uid} -> + toFlag (unUnitId uid) + TestComponentLocalBuildInfo{componentUnitId = uid} -> + toFlag (unUnitId uid) + BenchComponentLocalBuildInfo{componentUnitId = uid} -> + toFlag (unUnitId uid) + FLibComponentLocalBuildInfo{componentUnitId = uid} -> + toFlag (unUnitId uid) + , ghcOptThisComponentId = case clbi of + LibComponentLocalBuildInfo + { componentComponentId = cid + , componentInstantiatedWith = insts + } -> + if null insts + then mempty + else toFlag cid + _ -> mempty + , ghcOptInstantiatedWith = case clbi of + LibComponentLocalBuildInfo{componentInstantiatedWith = insts} -> + insts + _ -> [] + , ghcOptNoCode = toFlag $ componentIsIndefinite clbi + , ghcOptHideAllPackages = toFlag True + , ghcOptWarnMissingHomeModules = toFlag $ flagWarnMissingHomeModules implInfo + , ghcOptPackageDBs = withPackageDB lbi + , ghcOptPackages = toNubListR $ mkGhcOptPackages mempty clbi + , ghcOptSplitSections = toFlag (splitSections lbi) + , ghcOptSplitObjs = toFlag (splitObjs lbi) + , ghcOptSourcePathClear = toFlag True + , ghcOptSourcePath = + toNubListR $ + map getSymbolicPath (hsSourceDirs bi) + ++ [odir] + ++ [autogenComponentModulesDir lbi clbi] + ++ [autogenPackageModulesDir lbi] + , ghcOptCppIncludePath = + toNubListR $ + [ autogenComponentModulesDir lbi clbi + , autogenPackageModulesDir lbi + , odir + ] + -- includes relative to the package + ++ includeDirs bi + -- potential includes generated by `configure' + -- in the build directory + ++ [buildDir lbi dir | dir <- includeDirs bi] + , ghcOptCppOptions = cppOptions bi + , ghcOptCppIncludes = + toNubListR $ + [autogenComponentModulesDir lbi clbi cppHeaderName] + , ghcOptFfiIncludes = toNubListR $ includes bi + , ghcOptObjDir = toFlag odir + , ghcOptHiDir = toFlag odir + , ghcOptHieDir = bool NoFlag (toFlag $ odir extraCompilationArtifacts "hie") $ flagHie implInfo + , ghcOptStubDir = toFlag odir + , ghcOptOutputDir = toFlag odir + , ghcOptOptimisation = toGhcOptimisation (withOptimization lbi) + , ghcOptDebugInfo = toFlag (withDebugInfo lbi) + , ghcOptExtra = hcOptions GHC bi + , ghcOptExtraPath = toNubListR $ exe_paths + , ghcOptLanguage = toFlag (fromMaybe Haskell98 (defaultLanguage bi)) + , -- Unsupported extensions have already been checked by configure + ghcOptExtensions = toNubListR $ usedExtensions bi + , ghcOptExtensionMap = Map.fromList . compilerExtensions $ (compiler lbi) + } where exe_paths = [ componentBuildDir lbi (targetCLBI exe_tgt) @@ -605,14 +610,13 @@ toGhcOptimisation MaximumOptimisation = toFlag GhcMaximumOptimisation componentCmmGhcOptions :: Verbosity - -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions -componentCmmGhcOptions verbosity _implInfo lbi bi clbi odir filename = +componentCmmGhcOptions verbosity lbi bi clbi odir filename = mempty { -- Respect -v0, but don't crank up verbosity on GHC if -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! @@ -777,6 +781,7 @@ profDetailLevelFlag forLib mpl = ghcArchString :: Arch -> String ghcArchString PPC = "powerpc" ghcArchString PPC64 = "powerpc64" +ghcArchString PPC64LE = "powerpc64le" ghcArchString other = prettyShow other -- | GHC's rendering of its host or target 'OS' as used in its platform @@ -785,6 +790,7 @@ ghcOsString :: OS -> String ghcOsString Windows = "mingw32" ghcOsString OSX = "darwin" ghcOsString Solaris = "solaris2" +ghcOsString Hurd = "gnu" ghcOsString other = prettyShow other -- | GHC's rendering of its platform and compiler version string as used in diff --git a/Cabal/src/Distribution/Simple/GHCJS.hs b/Cabal/src/Distribution/Simple/GHCJS.hs index 58194f5ffa3..4e14bc04d5d 100644 --- a/Cabal/src/Distribution/Simple/GHCJS.hs +++ b/Cabal/src/Distribution/Simple/GHCJS.hs @@ -23,7 +23,7 @@ module Distribution.Simple.GHCJS , hcPkgInfo , registerPackage , componentGhcOptions - , componentCcGhcOptions + , Internal.componentCcGhcOptions , getLibDir , isDynamic , getGlobalPackageDB @@ -68,11 +68,12 @@ import qualified Distribution.Simple.Hpc as Hpc import Distribution.Simple.LocalBuildInfo import Distribution.Simple.PackageIndex (InstalledPackageIndex) import qualified Distribution.Simple.PackageIndex as PackageIndex +import Distribution.Simple.PreProcess.Types import Distribution.Simple.Program import Distribution.Simple.Program.GHC import qualified Distribution.Simple.Program.HcPkg as HcPkg import qualified Distribution.Simple.Program.Strip as Strip -import Distribution.Simple.Setup.Config +import Distribution.Simple.Setup.Common import Distribution.Simple.Utils import Distribution.System import Distribution.Types.ComponentLocalBuildInfo @@ -481,7 +482,7 @@ buildOrReplLib -> Library -> ComponentLocalBuildInfo -> IO () -buildOrReplLib mReplFlags verbosity numJobs pkg_descr lbi lib clbi = do +buildOrReplLib mReplFlags verbosity numJobs _pkg_descr lbi lib clbi = do let uid = componentUnitId clbi libTargetDir = componentBuildDir lbi clbi whenVanillaLib forceVanilla = @@ -515,15 +516,9 @@ buildOrReplLib mReplFlags verbosity numJobs pkg_descr lbi lib clbi = do -- Determine if program coverage should be enabled and if so, what -- '-hpcdir' should be. let isCoverageEnabled = libCoverage lbi - -- TODO: Historically HPC files have been put into a directory which - -- has the package name. I'm going to avoid changing this for - -- now, but it would probably be better for this to be the - -- component ID instead... - pkg_name = prettyShow (PD.package pkg_descr) - distPref = fromFlag $ configDistPref $ configFlags lbi hpcdir way | forRepl = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way pkg_name + | isCoverageEnabled = toFlag $ Hpc.mixDir (libTargetDir extraCompilationArtifacts) way | otherwise = mempty createDirectoryIfMissingVerbose verbosity True libTargetDir @@ -1220,7 +1215,6 @@ gbuild verbosity numJobs pkg_descr lbi bm clbi = do GBuildFLib{} -> mempty comp = compiler lbi platform = hostPlatform lbi - implInfo = getImplInfo comp runGhcProg = runGHC verbosity ghcjsProg comp platform let (bnfo, threaded) = case bm of @@ -1240,10 +1234,9 @@ gbuild verbosity numJobs pkg_descr lbi bm clbi = do -- Determine if program coverage should be enabled and if so, what -- '-hpcdir' should be. let isCoverageEnabled = exeCoverage lbi - distPref = fromFlag $ configDistPref $ configFlags lbi hpcdir way | gbuildIsRepl bm = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way (gbuildName bm) + | isCoverageEnabled = toFlag $ Hpc.mixDir (tmpDir extraCompilationArtifacts) way | otherwise = mempty rpaths <- getRPaths lbi clbi @@ -1425,7 +1418,6 @@ gbuild verbosity numJobs pkg_descr lbi bm clbi = do let baseCxxOpts = Internal.componentCxxGhcOptions verbosity - implInfo lbi bnfo clbi @@ -1472,7 +1464,6 @@ gbuild verbosity numJobs pkg_descr lbi bm clbi = do let baseCcOpts = Internal.componentCcGhcOptions verbosity - implInfo lbi bnfo clbi @@ -1697,7 +1688,7 @@ getRPaths lbi clbi | supportRPaths hostOS = do supportRPaths Android = False supportRPaths Ghcjs = False supportRPaths Wasi = False - supportRPaths Hurd = False + supportRPaths Hurd = True supportRPaths Haiku = False supportRPaths (OtherOS _) = False -- Do _not_ add a default case so that we get a warning here when a new OS @@ -1739,20 +1730,12 @@ libAbiHash verbosity _pkg_descr lbi lib clbi = do libBi = libBuildInfo lib comp = compiler lbi platform = hostPlatform lbi - vanillaArgs0 = + vanillaArgs = (componentGhcOptions verbosity lbi libBi clbi (componentBuildDir lbi clbi)) `mappend` mempty { ghcOptMode = toFlag GhcModeAbiHash , ghcOptInputModules = toNubListR $ exposedModules lib } - vanillaArgs = - -- Package DBs unnecessary, and break ghc-cabal. See #3633 - -- BUT, put at least the global database so that 7.4 doesn't - -- break. - vanillaArgs0 - { ghcOptPackageDBs = [GlobalPackageDB] - , ghcOptPackages = mempty - } sharedArgs = vanillaArgs `mappend` mempty @@ -1784,7 +1767,7 @@ libAbiHash verbosity _pkg_descr lbi lib clbi = do hash <- getProgramInvocationOutput verbosity - (ghcInvocation ghcjsProg comp platform ghcArgs) + =<< ghcInvocation verbosity ghcjsProg comp platform ghcArgs return (takeWhile (not . isSpace) hash) componentGhcOptions @@ -1795,27 +1778,11 @@ componentGhcOptions -> FilePath -> GhcOptions componentGhcOptions verbosity lbi bi clbi odir = - let opts = Internal.componentGhcOptions verbosity implInfo lbi bi clbi odir - comp = compiler lbi - implInfo = getImplInfo comp + let opts = Internal.componentGhcOptions verbosity lbi bi clbi odir in opts { ghcOptExtra = ghcOptExtra opts `mappend` hcOptions GHCJS bi } -componentCcGhcOptions - :: Verbosity - -> LocalBuildInfo - -> BuildInfo - -> ComponentLocalBuildInfo - -> FilePath - -> FilePath - -> GhcOptions -componentCcGhcOptions verbosity lbi = - Internal.componentCcGhcOptions verbosity implInfo lbi - where - comp = compiler lbi - implInfo = getImplInfo comp - -- ----------------------------------------------------------------------------- -- Installing @@ -1895,9 +1862,9 @@ installLib -> ComponentLocalBuildInfo -> IO () installLib verbosity lbi targetDir dynlibTargetDir _builtDir _pkg lib clbi = do - whenVanilla $ copyModuleFiles "js_hi" - whenProf $ copyModuleFiles "js_p_hi" - whenShared $ copyModuleFiles "js_dyn_hi" + whenVanilla $ copyModuleFiles $ Suffix "js_hi" + whenProf $ copyModuleFiles $ Suffix "js_p_hi" + whenShared $ copyModuleFiles $ Suffix "js_dyn_hi" -- whenVanilla $ installOrdinary builtDir targetDir $ toJSLibName vanillaLibName -- whenProf $ installOrdinary builtDir targetDir $ toJSLibName profileLibName diff --git a/Cabal/src/Distribution/Simple/Glob.hs b/Cabal/src/Distribution/Simple/Glob.hs index 67abe7e2da4..9ce97d7555b 100644 --- a/Cabal/src/Distribution/Simple/Glob.hs +++ b/Cabal/src/Distribution/Simple/Glob.hs @@ -1,6 +1,6 @@ {-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE LambdaCase #-} ----------------------------------------------------------------------------- @@ -15,219 +15,53 @@ -- -- Simple file globbing. module Distribution.Simple.Glob - ( GlobSyntaxError (..) + ( -- * Globs + Glob + + -- * Matching on globs , GlobResult (..) + , globMatches + , fileGlobMatches , matchDirFileGlob , matchDirFileGlobWithDie , runDirFileGlob - , fileGlobMatches + + -- * Parsing globs , parseFileGlob + , GlobSyntaxError (..) , explainGlobSyntaxError + + -- * Utility , isRecursiveInRoot - , Glob - ) where + ) +where import Distribution.Compat.Prelude import Prelude () -import Distribution.CabalSpecVersion -import Distribution.Simple.Utils -import Distribution.Verbosity - -import System.Directory (doesDirectoryExist, doesFileExist, getDirectoryContents) -import System.FilePath (joinPath, splitDirectories, splitExtensions, takeFileName, (<.>), ()) - -import qualified Data.List.NonEmpty as NE +import Distribution.CabalSpecVersion (CabalSpecVersion) import Distribution.Simple.Errors + ( CabalException (MatchDirFileGlob, MatchDirFileGlobErrors) + ) +import Distribution.Simple.Glob.Internal +import Distribution.Simple.Utils (dieWithException, warn) +import Distribution.Verbosity (Verbosity) + +------------------------------------------------------------------------------- --- Note throughout that we use splitDirectories, not splitPath. On --- Posix, this makes no difference, but, because Windows accepts both --- slash and backslash as its path separators, if we left in the --- separators from the glob we might not end up properly normalised. +-- * Matching -data GlobResult a - = -- | The glob matched the value supplied. - GlobMatch a - | -- | The glob did not match the value supplied because the - -- cabal-version is too low and the extensions on the file did - -- not precisely match the glob's extensions, but rather the - -- glob was a proper suffix of the file's extensions; i.e., if - -- not for the low cabal-version, it would have matched. - GlobWarnMultiDot a - | -- | The glob couldn't match because the directory named doesn't - -- exist. The directory will be as it appears in the glob (i.e., - -- relative to the directory passed to 'matchDirFileGlob', and, - -- for 'data-files', relative to 'data-dir'). - GlobMissingDirectory FilePath - deriving (Show, Eq, Ord, Functor) +-------------------------------------------------------------------------------- -- | Extract the matches from a list of 'GlobResult's. -- -- Note: throws away the 'GlobMissingDirectory' results; chances are -- that you want to check for these and error out if any are present. +-- +-- @since 3.12.0.0 globMatches :: [GlobResult a] -> [a] globMatches input = [a | GlobMatch a <- input] -data GlobSyntaxError - = StarInDirectory - | StarInFileName - | StarInExtension - | NoExtensionOnStar - | EmptyGlob - | LiteralFileNameGlobStar - | VersionDoesNotSupportGlobStar - | VersionDoesNotSupportGlob - deriving (Eq, Show) - -explainGlobSyntaxError :: FilePath -> GlobSyntaxError -> String -explainGlobSyntaxError filepath StarInDirectory = - "invalid file glob '" - ++ filepath - ++ "'. A wildcard '**' is only allowed as the final parent" - ++ " directory. Stars must not otherwise appear in the parent" - ++ " directories." -explainGlobSyntaxError filepath StarInExtension = - "invalid file glob '" - ++ filepath - ++ "'. Wildcards '*' are only allowed as the" - ++ " file's base name, not in the file extension." -explainGlobSyntaxError filepath StarInFileName = - "invalid file glob '" - ++ filepath - ++ "'. Wildcards '*' may only totally replace the" - ++ " file's base name, not only parts of it." -explainGlobSyntaxError filepath NoExtensionOnStar = - "invalid file glob '" - ++ filepath - ++ "'. If a wildcard '*' is used it must be with an file extension." -explainGlobSyntaxError filepath LiteralFileNameGlobStar = - "invalid file glob '" - ++ filepath - ++ "'. Prior to 'cabal-version: 3.8'" - ++ " if a wildcard '**' is used as a parent directory, the" - ++ " file's base name must be a wildcard '*'." -explainGlobSyntaxError _ EmptyGlob = - "invalid file glob. A glob cannot be the empty string." -explainGlobSyntaxError filepath VersionDoesNotSupportGlobStar = - "invalid file glob '" - ++ filepath - ++ "'. Using the double-star syntax requires 'cabal-version: 2.4'" - ++ " or greater. Alternatively, for compatibility with earlier Cabal" - ++ " versions, list the included directories explicitly." -explainGlobSyntaxError filepath VersionDoesNotSupportGlob = - "invalid file glob '" - ++ filepath - ++ "'. Using star wildcards requires 'cabal-version: >= 1.6'. " - ++ "Alternatively if you require compatibility with earlier Cabal " - ++ "versions then list all the files explicitly." - -data IsRecursive = Recursive | NonRecursive deriving (Eq) - -data MultiDot = MultiDotDisabled | MultiDotEnabled - -data Glob - = -- | A single subdirectory component + remainder. - GlobStem FilePath Glob - | GlobFinal GlobFinal - -data GlobFinal - = -- | First argument: Is this a @**/*.ext@ pattern? - -- Second argument: should we match against the exact extensions, or accept a suffix? - -- Third argument: the extensions to accept. - FinalMatch IsRecursive MultiDot String - | -- | Literal file name. - FinalLit IsRecursive FilePath - -reconstructGlob :: Glob -> FilePath -reconstructGlob (GlobStem dir glob) = - dir reconstructGlob glob -reconstructGlob (GlobFinal final) = case final of - FinalMatch Recursive _ exts -> "**" "*" <.> exts - FinalMatch NonRecursive _ exts -> "*" <.> exts - FinalLit Recursive path -> "**" path - FinalLit NonRecursive path -> path - --- | Returns 'Nothing' if the glob didn't match at all, or 'Just' the --- result if the glob matched (or would have matched with a higher --- cabal-version). -fileGlobMatches :: Glob -> FilePath -> Maybe (GlobResult FilePath) -fileGlobMatches pat candidate = do - match <- fileGlobMatchesSegments pat (splitDirectories candidate) - return (candidate <$ match) - -fileGlobMatchesSegments :: Glob -> [FilePath] -> Maybe (GlobResult ()) -fileGlobMatchesSegments _ [] = Nothing -fileGlobMatchesSegments pat (seg : segs) = case pat of - GlobStem dir pat' -> do - guard (dir == seg) - fileGlobMatchesSegments pat' segs - GlobFinal final -> case final of - FinalMatch Recursive multidot ext -> do - let (candidateBase, candidateExts) = splitExtensions (NE.last $ seg :| segs) - guard (not (null candidateBase)) - checkExt multidot ext candidateExts - FinalMatch NonRecursive multidot ext -> do - let (candidateBase, candidateExts) = splitExtensions seg - guard (null segs && not (null candidateBase)) - checkExt multidot ext candidateExts - FinalLit isRecursive filename -> do - guard ((isRecursive == Recursive || null segs) && filename == seg) - return (GlobMatch ()) - -checkExt - :: MultiDot - -> String - -- ^ The pattern's extension - -> String - -- ^ The candidate file's extension - -> Maybe (GlobResult ()) -checkExt multidot ext candidate - | ext == candidate = Just (GlobMatch ()) - | ext `isSuffixOf` candidate = case multidot of - MultiDotDisabled -> Just (GlobWarnMultiDot ()) - MultiDotEnabled -> Just (GlobMatch ()) - | otherwise = Nothing - -parseFileGlob :: CabalSpecVersion -> FilePath -> Either GlobSyntaxError Glob -parseFileGlob version filepath = case reverse (splitDirectories filepath) of - [] -> - Left EmptyGlob - (filename : "**" : segments) - | allowGlobStar -> do - finalSegment <- case splitExtensions filename of - ("*", ext) - | '*' `elem` ext -> Left StarInExtension - | null ext -> Left NoExtensionOnStar - | otherwise -> Right (FinalMatch Recursive multidot ext) - _ -> - if allowLiteralFilenameGlobStar - then Right (FinalLit Recursive filename) - else Left LiteralFileNameGlobStar - foldM addStem (GlobFinal finalSegment) segments - | otherwise -> Left VersionDoesNotSupportGlobStar - (filename : segments) -> do - pat <- case splitExtensions filename of - ("*", ext) - | not allowGlob -> Left VersionDoesNotSupportGlob - | '*' `elem` ext -> Left StarInExtension - | null ext -> Left NoExtensionOnStar - | otherwise -> Right (FinalMatch NonRecursive multidot ext) - (_, ext) - | '*' `elem` ext -> Left StarInExtension - | '*' `elem` filename -> Left StarInFileName - | otherwise -> Right (FinalLit NonRecursive filename) - foldM addStem (GlobFinal pat) segments - where - allowGlob = version >= CabalSpecV1_6 - allowGlobStar = version >= CabalSpecV2_4 - addStem pat seg - | '*' `elem` seg = Left StarInDirectory - | otherwise = Right (GlobStem seg pat) - multidot - | version >= CabalSpecV2_4 = MultiDotEnabled - | otherwise = MultiDotDisabled - allowLiteralFilenameGlobStar = version >= CabalSpecV3_8 - -- | This will 'die'' when the glob matches no files, or if the glob -- refers to a missing directory, or if the glob fails to parse. -- @@ -247,14 +81,21 @@ matchDirFileGlob v = matchDirFileGlobWithDie v dieWithException -- | Like 'matchDirFileGlob' but with customizable 'die' -- -- @since 3.6.0.0 -matchDirFileGlobWithDie :: Verbosity -> (Verbosity -> CabalException -> IO [FilePath]) -> CabalSpecVersion -> FilePath -> FilePath -> IO [FilePath] +matchDirFileGlobWithDie + :: Verbosity + -> (Verbosity -> CabalException -> IO [FilePath]) + -> CabalSpecVersion + -> FilePath + -> FilePath + -> IO [FilePath] matchDirFileGlobWithDie verbosity rip version dir filepath = case parseFileGlob version filepath of Left err -> rip verbosity $ MatchDirFileGlob (explainGlobSyntaxError filepath err) Right glob -> do - results <- runDirFileGlob verbosity dir glob + results <- runDirFileGlob verbosity (Just version) dir glob let missingDirectories = [missingDir | GlobMissingDirectory missingDir <- results] matches = globMatches results + directoryMatches = [a | GlobMatchesDirectory a <- results] let errors :: [String] errors = @@ -267,89 +108,20 @@ matchDirFileGlobWithDie verbosity rip version dir filepath = case parseFileGlob | missingDir <- missingDirectories ] ++ [ "filepath wildcard '" ++ filepath ++ "' does not match any files." - | null matches + | null matches && null directoryMatches + -- we don't error out on directory matches, simply warn about them and ignore. ] + warns :: [String] + warns = + [ "Ignoring directory '" ++ path ++ "'" ++ " listed in a Cabal package field which should only include files (not directories)." + | path <- directoryMatches + ] + if null errors - then return matches + then do + unless (null warns) $ + warn verbosity $ + unlines warns + return matches else rip verbosity $ MatchDirFileGlobErrors errors - --- | Match files against a pre-parsed glob, starting in a directory. --- --- The 'Version' argument must be the spec version of the package --- description being processed, as globs behave slightly differently --- in different spec versions. --- --- The 'FilePath' argument is the directory that the glob is relative --- to. It must be a valid directory (and hence it can't be the empty --- string). The returned values will not include this prefix. -runDirFileGlob :: Verbosity -> FilePath -> Glob -> IO [GlobResult FilePath] -runDirFileGlob verbosity rawDir pat = do - -- The default data-dir is null. Our callers -should- be - -- converting that to '.' themselves, but it's a certainty that - -- some future call-site will forget and trigger a really - -- hard-to-debug failure if we don't check for that here. - when (null rawDir) $ - warn verbosity $ - "Null dir passed to runDirFileGlob; interpreting it " - ++ "as '.'. This is probably an internal error." - let dir = if null rawDir then "." else rawDir - debug verbosity $ "Expanding glob '" ++ reconstructGlob pat ++ "' in directory '" ++ dir ++ "'." - -- This function might be called from the project root with dir as - -- ".". Walking the tree starting there involves going into .git/ - -- and dist-newstyle/, which is a lot of work for no reward, so - -- extract the constant prefix from the pattern and start walking - -- there, and only walk as much as we need to: recursively if **, - -- the whole directory if *, and just the specific file if it's a - -- literal. - let (prefixSegments, final) = splitConstantPrefix pat - joinedPrefix = joinPath prefixSegments - case final of - FinalMatch recursive multidot exts -> do - let prefix = dir joinedPrefix - directoryExists <- doesDirectoryExist prefix - if directoryExists - then do - candidates <- case recursive of - Recursive -> getDirectoryContentsRecursive prefix - NonRecursive -> filterM (doesFileExist . (prefix )) =<< getDirectoryContents prefix - let checkName candidate = do - let (candidateBase, candidateExts) = splitExtensions $ takeFileName candidate - guard (not (null candidateBase)) - match <- checkExt multidot exts candidateExts - return (joinedPrefix candidate <$ match) - return $ mapMaybe checkName candidates - else return [GlobMissingDirectory joinedPrefix] - FinalLit Recursive fn -> do - let prefix = dir joinedPrefix - directoryExists <- doesDirectoryExist prefix - if directoryExists - then do - candidates <- getDirectoryContentsRecursive prefix - let checkName candidate - | takeFileName candidate == fn = Just $ GlobMatch (joinedPrefix candidate) - | otherwise = Nothing - return $ mapMaybe checkName candidates - else return [GlobMissingDirectory joinedPrefix] - FinalLit NonRecursive fn -> do - exists <- doesFileExist (dir joinedPrefix fn) - return [GlobMatch (joinedPrefix fn) | exists] - -unfoldr' :: (a -> Either r (b, a)) -> a -> ([b], r) -unfoldr' f a = case f a of - Left r -> ([], r) - Right (b, a') -> case unfoldr' f a' of - (bs, r) -> (b : bs, r) - --- | Extract the (possibly null) constant prefix from the pattern. --- This has the property that, if @(pref, final) = splitConstantPrefix pat@, --- then @pat === foldr GlobStem (GlobFinal final) pref@. -splitConstantPrefix :: Glob -> ([FilePath], GlobFinal) -splitConstantPrefix = unfoldr' step - where - step (GlobStem seg pat) = Right (seg, pat) - step (GlobFinal pat) = Left pat - -isRecursiveInRoot :: Glob -> Bool -isRecursiveInRoot (GlobFinal (FinalMatch Recursive _ _)) = True -isRecursiveInRoot _ = False diff --git a/Cabal/src/Distribution/Simple/Glob/Internal.hs b/Cabal/src/Distribution/Simple/Glob/Internal.hs new file mode 100644 index 00000000000..4f0b91eca39 --- /dev/null +++ b/Cabal/src/Distribution/Simple/Glob/Internal.hs @@ -0,0 +1,497 @@ +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE LambdaCase #-} + +----------------------------------------------------------------------------- + +-- | +-- Module : Distribution.Simple.Glob.Internal +-- Copyright : Isaac Jones, Simon Marlow 2003-2004 +-- License : BSD3 +-- portions Copyright (c) 2007, Galois Inc. +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- Internal module for simple file globbing. +-- Please import "Distribution.Simple.Glob" instead. +module Distribution.Simple.Glob.Internal where + +import Distribution.Compat.Prelude +import Prelude () + +import Control.Monad (mapM) + +import Distribution.Parsec +import Distribution.Pretty + +import Distribution.CabalSpecVersion +import Distribution.Simple.Utils +import Distribution.Verbosity hiding (normal) + +import Data.List (stripPrefix) +import System.Directory +import System.FilePath + +import qualified Distribution.Compat.CharParsing as P +import qualified Text.PrettyPrint as Disp + +-------------------------------------------------------------------------------- + +-- | A filepath specified by globbing. +data Glob + = -- | @/@ + GlobDir !GlobPieces !Glob + | -- | @**/@, where @**@ denotes recursively traversing + -- all directories and matching filenames on . + GlobDirRecursive !GlobPieces + | -- | A file glob. + GlobFile !GlobPieces + | -- | Trailing dir; a glob ending in @/@. + GlobDirTrailing + deriving (Eq, Show, Generic) + +instance Binary Glob +instance Structured Glob + +-- | A single directory or file component of a globbed path +type GlobPieces = [GlobPiece] + +-- | A piece of a globbing pattern +data GlobPiece + = -- | A wildcard @*@ + WildCard + | -- | A literal string @dirABC@ + Literal String + | -- | A union of patterns, e.g. @dir/{a,*.txt,c}/...@ + Union [GlobPieces] + deriving (Eq, Show, Generic) + +instance Binary GlobPiece +instance Structured GlobPiece + +------------------------------------------------------------------------------- + +-- * Matching + +-------------------------------------------------------------------------------- + +-- | Match a 'Glob' against the file system, starting from a +-- given root directory. The results are all relative to the given root. +-- +-- @since 3.12.0.0 +matchGlob :: FilePath -> Glob -> IO [FilePath] +matchGlob root glob = + -- For this function, which is the general globbing one (doesn't care about + -- cabal spec, used e.g. for monitoring), we consider all matches. + mapMaybe + ( \case + GlobMatch a -> Just a + GlobWarnMultiDot a -> Just a + GlobMatchesDirectory a -> Just a + GlobMissingDirectory{} -> Nothing + ) + <$> runDirFileGlob silent Nothing root glob + +-- | Match a globbing pattern against a file path component +matchGlobPieces :: GlobPieces -> String -> Bool +matchGlobPieces = goStart + where + -- From the man page, glob(7): + -- "If a filename starts with a '.', this character must be + -- matched explicitly." + + go, goStart :: [GlobPiece] -> String -> Bool + + goStart (WildCard : _) ('.' : _) = False + goStart (Union globs : rest) cs = + any + (\glob -> goStart (glob ++ rest) cs) + globs + goStart rest cs = go rest cs + + go [] "" = True + go (Literal lit : rest) cs + | Just cs' <- stripPrefix lit cs = + go rest cs' + | otherwise = False + go [WildCard] "" = True + go (WildCard : rest) (c : cs) = go rest (c : cs) || go (WildCard : rest) cs + go (Union globs : rest) cs = any (\glob -> go (glob ++ rest) cs) globs + go [] (_ : _) = False + go (_ : _) "" = False + +------------------------------------------------------------------------------- + +-- * Parsing & printing + +-------------------------------------------------------------------------------- +-- Filepaths with globs may be parsed in the special context is globbing in +-- cabal package fields, such as `data-files`. In that case, we restrict the +-- globbing syntax to that supported by the cabal spec version in use. +-- Otherwise, we parse the globs to the extent of our globbing features +-- (wildcards `*`, unions `{a,b,c}`, and directory-recursive wildcards `**`). + +-- ** Parsing globs in a cabal package + +parseFileGlob :: CabalSpecVersion -> FilePath -> Either GlobSyntaxError Glob +parseFileGlob version filepath = case reverse (splitDirectories filepath) of + [] -> + Left EmptyGlob + (filename : "**" : segments) + | allowGlobStar -> do + finalSegment <- case splitExtensions filename of + ("*", ext) + | '*' `elem` ext -> Left StarInExtension + | null ext -> Left NoExtensionOnStar + | otherwise -> Right (GlobDirRecursive [WildCard, Literal ext]) + _ + | allowLiteralFilenameGlobStar -> + Right (GlobDirRecursive [Literal filename]) + | otherwise -> + Left LiteralFileNameGlobStar + + foldM addStem finalSegment segments + | otherwise -> Left VersionDoesNotSupportGlobStar + (filename : segments) -> do + pat <- case splitExtensions filename of + ("*", ext) + | not allowGlob -> Left VersionDoesNotSupportGlob + | '*' `elem` ext -> Left StarInExtension + | null ext -> Left NoExtensionOnStar + | otherwise -> Right (GlobFile [WildCard, Literal ext]) + (_, ext) + | '*' `elem` ext -> Left StarInExtension + | '*' `elem` filename -> Left StarInFileName + | otherwise -> Right (GlobFile [Literal filename]) + + foldM addStem pat segments + where + addStem pat seg + | '*' `elem` seg = Left StarInDirectory + | otherwise = Right (GlobDir [Literal seg] pat) + allowGlob = version >= CabalSpecV1_6 + allowGlobStar = version >= CabalSpecV2_4 + allowLiteralFilenameGlobStar = version >= CabalSpecV3_8 + +enableMultidot :: CabalSpecVersion -> Bool +enableMultidot version + | version >= CabalSpecV2_4 = True + | otherwise = False + +-- ** Parsing globs otherwise + +instance Pretty Glob where + pretty (GlobDir glob pathglob) = + dispGlobPieces glob + Disp.<> Disp.char '/' + Disp.<> pretty pathglob + pretty (GlobDirRecursive glob) = + Disp.text "**/" + Disp.<> dispGlobPieces glob + pretty (GlobFile glob) = dispGlobPieces glob + pretty GlobDirTrailing = Disp.empty + +instance Parsec Glob where + parsec = parsecPath + where + parsecPath :: CabalParsing m => m Glob + parsecPath = do + glob <- parsecGlob + dirSep *> (GlobDir glob <$> parsecPath <|> pure (GlobDir glob GlobDirTrailing)) <|> pure (GlobFile glob) + -- We could support parsing recursive directory search syntax + -- @**@ here too, rather than just in 'parseFileGlob' + + dirSep :: CabalParsing m => m () + dirSep = + () <$ P.char '/' + <|> P.try + ( do + _ <- P.char '\\' + -- check this isn't an escape code + P.notFollowedBy (P.satisfy isGlobEscapedChar) + ) + + parsecGlob :: CabalParsing m => m GlobPieces + parsecGlob = some parsecPiece + where + parsecPiece = P.choice [literal, wildcard, union] + + wildcard = WildCard <$ P.char '*' + union = Union . toList <$> P.between (P.char '{') (P.char '}') (P.sepByNonEmpty parsecGlob (P.char ',')) + literal = Literal <$> some litchar + + litchar = normal <|> escape + + normal = P.satisfy (\c -> not (isGlobEscapedChar c) && c /= '/' && c /= '\\') + escape = P.try $ P.char '\\' >> P.satisfy isGlobEscapedChar + +-------------------------------------------------------------------------------- +-- Parse and printing utils +-------------------------------------------------------------------------------- + +dispGlobPieces :: GlobPieces -> Disp.Doc +dispGlobPieces = Disp.hcat . map dispPiece + where + dispPiece WildCard = Disp.char '*' + dispPiece (Literal str) = Disp.text (escape str) + dispPiece (Union globs) = + Disp.braces + ( Disp.hcat + ( Disp.punctuate + (Disp.char ',') + (map dispGlobPieces globs) + ) + ) + escape [] = [] + escape (c : cs) + | isGlobEscapedChar c = '\\' : c : escape cs + | otherwise = c : escape cs + +isGlobEscapedChar :: Char -> Bool +isGlobEscapedChar '*' = True +isGlobEscapedChar '{' = True +isGlobEscapedChar '}' = True +isGlobEscapedChar ',' = True +isGlobEscapedChar _ = False + +-- ** Cabal package globbing errors + +data GlobSyntaxError + = StarInDirectory + | StarInFileName + | StarInExtension + | NoExtensionOnStar + | EmptyGlob + | LiteralFileNameGlobStar + | VersionDoesNotSupportGlobStar + | VersionDoesNotSupportGlob + deriving (Eq, Show) + +explainGlobSyntaxError :: FilePath -> GlobSyntaxError -> String +explainGlobSyntaxError filepath StarInDirectory = + "invalid file glob '" + ++ filepath + ++ "'. A wildcard '**' is only allowed as the final parent" + ++ " directory. Stars must not otherwise appear in the parent" + ++ " directories." +explainGlobSyntaxError filepath StarInExtension = + "invalid file glob '" + ++ filepath + ++ "'. Wildcards '*' are only allowed as the" + ++ " file's base name, not in the file extension." +explainGlobSyntaxError filepath StarInFileName = + "invalid file glob '" + ++ filepath + ++ "'. Wildcards '*' may only totally replace the" + ++ " file's base name, not only parts of it." +explainGlobSyntaxError filepath NoExtensionOnStar = + "invalid file glob '" + ++ filepath + ++ "'. If a wildcard '*' is used it must be with an file extension." +explainGlobSyntaxError filepath LiteralFileNameGlobStar = + "invalid file glob '" + ++ filepath + ++ "'. Prior to 'cabal-version: 3.8'" + ++ " if a wildcard '**' is used as a parent directory, the" + ++ " file's base name must be a wildcard '*'." +explainGlobSyntaxError _ EmptyGlob = + "invalid file glob. A glob cannot be the empty string." +explainGlobSyntaxError filepath VersionDoesNotSupportGlobStar = + "invalid file glob '" + ++ filepath + ++ "'. Using the double-star syntax requires 'cabal-version: 2.4'" + ++ " or greater. Alternatively, for compatibility with earlier Cabal" + ++ " versions, list the included directories explicitly." +explainGlobSyntaxError filepath VersionDoesNotSupportGlob = + "invalid file glob '" + ++ filepath + ++ "'. Using star wildcards requires 'cabal-version: >= 1.6'. " + ++ "Alternatively if you require compatibility with earlier Cabal " + ++ "versions then list all the files explicitly." + +-- Note throughout that we use splitDirectories, not splitPath. On +-- Posix, this makes no difference, but, because Windows accepts both +-- slash and backslash as its path separators, if we left in the +-- separators from the glob we might not end up properly normalised. + +data GlobResult a + = -- | The glob matched the value supplied. + GlobMatch a + | -- | The glob did not match the value supplied because the + -- cabal-version is too low and the extensions on the file did + -- not precisely match the glob's extensions, but rather the + -- glob was a proper suffix of the file's extensions; i.e., if + -- not for the low cabal-version, it would have matched. + GlobWarnMultiDot a + | -- | The glob couldn't match because the directory named doesn't + -- exist. The directory will be as it appears in the glob (i.e., + -- relative to the directory passed to 'matchDirFileGlob', and, + -- for 'data-files', relative to 'data-dir'). + GlobMissingDirectory a + | -- | The glob matched a directory when we were looking for files only. + -- It didn't match a file! + -- + -- @since 3.12.0.0 + GlobMatchesDirectory a + deriving (Show, Eq, Ord, Functor) + +-- | Match files against a pre-parsed glob, starting in a directory. +-- +-- The 'Version' argument must be the spec version of the package +-- description being processed, as globs behave slightly differently +-- in different spec versions. +-- +-- The 'FilePath' argument is the directory that the glob is relative +-- to. It must be a valid directory (and hence it can't be the empty +-- string). The returned values will not include this prefix. +runDirFileGlob + :: Verbosity + -> Maybe CabalSpecVersion + -- ^ If the glob we are running should care about the cabal spec, and warnings such as 'GlobWarnMultiDot', then this should be the version. + -- If you want to run a glob but don't care about any of the cabal-spec restrictions on globs, use 'Nothing'! + -> FilePath + -> Glob + -> IO [GlobResult FilePath] +runDirFileGlob verbosity mspec rawRoot pat = do + -- The default data-dir is null. Our callers -should- be + -- converting that to '.' themselves, but it's a certainty that + -- some future call-site will forget and trigger a really + -- hard-to-debug failure if we don't check for that here. + when (null rawRoot) $ + warn verbosity $ + "Null dir passed to runDirFileGlob; interpreting it " + ++ "as '.'. This is probably an internal error." + let root = if null rawRoot then "." else rawRoot + debug verbosity $ "Expanding glob '" ++ show (pretty pat) ++ "' in directory '" ++ root ++ "'." + -- This function might be called from the project root with dir as + -- ".". Walking the tree starting there involves going into .git/ + -- and dist-newstyle/, which is a lot of work for no reward, so + -- extract the constant prefix from the pattern and start walking + -- there, and only walk as much as we need to: recursively if **, + -- the whole directory if *, and just the specific file if it's a + -- literal. + let + (prefixSegments, variablePattern) = splitConstantPrefix pat + joinedPrefix = joinPath prefixSegments + + -- The glob matching function depends on whether we care about the cabal version or not + doesGlobMatch :: GlobPieces -> String -> Maybe (GlobResult ()) + doesGlobMatch glob str = case mspec of + Just spec -> checkNameMatches spec glob str + Nothing -> if matchGlobPieces glob str then Just (GlobMatch ()) else Nothing + + go (GlobFile glob) dir = do + entries <- getDirectoryContents (root dir) + catMaybes + <$> mapM + ( \s -> do + -- When running a glob from a Cabal package description (i.e. + -- when a cabal spec version is passed as an argument), we + -- disallow matching a @GlobFile@ against a directory, preferring + -- @GlobDir dir GlobDirTrailing@ to specify a directory match. + isFile <- maybe (return True) (const $ doesFileExist (root dir s)) mspec + let match = (dir s <$) <$> doesGlobMatch glob s + return $ + if isFile + then match + else case match of + Just (GlobMatch x) -> Just $ GlobMatchesDirectory x + Just (GlobWarnMultiDot x) -> Just $ GlobMatchesDirectory x + Just (GlobMatchesDirectory x) -> Just $ GlobMatchesDirectory x + Just (GlobMissingDirectory x) -> Just $ GlobMissingDirectory x -- this should never match, unless you are in a file-delete-heavy concurrent setting i guess + Nothing -> Nothing + ) + entries + go (GlobDirRecursive glob) dir = do + entries <- getDirectoryContentsRecursive (root dir) + return $ + mapMaybe + ( \s -> do + globMatch <- doesGlobMatch glob (takeFileName s) + pure ((dir s) <$ globMatch) + ) + entries + go (GlobDir glob globPath) dir = do + entries <- getDirectoryContents (root dir) + subdirs <- + filterM + ( \subdir -> + doesDirectoryExist + (root dir subdir) + ) + $ filter (matchGlobPieces glob) entries + concat <$> traverse (\subdir -> go globPath (dir subdir)) subdirs + go GlobDirTrailing dir = return [GlobMatch dir] + + directoryExists <- doesDirectoryExist (root joinedPrefix) + if directoryExists + then go variablePattern joinedPrefix + else return [GlobMissingDirectory joinedPrefix] + where + -- \| Extract the (possibly null) constant prefix from the pattern. + -- This has the property that, if @(pref, final) = splitConstantPrefix pat@, + -- then @pat === foldr GlobDir final pref@. + splitConstantPrefix :: Glob -> ([FilePath], Glob) + splitConstantPrefix = unfoldr' step + where + step (GlobDir [Literal seg] pat') = Right (seg, pat') + step pat' = Left pat' + + unfoldr' :: (a -> Either r (b, a)) -> a -> ([b], r) + unfoldr' f a = case f a of + Left r -> ([], r) + Right (b, a') -> case unfoldr' f a' of + (bs, r) -> (b : bs, r) + +-- | Is the root of this relative glob path a directory-recursive wildcard, e.g. @**/*.txt@ ? +isRecursiveInRoot :: Glob -> Bool +isRecursiveInRoot (GlobDirRecursive _) = True +isRecursiveInRoot _ = False + +-- | Check how the string matches the glob under this cabal version +checkNameMatches :: CabalSpecVersion -> GlobPieces -> String -> Maybe (GlobResult ()) +checkNameMatches spec glob candidate + -- Check if glob matches in its general form + | matchGlobPieces glob candidate = + -- if multidot is supported, then this is a clean match + if enableMultidot spec + then pure (GlobMatch ()) + else -- if not, issue a warning saying multidot is needed for the match + + let (_, candidateExts) = splitExtensions $ takeFileName candidate + extractExts :: GlobPieces -> Maybe String + extractExts [] = Nothing + extractExts [Literal lit] + -- Any literal terminating a glob, and which does have an extension, + -- returns that extension. Otherwise, recurse until Nothing is returned. + | let ext = takeExtensions lit + , ext /= "" = + Just ext + extractExts (_ : x) = extractExts x + in case extractExts glob of + Just exts + | exts == candidateExts -> + return (GlobMatch ()) + | exts `isSuffixOf` candidateExts -> + return (GlobWarnMultiDot ()) + _ -> return (GlobMatch ()) + | otherwise = empty + +-- | How/does the glob match the given filepath, according to the cabal version? +-- Since this is pure, we don't make a distinction between matching on +-- directories or files (i.e. this function won't return 'GlobMatchesDirectory') +fileGlobMatches :: CabalSpecVersion -> Glob -> FilePath -> Maybe (GlobResult ()) +fileGlobMatches version g path = go g (splitDirectories path) + where + go GlobDirTrailing [] = Just (GlobMatch ()) + go (GlobFile glob) [file] = checkNameMatches version glob file + go (GlobDirRecursive glob) dirs + | [] <- reverse dirs = + Nothing -- @dir/**/x.txt@ should not match @dir/hello@ + | file : _ <- reverse dirs = + checkNameMatches version glob file + go (GlobDir glob globPath) (dir : dirs) = do + _ <- checkNameMatches version glob dir -- we only care if dir segment matches + go globPath dirs + go _ _ = Nothing diff --git a/Cabal/src/Distribution/Simple/Haddock.hs b/Cabal/src/Distribution/Simple/Haddock.hs index f06824b24a9..33d497231af 100644 --- a/Cabal/src/Distribution/Simple/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Haddock.hs @@ -49,7 +49,7 @@ import Distribution.Simple.BuildPaths import Distribution.Simple.BuildTarget import Distribution.Simple.Compiler import Distribution.Simple.Flag -import Distribution.Simple.Glob +import Distribution.Simple.Glob (matchDirFileGlob) import Distribution.Simple.InstallDirs import Distribution.Simple.LocalBuildInfo hiding (substPathTemplate) import qualified Distribution.Simple.PackageIndex as PackageIndex @@ -269,7 +269,8 @@ haddock pkg_descr lbi suffixes flags' = do -- We fall back to using HsColour only for versions of Haddock which don't -- support '--hyperlinked-sources'. - when (flag haddockLinkedSource && version < mkVersion [2, 17]) $ + let using_hscolour = flag haddockLinkedSource && version < mkVersion [2, 17] + when using_hscolour $ hscolour' (warn verbosity) haddockTarget @@ -293,7 +294,7 @@ haddock pkg_descr lbi suffixes flags' = do let component = targetComponent target clbi = targetCLBI target - componentInitialBuildSteps (flag haddockDistPref) pkg_descr lbi clbi verbosity + preBuildComponent verbosity lbi target let lbi' = @@ -1152,7 +1153,8 @@ hscolour' onNoHsColour haddockTarget pkg_descr lbi suffixes flags = hscolourPref haddockTarget distPref pkg_descr withAllComponentsInBuildOrder pkg_descr lbi $ \comp clbi -> do - componentInitialBuildSteps distPref pkg_descr lbi clbi verbosity + let tgt = TargetInfo clbi comp + preBuildComponent verbosity lbi tgt preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes let doExe com = case (compToExe com) of diff --git a/Cabal/src/Distribution/Simple/Hpc.hs b/Cabal/src/Distribution/Simple/Hpc.hs index 5d24f190b7e..158051b0924 100644 --- a/Cabal/src/Distribution/Simple/Hpc.hs +++ b/Cabal/src/Distribution/Simple/Hpc.hs @@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- @@ -21,17 +22,16 @@ module Distribution.Simple.Hpc , mixDir , tixDir , tixFilePath + , HPCMarkupInfo (..) , markupPackage - , markupTest ) where import Distribution.Compat.Prelude import Prelude () -import Distribution.ModuleName (main) +import Distribution.ModuleName (ModuleName, main) import Distribution.PackageDescription - ( Library (..) - , TestSuite (..) + ( TestSuite (..) , testModules ) import qualified Distribution.PackageDescription as PD @@ -73,44 +73,16 @@ mixDir -- ^ \"dist/\" prefix -> Way -> FilePath - -- ^ Component name - -> FilePath -- ^ Directory containing test suite's .mix files -mixDir distPref way name = hpcDir distPrefBuild way "mix" name - where - -- This is a hack for HPC over test suites, needed to match the directory - -- where HPC saves and reads .mix files when the main library of the same - -- package is being processed, perhaps in a previous cabal run (#5213). - -- E.g., @distPref@ may be - -- @./dist-newstyle/build/x86_64-linux/ghc-9.0.1/cabal-gh5213-0.1/t/tests@ - -- but the path where library mix files reside has two less components - -- at the end (@t/tests@) and this reduced path needs to be passed to - -- both @hpc@ and @ghc@. For non-default optimization levels, the path - -- suffix is one element longer and the extra path element needs - -- to be preserved. - distPrefElements = splitDirectories distPref - distPrefBuild = case drop (length distPrefElements - 3) distPrefElements of - ["t", _, "noopt"] -> - joinPath $ - take (length distPrefElements - 3) distPrefElements - ++ ["noopt"] - ["t", _, "opt"] -> - joinPath $ - take (length distPrefElements - 3) distPrefElements - ++ ["opt"] - [_, "t", _] -> - joinPath $ take (length distPrefElements - 2) distPrefElements - _ -> distPref +mixDir distPref way = hpcDir distPref way "mix" tixDir :: FilePath -- ^ \"dist/\" prefix -> Way -> FilePath - -- ^ Component name - -> FilePath -- ^ Directory containing test suite's .tix files -tixDir distPref way name = hpcDir distPref way "tix" name +tixDir distPref way = hpcDir distPref way "tix" -- | Path to the .tix file containing a test suite's sum statistics. tixFilePath @@ -121,17 +93,15 @@ tixFilePath -- ^ Component name -> FilePath -- ^ Path to test suite's .tix file -tixFilePath distPref way name = tixDir distPref way name name <.> "tix" +tixFilePath distPref way name = tixDir distPref way name <.> "tix" htmlDir :: FilePath -- ^ \"dist/\" prefix -> Way -> FilePath - -- ^ Component name - -> FilePath -- ^ Path to test suite's HTML markup directory -htmlDir distPref way name = hpcDir distPref way "html" name +htmlDir distPref way = hpcDir distPref way "html" -- | Attempt to guess the way the test suites in this package were compiled -- and linked with the library so the correct module interfaces are found. @@ -141,57 +111,28 @@ guessWay lbi | withDynExe lbi = Dyn | otherwise = Vanilla --- | Generate the HTML markup for a test suite. -markupTest - :: Verbosity - -> LocalBuildInfo - -> FilePath - -- ^ \"dist/\" prefix - -> String - -- ^ Library name - -> TestSuite - -> Library - -> IO () -markupTest verbosity lbi distPref libraryName suite library = do - tixFileExists <- doesFileExist $ tixFilePath distPref way $ testName' - when tixFileExists $ do - -- behaviour of 'markup' depends on version, so we need *a* version - -- but no particular one - (hpc, hpcVer, _) <- - requireProgramVersion - verbosity - hpcProgram - anyVersion - (withPrograms lbi) - let htmlDir_ = htmlDir distPref way testName' - markup - hpc - hpcVer - verbosity - (tixFilePath distPref way testName') - mixDirs - htmlDir_ - (exposedModules library) - notice verbosity $ - "Test coverage report written to " - ++ htmlDir_ - "hpc_index" <.> "html" - where - way = guessWay lbi - testName' = unUnqualComponentName $ testName suite - mixDirs = map (mixDir distPref way) [testName', libraryName] +-- | Haskell Program Coverage information required to produce a valid HPC +-- report through the `hpc markup` call for the package libraries. +data HPCMarkupInfo = HPCMarkupInfo + { pathsToLibsArtifacts :: [FilePath] + -- ^ The paths to the library components whose modules are included in the + -- coverage report + , libsModulesToInclude :: [ModuleName] + -- ^ The modules to include in the coverage report + } --- | Generate the HTML markup for all of a package's test suites. +-- | Generate the HTML markup for a package's test suites. markupPackage :: Verbosity + -> HPCMarkupInfo -> LocalBuildInfo -> FilePath - -- ^ \"dist/\" prefix + -- ^ Testsuite \"dist/\" prefix -> PD.PackageDescription -> [TestSuite] -> IO () -markupPackage verbosity lbi distPref pkg_descr suites = do - let tixFiles = map (tixFilePath distPref way) testNames +markupPackage verbosity HPCMarkupInfo{pathsToLibsArtifacts, libsModulesToInclude} lbi testDistPref pkg_descr suites = do + let tixFiles = map (tixFilePath testDistPref way) testNames tixFilesExist <- traverse doesFileExist tixFiles when (and tixFilesExist) $ do -- behaviour of 'markup' depends on version, so we need *a* version @@ -202,12 +143,33 @@ markupPackage verbosity lbi distPref pkg_descr suites = do hpcProgram anyVersion (withPrograms lbi) - let outFile = tixFilePath distPref way libraryName - htmlDir' = htmlDir distPref way libraryName - excluded = concatMap testModules suites ++ [main] - createDirectoryIfMissing True $ takeDirectory outFile - union hpc verbosity tixFiles outFile excluded - markup hpc hpcVer verbosity outFile mixDirs htmlDir' included + let htmlDir' = htmlDir testDistPref way + -- The tix file used to generate the report is either the testsuite's + -- tix file, when there is only one testsuite, or the sum of the tix + -- files of all testsuites in the package, which gets put under pkgName + -- for this component (a bit weird) + -- TODO: cabal-install should pass to Cabal where to put the summed tix + -- and report, and perhaps even the testsuites from other packages in + -- the project which are currently not accounted for in the summed + -- report. + tixFile <- case suites of + -- We call 'markupPackage' once for each testsuite to run individually, + -- to get the coverage report of just the one testsuite + [oneTest] -> do + let testName' = unUnqualComponentName $ testName oneTest + return $ + tixFilePath testDistPref way testName' + -- And call 'markupPackage' once per `test` invocation with all the + -- testsuites to run, which results in multiple tix files being considered + _ -> do + let excluded = concatMap testModules suites ++ [main] + pkgName = prettyShow $ PD.package pkg_descr + summedTixFile = tixFilePath testDistPref way pkgName + createDirectoryIfMissing True $ takeDirectory summedTixFile + union hpc verbosity tixFiles summedTixFile excluded + return summedTixFile + + markup hpc hpcVer verbosity tixFile mixDirs htmlDir' libsModulesToInclude notice verbosity $ "Package coverage report written to " ++ htmlDir' @@ -215,6 +177,4 @@ markupPackage verbosity lbi distPref pkg_descr suites = do where way = guessWay lbi testNames = fmap (unUnqualComponentName . testName) suites - mixDirs = map (mixDir distPref way) $ libraryName : testNames - included = concatMap (exposedModules) $ PD.allLibraries pkg_descr - libraryName = prettyShow $ PD.package pkg_descr + mixDirs = map (`mixDir` way) pathsToLibsArtifacts diff --git a/Cabal/src/Distribution/Simple/InstallDirs.hs b/Cabal/src/Distribution/Simple/InstallDirs.hs index cbbde89323a..f03a78cf2dc 100644 --- a/Cabal/src/Distribution/Simple/InstallDirs.hs +++ b/Cabal/src/Distribution/Simple/InstallDirs.hs @@ -346,6 +346,7 @@ data CopyDest deriving (Eq, Show, Generic) instance Binary CopyDest +instance Structured CopyDest -- | Check which of the paths are relative to the installation $prefix. -- diff --git a/Cabal/src/Distribution/Simple/LocalBuildInfo.hs b/Cabal/src/Distribution/Simple/LocalBuildInfo.hs index 78166c6e25c..8659764d0c4 100644 --- a/Cabal/src/Distribution/Simple/LocalBuildInfo.hs +++ b/Cabal/src/Distribution/Simple/LocalBuildInfo.hs @@ -1,5 +1,7 @@ {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- @@ -25,6 +27,12 @@ module Distribution.Simple.LocalBuildInfo , localUnitId , localCompatPackageKey + -- * Convenience accessors + , buildDir + , cabalFilePath + , progPrefix + , progSuffix + -- * Buildable package components , Component (..) , ComponentName (..) @@ -200,8 +208,8 @@ withAllComponentsInBuildOrder pkg lbi f = allComponentsInBuildOrder :: LocalBuildInfo -> [ComponentLocalBuildInfo] -allComponentsInBuildOrder lbi = - Graph.topSort (componentGraph lbi) +allComponentsInBuildOrder (LocalBuildInfo{componentGraph = compGraph}) = + Graph.topSort compGraph -- ----------------------------------------------------------------------------- -- A random function that has no business in this module @@ -219,94 +227,101 @@ depLibraryPaths -> ComponentLocalBuildInfo -- ^ Component that is being built -> IO [FilePath] -depLibraryPaths inplace relative lbi clbi = do - let pkgDescr = localPkgDescr lbi - installDirs = absoluteComponentInstallDirs pkgDescr lbi (componentUnitId clbi) NoCopyDest - executable = case clbi of - ExeComponentLocalBuildInfo{} -> True - _ -> False - relDir - | executable = bindir installDirs - | otherwise = libdir installDirs - - let - -- TODO: this is kind of inefficient - internalDeps = - [ uid - | (uid, _) <- componentPackageDeps clbi - , -- Test that it's internal - sub_target <- allTargetsInBuildOrder' pkgDescr lbi - , componentUnitId (targetCLBI (sub_target)) == uid - ] - internalLibs = - [ getLibDir (targetCLBI sub_target) - | sub_target <- - neededTargetsInBuildOrder' - pkgDescr - lbi - internalDeps - ] - {- - -- This is better, but it doesn't work, because we may be passed a - -- CLBI which doesn't actually exist, and was faked up when we - -- were building a test suite/benchmark. See #3599 for proposal - -- to fix this. - let internalCLBIs = filter ((/= componentUnitId clbi) . componentUnitId) - . map targetCLBI - $ neededTargetsInBuildOrder lbi [componentUnitId clbi] - internalLibs = map getLibDir internalCLBIs - -} - getLibDir sub_clbi - | inplace = componentBuildDir lbi sub_clbi - | otherwise = dynlibdir (absoluteComponentInstallDirs pkgDescr lbi (componentUnitId sub_clbi) NoCopyDest) - - -- Why do we go through all the trouble of a hand-crafting - -- internalLibs, when 'installedPkgs' actually contains the - -- internal libraries? The trouble is that 'installedPkgs' - -- may contain *inplace* entries, which we must NOT use for - -- not inplace 'depLibraryPaths' (e.g., for RPATH calculation). - -- See #4025 for more details. This is all horrible but it - -- is a moot point if you are using a per-component build, - -- because you never have any internal libraries in this case; - -- they're all external. - let external_ipkgs = filter is_external (allPackages (installedPkgs lbi)) - is_external ipkg = not (installedUnitId ipkg `elem` internalDeps) - -- First look for dynamic libraries in `dynamic-library-dirs`, and use - -- `library-dirs` as a fall back. - getDynDir pkg = case Installed.libraryDynDirs pkg of - [] -> Installed.libraryDirs pkg - d -> d - allDepLibDirs = concatMap getDynDir external_ipkgs - - allDepLibDirs' = internalLibs ++ allDepLibDirs - allDepLibDirsC <- traverse canonicalizePathNoFail allDepLibDirs' - - let p = prefix installDirs - prefixRelative l = isJust (stripPrefix p l) - libPaths - | relative - && prefixRelative relDir = - map - ( \l -> - if prefixRelative l - then shortRelativePath relDir l - else l - ) - allDepLibDirsC - | otherwise = allDepLibDirsC - - -- For some reason, this function returns lots of duplicates. Avoid - -- exceeding `ARG_MAX` (the result of this function is used to populate - -- `LD_LIBRARY_PATH`) by deduplicating the list. - return $ ordNub libPaths - where - -- 'canonicalizePath' fails on UNIX when the directory does not exists. - -- So just don't canonicalize when it doesn't exist. - canonicalizePathNoFail p = do - exists <- doesDirectoryExist p - if exists - then canonicalizePath p - else return p +depLibraryPaths + inplace + relative + lbi@( LocalBuildInfo + { localPkgDescr = pkgDescr + , installedPkgs = installed + } + ) + clbi = do + let installDirs = absoluteComponentInstallDirs pkgDescr lbi (componentUnitId clbi) NoCopyDest + executable = case clbi of + ExeComponentLocalBuildInfo{} -> True + _ -> False + relDir + | executable = bindir installDirs + | otherwise = libdir installDirs + + let + -- TODO: this is kind of inefficient + internalDeps = + [ uid + | (uid, _) <- componentPackageDeps clbi + , -- Test that it's internal + sub_target <- allTargetsInBuildOrder' pkgDescr lbi + , componentUnitId (targetCLBI (sub_target)) == uid + ] + internalLibs = + [ getLibDir (targetCLBI sub_target) + | sub_target <- + neededTargetsInBuildOrder' + pkgDescr + lbi + internalDeps + ] + {- + -- This is better, but it doesn't work, because we may be passed a + -- CLBI which doesn't actually exist, and was faked up when we + -- were building a test suite/benchmark. See #3599 for proposal + -- to fix this. + let internalCLBIs = filter ((/= componentUnitId clbi) . componentUnitId) + . map targetCLBI + $ neededTargetsInBuildOrder lbi [componentUnitId clbi] + internalLibs = map getLibDir internalCLBIs + -} + getLibDir sub_clbi + | inplace = componentBuildDir lbi sub_clbi + | otherwise = dynlibdir (absoluteComponentInstallDirs pkgDescr lbi (componentUnitId sub_clbi) NoCopyDest) + + -- Why do we go through all the trouble of a hand-crafting + -- internalLibs, when 'installedPkgs' actually contains the + -- internal libraries? The trouble is that 'installedPkgs' + -- may contain *inplace* entries, which we must NOT use for + -- not inplace 'depLibraryPaths' (e.g., for RPATH calculation). + -- See #4025 for more details. This is all horrible but it + -- is a moot point if you are using a per-component build, + -- because you never have any internal libraries in this case; + -- they're all external. + let external_ipkgs = filter is_external (allPackages installed) + is_external ipkg = not (installedUnitId ipkg `elem` internalDeps) + -- First look for dynamic libraries in `dynamic-library-dirs`, and use + -- `library-dirs` as a fall back. + getDynDir pkg = case Installed.libraryDynDirs pkg of + [] -> Installed.libraryDirs pkg + d -> d + allDepLibDirs = concatMap getDynDir external_ipkgs + + allDepLibDirs' = internalLibs ++ allDepLibDirs + allDepLibDirsC <- traverse canonicalizePathNoFail allDepLibDirs' + + let p = prefix installDirs + prefixRelative l = isJust (stripPrefix p l) + libPaths + | relative + && prefixRelative relDir = + map + ( \l -> + if prefixRelative l + then shortRelativePath relDir l + else l + ) + allDepLibDirsC + | otherwise = allDepLibDirsC + + -- For some reason, this function returns lots of duplicates. Avoid + -- exceeding `ARG_MAX` (the result of this function is used to populate + -- `LD_LIBRARY_PATH`) by deduplicating the list. + return $ ordNub libPaths + where + -- 'canonicalizePath' fails on UNIX when the directory does not exists. + -- So just don't canonicalize when it doesn't exist. + canonicalizePathNoFail p = do + exists <- doesDirectoryExist p + if exists + then canonicalizePath p + else return p -- | Get all module names that needed to be built by GHC; i.e., all -- of these 'ModuleName's have interface files associated with them @@ -341,14 +356,18 @@ absoluteComponentInstallDirs -> UnitId -> CopyDest -> InstallDirs FilePath -absoluteComponentInstallDirs pkg lbi uid copydest = - InstallDirs.absoluteInstallDirs - (packageId pkg) - uid - (compilerInfo (compiler lbi)) - copydest - (hostPlatform lbi) - (installDirTemplates lbi) +absoluteComponentInstallDirs + pkg + (LocalBuildInfo{compiler = comp, hostPlatform = plat, installDirTemplates = installDirs}) + uid + copydest = + InstallDirs.absoluteInstallDirs + (packageId pkg) + uid + (compilerInfo comp) + copydest + plat + installDirs absoluteInstallCommandDirs :: PackageDescription @@ -397,13 +416,16 @@ prefixRelativeComponentInstallDirs -> LocalBuildInfo -> UnitId -> InstallDirs (Maybe FilePath) -prefixRelativeComponentInstallDirs pkg_descr lbi uid = - InstallDirs.prefixRelativeInstallDirs - (packageId pkg_descr) - uid - (compilerInfo (compiler lbi)) - (hostPlatform lbi) - (installDirTemplates lbi) +prefixRelativeComponentInstallDirs + pkg_descr + (LocalBuildInfo{compiler = comp, hostPlatform = plat, installDirTemplates = installDirs}) + uid = + InstallDirs.prefixRelativeInstallDirs + (packageId pkg_descr) + uid + (compilerInfo comp) + plat + installDirs substPathTemplate :: PackageId @@ -411,13 +433,16 @@ substPathTemplate -> UnitId -> PathTemplate -> FilePath -substPathTemplate pkgid lbi uid = - fromPathTemplate - . (InstallDirs.substPathTemplate env) - where - env = - initialPathTemplateEnv - pkgid - uid - (compilerInfo (compiler lbi)) - (hostPlatform lbi) +substPathTemplate + pkgid + (LocalBuildInfo{compiler = comp, hostPlatform = plat}) + uid = + fromPathTemplate + . (InstallDirs.substPathTemplate env) + where + env = + initialPathTemplateEnv + pkgid + uid + (compilerInfo comp) + plat diff --git a/Cabal/src/Distribution/Simple/PreProcess.hs b/Cabal/src/Distribution/Simple/PreProcess.hs index 31e228812d6..4f69ce6fc05 100644 --- a/Cabal/src/Distribution/Simple/PreProcess.hs +++ b/Cabal/src/Distribution/Simple/PreProcess.hs @@ -11,21 +11,23 @@ -- Maintainer : cabal-devel@haskell.org -- Portability : portable -- --- This defines a 'PreProcessor' abstraction which represents a pre-processor --- that can transform one kind of file into another. There is also a --- 'PPSuffixHandler' which is a combination of a file extension and a function --- for configuring a 'PreProcessor'. It defines a bunch of known built-in --- preprocessors like @cpp@, @cpphs@, @c2hs@, @hsc2hs@, @happy@, @alex@ etc and --- lists them in 'knownSuffixHandlers'. On top of this it provides a function --- for actually preprocessing some sources given a bunch of known suffix --- handlers. This module is not as good as it could be, it could really do with --- a rewrite to address some of the problems we have with pre-processors. +-- This module defines 'PPSuffixHandler', which is a combination of a file +-- extension and a function for configuring a 'PreProcessor'. It also defines +-- a bunch of known built-in preprocessors like @cpp@, @cpphs@, @c2hs@, +-- @hsc2hs@, @happy@, @alex@ etc and lists them in 'knownSuffixHandlers'. +-- On top of this it provides a function for actually preprocessing some sources +-- given a bunch of known suffix handlers. +-- This module is not as good as it could be, it could really do with a rewrite +-- to address some of the problems we have with pre-processors. module Distribution.Simple.PreProcess ( preprocessComponent , preprocessExtras , knownSuffixHandlers , ppSuffixes , PPSuffixHandler + , Suffix (..) + , builtinHaskellSuffixes + , builtinHaskellBootSuffixes , PreProcessor (..) , mkSimplePreProcessor , runSimplePreProcessor @@ -58,6 +60,7 @@ import Distribution.Simple.Compiler import Distribution.Simple.Errors import Distribution.Simple.LocalBuildInfo import qualified Distribution.Simple.PackageIndex as PackageIndex +import Distribution.Simple.PreProcess.Types import Distribution.Simple.PreProcess.Unlit import Distribution.Simple.Program import Distribution.Simple.Program.ResponseFile @@ -81,69 +84,6 @@ import System.FilePath ) import System.Info (arch, os) --- | The interface to a preprocessor, which may be implemented using an --- external program, but need not be. The arguments are the name of --- the input file, the name of the output file and a verbosity level. --- Here is a simple example that merely prepends a comment to the given --- source file: --- --- > ppTestHandler :: PreProcessor --- > ppTestHandler = --- > PreProcessor { --- > platformIndependent = True, --- > runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity -> --- > do info verbosity (inFile++" has been preprocessed to "++outFile) --- > stuff <- readFile inFile --- > writeFile outFile ("-- preprocessed as a test\n\n" ++ stuff) --- > return ExitSuccess --- --- We split the input and output file names into a base directory and the --- rest of the file name. The input base dir is the path in the list of search --- dirs that this file was found in. The output base dir is the build dir where --- all the generated source files are put. --- --- The reason for splitting it up this way is that some pre-processors don't --- simply generate one output .hs file from one input file but have --- dependencies on other generated files (notably c2hs, where building one --- .hs file may require reading other .chi files, and then compiling the .hs --- file may require reading a generated .h file). In these cases the generated --- files need to embed relative path names to each other (eg the generated .hs --- file mentions the .h file in the FFI imports). This path must be relative to --- the base directory where the generated files are located, it cannot be --- relative to the top level of the build tree because the compilers do not --- look for .h files relative to there, ie we do not use \"-I .\", instead we --- use \"-I dist\/build\" (or whatever dist dir has been set by the user) --- --- Most pre-processors do not care of course, so mkSimplePreProcessor and --- runSimplePreProcessor functions handle the simple case. -data PreProcessor = PreProcessor - { -- Is the output of the pre-processor platform independent? eg happy output - -- is portable haskell but c2hs's output is platform dependent. - -- This matters since only platform independent generated code can be - -- included into a source tarball. - platformIndependent :: Bool - , -- TODO: deal with pre-processors that have implementation dependent output - -- eg alex and happy have --ghc flags. However we can't really include - -- ghc-specific code into supposedly portable source tarballs. - - ppOrdering - :: Verbosity - -> [FilePath] -- Source directories - -> [ModuleName] -- Module names - -> IO [ModuleName] -- Sorted modules - - -- ^ This function can reorder /all/ modules, not just those that the - -- require the preprocessor in question. As such, this function should be - -- well-behaved and not reorder modules it doesn't have dominion over! - -- - -- @since 3.8.1.0 - , runPreProcessor - :: (FilePath, FilePath) -- Location of the source file relative to a base dir - -> (FilePath, FilePath) -- Output file name, relative to an output base dir - -> Verbosity -- verbosity - -> IO () -- Should exit if the preprocessor fails - } - -- | Just present the modules in the order given; this is the default and it is -- appropriate for preprocessors which do not have any sort of dependencies -- between modules. @@ -184,10 +124,10 @@ runSimplePreProcessor runSimplePreProcessor pp inFile outFile verbosity = runPreProcessor pp (".", inFile) (".", outFile) verbosity --- | A preprocessor for turning non-Haskell files with the given extension --- into plain Haskell source files. +-- | A preprocessor for turning non-Haskell files with the given 'Suffix' +-- (i.e. file extension) into plain Haskell source files. type PPSuffixHandler = - (String, BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor) + (Suffix, BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor) -- | Apply preprocessors to the sources from 'hsSourceDirs' for a given -- component (lib, exe, or test suite). @@ -274,8 +214,7 @@ preprocessComponent pd comp lbi clbi isSrcDist verbosity handlers = where orderingFromHandlers v d hndlrs mods = foldM (\acc (_, pp) -> ppOrdering pp v d acc) mods hndlrs - builtinHaskellSuffixes = ["hs", "lhs", "hsig", "lhsig"] - builtinCSuffixes = cSourceExtensions + builtinCSuffixes = map Suffix cSourceExtensions builtinSuffixes = builtinHaskellSuffixes ++ builtinCSuffixes localHandlers bi = [(ext, h bi lbi clbi) | (ext, h) <- handlers] pre dirs dir lhndlrs fp = @@ -344,9 +283,9 @@ preprocessFile -- ^ module file name -> Verbosity -- ^ verbosity - -> [String] + -> [Suffix] -- ^ builtin suffixes - -> [(String, PreProcessor)] + -> [(Suffix, PreProcessor)] -- ^ possible preprocessors -> Bool -- ^ fail on missing file @@ -381,7 +320,7 @@ preprocessFile searchLoc buildLoc forSDist baseFile verbosity builtinSuffixes ha pp = fromMaybe (error "Distribution.Simple.PreProcess: Just expected") - (lookup (safeTail ext) handlers) + (lookup (Suffix $ safeTail ext) handlers) -- Preprocessing files for 'sdist' is different from preprocessing -- for 'build'. When preprocessing for sdist we preprocess to -- avoid that the user has to have the preprocessors available. @@ -849,7 +788,9 @@ platformDefines lbi = X86_64 -> ["x86_64"] PPC -> ["powerpc"] PPC64 -> ["powerpc64"] + PPC64LE -> ["powerpc64le"] Sparc -> ["sparc"] + Sparc64 -> ["sparc64"] Arm -> ["arm"] AArch64 -> ["aarch64"] Mips -> ["mips"] @@ -900,19 +841,19 @@ standardPP lbi prog args = } -- | Convenience function; get the suffixes of these preprocessors. -ppSuffixes :: [PPSuffixHandler] -> [String] +ppSuffixes :: [PPSuffixHandler] -> [Suffix] ppSuffixes = map fst -- | Standard preprocessors: GreenCard, c2hs, hsc2hs, happy, alex and cpphs. knownSuffixHandlers :: [PPSuffixHandler] knownSuffixHandlers = - [ ("gc", ppGreenCard) - , ("chs", ppC2hs) - , ("hsc", ppHsc2hs) - , ("x", ppAlex) - , ("y", ppHappy) - , ("ly", ppHappy) - , ("cpphs", ppCpp) + [ (Suffix "gc", ppGreenCard) + , (Suffix "chs", ppC2hs) + , (Suffix "hsc", ppHsc2hs) + , (Suffix "x", ppAlex) + , (Suffix "y", ppHappy) + , (Suffix "ly", ppHappy) + , (Suffix "cpphs", ppCpp) ] -- | Standard preprocessors with possible extra C sources: c2hs, hsc2hs. diff --git a/Cabal/src/Distribution/Simple/PreProcess/Types.hs b/Cabal/src/Distribution/Simple/PreProcess/Types.hs new file mode 100644 index 00000000000..02a5bdbc531 --- /dev/null +++ b/Cabal/src/Distribution/Simple/PreProcess/Types.hs @@ -0,0 +1,114 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE RankNTypes #-} + +----------------------------------------------------------------------------- + +-- | +-- Module : Distribution.Simple.PreProcess.Types +-- Copyright : (c) 2003-2005, Isaac Jones, Malcolm Wallace +-- License : BSD3 +-- +-- Maintainer : cabal-devel@haskell.org +-- Portability : portable +-- +-- This defines a 'PreProcessor' abstraction which represents a pre-processor +-- that can transform one kind of file into another. +module Distribution.Simple.PreProcess.Types + ( Suffix (..) + , PreProcessor (..) + , builtinHaskellSuffixes + , builtinHaskellBootSuffixes + ) +where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.ModuleName (ModuleName) +import Distribution.Pretty +import Distribution.Verbosity +import qualified Text.PrettyPrint as Disp + +-- | The interface to a preprocessor, which may be implemented using an +-- external program, but need not be. The arguments are the name of +-- the input file, the name of the output file and a verbosity level. +-- Here is a simple example that merely prepends a comment to the given +-- source file: +-- +-- > ppTestHandler :: PreProcessor +-- > ppTestHandler = +-- > PreProcessor { +-- > platformIndependent = True, +-- > runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity -> +-- > do info verbosity (inFile++" has been preprocessed to "++outFile) +-- > stuff <- readFile inFile +-- > writeFile outFile ("-- preprocessed as a test\n\n" ++ stuff) +-- > return ExitSuccess +-- +-- We split the input and output file names into a base directory and the +-- rest of the file name. The input base dir is the path in the list of search +-- dirs that this file was found in. The output base dir is the build dir where +-- all the generated source files are put. +-- +-- The reason for splitting it up this way is that some pre-processors don't +-- simply generate one output .hs file from one input file but have +-- dependencies on other generated files (notably c2hs, where building one +-- .hs file may require reading other .chi files, and then compiling the .hs +-- file may require reading a generated .h file). In these cases the generated +-- files need to embed relative path names to each other (eg the generated .hs +-- file mentions the .h file in the FFI imports). This path must be relative to +-- the base directory where the generated files are located, it cannot be +-- relative to the top level of the build tree because the compilers do not +-- look for .h files relative to there, ie we do not use \"-I .\", instead we +-- use \"-I dist\/build\" (or whatever dist dir has been set by the user) +-- +-- Most pre-processors do not care of course, so mkSimplePreProcessor and +-- runSimplePreProcessor functions handle the simple case. +data PreProcessor = PreProcessor + { -- Is the output of the pre-processor platform independent? eg happy output + -- is portable haskell but c2hs's output is platform dependent. + -- This matters since only platform independent generated code can be + -- included into a source tarball. + platformIndependent :: Bool + , -- TODO: deal with pre-processors that have implementation dependent output + -- eg alex and happy have --ghc flags. However we can't really include + -- ghc-specific code into supposedly portable source tarballs. + + ppOrdering + :: Verbosity + -> [FilePath] -- Source directories + -> [ModuleName] -- Module names + -> IO [ModuleName] -- Sorted modules + + -- ^ This function can reorder /all/ modules, not just those that the + -- require the preprocessor in question. As such, this function should be + -- well-behaved and not reorder modules it doesn't have dominion over! + -- + -- @since 3.8.1.0 + , runPreProcessor + :: (FilePath, FilePath) -- Location of the source file relative to a base dir + -> (FilePath, FilePath) -- Output file name, relative to an output base dir + -> Verbosity -- verbosity + -> IO () -- Should exit if the preprocessor fails + } + +-- | A suffix (or file extension). +-- +-- Mostly used to decide which preprocessor to use, e.g. files with suffix @"y"@ +-- are usually processed by the @"happy"@ build tool. +newtype Suffix = Suffix String + deriving (Eq, Ord, Show, Generic, IsString) + +instance Pretty Suffix where + pretty (Suffix s) = Disp.text s + +instance Binary Suffix +instance Structured Suffix + +builtinHaskellSuffixes :: [Suffix] +builtinHaskellSuffixes = map Suffix ["hs", "lhs", "hsig", "lhsig"] + +builtinHaskellBootSuffixes :: [Suffix] +builtinHaskellBootSuffixes = map Suffix ["hs-boot", "lhs-boot"] diff --git a/Cabal/src/Distribution/Simple/Program/Builtin.hs b/Cabal/src/Distribution/Simple/Program/Builtin.hs index e604dbbe962..e79e676d8cc 100644 --- a/Cabal/src/Distribution/Simple/Program/Builtin.hs +++ b/Cabal/src/Distribution/Simple/Program/Builtin.hs @@ -370,7 +370,19 @@ ldProgram = -- `lld` only accepts `-help`. `catchIO` (\_ -> return "") let k = "Supports relocatable output" - v = if "--relocatable" `isInfixOf` ldHelpOutput then "YES" else "NO" + -- Standard GNU `ld` uses `--relocatable` while `ld.gold` uses + -- `-relocatable` (single `-`). + v + | "-relocatable" `isInfixOf` ldHelpOutput = "YES" + -- ld64 on macOS has this lovely response for "--help" + -- + -- ld64: For information on command line options please use 'man ld'. + -- + -- it does however support -r, if you read the manpage + -- (e.g. https://www.manpagez.com/man/1/ld64/) + | "ld64:" `isPrefixOf` ldHelpOutput = "YES" + | otherwise = "NO" + m = Map.insert k v (programProperties ldProg) return $ ldProg{programProperties = m} } diff --git a/Cabal/src/Distribution/Simple/Program/Db.hs b/Cabal/src/Distribution/Simple/Program/Db.hs index 5bef94e4b5f..a5e4e4ab381 100644 --- a/Cabal/src/Distribution/Simple/Program/Db.hs +++ b/Cabal/src/Distribution/Simple/Program/Db.hs @@ -34,6 +34,7 @@ module Distribution.Simple.Program.Db -- ** Query and manipulate the program db , addKnownProgram , addKnownPrograms + , prependProgramSearchPath , lookupKnownProgram , knownPrograms , getProgramSearchPath @@ -46,6 +47,7 @@ module Distribution.Simple.Program.Db , userSpecifyArgss , userSpecifiedArgs , lookupProgram + , lookupProgramByName , updateProgram , configuredPrograms @@ -220,6 +222,21 @@ modifyProgramSearchPath modifyProgramSearchPath f db = setProgramSearchPath (f $ getProgramSearchPath db) db +-- | Modify the current 'ProgramSearchPath' used by the 'ProgramDb' +-- by prepending the provided extra paths. Also logs the added paths +-- in info verbosity. +prependProgramSearchPath + :: Verbosity + -> [FilePath] + -> ProgramDb + -> IO ProgramDb +prependProgramSearchPath verbosity extraPaths db = + if not $ null extraPaths + then do + logExtraProgramSearchPath verbosity extraPaths + pure $ modifyProgramSearchPath (map ProgramSearchPathDir extraPaths ++) db + else pure db + -- | User-specify this path. Basically override any path information -- for this program in the configuration. If it's not a known -- program ignore it. @@ -299,7 +316,11 @@ userSpecifiedArgs prog = -- | Try to find a configured program lookupProgram :: Program -> ProgramDb -> Maybe ConfiguredProgram -lookupProgram prog = Map.lookup (programName prog) . configuredProgs +lookupProgram = lookupProgramByName . programName + +-- | Try to find a configured program +lookupProgramByName :: String -> ProgramDb -> Maybe ConfiguredProgram +lookupProgramByName name = Map.lookup name . configuredProgs -- | Update a configured program in the database. updateProgram diff --git a/Cabal/src/Distribution/Simple/Program/Find.hs b/Cabal/src/Distribution/Simple/Program/Find.hs index 806c9125968..4bebe2a19b6 100644 --- a/Cabal/src/Distribution/Simple/Program/Find.hs +++ b/Cabal/src/Distribution/Simple/Program/Find.hs @@ -32,13 +32,17 @@ module Distribution.Simple.Program.Find , defaultProgramSearchPath , findProgramOnSearchPath , programSearchPathAsPATHVar + , logExtraProgramSearchPath , getSystemSearchPath + , getExtraPathEnv + , simpleProgram ) where import Distribution.Compat.Prelude import Prelude () import Distribution.Compat.Environment +import Distribution.Simple.Program.Types import Distribution.Simple.Utils import Distribution.System import Distribution.Verbosity @@ -58,32 +62,18 @@ import System.FilePath as FilePath import qualified System.Win32 as Win32 #endif --- | A search path to use when locating executables. This is analogous --- to the unix @$PATH@ or win32 @%PATH%@ but with the ability to use --- the system default method for finding executables ('findExecutable' which --- on unix is simply looking on the @$PATH@ but on win32 is a bit more --- complicated). --- --- The default to use is @[ProgSearchPathDefault]@ but you can add extra dirs --- either before, after or instead of the default, e.g. here we add an extra --- dir to search after the usual ones. --- --- > ['ProgramSearchPathDefault', 'ProgramSearchPathDir' dir] -type ProgramSearchPath = [ProgramSearchPathEntry] - -data ProgramSearchPathEntry - = -- | A specific dir - ProgramSearchPathDir FilePath - | -- | The system default - ProgramSearchPathDefault - deriving (Eq, Generic, Typeable) - -instance Binary ProgramSearchPathEntry -instance Structured ProgramSearchPathEntry - defaultProgramSearchPath :: ProgramSearchPath defaultProgramSearchPath = [ProgramSearchPathDefault] +logExtraProgramSearchPath + :: Verbosity + -> [FilePath] + -> IO () +logExtraProgramSearchPath verbosity extraPaths = + info verbosity . unlines $ + "Including the following directories in PATH:" + : map ("- " ++) extraPaths + findProgramOnSearchPath :: Verbosity -> ProgramSearchPath @@ -154,6 +144,25 @@ findProgramOnSearchPath verbosity searchpath prog = do Just _ -> return a Nothing -> firstJustM mas +-- | Adds some paths to the "PATH" entry in the key-value environment provided +-- or if there is none, looks up @$PATH@ in the real environment. +getExtraPathEnv + :: Verbosity + -> [(String, Maybe String)] + -> [FilePath] + -> IO [(String, Maybe String)] +getExtraPathEnv _ _ [] = return [] +getExtraPathEnv verbosity env extras = do + mb_path <- case lookup "PATH" env of + Just x -> return x + Nothing -> lookupEnv "PATH" + logExtraProgramSearchPath verbosity extras + let extra = intercalate [searchPathSeparator] extras + path' = case mb_path of + Nothing -> extra + Just path -> extra ++ searchPathSeparator : path + return [("PATH", Just path')] + -- | Interpret a 'ProgramSearchPath' to construct a new @$PATH@ env var. -- Note that this is close but not perfect because on Windows the search -- algorithm looks at more than just the @%PATH%@. @@ -207,3 +216,19 @@ findExecutable prog = do else return Nothing _ -> return mExe #endif + +-- | Make a simple named program. +-- +-- By default we'll just search for it in the path and not try to find the +-- version name. You can override these behaviours if necessary, eg: +-- +-- > (simpleProgram "foo") { programFindLocation = ... , programFindVersion ... } +simpleProgram :: String -> Program +simpleProgram name = + Program + { programName = name + , programFindLocation = \v p -> findProgramOnSearchPath v p name + , programFindVersion = \_ _ -> return Nothing + , programPostConf = \_ p -> return p + , programNormaliseArgs = \_ _ -> id + } diff --git a/Cabal/src/Distribution/Simple/Program/GHC.hs b/Cabal/src/Distribution/Simple/Program/GHC.hs index 537e008c17f..9fa70feb5a2 100644 --- a/Cabal/src/Distribution/Simple/Program/GHC.hs +++ b/Cabal/src/Distribution/Simple/Program/GHC.hs @@ -28,6 +28,7 @@ import Distribution.Pretty import Distribution.Simple.Compiler import Distribution.Simple.Flag import Distribution.Simple.GHC.ImplInfo +import Distribution.Simple.Program.Find (getExtraPathEnv) import Distribution.Simple.Program.Run import Distribution.Simple.Program.Types import Distribution.System @@ -554,8 +555,6 @@ data GhcOptions = GhcOptions , ghcOptExtraPath :: NubListR FilePath -- ^ Put the extra folders in the PATH environment variable we invoke -- GHC with - -- | Put the extra folders in the PATH environment variable we invoke - -- GHC with , ghcOptCabal :: Flag Bool -- ^ Let GHC know that it is Cabal that's calling it. -- Modifies some of the GHC error messages. @@ -616,18 +615,24 @@ runGHC -> GhcOptions -> IO () runGHC verbosity ghcProg comp platform opts = do - runProgramInvocation verbosity (ghcInvocation ghcProg comp platform opts) + runProgramInvocation verbosity =<< ghcInvocation verbosity ghcProg comp platform opts ghcInvocation - :: ConfiguredProgram + :: Verbosity + -> ConfiguredProgram -> Compiler -> Platform -> GhcOptions - -> ProgramInvocation -ghcInvocation prog comp platform opts = - (programInvocation prog (renderGhcOptions comp platform opts)) - { progInvokePathEnv = fromNubListR (ghcOptExtraPath opts) - } + -> IO ProgramInvocation +ghcInvocation verbosity ghcProg comp platform opts = do + -- NOTE: GHC is the only program whose path we modify with more values than + -- the standard @extra-prog-path@, namely the folders of the executables in + -- the components, see @componentGhcOptions@. + let envOverrides = programOverrideEnv ghcProg + extraPath <- getExtraPathEnv verbosity envOverrides (fromNubListR (ghcOptExtraPath opts)) + let ghcProg' = ghcProg{programOverrideEnv = envOverrides ++ extraPath} + + pure $ programInvocation ghcProg' (renderGhcOptions comp platform opts) renderGhcOptions :: Compiler -> Platform -> GhcOptions -> [String] renderGhcOptions comp _platform@(Platform _arch os) opts @@ -773,10 +778,7 @@ renderGhcOptions comp _platform@(Platform _arch os) opts else [] , ["-no-hs-main" | flagBool ghcOptLinkNoHsMain] , ["-dynload deploy" | not (null (flags ghcOptRPaths))] - , concat - [ ["-optl-Wl,-rpath," ++ dir] - | dir <- flags ghcOptRPaths - ] + , ["-optl-Wl,-rpath," ++ dir | dir <- flags ghcOptRPaths] , flags ghcOptLinkModDefFiles , ------------- -- Packages diff --git a/Cabal/src/Distribution/Simple/Program/Run.hs b/Cabal/src/Distribution/Simple/Program/Run.hs index 27ff33dce01..e9a1298559b 100644 --- a/Cabal/src/Distribution/Simple/Program/Run.hs +++ b/Cabal/src/Distribution/Simple/Program/Run.hs @@ -24,6 +24,7 @@ module Distribution.Simple.Program.Run , getProgramInvocationOutput , getProgramInvocationLBS , getProgramInvocationOutputAndErrors + , getProgramInvocationLBSAndErrors , getEffectiveEnvironment ) where @@ -36,7 +37,6 @@ import Distribution.Simple.Program.Types import Distribution.Simple.Utils import Distribution.Utils.Generic import Distribution.Verbosity -import System.FilePath (searchPathSeparator) import qualified Data.ByteString.Lazy as LBS import qualified Data.Map as Map @@ -51,8 +51,6 @@ data ProgramInvocation = ProgramInvocation { progInvokePath :: FilePath , progInvokeArgs :: [String] , progInvokeEnv :: [(String, Maybe String)] - , -- Extra paths to add to PATH - progInvokePathEnv :: [FilePath] , progInvokeCwd :: Maybe FilePath , progInvokeInput :: Maybe IOData , progInvokeInputEncoding :: IOEncoding @@ -75,7 +73,6 @@ emptyProgramInvocation = { progInvokePath = "" , progInvokeArgs = [] , progInvokeEnv = [] - , progInvokePathEnv = [] , progInvokeCwd = Nothing , progInvokeInput = Nothing , progInvokeInputEncoding = IOEncodingText @@ -107,7 +104,6 @@ runProgramInvocation { progInvokePath = path , progInvokeArgs = args , progInvokeEnv = [] - , progInvokePathEnv = [] , progInvokeCwd = Nothing , progInvokeInput = Nothing } = @@ -118,12 +114,10 @@ runProgramInvocation { progInvokePath = path , progInvokeArgs = args , progInvokeEnv = envOverrides - , progInvokePathEnv = extraPath , progInvokeCwd = mcwd , progInvokeInput = Nothing } = do - pathOverride <- getExtraPathEnv envOverrides extraPath - menv <- getEffectiveEnvironment (envOverrides ++ pathOverride) + menv <- getEffectiveEnvironment envOverrides maybeExit $ rawSystemIOWithEnv verbosity @@ -140,13 +134,11 @@ runProgramInvocation { progInvokePath = path , progInvokeArgs = args , progInvokeEnv = envOverrides - , progInvokePathEnv = extraPath , progInvokeCwd = mcwd , progInvokeInput = Just inputStr , progInvokeInputEncoding = encoding } = do - pathOverride <- getExtraPathEnv envOverrides extraPath - menv <- getEffectiveEnvironment (envOverrides ++ pathOverride) + menv <- getEffectiveEnvironment envOverrides (_, errors, exitCode) <- rawSystemStdInOut verbosity @@ -190,6 +182,13 @@ getProgramInvocationOutputAndErrors verbosity inv = case progInvokeOutputEncodin (output', errors, exitCode) <- getProgramInvocationIODataAndErrors verbosity inv IODataModeBinary return (normaliseLineEndings (fromUTF8LBS output'), errors, exitCode) +getProgramInvocationLBSAndErrors + :: Verbosity + -> ProgramInvocation + -> IO (LBS.ByteString, String, ExitCode) +getProgramInvocationLBSAndErrors verbosity inv = + getProgramInvocationIODataAndErrors verbosity inv IODataModeBinary + getProgramInvocationIODataAndErrors :: KnownIODataMode mode => Verbosity @@ -202,30 +201,16 @@ getProgramInvocationIODataAndErrors { progInvokePath = path , progInvokeArgs = args , progInvokeEnv = envOverrides - , progInvokePathEnv = extraPath , progInvokeCwd = mcwd , progInvokeInput = minputStr , progInvokeInputEncoding = encoding } mode = do - pathOverride <- getExtraPathEnv envOverrides extraPath - menv <- getEffectiveEnvironment (envOverrides ++ pathOverride) + menv <- getEffectiveEnvironment envOverrides rawSystemStdInOut verbosity path args mcwd menv input mode where input = encodeToIOData encoding <$> minputStr -getExtraPathEnv :: [(String, Maybe String)] -> [FilePath] -> IO [(String, Maybe String)] -getExtraPathEnv _ [] = return [] -getExtraPathEnv env extras = do - mb_path <- case lookup "PATH" env of - Just x -> return x - Nothing -> lookupEnv "PATH" - let extra = intercalate [searchPathSeparator] extras - path' = case mb_path of - Nothing -> extra - Just path -> extra ++ searchPathSeparator : path - return [("PATH", Just path')] - -- | Return the current environment extended with the given overrides. -- If an entry is specified twice in @overrides@, the second entry takes -- precedence. diff --git a/Cabal/src/Distribution/Simple/Program/Types.hs b/Cabal/src/Distribution/Simple/Program/Types.hs index 2186b23fc01..53105b6c9a3 100644 --- a/Cabal/src/Distribution/Simple/Program/Types.hs +++ b/Cabal/src/Distribution/Simple/Program/Types.hs @@ -24,7 +24,6 @@ module Distribution.Simple.Program.Types Program (..) , ProgramSearchPath , ProgramSearchPathEntry (..) - , simpleProgram -- * Configured program and related functions , ConfiguredProgram (..) @@ -39,7 +38,6 @@ import Distribution.Compat.Prelude import Prelude () import Distribution.PackageDescription -import Distribution.Simple.Program.Find import Distribution.Verbosity import Distribution.Version @@ -84,6 +82,36 @@ instance Show Program where type ProgArg = String +-- | A search path to use when locating executables. This is analogous +-- to the unix @$PATH@ or win32 @%PATH%@ but with the ability to use +-- the system default method for finding executables ('findExecutable' which +-- on unix is simply looking on the @$PATH@ but on win32 is a bit more +-- complicated). +-- +-- The default to use is @[ProgSearchPathDefault]@ but you can add extra dirs +-- either before, after or instead of the default, e.g. here we add an extra +-- dir to search after the usual ones. +-- +-- > ['ProgramSearchPathDefault', 'ProgramSearchPathDir' dir] +-- +-- We also use this path to set the environment when running child processes. +-- +-- The @ProgramDb@ is created with a @ProgramSearchPath@ to which we +-- @prependProgramSearchPath@ to add the ones that come from cli flags and from +-- configurations. Then each of the programs that are configured in the db +-- inherits the same path as part of @configureProgram@. +type ProgramSearchPath = [ProgramSearchPathEntry] + +data ProgramSearchPathEntry + = -- | A specific dir + ProgramSearchPathDir FilePath + | -- | The system default + ProgramSearchPathDefault + deriving (Eq, Generic, Typeable) + +instance Binary ProgramSearchPathEntry +instance Structured ProgramSearchPathEntry + -- | Represents a program which has been configured and is thus ready to be run. -- -- These are usually made by configuring a 'Program', but if you have to @@ -145,22 +173,6 @@ programPath = locationPath . programLocation suppressOverrideArgs :: ConfiguredProgram -> ConfiguredProgram suppressOverrideArgs prog = prog{programOverrideArgs = []} --- | Make a simple named program. --- --- By default we'll just search for it in the path and not try to find the --- version name. You can override these behaviours if necessary, eg: --- --- > (simpleProgram "foo") { programFindLocation = ... , programFindVersion ... } -simpleProgram :: String -> Program -simpleProgram name = - Program - { programName = name - , programFindLocation = \v p -> findProgramOnSearchPath v p name - , programFindVersion = \_ _ -> return Nothing - , programPostConf = \_ p -> return p - , programNormaliseArgs = \_ _ -> id - } - -- | Make a simple 'ConfiguredProgram'. -- -- > simpleConfiguredProgram "foo" (FoundOnSystem path) diff --git a/Cabal/src/Distribution/Simple/Setup.hs b/Cabal/src/Distribution/Simple/Setup.hs index b4d55d604ba..cd8f10aff3c 100644 --- a/Cabal/src/Distribution/Simple/Setup.hs +++ b/Cabal/src/Distribution/Simple/Setup.hs @@ -2,6 +2,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- @@ -131,9 +132,13 @@ module Distribution.Simple.Setup , trueArg , falseArg , optionVerbosity + , BuildingWhat (..) + , buildingWhatVerbosity + , buildingWhatDistPref ) where -import Prelude () +import GHC.Generics (Generic) +import Prelude (FilePath, Show, ($)) import Distribution.Simple.Flag import Distribution.Simple.InstallDirs @@ -154,6 +159,37 @@ import Distribution.Simple.Setup.Repl import Distribution.Simple.Setup.SDist import Distribution.Simple.Setup.Test +import Distribution.Verbosity (Verbosity) + +-- | What kind of build are we doing? +-- +-- Is this a normal build, or is it perhaps for running an interactive +-- session or Haddock? +data BuildingWhat + = -- | A normal build. + BuildNormal BuildFlags + | -- | Build steps for an interactive session. + BuildRepl ReplFlags + | -- | Build steps for generating documentation. + BuildHaddock HaddockFlags + | -- | Build steps for Hscolour. + BuildHscolour HscolourFlags + deriving (Generic, Show) + +buildingWhatVerbosity :: BuildingWhat -> Verbosity +buildingWhatVerbosity = \case + BuildNormal flags -> fromFlag $ buildVerbosity flags + BuildRepl flags -> fromFlag $ replVerbosity flags + BuildHaddock flags -> fromFlag $ haddockVerbosity flags + BuildHscolour flags -> fromFlag $ hscolourVerbosity flags + +buildingWhatDistPref :: BuildingWhat -> FilePath +buildingWhatDistPref = \case + BuildNormal flags -> fromFlag $ buildDistPref flags + BuildRepl flags -> fromFlag $ replDistPref flags + BuildHaddock flags -> fromFlag $ haddockDistPref flags + BuildHscolour flags -> fromFlag $ hscolourDistPref flags + -- The test cases kinda have to be rewritten from the ground up... :/ -- hunitTests :: [Test] -- hunitTests = diff --git a/Cabal/src/Distribution/Simple/Setup/Benchmark.hs b/Cabal/src/Distribution/Simple/Setup/Benchmark.hs index 3f657c22466..5eac60aee00 100644 --- a/Cabal/src/Distribution/Simple/Setup/Benchmark.hs +++ b/Cabal/src/Distribution/Simple/Setup/Benchmark.hs @@ -49,6 +49,9 @@ data BenchmarkFlags = BenchmarkFlags } deriving (Show, Generic, Typeable) +instance Binary BenchmarkFlags +instance Structured BenchmarkFlags + defaultBenchmarkFlags :: BenchmarkFlags defaultBenchmarkFlags = BenchmarkFlags diff --git a/Cabal/src/Distribution/Simple/Setup/Build.hs b/Cabal/src/Distribution/Simple/Setup/Build.hs index 434558ca546..aa1fa5e61ab 100644 --- a/Cabal/src/Distribution/Simple/Setup/Build.hs +++ b/Cabal/src/Distribution/Simple/Setup/Build.hs @@ -58,6 +58,9 @@ data BuildFlags = BuildFlags } deriving (Read, Show, Generic, Typeable) +instance Binary BuildFlags +instance Structured BuildFlags + defaultBuildFlags :: BuildFlags defaultBuildFlags = BuildFlags diff --git a/Cabal/src/Distribution/Simple/Setup/Clean.hs b/Cabal/src/Distribution/Simple/Setup/Clean.hs index b08a3cac75c..14cb65bae6e 100644 --- a/Cabal/src/Distribution/Simple/Setup/Clean.hs +++ b/Cabal/src/Distribution/Simple/Setup/Clean.hs @@ -47,6 +47,9 @@ data CleanFlags = CleanFlags } deriving (Show, Generic, Typeable) +instance Binary CleanFlags +instance Structured CleanFlags + defaultCleanFlags :: CleanFlags defaultCleanFlags = CleanFlags diff --git a/Cabal/src/Distribution/Simple/Setup/Config.hs b/Cabal/src/Distribution/Simple/Setup/Config.hs index f446eca9f74..148181a226c 100644 --- a/Cabal/src/Distribution/Simple/Setup/Config.hs +++ b/Cabal/src/Distribution/Simple/Setup/Config.hs @@ -54,6 +54,7 @@ import Distribution.Types.DumpBuildInfo import Distribution.Types.GivenComponent import Distribution.Types.Module import Distribution.Types.PackageVersionConstraint +import Distribution.Types.UnitId import Distribution.Utils.NubList import Distribution.Verbosity import qualified Text.PrettyPrint as Disp @@ -220,6 +221,11 @@ data ConfigFlags = ConfigFlags -- ^ Allow depending on private sublibraries. This is used by external -- tools (like cabal-install) so they can add multiple-public-libraries -- compatibility to older ghcs by checking visibility externally. + , configCoverageFor :: Flag [UnitId] + -- ^ The list of libraries to be included in the hpc coverage report for + -- testsuites run with @--enable-coverage@. Notably, this list must exclude + -- indefinite libraries and instantiations because HPC does not support + -- backpack (Nov. 2023). } deriving (Generic, Read, Show, Typeable) @@ -288,6 +294,7 @@ instance Eq ConfigFlags where && equal configDebugInfo && equal configDumpBuildInfo && equal configUseResponseFiles + && equal configCoverageFor where equal f = on (==) f a b @@ -828,6 +835,22 @@ configureOptions showOrParseArgs = configAllowDependingOnPrivateLibs (\v flags -> flags{configAllowDependingOnPrivateLibs = v}) trueArg + , option + "" + ["coverage-for"] + "A list of unit-ids of libraries to include in the Haskell Program Coverage report." + configCoverageFor + ( \v flags -> + flags + { configCoverageFor = + mergeListFlag (configCoverageFor flags) v + } + ) + ( reqArg' + "UNITID" + (Flag . (: []) . fromString) + (fmap prettyShow . fromFlagOrDefault []) + ) ] where liftInstallDirs = diff --git a/Cabal/src/Distribution/Simple/Setup/Copy.hs b/Cabal/src/Distribution/Simple/Setup/Copy.hs index 56416ddae5d..466263ffedb 100644 --- a/Cabal/src/Distribution/Simple/Setup/Copy.hs +++ b/Cabal/src/Distribution/Simple/Setup/Copy.hs @@ -55,6 +55,9 @@ data CopyFlags = CopyFlags } deriving (Show, Generic) +instance Binary CopyFlags +instance Structured CopyFlags + defaultCopyFlags :: CopyFlags defaultCopyFlags = CopyFlags diff --git a/Cabal/src/Distribution/Simple/Setup/Haddock.hs b/Cabal/src/Distribution/Simple/Setup/Haddock.hs index 3efc6640bd2..f332a958d08 100644 --- a/Cabal/src/Distribution/Simple/Setup/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Setup/Haddock.hs @@ -109,6 +109,9 @@ data HaddockFlags = HaddockFlags } deriving (Show, Generic, Typeable) +instance Binary HaddockFlags +instance Structured HaddockFlags + defaultHaddockFlags :: HaddockFlags defaultHaddockFlags = HaddockFlags @@ -445,10 +448,10 @@ haddockProjectCommand = { commandName = "v2-haddock-project" , commandSynopsis = "Generate Haddocks HTML documentation for the cabal project." , commandDescription = Just $ \_ -> - "Require the programm haddock, version 2.26.\n" + "Requires the program haddock, version 2.26.\n" , commandNotes = Nothing , commandUsage = - usageAlternatives "haddocks" $ + usageAlternatives "haddock-project" $ [ "[FLAGS]" , "COMPONENTS [FLAGS]" ] diff --git a/Cabal/src/Distribution/Simple/Setup/Hscolour.hs b/Cabal/src/Distribution/Simple/Setup/Hscolour.hs index 6b5e2761133..443be76c5d5 100644 --- a/Cabal/src/Distribution/Simple/Setup/Hscolour.hs +++ b/Cabal/src/Distribution/Simple/Setup/Hscolour.hs @@ -51,6 +51,9 @@ data HscolourFlags = HscolourFlags } deriving (Show, Generic, Typeable) +instance Binary HscolourFlags +instance Structured HscolourFlags + emptyHscolourFlags :: HscolourFlags emptyHscolourFlags = mempty diff --git a/Cabal/src/Distribution/Simple/Setup/Repl.hs b/Cabal/src/Distribution/Simple/Setup/Repl.hs index 19c75836366..2fae5bffcd4 100644 --- a/Cabal/src/Distribution/Simple/Setup/Repl.hs +++ b/Cabal/src/Distribution/Simple/Setup/Repl.hs @@ -70,6 +70,9 @@ data ReplFlags = ReplFlags } deriving (Show, Generic, Typeable) +instance Binary ReplFlags +instance Structured ReplFlags + defaultReplFlags :: ReplFlags defaultReplFlags = ReplFlags diff --git a/Cabal/src/Distribution/Simple/Setup/Test.hs b/Cabal/src/Distribution/Simple/Setup/Test.hs index bee0ccbef1a..12501c791b8 100644 --- a/Cabal/src/Distribution/Simple/Setup/Test.hs +++ b/Cabal/src/Distribution/Simple/Setup/Test.hs @@ -93,6 +93,9 @@ data TestFlags = TestFlags } deriving (Show, Generic, Typeable) +instance Binary TestFlags +instance Structured TestFlags + defaultTestFlags :: TestFlags defaultTestFlags = TestFlags diff --git a/Cabal/src/Distribution/Simple/SrcDist.hs b/Cabal/src/Distribution/Simple/SrcDist.hs index 706d3b51e35..90250290fc1 100644 --- a/Cabal/src/Distribution/Simple/SrcDist.hs +++ b/Cabal/src/Distribution/Simple/SrcDist.hs @@ -245,12 +245,13 @@ listPackageSources' verbosity rip cwd pkg_descr pps = , -- Data files. fmap concat . for (dataFiles pkg_descr) - $ \filename -> do - let srcDataDirRaw = dataDir pkg_descr - srcDataDir - | null srcDataDirRaw = "." - | otherwise = srcDataDirRaw - matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) cwd (srcDataDir filename) + $ \filename -> + do + let srcDataDirRaw = dataDir pkg_descr + srcDataDir + | null srcDataDirRaw = "." + | otherwise = srcDataDirRaw + matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) cwd (srcDataDir filename) , -- Extra source files. fmap concat . for (extraSrcFiles pkg_descr) $ \fpath -> matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) cwd fpath @@ -521,7 +522,7 @@ allSourcesBuildInfo verbosity rip cwd bi pps modules = do bootFiles <- sequenceA [ let file = ModuleName.toFilePath module_ - fileExts = ["hs-boot", "lhs-boot"] + fileExts = builtinHaskellBootSuffixes in findFileCwdWithExtension cwd fileExts (map getSymbolicPath (hsSourceDirs bi)) file | module_ <- modules ++ otherModules bi ] @@ -539,7 +540,7 @@ allSourcesBuildInfo verbosity rip cwd bi pps modules = do nonEmpty' x _ [] = x nonEmpty' _ f xs = f xs - suffixes = ppSuffixes pps ++ ["hs", "lhs", "hsig", "lhsig"] + suffixes = ppSuffixes pps ++ builtinHaskellSuffixes notFound :: ModuleName -> IO [FilePath] notFound m = diff --git a/Cabal/src/Distribution/Simple/Test.hs b/Cabal/src/Distribution/Simple/Test.hs index 7cb695cabaf..3c033dd979b 100644 --- a/Cabal/src/Distribution/Simple/Test.hs +++ b/Cabal/src/Distribution/Simple/Test.hs @@ -1,5 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -38,7 +40,15 @@ import Distribution.TestSuite import qualified Distribution.Types.LocalBuildInfo as LBI import Distribution.Types.UnqualComponentName +import Distribution.Simple.Configure (getInstalledPackagesById) import Distribution.Simple.Errors +import Distribution.Simple.Register +import Distribution.Simple.Setup (fromFlagOrDefault) +import Distribution.Simple.Setup.Common (extraCompilationArtifacts) +import Distribution.Simple.Setup.Config +import Distribution.Types.ExposedModule +import Distribution.Types.InstalledPackageInfo (InstalledPackageInfo (libraryDirs), exposedModules) +import Distribution.Types.LocalBuildInfo (LocalBuildInfo (..)) import System.Directory ( createDirectoryIfMissing , doesFileExist @@ -58,7 +68,7 @@ test -> TestFlags -- ^ flags sent to test -> IO () -test args pkg_descr lbi flags = do +test args pkg_descr lbi0 flags = do let verbosity = fromFlag $ testVerbosity flags machineTemplate = fromFlag $ testMachineLog flags distPref = fromFlag $ testDistPref flags @@ -66,18 +76,23 @@ test args pkg_descr lbi flags = do testNames = args pkgTests = PD.testSuites pkg_descr enabledTests = LBI.enabledTestLBIs pkg_descr lbi + -- We must add the internalPkgDB to the package database stack to lookup + -- the path to HPC dirs of libraries local to this package + internalPkgDB = internalPackageDBPath lbi distPref + lbi = lbi0{withPackageDB = withPackageDB lbi0 ++ [SpecificPackageDB internalPkgDB]} doTest - :: ( (PD.TestSuite, LBI.ComponentLocalBuildInfo) + :: HPCMarkupInfo + -> ( (PD.TestSuite, LBI.ComponentLocalBuildInfo) , Maybe TestSuiteLog ) -> IO TestSuiteLog - doTest ((suite, clbi), _) = + doTest hpcMarkupInfo ((suite, clbi), _) = case PD.testInterface suite of PD.TestSuiteExeV10 _ _ -> - ExeV10.runTest pkg_descr lbi clbi flags suite + ExeV10.runTest pkg_descr lbi clbi hpcMarkupInfo flags suite PD.TestSuiteLibV09 _ _ -> - LibV09.runTest pkg_descr lbi clbi flags suite + LibV09.runTest pkg_descr lbi clbi hpcMarkupInfo flags suite _ -> return TestSuiteLog @@ -122,9 +137,33 @@ test args pkg_descr lbi flags = do >>= filterM doesFileExist . map (testLogDir ) >>= traverse_ removeFile + -- We configured the unit-ids of libraries we should cover in our coverage + -- report at configure time into the local build info. At build time, we built + -- the hpc artifacts into the extraCompilationArtifacts directory, which, at + -- install time, is copied into the ghc-pkg database files. + -- Now, we get the path to the HPC artifacts and exposed modules of each + -- library by querying the package database keyed by unit-id: + let coverageFor = + nub $ + fromFlagOrDefault [] (configCoverageFor (configFlags lbi)) + <> extraCoverageFor lbi + ipkginfos <- getInstalledPackagesById verbosity lbi MissingCoveredInstalledLibrary coverageFor + let ( concat -> pathsToLibsArtifacts + , concat -> libsModulesToInclude + ) = + unzip $ + map + ( \ip -> + ( map ( extraCompilationArtifacts) $ libraryDirs ip + , map exposedName $ exposedModules ip + ) + ) + ipkginfos + hpcMarkupInfo = HPCMarkupInfo{pathsToLibsArtifacts, libsModulesToInclude} + let totalSuites = length testsToRun notice verbosity $ "Running " ++ show totalSuites ++ " test suites..." - suites <- traverse doTest testsToRun + suites <- traverse (doTest hpcMarkupInfo) testsToRun let packageLog = (localPackageLog pkg_descr lbi){testSuites = suites} packageLogFile = () testLogDir $ @@ -133,7 +172,7 @@ test args pkg_descr lbi flags = do writeFile packageLogFile $ show packageLog when (LBI.testCoverage lbi) $ - markupPackage verbosity lbi distPref pkg_descr $ + markupPackage verbosity hpcMarkupInfo lbi distPref pkg_descr $ map (fst . fst) testsToRun unless allOk exitFailure diff --git a/Cabal/src/Distribution/Simple/Test/ExeV10.hs b/Cabal/src/Distribution/Simple/Test/ExeV10.hs index 04c7e30073a..af7a896d841 100644 --- a/Cabal/src/Distribution/Simple/Test/ExeV10.hs +++ b/Cabal/src/Distribution/Simple/Test/ExeV10.hs @@ -10,7 +10,6 @@ import Prelude () import Distribution.Compat.Environment import qualified Distribution.PackageDescription as PD -import Distribution.Pretty import Distribution.Simple.Build.PathsModule import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler @@ -18,12 +17,20 @@ import Distribution.Simple.Flag import Distribution.Simple.Hpc import Distribution.Simple.InstallDirs import qualified Distribution.Simple.LocalBuildInfo as LBI + ( ComponentLocalBuildInfo (..) + , buildDir + , depLibraryPaths + ) import Distribution.Simple.Setup.Test import Distribution.Simple.Test.Log import Distribution.Simple.Utils import Distribution.System import Distribution.TestSuite import qualified Distribution.Types.LocalBuildInfo as LBI + ( LocalBuildInfo (..) + , localUnitId + , testCoverage + ) import Distribution.Types.UnqualComponentName import Distribution.Verbosity @@ -45,13 +52,14 @@ runTest :: PD.PackageDescription -> LBI.LocalBuildInfo -> LBI.ComponentLocalBuildInfo + -> HPCMarkupInfo -> TestFlags -> PD.TestSuite -> IO TestSuiteLog -runTest pkg_descr lbi clbi flags suite = do +runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do let isCoverageEnabled = LBI.testCoverage lbi way = guessWay lbi - tixDir_ = tixDir distPref way testName' + tixDir_ = tixDir distPref way pwd <- getCurrentDirectory existingEnv <- getEnvironment @@ -170,12 +178,16 @@ runTest pkg_descr lbi clbi flags suite = do -- Write summary notice to terminal indicating end of test suite notice verbosity $ summarizeSuiteFinish suiteLog - when isCoverageEnabled $ - case PD.library pkg_descr of - Nothing -> - dieWithException verbosity TestCoverageSupport - Just library -> - markupTest verbosity lbi distPref (prettyShow $ PD.package pkg_descr) suite library + when isCoverageEnabled $ do + -- Until #9493 is fixed, we expect cabal-install to pass one dist dir per + -- library and there being at least one library in the package with the + -- testsuite. When it is fixed, we can remove this predicate and allow a + -- testsuite without a library to cover libraries in other packages of the + -- same project + when (null $ PD.allLibraries pkg_descr) $ + dieWithException verbosity TestCoverageSupport + + markupPackage verbosity hpcMarkupInfo lbi distPref pkg_descr [suite] return suiteLog where diff --git a/Cabal/src/Distribution/Simple/Test/LibV09.hs b/Cabal/src/Distribution/Simple/Test/LibV09.hs index b87897bfed7..f5a6ec2ce18 100644 --- a/Cabal/src/Distribution/Simple/Test/LibV09.hs +++ b/Cabal/src/Distribution/Simple/Test/LibV09.hs @@ -58,10 +58,11 @@ runTest :: PD.PackageDescription -> LBI.LocalBuildInfo -> LBI.ComponentLocalBuildInfo + -> HPCMarkupInfo -> TestFlags -> PD.TestSuite -> IO TestSuiteLog -runTest pkg_descr lbi clbi flags suite = do +runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do let isCoverageEnabled = LBI.testCoverage lbi way = guessWay lbi @@ -80,12 +81,12 @@ runTest pkg_descr lbi clbi flags suite = do -- Remove old .tix files if appropriate. unless (fromFlag $ testKeepTix flags) $ do - let tDir = tixDir distPref way testName' + let tDir = tixDir distPref way exists' <- doesDirectoryExist tDir when exists' $ removeDirectoryRecursive tDir -- Create directory for HPC files. - createDirectoryIfMissing True $ tixDir distPref way testName' + createDirectoryIfMissing True $ tixDir distPref way -- Write summary notices indicating start of test suite notice verbosity $ summarizeSuiteStart testName' @@ -185,12 +186,16 @@ runTest pkg_descr lbi clbi flags suite = do -- Write summary notice to terminal indicating end of test suite notice verbosity $ summarizeSuiteFinish suiteLog - when isCoverageEnabled $ - case PD.library pkg_descr of - Nothing -> - dieWithException verbosity TestCoverageSupportLibV09 - Just library -> - markupTest verbosity lbi distPref (prettyShow $ PD.package pkg_descr) suite library + when isCoverageEnabled $ do + -- Until #9493 is fixed, we expect cabal-install to pass one dist dir per + -- library and there being at least one library in the package with the + -- testsuite. When it is fixed, we can remove this predicate and allow a + -- testsuite without a library to cover libraries in other packages of the + -- same project + when (null $ PD.allLibraries pkg_descr) $ + dieWithException verbosity TestCoverageSupport + + markupPackage verbosity hpcMarkupInfo lbi distPref pkg_descr [suite] return suiteLog where diff --git a/Cabal/src/Distribution/Simple/Utils.hs b/Cabal/src/Distribution/Simple/Utils.hs index f05957bc271..1da133ca4c4 100644 --- a/Cabal/src/Distribution/Simple/Utils.hs +++ b/Cabal/src/Distribution/Simple/Utils.hs @@ -201,6 +201,7 @@ import Distribution.Compat.Prelude import Distribution.Compat.Stack import Distribution.ModuleName as ModuleName import Distribution.Simple.Errors +import Distribution.Simple.PreProcess.Types import Distribution.System import Distribution.Types.PackageId import Distribution.Utils.Generic @@ -1198,7 +1199,7 @@ findFileCwd verbosity cwd searchPath fileName = findFirstFile (cwd ) [ path fileName - | path <- nub searchPath + | path <- ordNub searchPath ] >>= maybe (dieWithException verbosity $ FindFileCwd fileName) return @@ -1214,7 +1215,7 @@ findFileEx verbosity searchPath fileName = findFirstFile id [ path fileName - | path <- nub searchPath + | path <- ordNub searchPath ] >>= maybe (dieWithException verbosity $ FindFileEx fileName) return @@ -1222,7 +1223,7 @@ findFileEx verbosity searchPath fileName = -- file extensions. The file base name should be given and it will be tried -- with each of the extensions in each element of the search path. findFileWithExtension - :: [String] + :: [Suffix] -> [FilePath] -> FilePath -> IO (Maybe FilePath) @@ -1230,14 +1231,14 @@ findFileWithExtension extensions searchPath baseName = findFirstFile id [ path baseName <.> ext - | path <- nub searchPath - , ext <- nub extensions + | path <- ordNub searchPath + , Suffix ext <- ordNub extensions ] -- | @since 3.4.0.0 findFileCwdWithExtension :: FilePath - -> [String] + -> [Suffix] -> [FilePath] -> FilePath -> IO (Maybe FilePath) @@ -1245,15 +1246,15 @@ findFileCwdWithExtension cwd extensions searchPath baseName = findFirstFile (cwd ) [ path baseName <.> ext - | path <- nub searchPath - , ext <- nub extensions + | path <- ordNub searchPath + , Suffix ext <- ordNub extensions ] -- | @since 3.4.0.0 findAllFilesCwdWithExtension :: FilePath -- ^ cwd - -> [String] + -> [Suffix] -- ^ extensions -> [FilePath] -- ^ relative search locations @@ -1264,12 +1265,12 @@ findAllFilesCwdWithExtension cwd extensions searchPath basename = findAllFiles (cwd ) [ path basename <.> ext - | path <- nub searchPath - , ext <- nub extensions + | path <- ordNub searchPath + , Suffix ext <- ordNub extensions ] findAllFilesWithExtension - :: [String] + :: [Suffix] -> [FilePath] -> FilePath -> IO [FilePath] @@ -1277,14 +1278,14 @@ findAllFilesWithExtension extensions searchPath basename = findAllFiles id [ path basename <.> ext - | path <- nub searchPath - , ext <- nub extensions + | path <- ordNub searchPath + , Suffix ext <- ordNub extensions ] -- | Like 'findFileWithExtension' but returns which element of the search path -- the file was found in, and the file path relative to that base directory. findFileWithExtension' - :: [String] + :: [Suffix] -> [FilePath] -> FilePath -> IO (Maybe (FilePath, FilePath)) @@ -1292,8 +1293,8 @@ findFileWithExtension' extensions searchPath baseName = findFirstFile (uncurry ()) [ (path, baseName <.> ext) - | path <- nub searchPath - , ext <- nub extensions + | path <- ordNub searchPath + , Suffix ext <- ordNub extensions ] findFirstFile :: (a -> FilePath) -> [a] -> IO (Maybe a) @@ -1316,7 +1317,7 @@ findModuleFilesEx :: Verbosity -> [FilePath] -- ^ build prefix (location of objects) - -> [String] + -> [Suffix] -- ^ search suffixes -> [ModuleName] -- ^ modules @@ -1332,7 +1333,7 @@ findModuleFileEx :: Verbosity -> [FilePath] -- ^ build prefix (location of objects) - -> [String] + -> [Suffix] -- ^ search suffixes -> ModuleName -- ^ module @@ -1535,7 +1536,7 @@ copyFilesWith -> IO () copyFilesWith doCopy verbosity targetDir srcFiles = withFrozenCallStack $ do -- Create parent directories for everything - let dirs = map (targetDir ) . nub . map (takeDirectory . snd) $ srcFiles + let dirs = map (targetDir ) . ordNub . map (takeDirectory . snd) $ srcFiles traverse_ (createDirectoryIfMissingVerbose verbosity True) dirs -- Copy all the files diff --git a/Cabal/src/Distribution/Types/LocalBuildConfig.hs b/Cabal/src/Distribution/Types/LocalBuildConfig.hs new file mode 100644 index 00000000000..4423a77410d --- /dev/null +++ b/Cabal/src/Distribution/Types/LocalBuildConfig.hs @@ -0,0 +1,226 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} + +module Distribution.Types.LocalBuildConfig + ( -- * The types + PackageBuildDescr (..) + , ComponentBuildDescr (..) + , LocalBuildDescr (..) + , LocalBuildConfig (..) + , BuildOptions (..) + + -- * Conversion functions + , buildOptionsConfigFlags + ) where + +import Distribution.Compat.Prelude +import Prelude () + +import Distribution.Types.ComponentId +import Distribution.Types.ComponentLocalBuildInfo +import Distribution.Types.ComponentRequestedSpec +import Distribution.Types.PackageDescription +import Distribution.Types.UnitId + +import Distribution.PackageDescription +import Distribution.Simple.Compiler +import Distribution.Simple.Flag +import Distribution.Simple.InstallDirs hiding + ( absoluteInstallDirs + , prefixRelativeInstallDirs + , substPathTemplate + ) +import Distribution.Simple.PackageIndex +import Distribution.Simple.Program +import Distribution.Simple.Setup.Config +import Distribution.System + +import Distribution.Compat.Graph (Graph) + +-- | 'PackageBuildDescr' contains the information Cabal determines after +-- performing package-wide configuration of a package, before doing any +-- per-component configuration. +data PackageBuildDescr = PackageBuildDescr + { configFlags :: ConfigFlags + -- ^ Options passed to the configuration step. + -- Needed to re-run configuration when .cabal is out of date + , flagAssignment :: FlagAssignment + -- ^ The final set of flags which were picked for this package + , componentEnabledSpec :: ComponentRequestedSpec + -- ^ What components were enabled during configuration, and why. + , compiler :: Compiler + -- ^ The compiler we're building with + , hostPlatform :: Platform + -- ^ The platform we're building for + , pkgDescrFile :: Maybe FilePath + -- ^ the filename containing the .cabal file, if available + , localPkgDescr :: PackageDescription + -- ^ WARNING WARNING WARNING Be VERY careful about using + -- this function; we haven't deprecated it but using it + -- could introduce subtle bugs related to + -- 'HookedBuildInfo'. + -- + -- In principle, this is supposed to contain the + -- resolved package description, that does not contain + -- any conditionals. However, it MAY NOT contain + -- the description with a 'HookedBuildInfo' applied + -- to it; see 'HookedBuildInfo' for the whole sordid saga. + -- As much as possible, Cabal library should avoid using + -- this parameter. + , installDirTemplates :: InstallDirTemplates + -- ^ The installation directories for the various different + -- kinds of files + -- TODO: inplaceDirTemplates :: InstallDirs FilePath + , withPackageDB :: PackageDBStack + -- ^ What package database to use, global\/user + , extraCoverageFor :: [UnitId] + -- ^ For per-package builds-only: an extra list of libraries to be included in + -- the hpc coverage report for testsuites run with @--enable-coverage@. + -- Notably, this list must exclude indefinite libraries and instantiations + -- because HPC does not support backpack (Nov. 2023). + } + deriving (Generic, Read, Show) + +-- | Information about individual components in a package, +-- determined after the configure step. +data ComponentBuildDescr = ComponentBuildDescr + { componentGraph :: Graph ComponentLocalBuildInfo + -- ^ All the components to build, ordered by topological + -- sort, and with their INTERNAL dependencies over the + -- intrapackage dependency graph. + -- TODO: this is assumed to be short; otherwise we want + -- some sort of ordered map. + , componentNameMap :: Map ComponentName [ComponentLocalBuildInfo] + -- ^ A map from component name to all matching + -- components. These coincide with 'componentGraph' + -- There may be more than one matching component because of backpack instantiations + , promisedPkgs :: Map (PackageName, ComponentName) ComponentId + -- ^ The packages we were promised, but aren't already installed. + -- MP: Perhaps this just needs to be a Set UnitId at this stage. + , installedPkgs :: InstalledPackageIndex + -- ^ All the info about the installed packages that the + -- current package depends on (directly or indirectly). + -- The copy saved on disk does NOT include internal + -- dependencies (because we just don't have enough + -- information at this point to have an + -- 'InstalledPackageInfo' for an internal dep), but we + -- will often update it with the internal dependencies; + -- see for example 'Distribution.Simple.Build.build'. + -- (This admonition doesn't apply for per-component builds.) + } + deriving (Generic, Read, Show) + +-- | 'LocalBuildDescr ' contains the information Cabal determines after +-- performing package-wide and per-component configuration of a package. +-- +-- This information can no longer be changed after that point. +data LocalBuildDescr = LocalBuildDescr + { packageBuildDescr :: PackageBuildDescr + -- ^ Information that is available after configuring the package itself, + -- before looking at individual components. + , componentBuildDescr :: ComponentBuildDescr + -- ^ Information about individual components in the package + -- determined after the configure step. + } + deriving (Generic, Read, Show) + +-- | 'LocalBuildConfig' contains options that can be controlled +-- by the user and serve as inputs to the configuration of a package. +data LocalBuildConfig = LocalBuildConfig + { extraConfigArgs :: [String] + -- ^ Extra args on the command line for the configuration step. + -- Needed to re-run configuration when .cabal is out of date + , withPrograms :: ProgramDb + -- ^ Location and args for all programs + , withBuildOptions :: BuildOptions + -- ^ Options to control the build, e.g. whether to + -- enable profiling or to enable program coverage. + } + deriving (Generic, Read, Show) + +-- | 'BuildOptions' contains configuration options that can be controlled +-- by the user. +data BuildOptions = BuildOptions + { withVanillaLib :: Bool + -- ^ Whether to build normal libs. + , withProfLib :: Bool + -- ^ Whether to build profiling versions of libs. + , withSharedLib :: Bool + -- ^ Whether to build shared versions of libs. + , withStaticLib :: Bool + -- ^ Whether to build static versions of libs (with all other libs rolled in) + , withDynExe :: Bool + -- ^ Whether to link executables dynamically + , withFullyStaticExe :: Bool + -- ^ Whether to link executables fully statically + , withProfExe :: Bool + -- ^ Whether to build executables for profiling. + , withProfLibDetail :: ProfDetailLevel + -- ^ Level of automatic profile detail. + , withProfExeDetail :: ProfDetailLevel + -- ^ Level of automatic profile detail. + , withOptimization :: OptimisationLevel + -- ^ Whether to build with optimization (if available). + , withDebugInfo :: DebugInfoLevel + -- ^ Whether to emit debug info (if available). + , withGHCiLib :: Bool + -- ^ Whether to build libs suitable for use with GHCi. + , splitSections :: Bool + -- ^ Use -split-sections with GHC, if available + , splitObjs :: Bool + -- ^ Use -split-objs with GHC, if available + , stripExes :: Bool + -- ^ Whether to strip executables during install + , stripLibs :: Bool + -- ^ Whether to strip libraries during install + , exeCoverage :: Bool + -- ^ Whether to enable executable program coverage + , libCoverage :: Bool + -- ^ Whether to enable library program coverage + , relocatable :: Bool + -- ^ Whether to build a relocatable package + } + deriving (Eq, Generic, Read, Show) + +instance Binary PackageBuildDescr +instance Structured PackageBuildDescr +instance Binary ComponentBuildDescr +instance Structured ComponentBuildDescr +instance Binary LocalBuildDescr +instance Structured LocalBuildDescr +instance Binary LocalBuildConfig +instance Structured LocalBuildConfig +instance Binary BuildOptions +instance Structured BuildOptions + +buildOptionsConfigFlags :: BuildOptions -> ConfigFlags +buildOptionsConfigFlags (BuildOptions{..}) = + mempty + { configVanillaLib = toFlag $ withVanillaLib + , configSharedLib = toFlag $ withSharedLib + , configStaticLib = toFlag $ withStaticLib + , configDynExe = toFlag $ withDynExe + , configFullyStaticExe = toFlag $ withFullyStaticExe + , configGHCiLib = toFlag $ withGHCiLib + , configProfExe = toFlag $ withProfExe + , configProfLib = toFlag $ withProfLib + , configProf = mempty + , -- configProfDetail is for exe+lib, but overridden by configProfLibDetail + -- so we specify both so we can specify independently + configProfDetail = toFlag $ withProfExeDetail + , configProfLibDetail = toFlag $ withProfLibDetail + , configCoverage = toFlag $ exeCoverage + , configLibCoverage = mempty + , configRelocatable = toFlag $ relocatable + , configOptimization = toFlag $ withOptimization + , configSplitSections = toFlag $ splitSections + , configSplitObjs = toFlag $ splitObjs + , configStripExes = toFlag $ stripExes + , configStripLibs = toFlag $ stripLibs + , configDebugInfo = toFlag $ withDebugInfo + } diff --git a/Cabal/src/Distribution/Types/LocalBuildInfo.hs b/Cabal/src/Distribution/Types/LocalBuildInfo.hs index 116d5db264e..1c3aeef0161 100644 --- a/Cabal/src/Distribution/Types/LocalBuildInfo.hs +++ b/Cabal/src/Distribution/Types/LocalBuildInfo.hs @@ -1,17 +1,64 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-} module Distribution.Types.LocalBuildInfo - ( -- * The type - LocalBuildInfo (..) + ( -- * The types + LocalBuildInfo + ( LocalBuildInfo + , configFlags + , flagAssignment + , componentEnabledSpec + , extraConfigArgs + , installDirTemplates + , compiler + , hostPlatform + , pkgDescrFile + , componentGraph + , componentNameMap + , promisedPkgs + , installedPkgs + , localPkgDescr + , withPrograms + , withPackageDB + , withVanillaLib + , withProfLib + , withSharedLib + , withStaticLib + , withDynExe + , withFullyStaticExe + , withProfExe + , withProfLibDetail + , withProfExeDetail + , withOptimization + , withDebugInfo + , withGHCiLib + , splitSections + , splitObjs + , stripExes + , stripLibs + , exeCoverage + , libCoverage + , extraCoverageFor + , relocatable + , .. + ) -- * Convenience accessors , localComponentId , localUnitId , localCompatPackageKey , localPackage + , buildDir + , buildDirPBD + , configFlagsBuildDir + , cabalFilePath + , progPrefix + , progSuffix -- * Build targets of the 'LocalBuildInfo'. , componentNameCLBIs @@ -52,6 +99,7 @@ import Prelude () import Distribution.Types.ComponentId import Distribution.Types.ComponentLocalBuildInfo import Distribution.Types.ComponentRequestedSpec +import qualified Distribution.Types.LocalBuildConfig as LBC import Distribution.Types.PackageDescription import Distribution.Types.PackageId import Distribution.Types.TargetInfo @@ -60,6 +108,7 @@ import Distribution.Types.UnitId import Distribution.PackageDescription import Distribution.Pretty import Distribution.Simple.Compiler +import Distribution.Simple.Flag import Distribution.Simple.InstallDirs hiding ( absoluteInstallDirs , prefixRelativeInstallDirs @@ -73,123 +122,178 @@ import Distribution.System import qualified Data.Map as Map import Distribution.Compat.Graph (Graph) import qualified Distribution.Compat.Graph as Graph +import System.FilePath (()) -- | Data cached after configuration step. See also -- 'Distribution.Simple.Setup.ConfigFlags'. -data LocalBuildInfo = LocalBuildInfo - { configFlags :: ConfigFlags - -- ^ Options passed to the configuration step. - -- Needed to re-run configuration when .cabal is out of date - , flagAssignment :: FlagAssignment - -- ^ The final set of flags which were picked for this package - , componentEnabledSpec :: ComponentRequestedSpec - -- ^ What components were enabled during configuration, and why. - , extraConfigArgs :: [String] - -- ^ Extra args on the command line for the configuration step. - -- Needed to re-run configuration when .cabal is out of date - , installDirTemplates :: InstallDirTemplates - -- ^ The installation directories for the various different - -- kinds of files - -- TODO: inplaceDirTemplates :: InstallDirs FilePath - , compiler :: Compiler - -- ^ The compiler we're building with - , hostPlatform :: Platform - -- ^ The platform we're building for - , buildDir :: FilePath - -- ^ Where to build the package. - , cabalFilePath :: Maybe FilePath - -- ^ Path to the cabal file, if given during configuration. - , componentGraph :: Graph ComponentLocalBuildInfo - -- ^ All the components to build, ordered by topological - -- sort, and with their INTERNAL dependencies over the - -- intrapackage dependency graph. - -- TODO: this is assumed to be short; otherwise we want - -- some sort of ordered map. - , componentNameMap :: Map ComponentName [ComponentLocalBuildInfo] - -- ^ A map from component name to all matching - -- components. These coincide with 'componentGraph' - , promisedPkgs :: Map (PackageName, ComponentName) ComponentId - -- ^ The packages we were promised, but aren't already installed. - -- MP: Perhaps this just needs to be a Set UnitId at this stage. - , installedPkgs :: InstalledPackageIndex - -- ^ All the info about the installed packages that the - -- current package depends on (directly or indirectly). - -- The copy saved on disk does NOT include internal - -- dependencies (because we just don't have enough - -- information at this point to have an - -- 'InstalledPackageInfo' for an internal dep), but we - -- will often update it with the internal dependencies; - -- see for example 'Distribution.Simple.Build.build'. - -- (This admonition doesn't apply for per-component builds.) - , pkgDescrFile :: Maybe FilePath - -- ^ the filename containing the .cabal file, if available - , localPkgDescr :: PackageDescription - -- ^ WARNING WARNING WARNING Be VERY careful about using - -- this function; we haven't deprecated it but using it - -- could introduce subtle bugs related to - -- 'HookedBuildInfo'. - -- - -- In principle, this is supposed to contain the - -- resolved package description, that does not contain - -- any conditionals. However, it MAY NOT contain - -- the description with a 'HookedBuildInfo' applied - -- to it; see 'HookedBuildInfo' for the whole sordid saga. - -- As much as possible, Cabal library should avoid using - -- this parameter. - , withPrograms :: ProgramDb - -- ^ Location and args for all programs - , withPackageDB :: PackageDBStack - -- ^ What package database to use, global\/user - , withVanillaLib :: Bool - -- ^ Whether to build normal libs. - , withProfLib :: Bool - -- ^ Whether to build profiling versions of libs. - , withSharedLib :: Bool - -- ^ Whether to build shared versions of libs. - , withStaticLib :: Bool - -- ^ Whether to build static versions of libs (with all other libs rolled in) - , withDynExe :: Bool - -- ^ Whether to link executables dynamically - , withFullyStaticExe :: Bool - -- ^ Whether to link executables fully statically - , withProfExe :: Bool - -- ^ Whether to build executables for profiling. - , withProfLibDetail :: ProfDetailLevel - -- ^ Level of automatic profile detail. - , withProfExeDetail :: ProfDetailLevel - -- ^ Level of automatic profile detail. - , withOptimization :: OptimisationLevel - -- ^ Whether to build with optimization (if available). - , withDebugInfo :: DebugInfoLevel - -- ^ Whether to emit debug info (if available). - , withGHCiLib :: Bool - -- ^ Whether to build libs suitable for use with GHCi. - , splitSections :: Bool - -- ^ Use -split-sections with GHC, if available - , splitObjs :: Bool - -- ^ Use -split-objs with GHC, if available - , stripExes :: Bool - -- ^ Whether to strip executables during install - , stripLibs :: Bool - -- ^ Whether to strip libraries during install - , exeCoverage :: Bool - -- ^ Whether to enable executable program coverage - , libCoverage :: Bool - -- ^ Whether to enable library program coverage - , progPrefix :: PathTemplate - -- ^ Prefix to be prepended to installed executables - , progSuffix :: PathTemplate - -- ^ Suffix to be appended to installed executables - , relocatable :: Bool -- ^Whether to build a relocatable package +data LocalBuildInfo = NewLocalBuildInfo + { localBuildDescr :: LBC.LocalBuildDescr + -- ^ Information about a package determined by Cabal + -- after the configuration step. + , localBuildConfig :: LBC.LocalBuildConfig + -- ^ Information about a package configuration + -- that can be modified by the user at configuration time. } deriving (Generic, Read, Show, Typeable) +{-# COMPLETE LocalBuildInfo #-} + +-- | This pattern synonym is for backwards compatibility, to adapt +-- to 'LocalBuildInfo' being split into 'LocalBuildDescr' and 'LocalBuildConfig'. +pattern LocalBuildInfo + :: ConfigFlags + -> FlagAssignment + -> ComponentRequestedSpec + -> [String] + -> InstallDirTemplates + -> Compiler + -> Platform + -> Maybe FilePath + -> Graph ComponentLocalBuildInfo + -> Map ComponentName [ComponentLocalBuildInfo] + -> Map (PackageName, ComponentName) ComponentId + -> InstalledPackageIndex + -> PackageDescription + -> ProgramDb + -> PackageDBStack + -> Bool + -> Bool + -> Bool + -> Bool + -> Bool + -> Bool + -> Bool + -> ProfDetailLevel + -> ProfDetailLevel + -> OptimisationLevel + -> DebugInfoLevel + -> Bool + -> Bool + -> Bool + -> Bool + -> Bool + -> Bool + -> Bool + -> [UnitId] + -> Bool + -> LocalBuildInfo +pattern LocalBuildInfo + { configFlags + , flagAssignment + , componentEnabledSpec + , extraConfigArgs + , installDirTemplates + , compiler + , hostPlatform + , pkgDescrFile + , componentGraph + , componentNameMap + , promisedPkgs + , installedPkgs + , localPkgDescr + , withPrograms + , withPackageDB + , withVanillaLib + , withProfLib + , withSharedLib + , withStaticLib + , withDynExe + , withFullyStaticExe + , withProfExe + , withProfLibDetail + , withProfExeDetail + , withOptimization + , withDebugInfo + , withGHCiLib + , splitSections + , splitObjs + , stripExes + , stripLibs + , exeCoverage + , libCoverage + , extraCoverageFor + , relocatable + } = + NewLocalBuildInfo + { localBuildDescr = + LBC.LocalBuildDescr + { packageBuildDescr = + LBC.PackageBuildDescr + { configFlags + , flagAssignment + , componentEnabledSpec + , compiler + , hostPlatform + , localPkgDescr + , installDirTemplates + , withPackageDB + , pkgDescrFile + , extraCoverageFor + } + , componentBuildDescr = + LBC.ComponentBuildDescr + { componentGraph + , componentNameMap + , promisedPkgs + , installedPkgs + } + } + , localBuildConfig = + LBC.LocalBuildConfig + { extraConfigArgs + , withPrograms + , withBuildOptions = + LBC.BuildOptions + { withVanillaLib + , withProfLib + , withSharedLib + , withStaticLib + , withDynExe + , withFullyStaticExe + , withProfExe + , withProfLibDetail + , withProfExeDetail + , withOptimization + , withDebugInfo + , withGHCiLib + , splitSections + , splitObjs + , stripExes + , stripLibs + , exeCoverage + , libCoverage + , relocatable + } + } + } + instance Binary LocalBuildInfo instance Structured LocalBuildInfo ------------------------------------------------------------------------------- -- Accessor functions +buildDir :: LocalBuildInfo -> FilePath +buildDir lbi = + buildDirPBD $ LBC.packageBuildDescr $ localBuildDescr lbi + +buildDirPBD :: LBC.PackageBuildDescr -> FilePath +buildDirPBD (LBC.PackageBuildDescr{configFlags = cfg}) = + configFlagsBuildDir cfg + +configFlagsBuildDir :: ConfigFlags -> FilePath +configFlagsBuildDir cfg = fromFlag (configDistPref cfg) "build" + +cabalFilePath :: LocalBuildInfo -> Maybe FilePath +cabalFilePath (LocalBuildInfo{configFlags = cfg}) = + flagToMaybe (configCabalFilePath cfg) + +progPrefix, progSuffix :: LocalBuildInfo -> PathTemplate +progPrefix (LocalBuildInfo{configFlags = cfg}) = + fromFlag $ configProgPrefix cfg +progSuffix (LocalBuildInfo{configFlags = cfg}) = + fromFlag $ configProgSuffix cfg + -- TODO: Get rid of these functions, as much as possible. They are -- a bit useful in some cases, but you should be very careful! @@ -206,7 +310,7 @@ localComponentId lbi = -- | Extract the 'PackageIdentifier' of a 'LocalBuildInfo'. -- This is a "safe" use of 'localPkgDescr' localPackage :: LocalBuildInfo -> PackageId -localPackage lbi = package (localPkgDescr lbi) +localPackage (LocalBuildInfo{localPkgDescr = pkg}) = package pkg -- | Extract the 'UnitId' from the library component of a -- 'LocalBuildInfo' if it exists, or make a fake unit ID based on @@ -247,22 +351,22 @@ mkTargetInfo pkg_descr _lbi clbi = -- Has a prime because it takes a 'PackageDescription' argument -- which may disagree with 'localPkgDescr' in 'LocalBuildInfo'. componentNameTargets' :: PackageDescription -> LocalBuildInfo -> ComponentName -> [TargetInfo] -componentNameTargets' pkg_descr lbi cname = - case Map.lookup cname (componentNameMap lbi) of +componentNameTargets' pkg_descr lbi@(LocalBuildInfo{componentNameMap = comps}) cname = + case Map.lookup cname comps of Just clbis -> map (mkTargetInfo pkg_descr lbi) clbis Nothing -> [] unitIdTarget' :: PackageDescription -> LocalBuildInfo -> UnitId -> Maybe TargetInfo -unitIdTarget' pkg_descr lbi uid = - case Graph.lookup uid (componentGraph lbi) of +unitIdTarget' pkg_descr lbi@(LocalBuildInfo{componentGraph = compsGraph}) uid = + case Graph.lookup uid compsGraph of Just clbi -> Just (mkTargetInfo pkg_descr lbi clbi) Nothing -> Nothing -- | Return all 'ComponentLocalBuildInfo's associated with 'ComponentName'. -- In the presence of Backpack there may be more than one! componentNameCLBIs :: LocalBuildInfo -> ComponentName -> [ComponentLocalBuildInfo] -componentNameCLBIs lbi cname = - case Map.lookup cname (componentNameMap lbi) of +componentNameCLBIs (LocalBuildInfo{componentNameMap = comps}) cname = + case Map.lookup cname comps of Just clbis -> clbis Nothing -> [] @@ -273,8 +377,8 @@ componentNameCLBIs lbi cname = -- Has a prime because it takes a 'PackageDescription' argument -- which may disagree with 'localPkgDescr' in 'LocalBuildInfo'. allTargetsInBuildOrder' :: PackageDescription -> LocalBuildInfo -> [TargetInfo] -allTargetsInBuildOrder' pkg_descr lbi = - map (mkTargetInfo pkg_descr lbi) (Graph.revTopSort (componentGraph lbi)) +allTargetsInBuildOrder' pkg_descr lbi@(LocalBuildInfo{componentGraph = compsGraph}) = + map (mkTargetInfo pkg_descr lbi) (Graph.revTopSort compsGraph) -- | Execute @f@ for every 'TargetInfo' in the package, respecting the -- build dependency order. (TODO: We should use Shake!) @@ -289,8 +393,8 @@ withAllTargetsInBuildOrder' pkg_descr lbi f = -- Has a prime because it takes a 'PackageDescription' argument -- which may disagree with 'localPkgDescr' in 'LocalBuildInfo'. neededTargetsInBuildOrder' :: PackageDescription -> LocalBuildInfo -> [UnitId] -> [TargetInfo] -neededTargetsInBuildOrder' pkg_descr lbi uids = - case Graph.closure (componentGraph lbi) uids of +neededTargetsInBuildOrder' pkg_descr lbi@(LocalBuildInfo{componentGraph = compsGraph}) uids = + case Graph.closure compsGraph uids of Nothing -> error $ "localBuildPlan: missing uids " ++ intercalate ", " (map prettyShow uids) Just clos -> map (mkTargetInfo pkg_descr lbi) (Graph.revTopSort (Graph.fromDistinctList clos)) @@ -305,21 +409,28 @@ withNeededTargetsInBuildOrder' pkg_descr lbi uids f = -- | Is coverage enabled for test suites? In practice, this requires library -- and executable profiling to be enabled. testCoverage :: LocalBuildInfo -> Bool -testCoverage lbi = exeCoverage lbi && libCoverage lbi +testCoverage (LocalBuildInfo{exeCoverage = exes, libCoverage = libs}) = + exes && libs ------------------------------------------------------------------------------- -- Stub functions to prevent someone from accidentally defining them {-# WARNING componentNameTargets, unitIdTarget, allTargetsInBuildOrder, withAllTargetsInBuildOrder, neededTargetsInBuildOrder, withNeededTargetsInBuildOrder "By using this function, you may be introducing a bug where you retrieve a 'Component' which does not have 'HookedBuildInfo' applied to it. See the documentation for 'HookedBuildInfo' for an explanation of the issue. If you have a 'PackageDescription' handy (NOT from the 'LocalBuildInfo'), try using the primed version of the function, which takes it as an extra argument." #-} componentNameTargets :: LocalBuildInfo -> ComponentName -> [TargetInfo] -componentNameTargets lbi = componentNameTargets' (localPkgDescr lbi) lbi +componentNameTargets lbi@(LocalBuildInfo{localPkgDescr = pkg}) = + componentNameTargets' pkg lbi unitIdTarget :: LocalBuildInfo -> UnitId -> Maybe TargetInfo -unitIdTarget lbi = unitIdTarget' (localPkgDescr lbi) lbi +unitIdTarget lbi@(LocalBuildInfo{localPkgDescr = pkg}) = + unitIdTarget' pkg lbi allTargetsInBuildOrder :: LocalBuildInfo -> [TargetInfo] -allTargetsInBuildOrder lbi = allTargetsInBuildOrder' (localPkgDescr lbi) lbi +allTargetsInBuildOrder lbi@(LocalBuildInfo{localPkgDescr = pkg}) = + allTargetsInBuildOrder' pkg lbi withAllTargetsInBuildOrder :: LocalBuildInfo -> (TargetInfo -> IO ()) -> IO () -withAllTargetsInBuildOrder lbi = withAllTargetsInBuildOrder' (localPkgDescr lbi) lbi +withAllTargetsInBuildOrder lbi@(LocalBuildInfo{localPkgDescr = pkg}) = + withAllTargetsInBuildOrder' pkg lbi neededTargetsInBuildOrder :: LocalBuildInfo -> [UnitId] -> [TargetInfo] -neededTargetsInBuildOrder lbi = neededTargetsInBuildOrder' (localPkgDescr lbi) lbi +neededTargetsInBuildOrder lbi@(LocalBuildInfo{localPkgDescr = pkg}) = + neededTargetsInBuildOrder' pkg lbi withNeededTargetsInBuildOrder :: LocalBuildInfo -> [UnitId] -> (TargetInfo -> IO ()) -> IO () -withNeededTargetsInBuildOrder lbi = withNeededTargetsInBuildOrder' (localPkgDescr lbi) lbi +withNeededTargetsInBuildOrder lbi@(LocalBuildInfo{localPkgDescr = pkg}) = + withNeededTargetsInBuildOrder' pkg lbi diff --git a/Cabal/src/Distribution/Types/TargetInfo.hs b/Cabal/src/Distribution/Types/TargetInfo.hs index 8f724d894d1..a743b0b21b0 100644 --- a/Cabal/src/Distribution/Types/TargetInfo.hs +++ b/Cabal/src/Distribution/Types/TargetInfo.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeFamilies #-} module Distribution.Types.TargetInfo @@ -27,6 +28,10 @@ data TargetInfo = TargetInfo -- generalization. Figure it out later. -- targetSub :: Maybe (Either ModuleName FilePath) } + deriving (Generic, Show) + +instance Binary TargetInfo +instance Structured TargetInfo instance IsNode TargetInfo where type Key TargetInfo = UnitId diff --git a/LICENSE b/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/Makefile b/Makefile index 56747e4b9f5..fb0b6ef73d0 100644 --- a/Makefile +++ b/Makefile @@ -1,35 +1,58 @@ -.PHONY : all lexer sdpx lib exe doctest -.PHONY : phony +.PHONY: phony + # Adding dependency "phony" is like declaring a target as ".PHONY": + # See https://www.gnu.org/software/make/manual/html_node/Force-Targets.html CABALBUILD := cabal build CABALRUN := cabal run +# The newer and prefered way to call the doctest tool is: +# $ cabal repl --with-ghc=doctest +# SEE: https://github.com/haskell/cabal/issues/8504 +# There is but one caveat, we have to avoid allow-newer. +# SEE: https://github.com/haskell/cabal/issues/6859 +DOCTEST := cabal repl --with-ghc=doctest --repl-options="-w" --ghc-options="-Wwarn" --allow-newer=False + # default rules +.PHONY: all all : exe lib -lib : $(LEXER_HS) +.PHONY: lib +lib : $(CABALBUILD) Cabal:libs -exe : $(LEXER_HS) +.PHONY: exe +exe : $(CABALBUILD) cabal-install:exes +.PHONY: init init: ## Set up git hooks and ignored revisions @git config core.hooksPath .githooks ## TODO +.PHONY: style style: ## Run the code styler @fourmolu -q -i Cabal Cabal-syntax cabal-install +.PHONY: style-modified style-modified: ## Run the code styler on modified files @git ls-files --modified Cabal Cabal-syntax cabal-install \ | grep '.hs$$' | xargs -P $(PROCS) -I {} fourmolu -q -i {} +.PHONY: style-commit +style-commit: ## Run the code styler on the previous commit + @git diff --name-only HEAD $(COMMIT) Cabal Cabal-syntax cabal-install \ + | grep '.hs$$' | xargs -P $(PROCS) -I {} fourmolu -q -i {} + # source generation: SPDX SPDX_LICENSE_HS:=Cabal-syntax/src/Distribution/SPDX/LicenseId.hs SPDX_EXCEPTION_HS:=Cabal-syntax/src/Distribution/SPDX/LicenseExceptionId.hs +# Note: the 'spdx' goal is used in .github/workflows/quick-jobs.yml. +# Any changes to this goal need to be reconciled with this workflow. +# +.PHONY: spdx spdx : $(SPDX_LICENSE_HS) $(SPDX_EXCEPTION_HS) SPDX_LICENSE_VERSIONS:=3.0 3.2 3.6 3.9 3.10 3.16 @@ -45,7 +68,11 @@ $(SPDX_EXCEPTION_HS) : templates/SPDX.LicenseExceptionId.template.hs cabal-dev-s TEMPLATE_MACROS:=Cabal/src/Distribution/Simple/Build/Macros/Z.hs TEMPLATE_PATHS:=Cabal/src/Distribution/Simple/Build/PathsModule/Z.hs -templates : phony $(TEMPLATE_MACROS) $(TEMPLATE_PATHS) +# Note: the 'templates' goal is used in .github/workflows/quick-jobs.yml. +# Any changes to this goal need to be reconciled with this workflow. +# +.PHONY: templates +templates : $(TEMPLATE_MACROS) $(TEMPLATE_PATHS) $(TEMPLATE_MACROS) : templates/cabal_macros.template.h cabal-dev-scripts/src/GenCabalMacros.hs cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-cabal-macros -- $< $@ @@ -54,64 +81,74 @@ $(TEMPLATE_PATHS) : templates/Paths_pkg.template.hs cabal-dev-scripts/src/GenPat cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta gen-paths-module -- $< $@ # generated docs - -buildinfo-fields-reference : phony - cabal build --builddir=dist-newstyle-bi --project-file=cabal.project.buildinfo buildinfo-reference-generator - $$(cabal list-bin --builddir=dist-newstyle-bi buildinfo-reference-generator) buildinfo-reference-generator/template.zinza | tee $@ - -# analyse-imports -analyse-imports : phony +# Use cabal build before cabal run to avoid output of the build on stdout when running +doc/buildinfo-fields-reference.rst : \ + $(wildcard Cabal-syntax/src/*/*.hs Cabal-syntax/src/*/*/*.hs Cabal-syntax/src/*/*/*/*.hs) \ + $(wildcard Cabal-described/src/Distribution/Described.hs Cabal-described/src/Distribution/Utils/*.hs) \ + buildinfo-reference-generator/src/Main.hs \ + buildinfo-reference-generator/template.zinza + cabal build buildinfo-reference-generator + cabal run buildinfo-reference-generator buildinfo-reference-generator/template.zinza | tee $@ + git diff --exit-code $@ + +.PHONY: analyse-imports +analyse-imports : find Cabal-syntax/src Cabal/src cabal-install/src -type f -name '*.hs' | xargs cabal run --builddir=dist-newstyle-meta --project-file=cabal.project.meta analyse-imports -- # ghcid +.PHONY: ghcid-lib ghcid-lib : ghcid -c 'cabal repl Cabal' +.PHONY: ghcid-cli ghcid-cli : ghcid -c 'cabal repl cabal-install' -# Artem, 2023-02-03, https://github.com/haskell/cabal/issues/8504 -# The new and prefered way to call the doctest tool (as of now) is based on cabal repl --with-ghc=doctest. -# The call below reflects the current documentation of the doctest tool except one caveat, -# which is https://github.com/haskell/cabal/issues/6859, i.e. we have to hide allow-newer in our project -# file from cabal/doctest. This is easy: we just select a project file with no allow-newer (e.g. cabal.project.libonly). -# -# TODO: Cabal-described should be added here but its doctests currently broken, see: -# https://github.com/haskell/cabal/issues/8734 -# Just as well, cabal-install(-solver) doctests (the target below) bitrotted and need some care. +.PHONY: doctest doctest : - cabal repl --with-ghc=doctest --build-depends=QuickCheck --build-depends=template-haskell --repl-options="-w" --project-file="cabal.project.doctest" Cabal-syntax - cabal repl --with-ghc=doctest --build-depends=QuickCheck --build-depends=template-haskell --repl-options="-w" --project-file="cabal.project.doctest" Cabal - + $(DOCTEST) Cabal-syntax + $(DOCTEST) Cabal-described + $(DOCTEST) --build-depends=QuickCheck Cabal + $(DOCTEST) cabal-install-solver + $(DOCTEST) cabal-install # This is not run as part of validate.sh (we need hackage-security, which is tricky to get). +.PHONY: doctest-cli doctest-cli : doctest -D__DOCTEST__ --fast cabal-install/src cabal-install-solver/src cabal-install-solver/src-assertion +.PHONY: doctest-install doctest-install: cabal install doctest --overwrite-policy=always --ignore-project # tests +.PHONY: check-tests check-tests : $(CABALRUN) check-tests -- --cwd Cabal-tests ${TEST} +.PHONY: parser-tests parser-tests : $(CABALRUN) parser-tests -- --cwd Cabal-tests ${TEST} +.PHONY: parser-tests-accept parser-tests-accept : $(CABALRUN) parser-tests -- --cwd Cabal-tests --accept ${TEST} +.PHONY: custom-setup-tests custom-setup-tests : $(CABALRUN) custom-setup-tests -- +.PHONY: hackage-parsec-tests hackage-parsec-tests : $(CABALRUN) hackage-tests -- parsec +RTS -s -qg -I0 -A64M -N${THREADS} -RTS ${TEST} +.PHONY: hackage-rountrip-tests hackage-roundtrip-tests : $(CABALRUN) hackage-tests -- roundtrip +RTS -s -qg -I0 -A64M -N${THREADS} -RTS ${TEST} +.PHONY: cabal-install-test cabal-install-test: $(CABALBUILD) -j3 cabal-tests cabal rm -rf .ghc.environment.* @@ -119,6 +156,7 @@ cabal-install-test: # hackage-benchmarks (solver) +.PHONY: hackage-benchmarks-run hackage-benchmarks-run: $(CABALBUILD) -j3 hackage-benchmark cabal rm -rf .ghc.environment.* @@ -126,6 +164,7 @@ hackage-benchmarks-run: # This doesn't run build, as you first need to test with cabal-install-test :) +.PHONY: cabal-install-test-accept cabal-install-test-accept: rm -rf .ghc.environment.* cd cabal-testsuite && `cabal list-bin cabal-tests` --with-cabal=`cabal list-bin cabal` --hide-successes -j3 --accept ${TEST} @@ -136,12 +175,14 @@ cabal-install-test-accept: # # make validate-via-docker-all -j4 -O # +.PHONY: validate-via-docker-all validate-via-docker-all : validate-via-docker-8.2.2 validate-via-docker-all : validate-via-docker-8.4.4 validate-via-docker-all : validate-via-docker-8.6.5 validate-via-docker-all : validate-via-docker-8.8.4 validate-via-docker-all : validate-via-docker-8.10.4 +.PHONY: validate-dockerfiles validate-dockerfiles : .docker/validate-8.10.4.dockerfile validate-dockerfiles : .docker/validate-8.8.4.dockerfile validate-dockerfiles : .docker/validate-8.6.5.dockerfile @@ -155,29 +196,30 @@ validate-dockerfiles : .docker/validate-8.2.2.dockerfile # and we have a test relying on this limit being sufficiently small DOCKERARGS:=--ulimit nofile=1024:1024 +.PHONY: validate-via-docker-8.2.2 validate-via-docker-8.2.2: docker build $(DOCKERARGS) -t cabal-validate:8.2.2 -f .docker/validate-8.2.2.dockerfile . +.PHONY: validate-via-docker-8.4.4 validate-via-docker-8.4.4: docker build $(DOCKERARGS) -t cabal-validate:8.4.4 -f .docker/validate-8.4.4.dockerfile . +.PHONY: validate-via-docker-8.6.5 validate-via-docker-8.6.5: docker build $(DOCKERARGS) -t cabal-validate:8.6.5 -f .docker/validate-8.6.5.dockerfile . +.PHONY: validate-via-docker-8.8.4 validate-via-docker-8.8.4: docker build $(DOCKERARGS) -t cabal-validate:8.8.4 -f .docker/validate-8.8.4.dockerfile . +.PHONY: validate-via-docker-8.10.4 validate-via-docker-8.10.4: docker build $(DOCKERARGS) -t cabal-validate:8.10.4 -f .docker/validate-8.10.4.dockerfile . +.PHONY: validate-via-docker-old validate-via-docker-old: docker build $(DOCKERARGS) -t cabal-validate:older -f .docker/validate-old.dockerfile . -# Weeder -weeder : - cabal build all --project-file=cabal.project.weeder - weeder | less - # tags .PHONY : tags tags : @@ -187,7 +229,7 @@ tags : ############################################################################## bootstrap-json-%: phony - cabal build --project=cabal.project.release --with-compiler=ghc-$* --dry-run cabal-install:exe:cabal + cabal build --project-file=cabal.project.release --with-compiler=ghc-$* --dry-run cabal-install:exe:cabal cp dist-newstyle/cache/plan.json bootstrap/linux-$*.plan.json @# -v0 to avoid build output on stdout cd bootstrap && cabal run -v0 cabal-bootstrap-gen -- linux-$*.plan.json \ @@ -195,6 +237,7 @@ bootstrap-json-%: phony BOOTSTRAP_GHC_VERSIONS := 8.10.7 9.0.2 9.2.7 9.4.4 +.PHONY: bootstrap-jsons bootstrap-jsons: $(BOOTSTRAP_GHC_VERSIONS:%=bootstrap-json-%) # documentation diff --git a/README.md b/README.md index d8142339b47..bf6ea795060 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Documentation Status](http://readthedocs.org/projects/cabal/badge/?version=latest)](http://cabal.readthedocs.io/en/latest/?badge=latest) [![IRC chat](https://img.shields.io/badge/chat-via%20libera-brightgreen.svg)](https://web.libera.chat/#hackage) [![Matrix chat](https://img.shields.io/badge/chat-via%20matrix-brightgreen.svg)](https://matrix.to/#/#hackage:matrix.org) +[![GitLab pipeline status](https://gitlab.haskell.org/haskell/cabal/badges/cabal-head/pipeline.svg?key_text=Release%20CI%20Early%20Warning&key_width=150)](https://gitlab.haskell.org/haskell/cabal/-/commits/cabal-head) @@ -21,7 +22,7 @@ https://github.com/haskell/cabal. Ways to get the `cabal-install` binary -------------------------------- -1. _GHCup (**preferred**)_: get GHCup using [the directions on its website](https://www.haskell.org/ghcup/) and run: +1. _GHCup_ (**preferred**): get GHCup using [the directions on its website](https://www.haskell.org/ghcup/) and run: ``` ghcup install --set cabal latest @@ -30,6 +31,8 @@ Ways to get the `cabal-install` binary 2. _[Download from official website](https://www.haskell.org/cabal/download.html)_: the `cabal-install` binary download for your platform should contain the `cabal` executable. +#### Preview Releases + _Getting unreleased versions of `cabal-install`_: gives you a chance to try out yet-unreleased features. Currently, we only provide binaries for `x86_64` platforms. @@ -41,9 +44,27 @@ Currently, we only provide binaries for `x86_64` platforms. Replace "Linux" with "Windows" or "macOS" as appropriate. + The default Linux build is dynamically linked against `zlib`, `gmp` and `glibc`. + You will need to have appropriate versions of these libraries installed to use it. + Alternatively a statically linked "Linux-static" binary is also provided. + + You might need to add the following to your `cabal.project` file + if your build fails because of an out-of-date `Cabal` library: + ``` + allow-newer: + *:Cabal, + *:Cabal-syntax + + source-repository-package + type: git + location: https://github.com/haskell/cabal.git + subdir: Cabal Cabal-syntax + ``` + 2. Even more cutting-edge binaries built from pull requests are always available - from the `Validate` worklow page on GitHub, at the very bottom of the page. + from the `Validate` worklow page on GitHub, at the very bottom of the page, + or from the `build-alpine` workflow for statically linked Linux builds. Ways to build `cabal-install` for everyday use -------------------------------------------- diff --git a/bootstrap/README.md b/bootstrap/README.md index 1325bcefe48..e41f13d691c 100644 --- a/bootstrap/README.md +++ b/bootstrap/README.md @@ -47,3 +47,13 @@ in the same way as it is shown for Linux above. On a system with functional `cab There are rules in the top-level `Makefile` for generation of these files. +# Updating Bootstrap Plans + +In order to update the bootstrap plans on linux there is the convenient `./generate_bootstrap_plans` +script. You can modify this script with the GHC versions you want to generate the plans for and +then run it to generate the plans. + +``` +./generate_bootstrap_plans +``` + diff --git a/bootstrap/cabal-bootstrap-gen.cabal b/bootstrap/cabal-bootstrap-gen.cabal index 439e80117ff..c87e673c9a8 100644 --- a/bootstrap/cabal-bootstrap-gen.cabal +++ b/bootstrap/cabal-bootstrap-gen.cabal @@ -11,7 +11,7 @@ executable cabal-bootstrap-gen , aeson ^>=1.5.2.0 || ^>=2.0.3.0 || ^>=2.1.0.0 , base ^>=4.12.0.0 || ^>=4.13.0.0 || ^>=4.14.0.0 || ^>=4.15.0.0 || ^>=4.16.0.0 || ^>=4.17.0.0 , bytestring ^>=0.10.8.2 || ^>=0.11.0.0 - , Cabal ^>=3.2.0.0 || ^>=3.4.1.0 || ^>=3.6.3.0 || ^>=3.10.1.0 + , Cabal ^>=3.4.1.0 || ^>=3.6.3.0 || ^>=3.10.1.0 , Cabal-syntax ^>=3.10.1.0 , cabal-install-parsers ^>=0.3.0.1 || ^>=0.4.5 || ^>=0.6 , cabal-plan ^>=0.7.0.0 diff --git a/bootstrap/generate_bootstrap_plans b/bootstrap/generate_bootstrap_plans new file mode 100755 index 00000000000..d81b088bb64 --- /dev/null +++ b/bootstrap/generate_bootstrap_plans @@ -0,0 +1,23 @@ +nix build nixpkgs#jq.bin -o jq +PATH+=:$PWD/jq-bin/bin + +ghcs_nix="https://gitlab.haskell.org/bgamari/ghcs-nix/-/archive/master/ghcs-nix-master.tar.gz" + +nix build -f "$ghcs_nix" ghc-8_10_7 -o boot_ghc + +run() { + local ver="$1" + local drv="ghc-$ver" + echo "$ver" + nix build -f "$ghcs_nix" $drv + (cd ../; rm -r dist-bootstrap; cabal --distdir=dist-bootstrap build --project-file=cabal.project.release --dry-run cabal-install:exe:cabal -w bootstrap/result/bin/ghc) + jq --sort-keys < ../dist-bootstrap/cache/plan.json > "plan-$ver.json" + cabal run --with-ghc-pkg $PWD/boot_ghc/bin/ghc-pkg -w $PWD/boot_ghc/bin/ghc -v0 cabal-bootstrap-gen -- "plan-$ver.json" | jq --sort-keys | tee "linux-$(echo $ver | tr "_" ".").json" +} + +run "8_10_7" +run "9_0_2" +run "9_2_8" +run "9_4_8" +run "9_6_4" +run "9_8_1" diff --git a/bootstrap/linux-8.10.7.json b/bootstrap/linux-8.10.7.json index 4ef250fd0c2..f20d989baa5 100644 --- a/bootstrap/linux-8.10.7.json +++ b/bootstrap/linux-8.10.7.json @@ -1,525 +1,560 @@ { - "builtin": [ - { - "package": "rts", - "version": "1.0.1" - }, - { - "package": "ghc-prim", - "version": "0.6.1" - }, - { - "package": "integer-gmp", - "version": "1.0.3.0" - }, - { - "package": "base", - "version": "4.14.3.0" - }, - { - "package": "array", - "version": "0.5.4.0" - }, - { - "package": "deepseq", - "version": "1.4.4.0" - }, - { - "package": "containers", - "version": "0.6.5.1" - }, - { - "package": "ghc-boot-th", - "version": "8.10.7" - }, - { - "package": "pretty", - "version": "1.1.3.6" - }, - { - "package": "template-haskell", - "version": "2.16.0.0" - }, - { - "package": "transformers", - "version": "0.5.6.2" - }, - { - "package": "mtl", - "version": "2.2.2" - }, - { - "package": "stm", - "version": "2.5.0.1" - }, - { - "package": "exceptions", - "version": "0.10.4" - }, - { - "package": "time", - "version": "1.9.3" - } - ], - "dependencies": [ - { - "cabal_sha256": "458d4794a5ced371a844e325fe539dd5fee8fe41f78b6f00e6c70920b7dd18e3", - "component": "lib:bytestring", - "flags": [], - "package": "bytestring", - "revision": 0, - "source": "hackage", - "src_sha256": "76193d39b66197107f452184597a4e458194c64731efbba1e9605550c732f7f4", - "version": "0.11.5.0" - }, - { - "cabal_sha256": "2de84756d3907308230e34fcc7c1917a73f218f6d53838618b7d5b95dd33e2c3", - "component": "lib:filepath", - "flags": [ - "-cpphs" - ], - "package": "filepath", - "revision": 0, - "source": "hackage", - "src_sha256": "82876250347c2fdf0f9de5448ce44f02539f37951b671d9a30719a6c4f96e9ad", - "version": "1.4.100.4" - }, - { - "cabal_sha256": "91cbc951a742fc2c95d5902be38fcf1b859c2891241bc353ff16154a8f7c35ae", - "component": "lib:unix", - "flags": [], - "package": "unix", - "revision": 0, - "source": "hackage", - "src_sha256": "cc287659427c80f3598c199387ba7eb7d4cc3270cbb31f75e2f677e879f26384", - "version": "2.8.1.1" - }, - { - "cabal_sha256": "e384a4831b0ac0f8908a1d99d14ce44bf9c5fe2092eec5b2c47ea072d477a493", - "component": "lib:directory", - "flags": [], - "package": "directory", - "revision": 0, - "source": "hackage", - "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", - "version": "1.3.8.1" - }, - { - "cabal_sha256": "3c9e1e6b4f2f956623375dd15b904144dd3183b28f1ce1afcce11192f6d868dd", - "component": "exe:alex", - "flags": [], - "package": "alex", - "revision": 0, - "source": "hackage", - "src_sha256": "7a1cd4e21399c40ea9372d1c03bf38698944b8437ce95cf27d1a7c262babe38e", - "version": "3.4.0.0" - }, - { - "cabal_sha256": "81f468c1c75fd6535152ab69b2d32ac6cfcc03e345267b069abe4da56ec95801", - "component": "lib:binary", - "flags": [], - "package": "binary", - "revision": 0, - "source": "hackage", - "src_sha256": "ac21ca63452dfc9b0bcab87c57699c531d87f7a9bcb6230ca46fba1b7faeebc0", - "version": "0.8.9.1" - }, - { - "cabal_sha256": "71b5fa8c64d3c1fd0a08f993463220867b08290a2256e94b0952bf0e8f5a45cc", - "component": "lib:text", - "flags": [ - "-developer", - "+simdutf" - ], - "package": "text", - "revision": 1, - "source": "hackage", - "src_sha256": "c735be650a898606ce9f2c8642bc6ac6123eea82871d5e90f92797801f59efad", - "version": "2.0.2" - }, - { - "cabal_sha256": "5769242043b01bf759b07b7efedcb19607837ee79015fcddde34645664136aed", - "component": "lib:parsec", - "flags": [], - "package": "parsec", - "revision": 0, - "source": "hackage", - "src_sha256": "a41962e5d76ea68658876735b8d5b755e0eff336b079d0a2f439c364755d1246", - "version": "3.1.16.1" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal-syntax", - "flags": [], - "package": "Cabal-syntax", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "49d8a7f372d35363011591b253cae4c8db8b9ec594590448e20b7bed7acaee98", - "component": "lib:process", - "flags": [], - "package": "process", - "revision": 0, - "source": "hackage", - "src_sha256": "4c5c454e0f5c864c79b9fabd850307b26d8ac4037e45a6a39ab87e20b583bf06", - "version": "1.6.17.0" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal", - "flags": [], - "package": "Cabal", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "115b8c34b9f83603cfd9eb8b1e2d7ac520da0a4a43d96be435f06ce01a7bc95e", - "component": "exe:hsc2hs", - "flags": [ - "-in-ghc-tree" - ], - "package": "hsc2hs", - "revision": 0, - "source": "hackage", - "src_sha256": "c95b10ce0b2c881480e35118d738dcc9cefc435ec72baa0031af81d0d4d3bc0a", - "version": "0.68.9" - }, - { - "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", - "component": "lib:network", - "flags": [ - "-devel" - ], - "package": "network", - "revision": 1, - "source": "hackage", - "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", - "version": "3.1.4.0" - }, - { - "cabal_sha256": "e5ae7c083ef3a22248558f8451669bb1c55ea8090f5908b86b9033743c161730", - "component": "lib:th-compat", - "flags": [], - "package": "th-compat", - "revision": 2, - "source": "hackage", - "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", - "version": "0.1.4" - }, - { - "cabal_sha256": "1fde59abf5d82a9666b4415bc2b2e9e33f6c1309074fda12d50410c7dbd95f3b", - "component": "lib:network-uri", - "flags": [], - "package": "network-uri", - "revision": 0, - "source": "hackage", - "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", - "version": "2.6.4.2" - }, - { - "cabal_sha256": "d9220cc1b8c1f287248d650910710b96e62e54530772e3bcd19dbdec6547f8ae", - "component": "lib:HTTP", - "flags": [ - "-conduit10", - "+network-uri", - "-warn-as-error", - "-warp-tests" - ], - "package": "HTTP", - "revision": 2, - "source": "hackage", - "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", - "version": "4000.4.1" - }, - { - "cabal_sha256": "0bdd3486d3a1bcbed0513b46af4a13ca74b395313fa5b6e0068d6b7413b76a04", - "component": "lib:base-orphans", - "flags": [], - "package": "base-orphans", - "revision": 0, - "source": "hackage", - "src_sha256": "613ed4d8241ed5a648a59ae6569a6962990bb545711d020d49fb83fa12d16e62", - "version": "0.9.0" - }, - { - "cabal_sha256": "2ef1bd3511e82ba56f7f23cd793dd2da84338a1e7c2cbea5b151417afe3baada", - "component": "lib:data-array-byte", - "flags": [], - "package": "data-array-byte", - "revision": 1, - "source": "hackage", - "src_sha256": "1bb6eca0b3e02d057fe7f4e14c81ef395216f421ab30fdaa1b18017c9c025600", - "version": "0.1.0.1" - }, - { - "cabal_sha256": "585792335d5541dba78fa8dfcb291a89cd5812a281825ff7a44afa296ab5d58a", - "component": "lib:hashable", - "flags": [ - "+integer-gmp", - "-random-initial-seed" - ], - "package": "hashable", - "revision": 1, - "source": "hackage", - "src_sha256": "1b4000ea82b81f69d46d0af4152c10c6303873510738e24cfc4767760d30e3f8", - "version": "1.4.2.0" - }, - { - "cabal_sha256": "46367dc0c8326dcbeb7b93f200b567491c2f6029bccf822b8bb26ee660397e08", - "component": "lib:async", - "flags": [ - "-bench" - ], - "package": "async", - "revision": 3, - "source": "hackage", - "src_sha256": "484df85be0e76c4fed9376451e48e1d0c6e97952ce79735b72d54297e7e0a725", - "version": "2.2.4" - }, - { - "cabal_sha256": "64abad7816ab8cabed8489e29f807b3a6f828e0b2cec0eae404323d69d36df9a", - "component": "lib:base16-bytestring", - "flags": [], - "package": "base16-bytestring", - "revision": 0, - "source": "hackage", - "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", - "version": "1.0.2.0" - }, - { - "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", - "component": "lib:base64-bytestring", - "flags": [], - "package": "base64-bytestring", - "revision": 1, - "source": "hackage", - "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", - "version": "1.2.1.0" - }, - { - "cabal_sha256": "db25c2e17967aa6b6046ab8b1b96ba3f344ca59a62b60fb6113d51ea305a3d8e", - "component": "lib:splitmix", - "flags": [ - "-optimised-mixer" - ], - "package": "splitmix", - "revision": 2, - "source": "hackage", - "src_sha256": "6d065402394e7a9117093dbb4530a21342c9b1e2ec509516c8a8d0ffed98ecaa", - "version": "0.1.0.4" - }, - { - "cabal_sha256": "dea1f11e5569332dc6c8efaad1cb301016a5587b6754943a49f9de08ae0e56d9", - "component": "lib:random", - "flags": [], - "package": "random", - "revision": 0, - "source": "hackage", - "src_sha256": "3e1272f7ed6a4d7bd1712b90143ec326fee9b225789222379fea20a9c90c9b76", - "version": "1.2.1.1" - }, - { - "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", - "component": "lib:edit-distance", - "flags": [], - "package": "edit-distance", - "revision": 1, - "source": "hackage", - "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", - "version": "0.2.2.1" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install-solver", - "flags": [ - "-debug-conflict-sets", - "-debug-expensive-assertions", - "-debug-tracetree" - ], - "package": "cabal-install-solver", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "72ce9095872eae653addca5f412ac8070d6282d8e1c8578c2237c33f2cbbf4bc", - "component": "lib:cryptohash-sha256", - "flags": [ - "-exe", - "+use-cbits" - ], - "package": "cryptohash-sha256", - "revision": 2, - "source": "hackage", - "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", - "version": "0.11.102.1" - }, - { - "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", - "component": "lib:echo", - "flags": [ - "-example" - ], - "package": "echo", - "revision": 0, - "source": "hackage", - "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", - "version": "0.1.4" - }, - { - "cabal_sha256": "3db04d7c18b9e68ba5eef3fa7eeca05e1e248958dd182290c8e6b010c81ef73e", - "component": "lib:ed25519", - "flags": [ - "+no-donna", - "+test-doctests", - "+test-hlint", - "+test-properties" - ], - "package": "ed25519", - "revision": 7, - "source": "hackage", - "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", - "version": "0.0.5.0" - }, - { - "cabal_sha256": "9ab54ee4f80bbd8a3fddd639ea142b7039ee2deb27f7df031a93de1819e34146", - "component": "lib:lukko", - "flags": [ - "+ofd-locking" - ], - "package": "lukko", - "revision": 4, - "source": "hackage", - "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", - "version": "0.1.1.3" - }, - { - "cabal_sha256": "63dbcb0f507273a8331363e4c13a1fe91f4ea0c495883cf65f314629582a2630", - "component": "lib:tar", - "flags": [ - "-old-bytestring", - "-old-time" - ], - "package": "tar", - "revision": 6, - "source": "hackage", - "src_sha256": "b384449f62b2b0aa3e6d2cb1004b8060b01f21ec93e7b63e7af6d8fad8a9f1de", - "version": "0.5.1.1" - }, - { - "cabal_sha256": "386dd93bc0352bf6ad5c6bca4dee0442b52d95b4c34e85901064f3eb05c81731", - "component": "lib:zlib", - "flags": [ - "-bundled-c-zlib", - "-non-blocking-ffi", - "-pkg-config" - ], - "package": "zlib", - "revision": 2, - "source": "hackage", - "src_sha256": "9eaa989ad4534438b5beb51c1d3a4c8f6a088fdff0b259a5394fbf39aaee04da", - "version": "0.6.3.0" - }, - { - "cabal_sha256": "2e5893334ee8967a990349a04953331b28e83bebd64d4f7cb46b71603d183d0c", - "component": "lib:hackage-security", - "flags": [ - "+base48", - "+cabal-syntax", - "+lukko", - "-mtl21", - "-old-directory", - "+use-network-uri" - ], - "package": "hackage-security", - "revision": 5, - "source": "hackage", - "src_sha256": "52ee0576971955571d846b8e6c09638f89f4f7881f4a95173e44ccc0d856a066", - "version": "0.6.2.3" - }, - { - "cabal_sha256": "3a76c313f9f75e8e0b3c103c1bff5bbaf754da30cbddedc1d5b7061d001030e0", - "component": "lib:regex-base", - "flags": [], - "package": "regex-base", - "revision": 2, - "source": "hackage", - "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", - "version": "0.94.0.2" - }, - { - "cabal_sha256": "d479ca2cc6274c15801169f83dae883c9b62b78af3c7b30ed3fbd4b4612156b8", - "component": "lib:regex-posix", - "flags": [ - "-_regex-posix-clib" - ], - "package": "regex-posix", - "revision": 2, - "source": "hackage", - "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", - "version": "0.96.0.1" - }, - { - "cabal_sha256": "a42b4a473478db92f4728f755403db232b55445e3091a957be073fc8e84e5d46", - "component": "lib:resolv", - "flags": [], - "package": "resolv", - "revision": 1, - "source": "hackage", - "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", - "version": "0.2.0.2" - }, - { - "cabal_sha256": "f4aad0eca90044cb1eba53b84f75d5fa142d25d695117730bf31178d409c4fe0", - "component": "lib:safe-exceptions", - "flags": [], - "package": "safe-exceptions", - "revision": 0, - "source": "hackage", - "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", - "version": "0.1.7.4" - }, - { - "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", - "component": "lib:semaphore-compat", - "flags": [], - "package": "semaphore-compat", - "revision": 1, - "source": "hackage", - "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", - "version": "1.0.0" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": null, - "component": "exe:cabal", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - } - ] + "builtin": [ + { + "package": "rts", + "version": "1.0.1" + }, + { + "package": "ghc-prim", + "version": "0.6.1" + }, + { + "package": "integer-gmp", + "version": "1.0.3.0" + }, + { + "package": "base", + "version": "4.14.3.0" + }, + { + "package": "array", + "version": "0.5.4.0" + }, + { + "package": "deepseq", + "version": "1.4.4.0" + }, + { + "package": "containers", + "version": "0.6.5.1" + }, + { + "package": "ghc-boot-th", + "version": "8.10.7" + }, + { + "package": "pretty", + "version": "1.1.3.6" + }, + { + "package": "template-haskell", + "version": "2.16.0.0" + }, + { + "package": "transformers", + "version": "0.5.6.2" + }, + { + "package": "mtl", + "version": "2.2.2" + }, + { + "package": "stm", + "version": "2.5.0.1" + }, + { + "package": "exceptions", + "version": "0.10.4" + }, + { + "package": "time", + "version": "1.9.3" + } + ], + "dependencies": [ + { + "cabal_sha256": "ad89e28b2b046175698fbf542af2ce43e5d2af50aae9f48d12566b1bb3de1d3c", + "component": "lib:data-array-byte", + "flags": [], + "package": "data-array-byte", + "revision": 2, + "source": "hackage", + "src_sha256": "1bb6eca0b3e02d057fe7f4e14c81ef395216f421ab30fdaa1b18017c9c025600", + "version": "0.1.0.1" + }, + { + "cabal_sha256": "9fc077ff5b7ed2246773c3ac4370ef8822e4834d4587522b68ae551a5968fb86", + "component": "lib:bytestring", + "flags": [], + "package": "bytestring", + "revision": 0, + "source": "hackage", + "src_sha256": "a93fe5fbc8062656bd611ab1529b4879bb61411eda6529b350c7bf3aaf7dba3e", + "version": "0.12.0.2" + }, + { + "cabal_sha256": "d9e181e1acae0ac505d8b217dec3805c68554878f1e32b3d8351b9ce17061623", + "component": "lib:filepath", + "flags": [ + "-cpphs" + ], + "package": "filepath", + "revision": 0, + "source": "hackage", + "src_sha256": "337a0b5bcf0898cb7f51ff327528cf26f4ac38baed7b66b28fbdea334699d8ed", + "version": "1.4.300.1" + }, + { + "cabal_sha256": "633f15ef0bd50a16a7b5c5e86e6659fee6e4e211e098cc8bd0029f452bfcfddc", + "component": "lib:unix", + "flags": [ + "-os-string" + ], + "package": "unix", + "revision": 0, + "source": "hackage", + "src_sha256": "d70b81e242ee7e2e866118616c5b97afca9047e76bbfd51baa085a38db92857d", + "version": "2.8.5.0" + }, + { + "cabal_sha256": "bd3b0a0947a365d2da80b9f4a960a864d42ffa7a46577fdc7a0611703486a7f9", + "component": "lib:directory", + "flags": [], + "package": "directory", + "revision": 1, + "source": "hackage", + "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", + "version": "1.3.8.1" + }, + { + "cabal_sha256": "348778ae5f77f946e45b88c6c94b3a65c655954e5f07f6d7dfa6c99efde5248c", + "component": "exe:alex", + "flags": [], + "package": "alex", + "revision": 0, + "source": "hackage", + "src_sha256": "caed9f23b4bc1cdd6f8083b79a0bb86ba86ed81ab9a1238fe0e13ed544809fed", + "version": "3.5.0.0" + }, + { + "cabal_sha256": "81f468c1c75fd6535152ab69b2d32ac6cfcc03e345267b069abe4da56ec95801", + "component": "lib:binary", + "flags": [], + "package": "binary", + "revision": 0, + "source": "hackage", + "src_sha256": "ac21ca63452dfc9b0bcab87c57699c531d87f7a9bcb6230ca46fba1b7faeebc0", + "version": "0.8.9.1" + }, + { + "cabal_sha256": "471b9a22f88b1d51bc343e7d1db7bf88b84e1582eb6d5fbe643fe7afc683c256", + "component": "lib:text", + "flags": [ + "-developer", + "+simdutf" + ], + "package": "text", + "revision": 0, + "source": "hackage", + "src_sha256": "cbe65b04a28a96a1de364d19c5ee33dc63cd253aa2716d22ceb8496b2062b6c8", + "version": "2.1" + }, + { + "cabal_sha256": "6cf18e59d9f1c5b40385457b82ab679dc18d3c5bd3c2c67b2f94e1e8732e6624", + "component": "lib:parsec", + "flags": [], + "package": "parsec", + "revision": 0, + "source": "hackage", + "src_sha256": "58c500bec1ec3c849c8243ddfd675a5983b17a8e5da55acea6adade5ae179d36", + "version": "3.1.17.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal-syntax", + "flags": [], + "package": "Cabal-syntax", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "8b4bce2749e4f61a440049e6088487003e8023c720e2019345e399d50888594f", + "component": "lib:process", + "flags": [], + "package": "process", + "revision": 2, + "source": "hackage", + "src_sha256": "aa5f4c4fe4974f89f5ab998c7509daa4bda3926cfb06daacd5eba892aad8a37e", + "version": "1.6.18.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal", + "flags": [], + "package": "Cabal", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "488cca2a179a5141da8f35a3a7e6699a0ef690f834f589d6b152c4947aa8fe2d", + "component": "exe:hsc2hs", + "flags": [ + "-in-ghc-tree" + ], + "package": "hsc2hs", + "revision": 1, + "source": "hackage", + "src_sha256": "6f4e34d788fe2ca7091ee0a10307ee8a7c060a1ba890f2bffad16a7d4d5cef76", + "version": "0.68.10" + }, + { + "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", + "component": "lib:network", + "flags": [ + "-devel" + ], + "package": "network", + "revision": 1, + "source": "hackage", + "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", + "version": "3.1.4.0" + }, + { + "cabal_sha256": "f5f2c679ecc1c1b83d2d68db6cc564e5c78d53425e69e1b9e36784820e122d37", + "component": "lib:th-compat", + "flags": [], + "package": "th-compat", + "revision": 4, + "source": "hackage", + "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", + "version": "0.1.4" + }, + { + "cabal_sha256": "6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588", + "component": "lib:network-uri", + "flags": [], + "package": "network-uri", + "revision": 1, + "source": "hackage", + "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", + "version": "2.6.4.2" + }, + { + "cabal_sha256": "0e37572590743e49d7a610f472e1618a594dc861410846f64d9f2347923c4f5b", + "component": "lib:HTTP", + "flags": [ + "-conduit10", + "+network-uri", + "-warn-as-error", + "-warp-tests" + ], + "package": "HTTP", + "revision": 3, + "source": "hackage", + "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", + "version": "4000.4.1" + }, + { + "cabal_sha256": "c4733d09f798fc4304e936924a1a7d9fc2425aefad6c46ad4592035254b46051", + "component": "lib:base-orphans", + "flags": [], + "package": "base-orphans", + "revision": 0, + "source": "hackage", + "src_sha256": "5bbf2da382c5b212d6a8be2f8c49edee0eba30f272a15fd32c13e6e4091ef172", + "version": "0.9.1" + }, + { + "cabal_sha256": "f3bf68acfa0df7a064a378ef2cdcfeb55e6fb96100675f4c593556dcbf3d7194", + "component": "lib:hashable", + "flags": [ + "+integer-gmp", + "-random-initial-seed" + ], + "package": "hashable", + "revision": 1, + "source": "hackage", + "src_sha256": "32efb16c2891786209b7cbe5c39df9b3a9ae51e836f1a54f646bc4602b7ab0f5", + "version": "1.4.3.0" + }, + { + "cabal_sha256": "957d5ca4496e7048e3e78f108dbdc3e391eafe60b50417486e4c28957d430b05", + "component": "lib:async", + "flags": [ + "-bench" + ], + "package": "async", + "revision": 0, + "source": "hackage", + "src_sha256": "1818473ebab9212afad2ed76297aefde5fae8b5d4404daf36939aece6a8f16f7", + "version": "2.2.5" + }, + { + "cabal_sha256": "a694e88f9ec9fc79f0b03f233d3fea592b68f70a34aac2ddb5bcaecb6562e2fd", + "component": "lib:base16-bytestring", + "flags": [], + "package": "base16-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", + "version": "1.0.2.0" + }, + { + "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", + "component": "lib:base64-bytestring", + "flags": [], + "package": "base64-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", + "version": "1.2.1.0" + }, + { + "cabal_sha256": "bac0ae8d46a04e410666b0c8081cff63f060f29157983b569ca86ddb6e6e0dc6", + "component": "lib:splitmix", + "flags": [ + "-optimised-mixer" + ], + "package": "splitmix", + "revision": 0, + "source": "hackage", + "src_sha256": "9df07a9611ef45f1b1258a0b412f4d02c920248f69d2e2ce8ccda328f7e13002", + "version": "0.1.0.5" + }, + { + "cabal_sha256": "32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867", + "component": "lib:random", + "flags": [], + "package": "random", + "revision": 0, + "source": "hackage", + "src_sha256": "790f4dc2d2327c453ff6aac7bf15399fd123d55e927935f68f84b5df42d9a4b4", + "version": "1.2.1.2" + }, + { + "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", + "component": "lib:edit-distance", + "flags": [], + "package": "edit-distance", + "revision": 1, + "source": "hackage", + "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", + "version": "0.2.2.1" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install-solver", + "flags": [ + "-debug-expensive-assertions", + "-debug-tracetree" + ], + "package": "cabal-install-solver", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "03db065161987f614a3a2bbcd16264f78e47efe231fb5bd161be2043eaf20488", + "component": "lib:cryptohash-sha256", + "flags": [ + "-exe", + "+use-cbits" + ], + "package": "cryptohash-sha256", + "revision": 3, + "source": "hackage", + "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", + "version": "0.11.102.1" + }, + { + "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", + "component": "lib:echo", + "flags": [ + "-example" + ], + "package": "echo", + "revision": 0, + "source": "hackage", + "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", + "version": "0.1.4" + }, + { + "cabal_sha256": "48383789821af5cc624498f3ee1d0939a070cda9468c0bfe63c951736be81c75", + "component": "lib:ed25519", + "flags": [ + "+no-donna", + "+test-doctests", + "+test-hlint", + "+test-properties" + ], + "package": "ed25519", + "revision": 8, + "source": "hackage", + "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", + "version": "0.0.5.0" + }, + { + "cabal_sha256": "17786545dce60c4d5783ba6125c0a6499a1abddd3d7417b15500ccd767c35f07", + "component": "lib:lukko", + "flags": [ + "+ofd-locking" + ], + "package": "lukko", + "revision": 5, + "source": "hackage", + "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", + "version": "0.1.1.3" + }, + { + "cabal_sha256": "32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e", + "component": "lib:os-string", + "flags": [], + "package": "os-string", + "revision": 0, + "source": "hackage", + "src_sha256": "0953126e962966719753c98d71f596f5fea07e100bce191b7453735a1ff2caa1", + "version": "2.0.2" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar-internal", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "13aee0a157b2362cf079a4fa0156927403aef2a9540694c9d170ac8339d17bda", + "component": "lib:zlib", + "flags": [ + "-bundled-c-zlib", + "+non-blocking-ffi", + "-pkg-config" + ], + "package": "zlib", + "revision": 0, + "source": "hackage", + "src_sha256": "7e43c205e1e1ff5a4b033086ec8cce82ab658879e977c8ba02a6701946ff7a47", + "version": "0.7.0.0" + }, + { + "cabal_sha256": "9695169282e5b1172b9595a99a955b013a2713ce53ccfcdf97d9be088fd67258", + "component": "lib:hackage-security", + "flags": [ + "+cabal-syntax", + "+lukko", + "+use-network-uri" + ], + "package": "hackage-security", + "revision": 1, + "source": "hackage", + "src_sha256": "8b925b3bb04b42e93ae60b4db1df65e263feb5642c7b0e76134e691887ed4c82", + "version": "0.6.2.4" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "lib:open-browser", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + }, + { + "cabal_sha256": "0322b2fcd1358f3355e0c8608efa60d27b14d1c9d476451dbcb9181363bd8b27", + "component": "lib:regex-base", + "flags": [], + "package": "regex-base", + "revision": 4, + "source": "hackage", + "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", + "version": "0.94.0.2" + }, + { + "cabal_sha256": "816d6acc560cb86672f347a7bef8129578dde26ed760f9e79b4976ed9bd7b9fd", + "component": "lib:regex-posix", + "flags": [ + "-_regex-posix-clib" + ], + "package": "regex-posix", + "revision": 3, + "source": "hackage", + "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", + "version": "0.96.0.1" + }, + { + "cabal_sha256": "4868265ab5760d2fdeb96625b138c8df25d41b9ee2651fa299ed019a69403045", + "component": "lib:resolv", + "flags": [], + "package": "resolv", + "revision": 3, + "source": "hackage", + "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", + "version": "0.2.0.2" + }, + { + "cabal_sha256": "8bb7261bd54bd58acfcb154be6a161fb6d0d31a1852aadc8e927d2ad2d7651d1", + "component": "lib:safe-exceptions", + "flags": [], + "package": "safe-exceptions", + "revision": 1, + "source": "hackage", + "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", + "version": "0.1.7.4" + }, + { + "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", + "component": "lib:semaphore-compat", + "flags": [], + "package": "semaphore-compat", + "revision": 1, + "source": "hackage", + "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", + "version": "1.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "exe:cabal", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "exe:example", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + } + ] } diff --git a/bootstrap/linux-9.0.2.json b/bootstrap/linux-9.0.2.json index 36613ac64ea..73c9d9c6519 100644 --- a/bootstrap/linux-9.0.2.json +++ b/bootstrap/linux-9.0.2.json @@ -1,525 +1,560 @@ { - "builtin": [ - { - "package": "rts", - "version": "1.0.2" - }, - { - "package": "ghc-prim", - "version": "0.7.0" - }, - { - "package": "ghc-bignum", - "version": "1.1" - }, - { - "package": "base", - "version": "4.15.1.0" - }, - { - "package": "array", - "version": "0.5.4.0" - }, - { - "package": "deepseq", - "version": "1.4.5.0" - }, - { - "package": "containers", - "version": "0.6.4.1" - }, - { - "package": "ghc-boot-th", - "version": "9.0.2" - }, - { - "package": "pretty", - "version": "1.1.3.6" - }, - { - "package": "template-haskell", - "version": "2.17.0.0" - }, - { - "package": "transformers", - "version": "0.5.6.2" - }, - { - "package": "mtl", - "version": "2.2.2" - }, - { - "package": "stm", - "version": "2.5.0.0" - }, - { - "package": "exceptions", - "version": "0.10.4" - }, - { - "package": "time", - "version": "1.9.3" - } - ], - "dependencies": [ - { - "cabal_sha256": "458d4794a5ced371a844e325fe539dd5fee8fe41f78b6f00e6c70920b7dd18e3", - "component": "lib:bytestring", - "flags": [], - "package": "bytestring", - "revision": 0, - "source": "hackage", - "src_sha256": "76193d39b66197107f452184597a4e458194c64731efbba1e9605550c732f7f4", - "version": "0.11.5.0" - }, - { - "cabal_sha256": "2de84756d3907308230e34fcc7c1917a73f218f6d53838618b7d5b95dd33e2c3", - "component": "lib:filepath", - "flags": [ - "-cpphs" - ], - "package": "filepath", - "revision": 0, - "source": "hackage", - "src_sha256": "82876250347c2fdf0f9de5448ce44f02539f37951b671d9a30719a6c4f96e9ad", - "version": "1.4.100.4" - }, - { - "cabal_sha256": "91cbc951a742fc2c95d5902be38fcf1b859c2891241bc353ff16154a8f7c35ae", - "component": "lib:unix", - "flags": [], - "package": "unix", - "revision": 0, - "source": "hackage", - "src_sha256": "cc287659427c80f3598c199387ba7eb7d4cc3270cbb31f75e2f677e879f26384", - "version": "2.8.1.1" - }, - { - "cabal_sha256": "e384a4831b0ac0f8908a1d99d14ce44bf9c5fe2092eec5b2c47ea072d477a493", - "component": "lib:directory", - "flags": [], - "package": "directory", - "revision": 0, - "source": "hackage", - "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", - "version": "1.3.8.1" - }, - { - "cabal_sha256": "3c9e1e6b4f2f956623375dd15b904144dd3183b28f1ce1afcce11192f6d868dd", - "component": "exe:alex", - "flags": [], - "package": "alex", - "revision": 0, - "source": "hackage", - "src_sha256": "7a1cd4e21399c40ea9372d1c03bf38698944b8437ce95cf27d1a7c262babe38e", - "version": "3.4.0.0" - }, - { - "cabal_sha256": "81f468c1c75fd6535152ab69b2d32ac6cfcc03e345267b069abe4da56ec95801", - "component": "lib:binary", - "flags": [], - "package": "binary", - "revision": 0, - "source": "hackage", - "src_sha256": "ac21ca63452dfc9b0bcab87c57699c531d87f7a9bcb6230ca46fba1b7faeebc0", - "version": "0.8.9.1" - }, - { - "cabal_sha256": "71b5fa8c64d3c1fd0a08f993463220867b08290a2256e94b0952bf0e8f5a45cc", - "component": "lib:text", - "flags": [ - "-developer", - "+simdutf" - ], - "package": "text", - "revision": 1, - "source": "hackage", - "src_sha256": "c735be650a898606ce9f2c8642bc6ac6123eea82871d5e90f92797801f59efad", - "version": "2.0.2" - }, - { - "cabal_sha256": "5769242043b01bf759b07b7efedcb19607837ee79015fcddde34645664136aed", - "component": "lib:parsec", - "flags": [], - "package": "parsec", - "revision": 0, - "source": "hackage", - "src_sha256": "a41962e5d76ea68658876735b8d5b755e0eff336b079d0a2f439c364755d1246", - "version": "3.1.16.1" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal-syntax", - "flags": [], - "package": "Cabal-syntax", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "49d8a7f372d35363011591b253cae4c8db8b9ec594590448e20b7bed7acaee98", - "component": "lib:process", - "flags": [], - "package": "process", - "revision": 0, - "source": "hackage", - "src_sha256": "4c5c454e0f5c864c79b9fabd850307b26d8ac4037e45a6a39ab87e20b583bf06", - "version": "1.6.17.0" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal", - "flags": [], - "package": "Cabal", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "115b8c34b9f83603cfd9eb8b1e2d7ac520da0a4a43d96be435f06ce01a7bc95e", - "component": "exe:hsc2hs", - "flags": [ - "-in-ghc-tree" - ], - "package": "hsc2hs", - "revision": 0, - "source": "hackage", - "src_sha256": "c95b10ce0b2c881480e35118d738dcc9cefc435ec72baa0031af81d0d4d3bc0a", - "version": "0.68.9" - }, - { - "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", - "component": "lib:network", - "flags": [ - "-devel" - ], - "package": "network", - "revision": 1, - "source": "hackage", - "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", - "version": "3.1.4.0" - }, - { - "cabal_sha256": "e5ae7c083ef3a22248558f8451669bb1c55ea8090f5908b86b9033743c161730", - "component": "lib:th-compat", - "flags": [], - "package": "th-compat", - "revision": 2, - "source": "hackage", - "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", - "version": "0.1.4" - }, - { - "cabal_sha256": "1fde59abf5d82a9666b4415bc2b2e9e33f6c1309074fda12d50410c7dbd95f3b", - "component": "lib:network-uri", - "flags": [], - "package": "network-uri", - "revision": 0, - "source": "hackage", - "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", - "version": "2.6.4.2" - }, - { - "cabal_sha256": "d9220cc1b8c1f287248d650910710b96e62e54530772e3bcd19dbdec6547f8ae", - "component": "lib:HTTP", - "flags": [ - "-conduit10", - "+network-uri", - "-warn-as-error", - "-warp-tests" - ], - "package": "HTTP", - "revision": 2, - "source": "hackage", - "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", - "version": "4000.4.1" - }, - { - "cabal_sha256": "0bdd3486d3a1bcbed0513b46af4a13ca74b395313fa5b6e0068d6b7413b76a04", - "component": "lib:base-orphans", - "flags": [], - "package": "base-orphans", - "revision": 0, - "source": "hackage", - "src_sha256": "613ed4d8241ed5a648a59ae6569a6962990bb545711d020d49fb83fa12d16e62", - "version": "0.9.0" - }, - { - "cabal_sha256": "2ef1bd3511e82ba56f7f23cd793dd2da84338a1e7c2cbea5b151417afe3baada", - "component": "lib:data-array-byte", - "flags": [], - "package": "data-array-byte", - "revision": 1, - "source": "hackage", - "src_sha256": "1bb6eca0b3e02d057fe7f4e14c81ef395216f421ab30fdaa1b18017c9c025600", - "version": "0.1.0.1" - }, - { - "cabal_sha256": "585792335d5541dba78fa8dfcb291a89cd5812a281825ff7a44afa296ab5d58a", - "component": "lib:hashable", - "flags": [ - "+integer-gmp", - "-random-initial-seed" - ], - "package": "hashable", - "revision": 1, - "source": "hackage", - "src_sha256": "1b4000ea82b81f69d46d0af4152c10c6303873510738e24cfc4767760d30e3f8", - "version": "1.4.2.0" - }, - { - "cabal_sha256": "46367dc0c8326dcbeb7b93f200b567491c2f6029bccf822b8bb26ee660397e08", - "component": "lib:async", - "flags": [ - "-bench" - ], - "package": "async", - "revision": 3, - "source": "hackage", - "src_sha256": "484df85be0e76c4fed9376451e48e1d0c6e97952ce79735b72d54297e7e0a725", - "version": "2.2.4" - }, - { - "cabal_sha256": "64abad7816ab8cabed8489e29f807b3a6f828e0b2cec0eae404323d69d36df9a", - "component": "lib:base16-bytestring", - "flags": [], - "package": "base16-bytestring", - "revision": 0, - "source": "hackage", - "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", - "version": "1.0.2.0" - }, - { - "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", - "component": "lib:base64-bytestring", - "flags": [], - "package": "base64-bytestring", - "revision": 1, - "source": "hackage", - "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", - "version": "1.2.1.0" - }, - { - "cabal_sha256": "db25c2e17967aa6b6046ab8b1b96ba3f344ca59a62b60fb6113d51ea305a3d8e", - "component": "lib:splitmix", - "flags": [ - "-optimised-mixer" - ], - "package": "splitmix", - "revision": 2, - "source": "hackage", - "src_sha256": "6d065402394e7a9117093dbb4530a21342c9b1e2ec509516c8a8d0ffed98ecaa", - "version": "0.1.0.4" - }, - { - "cabal_sha256": "dea1f11e5569332dc6c8efaad1cb301016a5587b6754943a49f9de08ae0e56d9", - "component": "lib:random", - "flags": [], - "package": "random", - "revision": 0, - "source": "hackage", - "src_sha256": "3e1272f7ed6a4d7bd1712b90143ec326fee9b225789222379fea20a9c90c9b76", - "version": "1.2.1.1" - }, - { - "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", - "component": "lib:edit-distance", - "flags": [], - "package": "edit-distance", - "revision": 1, - "source": "hackage", - "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", - "version": "0.2.2.1" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install-solver", - "flags": [ - "-debug-conflict-sets", - "-debug-expensive-assertions", - "-debug-tracetree" - ], - "package": "cabal-install-solver", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "72ce9095872eae653addca5f412ac8070d6282d8e1c8578c2237c33f2cbbf4bc", - "component": "lib:cryptohash-sha256", - "flags": [ - "-exe", - "+use-cbits" - ], - "package": "cryptohash-sha256", - "revision": 2, - "source": "hackage", - "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", - "version": "0.11.102.1" - }, - { - "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", - "component": "lib:echo", - "flags": [ - "-example" - ], - "package": "echo", - "revision": 0, - "source": "hackage", - "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", - "version": "0.1.4" - }, - { - "cabal_sha256": "3db04d7c18b9e68ba5eef3fa7eeca05e1e248958dd182290c8e6b010c81ef73e", - "component": "lib:ed25519", - "flags": [ - "+no-donna", - "+test-doctests", - "+test-hlint", - "+test-properties" - ], - "package": "ed25519", - "revision": 7, - "source": "hackage", - "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", - "version": "0.0.5.0" - }, - { - "cabal_sha256": "9ab54ee4f80bbd8a3fddd639ea142b7039ee2deb27f7df031a93de1819e34146", - "component": "lib:lukko", - "flags": [ - "+ofd-locking" - ], - "package": "lukko", - "revision": 4, - "source": "hackage", - "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", - "version": "0.1.1.3" - }, - { - "cabal_sha256": "63dbcb0f507273a8331363e4c13a1fe91f4ea0c495883cf65f314629582a2630", - "component": "lib:tar", - "flags": [ - "-old-bytestring", - "-old-time" - ], - "package": "tar", - "revision": 6, - "source": "hackage", - "src_sha256": "b384449f62b2b0aa3e6d2cb1004b8060b01f21ec93e7b63e7af6d8fad8a9f1de", - "version": "0.5.1.1" - }, - { - "cabal_sha256": "386dd93bc0352bf6ad5c6bca4dee0442b52d95b4c34e85901064f3eb05c81731", - "component": "lib:zlib", - "flags": [ - "-bundled-c-zlib", - "-non-blocking-ffi", - "-pkg-config" - ], - "package": "zlib", - "revision": 2, - "source": "hackage", - "src_sha256": "9eaa989ad4534438b5beb51c1d3a4c8f6a088fdff0b259a5394fbf39aaee04da", - "version": "0.6.3.0" - }, - { - "cabal_sha256": "2e5893334ee8967a990349a04953331b28e83bebd64d4f7cb46b71603d183d0c", - "component": "lib:hackage-security", - "flags": [ - "+base48", - "+cabal-syntax", - "+lukko", - "-mtl21", - "-old-directory", - "+use-network-uri" - ], - "package": "hackage-security", - "revision": 5, - "source": "hackage", - "src_sha256": "52ee0576971955571d846b8e6c09638f89f4f7881f4a95173e44ccc0d856a066", - "version": "0.6.2.3" - }, - { - "cabal_sha256": "3a76c313f9f75e8e0b3c103c1bff5bbaf754da30cbddedc1d5b7061d001030e0", - "component": "lib:regex-base", - "flags": [], - "package": "regex-base", - "revision": 2, - "source": "hackage", - "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", - "version": "0.94.0.2" - }, - { - "cabal_sha256": "d479ca2cc6274c15801169f83dae883c9b62b78af3c7b30ed3fbd4b4612156b8", - "component": "lib:regex-posix", - "flags": [ - "-_regex-posix-clib" - ], - "package": "regex-posix", - "revision": 2, - "source": "hackage", - "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", - "version": "0.96.0.1" - }, - { - "cabal_sha256": "a42b4a473478db92f4728f755403db232b55445e3091a957be073fc8e84e5d46", - "component": "lib:resolv", - "flags": [], - "package": "resolv", - "revision": 1, - "source": "hackage", - "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", - "version": "0.2.0.2" - }, - { - "cabal_sha256": "f4aad0eca90044cb1eba53b84f75d5fa142d25d695117730bf31178d409c4fe0", - "component": "lib:safe-exceptions", - "flags": [], - "package": "safe-exceptions", - "revision": 0, - "source": "hackage", - "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", - "version": "0.1.7.4" - }, - { - "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", - "component": "lib:semaphore-compat", - "flags": [], - "package": "semaphore-compat", - "revision": 1, - "source": "hackage", - "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", - "version": "1.0.0" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": null, - "component": "exe:cabal", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - } - ] + "builtin": [ + { + "package": "rts", + "version": "1.0.2" + }, + { + "package": "ghc-prim", + "version": "0.7.0" + }, + { + "package": "ghc-bignum", + "version": "1.1" + }, + { + "package": "base", + "version": "4.15.1.0" + }, + { + "package": "array", + "version": "0.5.4.0" + }, + { + "package": "deepseq", + "version": "1.4.5.0" + }, + { + "package": "containers", + "version": "0.6.4.1" + }, + { + "package": "ghc-boot-th", + "version": "9.0.2" + }, + { + "package": "pretty", + "version": "1.1.3.6" + }, + { + "package": "template-haskell", + "version": "2.17.0.0" + }, + { + "package": "transformers", + "version": "0.5.6.2" + }, + { + "package": "mtl", + "version": "2.2.2" + }, + { + "package": "stm", + "version": "2.5.0.0" + }, + { + "package": "exceptions", + "version": "0.10.4" + }, + { + "package": "time", + "version": "1.9.3" + } + ], + "dependencies": [ + { + "cabal_sha256": "ad89e28b2b046175698fbf542af2ce43e5d2af50aae9f48d12566b1bb3de1d3c", + "component": "lib:data-array-byte", + "flags": [], + "package": "data-array-byte", + "revision": 2, + "source": "hackage", + "src_sha256": "1bb6eca0b3e02d057fe7f4e14c81ef395216f421ab30fdaa1b18017c9c025600", + "version": "0.1.0.1" + }, + { + "cabal_sha256": "9fc077ff5b7ed2246773c3ac4370ef8822e4834d4587522b68ae551a5968fb86", + "component": "lib:bytestring", + "flags": [], + "package": "bytestring", + "revision": 0, + "source": "hackage", + "src_sha256": "a93fe5fbc8062656bd611ab1529b4879bb61411eda6529b350c7bf3aaf7dba3e", + "version": "0.12.0.2" + }, + { + "cabal_sha256": "d9e181e1acae0ac505d8b217dec3805c68554878f1e32b3d8351b9ce17061623", + "component": "lib:filepath", + "flags": [ + "-cpphs" + ], + "package": "filepath", + "revision": 0, + "source": "hackage", + "src_sha256": "337a0b5bcf0898cb7f51ff327528cf26f4ac38baed7b66b28fbdea334699d8ed", + "version": "1.4.300.1" + }, + { + "cabal_sha256": "633f15ef0bd50a16a7b5c5e86e6659fee6e4e211e098cc8bd0029f452bfcfddc", + "component": "lib:unix", + "flags": [ + "-os-string" + ], + "package": "unix", + "revision": 0, + "source": "hackage", + "src_sha256": "d70b81e242ee7e2e866118616c5b97afca9047e76bbfd51baa085a38db92857d", + "version": "2.8.5.0" + }, + { + "cabal_sha256": "bd3b0a0947a365d2da80b9f4a960a864d42ffa7a46577fdc7a0611703486a7f9", + "component": "lib:directory", + "flags": [], + "package": "directory", + "revision": 1, + "source": "hackage", + "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", + "version": "1.3.8.1" + }, + { + "cabal_sha256": "348778ae5f77f946e45b88c6c94b3a65c655954e5f07f6d7dfa6c99efde5248c", + "component": "exe:alex", + "flags": [], + "package": "alex", + "revision": 0, + "source": "hackage", + "src_sha256": "caed9f23b4bc1cdd6f8083b79a0bb86ba86ed81ab9a1238fe0e13ed544809fed", + "version": "3.5.0.0" + }, + { + "cabal_sha256": "81f468c1c75fd6535152ab69b2d32ac6cfcc03e345267b069abe4da56ec95801", + "component": "lib:binary", + "flags": [], + "package": "binary", + "revision": 0, + "source": "hackage", + "src_sha256": "ac21ca63452dfc9b0bcab87c57699c531d87f7a9bcb6230ca46fba1b7faeebc0", + "version": "0.8.9.1" + }, + { + "cabal_sha256": "471b9a22f88b1d51bc343e7d1db7bf88b84e1582eb6d5fbe643fe7afc683c256", + "component": "lib:text", + "flags": [ + "-developer", + "+simdutf" + ], + "package": "text", + "revision": 0, + "source": "hackage", + "src_sha256": "cbe65b04a28a96a1de364d19c5ee33dc63cd253aa2716d22ceb8496b2062b6c8", + "version": "2.1" + }, + { + "cabal_sha256": "6cf18e59d9f1c5b40385457b82ab679dc18d3c5bd3c2c67b2f94e1e8732e6624", + "component": "lib:parsec", + "flags": [], + "package": "parsec", + "revision": 0, + "source": "hackage", + "src_sha256": "58c500bec1ec3c849c8243ddfd675a5983b17a8e5da55acea6adade5ae179d36", + "version": "3.1.17.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal-syntax", + "flags": [], + "package": "Cabal-syntax", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "8b4bce2749e4f61a440049e6088487003e8023c720e2019345e399d50888594f", + "component": "lib:process", + "flags": [], + "package": "process", + "revision": 2, + "source": "hackage", + "src_sha256": "aa5f4c4fe4974f89f5ab998c7509daa4bda3926cfb06daacd5eba892aad8a37e", + "version": "1.6.18.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal", + "flags": [], + "package": "Cabal", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "488cca2a179a5141da8f35a3a7e6699a0ef690f834f589d6b152c4947aa8fe2d", + "component": "exe:hsc2hs", + "flags": [ + "-in-ghc-tree" + ], + "package": "hsc2hs", + "revision": 1, + "source": "hackage", + "src_sha256": "6f4e34d788fe2ca7091ee0a10307ee8a7c060a1ba890f2bffad16a7d4d5cef76", + "version": "0.68.10" + }, + { + "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", + "component": "lib:network", + "flags": [ + "-devel" + ], + "package": "network", + "revision": 1, + "source": "hackage", + "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", + "version": "3.1.4.0" + }, + { + "cabal_sha256": "f5f2c679ecc1c1b83d2d68db6cc564e5c78d53425e69e1b9e36784820e122d37", + "component": "lib:th-compat", + "flags": [], + "package": "th-compat", + "revision": 4, + "source": "hackage", + "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", + "version": "0.1.4" + }, + { + "cabal_sha256": "6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588", + "component": "lib:network-uri", + "flags": [], + "package": "network-uri", + "revision": 1, + "source": "hackage", + "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", + "version": "2.6.4.2" + }, + { + "cabal_sha256": "0e37572590743e49d7a610f472e1618a594dc861410846f64d9f2347923c4f5b", + "component": "lib:HTTP", + "flags": [ + "-conduit10", + "+network-uri", + "-warn-as-error", + "-warp-tests" + ], + "package": "HTTP", + "revision": 3, + "source": "hackage", + "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", + "version": "4000.4.1" + }, + { + "cabal_sha256": "c4733d09f798fc4304e936924a1a7d9fc2425aefad6c46ad4592035254b46051", + "component": "lib:base-orphans", + "flags": [], + "package": "base-orphans", + "revision": 0, + "source": "hackage", + "src_sha256": "5bbf2da382c5b212d6a8be2f8c49edee0eba30f272a15fd32c13e6e4091ef172", + "version": "0.9.1" + }, + { + "cabal_sha256": "f3bf68acfa0df7a064a378ef2cdcfeb55e6fb96100675f4c593556dcbf3d7194", + "component": "lib:hashable", + "flags": [ + "+integer-gmp", + "-random-initial-seed" + ], + "package": "hashable", + "revision": 1, + "source": "hackage", + "src_sha256": "32efb16c2891786209b7cbe5c39df9b3a9ae51e836f1a54f646bc4602b7ab0f5", + "version": "1.4.3.0" + }, + { + "cabal_sha256": "957d5ca4496e7048e3e78f108dbdc3e391eafe60b50417486e4c28957d430b05", + "component": "lib:async", + "flags": [ + "-bench" + ], + "package": "async", + "revision": 0, + "source": "hackage", + "src_sha256": "1818473ebab9212afad2ed76297aefde5fae8b5d4404daf36939aece6a8f16f7", + "version": "2.2.5" + }, + { + "cabal_sha256": "a694e88f9ec9fc79f0b03f233d3fea592b68f70a34aac2ddb5bcaecb6562e2fd", + "component": "lib:base16-bytestring", + "flags": [], + "package": "base16-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", + "version": "1.0.2.0" + }, + { + "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", + "component": "lib:base64-bytestring", + "flags": [], + "package": "base64-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", + "version": "1.2.1.0" + }, + { + "cabal_sha256": "bac0ae8d46a04e410666b0c8081cff63f060f29157983b569ca86ddb6e6e0dc6", + "component": "lib:splitmix", + "flags": [ + "-optimised-mixer" + ], + "package": "splitmix", + "revision": 0, + "source": "hackage", + "src_sha256": "9df07a9611ef45f1b1258a0b412f4d02c920248f69d2e2ce8ccda328f7e13002", + "version": "0.1.0.5" + }, + { + "cabal_sha256": "32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867", + "component": "lib:random", + "flags": [], + "package": "random", + "revision": 0, + "source": "hackage", + "src_sha256": "790f4dc2d2327c453ff6aac7bf15399fd123d55e927935f68f84b5df42d9a4b4", + "version": "1.2.1.2" + }, + { + "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", + "component": "lib:edit-distance", + "flags": [], + "package": "edit-distance", + "revision": 1, + "source": "hackage", + "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", + "version": "0.2.2.1" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install-solver", + "flags": [ + "-debug-expensive-assertions", + "-debug-tracetree" + ], + "package": "cabal-install-solver", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "03db065161987f614a3a2bbcd16264f78e47efe231fb5bd161be2043eaf20488", + "component": "lib:cryptohash-sha256", + "flags": [ + "-exe", + "+use-cbits" + ], + "package": "cryptohash-sha256", + "revision": 3, + "source": "hackage", + "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", + "version": "0.11.102.1" + }, + { + "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", + "component": "lib:echo", + "flags": [ + "-example" + ], + "package": "echo", + "revision": 0, + "source": "hackage", + "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", + "version": "0.1.4" + }, + { + "cabal_sha256": "48383789821af5cc624498f3ee1d0939a070cda9468c0bfe63c951736be81c75", + "component": "lib:ed25519", + "flags": [ + "+no-donna", + "+test-doctests", + "+test-hlint", + "+test-properties" + ], + "package": "ed25519", + "revision": 8, + "source": "hackage", + "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", + "version": "0.0.5.0" + }, + { + "cabal_sha256": "17786545dce60c4d5783ba6125c0a6499a1abddd3d7417b15500ccd767c35f07", + "component": "lib:lukko", + "flags": [ + "+ofd-locking" + ], + "package": "lukko", + "revision": 5, + "source": "hackage", + "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", + "version": "0.1.1.3" + }, + { + "cabal_sha256": "32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e", + "component": "lib:os-string", + "flags": [], + "package": "os-string", + "revision": 0, + "source": "hackage", + "src_sha256": "0953126e962966719753c98d71f596f5fea07e100bce191b7453735a1ff2caa1", + "version": "2.0.2" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar-internal", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "13aee0a157b2362cf079a4fa0156927403aef2a9540694c9d170ac8339d17bda", + "component": "lib:zlib", + "flags": [ + "-bundled-c-zlib", + "+non-blocking-ffi", + "-pkg-config" + ], + "package": "zlib", + "revision": 0, + "source": "hackage", + "src_sha256": "7e43c205e1e1ff5a4b033086ec8cce82ab658879e977c8ba02a6701946ff7a47", + "version": "0.7.0.0" + }, + { + "cabal_sha256": "9695169282e5b1172b9595a99a955b013a2713ce53ccfcdf97d9be088fd67258", + "component": "lib:hackage-security", + "flags": [ + "+cabal-syntax", + "+lukko", + "+use-network-uri" + ], + "package": "hackage-security", + "revision": 1, + "source": "hackage", + "src_sha256": "8b925b3bb04b42e93ae60b4db1df65e263feb5642c7b0e76134e691887ed4c82", + "version": "0.6.2.4" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "lib:open-browser", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + }, + { + "cabal_sha256": "0322b2fcd1358f3355e0c8608efa60d27b14d1c9d476451dbcb9181363bd8b27", + "component": "lib:regex-base", + "flags": [], + "package": "regex-base", + "revision": 4, + "source": "hackage", + "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", + "version": "0.94.0.2" + }, + { + "cabal_sha256": "816d6acc560cb86672f347a7bef8129578dde26ed760f9e79b4976ed9bd7b9fd", + "component": "lib:regex-posix", + "flags": [ + "-_regex-posix-clib" + ], + "package": "regex-posix", + "revision": 3, + "source": "hackage", + "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", + "version": "0.96.0.1" + }, + { + "cabal_sha256": "4868265ab5760d2fdeb96625b138c8df25d41b9ee2651fa299ed019a69403045", + "component": "lib:resolv", + "flags": [], + "package": "resolv", + "revision": 3, + "source": "hackage", + "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", + "version": "0.2.0.2" + }, + { + "cabal_sha256": "8bb7261bd54bd58acfcb154be6a161fb6d0d31a1852aadc8e927d2ad2d7651d1", + "component": "lib:safe-exceptions", + "flags": [], + "package": "safe-exceptions", + "revision": 1, + "source": "hackage", + "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", + "version": "0.1.7.4" + }, + { + "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", + "component": "lib:semaphore-compat", + "flags": [], + "package": "semaphore-compat", + "revision": 1, + "source": "hackage", + "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", + "version": "1.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "exe:cabal", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "exe:example", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + } + ] } diff --git a/bootstrap/linux-9.2.7.json b/bootstrap/linux-9.2.7.json deleted file mode 100644 index 4cc8973f751..00000000000 --- a/bootstrap/linux-9.2.7.json +++ /dev/null @@ -1,488 +0,0 @@ -{ - "builtin": [ - { - "package": "rts", - "version": "1.0.2" - }, - { - "package": "ghc-prim", - "version": "0.8.0" - }, - { - "package": "ghc-bignum", - "version": "1.2" - }, - { - "package": "base", - "version": "4.16.4.0" - }, - { - "package": "array", - "version": "0.5.4.0" - }, - { - "package": "deepseq", - "version": "1.4.6.1" - }, - { - "package": "containers", - "version": "0.6.5.1" - }, - { - "package": "ghc-boot-th", - "version": "9.2.7" - }, - { - "package": "pretty", - "version": "1.1.3.6" - }, - { - "package": "template-haskell", - "version": "2.18.0.0" - }, - { - "package": "bytestring", - "version": "0.11.4.0" - }, - { - "package": "transformers", - "version": "0.5.6.2" - }, - { - "package": "mtl", - "version": "2.2.2" - }, - { - "package": "stm", - "version": "2.5.0.2" - }, - { - "package": "exceptions", - "version": "0.10.4" - }, - { - "package": "time", - "version": "1.11.1.1" - }, - { - "package": "binary", - "version": "0.8.9.0" - }, - { - "package": "text", - "version": "1.2.5.0" - }, - { - "package": "parsec", - "version": "3.1.15.0" - } - ], - "dependencies": [ - { - "cabal_sha256": "2de84756d3907308230e34fcc7c1917a73f218f6d53838618b7d5b95dd33e2c3", - "component": "lib:filepath", - "flags": [ - "-cpphs" - ], - "package": "filepath", - "revision": 0, - "source": "hackage", - "src_sha256": "82876250347c2fdf0f9de5448ce44f02539f37951b671d9a30719a6c4f96e9ad", - "version": "1.4.100.4" - }, - { - "cabal_sha256": "91cbc951a742fc2c95d5902be38fcf1b859c2891241bc353ff16154a8f7c35ae", - "component": "lib:unix", - "flags": [], - "package": "unix", - "revision": 0, - "source": "hackage", - "src_sha256": "cc287659427c80f3598c199387ba7eb7d4cc3270cbb31f75e2f677e879f26384", - "version": "2.8.1.1" - }, - { - "cabal_sha256": "e384a4831b0ac0f8908a1d99d14ce44bf9c5fe2092eec5b2c47ea072d477a493", - "component": "lib:directory", - "flags": [], - "package": "directory", - "revision": 0, - "source": "hackage", - "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", - "version": "1.3.8.1" - }, - { - "cabal_sha256": "3c9e1e6b4f2f956623375dd15b904144dd3183b28f1ce1afcce11192f6d868dd", - "component": "exe:alex", - "flags": [], - "package": "alex", - "revision": 0, - "source": "hackage", - "src_sha256": "7a1cd4e21399c40ea9372d1c03bf38698944b8437ce95cf27d1a7c262babe38e", - "version": "3.4.0.0" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal-syntax", - "flags": [], - "package": "Cabal-syntax", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "49d8a7f372d35363011591b253cae4c8db8b9ec594590448e20b7bed7acaee98", - "component": "lib:process", - "flags": [], - "package": "process", - "revision": 0, - "source": "hackage", - "src_sha256": "4c5c454e0f5c864c79b9fabd850307b26d8ac4037e45a6a39ab87e20b583bf06", - "version": "1.6.17.0" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal", - "flags": [], - "package": "Cabal", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "115b8c34b9f83603cfd9eb8b1e2d7ac520da0a4a43d96be435f06ce01a7bc95e", - "component": "exe:hsc2hs", - "flags": [ - "-in-ghc-tree" - ], - "package": "hsc2hs", - "revision": 0, - "source": "hackage", - "src_sha256": "c95b10ce0b2c881480e35118d738dcc9cefc435ec72baa0031af81d0d4d3bc0a", - "version": "0.68.9" - }, - { - "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", - "component": "lib:network", - "flags": [ - "-devel" - ], - "package": "network", - "revision": 1, - "source": "hackage", - "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", - "version": "3.1.4.0" - }, - { - "cabal_sha256": "e5ae7c083ef3a22248558f8451669bb1c55ea8090f5908b86b9033743c161730", - "component": "lib:th-compat", - "flags": [], - "package": "th-compat", - "revision": 2, - "source": "hackage", - "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", - "version": "0.1.4" - }, - { - "cabal_sha256": "1fde59abf5d82a9666b4415bc2b2e9e33f6c1309074fda12d50410c7dbd95f3b", - "component": "lib:network-uri", - "flags": [], - "package": "network-uri", - "revision": 0, - "source": "hackage", - "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", - "version": "2.6.4.2" - }, - { - "cabal_sha256": "d9220cc1b8c1f287248d650910710b96e62e54530772e3bcd19dbdec6547f8ae", - "component": "lib:HTTP", - "flags": [ - "-conduit10", - "+network-uri", - "-warn-as-error", - "-warp-tests" - ], - "package": "HTTP", - "revision": 2, - "source": "hackage", - "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", - "version": "4000.4.1" - }, - { - "cabal_sha256": "2ef1bd3511e82ba56f7f23cd793dd2da84338a1e7c2cbea5b151417afe3baada", - "component": "lib:data-array-byte", - "flags": [], - "package": "data-array-byte", - "revision": 1, - "source": "hackage", - "src_sha256": "1bb6eca0b3e02d057fe7f4e14c81ef395216f421ab30fdaa1b18017c9c025600", - "version": "0.1.0.1" - }, - { - "cabal_sha256": "585792335d5541dba78fa8dfcb291a89cd5812a281825ff7a44afa296ab5d58a", - "component": "lib:hashable", - "flags": [ - "+integer-gmp", - "-random-initial-seed" - ], - "package": "hashable", - "revision": 1, - "source": "hackage", - "src_sha256": "1b4000ea82b81f69d46d0af4152c10c6303873510738e24cfc4767760d30e3f8", - "version": "1.4.2.0" - }, - { - "cabal_sha256": "46367dc0c8326dcbeb7b93f200b567491c2f6029bccf822b8bb26ee660397e08", - "component": "lib:async", - "flags": [ - "-bench" - ], - "package": "async", - "revision": 3, - "source": "hackage", - "src_sha256": "484df85be0e76c4fed9376451e48e1d0c6e97952ce79735b72d54297e7e0a725", - "version": "2.2.4" - }, - { - "cabal_sha256": "64abad7816ab8cabed8489e29f807b3a6f828e0b2cec0eae404323d69d36df9a", - "component": "lib:base16-bytestring", - "flags": [], - "package": "base16-bytestring", - "revision": 0, - "source": "hackage", - "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", - "version": "1.0.2.0" - }, - { - "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", - "component": "lib:base64-bytestring", - "flags": [], - "package": "base64-bytestring", - "revision": 1, - "source": "hackage", - "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", - "version": "1.2.1.0" - }, - { - "cabal_sha256": "db25c2e17967aa6b6046ab8b1b96ba3f344ca59a62b60fb6113d51ea305a3d8e", - "component": "lib:splitmix", - "flags": [ - "-optimised-mixer" - ], - "package": "splitmix", - "revision": 2, - "source": "hackage", - "src_sha256": "6d065402394e7a9117093dbb4530a21342c9b1e2ec509516c8a8d0ffed98ecaa", - "version": "0.1.0.4" - }, - { - "cabal_sha256": "dea1f11e5569332dc6c8efaad1cb301016a5587b6754943a49f9de08ae0e56d9", - "component": "lib:random", - "flags": [], - "package": "random", - "revision": 0, - "source": "hackage", - "src_sha256": "3e1272f7ed6a4d7bd1712b90143ec326fee9b225789222379fea20a9c90c9b76", - "version": "1.2.1.1" - }, - { - "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", - "component": "lib:edit-distance", - "flags": [], - "package": "edit-distance", - "revision": 1, - "source": "hackage", - "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", - "version": "0.2.2.1" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install-solver", - "flags": [ - "-debug-conflict-sets", - "-debug-expensive-assertions", - "-debug-tracetree" - ], - "package": "cabal-install-solver", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "72ce9095872eae653addca5f412ac8070d6282d8e1c8578c2237c33f2cbbf4bc", - "component": "lib:cryptohash-sha256", - "flags": [ - "-exe", - "+use-cbits" - ], - "package": "cryptohash-sha256", - "revision": 2, - "source": "hackage", - "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", - "version": "0.11.102.1" - }, - { - "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", - "component": "lib:echo", - "flags": [ - "-example" - ], - "package": "echo", - "revision": 0, - "source": "hackage", - "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", - "version": "0.1.4" - }, - { - "cabal_sha256": "3db04d7c18b9e68ba5eef3fa7eeca05e1e248958dd182290c8e6b010c81ef73e", - "component": "lib:ed25519", - "flags": [ - "+no-donna", - "+test-doctests", - "+test-hlint", - "+test-properties" - ], - "package": "ed25519", - "revision": 7, - "source": "hackage", - "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", - "version": "0.0.5.0" - }, - { - "cabal_sha256": "9ab54ee4f80bbd8a3fddd639ea142b7039ee2deb27f7df031a93de1819e34146", - "component": "lib:lukko", - "flags": [ - "+ofd-locking" - ], - "package": "lukko", - "revision": 4, - "source": "hackage", - "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", - "version": "0.1.1.3" - }, - { - "cabal_sha256": "63dbcb0f507273a8331363e4c13a1fe91f4ea0c495883cf65f314629582a2630", - "component": "lib:tar", - "flags": [ - "-old-bytestring", - "-old-time" - ], - "package": "tar", - "revision": 6, - "source": "hackage", - "src_sha256": "b384449f62b2b0aa3e6d2cb1004b8060b01f21ec93e7b63e7af6d8fad8a9f1de", - "version": "0.5.1.1" - }, - { - "cabal_sha256": "386dd93bc0352bf6ad5c6bca4dee0442b52d95b4c34e85901064f3eb05c81731", - "component": "lib:zlib", - "flags": [ - "-bundled-c-zlib", - "-non-blocking-ffi", - "-pkg-config" - ], - "package": "zlib", - "revision": 2, - "source": "hackage", - "src_sha256": "9eaa989ad4534438b5beb51c1d3a4c8f6a088fdff0b259a5394fbf39aaee04da", - "version": "0.6.3.0" - }, - { - "cabal_sha256": "2e5893334ee8967a990349a04953331b28e83bebd64d4f7cb46b71603d183d0c", - "component": "lib:hackage-security", - "flags": [ - "+base48", - "+cabal-syntax", - "+lukko", - "-mtl21", - "-old-directory", - "+use-network-uri" - ], - "package": "hackage-security", - "revision": 5, - "source": "hackage", - "src_sha256": "52ee0576971955571d846b8e6c09638f89f4f7881f4a95173e44ccc0d856a066", - "version": "0.6.2.3" - }, - { - "cabal_sha256": "3a76c313f9f75e8e0b3c103c1bff5bbaf754da30cbddedc1d5b7061d001030e0", - "component": "lib:regex-base", - "flags": [], - "package": "regex-base", - "revision": 2, - "source": "hackage", - "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", - "version": "0.94.0.2" - }, - { - "cabal_sha256": "d479ca2cc6274c15801169f83dae883c9b62b78af3c7b30ed3fbd4b4612156b8", - "component": "lib:regex-posix", - "flags": [ - "-_regex-posix-clib" - ], - "package": "regex-posix", - "revision": 2, - "source": "hackage", - "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", - "version": "0.96.0.1" - }, - { - "cabal_sha256": "a42b4a473478db92f4728f755403db232b55445e3091a957be073fc8e84e5d46", - "component": "lib:resolv", - "flags": [], - "package": "resolv", - "revision": 1, - "source": "hackage", - "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", - "version": "0.2.0.2" - }, - { - "cabal_sha256": "f4aad0eca90044cb1eba53b84f75d5fa142d25d695117730bf31178d409c4fe0", - "component": "lib:safe-exceptions", - "flags": [], - "package": "safe-exceptions", - "revision": 0, - "source": "hackage", - "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", - "version": "0.1.7.4" - }, - { - "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", - "component": "lib:semaphore-compat", - "flags": [], - "package": "semaphore-compat", - "revision": 1, - "source": "hackage", - "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", - "version": "1.0.0" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": null, - "component": "exe:cabal", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - } - ] -} diff --git a/bootstrap/linux-9.2.8.json b/bootstrap/linux-9.2.8.json new file mode 100644 index 00000000000..d21f90ac673 --- /dev/null +++ b/bootstrap/linux-9.2.8.json @@ -0,0 +1,523 @@ +{ + "builtin": [ + { + "package": "rts", + "version": "1.0.2" + }, + { + "package": "ghc-prim", + "version": "0.8.0" + }, + { + "package": "ghc-bignum", + "version": "1.2" + }, + { + "package": "base", + "version": "4.16.4.0" + }, + { + "package": "array", + "version": "0.5.4.0" + }, + { + "package": "deepseq", + "version": "1.4.6.1" + }, + { + "package": "containers", + "version": "0.6.5.1" + }, + { + "package": "ghc-boot-th", + "version": "9.2.8" + }, + { + "package": "pretty", + "version": "1.1.3.6" + }, + { + "package": "template-haskell", + "version": "2.18.0.0" + }, + { + "package": "bytestring", + "version": "0.11.4.0" + }, + { + "package": "transformers", + "version": "0.5.6.2" + }, + { + "package": "mtl", + "version": "2.2.2" + }, + { + "package": "stm", + "version": "2.5.0.2" + }, + { + "package": "exceptions", + "version": "0.10.4" + }, + { + "package": "time", + "version": "1.11.1.1" + }, + { + "package": "binary", + "version": "0.8.9.0" + }, + { + "package": "text", + "version": "1.2.5.0" + }, + { + "package": "parsec", + "version": "3.1.15.0" + } + ], + "dependencies": [ + { + "cabal_sha256": "d9e181e1acae0ac505d8b217dec3805c68554878f1e32b3d8351b9ce17061623", + "component": "lib:filepath", + "flags": [ + "-cpphs" + ], + "package": "filepath", + "revision": 0, + "source": "hackage", + "src_sha256": "337a0b5bcf0898cb7f51ff327528cf26f4ac38baed7b66b28fbdea334699d8ed", + "version": "1.4.300.1" + }, + { + "cabal_sha256": "633f15ef0bd50a16a7b5c5e86e6659fee6e4e211e098cc8bd0029f452bfcfddc", + "component": "lib:unix", + "flags": [ + "-os-string" + ], + "package": "unix", + "revision": 0, + "source": "hackage", + "src_sha256": "d70b81e242ee7e2e866118616c5b97afca9047e76bbfd51baa085a38db92857d", + "version": "2.8.5.0" + }, + { + "cabal_sha256": "bd3b0a0947a365d2da80b9f4a960a864d42ffa7a46577fdc7a0611703486a7f9", + "component": "lib:directory", + "flags": [], + "package": "directory", + "revision": 1, + "source": "hackage", + "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", + "version": "1.3.8.1" + }, + { + "cabal_sha256": "348778ae5f77f946e45b88c6c94b3a65c655954e5f07f6d7dfa6c99efde5248c", + "component": "exe:alex", + "flags": [], + "package": "alex", + "revision": 0, + "source": "hackage", + "src_sha256": "caed9f23b4bc1cdd6f8083b79a0bb86ba86ed81ab9a1238fe0e13ed544809fed", + "version": "3.5.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal-syntax", + "flags": [], + "package": "Cabal-syntax", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "8b4bce2749e4f61a440049e6088487003e8023c720e2019345e399d50888594f", + "component": "lib:process", + "flags": [], + "package": "process", + "revision": 2, + "source": "hackage", + "src_sha256": "aa5f4c4fe4974f89f5ab998c7509daa4bda3926cfb06daacd5eba892aad8a37e", + "version": "1.6.18.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal", + "flags": [], + "package": "Cabal", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "488cca2a179a5141da8f35a3a7e6699a0ef690f834f589d6b152c4947aa8fe2d", + "component": "exe:hsc2hs", + "flags": [ + "-in-ghc-tree" + ], + "package": "hsc2hs", + "revision": 1, + "source": "hackage", + "src_sha256": "6f4e34d788fe2ca7091ee0a10307ee8a7c060a1ba890f2bffad16a7d4d5cef76", + "version": "0.68.10" + }, + { + "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", + "component": "lib:network", + "flags": [ + "-devel" + ], + "package": "network", + "revision": 1, + "source": "hackage", + "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", + "version": "3.1.4.0" + }, + { + "cabal_sha256": "f5f2c679ecc1c1b83d2d68db6cc564e5c78d53425e69e1b9e36784820e122d37", + "component": "lib:th-compat", + "flags": [], + "package": "th-compat", + "revision": 4, + "source": "hackage", + "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", + "version": "0.1.4" + }, + { + "cabal_sha256": "6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588", + "component": "lib:network-uri", + "flags": [], + "package": "network-uri", + "revision": 1, + "source": "hackage", + "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", + "version": "2.6.4.2" + }, + { + "cabal_sha256": "0e37572590743e49d7a610f472e1618a594dc861410846f64d9f2347923c4f5b", + "component": "lib:HTTP", + "flags": [ + "-conduit10", + "+network-uri", + "-warn-as-error", + "-warp-tests" + ], + "package": "HTTP", + "revision": 3, + "source": "hackage", + "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", + "version": "4000.4.1" + }, + { + "cabal_sha256": "ad89e28b2b046175698fbf542af2ce43e5d2af50aae9f48d12566b1bb3de1d3c", + "component": "lib:data-array-byte", + "flags": [], + "package": "data-array-byte", + "revision": 2, + "source": "hackage", + "src_sha256": "1bb6eca0b3e02d057fe7f4e14c81ef395216f421ab30fdaa1b18017c9c025600", + "version": "0.1.0.1" + }, + { + "cabal_sha256": "f3bf68acfa0df7a064a378ef2cdcfeb55e6fb96100675f4c593556dcbf3d7194", + "component": "lib:hashable", + "flags": [ + "+integer-gmp", + "-random-initial-seed" + ], + "package": "hashable", + "revision": 1, + "source": "hackage", + "src_sha256": "32efb16c2891786209b7cbe5c39df9b3a9ae51e836f1a54f646bc4602b7ab0f5", + "version": "1.4.3.0" + }, + { + "cabal_sha256": "957d5ca4496e7048e3e78f108dbdc3e391eafe60b50417486e4c28957d430b05", + "component": "lib:async", + "flags": [ + "-bench" + ], + "package": "async", + "revision": 0, + "source": "hackage", + "src_sha256": "1818473ebab9212afad2ed76297aefde5fae8b5d4404daf36939aece6a8f16f7", + "version": "2.2.5" + }, + { + "cabal_sha256": "a694e88f9ec9fc79f0b03f233d3fea592b68f70a34aac2ddb5bcaecb6562e2fd", + "component": "lib:base16-bytestring", + "flags": [], + "package": "base16-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", + "version": "1.0.2.0" + }, + { + "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", + "component": "lib:base64-bytestring", + "flags": [], + "package": "base64-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", + "version": "1.2.1.0" + }, + { + "cabal_sha256": "bac0ae8d46a04e410666b0c8081cff63f060f29157983b569ca86ddb6e6e0dc6", + "component": "lib:splitmix", + "flags": [ + "-optimised-mixer" + ], + "package": "splitmix", + "revision": 0, + "source": "hackage", + "src_sha256": "9df07a9611ef45f1b1258a0b412f4d02c920248f69d2e2ce8ccda328f7e13002", + "version": "0.1.0.5" + }, + { + "cabal_sha256": "32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867", + "component": "lib:random", + "flags": [], + "package": "random", + "revision": 0, + "source": "hackage", + "src_sha256": "790f4dc2d2327c453ff6aac7bf15399fd123d55e927935f68f84b5df42d9a4b4", + "version": "1.2.1.2" + }, + { + "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", + "component": "lib:edit-distance", + "flags": [], + "package": "edit-distance", + "revision": 1, + "source": "hackage", + "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", + "version": "0.2.2.1" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install-solver", + "flags": [ + "-debug-expensive-assertions", + "-debug-tracetree" + ], + "package": "cabal-install-solver", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "03db065161987f614a3a2bbcd16264f78e47efe231fb5bd161be2043eaf20488", + "component": "lib:cryptohash-sha256", + "flags": [ + "-exe", + "+use-cbits" + ], + "package": "cryptohash-sha256", + "revision": 3, + "source": "hackage", + "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", + "version": "0.11.102.1" + }, + { + "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", + "component": "lib:echo", + "flags": [ + "-example" + ], + "package": "echo", + "revision": 0, + "source": "hackage", + "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", + "version": "0.1.4" + }, + { + "cabal_sha256": "48383789821af5cc624498f3ee1d0939a070cda9468c0bfe63c951736be81c75", + "component": "lib:ed25519", + "flags": [ + "+no-donna", + "+test-doctests", + "+test-hlint", + "+test-properties" + ], + "package": "ed25519", + "revision": 8, + "source": "hackage", + "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", + "version": "0.0.5.0" + }, + { + "cabal_sha256": "17786545dce60c4d5783ba6125c0a6499a1abddd3d7417b15500ccd767c35f07", + "component": "lib:lukko", + "flags": [ + "+ofd-locking" + ], + "package": "lukko", + "revision": 5, + "source": "hackage", + "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", + "version": "0.1.1.3" + }, + { + "cabal_sha256": "32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e", + "component": "lib:os-string", + "flags": [], + "package": "os-string", + "revision": 0, + "source": "hackage", + "src_sha256": "0953126e962966719753c98d71f596f5fea07e100bce191b7453735a1ff2caa1", + "version": "2.0.2" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar-internal", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "13aee0a157b2362cf079a4fa0156927403aef2a9540694c9d170ac8339d17bda", + "component": "lib:zlib", + "flags": [ + "-bundled-c-zlib", + "+non-blocking-ffi", + "-pkg-config" + ], + "package": "zlib", + "revision": 0, + "source": "hackage", + "src_sha256": "7e43c205e1e1ff5a4b033086ec8cce82ab658879e977c8ba02a6701946ff7a47", + "version": "0.7.0.0" + }, + { + "cabal_sha256": "9695169282e5b1172b9595a99a955b013a2713ce53ccfcdf97d9be088fd67258", + "component": "lib:hackage-security", + "flags": [ + "+cabal-syntax", + "+lukko", + "+use-network-uri" + ], + "package": "hackage-security", + "revision": 1, + "source": "hackage", + "src_sha256": "8b925b3bb04b42e93ae60b4db1df65e263feb5642c7b0e76134e691887ed4c82", + "version": "0.6.2.4" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "lib:open-browser", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + }, + { + "cabal_sha256": "0322b2fcd1358f3355e0c8608efa60d27b14d1c9d476451dbcb9181363bd8b27", + "component": "lib:regex-base", + "flags": [], + "package": "regex-base", + "revision": 4, + "source": "hackage", + "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", + "version": "0.94.0.2" + }, + { + "cabal_sha256": "816d6acc560cb86672f347a7bef8129578dde26ed760f9e79b4976ed9bd7b9fd", + "component": "lib:regex-posix", + "flags": [ + "-_regex-posix-clib" + ], + "package": "regex-posix", + "revision": 3, + "source": "hackage", + "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", + "version": "0.96.0.1" + }, + { + "cabal_sha256": "4868265ab5760d2fdeb96625b138c8df25d41b9ee2651fa299ed019a69403045", + "component": "lib:resolv", + "flags": [], + "package": "resolv", + "revision": 3, + "source": "hackage", + "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", + "version": "0.2.0.2" + }, + { + "cabal_sha256": "8bb7261bd54bd58acfcb154be6a161fb6d0d31a1852aadc8e927d2ad2d7651d1", + "component": "lib:safe-exceptions", + "flags": [], + "package": "safe-exceptions", + "revision": 1, + "source": "hackage", + "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", + "version": "0.1.7.4" + }, + { + "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", + "component": "lib:semaphore-compat", + "flags": [], + "package": "semaphore-compat", + "revision": 1, + "source": "hackage", + "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", + "version": "1.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "exe:cabal", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "exe:example", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + } + ] +} diff --git a/bootstrap/linux-9.4.4.json b/bootstrap/linux-9.4.4.json deleted file mode 100644 index af00acf12af..00000000000 --- a/bootstrap/linux-9.4.4.json +++ /dev/null @@ -1,478 +0,0 @@ -{ - "builtin": [ - { - "package": "rts", - "version": "1.0.2" - }, - { - "package": "ghc-prim", - "version": "0.9.0" - }, - { - "package": "ghc-bignum", - "version": "1.3" - }, - { - "package": "base", - "version": "4.17.0.0" - }, - { - "package": "array", - "version": "0.5.4.0" - }, - { - "package": "deepseq", - "version": "1.4.8.0" - }, - { - "package": "ghc-boot-th", - "version": "9.4.4" - }, - { - "package": "pretty", - "version": "1.1.3.6" - }, - { - "package": "template-haskell", - "version": "2.19.0.0" - }, - { - "package": "containers", - "version": "0.6.6" - }, - { - "package": "bytestring", - "version": "0.11.3.1" - }, - { - "package": "transformers", - "version": "0.5.6.2" - }, - { - "package": "mtl", - "version": "2.2.2" - }, - { - "package": "stm", - "version": "2.5.1.0" - }, - { - "package": "exceptions", - "version": "0.10.5" - }, - { - "package": "time", - "version": "1.12.2" - }, - { - "package": "binary", - "version": "0.8.9.1" - }, - { - "package": "text", - "version": "2.0.1" - }, - { - "package": "parsec", - "version": "3.1.15.0" - } - ], - "dependencies": [ - { - "cabal_sha256": "2de84756d3907308230e34fcc7c1917a73f218f6d53838618b7d5b95dd33e2c3", - "component": "lib:filepath", - "flags": [ - "-cpphs" - ], - "package": "filepath", - "revision": 0, - "source": "hackage", - "src_sha256": "82876250347c2fdf0f9de5448ce44f02539f37951b671d9a30719a6c4f96e9ad", - "version": "1.4.100.4" - }, - { - "cabal_sha256": "91cbc951a742fc2c95d5902be38fcf1b859c2891241bc353ff16154a8f7c35ae", - "component": "lib:unix", - "flags": [], - "package": "unix", - "revision": 0, - "source": "hackage", - "src_sha256": "cc287659427c80f3598c199387ba7eb7d4cc3270cbb31f75e2f677e879f26384", - "version": "2.8.1.1" - }, - { - "cabal_sha256": "e384a4831b0ac0f8908a1d99d14ce44bf9c5fe2092eec5b2c47ea072d477a493", - "component": "lib:directory", - "flags": [], - "package": "directory", - "revision": 0, - "source": "hackage", - "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", - "version": "1.3.8.1" - }, - { - "cabal_sha256": "3c9e1e6b4f2f956623375dd15b904144dd3183b28f1ce1afcce11192f6d868dd", - "component": "exe:alex", - "flags": [], - "package": "alex", - "revision": 0, - "source": "hackage", - "src_sha256": "7a1cd4e21399c40ea9372d1c03bf38698944b8437ce95cf27d1a7c262babe38e", - "version": "3.4.0.0" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal-syntax", - "flags": [], - "package": "Cabal-syntax", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "49d8a7f372d35363011591b253cae4c8db8b9ec594590448e20b7bed7acaee98", - "component": "lib:process", - "flags": [], - "package": "process", - "revision": 0, - "source": "hackage", - "src_sha256": "4c5c454e0f5c864c79b9fabd850307b26d8ac4037e45a6a39ab87e20b583bf06", - "version": "1.6.17.0" - }, - { - "cabal_sha256": null, - "component": "lib:Cabal", - "flags": [], - "package": "Cabal", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "115b8c34b9f83603cfd9eb8b1e2d7ac520da0a4a43d96be435f06ce01a7bc95e", - "component": "exe:hsc2hs", - "flags": [ - "-in-ghc-tree" - ], - "package": "hsc2hs", - "revision": 0, - "source": "hackage", - "src_sha256": "c95b10ce0b2c881480e35118d738dcc9cefc435ec72baa0031af81d0d4d3bc0a", - "version": "0.68.9" - }, - { - "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", - "component": "lib:network", - "flags": [ - "-devel" - ], - "package": "network", - "revision": 1, - "source": "hackage", - "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", - "version": "3.1.4.0" - }, - { - "cabal_sha256": "e5ae7c083ef3a22248558f8451669bb1c55ea8090f5908b86b9033743c161730", - "component": "lib:th-compat", - "flags": [], - "package": "th-compat", - "revision": 2, - "source": "hackage", - "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", - "version": "0.1.4" - }, - { - "cabal_sha256": "1fde59abf5d82a9666b4415bc2b2e9e33f6c1309074fda12d50410c7dbd95f3b", - "component": "lib:network-uri", - "flags": [], - "package": "network-uri", - "revision": 0, - "source": "hackage", - "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", - "version": "2.6.4.2" - }, - { - "cabal_sha256": "d9220cc1b8c1f287248d650910710b96e62e54530772e3bcd19dbdec6547f8ae", - "component": "lib:HTTP", - "flags": [ - "-conduit10", - "+network-uri", - "-warn-as-error", - "-warp-tests" - ], - "package": "HTTP", - "revision": 2, - "source": "hackage", - "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", - "version": "4000.4.1" - }, - { - "cabal_sha256": "585792335d5541dba78fa8dfcb291a89cd5812a281825ff7a44afa296ab5d58a", - "component": "lib:hashable", - "flags": [ - "+integer-gmp", - "-random-initial-seed" - ], - "package": "hashable", - "revision": 1, - "source": "hackage", - "src_sha256": "1b4000ea82b81f69d46d0af4152c10c6303873510738e24cfc4767760d30e3f8", - "version": "1.4.2.0" - }, - { - "cabal_sha256": "46367dc0c8326dcbeb7b93f200b567491c2f6029bccf822b8bb26ee660397e08", - "component": "lib:async", - "flags": [ - "-bench" - ], - "package": "async", - "revision": 3, - "source": "hackage", - "src_sha256": "484df85be0e76c4fed9376451e48e1d0c6e97952ce79735b72d54297e7e0a725", - "version": "2.2.4" - }, - { - "cabal_sha256": "64abad7816ab8cabed8489e29f807b3a6f828e0b2cec0eae404323d69d36df9a", - "component": "lib:base16-bytestring", - "flags": [], - "package": "base16-bytestring", - "revision": 0, - "source": "hackage", - "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", - "version": "1.0.2.0" - }, - { - "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", - "component": "lib:base64-bytestring", - "flags": [], - "package": "base64-bytestring", - "revision": 1, - "source": "hackage", - "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", - "version": "1.2.1.0" - }, - { - "cabal_sha256": "db25c2e17967aa6b6046ab8b1b96ba3f344ca59a62b60fb6113d51ea305a3d8e", - "component": "lib:splitmix", - "flags": [ - "-optimised-mixer" - ], - "package": "splitmix", - "revision": 2, - "source": "hackage", - "src_sha256": "6d065402394e7a9117093dbb4530a21342c9b1e2ec509516c8a8d0ffed98ecaa", - "version": "0.1.0.4" - }, - { - "cabal_sha256": "dea1f11e5569332dc6c8efaad1cb301016a5587b6754943a49f9de08ae0e56d9", - "component": "lib:random", - "flags": [], - "package": "random", - "revision": 0, - "source": "hackage", - "src_sha256": "3e1272f7ed6a4d7bd1712b90143ec326fee9b225789222379fea20a9c90c9b76", - "version": "1.2.1.1" - }, - { - "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", - "component": "lib:edit-distance", - "flags": [], - "package": "edit-distance", - "revision": 1, - "source": "hackage", - "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", - "version": "0.2.2.1" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install-solver", - "flags": [ - "-debug-conflict-sets", - "-debug-expensive-assertions", - "-debug-tracetree" - ], - "package": "cabal-install-solver", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": "72ce9095872eae653addca5f412ac8070d6282d8e1c8578c2237c33f2cbbf4bc", - "component": "lib:cryptohash-sha256", - "flags": [ - "-exe", - "+use-cbits" - ], - "package": "cryptohash-sha256", - "revision": 2, - "source": "hackage", - "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", - "version": "0.11.102.1" - }, - { - "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", - "component": "lib:echo", - "flags": [ - "-example" - ], - "package": "echo", - "revision": 0, - "source": "hackage", - "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", - "version": "0.1.4" - }, - { - "cabal_sha256": "3db04d7c18b9e68ba5eef3fa7eeca05e1e248958dd182290c8e6b010c81ef73e", - "component": "lib:ed25519", - "flags": [ - "+no-donna", - "+test-doctests", - "+test-hlint", - "+test-properties" - ], - "package": "ed25519", - "revision": 7, - "source": "hackage", - "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", - "version": "0.0.5.0" - }, - { - "cabal_sha256": "9ab54ee4f80bbd8a3fddd639ea142b7039ee2deb27f7df031a93de1819e34146", - "component": "lib:lukko", - "flags": [ - "+ofd-locking" - ], - "package": "lukko", - "revision": 4, - "source": "hackage", - "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", - "version": "0.1.1.3" - }, - { - "cabal_sha256": "63dbcb0f507273a8331363e4c13a1fe91f4ea0c495883cf65f314629582a2630", - "component": "lib:tar", - "flags": [ - "-old-bytestring", - "-old-time" - ], - "package": "tar", - "revision": 6, - "source": "hackage", - "src_sha256": "b384449f62b2b0aa3e6d2cb1004b8060b01f21ec93e7b63e7af6d8fad8a9f1de", - "version": "0.5.1.1" - }, - { - "cabal_sha256": "386dd93bc0352bf6ad5c6bca4dee0442b52d95b4c34e85901064f3eb05c81731", - "component": "lib:zlib", - "flags": [ - "-bundled-c-zlib", - "-non-blocking-ffi", - "-pkg-config" - ], - "package": "zlib", - "revision": 2, - "source": "hackage", - "src_sha256": "9eaa989ad4534438b5beb51c1d3a4c8f6a088fdff0b259a5394fbf39aaee04da", - "version": "0.6.3.0" - }, - { - "cabal_sha256": "2e5893334ee8967a990349a04953331b28e83bebd64d4f7cb46b71603d183d0c", - "component": "lib:hackage-security", - "flags": [ - "+base48", - "+cabal-syntax", - "+lukko", - "-mtl21", - "-old-directory", - "+use-network-uri" - ], - "package": "hackage-security", - "revision": 5, - "source": "hackage", - "src_sha256": "52ee0576971955571d846b8e6c09638f89f4f7881f4a95173e44ccc0d856a066", - "version": "0.6.2.3" - }, - { - "cabal_sha256": "3a76c313f9f75e8e0b3c103c1bff5bbaf754da30cbddedc1d5b7061d001030e0", - "component": "lib:regex-base", - "flags": [], - "package": "regex-base", - "revision": 2, - "source": "hackage", - "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", - "version": "0.94.0.2" - }, - { - "cabal_sha256": "d479ca2cc6274c15801169f83dae883c9b62b78af3c7b30ed3fbd4b4612156b8", - "component": "lib:regex-posix", - "flags": [ - "-_regex-posix-clib" - ], - "package": "regex-posix", - "revision": 2, - "source": "hackage", - "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", - "version": "0.96.0.1" - }, - { - "cabal_sha256": "a42b4a473478db92f4728f755403db232b55445e3091a957be073fc8e84e5d46", - "component": "lib:resolv", - "flags": [], - "package": "resolv", - "revision": 1, - "source": "hackage", - "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", - "version": "0.2.0.2" - }, - { - "cabal_sha256": "f4aad0eca90044cb1eba53b84f75d5fa142d25d695117730bf31178d409c4fe0", - "component": "lib:safe-exceptions", - "flags": [], - "package": "safe-exceptions", - "revision": 0, - "source": "hackage", - "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", - "version": "0.1.7.4" - }, - { - "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", - "component": "lib:semaphore-compat", - "flags": [], - "package": "semaphore-compat", - "revision": 1, - "source": "hackage", - "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", - "version": "1.0.0" - }, - { - "cabal_sha256": null, - "component": "lib:cabal-install", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - }, - { - "cabal_sha256": null, - "component": "exe:cabal", - "flags": [ - "+lukko", - "+native-dns" - ], - "package": "cabal-install", - "revision": null, - "source": "local", - "src_sha256": null, - "version": "3.11.0.0" - } - ] -} diff --git a/bootstrap/linux-9.4.8.json b/bootstrap/linux-9.4.8.json new file mode 100644 index 00000000000..d7c3a2e9a2d --- /dev/null +++ b/bootstrap/linux-9.4.8.json @@ -0,0 +1,513 @@ +{ + "builtin": [ + { + "package": "rts", + "version": "1.0.2" + }, + { + "package": "ghc-prim", + "version": "0.9.1" + }, + { + "package": "ghc-bignum", + "version": "1.3" + }, + { + "package": "base", + "version": "4.17.2.1" + }, + { + "package": "array", + "version": "0.5.4.0" + }, + { + "package": "deepseq", + "version": "1.4.8.0" + }, + { + "package": "ghc-boot-th", + "version": "9.4.8" + }, + { + "package": "pretty", + "version": "1.1.3.6" + }, + { + "package": "template-haskell", + "version": "2.19.0.0" + }, + { + "package": "containers", + "version": "0.6.7" + }, + { + "package": "bytestring", + "version": "0.11.5.3" + }, + { + "package": "transformers", + "version": "0.5.6.2" + }, + { + "package": "mtl", + "version": "2.2.2" + }, + { + "package": "stm", + "version": "2.5.1.0" + }, + { + "package": "exceptions", + "version": "0.10.5" + }, + { + "package": "time", + "version": "1.12.2" + }, + { + "package": "binary", + "version": "0.8.9.1" + }, + { + "package": "text", + "version": "2.0.2" + }, + { + "package": "parsec", + "version": "3.1.16.1" + } + ], + "dependencies": [ + { + "cabal_sha256": "d9e181e1acae0ac505d8b217dec3805c68554878f1e32b3d8351b9ce17061623", + "component": "lib:filepath", + "flags": [ + "-cpphs" + ], + "package": "filepath", + "revision": 0, + "source": "hackage", + "src_sha256": "337a0b5bcf0898cb7f51ff327528cf26f4ac38baed7b66b28fbdea334699d8ed", + "version": "1.4.300.1" + }, + { + "cabal_sha256": "633f15ef0bd50a16a7b5c5e86e6659fee6e4e211e098cc8bd0029f452bfcfddc", + "component": "lib:unix", + "flags": [ + "-os-string" + ], + "package": "unix", + "revision": 0, + "source": "hackage", + "src_sha256": "d70b81e242ee7e2e866118616c5b97afca9047e76bbfd51baa085a38db92857d", + "version": "2.8.5.0" + }, + { + "cabal_sha256": "bd3b0a0947a365d2da80b9f4a960a864d42ffa7a46577fdc7a0611703486a7f9", + "component": "lib:directory", + "flags": [], + "package": "directory", + "revision": 1, + "source": "hackage", + "src_sha256": "bd8253197587d32d4553070d2de89d3817176860932b0e9ab7bb7ba3759d8e9c", + "version": "1.3.8.1" + }, + { + "cabal_sha256": "348778ae5f77f946e45b88c6c94b3a65c655954e5f07f6d7dfa6c99efde5248c", + "component": "exe:alex", + "flags": [], + "package": "alex", + "revision": 0, + "source": "hackage", + "src_sha256": "caed9f23b4bc1cdd6f8083b79a0bb86ba86ed81ab9a1238fe0e13ed544809fed", + "version": "3.5.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal-syntax", + "flags": [], + "package": "Cabal-syntax", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "8b4bce2749e4f61a440049e6088487003e8023c720e2019345e399d50888594f", + "component": "lib:process", + "flags": [], + "package": "process", + "revision": 2, + "source": "hackage", + "src_sha256": "aa5f4c4fe4974f89f5ab998c7509daa4bda3926cfb06daacd5eba892aad8a37e", + "version": "1.6.18.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal", + "flags": [], + "package": "Cabal", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "488cca2a179a5141da8f35a3a7e6699a0ef690f834f589d6b152c4947aa8fe2d", + "component": "exe:hsc2hs", + "flags": [ + "-in-ghc-tree" + ], + "package": "hsc2hs", + "revision": 1, + "source": "hackage", + "src_sha256": "6f4e34d788fe2ca7091ee0a10307ee8a7c060a1ba890f2bffad16a7d4d5cef76", + "version": "0.68.10" + }, + { + "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", + "component": "lib:network", + "flags": [ + "-devel" + ], + "package": "network", + "revision": 1, + "source": "hackage", + "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", + "version": "3.1.4.0" + }, + { + "cabal_sha256": "f5f2c679ecc1c1b83d2d68db6cc564e5c78d53425e69e1b9e36784820e122d37", + "component": "lib:th-compat", + "flags": [], + "package": "th-compat", + "revision": 4, + "source": "hackage", + "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", + "version": "0.1.4" + }, + { + "cabal_sha256": "6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588", + "component": "lib:network-uri", + "flags": [], + "package": "network-uri", + "revision": 1, + "source": "hackage", + "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", + "version": "2.6.4.2" + }, + { + "cabal_sha256": "0e37572590743e49d7a610f472e1618a594dc861410846f64d9f2347923c4f5b", + "component": "lib:HTTP", + "flags": [ + "-conduit10", + "+network-uri", + "-warn-as-error", + "-warp-tests" + ], + "package": "HTTP", + "revision": 3, + "source": "hackage", + "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", + "version": "4000.4.1" + }, + { + "cabal_sha256": "f3bf68acfa0df7a064a378ef2cdcfeb55e6fb96100675f4c593556dcbf3d7194", + "component": "lib:hashable", + "flags": [ + "+integer-gmp", + "-random-initial-seed" + ], + "package": "hashable", + "revision": 1, + "source": "hackage", + "src_sha256": "32efb16c2891786209b7cbe5c39df9b3a9ae51e836f1a54f646bc4602b7ab0f5", + "version": "1.4.3.0" + }, + { + "cabal_sha256": "957d5ca4496e7048e3e78f108dbdc3e391eafe60b50417486e4c28957d430b05", + "component": "lib:async", + "flags": [ + "-bench" + ], + "package": "async", + "revision": 0, + "source": "hackage", + "src_sha256": "1818473ebab9212afad2ed76297aefde5fae8b5d4404daf36939aece6a8f16f7", + "version": "2.2.5" + }, + { + "cabal_sha256": "a694e88f9ec9fc79f0b03f233d3fea592b68f70a34aac2ddb5bcaecb6562e2fd", + "component": "lib:base16-bytestring", + "flags": [], + "package": "base16-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", + "version": "1.0.2.0" + }, + { + "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", + "component": "lib:base64-bytestring", + "flags": [], + "package": "base64-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", + "version": "1.2.1.0" + }, + { + "cabal_sha256": "bac0ae8d46a04e410666b0c8081cff63f060f29157983b569ca86ddb6e6e0dc6", + "component": "lib:splitmix", + "flags": [ + "-optimised-mixer" + ], + "package": "splitmix", + "revision": 0, + "source": "hackage", + "src_sha256": "9df07a9611ef45f1b1258a0b412f4d02c920248f69d2e2ce8ccda328f7e13002", + "version": "0.1.0.5" + }, + { + "cabal_sha256": "32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867", + "component": "lib:random", + "flags": [], + "package": "random", + "revision": 0, + "source": "hackage", + "src_sha256": "790f4dc2d2327c453ff6aac7bf15399fd123d55e927935f68f84b5df42d9a4b4", + "version": "1.2.1.2" + }, + { + "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", + "component": "lib:edit-distance", + "flags": [], + "package": "edit-distance", + "revision": 1, + "source": "hackage", + "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", + "version": "0.2.2.1" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install-solver", + "flags": [ + "-debug-expensive-assertions", + "-debug-tracetree" + ], + "package": "cabal-install-solver", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "03db065161987f614a3a2bbcd16264f78e47efe231fb5bd161be2043eaf20488", + "component": "lib:cryptohash-sha256", + "flags": [ + "-exe", + "+use-cbits" + ], + "package": "cryptohash-sha256", + "revision": 3, + "source": "hackage", + "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", + "version": "0.11.102.1" + }, + { + "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", + "component": "lib:echo", + "flags": [ + "-example" + ], + "package": "echo", + "revision": 0, + "source": "hackage", + "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", + "version": "0.1.4" + }, + { + "cabal_sha256": "48383789821af5cc624498f3ee1d0939a070cda9468c0bfe63c951736be81c75", + "component": "lib:ed25519", + "flags": [ + "+no-donna", + "+test-doctests", + "+test-hlint", + "+test-properties" + ], + "package": "ed25519", + "revision": 8, + "source": "hackage", + "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", + "version": "0.0.5.0" + }, + { + "cabal_sha256": "17786545dce60c4d5783ba6125c0a6499a1abddd3d7417b15500ccd767c35f07", + "component": "lib:lukko", + "flags": [ + "+ofd-locking" + ], + "package": "lukko", + "revision": 5, + "source": "hackage", + "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", + "version": "0.1.1.3" + }, + { + "cabal_sha256": "32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e", + "component": "lib:os-string", + "flags": [], + "package": "os-string", + "revision": 0, + "source": "hackage", + "src_sha256": "0953126e962966719753c98d71f596f5fea07e100bce191b7453735a1ff2caa1", + "version": "2.0.2" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar-internal", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "13aee0a157b2362cf079a4fa0156927403aef2a9540694c9d170ac8339d17bda", + "component": "lib:zlib", + "flags": [ + "-bundled-c-zlib", + "+non-blocking-ffi", + "-pkg-config" + ], + "package": "zlib", + "revision": 0, + "source": "hackage", + "src_sha256": "7e43c205e1e1ff5a4b033086ec8cce82ab658879e977c8ba02a6701946ff7a47", + "version": "0.7.0.0" + }, + { + "cabal_sha256": "9695169282e5b1172b9595a99a955b013a2713ce53ccfcdf97d9be088fd67258", + "component": "lib:hackage-security", + "flags": [ + "+cabal-syntax", + "+lukko", + "+use-network-uri" + ], + "package": "hackage-security", + "revision": 1, + "source": "hackage", + "src_sha256": "8b925b3bb04b42e93ae60b4db1df65e263feb5642c7b0e76134e691887ed4c82", + "version": "0.6.2.4" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "lib:open-browser", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + }, + { + "cabal_sha256": "0322b2fcd1358f3355e0c8608efa60d27b14d1c9d476451dbcb9181363bd8b27", + "component": "lib:regex-base", + "flags": [], + "package": "regex-base", + "revision": 4, + "source": "hackage", + "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", + "version": "0.94.0.2" + }, + { + "cabal_sha256": "816d6acc560cb86672f347a7bef8129578dde26ed760f9e79b4976ed9bd7b9fd", + "component": "lib:regex-posix", + "flags": [ + "-_regex-posix-clib" + ], + "package": "regex-posix", + "revision": 3, + "source": "hackage", + "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", + "version": "0.96.0.1" + }, + { + "cabal_sha256": "4868265ab5760d2fdeb96625b138c8df25d41b9ee2651fa299ed019a69403045", + "component": "lib:resolv", + "flags": [], + "package": "resolv", + "revision": 3, + "source": "hackage", + "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", + "version": "0.2.0.2" + }, + { + "cabal_sha256": "8bb7261bd54bd58acfcb154be6a161fb6d0d31a1852aadc8e927d2ad2d7651d1", + "component": "lib:safe-exceptions", + "flags": [], + "package": "safe-exceptions", + "revision": 1, + "source": "hackage", + "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", + "version": "0.1.7.4" + }, + { + "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", + "component": "lib:semaphore-compat", + "flags": [], + "package": "semaphore-compat", + "revision": 1, + "source": "hackage", + "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", + "version": "1.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "exe:cabal", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "exe:example", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + } + ] +} diff --git a/bootstrap/linux-9.6.4.json b/bootstrap/linux-9.6.4.json new file mode 100644 index 00000000000..19c9d6d5352 --- /dev/null +++ b/bootstrap/linux-9.6.4.json @@ -0,0 +1,485 @@ +{ + "builtin": [ + { + "package": "rts", + "version": "1.0.2" + }, + { + "package": "ghc-prim", + "version": "0.10.0" + }, + { + "package": "ghc-bignum", + "version": "1.3" + }, + { + "package": "base", + "version": "4.18.2.0" + }, + { + "package": "array", + "version": "0.5.6.0" + }, + { + "package": "deepseq", + "version": "1.4.8.1" + }, + { + "package": "ghc-boot-th", + "version": "9.6.4" + }, + { + "package": "pretty", + "version": "1.1.3.6" + }, + { + "package": "template-haskell", + "version": "2.20.0.0" + }, + { + "package": "containers", + "version": "0.6.7" + }, + { + "package": "bytestring", + "version": "0.11.5.3" + }, + { + "package": "transformers", + "version": "0.6.1.0" + }, + { + "package": "mtl", + "version": "2.3.1" + }, + { + "package": "stm", + "version": "2.5.1.0" + }, + { + "package": "exceptions", + "version": "0.10.7" + }, + { + "package": "filepath", + "version": "1.4.200.1" + }, + { + "package": "time", + "version": "1.12.2" + }, + { + "package": "unix", + "version": "2.8.4.0" + }, + { + "package": "directory", + "version": "1.3.8.1" + }, + { + "package": "binary", + "version": "0.8.9.1" + }, + { + "package": "text", + "version": "2.0.2" + }, + { + "package": "parsec", + "version": "3.1.16.1" + }, + { + "package": "process", + "version": "1.6.17.0" + } + ], + "dependencies": [ + { + "cabal_sha256": "348778ae5f77f946e45b88c6c94b3a65c655954e5f07f6d7dfa6c99efde5248c", + "component": "exe:alex", + "flags": [], + "package": "alex", + "revision": 0, + "source": "hackage", + "src_sha256": "caed9f23b4bc1cdd6f8083b79a0bb86ba86ed81ab9a1238fe0e13ed544809fed", + "version": "3.5.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal-syntax", + "flags": [], + "package": "Cabal-syntax", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal", + "flags": [], + "package": "Cabal", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "488cca2a179a5141da8f35a3a7e6699a0ef690f834f589d6b152c4947aa8fe2d", + "component": "exe:hsc2hs", + "flags": [ + "-in-ghc-tree" + ], + "package": "hsc2hs", + "revision": 1, + "source": "hackage", + "src_sha256": "6f4e34d788fe2ca7091ee0a10307ee8a7c060a1ba890f2bffad16a7d4d5cef76", + "version": "0.68.10" + }, + { + "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", + "component": "lib:network", + "flags": [ + "-devel" + ], + "package": "network", + "revision": 1, + "source": "hackage", + "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", + "version": "3.1.4.0" + }, + { + "cabal_sha256": "f5f2c679ecc1c1b83d2d68db6cc564e5c78d53425e69e1b9e36784820e122d37", + "component": "lib:th-compat", + "flags": [], + "package": "th-compat", + "revision": 4, + "source": "hackage", + "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", + "version": "0.1.4" + }, + { + "cabal_sha256": "6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588", + "component": "lib:network-uri", + "flags": [], + "package": "network-uri", + "revision": 1, + "source": "hackage", + "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", + "version": "2.6.4.2" + }, + { + "cabal_sha256": "0e37572590743e49d7a610f472e1618a594dc861410846f64d9f2347923c4f5b", + "component": "lib:HTTP", + "flags": [ + "-conduit10", + "+network-uri", + "-warn-as-error", + "-warp-tests" + ], + "package": "HTTP", + "revision": 3, + "source": "hackage", + "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", + "version": "4000.4.1" + }, + { + "cabal_sha256": "f3bf68acfa0df7a064a378ef2cdcfeb55e6fb96100675f4c593556dcbf3d7194", + "component": "lib:hashable", + "flags": [ + "+integer-gmp", + "-random-initial-seed" + ], + "package": "hashable", + "revision": 1, + "source": "hackage", + "src_sha256": "32efb16c2891786209b7cbe5c39df9b3a9ae51e836f1a54f646bc4602b7ab0f5", + "version": "1.4.3.0" + }, + { + "cabal_sha256": "957d5ca4496e7048e3e78f108dbdc3e391eafe60b50417486e4c28957d430b05", + "component": "lib:async", + "flags": [ + "-bench" + ], + "package": "async", + "revision": 0, + "source": "hackage", + "src_sha256": "1818473ebab9212afad2ed76297aefde5fae8b5d4404daf36939aece6a8f16f7", + "version": "2.2.5" + }, + { + "cabal_sha256": "a694e88f9ec9fc79f0b03f233d3fea592b68f70a34aac2ddb5bcaecb6562e2fd", + "component": "lib:base16-bytestring", + "flags": [], + "package": "base16-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", + "version": "1.0.2.0" + }, + { + "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", + "component": "lib:base64-bytestring", + "flags": [], + "package": "base64-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", + "version": "1.2.1.0" + }, + { + "cabal_sha256": "bac0ae8d46a04e410666b0c8081cff63f060f29157983b569ca86ddb6e6e0dc6", + "component": "lib:splitmix", + "flags": [ + "-optimised-mixer" + ], + "package": "splitmix", + "revision": 0, + "source": "hackage", + "src_sha256": "9df07a9611ef45f1b1258a0b412f4d02c920248f69d2e2ce8ccda328f7e13002", + "version": "0.1.0.5" + }, + { + "cabal_sha256": "32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867", + "component": "lib:random", + "flags": [], + "package": "random", + "revision": 0, + "source": "hackage", + "src_sha256": "790f4dc2d2327c453ff6aac7bf15399fd123d55e927935f68f84b5df42d9a4b4", + "version": "1.2.1.2" + }, + { + "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", + "component": "lib:edit-distance", + "flags": [], + "package": "edit-distance", + "revision": 1, + "source": "hackage", + "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", + "version": "0.2.2.1" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install-solver", + "flags": [ + "-debug-expensive-assertions", + "-debug-tracetree" + ], + "package": "cabal-install-solver", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "03db065161987f614a3a2bbcd16264f78e47efe231fb5bd161be2043eaf20488", + "component": "lib:cryptohash-sha256", + "flags": [ + "-exe", + "+use-cbits" + ], + "package": "cryptohash-sha256", + "revision": 3, + "source": "hackage", + "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", + "version": "0.11.102.1" + }, + { + "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", + "component": "lib:echo", + "flags": [ + "-example" + ], + "package": "echo", + "revision": 0, + "source": "hackage", + "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", + "version": "0.1.4" + }, + { + "cabal_sha256": "48383789821af5cc624498f3ee1d0939a070cda9468c0bfe63c951736be81c75", + "component": "lib:ed25519", + "flags": [ + "+no-donna", + "+test-doctests", + "+test-hlint", + "+test-properties" + ], + "package": "ed25519", + "revision": 8, + "source": "hackage", + "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", + "version": "0.0.5.0" + }, + { + "cabal_sha256": "17786545dce60c4d5783ba6125c0a6499a1abddd3d7417b15500ccd767c35f07", + "component": "lib:lukko", + "flags": [ + "+ofd-locking" + ], + "package": "lukko", + "revision": 5, + "source": "hackage", + "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", + "version": "0.1.1.3" + }, + { + "cabal_sha256": "32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e", + "component": "lib:os-string", + "flags": [], + "package": "os-string", + "revision": 0, + "source": "hackage", + "src_sha256": "0953126e962966719753c98d71f596f5fea07e100bce191b7453735a1ff2caa1", + "version": "2.0.2" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar-internal", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "13aee0a157b2362cf079a4fa0156927403aef2a9540694c9d170ac8339d17bda", + "component": "lib:zlib", + "flags": [ + "-bundled-c-zlib", + "+non-blocking-ffi", + "-pkg-config" + ], + "package": "zlib", + "revision": 0, + "source": "hackage", + "src_sha256": "7e43c205e1e1ff5a4b033086ec8cce82ab658879e977c8ba02a6701946ff7a47", + "version": "0.7.0.0" + }, + { + "cabal_sha256": "9695169282e5b1172b9595a99a955b013a2713ce53ccfcdf97d9be088fd67258", + "component": "lib:hackage-security", + "flags": [ + "+cabal-syntax", + "+lukko", + "+use-network-uri" + ], + "package": "hackage-security", + "revision": 1, + "source": "hackage", + "src_sha256": "8b925b3bb04b42e93ae60b4db1df65e263feb5642c7b0e76134e691887ed4c82", + "version": "0.6.2.4" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "lib:open-browser", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + }, + { + "cabal_sha256": "0322b2fcd1358f3355e0c8608efa60d27b14d1c9d476451dbcb9181363bd8b27", + "component": "lib:regex-base", + "flags": [], + "package": "regex-base", + "revision": 4, + "source": "hackage", + "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", + "version": "0.94.0.2" + }, + { + "cabal_sha256": "816d6acc560cb86672f347a7bef8129578dde26ed760f9e79b4976ed9bd7b9fd", + "component": "lib:regex-posix", + "flags": [ + "-_regex-posix-clib" + ], + "package": "regex-posix", + "revision": 3, + "source": "hackage", + "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", + "version": "0.96.0.1" + }, + { + "cabal_sha256": "4868265ab5760d2fdeb96625b138c8df25d41b9ee2651fa299ed019a69403045", + "component": "lib:resolv", + "flags": [], + "package": "resolv", + "revision": 3, + "source": "hackage", + "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", + "version": "0.2.0.2" + }, + { + "cabal_sha256": "8bb7261bd54bd58acfcb154be6a161fb6d0d31a1852aadc8e927d2ad2d7651d1", + "component": "lib:safe-exceptions", + "flags": [], + "package": "safe-exceptions", + "revision": 1, + "source": "hackage", + "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", + "version": "0.1.7.4" + }, + { + "cabal_sha256": "8ed6242cab5b0e1a8c654424275ac178035d108dfe4d651053947790fcf83017", + "component": "lib:semaphore-compat", + "flags": [], + "package": "semaphore-compat", + "revision": 1, + "source": "hackage", + "src_sha256": "1c6e6fab021c2ccee5d86112fb1c0bd016d15e0cf70c489dae5fb5ec156ed9e2", + "version": "1.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "exe:cabal", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "exe:example", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + } + ] +} diff --git a/bootstrap/linux-9.8.1.json b/bootstrap/linux-9.8.1.json new file mode 100644 index 00000000000..e90e48bef62 --- /dev/null +++ b/bootstrap/linux-9.8.1.json @@ -0,0 +1,479 @@ +{ + "builtin": [ + { + "package": "rts", + "version": "1.0.2" + }, + { + "package": "ghc-prim", + "version": "0.11.0" + }, + { + "package": "ghc-bignum", + "version": "1.3" + }, + { + "package": "base", + "version": "4.19.0.0" + }, + { + "package": "array", + "version": "0.5.6.0" + }, + { + "package": "deepseq", + "version": "1.5.0.0" + }, + { + "package": "ghc-boot-th", + "version": "9.8.1" + }, + { + "package": "pretty", + "version": "1.1.3.6" + }, + { + "package": "template-haskell", + "version": "2.21.0.0" + }, + { + "package": "containers", + "version": "0.6.8" + }, + { + "package": "bytestring", + "version": "0.12.0.2" + }, + { + "package": "transformers", + "version": "0.6.1.0" + }, + { + "package": "mtl", + "version": "2.3.1" + }, + { + "package": "stm", + "version": "2.5.2.1" + }, + { + "package": "exceptions", + "version": "0.10.7" + }, + { + "package": "filepath", + "version": "1.4.100.4" + }, + { + "package": "time", + "version": "1.12.2" + }, + { + "package": "unix", + "version": "2.8.3.0" + }, + { + "package": "directory", + "version": "1.3.8.1" + }, + { + "package": "binary", + "version": "0.8.9.1" + }, + { + "package": "text", + "version": "2.1" + }, + { + "package": "parsec", + "version": "3.1.17.0" + }, + { + "package": "process", + "version": "1.6.18.0" + }, + { + "package": "semaphore-compat", + "version": "1.0.0" + } + ], + "dependencies": [ + { + "cabal_sha256": "348778ae5f77f946e45b88c6c94b3a65c655954e5f07f6d7dfa6c99efde5248c", + "component": "exe:alex", + "flags": [], + "package": "alex", + "revision": 0, + "source": "hackage", + "src_sha256": "caed9f23b4bc1cdd6f8083b79a0bb86ba86ed81ab9a1238fe0e13ed544809fed", + "version": "3.5.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal-syntax", + "flags": [], + "package": "Cabal-syntax", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "lib:Cabal", + "flags": [], + "package": "Cabal", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "488cca2a179a5141da8f35a3a7e6699a0ef690f834f589d6b152c4947aa8fe2d", + "component": "exe:hsc2hs", + "flags": [ + "-in-ghc-tree" + ], + "package": "hsc2hs", + "revision": 1, + "source": "hackage", + "src_sha256": "6f4e34d788fe2ca7091ee0a10307ee8a7c060a1ba890f2bffad16a7d4d5cef76", + "version": "0.68.10" + }, + { + "cabal_sha256": "e152cdb03243afb52bbc740cfbe96905ca298a6f6342f0c47b3f2e227ff19def", + "component": "lib:network", + "flags": [ + "-devel" + ], + "package": "network", + "revision": 1, + "source": "hackage", + "src_sha256": "b452a2afac95d9207357eb3820c719c7c7d27871ef4b6ed7bfcd03a036b9158e", + "version": "3.1.4.0" + }, + { + "cabal_sha256": "f5f2c679ecc1c1b83d2d68db6cc564e5c78d53425e69e1b9e36784820e122d37", + "component": "lib:th-compat", + "flags": [], + "package": "th-compat", + "revision": 4, + "source": "hackage", + "src_sha256": "d8f97ac14ab47b6b8a7b0fdb4ff95426322ec56badd01652ac15da4a44d4bab8", + "version": "0.1.4" + }, + { + "cabal_sha256": "6fffb57373962b5651a2db8b0af732098b3bf029a7ced76a9855615de2026588", + "component": "lib:network-uri", + "flags": [], + "package": "network-uri", + "revision": 1, + "source": "hackage", + "src_sha256": "9c188973126e893250b881f20e8811dca06c223c23402b06f7a1f2e995797228", + "version": "2.6.4.2" + }, + { + "cabal_sha256": "0e37572590743e49d7a610f472e1618a594dc861410846f64d9f2347923c4f5b", + "component": "lib:HTTP", + "flags": [ + "-conduit10", + "+network-uri", + "-warn-as-error", + "-warp-tests" + ], + "package": "HTTP", + "revision": 3, + "source": "hackage", + "src_sha256": "df31d8efec775124dab856d7177ddcba31be9f9e0836ebdab03d94392f2dd453", + "version": "4000.4.1" + }, + { + "cabal_sha256": "f3bf68acfa0df7a064a378ef2cdcfeb55e6fb96100675f4c593556dcbf3d7194", + "component": "lib:hashable", + "flags": [ + "+integer-gmp", + "-random-initial-seed" + ], + "package": "hashable", + "revision": 1, + "source": "hackage", + "src_sha256": "32efb16c2891786209b7cbe5c39df9b3a9ae51e836f1a54f646bc4602b7ab0f5", + "version": "1.4.3.0" + }, + { + "cabal_sha256": "957d5ca4496e7048e3e78f108dbdc3e391eafe60b50417486e4c28957d430b05", + "component": "lib:async", + "flags": [ + "-bench" + ], + "package": "async", + "revision": 0, + "source": "hackage", + "src_sha256": "1818473ebab9212afad2ed76297aefde5fae8b5d4404daf36939aece6a8f16f7", + "version": "2.2.5" + }, + { + "cabal_sha256": "a694e88f9ec9fc79f0b03f233d3fea592b68f70a34aac2ddb5bcaecb6562e2fd", + "component": "lib:base16-bytestring", + "flags": [], + "package": "base16-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "1d5a91143ef0e22157536093ec8e59d226a68220ec89378d5dcaeea86472c784", + "version": "1.0.2.0" + }, + { + "cabal_sha256": "45305ccf8914c66d385b518721472c7b8c858f1986945377f74f85c1e0d49803", + "component": "lib:base64-bytestring", + "flags": [], + "package": "base64-bytestring", + "revision": 1, + "source": "hackage", + "src_sha256": "fbf8ed30edde271eb605352021431d8f1b055f95a56af31fe2eacf6bdfdc49c9", + "version": "1.2.1.0" + }, + { + "cabal_sha256": "bac0ae8d46a04e410666b0c8081cff63f060f29157983b569ca86ddb6e6e0dc6", + "component": "lib:splitmix", + "flags": [ + "-optimised-mixer" + ], + "package": "splitmix", + "revision": 0, + "source": "hackage", + "src_sha256": "9df07a9611ef45f1b1258a0b412f4d02c920248f69d2e2ce8ccda328f7e13002", + "version": "0.1.0.5" + }, + { + "cabal_sha256": "32397de181e20ccaacf806ec70de9308cf044f089a2be37c936f3f8967bde867", + "component": "lib:random", + "flags": [], + "package": "random", + "revision": 0, + "source": "hackage", + "src_sha256": "790f4dc2d2327c453ff6aac7bf15399fd123d55e927935f68f84b5df42d9a4b4", + "version": "1.2.1.2" + }, + { + "cabal_sha256": "4d33a49cd383d50af090f1b888642d10116e43809f9da6023d9fc6f67d2656ee", + "component": "lib:edit-distance", + "flags": [], + "package": "edit-distance", + "revision": 1, + "source": "hackage", + "src_sha256": "3e8885ee2f56ad4da940f043ae8f981ee2fe336b5e8e4ba3f7436cff4f526c4a", + "version": "0.2.2.1" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install-solver", + "flags": [ + "-debug-expensive-assertions", + "-debug-tracetree" + ], + "package": "cabal-install-solver", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "03db065161987f614a3a2bbcd16264f78e47efe231fb5bd161be2043eaf20488", + "component": "lib:cryptohash-sha256", + "flags": [ + "-exe", + "+use-cbits" + ], + "package": "cryptohash-sha256", + "revision": 3, + "source": "hackage", + "src_sha256": "73a7dc7163871a80837495039a099967b11f5c4fe70a118277842f7a713c6bf6", + "version": "0.11.102.1" + }, + { + "cabal_sha256": "ccce771562c49a2b29a52046ca68c62179e97e8fbeacdae32ca84a85445e8f42", + "component": "lib:echo", + "flags": [ + "-example" + ], + "package": "echo", + "revision": 0, + "source": "hackage", + "src_sha256": "c9fe1bf2904825a65b667251ec644f197b71dc5c209d2d254be5de3d496b0e43", + "version": "0.1.4" + }, + { + "cabal_sha256": "48383789821af5cc624498f3ee1d0939a070cda9468c0bfe63c951736be81c75", + "component": "lib:ed25519", + "flags": [ + "+no-donna", + "+test-doctests", + "+test-hlint", + "+test-properties" + ], + "package": "ed25519", + "revision": 8, + "source": "hackage", + "src_sha256": "d8a5958ebfa9309790efade64275dc5c441b568645c45ceed1b0c6ff36d6156d", + "version": "0.0.5.0" + }, + { + "cabal_sha256": "17786545dce60c4d5783ba6125c0a6499a1abddd3d7417b15500ccd767c35f07", + "component": "lib:lukko", + "flags": [ + "+ofd-locking" + ], + "package": "lukko", + "revision": 5, + "source": "hackage", + "src_sha256": "a80efb60cfa3dae18682c01980d76d5f7e413e191cd186992e1bf7388d48ab1f", + "version": "0.1.1.3" + }, + { + "cabal_sha256": "32fa47f8345a2c0662fb602fc42e4b674e41ec48079b68bdecb4b6f68032c24e", + "component": "lib:os-string", + "flags": [], + "package": "os-string", + "revision": 0, + "source": "hackage", + "src_sha256": "0953126e962966719753c98d71f596f5fea07e100bce191b7453735a1ff2caa1", + "version": "2.0.2" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar-internal", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "3ed979ee1bb00b4e488537988ee6bb3c2c67e66678804125e2df08a527822b4e", + "component": "lib:tar", + "flags": [], + "package": "tar", + "revision": 0, + "source": "hackage", + "src_sha256": "edfef2e126440839d34f23fff7f3616d0bfffa0345ea13d4d0fee9a669d305da", + "version": "0.6.1.0" + }, + { + "cabal_sha256": "13aee0a157b2362cf079a4fa0156927403aef2a9540694c9d170ac8339d17bda", + "component": "lib:zlib", + "flags": [ + "-bundled-c-zlib", + "+non-blocking-ffi", + "-pkg-config" + ], + "package": "zlib", + "revision": 0, + "source": "hackage", + "src_sha256": "7e43c205e1e1ff5a4b033086ec8cce82ab658879e977c8ba02a6701946ff7a47", + "version": "0.7.0.0" + }, + { + "cabal_sha256": "9695169282e5b1172b9595a99a955b013a2713ce53ccfcdf97d9be088fd67258", + "component": "lib:hackage-security", + "flags": [ + "+cabal-syntax", + "+lukko", + "+use-network-uri" + ], + "package": "hackage-security", + "revision": 1, + "source": "hackage", + "src_sha256": "8b925b3bb04b42e93ae60b4db1df65e263feb5642c7b0e76134e691887ed4c82", + "version": "0.6.2.4" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "lib:open-browser", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + }, + { + "cabal_sha256": "0322b2fcd1358f3355e0c8608efa60d27b14d1c9d476451dbcb9181363bd8b27", + "component": "lib:regex-base", + "flags": [], + "package": "regex-base", + "revision": 4, + "source": "hackage", + "src_sha256": "7b99408f580f5bb67a1c413e0bc735886608251331ad36322020f2169aea2ef1", + "version": "0.94.0.2" + }, + { + "cabal_sha256": "816d6acc560cb86672f347a7bef8129578dde26ed760f9e79b4976ed9bd7b9fd", + "component": "lib:regex-posix", + "flags": [ + "-_regex-posix-clib" + ], + "package": "regex-posix", + "revision": 3, + "source": "hackage", + "src_sha256": "c7827c391919227711e1cff0a762b1678fd8739f9c902fc183041ff34f59259c", + "version": "0.96.0.1" + }, + { + "cabal_sha256": "4868265ab5760d2fdeb96625b138c8df25d41b9ee2651fa299ed019a69403045", + "component": "lib:resolv", + "flags": [], + "package": "resolv", + "revision": 3, + "source": "hackage", + "src_sha256": "880d283df9132a7375fa28670f71e86480a4f49972256dc2a204c648274ae74b", + "version": "0.2.0.2" + }, + { + "cabal_sha256": "8bb7261bd54bd58acfcb154be6a161fb6d0d31a1852aadc8e927d2ad2d7651d1", + "component": "lib:safe-exceptions", + "flags": [], + "package": "safe-exceptions", + "revision": 1, + "source": "hackage", + "src_sha256": "3c51d8d50c9b60ff8bf94f942fd92e3bea9e62c5afa778dfc9f707b79da41ef6", + "version": "0.1.7.4" + }, + { + "cabal_sha256": null, + "component": "lib:cabal-install", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": null, + "component": "exe:cabal", + "flags": [ + "+lukko", + "+native-dns" + ], + "package": "cabal-install", + "revision": null, + "source": "local", + "src_sha256": null, + "version": "3.11.0.0" + }, + { + "cabal_sha256": "e4be4a206f5ab6ddb5ae4fbb39101529196e20af5670c5d33326fea6eff886fd", + "component": "exe:example", + "flags": [], + "package": "open-browser", + "revision": 0, + "source": "hackage", + "src_sha256": "0bed2e63800f738e78a4803ed22902accb50ac02068b96c17ce83a267244ca66", + "version": "0.2.1.0" + } + ] +} diff --git a/bootstrap/src/Main.hs b/bootstrap/src/Main.hs index 8f06acba2ce..04e3bd59dd1 100644 --- a/bootstrap/src/Main.hs +++ b/bootstrap/src/Main.hs @@ -113,7 +113,7 @@ main2 meta plan = do case P.uPkgSrc unit of Just (P.RepoTarballPackage (P.RepoSecure _uri)) -> return Hackage - Just (P.LocalUnpackedPackage _path) -> + Just (P.LocalUnpackedPackage _path) -> return Local pkgsrc -> die $ "package source not supported: " ++ show pkgsrc diff --git a/buildinfo-reference-generator/buildinfo-reference-generator.cabal b/buildinfo-reference-generator/buildinfo-reference-generator.cabal index cd222b59bee..667e8346b63 100644 --- a/buildinfo-reference-generator/buildinfo-reference-generator.cabal +++ b/buildinfo-reference-generator/buildinfo-reference-generator.cabal @@ -8,7 +8,7 @@ executable buildinfo-reference-generator ghc-options: -Wall main-is: Main.hs build-depends: - , base ^>=4.12 || ^>=4.13 + , base >=4.11 && <4.20 , Cabal , Cabal-described , containers diff --git a/buildinfo-reference-generator/template.zinza b/buildinfo-reference-generator/template.zinza index 09d073d9bdc..8f05a416a8f 100644 --- a/buildinfo-reference-generator/template.zinza +++ b/buildinfo-reference-generator/template.zinza @@ -157,7 +157,7 @@ Build info fields {# We show documentation link only for non deprecated fields #} {% if null field.deprecatedSince.fst %} {% if null field.removedIn.fst %} - * Documentation of :pkg-field:`{{field.name}}` + * Documentation of :pkg-field:`library:{{field.name}}` {% endif %} {% endif %} {% if notNull field.syntax %} diff --git a/cabal-benchmarks/LICENSE b/cabal-benchmarks/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/cabal-benchmarks/LICENSE +++ b/cabal-benchmarks/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/cabal-benchmarks/bench/CabalBenchmarks.hs b/cabal-benchmarks/bench/CabalBenchmarks.hs index 4d8bbddd0fd..39580898e86 100644 --- a/cabal-benchmarks/bench/CabalBenchmarks.hs +++ b/cabal-benchmarks/bench/CabalBenchmarks.hs @@ -1,7 +1,7 @@ {-# OPTIONS_GHC -fno-warn-deprecations #-} module Main where -import Criterion.Main (bench, bgroup, defaultMain, env, nf, whnf) +import Test.Tasty.Bench (bench, bgroup, defaultMain, env, nf, whnf) import Distribution.PackageDescription.Parsec (parseGenericPackageDescriptionMaybe) import Distribution.Parsec (eitherParsec) import Distribution.Version diff --git a/cabal-benchmarks/cabal-benchmarks.cabal b/cabal-benchmarks/cabal-benchmarks.cabal index 4e911918321..2b247e565cf 100644 --- a/cabal-benchmarks/cabal-benchmarks.cabal +++ b/cabal-benchmarks/cabal-benchmarks.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: cabal-benchmarks version: 3 -copyright: 2003-2023, Cabal Development Team (see AUTHORS file) +copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team @@ -31,4 +31,4 @@ test-suite cabal-benchmarks base , bytestring , Cabal-syntax - , criterion >=1.5.6.2 && <1.6 + , tasty-bench >= 0.3.5 && < 0.4 diff --git a/cabal-dev-scripts/LICENSE b/cabal-dev-scripts/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/cabal-dev-scripts/LICENSE +++ b/cabal-dev-scripts/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/cabal-dev-scripts/cabal-dev-scripts.cabal b/cabal-dev-scripts/cabal-dev-scripts.cabal index 24e160eaa92..900908acbd2 100644 --- a/cabal-dev-scripts/cabal-dev-scripts.cabal +++ b/cabal-dev-scripts/cabal-dev-scripts.cabal @@ -17,8 +17,8 @@ executable gen-spdx hs-source-dirs: src ghc-options: -Wall build-depends: - , aeson ^>=1.4.1.0 || ^>=1.5.2.0 || ^>=2.1.1.0 - , base >=4.10 && <4.19 + , aeson ^>=1.4.1.0 || ^>=1.5.2.0 || ^>=2.2.1.0 + , base >=4.10 && <4.20 , bytestring , containers , Diff ^>=0.4 @@ -34,8 +34,8 @@ executable gen-spdx-exc hs-source-dirs: src ghc-options: -Wall build-depends: - , aeson ^>=1.4.1.0 || ^>=1.5.2.0 || ^>=2.1.1.0 - , base >=4.10 && <4.19 + , aeson ^>=1.4.1.0 || ^>=1.5.2.0 || ^>=2.2.1.0 + , base >=4.10 && <4.20 , bytestring , containers , Diff ^>=0.4 diff --git a/cabal-dev-scripts/src/GenSPDX.hs b/cabal-dev-scripts/src/GenSPDX.hs index 288a0643a9c..2de9229aa64 100644 --- a/cabal-dev-scripts/src/GenSPDX.hs +++ b/cabal-dev-scripts/src/GenSPDX.hs @@ -5,7 +5,6 @@ module Main (main) where import Control.Lens (imap) import Data.Aeson (FromJSON (..), eitherDecode, withObject, (.!=), (.:), (.:?)) import Data.List (sortOn) -import Data.Semigroup ((<>)) import Data.Text (Text) import Data.Traversable (for) diff --git a/cabal-dev-scripts/src/GenSPDXExc.hs b/cabal-dev-scripts/src/GenSPDXExc.hs index c0fa0f3861d..4e770f4ccbc 100644 --- a/cabal-dev-scripts/src/GenSPDXExc.hs +++ b/cabal-dev-scripts/src/GenSPDXExc.hs @@ -4,7 +4,6 @@ module Main (main) where import Control.Lens (imap) import Data.Aeson (FromJSON (..), eitherDecode, withObject, (.:)) import Data.List (sortOn) -import Data.Semigroup ((<>)) import Data.Text (Text) import Data.Traversable (for) diff --git a/cabal-install-solver/ChangeLog.md b/cabal-install-solver/ChangeLog.md index 7af34641df0..3bfdd653afe 100644 --- a/cabal-install-solver/ChangeLog.md +++ b/cabal-install-solver/ChangeLog.md @@ -1 +1 @@ -Please see https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.10.2.0.md +Please see https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.10.3.0.md diff --git a/cabal-install-solver/LICENSE b/cabal-install-solver/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/cabal-install-solver/LICENSE +++ b/cabal-install-solver/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/cabal-install-solver/cabal-install-solver.cabal b/cabal-install-solver/cabal-install-solver.cabal index 98f8253b102..e692c79ce88 100644 --- a/cabal-install-solver/cabal-install-solver.cabal +++ b/cabal-install-solver/cabal-install-solver.cabal @@ -11,10 +11,10 @@ license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team (see AUTHORS file) maintainer: Cabal Development Team -copyright: 2003-2023, Cabal Development Team +copyright: 2003-2024, Cabal Development Team category: Distribution build-type: Simple -Extra-Source-Files: +extra-doc-files: ChangeLog.md source-repository head @@ -27,11 +27,6 @@ flag debug-expensive-assertions default: False manual: True -flag debug-conflict-sets - description: Add additional information to ConflictSets - default: False - manual: True - flag debug-tracetree description: Compile in support for tracetree (used to debug the solver) default: False @@ -47,6 +42,7 @@ library if impl(ghc <8.8) ghc-options: -Wnoncanonical-monadfail-instances + if impl(ghc >=8.10) ghc-options: -Wunused-packages @@ -105,24 +101,21 @@ library build-depends: , array >=0.4 && <0.6 - , base >=4.10 && <4.19 + , base >=4.10 && <4.20 , bytestring >=0.10.6.0 && <0.13 , Cabal ^>=3.11 , Cabal-syntax ^>=3.11 , containers >=0.5.6.2 && <0.8 , edit-distance ^>= 0.2.2 - , filepath ^>=1.4.0.0 + , filepath ^>=1.4.0.0 || ^>=1.5.0.0 , mtl >=2.0 && <2.4 , pretty ^>=1.1 , transformers >=0.4.2.0 && <0.7 + , text (>= 1.2.3.0 && < 1.3) || (>= 2.0 && < 2.2) if flag(debug-expensive-assertions) cpp-options: -DDEBUG_EXPENSIVE_ASSERTIONS - if flag(debug-conflict-sets) - cpp-options: -DDEBUG_CONFLICT_SETS - build-depends: base >=4.9 - if flag(debug-tracetree) cpp-options: -DDEBUG_TRACETREE build-depends: tracetree ^>=0.1 @@ -138,10 +131,10 @@ Test-Suite unit-tests UnitTests.Distribution.Solver.Modular.MessageUtils build-depends: - , base >= 4.10 && <4.19 + , base >= 4.10 && <4.20 , Cabal , Cabal-syntax , cabal-install-solver - , tasty >= 1.2.3 && <1.5 + , tasty >= 1.2.3 && <1.6 , tasty-quickcheck , tasty-hunit >= 0.10 diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/ConflictSet.hs b/cabal-install-solver/src/Distribution/Solver/Modular/ConflictSet.hs index 190e811f06f..00cf15b466f 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/ConflictSet.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/ConflictSet.hs @@ -1,7 +1,3 @@ -{-# LANGUAGE CPP #-} -#ifdef DEBUG_CONFLICT_SETS -{-# LANGUAGE ImplicitParams #-} -#endif -- | Conflict sets -- -- Intended for double import @@ -13,9 +9,6 @@ module Distribution.Solver.Modular.ConflictSet ( , Conflict(..) , ConflictMap , OrderedVersionRange(..) -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin -#endif , showConflictSet , showCSSortedByFrequency , showCSWithFrequency @@ -44,36 +37,17 @@ import Data.Function (on) import qualified Data.Map.Strict as M import qualified Data.Set as S -#ifdef DEBUG_CONFLICT_SETS -import Data.Tree -import GHC.Stack -#endif - import Distribution.Solver.Modular.Var import Distribution.Solver.Modular.Version import Distribution.Solver.Types.PackagePath -- | The set of variables involved in a solver conflict, each paired with -- details about the conflict. -data ConflictSet = CS { +newtype ConflictSet = CS { -- | The set of variables involved in the conflict - conflictSetToMap :: !(Map (Var QPN) (Set Conflict)) - -#ifdef DEBUG_CONFLICT_SETS - -- | The origin of the conflict set - -- - -- When @DEBUG_CONFLICT_SETS@ is defined @(-f debug-conflict-sets)@, - -- we record the origin of every conflict set. For new conflict sets - -- ('empty', 'fromVars', ..) we just record the 'CallStack'; for operations - -- that construct new conflict sets from existing conflict sets ('union', - -- 'filter', ..) we record the 'CallStack' to the call to the combinator - -- as well as the 'CallStack's of the input conflict sets. - -- - -- Requires @GHC >= 7.10@. - , conflictSetOrigin :: Tree CallStack -#endif + conflictSetToMap :: Map (Var QPN) (Set Conflict) } - deriving (Show) + deriving (Eq, Show) -- | More detailed information about how a conflict set variable caused a -- conflict. This information can be used to determine whether a second value @@ -112,12 +86,6 @@ newtype OrderedVersionRange = OrderedVersionRange VR instance Ord OrderedVersionRange where compare = compare `on` show -instance Eq ConflictSet where - (==) = (==) `on` conflictSetToMap - -instance Ord ConflictSet where - compare = compare `on` conflictSetToMap - showConflictSet :: ConflictSet -> String showConflictSet = intercalate ", " . map showVar . toList @@ -147,40 +115,19 @@ toSet = M.keysSet . conflictSetToMap toList :: ConflictSet -> [Var QPN] toList = M.keys . conflictSetToMap -union :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - ConflictSet -> ConflictSet -> ConflictSet +union :: ConflictSet -> ConflictSet -> ConflictSet union cs cs' = CS { conflictSetToMap = M.unionWith S.union (conflictSetToMap cs) (conflictSetToMap cs') -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin = Node ?loc (map conflictSetOrigin [cs, cs']) -#endif } -unions :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - [ConflictSet] -> ConflictSet +unions :: [ConflictSet] -> ConflictSet unions css = CS { conflictSetToMap = M.unionsWith S.union (map conflictSetToMap css) -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin = Node ?loc (map conflictSetOrigin css) -#endif } -insert :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - Var QPN -> ConflictSet -> ConflictSet +insert :: Var QPN -> ConflictSet -> ConflictSet insert var cs = CS { conflictSetToMap = M.insert var (S.singleton OtherConflict) (conflictSetToMap cs) -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin = Node ?loc [conflictSetOrigin cs] -#endif } delete :: Var QPN -> ConflictSet -> ConflictSet @@ -188,35 +135,17 @@ delete var cs = CS { conflictSetToMap = M.delete var (conflictSetToMap cs) } -empty :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - ConflictSet +empty :: ConflictSet empty = CS { conflictSetToMap = M.empty -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin = Node ?loc [] -#endif } -singleton :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - Var QPN -> ConflictSet +singleton :: Var QPN -> ConflictSet singleton var = singletonWithConflict var OtherConflict -singletonWithConflict :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - Var QPN -> Conflict -> ConflictSet +singletonWithConflict :: Var QPN -> Conflict -> ConflictSet singletonWithConflict var conflict = CS { conflictSetToMap = M.singleton var (S.singleton conflict) -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin = Node ?loc [] -#endif } size :: ConflictSet -> Int @@ -228,17 +157,9 @@ member var = M.member var . conflictSetToMap lookup :: Var QPN -> ConflictSet -> Maybe (Set Conflict) lookup var = M.lookup var . conflictSetToMap -fromList :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - [Var QPN] -> ConflictSet +fromList :: [Var QPN] -> ConflictSet fromList vars = CS { conflictSetToMap = M.fromList [(var, S.singleton OtherConflict) | var <- vars] -#ifdef DEBUG_CONFLICT_SETS - , conflictSetOrigin = Node ?loc [] -#endif } type ConflictMap = Map (Var QPN) Int - diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs index 73580aff3e6..810e5121002 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs @@ -1,10 +1,13 @@ {-# LANGUAGE BangPatterns #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE ViewPatterns #-} module Distribution.Solver.Modular.Message ( Message(..), showMessages ) where +import Data.Maybe (isJust) import qualified Data.List as L import Data.Map (Map) import qualified Data.Map as M @@ -17,7 +20,8 @@ import Distribution.Pretty (prettyShow) -- from Cabal import qualified Distribution.Solver.Modular.ConflictSet as CS import Distribution.Solver.Modular.Dependency -import Distribution.Solver.Modular.Flag +import Distribution.Solver.Modular.Flag ( QFN, QSN ) +import qualified Distribution.Solver.Modular.Flag as Flag ( showQFN, showQFNBool, showQSN, showQSNBool ) import Distribution.Solver.Modular.MessageUtils (showUnsupportedExtension, showUnsupportedLanguage) import Distribution.Solver.Modular.Package @@ -60,24 +64,24 @@ showMessages = go 0 go !l (Step (TryP qpn i) (Step Enter (Step (Skip conflicts) (Step Leave ms)))) = goPSkip l qpn [i] conflicts ms go !l (Step (TryF qfn b) (Step Enter (Step (Failure c fr) (Step Leave ms)))) = - (atLevel l $ "rejecting: " ++ showQFNBool qfn b ++ showFR c fr) (go l ms) + (atLevel l $ blurbQFNBool Rejecting qfn b ++ showFR c fr) (go l ms) go !l (Step (TryS qsn b) (Step Enter (Step (Failure c fr) (Step Leave ms)))) = - (atLevel l $ "rejecting: " ++ showQSNBool qsn b ++ showFR c fr) (go l ms) + (atLevel l $ blurbQSNBool Rejecting qsn b ++ showFR c fr) (go l ms) go !l (Step (Next (Goal (P _ ) gr)) (Step (TryP qpn' i) ms@(Step Enter (Step (Next _) _)))) = - (atLevel l $ "trying: " ++ showQPNPOpt qpn' i ++ showGR gr) (go l ms) + (atLevel l $ blurbOption Trying qpn' i ++ showGR gr) (go l ms) go !l (Step (Next (Goal (P qpn) gr)) (Step (Failure _c UnknownPackage) ms)) = atLevel l ("unknown package: " ++ showQPN qpn ++ showGR gr) $ go l ms -- standard display go !l (Step Enter ms) = go (l+1) ms go !l (Step Leave ms) = go (l-1) ms - go !l (Step (TryP qpn i) ms) = (atLevel l $ "trying: " ++ showQPNPOpt qpn i) (go l ms) - go !l (Step (TryF qfn b) ms) = (atLevel l $ "trying: " ++ showQFNBool qfn b) (go l ms) - go !l (Step (TryS qsn b) ms) = (atLevel l $ "trying: " ++ showQSNBool qsn b) (go l ms) + go !l (Step (TryP qpn i) ms) = (atLevel l $ blurbOption Trying qpn i) (go l ms) + go !l (Step (TryF qfn b) ms) = (atLevel l $ blurbQFNBool Trying qfn b) (go l ms) + go !l (Step (TryS qsn b) ms) = (atLevel l $ blurbQSNBool Trying qsn b) (go l ms) go !l (Step (Next (Goal (P qpn) gr)) ms) = (atLevel l $ showPackageGoal qpn gr) (go l ms) go !l (Step (Next _) ms) = go l ms -- ignore flag goals in the log go !l (Step (Skip conflicts) ms) = -- 'Skip' should always be handled by 'goPSkip' in the case above. - (atLevel l $ "skipping: " ++ showConflicts conflicts) (go l ms) + (atLevel l $ blurb Skipping ++ showConflicts conflicts) (go l ms) go !l (Step (Success) ms) = (atLevel l $ "done") (go l ms) go !l (Step (Failure c fr) ms) = (atLevel l $ showFailure c fr) (go l ms) @@ -96,9 +100,12 @@ showMessages = go 0 -> Progress Message a b -> Progress String a b goPReject l qpn is c fr (Step (TryP qpn' i) (Step Enter (Step (Failure _ fr') (Step Leave ms)))) - | qpn == qpn' && fr == fr' = goPReject l qpn (i : is) c fr ms + | qpn == qpn' && fr == fr' = + -- By prepending (i : is) we reverse the order of the instances. + goPReject l qpn (i : is) c fr ms goPReject l qpn is c fr ms = - (atLevel l $ "rejecting: " ++ L.intercalate ", " (map (showQPNPOpt qpn) (reverse is)) ++ showFR c fr) (go l ms) + (atLevel l $ blurbOptions Rejecting qpn (reverse is) ++ showFR c fr) + (go l ms) -- Handle many subsequent skipped package instances. goPSkip :: Int @@ -108,11 +115,11 @@ showMessages = go 0 -> Progress Message a b -> Progress String a b goPSkip l qpn is conflicts (Step (TryP qpn' i) (Step Enter (Step (Skip conflicts') (Step Leave ms)))) - | qpn == qpn' && conflicts == conflicts' = goPSkip l qpn (i : is) conflicts ms + | qpn == qpn' && conflicts == conflicts' = + -- By prepending (i : is) we reverse the order of the instances. + goPSkip l qpn (i : is) conflicts ms goPSkip l qpn is conflicts ms = - let msg = "skipping: " - ++ L.intercalate ", " (map (showQPNPOpt qpn) (reverse is)) - ++ showConflicts conflicts + let msg = blurbOptions Skipping qpn (reverse is) ++ showConflicts conflicts in atLevel l msg (go l ms) -- write a message with the current level number @@ -206,12 +213,83 @@ data MergedPackageConflict = MergedPackageConflict { , versionConflict :: Maybe VR } -showQPNPOpt :: QPN -> POption -> String -showQPNPOpt qpn@(Q _pp pn) (POption i linkedTo) = +data ProgressAction = + Trying + | Skipping + | Rejecting + +blurb :: ProgressAction -> String +blurb = \case + Trying -> "trying: " + Skipping -> "skipping: " + Rejecting -> "rejecting: " + +blurbQFNBool :: ProgressAction -> QFN -> Bool -> String +blurbQFNBool a q b = blurb a ++ Flag.showQFNBool q b + +blurbQSNBool :: ProgressAction -> QSN -> Bool -> String +blurbQSNBool a q b = blurb a ++ Flag.showQSNBool q b + +blurbOption :: ProgressAction -> QPN -> POption -> String +blurbOption a q p = blurb a ++ showOption q p + +blurbOptions :: ProgressAction -> QPN -> [POption] -> String +blurbOptions a q ps = blurb a ++ showIsOrVs q (tryVs ps) + +showOption :: QPN -> POption -> String +showOption qpn@(Q _pp pn) (POption i linkedTo) = case linkedTo of Nothing -> showPI (PI qpn i) -- Consistent with prior to POption Just pp' -> showQPN qpn ++ "~>" ++ showPI (PI (Q pp' pn) i) +-- | A list of versions, or a list of instances. +data IsOrVs = Is [POption] | Vs [Ver] deriving Show + +-- | Try to convert a list of options to a list of versions, or a list of +-- instances if any of the options is linked or installed. Singleton lists or +-- empty lists are always converted to Is. +-- >>> tryVs [v0, v1] +-- Vs [mkVersion [0],mkVersion [1]] +-- >>> tryVs [v0] +-- Is [POption (I (mkVersion [0]) InRepo) Nothing] +-- >>> tryVs [i0, i1] +-- Is [POption (I (mkVersion [0]) (Inst (UnitId "foo-bar-0-inplace"))) Nothing,POption (I (mkVersion [1]) (Inst (UnitId "foo-bar-1-inplace"))) Nothing] +-- >>> tryVs [i0, v1] +-- Is [POption (I (mkVersion [0]) (Inst (UnitId "foo-bar-0-inplace"))) Nothing,POption (I (mkVersion [1]) InRepo) Nothing] +-- >>> tryVs [v0, i1] +-- Is [POption (I (mkVersion [0]) InRepo) Nothing,POption (I (mkVersion [1]) (Inst (UnitId "foo-bar-1-inplace"))) Nothing] +-- >>> tryVs [i0] +-- Is [POption (I (mkVersion [0]) (Inst (UnitId "foo-bar-0-inplace"))) Nothing] +-- >>> tryVs [] +-- Is [] +tryVs :: [POption] -> IsOrVs +tryVs xs@[] = Is xs +tryVs xs@[_] = Is xs +tryVs xs + | any (\(POption (instI -> b0) (isJust -> b1)) -> b0 || b1) xs = Is xs + | otherwise = + let (vs, is) = L.partition ((== InRepo) . snd) [(v, l) | POption i _ <- xs, let I v l = i] + in if null is then Vs (fst `map` vs) else Is xs + +-- | Shows a list of versions in a human-friendly way, abbreviated. Shows a list +-- of instances in full. +-- >>> showIsOrVs foobarQPN $ tryVs [v0, v1] +-- "foo-bar; 0, 1" +-- >>> showIsOrVs foobarQPN $ tryVs [v0] +-- "foo-bar-0" +-- >>> showIsOrVs foobarQPN $ tryVs [i0, i1] +-- "foo-bar-0/installed-inplace, foo-bar-1/installed-inplace" +-- >>> showIsOrVs foobarQPN $ tryVs [i0, v1] +-- "foo-bar-0/installed-inplace, foo-bar-1" +-- >>> showIsOrVs foobarQPN $ tryVs [v0, i1] +-- "foo-bar-0, foo-bar-1/installed-inplace" +-- >>> showIsOrVs foobarQPN $ tryVs [] +-- "unexpected empty list of versions" +showIsOrVs :: QPN -> IsOrVs -> String +showIsOrVs _ (Is []) = "unexpected empty list of versions" +showIsOrVs q (Is xs) = L.intercalate ", " (showOption q `map` xs) +showIsOrVs q (Vs xs) = showQPN q ++ "; " ++ L.intercalate ", " (showVer `map` xs) + showGR :: QGoalReason -> String showGR UserGoal = " (user goal)" showGR (DependencyGoal dr) = " (dependency of " ++ showDependencyReason dr ++ ")" @@ -246,8 +324,8 @@ showFR _ (UnsupportedSpecVer ver) = " (unsupported spec-version " ++ pre -- The following are internal failures. They should not occur. In the -- interest of not crashing unnecessarily, we still just print an error -- message though. -showFR _ (MalformedFlagChoice qfn) = " (INTERNAL ERROR: MALFORMED FLAG CHOICE: " ++ showQFN qfn ++ ")" -showFR _ (MalformedStanzaChoice qsn) = " (INTERNAL ERROR: MALFORMED STANZA CHOICE: " ++ showQSN qsn ++ ")" +showFR _ (MalformedFlagChoice qfn) = " (INTERNAL ERROR: MALFORMED FLAG CHOICE: " ++ Flag.showQFN qfn ++ ")" +showFR _ (MalformedStanzaChoice qsn) = " (INTERNAL ERROR: MALFORMED STANZA CHOICE: " ++ Flag.showQSN qsn ++ ")" showFR _ EmptyGoalChoice = " (INTERNAL ERROR: EMPTY GOAL CHOICE)" showExposedComponent :: ExposedComponent -> String @@ -270,3 +348,13 @@ showConflictingDep (ConflictingDep dr (PkgComponent qpn comp) ci) = showQPN qpn ++ componentStr ++ "==" ++ showI i Constrained vr -> showDependencyReason dr ++ " => " ++ showQPN qpn ++ componentStr ++ showVR vr + +-- $setup +-- >>> import Distribution.Solver.Types.PackagePath +-- >>> import Distribution.Types.Version +-- >>> import Distribution.Types.UnitId +-- >>> let foobarQPN = Q (PackagePath DefaultNamespace QualToplevel) (mkPackageName "foo-bar") +-- >>> let v0 = POption (I (mkVersion [0]) InRepo) Nothing +-- >>> let v1 = POption (I (mkVersion [1]) InRepo) Nothing +-- >>> let i0 = POption (I (mkVersion [0]) (Inst $ mkUnitId "foo-bar-0-inplace")) Nothing +-- >>> let i1 = POption (I (mkVersion [1]) (Inst $ mkUnitId "foo-bar-1-inplace")) Nothing diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs index 54911f2c367..cbe6282b6d0 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs @@ -1,9 +1,5 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE CPP #-} -#ifdef DEBUG_CONFLICT_SETS -{-# LANGUAGE ImplicitParams #-} -#endif module Distribution.Solver.Modular.Validate (validateTree) where -- Validation of the tree. @@ -40,10 +36,6 @@ import Distribution.Solver.Types.PkgConfigDb (PkgConfigDb, pkgConfigPkgIsPresent import Distribution.Types.LibraryName import Distribution.Types.PkgconfigVersionRange -#ifdef DEBUG_CONFLICT_SETS -import GHC.Stack (CallStack) -#endif - -- In practice, most constraints are implication constraints (IF we have made -- a number of choices, THEN we also have to ensure that). We call constraints -- that for which the preconditions are fulfilled ACTIVE. We maintain a set @@ -450,11 +442,7 @@ extendWithPackageChoice (PI qpn i) ppa = -- set in the sense the it contains variables that allow us to backjump -- further. We might apply some heuristics here, such as to change the -- order in which we check the constraints. -merge :: -#ifdef DEBUG_CONFLICT_SETS - (?loc :: CallStack) => -#endif - MergedPkgDep -> PkgDep -> Either (ConflictSet, (ConflictingDep, ConflictingDep)) MergedPkgDep +merge :: MergedPkgDep -> PkgDep -> Either (ConflictSet, (ConflictingDep, ConflictingDep)) MergedPkgDep merge (MergedDepFixed comp1 vs1 i1) (PkgDep vs2 (PkgComponent p comp2) ci@(Fixed i2)) | i1 == i2 = Right $ MergedDepFixed comp1 vs1 i1 | otherwise = diff --git a/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs b/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs index 00bc38c28c3..21845eafdec 100644 --- a/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs +++ b/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE LambdaCase #-} ----------------------------------------------------------------------------- -- | -- Module : Distribution.Solver.Types.PkgConfigDb @@ -23,17 +24,23 @@ module Distribution.Solver.Types.PkgConfigDb import Distribution.Solver.Compat.Prelude import Prelude () -import Control.Exception (handle) -import Control.Monad (mapM) -import qualified Data.Map as M -import System.FilePath (splitSearchPath) +import Control.Exception (handle) +import Control.Monad (mapM) +import Data.ByteString (ByteString) +import qualified Data.ByteString.Lazy as LBS +import qualified Data.Map as M +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.Encoding.Error as T +import System.FilePath (splitSearchPath) import Distribution.Compat.Environment (lookupEnv) import Distribution.Package (PkgconfigName, mkPkgconfigName) import Distribution.Parsec import Distribution.Simple.Program (ProgramDb, getProgramOutput, pkgConfigProgram, needProgram, ConfiguredProgram) -import Distribution.Simple.Program.Run (getProgramInvocationOutputAndErrors, programInvocation) +import Distribution.Simple.Program.Run + (getProgramInvocationOutputAndErrors, programInvocation, getProgramInvocationLBSAndErrors) import Distribution.Simple.Utils (info) import Distribution.Types.PkgconfigVersion import Distribution.Types.PkgconfigVersionRange @@ -63,15 +70,43 @@ readPkgConfigDb verbosity progdb = handle ioErrorHandler $ do case mpkgConfig of Nothing -> noPkgConfig "Cannot find pkg-config program" Just (pkgConfig, _) -> do - pkgList <- lines <$> getProgramOutput verbosity pkgConfig ["--list-all"] - -- The output of @pkg-config --list-all@ also includes a description - -- for each package, which we do not need. - let pkgNames = map (takeWhile (not . isSpace)) pkgList - (pkgVersions, _errs, exitCode) <- + -- To prevent malformed Unicode in the descriptions from crashing cabal, + -- read without interpreting any encoding first. (#9608) + (listAllOutput, listAllErrs, listAllExitcode) <- + getProgramInvocationLBSAndErrors verbosity (programInvocation pkgConfig ["--list-all"]) + when (listAllExitcode /= ExitSuccess) $ + ioError (userError ("pkg-config --list-all failed: " ++ listAllErrs)) + let pkgList = LBS.split (fromIntegral (ord '\n')) listAllOutput + -- Now decode the package *names* to a String. The ones where decoding + -- failed end up in 'failedPkgNames'. + let (failedPkgNames, pkgNames) = + partitionEithers + -- Drop empty package names. This will handle empty lines + -- in pkg-config's output, including the spurious one + -- after the last newline (because of LBS.split). + . filter (either (const True) (not . null)) + -- Try decoding strictly; if it fails, put the lenient + -- decoding in a Left for later reporting. + . map (\bsname -> + let sbsname = LBS.toStrict bsname + in case T.decodeUtf8' sbsname of + Left _ -> Left (T.unpack (decodeUtf8LenientCompat sbsname)) + Right name -> Right (T.unpack name)) + -- The output of @pkg-config --list-all@ also includes a + -- description for each package, which we do not need. + -- We don't use Data.Char.isSpace because that would also + -- include 0xA0, the non-breaking space, which can occur + -- in multi-byte UTF-8 sequences. + . map (LBS.takeWhile (not . isAsciiSpace)) + $ pkgList + when (not (null failedPkgNames)) $ + info verbosity ("Some pkg-config packages have names containing invalid unicode: " ++ intercalate ", " failedPkgNames) + (outs, _errs, exitCode) <- getProgramInvocationOutputAndErrors verbosity (programInvocation pkgConfig ("--modversion" : pkgNames)) - if exitCode == ExitSuccess && length pkgNames == length pkgList - then (return . pkgConfigDbFromList . zip pkgNames) (lines pkgVersions) + let pkgVersions = lines outs + if exitCode == ExitSuccess && length pkgVersions == length pkgNames + then (return . pkgConfigDbFromList . zip pkgNames) pkgVersions else -- if there's a single broken pc file the above fails, so we fall back -- into calling it individually @@ -103,6 +138,15 @@ readPkgConfigDb verbosity progdb = handle ioErrorHandler $ do ExitSuccess -> Just (pkg, pkgVersion) _ -> Nothing + isAsciiSpace :: Word8 -> Bool + isAsciiSpace c = c `elem` map (fromIntegral . ord) " \t" + + -- The decodeUtf8Lenient function is defined starting with text-2.0.1; this + -- function simply reimplements it. When the minimum supported GHC version + -- is >= 9.4, switch to decodeUtf8Lenient. + decodeUtf8LenientCompat :: ByteString -> T.Text + decodeUtf8LenientCompat = T.decodeUtf8With T.lenientDecode + -- | Create a `PkgConfigDb` from a list of @(packageName, version)@ pairs. pkgConfigDbFromList :: [(String, String)] -> PkgConfigDb pkgConfigDbFromList pairs = (PkgConfigDb . M.fromList . map convert) pairs diff --git a/cabal-install/LICENSE b/cabal-install/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/cabal-install/LICENSE +++ b/cabal-install/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/cabal-install/cabal-install.cabal b/cabal-install/cabal-install.cabal index d32caebb53c..87f2112d028 100644 --- a/cabal-install/cabal-install.cabal +++ b/cabal-install/cabal-install.cabal @@ -13,12 +13,13 @@ License: BSD-3-Clause License-File: LICENSE Author: Cabal Development Team (see AUTHORS file) Maintainer: Cabal Development Team -Copyright: 2003-2023, Cabal Development Team +Copyright: 2003-2024, Cabal Development Team Category: Distribution Build-type: Simple Extra-Source-Files: - README.md bash-completion/cabal +extra-doc-files: + README.md changelog source-repository head @@ -40,13 +41,17 @@ Flag lukko common warnings ghc-options: -Wall -Wcompat -Wnoncanonical-monad-instances -Wincomplete-uni-patterns -Wincomplete-record-updates + if impl(ghc < 8.8) ghc-options: -Wnoncanonical-monadfail-instances - if impl(ghc >=8.10) + + if impl(ghc >=9.0) + -- Warning: even though introduced with GHC 8.10, -Wunused-packages + -- gives false positives with GHC 8.10. ghc-options: -Wunused-packages common base-dep - build-depends: base >=4.10 && <4.19 + build-depends: base >=4.10 && <4.20 common cabal-dep build-depends: Cabal ^>=3.11 @@ -63,6 +68,10 @@ library default-extensions: TypeOperators hs-source-dirs: src + autogen-modules: + Paths_cabal_install + other-modules: + Paths_cabal_install exposed-modules: -- this modules are moved from Cabal -- they are needed for as long until cabal-install moves to parsec parser @@ -102,6 +111,7 @@ library Distribution.Client.Compat.Orphans Distribution.Client.Compat.Prelude Distribution.Client.Compat.Semaphore + Distribution.Client.Compat.Tar Distribution.Client.Config Distribution.Client.Configure Distribution.Client.Dependency @@ -150,6 +160,8 @@ library Distribution.Client.PackageHash Distribution.Client.ParseUtils Distribution.Client.ProjectBuilding + Distribution.Client.ProjectBuilding.UnpackedPackage + Distribution.Client.ProjectBuilding.PackageFileMonitor Distribution.Client.ProjectBuilding.Types Distribution.Client.ProjectConfig Distribution.Client.ProjectConfig.FieldGrammar @@ -161,6 +173,7 @@ library Distribution.Client.ProjectOrchestration Distribution.Client.ProjectPlanOutput Distribution.Client.ProjectPlanning + Distribution.Client.ProjectPlanning.SetupPolicy Distribution.Client.ProjectPlanning.Types Distribution.Client.RebuildMonad Distribution.Client.Reconfigure @@ -211,7 +224,6 @@ library async >= 2.0 && < 2.3, array >= 0.4 && < 0.6, base16-bytestring >= 0.1.1 && < 1.1.0.0, - base64-bytestring >= 1.0 && < 1.3, binary >= 0.7.3 && < 0.9, bytestring >= 0.10.6.0 && < 0.13, containers >= 0.5.6.2 && < 0.8, @@ -220,7 +232,7 @@ library echo >= 0.1.3 && < 0.2, edit-distance >= 0.2.2 && < 0.3, exceptions >= 0.10.4 && < 0.11, - filepath >= 1.4.0.0 && < 1.5, + filepath >= 1.4.0.0 && < 1.6, hashable >= 1.0 && < 1.5, HTTP >= 4000.1.5 && < 4000.5, mtl >= 2.0 && < 2.4, @@ -229,12 +241,13 @@ library process >= 1.2.3.0 && < 1.7, random >= 1.2 && < 1.3, stm >= 2.0 && < 2.6, - tar >= 0.5.0.3 && < 0.6, + tar >= 0.5.0.3 && < 0.7, time >= 1.5.0.1 && < 1.13, - zlib >= 0.5.3 && < 0.7, + zlib >= 0.5.3 && < 0.8, hackage-security >= 0.6.2.0 && < 0.7, - text >= 1.2.3 && < 1.3 || >= 2.0 && < 2.1, + text >= 1.2.3 && < 1.3 || >= 2.0 && < 2.2, parsec >= 3.1.13.0 && < 3.2, + open-browser >= 0.2.1.0 && < 0.3, regex-base >= 0.94.0.0 && <0.95, regex-posix >= 0.96.0.0 && <0.97, safe-exceptions >= 0.1.7.0 && < 0.2, @@ -327,6 +340,7 @@ test-suite unit-tests cabal-install, Cabal-tree-diff, Cabal-QuickCheck, + Cabal-tests, containers, directory, filepath, @@ -336,7 +350,7 @@ test-suite unit-tests tar, time, zlib, - tasty >= 1.2.3 && <1.5, + tasty >= 1.2.3 && <1.6, tasty-golden >=2.3.1.1 && <2.4, tasty-quickcheck, tasty-hunit >= 0.10, @@ -366,7 +380,7 @@ test-suite mem-use-tests build-depends: cabal-install, containers, - tasty >= 1.2.3 && <1.5, + tasty >= 1.2.3 && <1.6, tasty-hunit >= 0.10 @@ -386,7 +400,7 @@ test-suite integration-tests2 containers, directory, filepath, - tasty >= 1.2.3 && <1.5, + tasty >= 1.2.3 && <1.6, tasty-hunit >= 0.10, tagged @@ -412,6 +426,7 @@ test-suite long-tests build-depends: Cabal-QuickCheck, Cabal-described, + Cabal-tests, cabal-install, containers, directory, @@ -421,7 +436,7 @@ test-suite long-tests network-uri >= 2.6.2.0 && <2.7, random, tagged, - tasty >= 1.2.3 && <1.5, + tasty >= 1.2.3 && <1.6, tasty-expected-failure, tasty-hunit >= 0.10, tasty-quickcheck, diff --git a/cabal-install/changelog b/cabal-install/changelog index 0a211ba0946..3fe99c798e6 100644 --- a/cabal-install/changelog +++ b/cabal-install/changelog @@ -1,6 +1,13 @@ -*-change-log-*- 3.10.2.0 Hécate August 2023 +3.10.3.0 Hécate January 2024 + * See https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.10.3.0.md + +3.10.2.1 Hécate November 2023 + * See https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.10.2.1.md + +3.10.2.0 Hécate November 2023 * See https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.10.2.0.md 3.10.1.0 Mikolaj Konarski March 2023 diff --git a/cabal-install/src/Distribution/Client/Check.hs b/cabal-install/src/Distribution/Client/Check.hs index ffd2e6c7ec3..07ec20bf93f 100644 --- a/cabal-install/src/Distribution/Client/Check.hs +++ b/cabal-install/src/Distribution/Client/Check.hs @@ -24,7 +24,6 @@ import Prelude () import Distribution.Client.Utils.Parsec (renderParseError) import Distribution.PackageDescription (GenericPackageDescription) import Distribution.PackageDescription.Check -import Distribution.PackageDescription.Configuration (flattenPackageDescription) import Distribution.PackageDescription.Parsec ( parseGenericPackageDescription , runParseResult @@ -60,28 +59,22 @@ readGenericPackageDescriptionCheck verbosity fpath = do -- is fit to upload to Hackage, @False@ otherwise. -- Note: must be called with the CWD set to the directory containing -- the '.cabal' file. -check :: Verbosity -> IO Bool -check verbosity = do +check + :: Verbosity + -> [CheckExplanationIDString] + -- ^ List of check-ids in String form + -- (e.g. @invalid-path-win@) to ignore. + -> IO Bool +check verbosity ignores = do pdfile <- defaultPackageDesc verbosity (ws, ppd) <- readGenericPackageDescriptionCheck verbosity pdfile -- convert parse warnings into PackageChecks let ws' = map (wrapParseWarning pdfile) ws - -- flatten the generic package description into a regular package - -- description - -- TODO: this may give more warnings than it should give; - -- consider two branches of a condition, one saying - -- ghc-options: -Wall - -- and the other - -- ghc-options: -Werror - -- joined into - -- ghc-options: -Wall -Werror - -- checkPackages will yield a warning on the last line, but it - -- would not on each individual branch. - -- However, this is the same way hackage does it, so we will yield - -- the exact same errors as it will. - let pkg_desc = flattenPackageDescription ppd - ioChecks <- checkPackageFiles verbosity pkg_desc "." - let packageChecks = ioChecks ++ checkPackage ppd (Just pkg_desc) ++ ws' + ioChecks <- checkPackageFilesGPD verbosity ppd "." + let packageChecksPrim = ioChecks ++ checkPackage ppd ++ ws' + (packageChecks, unrecs) = filterPackageChecksByIdString packageChecksPrim ignores + + CM.mapM_ (\s -> warn verbosity ("Unrecognised ignore \"" ++ s ++ "\"")) unrecs CM.mapM_ (outputGroupCheck verbosity) (groupChecks packageChecks) diff --git a/cabal-install/src/Distribution/Client/CmdExec.hs b/cabal-install/src/Distribution/Client/CmdExec.hs index 3a3dd306d8a..fc81f323fdc 100644 --- a/cabal-install/src/Distribution/Client/CmdExec.hs +++ b/cabal-install/src/Distribution/Client/CmdExec.hs @@ -26,6 +26,10 @@ import Distribution.Client.NixStyleOptions , defaultNixStyleFlags , nixStyleOptions ) +import Distribution.Client.ProjectConfig.Types + ( ProjectConfig (projectConfigShared) + , ProjectConfigShared (projectConfigProgPathExtra) + ) import Distribution.Client.ProjectFlags ( removeIgnoreProjectOption ) @@ -64,33 +68,32 @@ import Distribution.Simple.GHC ( GhcImplInfo (supportsPkgEnvFiles) , getImplInfo ) +import Distribution.Simple.Program + ( ConfiguredProgram + , programDefaultArgs + , programOverrideEnv + , programPath + , simpleProgram + ) import Distribution.Simple.Program.Db ( configuredPrograms - , modifyProgramSearchPath + , prependProgramSearchPath , requireProgram ) -import Distribution.Simple.Program.Find - ( ProgramSearchPathEntry (..) - ) import Distribution.Simple.Program.Run ( programInvocation , runProgramInvocation ) -import Distribution.Simple.Program.Types - ( ConfiguredProgram - , programDefaultArgs - , programOverrideEnv - , programPath - , simpleProgram - ) import Distribution.Simple.Utils ( createDirectoryIfMissingVerbose , dieWithException - , info , notice , withTempDirectory , wrapText ) +import Distribution.Utils.NubList + ( fromNubList + ) import Distribution.Verbosity ( normal ) @@ -162,13 +165,15 @@ execAction flags@NixStyleFlags{..} extraArgs globalFlags = do mempty -- Some dependencies may have executables. Let's put those on the PATH. - extraPaths <- pathAdditions verbosity baseCtx buildCtx - let programDb = - modifyProgramSearchPath - (map ProgramSearchPathDir extraPaths ++) - . pkgConfigCompilerProgs - . elaboratedShared - $ buildCtx + let extraPaths = pathAdditions baseCtx buildCtx + + programDb <- + prependProgramSearchPath + verbosity + extraPaths + . pkgConfigCompilerProgs + . elaboratedShared + $ buildCtx -- Now that we have the packages, set up the environment. We accomplish this -- by creating an environment file that selects the databases and packages we @@ -263,17 +268,21 @@ withTempEnvFile verbosity baseCtx buildCtx buildStatus action = do action envOverrides ) -pathAdditions :: Verbosity -> ProjectBaseContext -> ProjectBuildContext -> IO [FilePath] -pathAdditions verbosity ProjectBaseContext{..} ProjectBuildContext{..} = do - info verbosity . unlines $ - "Including the following directories in PATH:" - : paths - return paths +-- | Get paths to all dependency executables to be included in PATH. +pathAdditions :: ProjectBaseContext -> ProjectBuildContext -> [FilePath] +pathAdditions ProjectBaseContext{..} ProjectBuildContext{..} = + paths ++ cabalConfigPaths where + cabalConfigPaths = + fromNubList + . projectConfigProgPathExtra + . projectConfigShared + $ projectConfig paths = S.toList $ binDirectories distDirLayout elaboratedShared elaboratedPlanToExecute +-- | Get paths to all dependency executables to be included in PATH. binDirectories :: DistDirLayout -> ElaboratedSharedConfig diff --git a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs index cac23c9b51b..bde0948dcf9 100644 --- a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs +++ b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs @@ -54,9 +54,6 @@ import Distribution.Client.TargetProblem (TargetProblem (..)) import Distribution.Simple.Command ( CommandUI (..) ) -import Distribution.Simple.Compiler - ( Compiler (..) - ) import Distribution.Simple.Flag ( Flag (..) , fromFlag @@ -319,7 +316,7 @@ haddockProjectAction flags _extraArgs globalFlags = do packageDir = storePackageDirectory (cabalStoreDirLayout cabalLayout) - (compilerId (pkgConfigCompiler sharedConfig')) + (pkgConfigCompiler sharedConfig') (elabUnitId package) docDir = packageDir "share" "doc" "html" destDir = outputDir packageName diff --git a/cabal-install/src/Distribution/Client/CmdInstall.hs b/cabal-install/src/Distribution/Client/CmdInstall.hs index cb032d2b712..be4f66363d4 100644 --- a/cabal-install/src/Distribution/Client/CmdInstall.hs +++ b/cabal-install/src/Distribution/Client/CmdInstall.hs @@ -2,6 +2,7 @@ {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} -- | cabal-install CLI command: build module Distribution.Client.CmdInstall @@ -53,8 +54,10 @@ import Distribution.Client.IndexUtils ) import qualified Distribution.Client.InstallPlan as InstallPlan import Distribution.Client.InstallSymlink - ( promptRun + ( Symlink (..) + , promptRun , symlinkBinary + , symlinkableBinary , trySymlink ) import Distribution.Client.NixStyleOptions @@ -67,6 +70,7 @@ import Distribution.Client.ProjectConfig , fetchAndReadSourcePackages , projectConfigWithBuilderRepoContext , resolveBuildTimeSettings + , withGlobalConfig , withProjectOrGlobalConfig ) import Distribution.Client.ProjectConfig.Types @@ -102,6 +106,8 @@ import Distribution.Client.Types , PackageSpecifier (..) , SourcePackageDb (..) , UnresolvedSourcePackage + , mkNamedPackage + , pkgSpecifierTarget ) import Distribution.Client.Types.OverwritePolicy ( OverwritePolicy (..) @@ -149,13 +155,10 @@ import qualified Distribution.Simple.InstallDirs as InstallDirs import qualified Distribution.Simple.PackageIndex as PI import Distribution.Simple.Program.Db ( defaultProgramDb - , modifyProgramSearchPath + , prependProgramSearchPath , userSpecifyArgss , userSpecifyPaths ) -import Distribution.Simple.Program.Find - ( ProgramSearchPathEntry (..) - ) import Distribution.Simple.Setup ( Flag (..) , installDirsOptions @@ -242,6 +245,46 @@ import System.FilePath , () ) +-- | Check or check then install an exe. The check is to see if the overwrite +-- policy allows installation. +data InstallCheck + = -- | Only check if install is permitted. + InstallCheckOnly + | -- | Actually install but check first if permitted. + InstallCheckInstall + +type InstallAction = + Verbosity + -> OverwritePolicy + -> InstallExe + -> (UnitId, [(ComponentTarget, NonEmpty TargetSelector)]) + -> IO () + +data InstallCfg = InstallCfg + { verbosity :: Verbosity + , baseCtx :: ProjectBaseContext + , buildCtx :: ProjectBuildContext + , platform :: Platform + , compiler :: Compiler + , installConfigFlags :: ConfigFlags + , installClientFlags :: ClientInstallFlags + } + +-- | A record of install method, install directory and file path functions +-- needed by actions that either check if an install is possible or actually +-- perform an installation. This is for installation of executables only. +data InstallExe = InstallExe + { installMethod :: InstallMethod + , installDir :: FilePath + , mkSourceBinDir :: UnitId -> FilePath + -- ^ A function to get an UnitId's store directory. + , mkExeName :: UnqualComponentName -> FilePath + -- ^ A function to get an exe's filename. + , mkFinalExeName :: UnqualComponentName -> FilePath + -- ^ A function to get an exe's final possibly different to the name in the + -- store. + } + installCommand :: CommandUI (NixStyleFlags ClientInstallFlags) installCommand = CommandUI @@ -254,7 +297,7 @@ installCommand = , commandDescription = Just $ \_ -> wrapText $ "Installs one or more packages. This is done by installing them " - ++ "in the store and symlinking/copying the executables in the directory " + ++ "in the store and symlinking or copying the executables in the directory " ++ "specified by the --installdir flag (`~/.local/bin/` by default). " ++ "If you want the installed executables to be available globally, " ++ "make sure that the PATH environment variable contains that directory. " @@ -303,144 +346,58 @@ installCommand = -- For more details on how this works, see the module -- "Distribution.Client.ProjectOrchestration" installAction :: NixStyleFlags ClientInstallFlags -> [String] -> GlobalFlags -> IO () -installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetStrings globalFlags = do +installAction flags@NixStyleFlags{extraFlags, configFlags, installFlags, projectFlags} targetStrings globalFlags = do -- Ensure there were no invalid configuration options specified. verifyPreconditionsOrDie verbosity configFlags' -- We cannot use establishDummyProjectBaseContext to get these flags, since -- it requires one of them as an argument. Normal establishProjectBaseContext -- does not, and this is why this is done only for the install command - clientInstallFlags <- getClientInstallFlags verbosity globalFlags clientInstallFlags' - + clientInstallFlags <- getClientInstallFlags verbosity globalFlags extraFlags let installLibs = fromFlagOrDefault False (cinstInstallLibs clientInstallFlags) - targetFilter = if installLibs then Just LibKind else Just ExeKind - targetStrings' = if null targetStrings then ["."] else targetStrings - - -- Note the logic here is rather goofy. Target selectors of the form "foo:bar" also parse as uris. - -- However, we want install to also take uri arguments. Hence, we only parse uri arguments in the case where - -- no project file is present (including an implicit one derived from being in a package directory) - -- or where the --ignore-project flag is passed explicitly. In such a case we only parse colon-free target selectors - -- as selectors, and otherwise parse things as URIs. - - -- However, in the special case where --ignore-project is passed with no selectors, we want to act as though this is - -- a "normal" ignore project that actually builds and installs the selected package. - - withProject :: IO ([PackageSpecifier UnresolvedSourcePackage], [URI], [TargetSelector], ProjectConfig) - withProject = do - let reducedVerbosity = lessVerbose verbosity - - -- First, we need to learn about what's available to be installed. - localBaseCtx <- - establishProjectBaseContext reducedVerbosity cliConfig InstallCommand - let localDistDirLayout = distDirLayout localBaseCtx - pkgDb <- - projectConfigWithBuilderRepoContext - reducedVerbosity - (buildSettings localBaseCtx) - (getSourcePackages verbosity) - - let - (targetStrings'', packageIds) = - partitionEithers - . flip fmap targetStrings' - $ \str -> case simpleParsec str of - Just (pkgId :: PackageId) - | pkgVersion pkgId /= nullVersion -> Right pkgId - _ -> Left str - packageSpecifiers = - flip fmap packageIds $ \case - PackageIdentifier{..} - | pkgVersion == nullVersion -> NamedPackage pkgName [] - | otherwise -> - NamedPackage - pkgName - [ PackagePropertyVersion - (thisVersion pkgVersion) - ] - packageTargets = - flip TargetPackageNamed targetFilter . pkgName <$> packageIds - - if null targetStrings'' -- if every selector is already resolved as a packageid, return without further parsing. - then return (packageSpecifiers, [], packageTargets, projectConfig localBaseCtx) - else do - targetSelectors <- - either (reportTargetSelectorProblems verbosity) return - =<< readTargetSelectors - (localPackages localBaseCtx) - Nothing - targetStrings'' - - (specs, selectors) <- - getSpecsAndTargetSelectors - verbosity - reducedVerbosity - pkgDb - targetSelectors - localDistDirLayout - localBaseCtx - targetFilter - - return - ( specs ++ packageSpecifiers - , [] - , selectors ++ packageTargets - , projectConfig localBaseCtx - ) - - withoutProject :: ProjectConfig -> IO ([PackageSpecifier UnresolvedSourcePackage], [URI], [TargetSelector], ProjectConfig) - withoutProject _ | null targetStrings = withProject -- if there's no targets, we don't parse specially, but treat it as install in a standard cabal package dir - withoutProject globalConfig = do - tss <- traverse (parseWithoutProjectTargetSelector verbosity) targetStrings' - let - projectConfig = globalConfig <> cliConfig - ProjectConfigBuildOnly - { projectConfigLogsDir - } = projectConfigBuildOnly projectConfig - - ProjectConfigShared - { projectConfigStoreDir - } = projectConfigShared projectConfig - - mlogsDir = flagToMaybe projectConfigLogsDir - mstoreDir = flagToMaybe projectConfigStoreDir - cabalDirLayout <- mkCabalDirLayout mstoreDir mlogsDir + normalisedTargetStrings = if null targetStrings then ["."] else targetStrings - let - buildSettings = - resolveBuildTimeSettings - verbosity - cabalDirLayout - projectConfig - - SourcePackageDb{packageIndex} <- - projectConfigWithBuilderRepoContext - verbosity - buildSettings - (getSourcePackages verbosity) - - for_ (concatMap woPackageNames tss) $ \name -> do - when (null (lookupPackageName packageIndex name)) $ do - let xs = searchByName packageIndex (unPackageName name) - let emptyIf True _ = [] - emptyIf False zs = zs - str2 = - emptyIf - (null xs) - [ "Did you mean any of the following?\n" - , unlines (("- " ++) . unPackageName . fst <$> xs) - ] - dieWithException verbosity $ WithoutProject (unPackageName name) str2 - - let - (uris, packageSpecifiers) = partitionEithers $ map woPackageSpecifiers tss - packageTargets = map woPackageTargets tss + -- Note the logic here is rather goofy. Target selectors of the form "foo:bar" also parse as uris. + -- However, we want install to also take uri arguments. Hence, we only parse uri arguments in the case where + -- no project file is present (including an implicit one derived from being in a package directory) + -- or where the --ignore-project flag is passed explicitly. In such a case we only parse colon-free target selectors + -- as selectors, and otherwise parse things as URIs. - return (packageSpecifiers, uris, packageTargets, projectConfig) + -- However, in the special case where --ignore-project is passed with no selectors, we want to act as though this is + -- a "normal" ignore project that actually builds and installs the selected package. - (specs, uris, targetSelectors, config) <- - withProjectOrGlobalConfig verbosity ignoreProject globalConfigFlag withProject withoutProject + (pkgSpecs, uris, targetSelectors, config) <- + let + with = do + (pkgSpecs, targetSelectors, baseConfig) <- + withProject verbosity cliConfig normalisedTargetStrings installLibs + -- No URIs in this case, see note above + return (pkgSpecs, [], targetSelectors, baseConfig) + + without = + withGlobalConfig verbosity globalConfigFlag $ \globalConfig -> + withoutProject verbosity (globalConfig <> cliConfig) normalisedTargetStrings + in + -- If there's no targets it does not make sense to not be in a project. + if null targetStrings + then with + else withProjectOrGlobalConfig ignoreProject with without + + -- NOTE: CmdInstall and project local packages. + -- + -- CmdInstall always installs packages from a source distribution that, in case of unpackage + -- pacakges, is created automatically. This is implemented in getSpecsAndTargetSelectors. + -- + -- This has the inconvenience that the planner will consider all packages as non-local + -- (see `ProjectPlanning.shouldBeLocal`) and that any project or cli configuration will + -- not apply to them. + -- + -- We rectify this here. In the project configuration, we copy projectConfigLocalPackages to a + -- new projectConfigSpecificPackage entry for each package corresponding to a target selector. + -- + -- See #8637 and later #7297, #8909, #7236. let ProjectConfig @@ -454,6 +411,8 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt , projectConfigHcPath , projectConfigHcPkg , projectConfigStoreDir + , projectConfigProgPathExtra + , projectConfigPackageDBs } , projectConfigLocalPackages = PackageConfig @@ -467,26 +426,16 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt hcPath = flagToMaybe projectConfigHcPath hcPkg = flagToMaybe projectConfigHcPkg + configProgDb <- prependProgramSearchPath verbosity ((fromNubList packageConfigProgramPathExtra) ++ (fromNubList projectConfigProgPathExtra)) defaultProgramDb + let -- ProgramDb with directly user specified paths preProgDb = userSpecifyPaths (Map.toList (getMapLast packageConfigProgramPaths)) . userSpecifyArgss (Map.toList (getMapMappend packageConfigProgramArgs)) - . modifyProgramSearchPath - ( ++ - [ ProgramSearchPathDir dir - | dir <- fromNubList packageConfigProgramPathExtra - ] - ) - $ defaultProgramDb + $ configProgDb -- progDb is a program database with compiler tools configured properly - ( compiler@Compiler - { compilerId = - compilerId@(CompilerId compilerFlavor compilerVersion) - } - , platform - , progDb - ) <- + (compiler@Compiler{compilerId = CompilerId compilerFlavor compilerVersion}, platform, progDb) <- configCompilerEx hcFlavor hcPath hcPkg preProgDb verbosity let @@ -495,7 +444,7 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt envFile <- getEnvFile clientInstallFlags platform compilerVersion existingEnvEntries <- getExistingEnvEntries verbosity compilerFlavor supportsPkgEnvFiles envFile - packageDbs <- getPackageDbStack compilerId projectConfigStoreDir projectConfigLogsDir + packageDbs <- getPackageDbStack compiler projectConfigStoreDir projectConfigLogsDir projectConfigPackageDBs installedIndex <- getInstalledPackages verbosity compiler packageDbs progDb let @@ -521,9 +470,8 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt -- check for targets already in env let getPackageName :: PackageSpecifier UnresolvedSourcePackage -> PackageName - getPackageName (NamedPackage pn _) = pn - getPackageName (SpecificSourcePackage (SourcePackage pkgId _ _ _)) = pkgName pkgId - targetNames = S.fromList $ map getPackageName (specs ++ uriSpecs) + getPackageName = pkgSpecifierTarget + targetNames = S.fromList $ map getPackageName (pkgSpecs ++ uriSpecs) envNames = S.fromList $ map getPackageName envSpecs forceInstall = fromFlagOrDefault False $ installOverrideReinstall installFlags nameIntersection = S.intersection targetNames envNames @@ -540,7 +488,8 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt in pure (es, nge) else dieWithException verbosity $ PackagesAlreadyExistInEnvfile envFile (map prettyShow $ S.toList nameIntersection) - -- we construct an installed index of files in the cleaned target environment (absent overwrites) so that we can solve with regards to packages installed locally but not in the upstream repo + -- we construct an installed index of files in the cleaned target environment (absent overwrites) so that + -- we can solve with regards to packages installed locally but not in the upstream repo let installedPacks = PI.allPackagesByName installedIndex newEnvNames = S.fromList $ map getPackageName envSpecs' installedIndex' = PI.fromList . concatMap snd . filter (\p -> fst p `S.member` newEnvNames) $ installedPacks @@ -550,24 +499,29 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt verbosity config distDirLayout - (envSpecs' ++ specs ++ uriSpecs) + (envSpecs' ++ pkgSpecs ++ uriSpecs) InstallCommand buildCtx <- constructProjectBuildContext verbosity (baseCtx{installedPackages = Just installedIndex'}) targetSelectors printPlan verbosity baseCtx buildCtx + let installCfg = InstallCfg verbosity baseCtx buildCtx platform compiler configFlags clientInstallFlags - buildOutcomes <- runProjectBuildPhase verbosity baseCtx buildCtx - runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes - - -- Now that we built everything we can do the installation part. - -- First, figure out if / what parts we want to install: let dryRun = buildSettingDryRun (buildSettings baseCtx) || buildSettingOnlyDownload (buildSettings baseCtx) - -- Then, install! + -- Before building, check if we could install any built exe by symlinking or + -- copying it? + unless + (dryRun || installLibs) + (traverseInstall (installCheckUnitExes InstallCheckOnly) installCfg) + + buildOutcomes <- runProjectBuildPhase verbosity baseCtx buildCtx + runProjectPostBuildPhase verbosity baseCtx buildCtx buildOutcomes + + -- Having built everything, do the install. unless dryRun $ if installLibs then @@ -579,30 +533,167 @@ installAction flags@NixStyleFlags{extraFlags = clientInstallFlags', ..} targetSt packageDbs envFile nonGlobalEnvEntries' - else - installExes - verbosity - baseCtx - buildCtx - platform - compiler - configFlags - clientInstallFlags + else -- Install any built exe by symlinking or copying it we don't use + -- BuildOutcomes because we also need the component names + traverseInstall (installCheckUnitExes InstallCheckInstall) installCfg where configFlags' = disableTestsBenchsByDefault configFlags verbosity = fromFlagOrDefault normal (configVerbosity configFlags') ignoreProject = flagIgnoreProject projectFlags - baseCliConfig = + cliConfig = commandLineFlagsToProjectConfig globalFlags flags{configFlags = configFlags'} - clientInstallFlags' - cliConfig = addLocalConfigToTargets baseCliConfig targetStrings + extraFlags + globalConfigFlag = projectConfigConfigFile (projectConfigShared cliConfig) --- | Treat all direct targets of install command as local packages: #8637 -addLocalConfigToTargets :: ProjectConfig -> [String] -> ProjectConfig -addLocalConfigToTargets config targetStrings = + -- Do the install action for each executable in the install configuration. + traverseInstall :: InstallAction -> InstallCfg -> IO () + traverseInstall action cfg@InstallCfg{verbosity = v, buildCtx, installClientFlags} = do + let overwritePolicy = fromFlagOrDefault NeverOverwrite $ cinstOverwritePolicy installClientFlags + actionOnExe <- action v overwritePolicy <$> prepareExeInstall cfg + traverse_ actionOnExe . Map.toList $ targetsMap buildCtx + +withProject + :: Verbosity + -> ProjectConfig + -> [String] + -> Bool + -> IO ([PackageSpecifier UnresolvedSourcePackage], [TargetSelector], ProjectConfig) +withProject verbosity cliConfig targetStrings installLibs = do + -- First, we need to learn about what's available to be installed. + baseCtx <- establishProjectBaseContext reducedVerbosity cliConfig InstallCommand + + (pkgSpecs, targetSelectors) <- + -- If every target is already resolved to a package id, we can return without any further parsing. + if null unresolvedTargetStrings + then return (parsedPkgSpecs, parsedTargets) + else do + -- Anything that could not be parsed as a packageId (e.g. a package name without a version or + -- a target syntax using colons) must be resolved inside the project context. + (resolvedPkgSpecs, resolvedTargets) <- + resolveTargetSelectorsInProjectBaseContext verbosity baseCtx unresolvedTargetStrings targetFilter + return (resolvedPkgSpecs ++ parsedPkgSpecs, resolvedTargets ++ parsedTargets) + + -- Apply the local configuration (e.g. cli flags) to all direct targets of install command, see note + -- in 'installAction'. + -- + -- NOTE: If a target string had to be resolved inside the project context, then pkgSpecs will include + -- the project packages turned into source distributions (getSpecsAndTargetSelectors does this). + -- We want to apply the local configuration only to the actual targets. + let config = + addLocalConfigToPkgs (projectConfig baseCtx) $ + concatMap (targetPkgNames $ localPackages baseCtx) targetSelectors + return (pkgSpecs, targetSelectors, config) + where + reducedVerbosity = lessVerbose verbosity + + -- We take the targets and try to parse them as package ids (with name and version). + -- The ones who don't parse will have to be resolved in the project context. + (unresolvedTargetStrings, parsedPackageIds) = + partitionEithers $ + flip map targetStrings $ \s -> + case eitherParsec s of + Right pkgId@PackageIdentifier{pkgVersion} + | pkgVersion /= nullVersion -> + pure pkgId + _ -> Left s + + -- For each packageId, we output a NamedPackage specifier (i.e. a package only known by + -- its name) and a target selector. + (parsedPkgSpecs, parsedTargets) = + unzip + [ (mkNamedPackage pkgId, TargetPackageNamed (pkgName pkgId) targetFilter) + | pkgId <- parsedPackageIds + ] + + targetFilter = if installLibs then Just LibKind else Just ExeKind + +resolveTargetSelectorsInProjectBaseContext + :: Verbosity + -> ProjectBaseContext + -> [String] + -> Maybe ComponentKindFilter + -> IO ([PackageSpecifier UnresolvedSourcePackage], [TargetSelector]) +resolveTargetSelectorsInProjectBaseContext verbosity baseCtx targetStrings targetFilter = do + let reducedVerbosity = lessVerbose verbosity + + sourcePkgDb <- + projectConfigWithBuilderRepoContext + reducedVerbosity + (buildSettings baseCtx) + (getSourcePackages verbosity) + + targetSelectors <- + readTargetSelectors (localPackages baseCtx) Nothing targetStrings + >>= \case + Left problems -> reportTargetSelectorProblems verbosity problems + Right ts -> return ts + + getSpecsAndTargetSelectors + verbosity + reducedVerbosity + sourcePkgDb + targetSelectors + (distDirLayout baseCtx) + baseCtx + targetFilter + +withoutProject + :: Verbosity + -> ProjectConfig + -> [String] + -> IO ([PackageSpecifier UnresolvedSourcePackage], [URI], [TargetSelector], ProjectConfig) +withoutProject verbosity globalConfig targetStrings = do + tss <- traverse (parseWithoutProjectTargetSelector verbosity) targetStrings + let + ProjectConfigBuildOnly + { projectConfigLogsDir + } = projectConfigBuildOnly globalConfig + + ProjectConfigShared + { projectConfigStoreDir + } = projectConfigShared globalConfig + + mlogsDir = flagToMaybe projectConfigLogsDir + mstoreDir = flagToMaybe projectConfigStoreDir + + cabalDirLayout <- mkCabalDirLayout mstoreDir mlogsDir + + let buildSettings = resolveBuildTimeSettings verbosity cabalDirLayout globalConfig + + SourcePackageDb{packageIndex} <- + projectConfigWithBuilderRepoContext + verbosity + buildSettings + (getSourcePackages verbosity) + + for_ (concatMap woPackageNames tss) $ \name -> do + when (null (lookupPackageName packageIndex name)) $ do + let xs = searchByName packageIndex (unPackageName name) + let emptyIf True _ = [] + emptyIf False zs = zs + str2 = + emptyIf + (null xs) + [ "Did you mean any of the following?\n" + , unlines (("- " ++) . unPackageName . fst <$> xs) + ] + dieWithException verbosity $ WithoutProject (unPackageName name) str2 + + let + packageSpecifiers :: [PackageSpecifier UnresolvedSourcePackage] + (uris, packageSpecifiers) = partitionEithers $ map woPackageSpecifiers tss + packageTargets = map woPackageTargets tss + + -- Apply the local configuration (e.g. cli flags) to all direct targets of install command, + -- see note in 'installAction' + let config = addLocalConfigToPkgs globalConfig (concatMap woPackageNames tss) + return (packageSpecifiers, uris, packageTargets, config) + +addLocalConfigToPkgs :: ProjectConfig -> [PackageName] -> ProjectConfig +addLocalConfigToPkgs config pkgs = config { projectConfigSpecificPackage = projectConfigSpecificPackage config @@ -610,7 +701,25 @@ addLocalConfigToTargets config targetStrings = } where localConfig = projectConfigLocalPackages config - targetPackageConfigs = map (\x -> (mkPackageName x, localConfig)) targetStrings + targetPackageConfigs = map (,localConfig) pkgs + +targetPkgNames + :: [PackageSpecifier UnresolvedSourcePackage] + -- ^ The local packages, to resolve 'TargetAllPackages' selectors + -> TargetSelector + -> [PackageName] +targetPkgNames localPkgs = \case + TargetPackage _ pkgIds _ -> map pkgName pkgIds + TargetPackageNamed name _ -> [name] + TargetAllPackages _ -> map pkgSpecifierTarget localPkgs + -- Note how the target may select a component only, but we will always apply + -- the local flags to the whole package in which that component is contained. + -- The reason is that our finest level of configuration is per-package, so + -- there is no interface to configure options to a component only. It is not + -- trivial to say whether we could indeed support per-component configuration + -- because of legacy packages which we may always have to build whole. + TargetComponent pkgId _ _ -> [pkgName pkgId] + TargetComponentUnknown name _ _ -> [name] -- | Verify that invalid config options were not passed to the install command. -- @@ -625,6 +734,7 @@ verifyPreconditionsOrDie verbosity configFlags = do when (configBenchmarks configFlags == Flag True) $ dieWithException verbosity ConfigBenchmarks +-- | Apply the given 'ClientInstallFlags' on top of one coming from the global configuration. getClientInstallFlags :: Verbosity -> GlobalFlags -> ClientInstallFlags -> IO ClientInstallFlags getClientInstallFlags verbosity globalFlags existingClientInstallFlags = do let configFileFlag = globalConfigFile globalFlags @@ -640,28 +750,27 @@ getSpecsAndTargetSelectors -> ProjectBaseContext -> Maybe ComponentKindFilter -> IO ([PackageSpecifier UnresolvedSourcePackage], [TargetSelector]) -getSpecsAndTargetSelectors verbosity reducedVerbosity pkgDb targetSelectors localDistDirLayout localBaseCtx targetFilter = - withInstallPlan reducedVerbosity localBaseCtx $ \elaboratedPlan _ -> do +getSpecsAndTargetSelectors verbosity reducedVerbosity sourcePkgDb targetSelectors distDirLayout baseCtx targetFilter = + withInstallPlan reducedVerbosity baseCtx $ \elaboratedPlan _ -> do -- Split into known targets and hackage packages. - (targets, hackageNames) <- + (targetsMap, hackageNames) <- partitionToKnownTargetsAndHackagePackages verbosity - pkgDb + sourcePkgDb elaboratedPlan targetSelectors let planMap = InstallPlan.toMap elaboratedPlan - targetIds = Map.keys targets sdistize (SpecificSourcePackage spkg) = SpecificSourcePackage spkg' where - sdistPath = distSdistFile localDistDirLayout (packageId spkg) + sdistPath = distSdistFile distDirLayout (packageId spkg) spkg' = spkg{srcpkgSource = LocalTarballPackage sdistPath} sdistize named = named - local = sdistize <$> localPackages localBaseCtx + localPkgs = sdistize <$> localPackages baseCtx gatherTargets :: UnitId -> TargetSelector gatherTargets targetId = TargetPackageNamed pkgName targetFilter @@ -669,30 +778,38 @@ getSpecsAndTargetSelectors verbosity reducedVerbosity pkgDb targetSelectors loca targetUnit = Map.findWithDefault (error "cannot find target unit") targetId planMap PackageIdentifier{..} = packageId targetUnit - targets' = fmap gatherTargets targetIds + localTargets = map gatherTargets (Map.keys targetsMap) hackagePkgs :: [PackageSpecifier UnresolvedSourcePackage] - hackagePkgs = flip NamedPackage [] <$> hackageNames + hackagePkgs = [NamedPackage pn [] | pn <- hackageNames] hackageTargets :: [TargetSelector] - hackageTargets = - flip TargetPackageNamed targetFilter <$> hackageNames + hackageTargets = [TargetPackageNamed pn targetFilter | pn <- hackageNames] - createDirectoryIfMissing True (distSdistDirectory localDistDirLayout) + createDirectoryIfMissing True (distSdistDirectory distDirLayout) - unless (Map.null targets) $ for_ (localPackages localBaseCtx) $ \lpkg -> case lpkg of + unless (Map.null targetsMap) $ for_ (localPackages baseCtx) $ \case SpecificSourcePackage pkg -> packageToSdist verbosity - (distProjectRootDirectory localDistDirLayout) + (distProjectRootDirectory distDirLayout) TarGzArchive - (distSdistFile localDistDirLayout (packageId pkg)) + (distSdistFile distDirLayout (packageId pkg)) pkg - NamedPackage pkgName _ -> error $ "Got NamedPackage " ++ prettyShow pkgName - - if null targets + NamedPackage _ _ -> + -- This may happen if 'extra-packages' are listed in the project file. + -- We don't need to do extra work for NamedPackages since they will be + -- fetched from Hackage rather than locally 'sdistize'-d. Note how, + -- below, we already return the local 'sdistize'-d packages together + -- with the 'hackagePkgs' (which are 'NamedPackage's), and that + -- 'sdistize' is a no-op for 'NamedPackages', meaning the + -- 'NamedPackage's in 'localPkgs' will be treated just like + -- 'hackagePkgs' as they should. + pure () + + if null targetsMap then return (hackagePkgs, hackageTargets) - else return (local ++ hackagePkgs, targets' ++ hackageTargets) + else return (localPkgs ++ hackagePkgs, localTargets ++ hackageTargets) -- | Partitions the target selectors into known local targets and hackage packages. partitionToKnownTargetsAndHackagePackages @@ -783,35 +900,22 @@ constructProjectBuildContext verbosity baseCtx targetSelectors = do return (prunedElaboratedPlan, targets) --- | Install any built exe by symlinking/copying it --- we don't use BuildOutcomes because we also need the component names -installExes - :: Verbosity - -> ProjectBaseContext - -> ProjectBuildContext - -> Platform - -> Compiler - -> ConfigFlags - -> ClientInstallFlags - -> IO () -installExes - verbosity - baseCtx - buildCtx - platform - compiler - configFlags - clientInstallFlags = do +-- | From an install configuration, prepare the record needed by actions that +-- will either check if an install of a single executable is possible or +-- actually perform its installation. +prepareExeInstall :: InstallCfg -> IO InstallExe +prepareExeInstall + InstallCfg{verbosity, baseCtx, buildCtx, platform, compiler, installConfigFlags, installClientFlags} = do installPath <- defaultInstallPath let storeDirLayout = cabalStoreDirLayout $ cabalDirLayout baseCtx - prefix = fromFlagOrDefault "" (fmap InstallDirs.fromPathTemplate (configProgPrefix configFlags)) - suffix = fromFlagOrDefault "" (fmap InstallDirs.fromPathTemplate (configProgSuffix configFlags)) + prefix = fromFlagOrDefault "" (fmap InstallDirs.fromPathTemplate (configProgPrefix installConfigFlags)) + suffix = fromFlagOrDefault "" (fmap InstallDirs.fromPathTemplate (configProgSuffix installConfigFlags)) mkUnitBinDir :: UnitId -> FilePath mkUnitBinDir = InstallDirs.bindir - . storePackageInstallDirs' storeDirLayout (compilerId compiler) + . storePackageInstallDirs' storeDirLayout compiler mkExeName :: UnqualComponentName -> FilePath mkExeName exe = unUnqualComponentName exe <.> exeExtension platform @@ -826,42 +930,24 @@ installExes installdir <- fromFlagOrDefault (warn verbosity installdirUnknown >> pure installPath) - $ pure <$> cinstInstalldir clientInstallFlags + $ pure <$> cinstInstalldir installClientFlags createDirectoryIfMissingVerbose verbosity True installdir warnIfNoExes verbosity buildCtx - installMethod <- - flagElim defaultMethod return $ - cinstInstallMethod clientInstallFlags + -- This is in IO as we will make environment checks, to decide which install + -- method is best. + let defaultMethod :: IO InstallMethod + defaultMethod + -- Try symlinking in temporary directory, if it works default to + -- symlinking even on windows. + | buildOS == Windows = do + symlinks <- trySymlink verbosity + return $ if symlinks then InstallMethodSymlink else InstallMethodCopy + | otherwise = return InstallMethodSymlink - let - doInstall = - installUnitExes - verbosity - overwritePolicy - mkUnitBinDir - mkExeName - mkFinalExeName - installdir - installMethod - in - traverse_ doInstall $ Map.toList $ targetsMap buildCtx - where - overwritePolicy = - fromFlagOrDefault NeverOverwrite $ - cinstOverwritePolicy clientInstallFlags - isWindows = buildOS == Windows - - -- This is in IO as we will make environment checks, - -- to decide which method is best - defaultMethod :: IO InstallMethod - defaultMethod - -- Try symlinking in temporary directory, if it works default to - -- symlinking even on windows - | isWindows = do - symlinks <- trySymlink verbosity - return $ if symlinks then InstallMethodSymlink else InstallMethodCopy - | otherwise = return InstallMethodSymlink + installMethod <- flagElim defaultMethod return $ cinstInstallMethod installClientFlags + + return $ InstallExe installMethod installdir mkUnitBinDir mkExeName mkFinalExeName -- | Install any built library by adding it to the default ghc environment installLibraries @@ -987,41 +1073,49 @@ disableTestsBenchsByDefault configFlags = , configBenchmarks = Flag False <> configBenchmarks configFlags } --- | Symlink/copy every exe from a package from the store to a given location -installUnitExes - :: Verbosity - -> OverwritePolicy - -- ^ Whether to overwrite existing files - -> (UnitId -> FilePath) - -- ^ A function to get an UnitId's - -- ^ store directory - -> (UnqualComponentName -> FilePath) - -- ^ A function to get an - -- ^ exe's filename - -> (UnqualComponentName -> FilePath) - -- ^ A function to get an - -- ^ exe's final possibly - -- ^ different to the name in the store. - -> FilePath - -> InstallMethod - -> ( UnitId - , [(ComponentTarget, NonEmpty TargetSelector)] - ) - -> IO () -installUnitExes +-- | Prepares a record containing the information needed to either symlink or +-- copy an executable. +symlink :: OverwritePolicy -> InstallExe -> UnitId -> UnqualComponentName -> Symlink +symlink + overwritePolicy + InstallExe{installDir, mkSourceBinDir, mkExeName, mkFinalExeName} + unit + exe = + Symlink + overwritePolicy + installDir + (mkSourceBinDir unit) + (mkExeName exe) + (mkFinalExeName exe) + +-- | +-- -- * When 'InstallCheckOnly', warn if install would fail overwrite policy +-- checks but don't install anything. +-- -- * When 'InstallCheckInstall', try to symlink or copy every package exe +-- from the store to a given location. When not permitted by the overwrite +-- policy, stop with a message. +installCheckUnitExes :: InstallCheck -> InstallAction +installCheckUnitExes + installCheck verbosity overwritePolicy - mkSourceBinDir - mkExeName - mkFinalExeName - installdir - installMethod - (unit, components) = - traverse_ installAndWarn exes + installExe@InstallExe{installMethod, installDir, mkSourceBinDir, mkExeName, mkFinalExeName} + (unit, components) = do + symlinkables :: [Bool] <- traverse (symlinkableBinary . symlink overwritePolicy installExe unit) exes + case installCheck of + InstallCheckOnly -> traverse_ warnAbout (zip symlinkables exes) + InstallCheckInstall -> + if and symlinkables + then traverse_ installAndWarn exes + else traverse_ warnAbout (zip symlinkables exes) where exes = catMaybes $ (exeMaybe . fst) <$> components exeMaybe (ComponentTarget (CExeName exe) _) = Just exe exeMaybe _ = Nothing + + warnAbout (True, _) = return () + warnAbout (False, exe) = dieWithException verbosity $ InstallUnitExes (errorMessage installDir exe) + installAndWarn exe = do success <- installBuiltExe @@ -1030,22 +1124,22 @@ installUnitExes (mkSourceBinDir unit) (mkExeName exe) (mkFinalExeName exe) - installdir + installDir installMethod - let errorMessage = case overwritePolicy of - NeverOverwrite -> - "Path '" - <> (installdir prettyShow exe) - <> "' already exists. " - <> "Use --overwrite-policy=always to overwrite." - -- This shouldn't even be possible, but we keep it in case - -- symlinking/copying logic changes - _ -> - case installMethod of - InstallMethodSymlink -> "Symlinking" - InstallMethodCopy -> - "Copying" <> " '" <> prettyShow exe <> "' failed." - unless success $ dieWithException verbosity $ InstallUnitExes errorMessage + unless success $ dieWithException verbosity $ InstallUnitExes (errorMessage installDir exe) + + errorMessage installdir exe = case overwritePolicy of + NeverOverwrite -> + "Path '" + <> (installdir prettyShow exe) + <> "' already exists. " + <> "Use --overwrite-policy=always to overwrite." + -- This shouldn't even be possible, but we keep it in case symlinking or + -- copying logic changes. + _ -> + case installMethod of + InstallMethodSymlink -> "Symlinking" + InstallMethodCopy -> "Copying" <> " '" <> prettyShow exe <> "' failed." -- | Install a specific exe. installBuiltExe @@ -1072,11 +1166,13 @@ installBuiltExe InstallMethodSymlink = do notice verbosity $ "Symlinking '" <> exeName <> "' to '" <> destination <> "'" symlinkBinary - overwritePolicy - installdir - sourceDir - finalExeName - exeName + ( Symlink + overwritePolicy + installdir + sourceDir + finalExeName + exeName + ) where destination = installdir finalExeName installBuiltExe @@ -1191,16 +1287,17 @@ getLocalEnv dir platform compilerVersion = <> ghcPlatformAndVersionString platform compilerVersion getPackageDbStack - :: CompilerId + :: Compiler -> Flag FilePath -> Flag FilePath + -> [Maybe PackageDB] -> IO PackageDBStack -getPackageDbStack compilerId storeDirFlag logsDirFlag = do +getPackageDbStack compiler storeDirFlag logsDirFlag packageDbs = do mstoreDir <- traverse makeAbsolute $ flagToMaybe storeDirFlag let mlogsDir = flagToMaybe logsDirFlag cabalLayout <- mkCabalDirLayout mstoreDir mlogsDir - pure $ storePackageDBStack (cabalStoreDirLayout cabalLayout) compilerId + pure $ storePackageDBStack (cabalStoreDirLayout cabalLayout) compiler packageDbs -- | This defines what a 'TargetSelector' means for the @bench@ command. -- It selects the 'AvailableTarget's that the 'TargetSelector' refers to, diff --git a/cabal-install/src/Distribution/Client/CmdInstall/ClientInstallTargetSelector.hs b/cabal-install/src/Distribution/Client/CmdInstall/ClientInstallTargetSelector.hs index c6939729f61..7879602a913 100644 --- a/cabal-install/src/Distribution/Client/CmdInstall/ClientInstallTargetSelector.hs +++ b/cabal-install/src/Distribution/Client/CmdInstall/ClientInstallTargetSelector.hs @@ -18,8 +18,6 @@ import Distribution.Compat.CharParsing (char, optional) import Distribution.Package import Distribution.Simple.LocalBuildInfo (ComponentName (CExeName)) import Distribution.Simple.Utils (dieWithException) -import Distribution.Solver.Types.PackageConstraint (PackageProperty (..)) -import Distribution.Version data WithoutProjectTargetSelector = WoPackageId PackageId @@ -57,15 +55,6 @@ woPackageTargets (WoURI _) = TargetAllPackages (Just ExeKind) woPackageSpecifiers :: WithoutProjectTargetSelector -> Either URI (PackageSpecifier pkg) -woPackageSpecifiers (WoPackageId pid) = Right (pidPackageSpecifiers pid) -woPackageSpecifiers (WoPackageComponent pid _) = Right (pidPackageSpecifiers pid) +woPackageSpecifiers (WoPackageId pid) = Right (mkNamedPackage pid) +woPackageSpecifiers (WoPackageComponent pid _) = Right (mkNamedPackage pid) woPackageSpecifiers (WoURI uri) = Left uri - -pidPackageSpecifiers :: PackageId -> PackageSpecifier pkg -pidPackageSpecifiers pid - | pkgVersion pid == nullVersion = NamedPackage (pkgName pid) [] - | otherwise = - NamedPackage - (pkgName pid) - [ PackagePropertyVersion (thisVersion (pkgVersion pid)) - ] diff --git a/cabal-install/src/Distribution/Client/CmdRepl.hs b/cabal-install/src/Distribution/Client/CmdRepl.hs index a8189f8e677..e243eb82974 100644 --- a/cabal-install/src/Distribution/Client/CmdRepl.hs +++ b/cabal-install/src/Distribution/Client/CmdRepl.hs @@ -447,6 +447,25 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g -- unit files for components unit_files <- listDirectory dir + -- Order the unit files so that the find target becomes the active unit + let active_unit_fp :: Maybe FilePath + active_unit_fp = do + -- Get the first target selectors from the cli + activeTarget <- safeHead targetSelectors + -- Lookup the targets :: Map UnitId [(ComponentTarget, NonEmpty TargetSelector)] + unitId <- + Map.toList targets + -- Keep the UnitId matching the desired target selector + & find (\(_, xs) -> any (\(_, selectors) -> activeTarget `elem` selectors) xs) + & fmap fst + -- Convert to filename (adapted from 'storePackageDirectory') + pure (prettyShow unitId) + unit_files_ordered :: [FilePath] + unit_files_ordered = + let (active_unit_files, other_units) = partition (\fp -> Just fp == active_unit_fp) unit_files + in -- GHC considers the last unit passed to be the active one + other_units ++ active_unit_files + -- run ghc --interactive with runProgramInvocation verbosity $ programInvocation ghcProg' $ @@ -458,7 +477,7 @@ replAction flags@NixStyleFlags{extraFlags = r@ReplFlags{..}, ..} targetStrings g , show (buildSettingNumJobs (buildSettings ctx)) ] : [ ["-unit", "@" ++ dir unit] - | unit <- unit_files + | unit <- unit_files_ordered , unit /= "paths" ] diff --git a/cabal-install/src/Distribution/Client/CmdRun.hs b/cabal-install/src/Distribution/Client/CmdRun.hs index 2ad1b992369..b390dacb22e 100644 --- a/cabal-install/src/Distribution/Client/CmdRun.hs +++ b/cabal-install/src/Distribution/Client/CmdRun.hs @@ -48,6 +48,10 @@ import Distribution.Client.NixStyleOptions , defaultNixStyleFlags , nixStyleOptions ) +import Distribution.Client.ProjectConfig.Types + ( ProjectConfig (projectConfigShared) + , ProjectConfigShared (projectConfigProgPathExtra) + ) import Distribution.Client.ProjectOrchestration import Distribution.Client.ProjectPlanning ( ElaboratedConfiguredPackage (..) @@ -56,6 +60,7 @@ import Distribution.Client.ProjectPlanning ) import Distribution.Client.ProjectPlanning.Types ( dataDirsEnvironmentForPlan + , elabExeDependencyPaths ) import Distribution.Client.ScriptUtils ( AcceptNoTargets (..) @@ -82,6 +87,12 @@ import Distribution.Simple.Command import Distribution.Simple.Flag ( fromFlagOrDefault ) +import Distribution.Simple.Program.Find + ( ProgramSearchPathEntry (ProgramSearchPathDir) + , defaultProgramSearchPath + , logExtraProgramSearchPath + , programSearchPathAsPATHVar + ) import Distribution.Simple.Program.Run ( ProgramInvocation (..) , emptyProgramInvocation @@ -105,6 +116,9 @@ import Distribution.Types.UnqualComponentName ( UnqualComponentName , unUnqualComponentName ) +import Distribution.Utils.NubList + ( fromNubList + ) import Distribution.Verbosity ( normal , silent @@ -288,6 +302,19 @@ runAction flags@NixStyleFlags{..} targetAndArgs globalFlags = buildSettingDryRun (buildSettings baseCtx) || buildSettingOnlyDownload (buildSettings baseCtx) + let extraPath = + elabExeDependencyPaths pkg + ++ ( fromNubList + . projectConfigProgPathExtra + . projectConfigShared + . projectConfig + $ baseCtx + ) + + logExtraProgramSearchPath verbosity extraPath + + progPath <- programSearchPathAsPATHVar (map ProgramSearchPathDir extraPath ++ defaultProgramSearchPath) + if dryRun then notice verbosity "Running of executable suppressed by flag(s)" else @@ -297,9 +324,10 @@ runAction flags@NixStyleFlags{..} targetAndArgs globalFlags = { progInvokePath = exePath , progInvokeArgs = args , progInvokeEnv = - dataDirsEnvironmentForPlan - (distDirLayout baseCtx) - elaboratedPlan + ("PATH", Just $ progPath) + : dataDirsEnvironmentForPlan + (distDirLayout baseCtx) + elaboratedPlan } where (targetStr, args) = splitAt 1 targetAndArgs diff --git a/cabal-install/src/Distribution/Client/CmdSdist.hs b/cabal-install/src/Distribution/Client/CmdSdist.hs index c77c1eae910..a1142b06a27 100644 --- a/cabal-install/src/Distribution/Client/CmdSdist.hs +++ b/cabal-install/src/Distribution/Client/CmdSdist.hs @@ -32,6 +32,7 @@ import Distribution.Client.ProjectConfig , commandLineFlagsToProjectConfig , projectConfigConfigFile , projectConfigShared + , withGlobalConfig , withProjectOrGlobalConfig ) import Distribution.Client.ProjectFlags @@ -219,7 +220,11 @@ sdistOptions showOrParseArgs = sdistAction :: (ProjectFlags, SdistFlags) -> [String] -> GlobalFlags -> IO () sdistAction (pf@ProjectFlags{..}, SdistFlags{..}) targetStrings globalFlags = do - (baseCtx, distDirLayout) <- withProjectOrGlobalConfig verbosity flagIgnoreProject globalConfigFlag withProject withoutProject + (baseCtx, distDirLayout) <- + withProjectOrGlobalConfig + flagIgnoreProject + withProject + (withGlobalConfig verbosity globalConfigFlag withoutProject) let localPkgs = localPackages baseCtx diff --git a/cabal-install/src/Distribution/Client/CmdUpdate.hs b/cabal-install/src/Distribution/Client/CmdUpdate.hs index 8f66a33a363..052c8d60edd 100644 --- a/cabal-install/src/Distribution/Client/CmdUpdate.hs +++ b/cabal-install/src/Distribution/Client/CmdUpdate.hs @@ -48,6 +48,7 @@ import Distribution.Client.ProjectConfig ( ProjectConfig (..) , ProjectConfigShared (projectConfigConfigFile) , projectConfigWithSolverRepoContext + , withGlobalConfig , withProjectOrGlobalConfig ) import Distribution.Client.ProjectFlags @@ -98,7 +99,7 @@ import Distribution.Simple.Command import System.FilePath (dropExtension, (<.>)) import Distribution.Client.Errors -import Distribution.Client.IndexUtils.Timestamp (nullTimestamp) +import Distribution.Client.IndexUtils.Timestamp (Timestamp (NoTimestamp)) import qualified Hackage.Security.Client as Sec updateCommand :: CommandUI (NixStyleFlags ()) @@ -162,11 +163,9 @@ updateAction flags@NixStyleFlags{..} extraArgs globalFlags = do projectConfig <- withProjectOrGlobalConfig - verbosity ignoreProject - globalConfigFlag (projectConfig <$> establishProjectBaseContext verbosity cliConfig OtherCommand) - (\globalConfig -> return $ globalConfig <> cliConfig) + (withGlobalConfig verbosity globalConfigFlag $ \globalConfig -> return $ globalConfig <> cliConfig) projectConfigWithSolverRepoContext verbosity @@ -257,18 +256,19 @@ updateRepo verbosity _updateFlags repoCtxt (repo, indexState) = do updateRepoIndexCache verbosity (RepoIndex repoCtxt repo) RepoSecure{} -> repoContextWithSecureRepo repoCtxt repo $ \repoSecure -> do let index = RepoIndex repoCtxt repo - -- NB: This may be a nullTimestamp if we've never updated before - current_ts <- currentIndexTimestamp (lessVerbose verbosity) repoCtxt repo + -- NB: This may be a NoTimestamp if we've never updated before + current_ts <- currentIndexTimestamp (lessVerbose verbosity) index -- NB: always update the timestamp, even if we didn't actually -- download anything writeIndexTimestamp index indexState - ce <- - if repoContextIgnoreExpiry repoCtxt - then Just `fmap` getCurrentTime - else return Nothing - updated <- Sec.uncheckClientErrors $ Sec.checkForUpdates repoSecure ce - -- this resolves indexState (which could be HEAD) into a timestamp - new_ts <- currentIndexTimestamp (lessVerbose verbosity) repoCtxt repo + + updated <- do + ce <- + if repoContextIgnoreExpiry repoCtxt + then Just <$> getCurrentTime + else return Nothing + Sec.uncheckClientErrors $ Sec.checkForUpdates repoSecure ce + let rname = remoteRepoName (repoRemote repo) -- Update cabal's internal index as well so that it's not out of sync @@ -277,7 +277,8 @@ updateRepo verbosity _updateFlags repoCtxt (repo, indexState) = do Sec.NoUpdates -> do now <- getCurrentTime setModificationTime (indexBaseName repo <.> "tar") now - `catchIO` (\e -> warn verbosity $ "Could not set modification time of index tarball -- " ++ displayException e) + `catchIO` \e -> + warn verbosity $ "Could not set modification time of index tarball -- " ++ displayException e noticeNoWrap verbosity $ "Package list of " ++ prettyShow rname ++ " is up to date." Sec.HasUpdates -> do @@ -285,6 +286,11 @@ updateRepo verbosity _updateFlags repoCtxt (repo, indexState) = do noticeNoWrap verbosity $ "Package list of " ++ prettyShow rname ++ " has been updated." + -- This resolves indexState (which could be HEAD) into a timestamp + -- This could be null but should not be, since the above guarantees + -- we have an updated index. + new_ts <- currentIndexTimestamp (lessVerbose verbosity) index + noticeNoWrap verbosity $ "The index-state is set to " ++ prettyShow (IndexStateTime new_ts) ++ "." @@ -294,7 +300,7 @@ updateRepo verbosity _updateFlags repoCtxt (repo, indexState) = do -- In case current_ts is a valid timestamp different from new_ts, let -- the user know how to go back to current_ts - when (current_ts /= nullTimestamp && new_ts /= current_ts) $ + when (current_ts /= NoTimestamp && new_ts /= current_ts) $ noticeNoWrap verbosity $ "To revert to previous state run:\n" ++ " cabal v2-update '" diff --git a/cabal-install/src/Distribution/Client/Compat/Tar.hs b/cabal-install/src/Distribution/Client/Compat/Tar.hs new file mode 100644 index 00000000000..8597c61fede --- /dev/null +++ b/cabal-install/src/Distribution/Client/Compat/Tar.hs @@ -0,0 +1,68 @@ +{-# LANGUAGE CPP #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + +{- FOURMOLU_DISABLE -} +module Distribution.Client.Compat.Tar + ( extractTarGzFile +#if MIN_VERSION_tar(0,6,0) + , Tar.Entry + , Tar.Entries + , Tar.GenEntries (..) + , Tar.GenEntryContent (..) + , Tar.entryContent +#else + , Tar.Entries (..) + , Tar.Entry (..) + , Tar.EntryContent (..) +#endif + ) where +{- FOURMOLU_ENABLE -} + +import Distribution.Client.Compat.Prelude +import Prelude () + +import qualified Codec.Archive.Tar as Tar +import qualified Codec.Archive.Tar.Check as Tar +#if MIN_VERSION_tar(0,6,0) +#else +import qualified Codec.Archive.Tar.Entry as Tar +#endif +import qualified Data.ByteString.Lazy as BS +import qualified Distribution.Client.GZipUtils as GZipUtils + +instance (Exception a, Exception b) => Exception (Either a b) where + toException (Left e) = toException e + toException (Right e) = toException e + + fromException e = + case fromException e of + Just e' -> Just (Left e') + Nothing -> case fromException e of + Just e' -> Just (Right e') + Nothing -> Nothing + +{- FOURMOLU_DISABLE -} +extractTarGzFile + :: FilePath + -- ^ Destination directory + -> FilePath + -- ^ Expected subdir (to check for tarbombs) + -> FilePath + -- ^ Tarball + -> IO () +extractTarGzFile dir expected tar = +#if MIN_VERSION_tar(0,6,0) + Tar.unpackAndCheck + ( \x -> + SomeException <$> Tar.checkEntryTarbomb expected x + <|> SomeException <$> Tar.checkEntrySecurity x + ) + dir +#else + Tar.unpack dir + . Tar.checkTarbomb expected +#endif + . Tar.read + . GZipUtils.maybeDecompress + =<< BS.readFile tar +{- FOURMOLU_ENABLE -} diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index 1a1fcfbb388..1c2b4dabb27 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -531,6 +531,7 @@ instance Semigroup SavedConfig where , configDumpBuildInfo = combine configDumpBuildInfo , configAllowDependingOnPrivateLibs = combine configAllowDependingOnPrivateLibs + , configCoverageFor = combine configCoverageFor } where combine = combine' savedConfigureFlags @@ -1539,6 +1540,14 @@ parseConfig src initial = \str -> do splitMultiPath (configConfigureArgs scf) } + , savedGlobalFlags = + let sgf = savedGlobalFlags conf + in sgf + { globalProgPathExtra = + toNubList $ + splitMultiPath + (fromNubList $ globalProgPathExtra sgf) + } } parse = diff --git a/cabal-install/src/Distribution/Client/Dependency.hs b/cabal-install/src/Distribution/Client/Dependency.hs index 544ad59a341..37e0cbdf1ee 100644 --- a/cabal-install/src/Distribution/Client/Dependency.hs +++ b/cabal-install/src/Distribution/Client/Dependency.hs @@ -67,7 +67,6 @@ module Distribution.Client.Dependency ) where import Distribution.Client.Compat.Prelude -import qualified Prelude as Unsafe (head) import Distribution.Client.Dependency.Types ( PackagesPreferenceDefault (..) @@ -950,8 +949,11 @@ planPackagesProblems platform cinfo pkgs = , let packageProblems = configuredPackageProblems platform cinfo pkg , not (null packageProblems) ] - ++ [ DuplicatePackageSolverId (Graph.nodeKey (Unsafe.head dups)) dups + ++ [ DuplicatePackageSolverId (Graph.nodeKey aDup) dups | dups <- duplicatesBy (comparing Graph.nodeKey) pkgs + , aDup <- case dups of + [] -> [] + (ad : _) -> [ad] ] data PackageProblem diff --git a/cabal-install/src/Distribution/Client/DistDirLayout.hs b/cabal-install/src/Distribution/Client/DistDirLayout.hs index 2b4bc54fb3e..b1a8dc5b48a 100644 --- a/cabal-install/src/Distribution/Client/DistDirLayout.hs +++ b/cabal-install/src/Distribution/Client/DistDirLayout.hs @@ -41,10 +41,12 @@ import Distribution.Package , UnitId ) import Distribution.Simple.Compiler - ( OptimisationLevel (..) + ( Compiler (..) + , OptimisationLevel (..) , PackageDB (..) , PackageDBStack ) +import Distribution.Simple.Configure (interpretPackageDbFlags) import Distribution.System import Distribution.Types.ComponentName import Distribution.Types.LibraryName @@ -116,13 +118,13 @@ data DistDirLayout = DistDirLayout -- | The layout of a cabal nix-style store. data StoreDirLayout = StoreDirLayout - { storeDirectory :: CompilerId -> FilePath - , storePackageDirectory :: CompilerId -> UnitId -> FilePath - , storePackageDBPath :: CompilerId -> FilePath - , storePackageDB :: CompilerId -> PackageDB - , storePackageDBStack :: CompilerId -> PackageDBStack - , storeIncomingDirectory :: CompilerId -> FilePath - , storeIncomingLock :: CompilerId -> UnitId -> FilePath + { storeDirectory :: Compiler -> FilePath + , storePackageDirectory :: Compiler -> UnitId -> FilePath + , storePackageDBPath :: Compiler -> FilePath + , storePackageDB :: Compiler -> PackageDB + , storePackageDBStack :: Compiler -> [Maybe PackageDB] -> PackageDBStack + , storeIncomingDirectory :: Compiler -> FilePath + , storeIncomingLock :: Compiler -> UnitId -> FilePath } -- TODO: move to another module, e.g. CabalDirLayout? @@ -267,33 +269,36 @@ defaultStoreDirLayout :: FilePath -> StoreDirLayout defaultStoreDirLayout storeRoot = StoreDirLayout{..} where - storeDirectory :: CompilerId -> FilePath - storeDirectory compid = - storeRoot prettyShow compid - - storePackageDirectory :: CompilerId -> UnitId -> FilePath - storePackageDirectory compid ipkgid = - storeDirectory compid prettyShow ipkgid - - storePackageDBPath :: CompilerId -> FilePath - storePackageDBPath compid = - storeDirectory compid "package.db" - - storePackageDB :: CompilerId -> PackageDB - storePackageDB compid = - SpecificPackageDB (storePackageDBPath compid) - - storePackageDBStack :: CompilerId -> PackageDBStack - storePackageDBStack compid = - [GlobalPackageDB, storePackageDB compid] - - storeIncomingDirectory :: CompilerId -> FilePath - storeIncomingDirectory compid = - storeDirectory compid "incoming" - - storeIncomingLock :: CompilerId -> UnitId -> FilePath - storeIncomingLock compid unitid = - storeIncomingDirectory compid prettyShow unitid <.> "lock" + storeDirectory :: Compiler -> FilePath + storeDirectory compiler = + storeRoot case compilerAbiTag compiler of + NoAbiTag -> prettyShow (compilerId compiler) + AbiTag tag -> prettyShow (compilerId compiler) <> "-" <> tag + + storePackageDirectory :: Compiler -> UnitId -> FilePath + storePackageDirectory compiler ipkgid = + storeDirectory compiler prettyShow ipkgid + + storePackageDBPath :: Compiler -> FilePath + storePackageDBPath compiler = + storeDirectory compiler "package.db" + + storePackageDB :: Compiler -> PackageDB + storePackageDB compiler = + SpecificPackageDB (storePackageDBPath compiler) + + storePackageDBStack :: Compiler -> [Maybe PackageDB] -> PackageDBStack + storePackageDBStack compiler extraPackageDB = + (interpretPackageDbFlags False extraPackageDB) + ++ [storePackageDB compiler] + + storeIncomingDirectory :: Compiler -> FilePath + storeIncomingDirectory compiler = + storeDirectory compiler "incoming" + + storeIncomingLock :: Compiler -> UnitId -> FilePath + storeIncomingLock compiler unitid = + storeIncomingDirectory compiler prettyShow unitid <.> "lock" defaultCabalDirLayout :: IO CabalDirLayout defaultCabalDirLayout = diff --git a/cabal-install/src/Distribution/Client/Errors.hs b/cabal-install/src/Distribution/Client/Errors.hs index 5db31ba5d3b..ada3eca5268 100644 --- a/cabal-install/src/Distribution/Client/Errors.hs +++ b/cabal-install/src/Distribution/Client/Errors.hs @@ -25,6 +25,9 @@ import Data.ByteString (ByteString) import qualified Data.ByteString.Base16 as Base16 import qualified Data.ByteString.Char8 as BS8 import Data.List (groupBy) +import Distribution.Client.IndexUtils.Timestamp +import Distribution.Client.Types.Repo +import Distribution.Client.Types.RepoName (RepoName (..)) import Distribution.Compat.Prelude import Distribution.Deprecated.ParseUtils (PWarning, showPWarning) import Distribution.Package @@ -179,6 +182,8 @@ data CabalInstallException | FreezeException String | PkgSpecifierException [String] | CorruptedIndexCache String + | UnusableIndexState RemoteRepo Timestamp Timestamp + | MissingPackageList RemoteRepo deriving (Show, Typeable) exceptionCodeCabalInstall :: CabalInstallException -> Int @@ -327,6 +332,8 @@ exceptionCodeCabalInstall e = case e of FreezeException{} -> 7156 PkgSpecifierException{} -> 7157 CorruptedIndexCache{} -> 7158 + UnusableIndexState{} -> 7159 + MissingPackageList{} -> 7160 exceptionMessageCabalInstall :: CabalInstallException -> String exceptionMessageCabalInstall e = case e of @@ -828,6 +835,20 @@ exceptionMessageCabalInstall e = case e of FreezeException errs -> errs PkgSpecifierException errorStr -> unlines errorStr CorruptedIndexCache str -> str + UnusableIndexState repoRemote maxFound requested -> + "Latest known index-state for '" + ++ unRepoName (remoteRepoName repoRemote) + ++ "' (" + ++ prettyShow maxFound + ++ ") is older than the requested index-state (" + ++ prettyShow requested + ++ ").\nRun 'cabal update' or set the index-state to a value at or before " + ++ prettyShow maxFound + ++ "." + MissingPackageList repoRemote -> + "The package list for '" + ++ unRepoName (remoteRepoName repoRemote) + ++ "' does not exist. Run 'cabal update' to download it." instance Exception (VerboseException CabalInstallException) where displayException :: VerboseException CabalInstallException -> [Char] diff --git a/cabal-install/src/Distribution/Client/FileMonitor.hs b/cabal-install/src/Distribution/Client/FileMonitor.hs index 5edd159496b..084545d5e7e 100644 --- a/cabal-install/src/Distribution/Client/FileMonitor.hs +++ b/cabal-install/src/Distribution/Client/FileMonitor.hs @@ -14,7 +14,7 @@ module Distribution.Client.FileMonitor MonitorFilePath (..) , MonitorKindFile (..) , MonitorKindDir (..) - , FilePathGlob (..) + , RootedGlob (..) , monitorFile , monitorFileHashed , monitorNonExistentFile @@ -91,7 +91,7 @@ data MonitorFilePath | MonitorFileGlob { monitorKindFile :: !MonitorKindFile , monitorKindDir :: !MonitorKindDir - , monitorPathGlob :: !FilePathGlob + , monitorPathGlob :: !RootedGlob } deriving (Eq, Show, Generic) @@ -168,13 +168,13 @@ monitorFileOrDirectory = MonitorFile FileModTime DirModTime -- The monitored glob is considered to have changed if the set of files -- matching the glob changes (i.e. creations or deletions), or for files if the -- modification time and content hash of any matching file has changed. -monitorFileGlob :: FilePathGlob -> MonitorFilePath +monitorFileGlob :: RootedGlob -> MonitorFilePath monitorFileGlob = MonitorFileGlob FileHashed DirExists -- | Monitor a set of files (or directories) identified by a file glob for -- existence only. The monitored glob is considered to have changed if the set -- of files matching the glob changes (i.e. creations or deletions). -monitorFileGlobExistence :: FilePathGlob -> MonitorFilePath +monitorFileGlobExistence :: RootedGlob -> MonitorFilePath monitorFileGlobExistence = MonitorFileGlob FileExists DirExists -- | Creates a list of files to monitor when you search for a file which @@ -263,12 +263,12 @@ data MonitorStateGlob data MonitorStateGlobRel = MonitorStateGlobDirs + !GlobPieces !Glob - !FilePathGlobRel !ModTime ![(FilePath, MonitorStateGlobRel)] -- invariant: sorted | MonitorStateGlobFiles - !Glob + !GlobPieces !ModTime ![(FilePath, MonitorStateFileStatus)] -- invariant: sorted | MonitorStateGlobDirTrailing @@ -294,7 +294,7 @@ reconstructMonitorFilePaths (MonitorStateFileSet singlePaths globPaths) = getGlobPath :: MonitorStateGlob -> MonitorFilePath getGlobPath (MonitorStateGlob kindfile kinddir root gstate) = MonitorFileGlob kindfile kinddir $ - FilePathGlob root $ + RootedGlob root $ case gstate of MonitorStateGlobDirs glob globs _ _ -> GlobDir glob globs MonitorStateGlobFiles glob _ _ -> GlobFile glob @@ -698,7 +698,7 @@ probeMonitorStateGlobRel let subdir = root dirName entry in liftIO $ doesDirectoryExist subdir ) - . filter (matchGlob glob) + . filter (matchGlobPieces glob) =<< liftIO (getDirectoryContents (root dirName)) children' <- @@ -784,7 +784,7 @@ probeMonitorStateGlobRel -- directory modification time changed: -- a matching file may have been added or deleted matches <- - return . filter (matchGlob glob) + return . filter (matchGlobPieces glob) =<< liftIO (getDirectoryContents (root dirName)) traverse_ probeMergeResult $ @@ -1002,7 +1002,7 @@ buildMonitorStateGlob -> MonitorKindDir -> FilePath -- ^ the root directory - -> FilePathGlob + -> RootedGlob -- ^ the matching glob -> IO MonitorStateGlob buildMonitorStateGlob @@ -1011,7 +1011,7 @@ buildMonitorStateGlob kindfile kinddir relroot - (FilePathGlob globroot globPath) = do + (RootedGlob globroot globPath) = do root <- liftIO $ getFilePathRootDirectory globroot relroot MonitorStateGlob kindfile kinddir globroot <$> buildMonitorStateGlobRel @@ -1035,7 +1035,7 @@ buildMonitorStateGlobRel -> FilePath -- ^ directory we are examining -- relative to the root - -> FilePathGlobRel + -> Glob -- ^ the matching glob -> IO MonitorStateGlobRel buildMonitorStateGlobRel @@ -1050,10 +1050,11 @@ buildMonitorStateGlobRel dirEntries <- getDirectoryContents absdir dirMTime <- getModTime absdir case globPath of + GlobDirRecursive{} -> error "Monitoring directory-recursive globs (i.e. ../**/...) is currently unsupported" GlobDir glob globPath' -> do subdirs <- filterM (\subdir -> doesDirectoryExist (absdir subdir)) $ - filter (matchGlob glob) dirEntries + filter (matchGlobPieces glob) dirEntries subdirStates <- for (sort subdirs) $ \subdir -> do fstate <- @@ -1068,7 +1069,7 @@ buildMonitorStateGlobRel return (subdir, fstate) return $! MonitorStateGlobDirs glob globPath' dirMTime subdirStates GlobFile glob -> do - let files = filter (matchGlob glob) dirEntries + let files = filter (matchGlobPieces glob) dirEntries filesStates <- for (sort files) $ \file -> do fstate <- diff --git a/cabal-install/src/Distribution/Client/Get.hs b/cabal-install/src/Distribution/Client/Get.hs index 99ebe749161..39ace2f2652 100644 --- a/cabal-install/src/Distribution/Client/Get.hs +++ b/cabal-install/src/Distribution/Client/Get.hs @@ -78,6 +78,9 @@ import Distribution.Solver.Types.SourcePackage import Control.Monad (mapM_) import qualified Data.Map as Map import Distribution.Client.Errors +import Distribution.Utils.NubList + ( fromNubList + ) import System.Directory ( createDirectoryIfMissing , doesDirectoryExist @@ -99,7 +102,7 @@ get -> IO () get verbosity _ _ _ [] = notice verbosity "No packages requested. Nothing to do." -get verbosity repoCtxt _ getFlags userTargets = do +get verbosity repoCtxt globalFlags getFlags userTargets = do let useSourceRepo = case getSourceRepository getFlags of NoFlag -> False _ -> True @@ -154,7 +157,7 @@ get verbosity repoCtxt _ getFlags userTargets = do clone :: [UnresolvedSourcePackage] -> IO () clone = - clonePackagesFromSourceRepo verbosity prefix kind + clonePackagesFromSourceRepo verbosity prefix kind (fromNubList $ globalProgPathExtra globalFlags) . map (\pkg -> (packageId pkg, packageSourceRepos pkg)) where kind :: Maybe RepoKind @@ -337,6 +340,8 @@ clonePackagesFromSourceRepo -- ^ destination dir prefix -> Maybe RepoKind -- ^ preferred 'RepoKind' + -> [FilePath] + -- ^ Extra prog paths -> [(PackageId, [PD.SourceRepo])] -- ^ the packages and their -- available 'SourceRepo's @@ -345,13 +350,14 @@ clonePackagesFromSourceRepo verbosity destDirPrefix preferredRepoKind + progPaths pkgrepos = do -- Do a bunch of checks and collect the required info pkgrepos' <- traverse preCloneChecks pkgrepos -- Configure the VCS drivers for all the repository types we may need vcss <- - configureVCSs verbosity $ + configureVCSs verbosity progPaths $ Map.fromList [ (vcsRepoType vcs, vcs) | (_, _, vcs, _) <- pkgrepos' diff --git a/cabal-install/src/Distribution/Client/Glob.hs b/cabal-install/src/Distribution/Client/Glob.hs index 66baadf7a5d..90054a8f64f 100644 --- a/cabal-install/src/Distribution/Client/Glob.hs +++ b/cabal-install/src/Distribution/Client/Glob.hs @@ -1,50 +1,48 @@ {-# LANGUAGE DeriveGeneric #-} --- TODO: [code cleanup] plausibly much of this module should be merged with --- similar functionality in Cabal. module Distribution.Client.Glob - ( FilePathGlob (..) + ( -- * cabal-install globbing features + RootedGlob (..) + , isTrivialRootedGlob , FilePathRoot (..) - , FilePathGlobRel (..) - , Glob + , getFilePathRootDirectory + + -- * Additional re-exports + , module Distribution.Simple.Glob + , Glob (..) , GlobPiece (..) - , matchFileGlob - , matchFileGlobRel + , GlobPieces , matchGlob - , isTrivialFilePathGlob - , getFilePathRootDirectory + , matchGlobPieces + , matchFileGlob ) where import Distribution.Client.Compat.Prelude import Prelude () -import Data.List (stripPrefix) +import Distribution.Simple.Glob +import Distribution.Simple.Glob.Internal + import System.Directory import System.FilePath import qualified Distribution.Compat.CharParsing as P import qualified Text.PrettyPrint as Disp --- | A file path specified by globbing -data FilePathGlob = FilePathGlob FilePathRoot FilePathGlobRel - deriving (Eq, Show, Generic) +-------------------------------------------------------------------------------- -data FilePathGlobRel - = GlobDir !Glob !FilePathGlobRel - | GlobFile !Glob - | -- | trailing dir, a glob ending in @/@ - GlobDirTrailing +-- | A file path specified by globbing, relative +-- to some root directory. +data RootedGlob + = RootedGlob + FilePathRoot + -- ^ what the glob is relative to + Glob + -- ^ the glob deriving (Eq, Show, Generic) --- | A single directory or file component of a globbed path -type Glob = [GlobPiece] - --- | A piece of a globbing pattern -data GlobPiece - = WildCard - | Literal String - | Union [Glob] - deriving (Eq, Show, Generic) +instance Binary RootedGlob +instance Structured RootedGlob data FilePathRoot = FilePathRelative @@ -53,27 +51,22 @@ data FilePathRoot | FilePathHomeDir deriving (Eq, Show, Generic) -instance Binary FilePathGlob instance Binary FilePathRoot -instance Binary FilePathGlobRel -instance Binary GlobPiece - -instance Structured FilePathGlob instance Structured FilePathRoot -instance Structured FilePathGlobRel -instance Structured GlobPiece --- | Check if a 'FilePathGlob' doesn't actually make use of any globbing and +-- | Check if a 'RootedGlob' doesn't actually make use of any globbing and -- is in fact equivalent to a non-glob 'FilePath'. -- -- If it is trivial in this sense then the result is the equivalent constant --- 'FilePath'. On the other hand if it is not trivial (so could in principle --- match more than one file) then the result is @Nothing@. -isTrivialFilePathGlob :: FilePathGlob -> Maybe FilePath -isTrivialFilePathGlob (FilePathGlob root pathglob) = +-- 'FilePath'. On the other hand, if it is not trivial (so could in principle +-- match more than one file), then the result is @Nothing@. +isTrivialRootedGlob :: RootedGlob -> Maybe FilePath +isTrivialRootedGlob (RootedGlob root pathglob) = case root of FilePathRelative -> go [] pathglob FilePathRoot root' -> go [root'] pathglob + -- TODO: why don't we do the following? + -- > go ["~"] pathglob FilePathHomeDir -> Nothing where go paths (GlobDir [Literal path] globs) = go (path : paths) globs @@ -102,79 +95,30 @@ getFilePathRootDirectory FilePathHomeDir _ = getHomeDirectory -- Matching -- --- | Match a 'FilePathGlob' against the file system, starting from a given +-- | Match a 'RootedGlob' against the file system, starting from a given -- root directory for relative paths. The results of relative globs are -- relative to the given root. Matches for absolute globs are absolute. -matchFileGlob :: FilePath -> FilePathGlob -> IO [FilePath] -matchFileGlob relroot (FilePathGlob globroot glob) = do +matchFileGlob :: FilePath -> RootedGlob -> IO [FilePath] +matchFileGlob relroot (RootedGlob globroot glob) = do root <- getFilePathRootDirectory globroot relroot - matches <- matchFileGlobRel root glob + matches <- matchGlob root glob case globroot of FilePathRelative -> return matches _ -> return (map (root ) matches) --- | Match a 'FilePathGlobRel' against the file system, starting from a --- given root directory. The results are all relative to the given root. -matchFileGlobRel :: FilePath -> FilePathGlobRel -> IO [FilePath] -matchFileGlobRel root glob0 = go glob0 "" - where - go (GlobFile glob) dir = do - entries <- getDirectoryContents (root dir) - let files = filter (matchGlob glob) entries - return (map (dir ) files) - go (GlobDir glob globPath) dir = do - entries <- getDirectoryContents (root dir) - subdirs <- - filterM - ( \subdir -> - doesDirectoryExist - (root dir subdir) - ) - $ filter (matchGlob glob) entries - concat <$> traverse (\subdir -> go globPath (dir subdir)) subdirs - go GlobDirTrailing dir = return [dir] - --- | Match a globbing pattern against a file path component -matchGlob :: Glob -> String -> Bool -matchGlob = goStart - where - -- From the man page, glob(7): - -- "If a filename starts with a '.', this character must be - -- matched explicitly." - - go, goStart :: [GlobPiece] -> String -> Bool - - goStart (WildCard : _) ('.' : _) = False - goStart (Union globs : rest) cs = - any - (\glob -> goStart (glob ++ rest) cs) - globs - goStart rest cs = go rest cs - - go [] "" = True - go (Literal lit : rest) cs - | Just cs' <- stripPrefix lit cs = - go rest cs' - | otherwise = False - go [WildCard] "" = True - go (WildCard : rest) (c : cs) = go rest (c : cs) || go (WildCard : rest) cs - go (Union globs : rest) cs = any (\glob -> go (glob ++ rest) cs) globs - go [] (_ : _) = False - go (_ : _) "" = False - ------------------------------------------------------------------------------ --- Parsing & printing +-- Parsing & pretty-printing -- -instance Pretty FilePathGlob where - pretty (FilePathGlob root pathglob) = pretty root Disp.<> pretty pathglob +instance Pretty RootedGlob where + pretty (RootedGlob root pathglob) = pretty root Disp.<> pretty pathglob -instance Parsec FilePathGlob where +instance Parsec RootedGlob where parsec = do root <- parsec case root of - FilePathRelative -> FilePathGlob root <$> parsec - _ -> FilePathGlob root <$> parsec <|> pure (FilePathGlob root GlobDirTrailing) + FilePathRelative -> RootedGlob root <$> parsec + _ -> RootedGlob root <$> parsec <|> pure (RootedGlob root GlobDirTrailing) instance Pretty FilePathRoot where pretty FilePathRelative = Disp.empty @@ -191,68 +135,3 @@ instance Parsec FilePathRoot where _ <- P.char ':' _ <- P.char '/' <|> P.char '\\' return (FilePathRoot (toUpper dr : ":\\")) - -instance Pretty FilePathGlobRel where - pretty (GlobDir glob pathglob) = - dispGlob glob - Disp.<> Disp.char '/' - Disp.<> pretty pathglob - pretty (GlobFile glob) = dispGlob glob - pretty GlobDirTrailing = Disp.empty - -instance Parsec FilePathGlobRel where - parsec = parsecPath - where - parsecPath :: CabalParsing m => m FilePathGlobRel - parsecPath = do - glob <- parsecGlob - dirSep *> (GlobDir glob <$> parsecPath <|> pure (GlobDir glob GlobDirTrailing)) <|> pure (GlobFile glob) - - dirSep :: CabalParsing m => m () - dirSep = - () <$ P.char '/' - <|> P.try - ( do - _ <- P.char '\\' - -- check this isn't an escape code - P.notFollowedBy (P.satisfy isGlobEscapedChar) - ) - -dispGlob :: Glob -> Disp.Doc -dispGlob = Disp.hcat . map dispPiece - where - dispPiece WildCard = Disp.char '*' - dispPiece (Literal str) = Disp.text (escape str) - dispPiece (Union globs) = - Disp.braces - ( Disp.hcat - ( Disp.punctuate - (Disp.char ',') - (map dispGlob globs) - ) - ) - escape [] = [] - escape (c : cs) - | isGlobEscapedChar c = '\\' : c : escape cs - | otherwise = c : escape cs - -parsecGlob :: CabalParsing m => m Glob -parsecGlob = some parsecPiece - where - parsecPiece = P.choice [literal, wildcard, union] - - wildcard = WildCard <$ P.char '*' - union = Union . toList <$> P.between (P.char '{') (P.char '}') (P.sepByNonEmpty parsecGlob (P.char ',')) - literal = Literal <$> some litchar - - litchar = normal <|> escape - - normal = P.satisfy (\c -> not (isGlobEscapedChar c) && c /= '/' && c /= '\\') - escape = P.try $ P.char '\\' >> P.satisfy isGlobEscapedChar - -isGlobEscapedChar :: Char -> Bool -isGlobEscapedChar '*' = True -isGlobEscapedChar '{' = True -isGlobEscapedChar '}' = True -isGlobEscapedChar ',' = True -isGlobEscapedChar _ = False diff --git a/cabal-install/src/Distribution/Client/HashValue.hs b/cabal-install/src/Distribution/Client/HashValue.hs index c245750bb9f..e19956b7ed3 100644 --- a/cabal-install/src/Distribution/Client/HashValue.hs +++ b/cabal-install/src/Distribution/Client/HashValue.hs @@ -7,7 +7,6 @@ module Distribution.Client.HashValue , hashValue , truncateHash , showHashValue - , showHashValueBase64 , readFileHashValue , hashFromTUF ) where @@ -19,7 +18,6 @@ import qualified Hackage.Security.Client as Sec import qualified Crypto.Hash.SHA256 as SHA256 import qualified Data.ByteString.Base16 as Base16 -import qualified Data.ByteString.Base64 as Base64 import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as LBS @@ -57,9 +55,6 @@ hashValue = HashValue . SHA256.hashlazy showHashValue :: HashValue -> String showHashValue (HashValue digest) = BS.unpack (Base16.encode digest) -showHashValueBase64 :: HashValue -> String -showHashValueBase64 (HashValue digest) = BS.unpack (Base64.encode digest) - -- | Hash the content of a file. Uses SHA256. readFileHashValue :: FilePath -> IO HashValue readFileHashValue tarball = diff --git a/cabal-install/src/Distribution/Client/HttpUtils.hs b/cabal-install/src/Distribution/Client/HttpUtils.hs index 39251039a36..72ba34d9f9d 100644 --- a/cabal-install/src/Distribution/Client/HttpUtils.hs +++ b/cabal-install/src/Distribution/Client/HttpUtils.hs @@ -38,7 +38,6 @@ import Distribution.Simple.Program ( ConfiguredProgram , Program , ProgramInvocation (..) - , ProgramSearchPathEntry (..) , getProgramInvocationOutput , programInvocation , programPath @@ -50,7 +49,7 @@ import Distribution.Simple.Program.Db , configureAllKnownPrograms , emptyProgramDb , lookupProgram - , modifyProgramSearchPath + , prependProgramSearchPath , requireProgram ) import Distribution.Simple.Program.Run @@ -409,7 +408,7 @@ configureTransport verbosity extraPath (Just name) = case find (\(name', _, _, _) -> name' == name) supportedTransports of Just (_, mprog, _tls, mkTrans) -> do - let baseProgDb = modifyProgramSearchPath (\p -> map ProgramSearchPathDir extraPath ++ p) emptyProgramDb + baseProgDb <- prependProgramSearchPath verbosity extraPath emptyProgramDb progdb <- case mprog of Nothing -> return emptyProgramDb Just prog -> snd <$> requireProgram verbosity prog baseProgDb @@ -425,7 +424,7 @@ configureTransport verbosity extraPath Nothing = do -- for all the transports except plain-http we need to try and find -- their external executable - let baseProgDb = modifyProgramSearchPath (\p -> map ProgramSearchPathDir extraPath ++ p) emptyProgramDb + baseProgDb <- prependProgramSearchPath verbosity extraPath emptyProgramDb progdb <- configureAllKnownPrograms verbosity $ addKnownPrograms diff --git a/cabal-install/src/Distribution/Client/IndexUtils.hs b/cabal-install/src/Distribution/Client/IndexUtils.hs index e2ea4486426..2dc7d37e29c 100644 --- a/cabal-install/src/Distribution/Client/IndexUtils.hs +++ b/cabal-install/src/Distribution/Client/IndexUtils.hs @@ -212,7 +212,7 @@ data IndexStateInfo = IndexStateInfo } emptyStateInfo :: IndexStateInfo -emptyStateInfo = IndexStateInfo nullTimestamp nullTimestamp +emptyStateInfo = IndexStateInfo NoTimestamp NoTimestamp -- | Filters a 'Cache' according to an 'IndexState' -- specification. Also returns 'IndexStateInfo' describing the @@ -318,40 +318,31 @@ getSourcePackagesAtIndexState verbosity repoCtxt mb_idxState mb_activeRepos = do IndexStateHead -> do info verbosity ("index-state(" ++ unRepoName rname ++ ") = " ++ prettyShow (isiHeadTime isi)) return () - IndexStateTime ts0 -> do + IndexStateTime ts0 -> + -- isiMaxTime is the latest timestamp in the filtered view returned by + -- `readRepoIndex` above. It is always true that isiMaxTime is less or + -- equal to a requested IndexStateTime. When `isiMaxTime isi /= ts0` (or + -- equivalently `isiMaxTime isi < ts0`) it means that ts0 falls between + -- two timestamps in the index. when (isiMaxTime isi /= ts0) $ - if ts0 > isiMaxTime isi - then - warn verbosity $ - "Requested index-state " - ++ prettyShow ts0 - ++ " is newer than '" + let commonMsg = + "There is no index-state for '" ++ unRepoName rname - ++ "'!" - ++ " Falling back to older state (" - ++ prettyShow (isiMaxTime isi) - ++ ")." - else - info verbosity $ - "Requested index-state " + ++ "' exactly at the requested timestamp (" ++ prettyShow ts0 - ++ " does not exist in '" - ++ unRepoName rname - ++ "'!" - ++ " Falling back to older state (" - ++ prettyShow (isiMaxTime isi) - ++ ")." - info - verbosity - ( "index-state(" - ++ unRepoName rname - ++ ") = " - ++ prettyShow (isiMaxTime isi) - ++ " (HEAD = " - ++ prettyShow (isiHeadTime isi) - ++ ")" - ) - + ++ "). " + in if isNothing $ timestampToUTCTime (isiMaxTime isi) + then + warn verbosity $ + commonMsg + ++ "Also, there are no index-states before the one requested, so the repository '" + ++ unRepoName rname + ++ "' will be empty." + else + info verbosity $ + commonMsg + ++ "Falling back to the previous index-state that exists: " + ++ prettyShow (isiMaxTime isi) pure RepoData { rdRepoName = rname @@ -381,7 +372,7 @@ getSourcePackagesAtIndexState verbosity repoCtxt mb_idxState mb_activeRepos = do [ (n, IndexStateTime ts) | (RepoData n ts _idx _prefs, _strategy) <- pkgss' , -- e.g. file+noindex have nullTimestamp as their timestamp - ts /= nullTimestamp + ts /= NoTimestamp ] let addIndex @@ -439,15 +430,16 @@ readRepoIndex -> IO (PackageIndex UnresolvedSourcePackage, [Dependency], IndexStateInfo) readRepoIndex verbosity repoCtxt repo idxState = handleNotFound $ do - when (isRepoRemote repo) $ warnIfIndexIsOld =<< getIndexFileAge repo - -- note that if this step fails due to a bad repo cache, the the procedure can still succeed by reading from the existing cache, which is updated regardless. - updateRepoIndexCache verbosity (RepoIndex repoCtxt repo) - `catchIO` (\e -> warn verbosity $ "unable to update the repo index cache -- " ++ displayException e) - readPackageIndexCacheFile - verbosity - mkAvailablePackage - (RepoIndex repoCtxt repo) - idxState + ret@(_, _, isi) <- + readPackageIndexCacheFile + verbosity + mkAvailablePackage + (RepoIndex repoCtxt repo) + idxState + when (isRepoRemote repo) $ do + warnIfIndexIsOld =<< getIndexFileAge repo + dieIfRequestedIdxIsNewer isi + pure ret where mkAvailablePackage pkgEntry = SourcePackage @@ -468,8 +460,8 @@ readRepoIndex verbosity repoCtxt repo idxState = if isDoesNotExistError e then do case repo of - RepoRemote{..} -> warn verbosity $ errMissingPackageList repoRemote - RepoSecure{..} -> warn verbosity $ errMissingPackageList repoRemote + RepoRemote{..} -> dieWithException verbosity $ MissingPackageList repoRemote + RepoSecure{..} -> dieWithException verbosity $ MissingPackageList repoRemote RepoLocalNoIndex local _ -> warn verbosity $ "Error during construction of local+noindex " @@ -479,18 +471,25 @@ readRepoIndex verbosity repoCtxt repo idxState = return (mempty, mempty, emptyStateInfo) else ioError e + isOldThreshold :: Double isOldThreshold = 15 -- days warnIfIndexIsOld dt = do when (dt >= isOldThreshold) $ case repo of - RepoRemote{..} -> warn verbosity $ errOutdatedPackageList repoRemote dt - RepoSecure{..} -> warn verbosity $ errOutdatedPackageList repoRemote dt + RepoRemote{..} -> warn verbosity $ warnOutdatedPackageList repoRemote dt + RepoSecure{..} -> warn verbosity $ warnOutdatedPackageList repoRemote dt RepoLocalNoIndex{} -> return () - errMissingPackageList repoRemote = - "The package list for '" - ++ unRepoName (remoteRepoName repoRemote) - ++ "' does not exist. Run 'cabal update' to download it." - errOutdatedPackageList repoRemote dt = + dieIfRequestedIdxIsNewer isi = + let latestTime = isiHeadTime isi + in case idxState of + IndexStateTime t -> when (t > latestTime) $ case repo of + RepoSecure{..} -> + dieWithException verbosity $ UnusableIndexState repoRemote latestTime t + RepoRemote{} -> pure () + RepoLocalNoIndex{} -> return () + IndexStateHead -> pure () + + warnOutdatedPackageList repoRemote dt = "The package list for '" ++ unRepoName (remoteRepoName repoRemote) ++ "' is " @@ -852,9 +851,8 @@ withIndexEntries _ (RepoIndex repoCtxt repo@RepoSecure{}) callback _ = where blockNo = Sec.directoryEntryBlockNo dirEntry timestamp = - fromMaybe (error "withIndexEntries: invalid timestamp") $ - epochTimeToTimestamp $ - Sec.indexEntryTime sie + epochTimeToTimestamp $ + Sec.indexEntryTime sie withIndexEntries verbosity (RepoIndex _repoCtxt (RepoLocalNoIndex (LocalRepo name localDir _) _cacheDir)) _ callback = do dirContents <- listDirectory localDir let contentSet = Set.fromList dirContents @@ -942,10 +940,14 @@ withIndexEntries verbosity index callback _ = do callback $ map toCache (catMaybes pkgsOrPrefs) where toCache :: PackageOrDep -> IndexCacheEntry - toCache (Pkg (NormalPackage pkgid _ _ blockNo)) = CachePackageId pkgid blockNo nullTimestamp + toCache (Pkg (NormalPackage pkgid _ _ blockNo)) = CachePackageId pkgid blockNo NoTimestamp toCache (Pkg (BuildTreeRef refType _ _ _ blockNo)) = CacheBuildTreeRef refType blockNo - toCache (Dep d) = CachePreference d 0 nullTimestamp + toCache (Dep d) = CachePreference d 0 NoTimestamp +-- | Read package data from a repository. +-- Throws IOException if any arise while accessing the index +-- (unless the repo is local+no-index) and dies if the cache +-- is corrupted and cannot be regenerated correctly. readPackageIndexCacheFile :: Package pkg => Verbosity @@ -959,12 +961,18 @@ readPackageIndexCacheFile verbosity mkPkg index idxState (pkgs, prefs) <- packageNoIndexFromCache verbosity mkPkg cache0 pure (pkgs, prefs, emptyStateInfo) | otherwise = do - cache0 <- readIndexCache verbosity index + (cache, isi) <- getIndexCache verbosity index idxState indexHnd <- openFile (indexFile index) ReadMode - let (cache, isi) = filterCache idxState cache0 (pkgs, deps) <- packageIndexFromCache verbosity mkPkg indexHnd cache pure (pkgs, deps, isi) +-- | Read 'Cache' and 'IndexStateInfo' from the repository index file. +-- Throws IOException if any arise (e.g. the index or its cache are missing). +-- Dies if the index cache is corrupted and cannot be regenerated correctly. +getIndexCache :: Verbosity -> Index -> RepoIndexState -> IO (Cache, IndexStateInfo) +getIndexCache verbosity index idxState = + filterCache idxState <$> readIndexCache verbosity index + packageIndexFromCache :: Package pkg => Verbosity @@ -1087,7 +1095,7 @@ packageListFromCache verbosity mkPkg hnd Cache{..} = accum mempty [] mempty cach ------------------------------------------------------------------------ -- Index cache data structure -- --- | Read the 'Index' cache from the filesystem +-- | Read a repository cache from the filesystem -- -- If a corrupted index cache is detected this function regenerates -- the index cache and then reattempt to read the index once (and @@ -1110,6 +1118,11 @@ readIndexCache verbosity index = do either (dieWithException verbosity . CorruptedIndexCache) (return . hashConsCache) =<< readIndexCache' index Right res -> return (hashConsCache res) +-- | Read a no-index repository cache from the filesystem +-- +-- If a corrupted index cache is detected this function regenerates +-- the index cache and then reattempts to read the index once (and +-- 'dieWithException's if it fails again). Throws IOException if any arise. readNoIndexCache :: Verbosity -> Index -> IO NoIndexCache readNoIndexCache verbosity index = do cacheOrFail <- readNoIndexCache' index @@ -1130,11 +1143,12 @@ readNoIndexCache verbosity index = do -- we don't hash cons local repository cache, they are hopefully small Right res -> return res --- | Read the 'Index' cache from the filesystem without attempting to --- regenerate on parsing failures. +-- | Read the 'Index' cache from the filesystem. Throws IO exceptions +-- if any arise and returns Left on invalid input. readIndexCache' :: Index -> IO (Either String Cache) readIndexCache' index - | is01Index index = structuredDecodeFileOrFail (cacheFile index) + | is01Index index = + structuredDecodeFileOrFail (cacheFile index) | otherwise = Right . read00IndexCache <$> BSS.readFile (cacheFile index) @@ -1159,15 +1173,27 @@ writeIndexTimestamp index st = writeFile (timestampFile index) (prettyShow st) -- | Read out the "current" index timestamp, i.e., what --- timestamp you would use to revert to this version -currentIndexTimestamp :: Verbosity -> RepoContext -> Repo -> IO Timestamp -currentIndexTimestamp verbosity repoCtxt r = do - mb_is <- readIndexTimestamp verbosity (RepoIndex repoCtxt r) +-- timestamp you would use to revert to this version. +-- +-- Note: this is not the same as 'readIndexTimestamp'! +-- This resolves HEAD to the index's 'isiHeadTime', i.e. +-- the index latest known timestamp. +-- +-- Return NoTimestamp if the index has never been updated. +currentIndexTimestamp :: Verbosity -> Index -> IO Timestamp +currentIndexTimestamp verbosity index = do + mb_is <- readIndexTimestamp verbosity index case mb_is of - Just (IndexStateTime ts) -> return ts - _ -> do - (_, _, isi) <- readRepoIndex verbosity repoCtxt r IndexStateHead - return (isiHeadTime isi) + -- If the index timestamp file specifies an index state time, use that + Just (IndexStateTime ts) -> + return ts + -- Otherwise used the head time as stored in the index cache + _otherwise -> + fmap (isiHeadTime . snd) (getIndexCache verbosity index IndexStateHead) + `catchIO` \e -> + if isDoesNotExistError e + then return NoTimestamp + else ioError e -- | Read the 'IndexState' from the filesystem readIndexTimestamp :: Verbosity -> Index -> IO (Maybe RepoIndexState) @@ -1259,7 +1285,7 @@ instance NFData NoIndexCacheEntry where rnf (NoIndexCachePreference dep) = rnf dep cacheEntryTimestamp :: IndexCacheEntry -> Timestamp -cacheEntryTimestamp (CacheBuildTreeRef _ _) = nullTimestamp +cacheEntryTimestamp (CacheBuildTreeRef _ _) = NoTimestamp cacheEntryTimestamp (CachePreference _ _ ts) = ts cacheEntryTimestamp (CachePackageId _ _ ts) = ts @@ -1311,7 +1337,7 @@ preferredVersionKey = "pref-ver:" read00IndexCache :: BSS.ByteString -> Cache read00IndexCache bs = Cache - { cacheHeadTs = nullTimestamp + { cacheHeadTs = NoTimestamp , cacheEntries = mapMaybe read00IndexCacheEntry $ BSS.lines bs } @@ -1329,7 +1355,7 @@ read00IndexCacheEntry = \line -> ( CachePackageId (PackageIdentifier pkgname pkgver) blockno - nullTimestamp + NoTimestamp ) _ -> Nothing [key, typecodestr, blocknostr] | key == BSS.pack buildTreeRefKey -> @@ -1339,7 +1365,7 @@ read00IndexCacheEntry = \line -> _ -> Nothing (key : remainder) | key == BSS.pack preferredVersionKey -> do pref <- simpleParsecBS (BSS.unwords remainder) - return $ CachePreference pref 0 nullTimestamp + return $ CachePreference pref 0 NoTimestamp _ -> Nothing where parseName str diff --git a/cabal-install/src/Distribution/Client/IndexUtils/ActiveRepos.hs b/cabal-install/src/Distribution/Client/IndexUtils/ActiveRepos.hs index e65000e6b98..daa4ec86355 100644 --- a/cabal-install/src/Distribution/Client/IndexUtils/ActiveRepos.hs +++ b/cabal-install/src/Distribution/Client/IndexUtils/ActiveRepos.hs @@ -70,7 +70,7 @@ instance Pretty ActiveRepos where -- Just (ActiveRepos [ActiveRepoRest CombineStrategyMerge]) -- -- >>> simpleParsec "hackage.haskell.org, :rest, head.hackage:override" :: Maybe ActiveRepos --- Just (ActiveRepos [ActiveRepo (RepoName "hackage.haskell.org") CombineStrategyMerge,ActiveRepoRest CombineStrategyMerge,ActiveRepo (RepoName "head.hackage") CombineStrategyOverride]) +-- Just (ActiveRepos [ActiveRepo (RepoName {unRepoName = "hackage.haskell.org"}) CombineStrategyMerge,ActiveRepoRest CombineStrategyMerge,ActiveRepo (RepoName {unRepoName = "head.hackage"}) CombineStrategyOverride]) instance Parsec ActiveRepos where parsec = ActiveRepos [] <$ P.try (P.string ":none") @@ -148,13 +148,13 @@ instance Parsec CombineStrategy where -- -- >>> let repos = [RepoName "a", RepoName "b", RepoName "c"] -- >>> organizeByRepos (ActiveRepos [ActiveRepoRest CombineStrategyMerge]) id repos --- Right [(RepoName "a",CombineStrategyMerge),(RepoName "b",CombineStrategyMerge),(RepoName "c",CombineStrategyMerge)] +-- Right [(RepoName {unRepoName = "a"},CombineStrategyMerge),(RepoName {unRepoName = "b"},CombineStrategyMerge),(RepoName {unRepoName = "c"},CombineStrategyMerge)] -- -- >>> organizeByRepos (ActiveRepos [ActiveRepo (RepoName "b") CombineStrategyOverride, ActiveRepoRest CombineStrategyMerge]) id repos --- Right [(RepoName "b",CombineStrategyOverride),(RepoName "a",CombineStrategyMerge),(RepoName "c",CombineStrategyMerge)] +-- Right [(RepoName {unRepoName = "b"},CombineStrategyOverride),(RepoName {unRepoName = "a"},CombineStrategyMerge),(RepoName {unRepoName = "c"},CombineStrategyMerge)] -- -- >>> organizeByRepos (ActiveRepos [ActiveRepoRest CombineStrategyMerge, ActiveRepo (RepoName "b") CombineStrategyOverride]) id repos --- Right [(RepoName "a",CombineStrategyMerge),(RepoName "c",CombineStrategyMerge),(RepoName "b",CombineStrategyOverride)] +-- Right [(RepoName {unRepoName = "a"},CombineStrategyMerge),(RepoName {unRepoName = "c"},CombineStrategyMerge),(RepoName {unRepoName = "b"},CombineStrategyOverride)] -- -- >>> organizeByRepos (ActiveRepos [ActiveRepoRest CombineStrategyMerge, ActiveRepo (RepoName "d") CombineStrategyOverride]) id repos -- Left "no repository provided d" diff --git a/cabal-install/src/Distribution/Client/IndexUtils/IndexState.hs b/cabal-install/src/Distribution/Client/IndexUtils/IndexState.hs index 8acf2b3bdc3..0e9cb6a73d3 100644 --- a/cabal-install/src/Distribution/Client/IndexUtils/IndexState.hs +++ b/cabal-install/src/Distribution/Client/IndexUtils/IndexState.hs @@ -68,10 +68,10 @@ instance Pretty TotalIndexState where -- Just (TIS IndexStateHead (fromList [])) -- -- >>> simpleParsec "2020-02-04T12:34:56Z, hackage.haskell.org HEAD" :: Maybe TotalIndexState --- Just (TIS (IndexStateTime (TS 1580819696)) (fromList [(RepoName "hackage.haskell.org",IndexStateHead)])) +-- Just (TIS (IndexStateTime (TS 1580819696)) (fromList [(RepoName {unRepoName = "hackage.haskell.org"},IndexStateHead)])) -- -- >>> simpleParsec "hackage.haskell.org 2020-02-04T12:34:56Z" :: Maybe TotalIndexState --- Just (TIS IndexStateHead (fromList [(RepoName "hackage.haskell.org",IndexStateTime (TS 1580819696))])) +-- Just (TIS IndexStateHead (fromList [(RepoName {unRepoName = "hackage.haskell.org"},IndexStateTime (TS 1580819696))])) instance Parsec TotalIndexState where parsec = normalise . foldl' add headTotalIndexState <$> parsecLeadingCommaNonEmpty single0 where diff --git a/cabal-install/src/Distribution/Client/IndexUtils/Timestamp.hs b/cabal-install/src/Distribution/Client/IndexUtils/Timestamp.hs index 3dfe2963437..10034472277 100644 --- a/cabal-install/src/Distribution/Client/IndexUtils/Timestamp.hs +++ b/cabal-install/src/Distribution/Client/IndexUtils/Timestamp.hs @@ -1,5 +1,5 @@ +{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -12,8 +12,7 @@ -- -- Timestamp type used in package indexes module Distribution.Client.IndexUtils.Timestamp - ( Timestamp - , nullTimestamp + ( Timestamp (NoTimestamp) , epochTimeToTimestamp , timestampToUTCTime , utcTimeToTimestamp @@ -33,38 +32,30 @@ import qualified Distribution.Compat.CharParsing as P import qualified Text.PrettyPrint as Disp -- | UNIX timestamp (expressed in seconds since unix epoch, i.e. 1970). -newtype Timestamp = TS Int64 -- Tar.EpochTime - deriving (Eq, Ord, Enum, NFData, Show, Generic) +data Timestamp = NoTimestamp | TS Int64 -- Tar.EpochTime + deriving (Eq, Ord, NFData, Show, Generic) -epochTimeToTimestamp :: Tar.EpochTime -> Maybe Timestamp -epochTimeToTimestamp et - | ts == nullTimestamp = Nothing - | otherwise = Just ts - where - ts = TS et +epochTimeToTimestamp :: Tar.EpochTime -> Timestamp +epochTimeToTimestamp = TS timestampToUTCTime :: Timestamp -> Maybe UTCTime -timestampToUTCTime (TS t) - | t == minBound = Nothing - | otherwise = Just $ posixSecondsToUTCTime (fromIntegral t) +timestampToUTCTime NoTimestamp = Nothing +timestampToUTCTime (TS t) = Just $ posixSecondsToUTCTime (fromIntegral t) -utcTimeToTimestamp :: UTCTime -> Maybe Timestamp -utcTimeToTimestamp utct - | minTime <= t, t <= maxTime = Just (TS (fromIntegral t)) - | otherwise = Nothing - where - maxTime = toInteger (maxBound :: Int64) - minTime = toInteger (succ minBound :: Int64) - t :: Integer - t = round . utcTimeToPOSIXSeconds $ utct +utcTimeToTimestamp :: UTCTime -> Timestamp +utcTimeToTimestamp = + TS + . (fromIntegral :: Integer -> Int64) + . round + . utcTimeToPOSIXSeconds -- | Compute the maximum 'Timestamp' value -- --- Returns 'nullTimestamp' for the empty list. Also note that --- 'nullTimestamp' compares as smaller to all non-'nullTimestamp' +-- Returns 'NoTimestamp' for the empty list. Also note that +-- 'NoTimestamp' compares as smaller to all non-'NoTimestamp' -- values. maximumTimestamp :: [Timestamp] -> Timestamp -maximumTimestamp [] = nullTimestamp +maximumTimestamp [] = NoTimestamp maximumTimestamp xs@(_ : _) = maximum xs -- returns 'Nothing' if not representable as 'Timestamp' @@ -76,17 +67,11 @@ posixSecondsToTimestamp pt maxTs = toInteger (maxBound :: Int64) minTs = toInteger (succ minBound :: Int64) --- | Pretty-prints 'Timestamp' in ISO8601/RFC3339 format --- (e.g. @"2017-12-31T23:59:59Z"@) --- --- Returns empty string for 'nullTimestamp' in order for --- --- > null (display nullTimestamp) == True --- --- to hold. +-- | Pretty-prints non-null 'Timestamp' in ISO8601/RFC3339 format +-- (e.g. @"2017-12-31T23:59:59Z"@). showTimestamp :: Timestamp -> String showTimestamp ts = case timestampToUTCTime ts of - Nothing -> "" + Nothing -> "Unknown or invalid timestamp" -- Note: we don't use 'formatTime' here to avoid incurring a -- dependency on 'old-locale' for older `time` libs Just UTCTime{..} -> showGregorian utctDay ++ ('T' : showTOD utctDayTime) ++ "Z" @@ -141,7 +126,7 @@ instance Parsec Timestamp where let utc = UTCTime{..} - maybe (fail (show utc ++ " is not representable as timestamp")) return $ utcTimeToTimestamp utc + return $ utcTimeToTimestamp utc parseTwoDigits = do d1 <- P.satisfy isDigit @@ -156,8 +141,3 @@ instance Parsec Timestamp where ds <- P.munch1 isDigit when (length ds < 4) $ fail "Year should have at least 4 digits" return (read (sign : ds)) - --- | Special timestamp value to be used when 'timestamp' is --- missing/unknown/invalid -nullTimestamp :: Timestamp -nullTimestamp = TS minBound diff --git a/cabal-install/src/Distribution/Client/Init/FileCreators.hs b/cabal-install/src/Distribution/Client/Init/FileCreators.hs index 18ea0bc71a1..f53ce7a6e53 100644 --- a/cabal-install/src/Distribution/Client/Init/FileCreators.hs +++ b/cabal-install/src/Distribution/Client/Init/FileCreators.hs @@ -65,7 +65,7 @@ writeProject (ProjectSettings opts pkgDesc libTarget exeTarget testTarget) message opts T.Error "no package name given, so no .cabal file can be generated\n" | otherwise = do -- clear prompt history a bit" - message opts T.Log $ + message opts T.Info $ "Using cabal specification: " ++ showCabalSpecVersion (_optCabalSpec opts) @@ -269,7 +269,7 @@ writeFileSafe opts fileName content = do go exists - message opts T.Log $ show action ++ " file " ++ fileName ++ "..." + message opts T.Info $ show action ++ " file " ++ fileName ++ "..." return $ action == Existing where doOverwrite = _optOverwrite opts @@ -279,7 +279,7 @@ writeFileSafe opts fileName content = do writeFile fileName content | exists && doOverwrite = do newName <- findNewPath fileName - message opts T.Log $ + message opts T.Info $ concat [ fileName , " already exists. Backing up old version in " @@ -302,7 +302,7 @@ writeDirectoriesSafe opts dirs = fmap or $ for dirs $ \dir -> do go dir exists - message opts T.Log $ show action ++ " directory ./" ++ dir ++ "..." + message opts T.Info $ show action ++ " directory ./" ++ dir ++ "..." return $ action == Existing where doOverwrite = _optOverwrite opts @@ -312,7 +312,7 @@ writeDirectoriesSafe opts dirs = fmap or $ for dirs $ \dir -> do createDirectory dir | exists && doOverwrite = do newDir <- findNewPath dir - message opts T.Log $ + message opts T.Info $ concat [ dir , " already exists. Backing up old version in " diff --git a/cabal-install/src/Distribution/Client/Init/Interactive/Command.hs b/cabal-install/src/Distribution/Client/Init/Interactive/Command.hs index a98794334d0..1e08e843d6f 100644 --- a/cabal-install/src/Distribution/Client/Init/Interactive/Command.hs +++ b/cabal-install/src/Distribution/Client/Init/Interactive/Command.hs @@ -312,6 +312,7 @@ cabalVersionPrompt flags = getCabalVersion flags $ do parseCabalVersion "2.4" = CabalSpecV2_4 parseCabalVersion "3.0" = CabalSpecV3_0 parseCabalVersion "3.4" = CabalSpecV3_4 + parseCabalVersion "3.12" = CabalSpecV3_12 parseCabalVersion _ = defaultCabalVersion -- 2.4 displayCabalVersion :: CabalSpecVersion -> String displayCabalVersion v = case v of @@ -455,11 +456,12 @@ languagePrompt flags pkgType = getLanguage flags $ do let h2010 = "Haskell2010" h98 = "Haskell98" ghc2021 = "GHC2021 (requires at least GHC 9.2)" + ghc2024 = "GHC2024 (requires at least GHC 9.10)" l <- promptList ("Choose a language for your " ++ pkgType) - [h2010, h98, ghc2021] + [h2010, h98, ghc2021, ghc2024] (DefaultPrompt h2010) Nothing True @@ -468,6 +470,7 @@ languagePrompt flags pkgType = getLanguage flags $ do | l == h2010 -> return Haskell2010 | l == h98 -> return Haskell98 | l == ghc2021 -> return GHC2021 + | l == ghc2024 -> return GHC2024 | otherwise -> return $ UnknownLanguage l noCommentsPrompt :: Interactive m => InitFlags -> m Bool diff --git a/cabal-install/src/Distribution/Client/Init/Licenses.hs b/cabal-install/src/Distribution/Client/Init/Licenses.hs index ef648e9351f..1f9177083bd 100644 --- a/cabal-install/src/Distribution/Client/Init/Licenses.hs +++ b/cabal-install/src/Distribution/Client/Init/Licenses.hs @@ -30,7 +30,6 @@ bsd2 :: String -> String -> License bsd2 authors year = unlines [ "Copyright (c) " ++ year ++ ", " ++ authors - , "All rights reserved." , "" , "Redistribution and use in source and binary forms, with or without" , "modification, are permitted provided that the following conditions are" @@ -48,7 +47,7 @@ bsd2 authors year = , "\"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," + , "HOLDER 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" @@ -62,7 +61,6 @@ bsd3 authors year = unlines [ "Copyright (c) " ++ year ++ ", " ++ authors , "" - , "All rights reserved." , "" , "Redistribution and use in source and binary forms, with or without" , "modification, are permitted provided that the following conditions are met:" @@ -75,7 +73,7 @@ bsd3 authors year = , " disclaimer in the documentation and/or other materials provided" , " with the distribution." , "" - , " * Neither the name of " ++ authors ++ " nor the names of other" + , " * Neither the name of the copyright holder nor the names of its" , " contributors may be used to endorse or promote products derived" , " from this software without specific prior written permission." , "" @@ -83,7 +81,7 @@ bsd3 authors year = , "\"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," + , "HOLDER 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" diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs index 8c37cad96f2..7eee9f82f7a 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Command.hs @@ -40,7 +40,7 @@ import Distribution.Client.Init.Types import Distribution.Client.Compat.Prelude hiding (getLine, head, last, putStr, putStrLn) import Prelude () -import Data.List (head, last) +import Data.List (last) import qualified Data.List.NonEmpty as NEL import Distribution.CabalSpecVersion (CabalSpecVersion (..)) @@ -340,12 +340,18 @@ packageTypeHeuristics flags = getPackageType flags $ guessPackageType flags -- to a default value. mainFileHeuristics :: Interactive m => InitFlags -> m HsFilePath mainFileHeuristics flags = do - appDir <- head <$> appDirsHeuristics flags + appDirs <- appDirsHeuristics flags + let appDir = case appDirs of + [] -> error "impossible: appDirsHeuristics returned empty list of dirs" + (appDir' : _) -> appDir' getMainFile flags . guessMainFile $ appDir testMainHeuristics :: Interactive m => InitFlags -> m HsFilePath testMainHeuristics flags = do - testDir <- head <$> testDirsHeuristics flags + testDirs' <- testDirsHeuristics flags + let testDir = case testDirs' of + [] -> error "impossible: testDirsHeuristics returned empty list of dirs" + (testDir' : _) -> testDir' guessMainFile testDir initializeTestSuiteHeuristics :: Interactive m => InitFlags -> m Bool diff --git a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs index 0fe0129d2c3..138f9684553 100644 --- a/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs +++ b/cabal-install/src/Distribution/Client/Init/NonInteractive/Heuristics.hs @@ -54,9 +54,9 @@ guessMainFile pkgDir = do then do files <- filter isMain <$> listFilesRecursive pkgDir return $ - if null files - then defaultMainIs - else toHsFilePath $ L.head files + case files of + [] -> defaultMainIs + (f : _) -> toHsFilePath f else return defaultMainIs -- | Juggling characters around to guess the desired cabal version based on diff --git a/cabal-install/src/Distribution/Client/Init/Types.hs b/cabal-install/src/Distribution/Client/Init/Types.hs index 41513d0f048..ee7d7cbe0c3 100644 --- a/cabal-install/src/Distribution/Client/Init/Types.hs +++ b/cabal-install/src/Distribution/Client/Init/Types.hs @@ -368,7 +368,7 @@ instance Interactive IO where hFlush = System.IO.hFlush message q severity msg | q == silent = pure () - | otherwise = putStrLn $ "[" ++ show severity ++ "] " ++ msg + | otherwise = putStrLn $ "[" ++ displaySeverity severity ++ "] " ++ msg break = return False throwPrompt = throwM @@ -407,7 +407,7 @@ instance Interactive PurePrompt where Error -> PurePrompt $ \_ -> Left $ BreakException - (show severity ++ ": " ++ msg) + (displaySeverity severity ++ ": " ++ msg) _ -> return () break = return True @@ -455,7 +455,13 @@ newtype BreakException = BreakException String deriving (Eq, Show) instance Exception BreakException -- | Used to inform the intent of prompted messages. -data Severity = Log | Info | Warning | Error deriving (Eq, Show) +data Severity = Info | Warning | Error deriving (Eq) + +displaySeverity :: Severity -> String +displaySeverity severity = case severity of + Info -> "Info" + Warning -> "Warn" + Error -> "Err" -- | Convenience alias for the literate haskell flag type IsLiterate = Bool diff --git a/cabal-install/src/Distribution/Client/Init/Utils.hs b/cabal-install/src/Distribution/Client/Init/Utils.hs index e8cde1184ae..f986cce0e03 100644 --- a/cabal-install/src/Distribution/Client/Init/Utils.hs +++ b/cabal-install/src/Distribution/Client/Init/Utils.hs @@ -214,7 +214,7 @@ retrieveDependencies v flags mods' pkgIx = do modDeps = map (\(mn, ds) -> (mn, ds, M.lookup ds modMap)) mods -- modDeps = map (id &&& flip M.lookup modMap) mods - message v Log "Guessing dependencies..." + message v Info "Guessing dependencies..." nub . catMaybes <$> traverse (chooseDep v flags) modDeps -- Given a module and a list of installed packages providing it, diff --git a/cabal-install/src/Distribution/Client/InstallPlan.hs b/cabal-install/src/Distribution/Client/InstallPlan.hs index 1a8042d6bad..46212baaccc 100644 --- a/cabal-install/src/Distribution/Client/InstallPlan.hs +++ b/cabal-install/src/Distribution/Client/InstallPlan.hs @@ -72,9 +72,9 @@ module Distribution.Client.InstallPlan , reverseDependencyClosure ) where -import Distribution.Client.Compat.Prelude hiding (lookup, tail, toList) +import Distribution.Client.Compat.Prelude hiding (lookup, toList) import Distribution.Compat.Stack (WithCallStack) -import Prelude (tail) +import Prelude () import Distribution.Client.Types hiding (BuildOutcomes) import qualified Distribution.PackageDescription as PD @@ -757,13 +757,13 @@ failed -> ([srcpkg], Processing) failed plan (Processing processingSet completedSet failedSet) pkgid = assert (pkgid `Set.member` processingSet) $ - assert (all (`Set.notMember` processingSet) (tail newlyFailedIds)) $ - assert (all (`Set.notMember` completedSet) (tail newlyFailedIds)) $ + assert (all (`Set.notMember` processingSet) (drop 1 newlyFailedIds)) $ + assert (all (`Set.notMember` completedSet) (drop 1 newlyFailedIds)) $ -- but note that some newlyFailed may already be in the failed set -- since one package can depend on two packages that both fail and -- so would be in the rev-dep closure for both. assert (processingInvariant plan processing') $ - ( map asConfiguredPackage (tail newlyFailed) + ( map asConfiguredPackage (drop 1 newlyFailed) , processing' ) where diff --git a/cabal-install/src/Distribution/Client/InstallSymlink.hs b/cabal-install/src/Distribution/Client/InstallSymlink.hs index cf57c54818e..13e29a44d81 100644 --- a/cabal-install/src/Distribution/Client/InstallSymlink.hs +++ b/cabal-install/src/Distribution/Client/InstallSymlink.hs @@ -1,5 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RecordWildCards #-} ----------------------------------------------------------------------------- @@ -16,8 +18,10 @@ -- -- Managing installing binaries with symlinks. module Distribution.Client.InstallSymlink - ( symlinkBinaries + ( Symlink (..) + , symlinkBinaries , symlinkBinary + , symlinkableBinary , trySymlink , promptRun ) where @@ -150,11 +154,13 @@ symlinkBinaries privateBinDir <- pkgBinDir pkg ipid ok <- symlinkBinary - overwritePolicy - publicBinDir - privateBinDir - (prettyShow publicExeName) - privateExeName + ( Symlink + overwritePolicy + publicBinDir + privateBinDir + (prettyShow publicExeName) + privateExeName + ) if ok then return Nothing else @@ -247,50 +253,80 @@ symlinkBinaries cinfo = compilerInfo comp (CompilerId compilerFlavor _) = compilerInfoId cinfo --- | Symlink binary. --- --- The paths are take in pieces, so we can make relative link when possible. -symlinkBinary - :: OverwritePolicy - -- ^ Whether to force overwrite an existing file - -> FilePath - -- ^ The canonical path of the public bin dir eg - -- @/home/user/bin@ - -> FilePath - -- ^ The canonical path of the private bin dir eg - -- @/home/user/.cabal/bin@ - -> FilePath - -- ^ The name of the executable to go in the public bin - -- dir, eg @foo@ - -> String - -- ^ The name of the executable to in the private bin - -- dir, eg @foo-1.0@ - -> IO Bool - -- ^ If creating the symlink was successful. @False@ if - -- there was another file there already that we did - -- not own. Other errors like permission errors just - -- propagate as exceptions. -symlinkBinary overwritePolicy publicBindir privateBindir publicName privateName = do +-- | A record needed to either check if a symlink is possible or to create a +-- symlink. Also used if copying instead of symlinking. +data Symlink = Symlink + { overwritePolicy :: OverwritePolicy + -- ^ Whether to force overwrite an existing file. + , publicBindir :: FilePath + -- ^ The canonical path of the public bin dir eg @/home/user/bin@. + , privateBindir :: FilePath + -- ^ The canonical path of the private bin dir eg @/home/user/.cabal/bin@. + , publicName :: FilePath + -- ^ The name of the executable to go in the public bin dir, eg @foo@. + , privateName :: String + -- ^ The name of the executable to in the private bin dir, eg @foo-1.0@. + } + +-- | After checking if a target is writeable given the overwrite policy, +-- dispatch to an appropriate action; +-- * @onMissing@ if the target doesn't exist +-- * @onOverwrite@ if the target exists and we are allowed to overwrite it +-- * @onNever@ if the target exists and we are never allowed to overwrite it +-- * @onPrompt@ if the target exists and we are allowed to overwrite after prompting +onSymlinkBinary + :: IO a + -- ^ Missing action + -> IO a + -- ^ Overwrite action + -> IO a + -- ^ Never action + -> IO a + -- ^ Prompt action + -> Symlink + -> IO a +onSymlinkBinary onMissing onOverwrite onNever onPrompt Symlink{..} = do ok <- targetOkToOverwrite (publicBindir publicName) (privateBindir privateName) case ok of - NotExists -> mkLink - OkToOverwrite -> overwrite + NotExists -> onMissing + OkToOverwrite -> onOverwrite NotOurFile -> case overwritePolicy of - NeverOverwrite -> return False - AlwaysOverwrite -> overwrite - PromptOverwrite -> maybeOverwrite + NeverOverwrite -> onNever + AlwaysOverwrite -> onOverwrite + PromptOverwrite -> onPrompt + +-- | Can we symlink a binary? +-- +-- @True@ if creating the symlink would be succeed, being optimistic that the user will +-- agree if prompted to overwrite. +symlinkableBinary :: Symlink -> IO Bool +symlinkableBinary = onSymlinkBinary (return True) (return True) (return False) (return True) + +-- | Symlink binary. +-- +-- The paths are take in pieces, so we can make relative link when possible. +-- @True@ if creating the symlink was successful. @False@ if there was another +-- file there already that we did not own. Other errors like permission errors +-- just propagate as exceptions. +symlinkBinary :: Symlink -> IO Bool +symlinkBinary inputs@Symlink{publicBindir, privateBindir, publicName, privateName} = do + onSymlinkBinary mkLink overwrite (return False) maybeOverwrite inputs where relativeBindir = makeRelative publicBindir privateBindir + mkLink :: IO Bool mkLink = True <$ createFileLink (relativeBindir privateName) (publicBindir publicName) + rmLink :: IO Bool rmLink = True <$ removeFile (publicBindir publicName) + overwrite :: IO Bool overwrite = rmLink *> mkLink + maybeOverwrite :: IO Bool maybeOverwrite = promptRun diff --git a/cabal-install/src/Distribution/Client/Main.hs b/cabal-install/src/Distribution/Client/Main.hs index 6d8c0e187aa..6ef0a673717 100644 --- a/cabal-install/src/Distribution/Client/Main.hs +++ b/cabal-install/src/Distribution/Client/Main.hs @@ -23,6 +23,7 @@ module Distribution.Client.Main (main) where import Distribution.Client.Setup ( ActAsSetupFlags (..) , BuildFlags (..) + , CheckFlags (..) , ConfigExFlags (..) , ConfigFlags (..) , FetchFlags (..) @@ -33,6 +34,8 @@ import Distribution.Client.Setup , InitFlags (initHcPath, initVerbosity) , InstallFlags (..) , ListFlags (..) + , Path (..) + , PathFlags (..) , ReportFlags (..) , UploadFlags (..) , UserConfigFlags (..) @@ -60,6 +63,8 @@ import Distribution.Client.Setup , listCommand , listNeedsCompiler , manpageCommand + , pathCommand + , pathName , reconfigureCommand , registerCommand , replCommand @@ -97,7 +102,11 @@ import Prelude () import Distribution.Client.Config ( SavedConfig (..) , createDefaultConfigFile + , defaultCacheDir , defaultConfigFile + , defaultInstallPath + , defaultLogsDir + , defaultStoreDir , getConfigFilePath , loadConfig , userConfigDiff @@ -143,6 +152,7 @@ import Distribution.Client.Install (install) -- import Distribution.Client.Clean (clean) +import Distribution.Client.CmdInstall.ClientInstallFlags (ClientInstallFlags (cinstInstalldir)) import Distribution.Client.Get (get) import Distribution.Client.Init (initCmd) import Distribution.Client.Manpage (manpageCmd) @@ -196,7 +206,8 @@ import Distribution.Simple.Command , commandAddAction , commandFromSpec , commandShowOptions - , commandsRun + , commandsRunWithFallback + , defaultCommandFallback , hiddenCommand ) import Distribution.Simple.Compiler (PackageDBStack) @@ -212,6 +223,8 @@ import Distribution.Simple.PackageDescription (readGenericPackageDescription) import Distribution.Simple.Program ( configureAllKnownPrograms , defaultProgramDb + , defaultProgramSearchPath + , findProgramOnSearchPath , getProgramInvocationOutput , simpleProgramInvocation ) @@ -227,6 +240,7 @@ import Distribution.Simple.Utils , notice , topHandler , tryFindPackageDesc + , withOutputMarker ) import Distribution.Text ( display @@ -242,6 +256,7 @@ import Distribution.Version ) import Control.Exception (AssertionFailed, assert, try) +import Control.Monad (mapM_) import Data.Monoid (Any (..)) import Distribution.Client.Errors import Distribution.Compat.ResponseFile @@ -250,7 +265,7 @@ import System.Directory , getCurrentDirectory , withCurrentDirectory ) -import System.Environment (getProgName) +import System.Environment (getEnvironment, getExecutablePath, getProgName) import System.FilePath ( dropExtension , splitExtension @@ -265,6 +280,7 @@ import System.IO , stderr , stdout ) +import System.Process (createProcess, env, proc) -- | Entry point -- @@ -322,8 +338,9 @@ warnIfAssertionsAreEnabled = -- into IO actions for execution. mainWorker :: [String] -> IO () mainWorker args = do - topHandler $ - case commandsRun (globalCommand commands) commands args of + topHandler $ do + command <- commandsRunWithFallback (globalCommand commands) commands delegateToExternal args + case command of CommandHelp help -> printGlobalHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs @@ -352,6 +369,27 @@ mainWorker args = do warnIfAssertionsAreEnabled action globalFlags where + delegateToExternal + :: [Command Action] + -> String + -> [String] + -> IO (CommandParse Action) + delegateToExternal commands' name cmdArgs = do + mCommand <- findProgramOnSearchPath normal defaultProgramSearchPath ("cabal-" <> name) + case mCommand of + Just (exec, _) -> return (CommandReadyToGo $ \_ -> callExternal exec name cmdArgs) + Nothing -> defaultCommandFallback commands' name cmdArgs + + callExternal :: String -> String -> [String] -> IO () + callExternal exec name cmdArgs = do + cur_env <- getEnvironment + cabal_exe <- getExecutablePath + let new_env = ("CABAL", cabal_exe) : cur_env + result <- try $ createProcess ((proc exec (name : cmdArgs)){env = Just new_env}) + case result of + Left ex -> printErrors ["Error executing external command: " ++ show (ex :: SomeException)] + Right _ -> return () + printCommandHelp help = do pname <- getProgName putStr (help pname) @@ -359,6 +397,10 @@ mainWorker args = do pname <- getProgName configFile <- defaultConfigFile putStr (help pname) + -- Andreas Abel, 2024-01-28: https://github.com/haskell/cabal/pull/9614 + -- See cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/ + -- Third-party tools may rely on the specific wording + -- to find the config file in the help text, so do not change! putStr $ "\nYou can edit the cabal configuration file to set defaults:\n" ++ " " @@ -392,6 +434,7 @@ mainWorker args = do , regularCmd reportCommand reportAction , regularCmd initCommand initAction , regularCmd userConfigCommand userConfigAction + , regularCmd pathCommand pathAction , regularCmd genBoundsCommand genBoundsAction , regularCmd CmdOutdated.outdatedCommand CmdOutdated.outdatedAction , wrapperCmd hscolourCommand hscolourVerbosity hscolourDistPref @@ -1187,13 +1230,14 @@ uploadAction uploadFlags extraArgs globalFlags = do pkg <- fmap LBI.localPkgDescr (getPersistBuildConfig distPref) return $ distPref display (packageId pkg) ++ "-docs" <.> "tar.gz" -checkAction :: Flag Verbosity -> [String] -> Action -checkAction verbosityFlag extraArgs _globalFlags = do - let verbosity = fromFlag verbosityFlag +checkAction :: CheckFlags -> [String] -> Action +checkAction checkFlags extraArgs _globalFlags = do + let verbosityFlag = checkVerbosity checkFlags + verbosity = fromFlag verbosityFlag unless (null extraArgs) $ dieWithException verbosity $ CheckAction extraArgs - allOk <- Check.check (fromFlag verbosityFlag) + allOk <- Check.check (fromFlag verbosityFlag) (checkIgnore checkFlags) unless allOk exitFailure formatAction :: Flag Verbosity -> [String] -> Action @@ -1344,3 +1388,32 @@ manpageAction commands flags extraArgs _ = do then dropExtension pname else pname manpageCmd cabalCmd commands flags + +pathAction :: PathFlags -> [String] -> Action +pathAction pathflags extraArgs globalFlags = do + let verbosity = fromFlag (pathVerbosity pathflags) + unless (null extraArgs) $ + dieWithException verbosity $ + ManpageAction extraArgs + cfg <- loadConfig verbosity mempty + let getDir getDefault getGlobal = + maybe + getDefault + pure + (flagToMaybe $ getGlobal $ savedGlobalFlags cfg) + getSomeDir PathCacheDir = getDir defaultCacheDir globalCacheDir + getSomeDir PathLogsDir = getDir defaultLogsDir globalLogsDir + getSomeDir PathStoreDir = getDir defaultStoreDir globalStoreDir + getSomeDir PathConfigFile = getConfigFilePath (globalConfigFile globalFlags) + getSomeDir PathInstallDir = + fromFlagOrDefault defaultInstallPath (pure <$> cinstInstalldir (savedClientInstallFlags cfg)) + printPath p = putStrLn . withOutputMarker verbosity . ((pathName p ++ ": ") ++) =<< getSomeDir p + -- If no paths have been requested, print all paths with labels. + -- + -- If a single path has been requested, print that path without any label. + -- + -- If multiple paths have been requested, print each of them with labels. + case fromFlag $ pathDirs pathflags of + [] -> mapM_ printPath [minBound .. maxBound] + [d] -> putStrLn . withOutputMarker verbosity =<< getSomeDir d + ds -> mapM_ printPath ds diff --git a/cabal-install/src/Distribution/Client/NixStyleOptions.hs b/cabal-install/src/Distribution/Client/NixStyleOptions.hs index 5237901bf80..7a047774b2b 100644 --- a/cabal-install/src/Distribution/Client/NixStyleOptions.hs +++ b/cabal-install/src/Distribution/Client/NixStyleOptions.hs @@ -55,11 +55,12 @@ nixStyleOptions commandOptions showOrParseArgs = configFlags set1 -- Note: [Hidden Flags] - -- hide "constraint", "dependency", "promised-dependency" and - -- "exact-configuration" from the configure options. + -- We reuse the configure options from v1 commands which on their turn + -- reuse the ones from Cabal) but we hide some of them in v2 commands. ( filter ( ( `notElem` - [ "constraint" + [ "cabal-file" + , "constraint" , "dependency" , "promised-dependency" , "exact-configuration" diff --git a/cabal-install/src/Distribution/Client/PackageHash.hs b/cabal-install/src/Distribution/Client/PackageHash.hs index 18be444cde7..f5387a37bd8 100644 --- a/cabal-install/src/Distribution/Client/PackageHash.hs +++ b/cabal-install/src/Distribution/Client/PackageHash.hs @@ -10,6 +10,8 @@ -- * the package tarball -- * the ids of all the direct dependencies -- * other local configuration (flags, profiling, etc) +-- +-- See 'PackageHashInputs' for a detailed list of what determines the hash. module Distribution.Client.PackageHash ( -- * Calculating package hashes PackageHashInputs (..) @@ -38,7 +40,8 @@ import Distribution.Package , mkComponentId ) import Distribution.Simple.Compiler - ( CompilerId + ( AbiTag (..) + , CompilerId , DebugInfoLevel (..) , OptimisationLevel (..) , PackageDB @@ -191,6 +194,7 @@ type PackageSourceHash = HashValue -- package hash. data PackageHashConfigInputs = PackageHashConfigInputs { pkgHashCompilerId :: CompilerId + , pkgHashCompilerABI :: AbiTag , pkgHashPlatform :: Platform , pkgHashFlagAssignment :: FlagAssignment -- complete not partial , pkgHashConfigureScriptArgs :: [String] -- just ./configure for build-type Configure @@ -301,6 +305,7 @@ renderPackageHashInputs pkgHashDirectDeps , -- and then all the config entry "compilerid" prettyShow pkgHashCompilerId + , entry "compilerabi" prettyShow pkgHashCompilerABI , entry "platform" prettyShow pkgHashPlatform , opt "flags" mempty showFlagAssignment pkgHashFlagAssignment , opt "configure-script" [] unwords pkgHashConfigureScriptArgs diff --git a/cabal-install/src/Distribution/Client/ProjectBuilding.hs b/cabal-install/src/Distribution/Client/ProjectBuilding.hs index fa917b9f1bf..a0906686dd1 100644 --- a/cabal-install/src/Distribution/Client/ProjectBuilding.hs +++ b/cabal-install/src/Distribution/Client/ProjectBuilding.hs @@ -44,18 +44,15 @@ module Distribution.Client.ProjectBuilding import Distribution.Client.Compat.Prelude import Prelude () -import Distribution.Client.PackageHash (renderPackageHashInputs) import Distribution.Client.ProjectBuilding.Types import Distribution.Client.ProjectConfig import Distribution.Client.ProjectConfig.Types import Distribution.Client.ProjectPlanning import Distribution.Client.ProjectPlanning.Types -import Distribution.Client.RebuildMonad import Distribution.Client.Store import Distribution.Client.DistDirLayout import Distribution.Client.FetchUtils -import Distribution.Client.FileMonitor import Distribution.Client.GlobalFlags (RepoContext) import Distribution.Client.InstallPlan ( GenericInstallPlan @@ -64,15 +61,6 @@ import Distribution.Client.InstallPlan ) import qualified Distribution.Client.InstallPlan as InstallPlan import Distribution.Client.JobControl -import Distribution.Client.Setup - ( filterConfigureFlags - , filterHaddockArgs - , filterHaddockFlags - , filterTestFlags - ) -import Distribution.Client.SetupWrapper -import Distribution.Client.SourceFiles -import Distribution.Client.SrcDist (allPackageSourceFiles) import qualified Distribution.Client.Tar as Tar import Distribution.Client.Types hiding ( BuildFailure (..) @@ -80,61 +68,37 @@ import Distribution.Client.Types hiding , BuildOutcomes , BuildResult (..) ) -import Distribution.Client.Utils - ( ProgressPhase (..) - , findOpenProgramLocation - , numberOfProcessors - , progressMessage - , removeExistingFile - ) -import Distribution.Compat.Lens -import Distribution.InstalledPackageInfo (InstalledPackageInfo) -import qualified Distribution.InstalledPackageInfo as Installed import Distribution.Package -import qualified Distribution.PackageDescription as PD -import Distribution.Simple.BuildPaths (haddockDirName) -import Distribution.Simple.Command (CommandUI) import Distribution.Simple.Compiler ( Compiler , PackageDB (..) - , compilerId , jsemSupported ) -import qualified Distribution.Simple.InstallDirs as InstallDirs -import Distribution.Simple.LocalBuildInfo - ( ComponentName (..) - , LibraryName (..) - ) import Distribution.Simple.Program import qualified Distribution.Simple.Register as Cabal -import qualified Distribution.Simple.Setup as Cabal -import Distribution.Types.BuildType -import Distribution.Types.PackageDescription.Lens (componentModules) import Distribution.Compat.Graph (IsNode (..)) import Distribution.Simple.Utils import Distribution.Version -import qualified Data.ByteString as BS -import qualified Data.ByteString.Lazy as LBS -import qualified Data.ByteString.Lazy.Char8 as LBS.Char8 -import qualified Data.List.NonEmpty as NE import qualified Data.Map as Map import qualified Data.Set as Set import qualified Text.PrettyPrint as Disp -import Control.Exception (Handler (..), SomeAsyncException, assert, bracket, catches, handle) -import System.Directory (canonicalizePath, createDirectoryIfMissing, doesDirectoryExist, doesFileExist, removeFile, renameDirectory) -import System.FilePath (dropDrive, makeRelative, normalise, takeDirectory, (<.>), ()) -import System.IO (Handle, IOMode (AppendMode), withFile) +import Control.Exception (assert, bracket, handle) +import System.Directory (doesDirectoryExist, doesFileExist, renameDirectory) +import System.FilePath (makeRelative, takeDirectory, (<.>), ()) import System.Semaphore (SemaphoreName (..)) import Distribution.Client.Errors -import Distribution.Compat.Directory (listDirectory) import Distribution.Simple.Flag (fromFlagOrDefault) +import Distribution.Client.ProjectBuilding.PackageFileMonitor +import Distribution.Client.ProjectBuilding.UnpackedPackage (annotateFailureNoLog, buildAndInstallUnpackedPackage, buildInplaceUnpackedPackage) +import Distribution.Client.Utils (numberOfProcessors) + ------------------------------------------------------------------------------ -- * Overall building strategy. @@ -344,271 +308,6 @@ improveInstallPlanWithUpToDatePackages pkgsBuildStatus = ++ prettyShow (packageId pkg) ++ " not in status map" ------------------------------ --- Package change detection --- - --- | As part of the dry run for local unpacked packages we have to check if the --- package config or files have changed. That is the purpose of --- 'PackageFileMonitor' and 'checkPackageFileMonitorChanged'. --- --- When a package is (re)built, the monitor must be updated to reflect the new --- state of the package. Because we sometimes build without reconfiguring the --- state updates are split into two, one for package config changes and one --- for other changes. This is the purpose of 'updatePackageConfigFileMonitor' --- and 'updatePackageBuildFileMonitor'. -data PackageFileMonitor = PackageFileMonitor - { pkgFileMonitorConfig :: FileMonitor ElaboratedConfiguredPackage () - , pkgFileMonitorBuild :: FileMonitor (Set ComponentName) BuildResultMisc - , pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo) - } - --- | This is all the components of the 'BuildResult' other than the --- @['InstalledPackageInfo']@. --- --- We have to split up the 'BuildResult' components since they get produced --- at different times (or rather, when different things change). -type BuildResultMisc = (DocsResult, TestsResult) - -newPackageFileMonitor - :: ElaboratedSharedConfig - -> DistDirLayout - -> DistDirParams - -> PackageFileMonitor -newPackageFileMonitor - shared - DistDirLayout{distPackageCacheFile} - dparams = - PackageFileMonitor - { pkgFileMonitorConfig = - FileMonitor - { fileMonitorCacheFile = distPackageCacheFile dparams "config" - , fileMonitorKeyValid = (==) `on` normaliseConfiguredPackage shared - , fileMonitorCheckIfOnlyValueChanged = False - } - , pkgFileMonitorBuild = - FileMonitor - { fileMonitorCacheFile = distPackageCacheFile dparams "build" - , fileMonitorKeyValid = \componentsToBuild componentsAlreadyBuilt -> - componentsToBuild `Set.isSubsetOf` componentsAlreadyBuilt - , fileMonitorCheckIfOnlyValueChanged = True - } - , pkgFileMonitorReg = - newFileMonitor (distPackageCacheFile dparams "registration") - } - --- | Helper function for 'checkPackageFileMonitorChanged', --- 'updatePackageConfigFileMonitor' and 'updatePackageBuildFileMonitor'. --- --- It selects the info from a 'ElaboratedConfiguredPackage' that are used by --- the 'FileMonitor's (in the 'PackageFileMonitor') to detect value changes. -packageFileMonitorKeyValues - :: ElaboratedConfiguredPackage - -> (ElaboratedConfiguredPackage, Set ComponentName) -packageFileMonitorKeyValues elab = - (elab_config, buildComponents) - where - -- The first part is the value used to guard (re)configuring the package. - -- That is, if this value changes then we will reconfigure. - -- The ElaboratedConfiguredPackage consists mostly (but not entirely) of - -- information that affects the (re)configure step. But those parts that - -- do not affect the configure step need to be nulled out. Those parts are - -- the specific targets that we're going to build. - -- - - -- Additionally we null out the parts that don't affect the configure step because they're simply - -- about how tests or benchmarks are run - - -- TODO there may be more things to null here too, in the future. - - elab_config :: ElaboratedConfiguredPackage - elab_config = - elab - { elabBuildTargets = [] - , elabTestTargets = [] - , elabBenchTargets = [] - , elabReplTarget = [] - , elabHaddockTargets = [] - , elabBuildHaddocks = False - , elabTestMachineLog = Nothing - , elabTestHumanLog = Nothing - , elabTestShowDetails = Nothing - , elabTestKeepTix = False - , elabTestTestOptions = [] - , elabBenchmarkOptions = [] - } - - -- The second part is the value used to guard the build step. So this is - -- more or less the opposite of the first part, as it's just the info about - -- what targets we're going to build. - -- - buildComponents :: Set ComponentName - buildComponents = elabBuildTargetWholeComponents elab - --- | Do all the checks on whether a package has changed and thus needs either --- rebuilding or reconfiguring and rebuilding. -checkPackageFileMonitorChanged - :: PackageFileMonitor - -> ElaboratedConfiguredPackage - -> FilePath - -> [BuildStatus] - -> IO (Either BuildStatusRebuild BuildResult) -checkPackageFileMonitorChanged - PackageFileMonitor{..} - pkg - srcdir - depsBuildStatus = do - -- TODO: [nice to have] some debug-level message about file - -- changes, like rerunIfChanged - configChanged <- - checkFileMonitorChanged - pkgFileMonitorConfig - srcdir - pkgconfig - case configChanged of - MonitorChanged monitorReason -> - return (Left (BuildStatusConfigure monitorReason')) - where - monitorReason' = fmap (const ()) monitorReason - MonitorUnchanged () _ - -- The configChanged here includes the identity of the dependencies, - -- so depsBuildStatus is just needed for the changes in the content - -- of dependencies. - | any buildStatusRequiresBuild depsBuildStatus -> do - regChanged <- checkFileMonitorChanged pkgFileMonitorReg srcdir () - let mreg = changedToMaybe regChanged - return (Left (BuildStatusBuild mreg BuildReasonDepsRebuilt)) - | otherwise -> do - buildChanged <- - checkFileMonitorChanged - pkgFileMonitorBuild - srcdir - buildComponents - regChanged <- - checkFileMonitorChanged - pkgFileMonitorReg - srcdir - () - let mreg = changedToMaybe regChanged - case (buildChanged, regChanged) of - (MonitorChanged (MonitoredValueChanged prevBuildComponents), _) -> - return (Left (BuildStatusBuild mreg buildReason)) - where - buildReason = BuildReasonExtraTargets prevBuildComponents - (MonitorChanged monitorReason, _) -> - return (Left (BuildStatusBuild mreg buildReason)) - where - buildReason = BuildReasonFilesChanged monitorReason' - monitorReason' = fmap (const ()) monitorReason - (MonitorUnchanged _ _, MonitorChanged monitorReason) -> - -- this should only happen if the file is corrupt or been - -- manually deleted. We don't want to bother with another - -- phase just for this, so we'll reregister by doing a build. - return (Left (BuildStatusBuild Nothing buildReason)) - where - buildReason = BuildReasonFilesChanged monitorReason' - monitorReason' = fmap (const ()) monitorReason - (MonitorUnchanged _ _, MonitorUnchanged _ _) - | pkgHasEphemeralBuildTargets pkg -> - return (Left (BuildStatusBuild mreg buildReason)) - where - buildReason = BuildReasonEphemeralTargets - (MonitorUnchanged buildResult _, MonitorUnchanged _ _) -> - return $ - Right - BuildResult - { buildResultDocs = docsResult - , buildResultTests = testsResult - , buildResultLogFile = Nothing - } - where - (docsResult, testsResult) = buildResult - where - (pkgconfig, buildComponents) = packageFileMonitorKeyValues pkg - changedToMaybe :: MonitorChanged a b -> Maybe b - changedToMaybe (MonitorChanged _) = Nothing - changedToMaybe (MonitorUnchanged x _) = Just x - -updatePackageConfigFileMonitor - :: PackageFileMonitor - -> FilePath - -> ElaboratedConfiguredPackage - -> IO () -updatePackageConfigFileMonitor - PackageFileMonitor{pkgFileMonitorConfig} - srcdir - pkg = - updateFileMonitor - pkgFileMonitorConfig - srcdir - Nothing - [] - pkgconfig - () - where - (pkgconfig, _buildComponents) = packageFileMonitorKeyValues pkg - -updatePackageBuildFileMonitor - :: PackageFileMonitor - -> FilePath - -> MonitorTimestamp - -> ElaboratedConfiguredPackage - -> BuildStatusRebuild - -> [MonitorFilePath] - -> BuildResultMisc - -> IO () -updatePackageBuildFileMonitor - PackageFileMonitor{pkgFileMonitorBuild} - srcdir - timestamp - pkg - pkgBuildStatus - monitors - buildResult = - updateFileMonitor - pkgFileMonitorBuild - srcdir - (Just timestamp) - monitors - buildComponents' - buildResult - where - (_pkgconfig, buildComponents) = packageFileMonitorKeyValues pkg - - -- If the only thing that's changed is that we're now building extra - -- components, then we can avoid later unnecessary rebuilds by saving the - -- total set of components that have been built, namely the union of the - -- existing ones plus the new ones. If files also changed this would be - -- the wrong thing to do. Note that we rely on the - -- fileMonitorCheckIfOnlyValueChanged = True mode to get this guarantee - -- that it's /only/ the value that changed not any files that changed. - buildComponents' = - case pkgBuildStatus of - BuildStatusBuild _ (BuildReasonExtraTargets prevBuildComponents) -> - buildComponents `Set.union` prevBuildComponents - _ -> buildComponents - -updatePackageRegFileMonitor - :: PackageFileMonitor - -> FilePath - -> Maybe InstalledPackageInfo - -> IO () -updatePackageRegFileMonitor - PackageFileMonitor{pkgFileMonitorReg} - srcdir - mipkg = - updateFileMonitor - pkgFileMonitorReg - srcdir - Nothing - [] - () - mipkg - -invalidatePackageRegFileMonitor :: PackageFileMonitor -> IO () -invalidatePackageRegFileMonitor PackageFileMonitor{pkgFileMonitorReg} = - removeExistingFile (fileMonitorCacheFile pkgFileMonitorReg) - ------------------------------------------------------------------------------ -- * Doing it: executing an 'ElaboratedInstallPlan' @@ -672,9 +371,9 @@ rebuildTargets info verbosity $ "Executing install plan " ++ case buildSettingNumJobs of - NumJobs n -> " in parallel using " ++ show n ++ " threads." - UseSem n -> " in parallel using a semaphore with " ++ show n ++ " slots." - Serial -> " serially." + NumJobs n -> "in parallel using " ++ show n ++ " threads." + UseSem n -> "in parallel using a semaphore with " ++ show n ++ " slots." + Serial -> "serially." createDirectoryIfMissingVerbose verbosity True distBuildRootDirectory createDirectoryIfMissingVerbose verbosity True distTempDirectory @@ -1135,755 +834,3 @@ moveTarballShippedDistDirectory where tarballDistDir = parentdir prettyShow pkgid "dist" targetDistDir = distBuildDirectory dparams - -buildAndInstallUnpackedPackage - :: Verbosity - -> DistDirLayout - -> StoreDirLayout - -> Maybe SemaphoreName - -- ^ Whether to pass a semaphore to build process - -- this is different to BuildTimeSettings because the - -- name of the semaphore is created freshly each time. - -> BuildTimeSettings - -> Lock - -> Lock - -> ElaboratedSharedConfig - -> ElaboratedInstallPlan - -> ElaboratedReadyPackage - -> FilePath - -> FilePath - -> IO BuildResult -buildAndInstallUnpackedPackage - verbosity - distDirLayout@DistDirLayout{distTempDirectory} - storeDirLayout@StoreDirLayout - { storePackageDBStack - } - maybe_semaphore - BuildTimeSettings - { buildSettingNumJobs - , buildSettingLogFile - } - registerLock - cacheLock - pkgshared@ElaboratedSharedConfig - { pkgConfigPlatform = platform - , pkgConfigCompiler = compiler - , pkgConfigCompilerProgs = progdb - } - plan - rpkg@(ReadyPackage pkg) - srcdir - builddir = do - createDirectoryIfMissingVerbose verbosity True (srcdir builddir) - initLogFile - - -- TODO: [code cleanup] deal consistently with talking to older - -- Setup.hs versions, much like we do for ghc, with a proper - -- options type and rendering step which will also let us - -- call directly into the lib, rather than always going via - -- the lib's command line interface, which would also allow - -- passing data like installed packages, compiler, and - -- program db for a quicker configure. - - -- TODO: [required feature] docs and tests - -- TODO: [required feature] sudo re-exec - - -- Configure phase - noticeProgress ProgressStarting - - annotateFailure mlogFile ConfigureFailed $ - setup' configureCommand configureFlags configureArgs - - -- Build phase - noticeProgress ProgressBuilding - - annotateFailure mlogFile BuildFailed $ - setup buildCommand buildFlags - - -- Haddock phase - whenHaddock $ do - noticeProgress ProgressHaddock - annotateFailureNoLog HaddocksFailed $ - setup haddockCommand haddockFlags - - -- Install phase - noticeProgress ProgressInstalling - annotateFailure mlogFile InstallFailed $ do - let copyPkgFiles tmpDir = do - let tmpDirNormalised = normalise tmpDir - setup Cabal.copyCommand (copyFlags tmpDirNormalised) - -- Note that the copy command has put the files into - -- @$tmpDir/$prefix@ so we need to return this dir so - -- the store knows which dir will be the final store entry. - let prefix = - normalise $ - dropDrive (InstallDirs.prefix (elabInstallDirs pkg)) - entryDir = tmpDirNormalised prefix - - -- if there weren't anything to build, it might be that directory is not created - -- the @setup Cabal.copyCommand@ above might do nothing. - -- https://github.com/haskell/cabal/issues/4130 - createDirectoryIfMissingVerbose verbosity True entryDir - - let hashFileName = entryDir "cabal-hash.txt" - outPkgHashInputs = renderPackageHashInputs (packageHashInputs pkgshared pkg) - - info verbosity $ - "creating file with the inputs used to compute the package hash: " ++ hashFileName - - LBS.writeFile hashFileName outPkgHashInputs - - debug verbosity "Package hash inputs:" - traverse_ - (debug verbosity . ("> " ++)) - (lines $ LBS.Char8.unpack outPkgHashInputs) - - -- Ensure that there are no files in `tmpDir`, that are - -- not in `entryDir`. While this breaks the - -- prefix-relocatable property of the libraries, it is - -- necessary on macOS to stay under the load command limit - -- of the macOS mach-o linker. See also - -- @PackageHash.hashedInstalledPackageIdVeryShort@. - -- - -- We also normalise paths to ensure that there are no - -- different representations for the same path. Like / and - -- \\ on windows under msys. - otherFiles <- - filter (not . isPrefixOf entryDir) - <$> listFilesRecursive tmpDirNormalised - -- Here's where we could keep track of the installed files - -- ourselves if we wanted to by making a manifest of the - -- files in the tmp dir. - return (entryDir, otherFiles) - where - listFilesRecursive :: FilePath -> IO [FilePath] - listFilesRecursive path = do - files <- fmap (path ) <$> (listDirectory path) - allFiles <- for files $ \file -> do - isDir <- doesDirectoryExist file - if isDir - then listFilesRecursive file - else return [file] - return (concat allFiles) - - registerPkg - | not (elabRequiresRegistration pkg) = - debug verbosity $ - "registerPkg: elab does NOT require registration for " - ++ prettyShow uid - | otherwise = do - -- We register ourselves rather than via Setup.hs. We need to - -- grab and modify the InstalledPackageInfo. We decide what - -- the installed package id is, not the build system. - ipkg0 <- generateInstalledPackageInfo - let ipkg = ipkg0{Installed.installedUnitId = uid} - assert - ( elabRegisterPackageDBStack pkg - == storePackageDBStack compid - ) - (return ()) - criticalSection registerLock $ - Cabal.registerPackage - verbosity - compiler - progdb - (storePackageDBStack compid) - ipkg - Cabal.defaultRegisterOptions - { Cabal.registerMultiInstance = True - , Cabal.registerSuppressFilesCheck = True - } - - -- Actual installation - void $ - newStoreEntry - verbosity - storeDirLayout - compid - uid - copyPkgFiles - registerPkg - - -- TODO: [nice to have] we currently rely on Setup.hs copy to do the right - -- thing. Although we do copy into an image dir and do the move into the - -- final location ourselves, perhaps we ought to do some sanity checks on - -- the image dir first. - - -- TODO: [required eventually] note that for nix-style - -- installations it is not necessary to do the - -- 'withWin32SelfUpgrade' dance, but it would be necessary for a - -- shared bin dir. - - -- TODO: [required feature] docs and test phases - let docsResult = DocsNotTried - testsResult = TestsNotTried - - noticeProgress ProgressCompleted - - return - BuildResult - { buildResultDocs = docsResult - , buildResultTests = testsResult - , buildResultLogFile = mlogFile - } - where - pkgid = packageId rpkg - uid = installedUnitId rpkg - compid = compilerId compiler - - dispname :: String - dispname = case elabPkgOrComp pkg of - ElabPackage _ -> - prettyShow pkgid - ++ " (all, legacy fallback)" - ElabComponent comp -> - prettyShow pkgid - ++ " (" - ++ maybe "custom" prettyShow (compComponentName comp) - ++ ")" - - noticeProgress :: ProgressPhase -> IO () - noticeProgress phase = - when (isParallelBuild buildSettingNumJobs) $ - progressMessage verbosity phase dispname - - whenHaddock action - | hasValidHaddockTargets pkg = action - | otherwise = return () - - configureCommand = Cabal.configureCommand defaultProgramDb - configureFlags v = - flip filterConfigureFlags v $ - setupHsConfigureFlags - rpkg - pkgshared - verbosity - builddir - configureArgs _ = setupHsConfigureArgs pkg - - buildCommand = Cabal.buildCommand defaultProgramDb - comp_par_strat = case maybe_semaphore of - Just sem_name -> Cabal.Flag (getSemaphoreName sem_name) - _ -> Cabal.NoFlag - buildFlags _ = setupHsBuildFlags comp_par_strat pkg pkgshared verbosity builddir - - haddockCommand = Cabal.haddockCommand - haddockFlags _ = - setupHsHaddockFlags - pkg - pkgshared - verbosity - builddir - - generateInstalledPackageInfo :: IO InstalledPackageInfo - generateInstalledPackageInfo = - withTempInstalledPackageInfoFile - verbosity - distTempDirectory - $ \pkgConfDest -> do - let registerFlags _ = - setupHsRegisterFlags - pkg - pkgshared - verbosity - builddir - pkgConfDest - setup Cabal.registerCommand registerFlags - - copyFlags destdir _ = - setupHsCopyFlags - pkg - pkgshared - verbosity - builddir - destdir - - scriptOptions = - setupHsScriptOptions - rpkg - plan - pkgshared - distDirLayout - srcdir - builddir - (isParallelBuild buildSettingNumJobs) - cacheLock - - setup :: CommandUI flags -> (Version -> flags) -> IO () - setup cmd flags = setup' cmd flags (const []) - - setup' - :: CommandUI flags - -> (Version -> flags) - -> (Version -> [String]) - -> IO () - setup' cmd flags args = - withLogging $ \mLogFileHandle -> - setupWrapper - verbosity - scriptOptions - { useLoggingHandle = mLogFileHandle - , useExtraEnvOverrides = - dataDirsEnvironmentForPlan - distDirLayout - plan - } - (Just (elabPkgDescription pkg)) - cmd - flags - args - - mlogFile :: Maybe FilePath - mlogFile = - case buildSettingLogFile of - Nothing -> Nothing - Just mkLogFile -> Just (mkLogFile compiler platform pkgid uid) - - initLogFile :: IO () - initLogFile = - case mlogFile of - Nothing -> return () - Just logFile -> do - createDirectoryIfMissing True (takeDirectory logFile) - exists <- doesFileExist logFile - when exists $ removeFile logFile - - withLogging :: (Maybe Handle -> IO r) -> IO r - withLogging action = - case mlogFile of - Nothing -> action Nothing - Just logFile -> withFile logFile AppendMode (action . Just) - -hasValidHaddockTargets :: ElaboratedConfiguredPackage -> Bool -hasValidHaddockTargets ElaboratedConfiguredPackage{..} - | not elabBuildHaddocks = False - | otherwise = any componentHasHaddocks components - where - components :: [ComponentTarget] - components = - elabBuildTargets - ++ elabTestTargets - ++ elabBenchTargets - ++ elabReplTarget - ++ elabHaddockTargets - - componentHasHaddocks :: ComponentTarget -> Bool - componentHasHaddocks (ComponentTarget name _) = - case name of - CLibName LMainLibName -> hasHaddocks - CLibName (LSubLibName _) -> elabHaddockInternal && hasHaddocks - CFLibName _ -> elabHaddockForeignLibs && hasHaddocks - CExeName _ -> elabHaddockExecutables && hasHaddocks - CTestName _ -> elabHaddockTestSuites && hasHaddocks - CBenchName _ -> elabHaddockBenchmarks && hasHaddocks - where - hasHaddocks = not (null (elabPkgDescription ^. componentModules name)) - -buildInplaceUnpackedPackage - :: Verbosity - -> DistDirLayout - -> Maybe SemaphoreName - -> BuildTimeSettings - -> Lock - -> Lock - -> ElaboratedSharedConfig - -> ElaboratedInstallPlan - -> ElaboratedReadyPackage - -> BuildStatusRebuild - -> FilePath - -> FilePath - -> IO BuildResult -buildInplaceUnpackedPackage - verbosity - distDirLayout@DistDirLayout - { distTempDirectory - , distPackageCacheDirectory - , distDirectory - , distHaddockOutputDir - } - maybe_semaphore - BuildTimeSettings{buildSettingNumJobs, buildSettingHaddockOpen} - registerLock - cacheLock - pkgshared@ElaboratedSharedConfig - { pkgConfigCompiler = compiler - , pkgConfigCompilerProgs = progdb - , pkgConfigPlatform = platform - } - plan - rpkg@(ReadyPackage pkg) - buildStatus - srcdir - builddir = do - -- TODO: [code cleanup] there is duplication between the - -- distdirlayout and the builddir here builddir is not - -- enough, we also need the per-package cachedir - createDirectoryIfMissingVerbose verbosity True builddir - createDirectoryIfMissingVerbose - verbosity - True - (distPackageCacheDirectory dparams) - - -- Configure phase - -- - whenReConfigure $ do - annotateFailureNoLog ConfigureFailed $ - setup configureCommand configureFlags configureArgs - invalidatePackageRegFileMonitor packageFileMonitor - updatePackageConfigFileMonitor packageFileMonitor srcdir pkg - - -- Build phase - -- - let docsResult = DocsNotTried - testsResult = TestsNotTried - - buildResult :: BuildResultMisc - buildResult = (docsResult, testsResult) - - whenRebuild $ do - timestamp <- beginUpdateFileMonitor - annotateFailureNoLog BuildFailed $ - setup buildCommand buildFlags buildArgs - - let listSimple = - execRebuild srcdir (needElaboratedConfiguredPackage pkg) - listSdist = - fmap (map monitorFileHashed) $ - allPackageSourceFiles verbosity srcdir - ifNullThen m m' = do - xs <- m - if null xs then m' else return xs - monitors <- case PD.buildType (elabPkgDescription pkg) of - Simple -> listSimple - -- If a Custom setup was used, AND the Cabal is recent - -- enough to have sdist --list-sources, use that to - -- determine the files that we need to track. This can - -- cause unnecessary rebuilding (for example, if README - -- is edited, we will try to rebuild) but there isn't - -- a more accurate Custom interface we can use to get - -- this info. We prefer not to use listSimple here - -- as it can miss extra source files that are considered - -- by the Custom setup. - _ - | elabSetupScriptCliVersion pkg >= mkVersion [1, 17] -> - -- However, sometimes sdist --list-sources will fail - -- and return an empty list. In that case, fall - -- back on the (inaccurate) simple tracking. - listSdist `ifNullThen` listSimple - | otherwise -> - listSimple - - let dep_monitors = - map monitorFileHashed $ - elabInplaceDependencyBuildCacheFiles - distDirLayout - pkgshared - plan - pkg - updatePackageBuildFileMonitor - packageFileMonitor - srcdir - timestamp - pkg - buildStatus - (monitors ++ dep_monitors) - buildResult - - -- PURPOSELY omitted: no copy! - - whenReRegister $ annotateFailureNoLog InstallFailed $ do - -- Register locally - mipkg <- - if elabRequiresRegistration pkg - then do - ipkg0 <- generateInstalledPackageInfo - -- We register ourselves rather than via Setup.hs. We need to - -- grab and modify the InstalledPackageInfo. We decide what - -- the installed package id is, not the build system. - let ipkg = ipkg0{Installed.installedUnitId = ipkgid} - criticalSection registerLock $ - Cabal.registerPackage - verbosity - compiler - progdb - (elabRegisterPackageDBStack pkg) - ipkg - Cabal.defaultRegisterOptions - return (Just ipkg) - else return Nothing - - updatePackageRegFileMonitor packageFileMonitor srcdir mipkg - - whenTest $ do - annotateFailureNoLog TestsFailed $ - setup testCommand testFlags testArgs - - whenBench $ - annotateFailureNoLog BenchFailed $ - setup benchCommand benchFlags benchArgs - - -- Repl phase - -- - whenRepl $ - annotateFailureNoLog ReplFailed $ - setupInteractive replCommand replFlags replArgs - - -- Haddock phase - whenHaddock $ - annotateFailureNoLog HaddocksFailed $ do - setup haddockCommand haddockFlags haddockArgs - let haddockTarget = elabHaddockForHackage pkg - when (haddockTarget == Cabal.ForHackage) $ do - let dest = distDirectory name <.> "tar.gz" - name = haddockDirName haddockTarget (elabPkgDescription pkg) - docDir = - distBuildDirectory distDirLayout dparams - "doc" - "html" - Tar.createTarGzFile dest docDir name - notice verbosity $ "Documentation tarball created: " ++ dest - - when (buildSettingHaddockOpen && haddockTarget /= Cabal.ForHackage) $ do - let dest = docDir "index.html" - name = haddockDirName haddockTarget (elabPkgDescription pkg) - docDir = case distHaddockOutputDir of - Nothing -> distBuildDirectory distDirLayout dparams "doc" "html" name - Just dir -> dir - exe <- findOpenProgramLocation platform - case exe of - Right open -> runProgramInvocation verbosity (simpleProgramInvocation open [dest]) - Left err -> dieWithException verbosity $ FindOpenProgramLocationErr err - - return - BuildResult - { buildResultDocs = docsResult - , buildResultTests = testsResult - , buildResultLogFile = Nothing - } - where - ipkgid = installedUnitId pkg - dparams = elabDistDirParams pkgshared pkg - - comp_par_strat = case maybe_semaphore of - Just sem_name -> Cabal.toFlag (getSemaphoreName sem_name) - _ -> Cabal.NoFlag - - packageFileMonitor = newPackageFileMonitor pkgshared distDirLayout dparams - - whenReConfigure action = case buildStatus of - BuildStatusConfigure _ -> action - _ -> return () - - whenRebuild action - | null (elabBuildTargets pkg) - , -- NB: we have to build the test/bench suite! - null (elabTestTargets pkg) - , null (elabBenchTargets pkg) = - return () - | otherwise = action - - whenTest action - | null (elabTestTargets pkg) = return () - | otherwise = action - - whenBench action - | null (elabBenchTargets pkg) = return () - | otherwise = action - - whenRepl action - | null (elabReplTarget pkg) = return () - | otherwise = action - - whenHaddock action - | hasValidHaddockTargets pkg = action - | otherwise = return () - - whenReRegister action = - case buildStatus of - -- We registered the package already - BuildStatusBuild (Just _) _ -> - info verbosity "whenReRegister: previously registered" - -- There is nothing to register - _ - | null (elabBuildTargets pkg) -> - info verbosity "whenReRegister: nothing to register" - | otherwise -> action - - configureCommand = Cabal.configureCommand defaultProgramDb - configureFlags v = - flip filterConfigureFlags v $ - setupHsConfigureFlags - rpkg - pkgshared - verbosity - builddir - configureArgs _ = setupHsConfigureArgs pkg - - buildCommand = Cabal.buildCommand defaultProgramDb - buildFlags _ = - setupHsBuildFlags - comp_par_strat - pkg - pkgshared - verbosity - builddir - buildArgs _ = setupHsBuildArgs pkg - - testCommand = Cabal.testCommand -- defaultProgramDb - testFlags v = - flip filterTestFlags v $ - setupHsTestFlags - pkg - pkgshared - verbosity - builddir - testArgs _ = setupHsTestArgs pkg - - benchCommand = Cabal.benchmarkCommand - benchFlags _ = - setupHsBenchFlags - pkg - pkgshared - verbosity - builddir - benchArgs _ = setupHsBenchArgs pkg - - replCommand = Cabal.replCommand defaultProgramDb - replFlags _ = - setupHsReplFlags - pkg - pkgshared - verbosity - builddir - replArgs _ = setupHsReplArgs pkg - - haddockCommand = Cabal.haddockCommand - haddockFlags v = - flip filterHaddockFlags v $ - setupHsHaddockFlags - pkg - pkgshared - verbosity - builddir - haddockArgs v = - flip filterHaddockArgs v $ - setupHsHaddockArgs pkg - - scriptOptions = - setupHsScriptOptions - rpkg - plan - pkgshared - distDirLayout - srcdir - builddir - (isParallelBuild buildSettingNumJobs) - cacheLock - - setupInteractive - :: CommandUI flags - -> (Version -> flags) - -> (Version -> [String]) - -> IO () - setupInteractive cmd flags args = - setupWrapper - verbosity - scriptOptions{isInteractive = True} - (Just (elabPkgDescription pkg)) - cmd - flags - args - - setup - :: CommandUI flags - -> (Version -> flags) - -> (Version -> [String]) - -> IO () - setup cmd flags args = - setupWrapper - verbosity - scriptOptions - (Just (elabPkgDescription pkg)) - cmd - flags - args - - generateInstalledPackageInfo :: IO InstalledPackageInfo - generateInstalledPackageInfo = - withTempInstalledPackageInfoFile - verbosity - distTempDirectory - $ \pkgConfDest -> do - let registerFlags _ = - setupHsRegisterFlags - pkg - pkgshared - verbosity - builddir - pkgConfDest - setup Cabal.registerCommand registerFlags (const []) - -withTempInstalledPackageInfoFile - :: Verbosity - -> FilePath - -> (FilePath -> IO ()) - -> IO InstalledPackageInfo -withTempInstalledPackageInfoFile verbosity tempdir action = - withTempDirectory verbosity tempdir "package-registration-" $ \dir -> do - -- make absolute since @action@ will often change directory - abs_dir <- canonicalizePath dir - - let pkgConfDest = abs_dir "pkgConf" - action pkgConfDest - - readPkgConf "." pkgConfDest - where - pkgConfParseFailed :: String -> IO a - pkgConfParseFailed perror = - dieWithException verbosity $ PkgConfParseFailed perror - - readPkgConf :: FilePath -> FilePath -> IO InstalledPackageInfo - readPkgConf pkgConfDir pkgConfFile = do - pkgConfStr <- BS.readFile (pkgConfDir pkgConfFile) - (warns, ipkg) <- case Installed.parseInstalledPackageInfo pkgConfStr of - Left perrors -> pkgConfParseFailed $ unlines $ NE.toList perrors - Right (warns, ipkg) -> return (warns, ipkg) - - unless (null warns) $ - warn verbosity $ - unlines warns - - return ipkg - ------------------------------------------------------------------------------- - --- * Utilities - ------------------------------------------------------------------------------- - -{- FOURMOLU_DISABLE -} -annotateFailureNoLog :: (SomeException -> BuildFailureReason) - -> IO a -> IO a -annotateFailureNoLog annotate action = - annotateFailure Nothing annotate action - -annotateFailure :: Maybe FilePath - -> (SomeException -> BuildFailureReason) - -> IO a -> IO a -annotateFailure mlogFile annotate action = - action `catches` - -- It's not just IOException and ExitCode we have to deal with, there's - -- lots, including exceptions from the hackage-security and tar packages. - -- So we take the strategy of catching everything except async exceptions. - [ -#if MIN_VERSION_base(4,7,0) - Handler $ \async -> throwIO (async :: SomeAsyncException) -#else - Handler $ \async -> throwIO (async :: AsyncException) -#endif - , Handler $ \other -> handler (other :: SomeException) - ] - where - handler :: Exception e => e -> IO a - handler = throwIO . BuildFailure mlogFile . annotate . toException diff --git a/cabal-install/src/Distribution/Client/ProjectBuilding/PackageFileMonitor.hs b/cabal-install/src/Distribution/Client/ProjectBuilding/PackageFileMonitor.hs new file mode 100644 index 00000000000..b93064ea7be --- /dev/null +++ b/cabal-install/src/Distribution/Client/ProjectBuilding/PackageFileMonitor.hs @@ -0,0 +1,294 @@ +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RecordWildCards #-} + +module Distribution.Client.ProjectBuilding.PackageFileMonitor where + +import Distribution.Client.Compat.Prelude +import Prelude () + +import Distribution.Client.ProjectBuilding.Types +import Distribution.Client.ProjectPlanning +import Distribution.Client.ProjectPlanning.Types +import Distribution.Client.RebuildMonad + +import Distribution.Client.DistDirLayout +import Distribution.Client.FileMonitor +import Distribution.Client.Types hiding + ( BuildFailure (..) + , BuildOutcome + , BuildOutcomes + , BuildResult (..) + ) + +import Distribution.InstalledPackageInfo (InstalledPackageInfo) +import Distribution.Simple.LocalBuildInfo + ( ComponentName (..) + ) + +import qualified Data.Set as Set +import Distribution.Client.Init.Types (removeExistingFile) + +----------------------------- +-- Package change detection +-- + +-- | As part of the dry run for local unpacked packages we have to check if the +-- package config or files have changed. That is the purpose of +-- 'PackageFileMonitor' and 'checkPackageFileMonitorChanged'. +-- +-- When a package is (re)built, the monitor must be updated to reflect the new +-- state of the package. Because we sometimes build without reconfiguring the +-- state updates are split into two, one for package config changes and one +-- for other changes. This is the purpose of 'updatePackageConfigFileMonitor' +-- and 'updatePackageBuildFileMonitor'. +data PackageFileMonitor = PackageFileMonitor + { pkgFileMonitorConfig :: FileMonitor ElaboratedConfiguredPackage () + , pkgFileMonitorBuild :: FileMonitor (Set ComponentName) BuildResultMisc + , pkgFileMonitorReg :: FileMonitor () (Maybe InstalledPackageInfo) + } + +-- | This is all the components of the 'BuildResult' other than the +-- @['InstalledPackageInfo']@. +-- +-- We have to split up the 'BuildResult' components since they get produced +-- at different times (or rather, when different things change). +type BuildResultMisc = (DocsResult, TestsResult) + +newPackageFileMonitor + :: ElaboratedSharedConfig + -> DistDirLayout + -> DistDirParams + -> PackageFileMonitor +newPackageFileMonitor + shared + DistDirLayout{distPackageCacheFile} + dparams = + PackageFileMonitor + { pkgFileMonitorConfig = + FileMonitor + { fileMonitorCacheFile = distPackageCacheFile dparams "config" + , fileMonitorKeyValid = (==) `on` normaliseConfiguredPackage shared + , fileMonitorCheckIfOnlyValueChanged = False + } + , pkgFileMonitorBuild = + FileMonitor + { fileMonitorCacheFile = distPackageCacheFile dparams "build" + , fileMonitorKeyValid = \componentsToBuild componentsAlreadyBuilt -> + componentsToBuild `Set.isSubsetOf` componentsAlreadyBuilt + , fileMonitorCheckIfOnlyValueChanged = True + } + , pkgFileMonitorReg = + newFileMonitor (distPackageCacheFile dparams "registration") + } + +-- | Helper function for 'checkPackageFileMonitorChanged', +-- 'updatePackageConfigFileMonitor' and 'updatePackageBuildFileMonitor'. +-- +-- It selects the info from a 'ElaboratedConfiguredPackage' that are used by +-- the 'FileMonitor's (in the 'PackageFileMonitor') to detect value changes. +packageFileMonitorKeyValues + :: ElaboratedConfiguredPackage + -> (ElaboratedConfiguredPackage, Set ComponentName) +packageFileMonitorKeyValues elab = + (elab_config, buildComponents) + where + -- The first part is the value used to guard (re)configuring the package. + -- That is, if this value changes then we will reconfigure. + -- The ElaboratedConfiguredPackage consists mostly (but not entirely) of + -- information that affects the (re)configure step. But those parts that + -- do not affect the configure step need to be nulled out. Those parts are + -- the specific targets that we're going to build. + -- + + -- Additionally we null out the parts that don't affect the configure step because they're simply + -- about how tests or benchmarks are run + + -- TODO there may be more things to null here too, in the future. + + elab_config :: ElaboratedConfiguredPackage + elab_config = + elab + { elabBuildTargets = [] + , elabTestTargets = [] + , elabBenchTargets = [] + , elabReplTarget = [] + , elabHaddockTargets = [] + , elabBuildHaddocks = False + , elabTestMachineLog = Nothing + , elabTestHumanLog = Nothing + , elabTestShowDetails = Nothing + , elabTestKeepTix = False + , elabTestTestOptions = [] + , elabBenchmarkOptions = [] + } + + -- The second part is the value used to guard the build step. So this is + -- more or less the opposite of the first part, as it's just the info about + -- what targets we're going to build. + -- + buildComponents :: Set ComponentName + buildComponents = elabBuildTargetWholeComponents elab + +-- | Do all the checks on whether a package has changed and thus needs either +-- rebuilding or reconfiguring and rebuilding. +checkPackageFileMonitorChanged + :: PackageFileMonitor + -> ElaboratedConfiguredPackage + -> FilePath + -> [BuildStatus] + -> IO (Either BuildStatusRebuild BuildResult) +checkPackageFileMonitorChanged + PackageFileMonitor{..} + pkg + srcdir + depsBuildStatus = do + -- TODO: [nice to have] some debug-level message about file + -- changes, like rerunIfChanged + configChanged <- + checkFileMonitorChanged + pkgFileMonitorConfig + srcdir + pkgconfig + case configChanged of + MonitorChanged monitorReason -> + return (Left (BuildStatusConfigure monitorReason')) + where + monitorReason' = fmap (const ()) monitorReason + MonitorUnchanged () _ + -- The configChanged here includes the identity of the dependencies, + -- so depsBuildStatus is just needed for the changes in the content + -- of dependencies. + | any buildStatusRequiresBuild depsBuildStatus -> do + regChanged <- checkFileMonitorChanged pkgFileMonitorReg srcdir () + let mreg = changedToMaybe regChanged + return (Left (BuildStatusBuild mreg BuildReasonDepsRebuilt)) + | otherwise -> do + buildChanged <- + checkFileMonitorChanged + pkgFileMonitorBuild + srcdir + buildComponents + regChanged <- + checkFileMonitorChanged + pkgFileMonitorReg + srcdir + () + let mreg = changedToMaybe regChanged + case (buildChanged, regChanged) of + (MonitorChanged (MonitoredValueChanged prevBuildComponents), _) -> + return (Left (BuildStatusBuild mreg buildReason)) + where + buildReason = BuildReasonExtraTargets prevBuildComponents + (MonitorChanged monitorReason, _) -> + return (Left (BuildStatusBuild mreg buildReason)) + where + buildReason = BuildReasonFilesChanged monitorReason' + monitorReason' = fmap (const ()) monitorReason + (MonitorUnchanged _ _, MonitorChanged monitorReason) -> + -- this should only happen if the file is corrupt or been + -- manually deleted. We don't want to bother with another + -- phase just for this, so we'll reregister by doing a build. + return (Left (BuildStatusBuild Nothing buildReason)) + where + buildReason = BuildReasonFilesChanged monitorReason' + monitorReason' = fmap (const ()) monitorReason + (MonitorUnchanged _ _, MonitorUnchanged _ _) + | pkgHasEphemeralBuildTargets pkg -> + return (Left (BuildStatusBuild mreg buildReason)) + where + buildReason = BuildReasonEphemeralTargets + (MonitorUnchanged buildResult _, MonitorUnchanged _ _) -> + return $ + Right + BuildResult + { buildResultDocs = docsResult + , buildResultTests = testsResult + , buildResultLogFile = Nothing + } + where + (docsResult, testsResult) = buildResult + where + (pkgconfig, buildComponents) = packageFileMonitorKeyValues pkg + changedToMaybe :: MonitorChanged a b -> Maybe b + changedToMaybe (MonitorChanged _) = Nothing + changedToMaybe (MonitorUnchanged x _) = Just x + +updatePackageConfigFileMonitor + :: PackageFileMonitor + -> FilePath + -> ElaboratedConfiguredPackage + -> IO () +updatePackageConfigFileMonitor + PackageFileMonitor{pkgFileMonitorConfig} + srcdir + pkg = + updateFileMonitor + pkgFileMonitorConfig + srcdir + Nothing + [] + pkgconfig + () + where + (pkgconfig, _buildComponents) = packageFileMonitorKeyValues pkg + +updatePackageBuildFileMonitor + :: PackageFileMonitor + -> FilePath + -> MonitorTimestamp + -> ElaboratedConfiguredPackage + -> BuildStatusRebuild + -> [MonitorFilePath] + -> BuildResultMisc + -> IO () +updatePackageBuildFileMonitor + PackageFileMonitor{pkgFileMonitorBuild} + srcdir + timestamp + pkg + pkgBuildStatus + monitors + buildResult = + updateFileMonitor + pkgFileMonitorBuild + srcdir + (Just timestamp) + monitors + buildComponents' + buildResult + where + (_pkgconfig, buildComponents) = packageFileMonitorKeyValues pkg + + -- If the only thing that's changed is that we're now building extra + -- components, then we can avoid later unnecessary rebuilds by saving the + -- total set of components that have been built, namely the union of the + -- existing ones plus the new ones. If files also changed this would be + -- the wrong thing to do. Note that we rely on the + -- fileMonitorCheckIfOnlyValueChanged = True mode to get this guarantee + -- that it's /only/ the value that changed not any files that changed. + buildComponents' = + case pkgBuildStatus of + BuildStatusBuild _ (BuildReasonExtraTargets prevBuildComponents) -> + buildComponents `Set.union` prevBuildComponents + _ -> buildComponents + +updatePackageRegFileMonitor + :: PackageFileMonitor + -> FilePath + -> Maybe InstalledPackageInfo + -> IO () +updatePackageRegFileMonitor + PackageFileMonitor{pkgFileMonitorReg} + srcdir + mipkg = + updateFileMonitor + pkgFileMonitorReg + srcdir + Nothing + [] + () + mipkg + +invalidatePackageRegFileMonitor :: PackageFileMonitor -> IO () +invalidatePackageRegFileMonitor PackageFileMonitor{pkgFileMonitorReg} = + removeExistingFile (fileMonitorCacheFile pkgFileMonitorReg) diff --git a/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs b/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs new file mode 100644 index 00000000000..5b651746dc1 --- /dev/null +++ b/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs @@ -0,0 +1,936 @@ +{-# LANGUAGE CPP #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} + +-- | This module exposes functions to build and register unpacked packages. +-- +-- Mainly, unpacked packages are either: +-- * Built and registered in-place +-- * Built and installed +-- +-- The two cases differ significantly for there to be a distinction. +-- For instance, we only care about file monitoring and re-building when dealing +-- with "inplace" registered packages, whereas for installed packages we don't. +module Distribution.Client.ProjectBuilding.UnpackedPackage + ( buildInplaceUnpackedPackage + , buildAndInstallUnpackedPackage + + -- ** Auxiliary definitions + , buildAndRegisterUnpackedPackage + , PackageBuildingPhase + + -- ** Utilities + , annotateFailure + , annotateFailureNoLog + ) where + +import Distribution.Client.Compat.Prelude +import Prelude () + +import Distribution.Client.PackageHash (renderPackageHashInputs) +import Distribution.Client.ProjectBuilding.Types +import Distribution.Client.ProjectConfig +import Distribution.Client.ProjectConfig.Types +import Distribution.Client.ProjectPlanning +import Distribution.Client.ProjectPlanning.Types +import Distribution.Client.RebuildMonad +import Distribution.Client.Store + +import Distribution.Client.DistDirLayout +import Distribution.Client.FileMonitor +import Distribution.Client.JobControl +import Distribution.Client.Setup + ( filterConfigureFlags + , filterHaddockArgs + , filterHaddockFlags + , filterTestFlags + ) +import Distribution.Client.SetupWrapper +import Distribution.Client.SourceFiles +import Distribution.Client.SrcDist (allPackageSourceFiles) +import qualified Distribution.Client.Tar as Tar +import Distribution.Client.Types hiding + ( BuildFailure (..) + , BuildOutcome + , BuildOutcomes + , BuildResult (..) + ) +import Distribution.Client.Utils + ( ProgressPhase (..) + , progressMessage + ) + +import Distribution.Compat.Lens +import Distribution.InstalledPackageInfo (InstalledPackageInfo) +import qualified Distribution.InstalledPackageInfo as Installed +import Distribution.Package +import qualified Distribution.PackageDescription as PD +import Distribution.Simple.BuildPaths (haddockDirName) +import Distribution.Simple.Command (CommandUI) +import Distribution.Simple.Compiler + ( PackageDBStack + ) +import qualified Distribution.Simple.InstallDirs as InstallDirs +import Distribution.Simple.LocalBuildInfo + ( ComponentName (..) + , LibraryName (..) + ) +import Distribution.Simple.Program +import qualified Distribution.Simple.Register as Cabal +import qualified Distribution.Simple.Setup as Cabal +import Distribution.Types.BuildType +import Distribution.Types.PackageDescription.Lens (componentModules) + +import Distribution.Simple.Utils +import Distribution.System (Platform (..)) +import Distribution.Version + +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as LBS +import qualified Data.ByteString.Lazy.Char8 as LBS.Char8 +import qualified Data.List.NonEmpty as NE + +import Control.Exception (ErrorCall, Handler (..), SomeAsyncException, assert, catches) +import System.Directory (canonicalizePath, createDirectoryIfMissing, doesDirectoryExist, doesFileExist, removeFile) +import System.FilePath (dropDrive, normalise, takeDirectory, (<.>), ()) +import System.IO (Handle, IOMode (AppendMode), withFile) +import System.Semaphore (SemaphoreName (..)) + +import Web.Browser (openBrowser) + +import Distribution.Client.Errors +import Distribution.Compat.Directory (listDirectory) + +import Distribution.Client.ProjectBuilding.PackageFileMonitor + +-- | Each unpacked package is processed in the following phases: +-- +-- * Configure phase +-- * Build phase +-- * Haddock phase +-- * Install phase (copy + register) +-- * Register phase +-- * Test phase +-- * Bench phase +-- * Repl phase +-- +-- Depending on whether we are installing the package or building it inplace, +-- the phases will be carried out differently. For example, when installing, +-- the test, benchmark, and repl phase are ignored. +data PackageBuildingPhase + = PBConfigurePhase {runConfigure :: IO ()} + | PBBuildPhase {runBuild :: IO ()} + | PBHaddockPhase {runHaddock :: IO ()} + | PBInstallPhase + { runCopy :: FilePath -> IO () + , runRegister + :: PackageDBStack + -> Cabal.RegisterOptions + -> IO InstalledPackageInfo + } + | PBTestPhase {runTest :: IO ()} + | PBBenchPhase {runBench :: IO ()} + | PBReplPhase {runRepl :: IO ()} + +-- | Structures the phases of building and registering a package amongst others +-- (see t'PackageBuildingPhase'). Delegates logic specific to a certain +-- building style (notably, inplace vs install) to the delegate function that +-- receives as an argument t'PackageBuildingPhase') +buildAndRegisterUnpackedPackage + :: Verbosity + -> DistDirLayout + -> Maybe SemaphoreName + -- ^ Whether to pass a semaphore to build process + -- this is different to BuildTimeSettings because the + -- name of the semaphore is created freshly each time. + -> BuildTimeSettings + -> Lock + -> Lock + -> ElaboratedSharedConfig + -> ElaboratedInstallPlan + -> ElaboratedReadyPackage + -> FilePath + -> FilePath + -> Maybe (FilePath) + -- ^ The path to an /initialized/ log file + -> (PackageBuildingPhase -> IO ()) + -> IO () +buildAndRegisterUnpackedPackage + verbosity + distDirLayout@DistDirLayout{distTempDirectory} + maybe_semaphore + BuildTimeSettings{buildSettingNumJobs} + registerLock + cacheLock + pkgshared@ElaboratedSharedConfig + { pkgConfigCompiler = compiler + , pkgConfigCompilerProgs = progdb + } + plan + rpkg@(ReadyPackage pkg) + srcdir + builddir + mlogFile + delegate = do + -- Configure phase + delegate $ + PBConfigurePhase $ + annotateFailure mlogFile ConfigureFailed $ + setup configureCommand configureFlags configureArgs + + -- Build phase + delegate $ + PBBuildPhase $ + annotateFailure mlogFile BuildFailed $ do + setup buildCommand buildFlags buildArgs + + -- Haddock phase + whenHaddock $ + delegate $ + PBHaddockPhase $ + annotateFailure mlogFile HaddocksFailed $ do + setup haddockCommand haddockFlags haddockArgs + + -- Install phase + delegate $ + PBInstallPhase + { runCopy = \destdir -> + annotateFailure mlogFile InstallFailed $ + setup Cabal.copyCommand (copyFlags destdir) copyArgs + , runRegister = \pkgDBStack registerOpts -> + annotateFailure mlogFile InstallFailed $ do + -- We register ourselves rather than via Setup.hs. We need to + -- grab and modify the InstalledPackageInfo. We decide what + -- the installed package id is, not the build system. + ipkg0 <- generateInstalledPackageInfo + let ipkg = ipkg0{Installed.installedUnitId = uid} + criticalSection registerLock $ + Cabal.registerPackage + verbosity + compiler + progdb + pkgDBStack + ipkg + registerOpts + return ipkg + } + + -- Test phase + whenTest $ + delegate $ + PBTestPhase $ + annotateFailure mlogFile TestsFailed $ + setup testCommand testFlags testArgs + + -- Bench phase + whenBench $ + delegate $ + PBBenchPhase $ + annotateFailure mlogFile BenchFailed $ + setup benchCommand benchFlags benchArgs + + -- Repl phase + whenRepl $ + delegate $ + PBReplPhase $ + annotateFailure mlogFile ReplFailed $ + setupInteractive replCommand replFlags replArgs + + return () + where + uid = installedUnitId rpkg + + comp_par_strat = case maybe_semaphore of + Just sem_name -> Cabal.toFlag (getSemaphoreName sem_name) + _ -> Cabal.NoFlag + + whenTest action + | null (elabTestTargets pkg) = return () + | otherwise = action + + whenBench action + | null (elabBenchTargets pkg) = return () + | otherwise = action + + whenRepl action + | null (elabReplTarget pkg) = return () + | otherwise = action + + whenHaddock action + | hasValidHaddockTargets pkg = action + | otherwise = return () + + configureCommand = Cabal.configureCommand defaultProgramDb + configureFlags v = + flip filterConfigureFlags v $ + setupHsConfigureFlags + plan + rpkg + pkgshared + verbosity + builddir + configureArgs _ = setupHsConfigureArgs pkg + + buildCommand = Cabal.buildCommand defaultProgramDb + buildFlags _ = setupHsBuildFlags comp_par_strat pkg pkgshared verbosity builddir + buildArgs _ = setupHsBuildArgs pkg + + copyFlags destdir _ = + setupHsCopyFlags + pkg + pkgshared + verbosity + builddir + destdir + -- In theory, we could want to copy less things than those that were + -- built, but instead, we simply copy the targets that were built. + copyArgs = buildArgs + + testCommand = Cabal.testCommand -- defaultProgramDb + testFlags v = + flip filterTestFlags v $ + setupHsTestFlags + pkg + verbosity + builddir + testArgs _ = setupHsTestArgs pkg + + benchCommand = Cabal.benchmarkCommand + benchFlags _ = + setupHsBenchFlags + pkg + pkgshared + verbosity + builddir + benchArgs _ = setupHsBenchArgs pkg + + replCommand = Cabal.replCommand defaultProgramDb + replFlags _ = + setupHsReplFlags + pkg + pkgshared + verbosity + builddir + replArgs _ = setupHsReplArgs pkg + + haddockCommand = Cabal.haddockCommand + haddockFlags v = + flip filterHaddockFlags v $ + setupHsHaddockFlags + pkg + pkgshared + verbosity + builddir + haddockArgs v = + flip filterHaddockArgs v $ + setupHsHaddockArgs pkg + + scriptOptions = + setupHsScriptOptions + rpkg + plan + pkgshared + distDirLayout + srcdir + builddir + (isParallelBuild buildSettingNumJobs) + cacheLock + + setup + :: CommandUI flags + -> (Version -> flags) + -> (Version -> [String]) + -> IO () + setup cmd flags args = + withLogging $ \mLogFileHandle -> + setupWrapper + verbosity + scriptOptions + { useLoggingHandle = mLogFileHandle + , useExtraEnvOverrides = + dataDirsEnvironmentForPlan + distDirLayout + plan + } + (Just (elabPkgDescription pkg)) + cmd + flags + args + + setupInteractive + :: CommandUI flags + -> (Version -> flags) + -> (Version -> [String]) + -> IO () + setupInteractive cmd flags args = + setupWrapper + verbosity + scriptOptions{isInteractive = True} + (Just (elabPkgDescription pkg)) + cmd + flags + args + + generateInstalledPackageInfo :: IO InstalledPackageInfo + generateInstalledPackageInfo = + withTempInstalledPackageInfoFile + verbosity + distTempDirectory + $ \pkgConfDest -> do + let registerFlags _ = + setupHsRegisterFlags + pkg + pkgshared + verbosity + builddir + pkgConfDest + setup Cabal.registerCommand registerFlags (const []) + + withLogging :: (Maybe Handle -> IO r) -> IO r + withLogging action = + case mlogFile of + Nothing -> action Nothing + Just logFile -> withFile logFile AppendMode (action . Just) + +-------------------------------------------------------------------------------- + +-- * Build Inplace + +-------------------------------------------------------------------------------- + +buildInplaceUnpackedPackage + :: Verbosity + -> DistDirLayout + -> Maybe SemaphoreName + -> BuildTimeSettings + -> Lock + -> Lock + -> ElaboratedSharedConfig + -> ElaboratedInstallPlan + -> ElaboratedReadyPackage + -> BuildStatusRebuild + -> FilePath + -> FilePath + -> IO BuildResult +buildInplaceUnpackedPackage + verbosity + distDirLayout@DistDirLayout + { distPackageCacheDirectory + , distDirectory + , distHaddockOutputDir + } + maybe_semaphore + buildSettings@BuildTimeSettings{buildSettingHaddockOpen} + registerLock + cacheLock + pkgshared@ElaboratedSharedConfig{pkgConfigPlatform = Platform _ os} + plan + rpkg@(ReadyPackage pkg) + buildStatus + srcdir + builddir = do + -- TODO: [code cleanup] there is duplication between the + -- distdirlayout and the builddir here builddir is not + -- enough, we also need the per-package cachedir + createDirectoryIfMissingVerbose verbosity True builddir + createDirectoryIfMissingVerbose + verbosity + True + (distPackageCacheDirectory dparams) + + let docsResult = DocsNotTried + testsResult = TestsNotTried + + buildResult :: BuildResultMisc + buildResult = (docsResult, testsResult) + + buildAndRegisterUnpackedPackage + verbosity + distDirLayout + maybe_semaphore + buildSettings + registerLock + cacheLock + pkgshared + plan + rpkg + srcdir + builddir + Nothing -- no log file for inplace builds! + $ \case + PBConfigurePhase{runConfigure} -> do + whenReConfigure $ do + runConfigure + invalidatePackageRegFileMonitor packageFileMonitor + updatePackageConfigFileMonitor packageFileMonitor srcdir pkg + PBBuildPhase{runBuild} -> do + whenRebuild $ do + timestamp <- beginUpdateFileMonitor + runBuild + + let listSimple = + execRebuild srcdir (needElaboratedConfiguredPackage pkg) + listSdist = + fmap (map monitorFileHashed) $ + allPackageSourceFiles verbosity srcdir + ifNullThen m m' = do + xs <- m + if null xs then m' else return xs + monitors <- case PD.buildType (elabPkgDescription pkg) of + Simple -> listSimple + -- If a Custom setup was used, AND the Cabal is recent + -- enough to have sdist --list-sources, use that to + -- determine the files that we need to track. This can + -- cause unnecessary rebuilding (for example, if README + -- is edited, we will try to rebuild) but there isn't + -- a more accurate Custom interface we can use to get + -- this info. We prefer not to use listSimple here + -- as it can miss extra source files that are considered + -- by the Custom setup. + _ + | elabSetupScriptCliVersion pkg >= mkVersion [1, 17] -> + -- However, sometimes sdist --list-sources will fail + -- and return an empty list. In that case, fall + -- back on the (inaccurate) simple tracking. + listSdist `ifNullThen` listSimple + | otherwise -> + listSimple + + let dep_monitors = + map monitorFileHashed $ + elabInplaceDependencyBuildCacheFiles + distDirLayout + pkgshared + plan + pkg + updatePackageBuildFileMonitor + packageFileMonitor + srcdir + timestamp + pkg + buildStatus + (monitors ++ dep_monitors) + buildResult + PBHaddockPhase{runHaddock} -> do + runHaddock + let haddockTarget = elabHaddockForHackage pkg + when (haddockTarget == Cabal.ForHackage) $ do + let dest = distDirectory name <.> "tar.gz" + name = haddockDirName haddockTarget (elabPkgDescription pkg) + docDir = + distBuildDirectory distDirLayout dparams + "doc" + "html" + Tar.createTarGzFile dest docDir name + notice verbosity $ "Documentation tarball created: " ++ dest + + when (buildSettingHaddockOpen && haddockTarget /= Cabal.ForHackage) $ do + let dest = docDir "index.html" + name = haddockDirName haddockTarget (elabPkgDescription pkg) + docDir = case distHaddockOutputDir of + Nothing -> distBuildDirectory distDirLayout dparams "doc" "html" name + Just dir -> dir + catch + (void $ openBrowser dest) + ( \(_ :: ErrorCall) -> + dieWithException verbosity $ + FindOpenProgramLocationErr $ + "Unsupported OS: " <> show os + ) + PBInstallPhase{runCopy = _runCopy, runRegister} -> do + -- PURPOSELY omitted: no copy! + + whenReRegister $ do + -- Register locally + mipkg <- + if elabRequiresRegistration pkg + then do + ipkg <- + runRegister + (elabRegisterPackageDBStack pkg) + Cabal.defaultRegisterOptions + return (Just ipkg) + else return Nothing + + updatePackageRegFileMonitor packageFileMonitor srcdir mipkg + PBTestPhase{runTest} -> runTest + PBBenchPhase{runBench} -> runBench + PBReplPhase{runRepl} -> runRepl + + return + BuildResult + { buildResultDocs = docsResult + , buildResultTests = testsResult + , buildResultLogFile = Nothing + } + where + dparams = elabDistDirParams pkgshared pkg + + packageFileMonitor = newPackageFileMonitor pkgshared distDirLayout dparams + + whenReConfigure action = case buildStatus of + BuildStatusConfigure _ -> action + _ -> return () + + whenRebuild action + | null (elabBuildTargets pkg) + , -- NB: we have to build the test/bench suite! + null (elabTestTargets pkg) + , null (elabBenchTargets pkg) = + return () + | otherwise = action + + whenReRegister action = + case buildStatus of + -- We registered the package already + BuildStatusBuild (Just _) _ -> + info verbosity "whenReRegister: previously registered" + -- There is nothing to register + _ + | null (elabBuildTargets pkg) -> + info verbosity "whenReRegister: nothing to register" + | otherwise -> action + +-------------------------------------------------------------------------------- + +-- * Build and Install + +-------------------------------------------------------------------------------- + +buildAndInstallUnpackedPackage + :: Verbosity + -> DistDirLayout + -> StoreDirLayout + -> Maybe SemaphoreName + -- ^ Whether to pass a semaphore to build process + -- this is different to BuildTimeSettings because the + -- name of the semaphore is created freshly each time. + -> BuildTimeSettings + -> Lock + -> Lock + -> ElaboratedSharedConfig + -> ElaboratedInstallPlan + -> ElaboratedReadyPackage + -> FilePath + -> FilePath + -> IO BuildResult +buildAndInstallUnpackedPackage + verbosity + distDirLayout + storeDirLayout@StoreDirLayout + { storePackageDBStack + } + maybe_semaphore + buildSettings@BuildTimeSettings{buildSettingNumJobs, buildSettingLogFile} + registerLock + cacheLock + pkgshared@ElaboratedSharedConfig + { pkgConfigCompiler = compiler + , pkgConfigPlatform = platform + } + plan + rpkg@(ReadyPackage pkg) + srcdir + builddir = do + createDirectoryIfMissingVerbose verbosity True (srcdir builddir) + + -- TODO: [code cleanup] deal consistently with talking to older + -- Setup.hs versions, much like we do for ghc, with a proper + -- options type and rendering step which will also let us + -- call directly into the lib, rather than always going via + -- the lib's command line interface, which would also allow + -- passing data like installed packages, compiler, and + -- program db for a quicker configure. + + -- TODO: [required feature] docs and tests + -- TODO: [required feature] sudo re-exec + + initLogFile + + buildAndRegisterUnpackedPackage + verbosity + distDirLayout + maybe_semaphore + buildSettings + registerLock + cacheLock + pkgshared + plan + rpkg + srcdir + builddir + mlogFile + $ \case + PBConfigurePhase{runConfigure} -> do + noticeProgress ProgressStarting + runConfigure + PBBuildPhase{runBuild} -> do + noticeProgress ProgressBuilding + runBuild + PBHaddockPhase{runHaddock} -> do + noticeProgress ProgressHaddock + runHaddock + PBInstallPhase{runCopy, runRegister} -> do + noticeProgress ProgressInstalling + + let registerPkg + | not (elabRequiresRegistration pkg) = + debug verbosity $ + "registerPkg: elab does NOT require registration for " + ++ prettyShow uid + | otherwise = do + assert + ( elabRegisterPackageDBStack pkg + == storePackageDBStack compiler (elabPackageDbs pkg) + ) + (return ()) + _ <- + runRegister + (elabRegisterPackageDBStack pkg) + Cabal.defaultRegisterOptions + { Cabal.registerMultiInstance = True + , Cabal.registerSuppressFilesCheck = True + } + return () + + -- Actual installation + void $ + newStoreEntry + verbosity + storeDirLayout + compiler + uid + (copyPkgFiles verbosity pkgshared pkg runCopy) + registerPkg + + -- No tests on install + PBTestPhase{} -> return () + -- No bench on install + PBBenchPhase{} -> return () + -- No repl on install + PBReplPhase{} -> return () + + -- TODO: [nice to have] we currently rely on Setup.hs copy to do the right + -- thing. Although we do copy into an image dir and do the move into the + -- final location ourselves, perhaps we ought to do some sanity checks on + -- the image dir first. + + -- TODO: [required eventually] note that for nix-style + -- installations it is not necessary to do the + -- 'withWin32SelfUpgrade' dance, but it would be necessary for a + -- shared bin dir. + + -- TODO: [required feature] docs and test phases + let docsResult = DocsNotTried + testsResult = TestsNotTried + + noticeProgress ProgressCompleted + + return + BuildResult + { buildResultDocs = docsResult + , buildResultTests = testsResult + , buildResultLogFile = mlogFile + } + where + uid = installedUnitId rpkg + pkgid = packageId rpkg + + dispname :: String + dispname = case elabPkgOrComp pkg of + -- Packages built altogether, instead of per component + ElabPackage ElaboratedPackage{pkgWhyNotPerComponent} -> + prettyShow pkgid + ++ " (all, legacy fallback: " + ++ unwords (map whyNotPerComponent $ NE.toList pkgWhyNotPerComponent) + ++ ")" + -- Packages built per component + ElabComponent comp -> + prettyShow pkgid + ++ " (" + ++ maybe "custom" prettyShow (compComponentName comp) + ++ ")" + + noticeProgress :: ProgressPhase -> IO () + noticeProgress phase = + when (isParallelBuild buildSettingNumJobs) $ + progressMessage verbosity phase dispname + + mlogFile :: Maybe FilePath + mlogFile = + case buildSettingLogFile of + Nothing -> Nothing + Just mkLogFile -> Just (mkLogFile compiler platform pkgid uid) + + initLogFile :: IO () + initLogFile = + case mlogFile of + Nothing -> return () + Just logFile -> do + createDirectoryIfMissing True (takeDirectory logFile) + exists <- doesFileExist logFile + when exists $ removeFile logFile + +-- | The copy part of the installation phase when doing build-and-install +copyPkgFiles + :: Verbosity + -> ElaboratedSharedConfig + -> ElaboratedConfiguredPackage + -> (FilePath -> IO ()) + -- ^ The 'runCopy' function which invokes ./Setup copy for the + -- given filepath + -> FilePath + -- ^ The temporary dir file path + -> IO (FilePath, [FilePath]) +copyPkgFiles verbosity pkgshared pkg runCopy tmpDir = do + let tmpDirNormalised = normalise tmpDir + runCopy tmpDirNormalised + -- Note that the copy command has put the files into + -- @$tmpDir/$prefix@ so we need to return this dir so + -- the store knows which dir will be the final store entry. + let prefix = + normalise $ + dropDrive (InstallDirs.prefix (elabInstallDirs pkg)) + entryDir = tmpDirNormalised prefix + + -- if there weren't anything to build, it might be that directory is not created + -- the @setup Cabal.copyCommand@ above might do nothing. + -- https://github.com/haskell/cabal/issues/4130 + createDirectoryIfMissingVerbose verbosity True entryDir + + let hashFileName = entryDir "cabal-hash.txt" + outPkgHashInputs = renderPackageHashInputs (packageHashInputs pkgshared pkg) + + info verbosity $ + "creating file with the inputs used to compute the package hash: " ++ hashFileName + + LBS.writeFile hashFileName outPkgHashInputs + + debug verbosity "Package hash inputs:" + traverse_ + (debug verbosity . ("> " ++)) + (lines $ LBS.Char8.unpack outPkgHashInputs) + + -- Ensure that there are no files in `tmpDir`, that are + -- not in `entryDir`. While this breaks the + -- prefix-relocatable property of the libraries, it is + -- necessary on macOS to stay under the load command limit + -- of the macOS mach-o linker. See also + -- @PackageHash.hashedInstalledPackageIdVeryShort@. + -- + -- We also normalise paths to ensure that there are no + -- different representations for the same path. Like / and + -- \\ on windows under msys. + otherFiles <- + filter (not . isPrefixOf entryDir) + <$> listFilesRecursive tmpDirNormalised + -- Here's where we could keep track of the installed files + -- ourselves if we wanted to by making a manifest of the + -- files in the tmp dir. + return (entryDir, otherFiles) + where + listFilesRecursive :: FilePath -> IO [FilePath] + listFilesRecursive path = do + files <- fmap (path ) <$> (listDirectory path) + allFiles <- for files $ \file -> do + isDir <- doesDirectoryExist file + if isDir + then listFilesRecursive file + else return [file] + return (concat allFiles) + +-------------------------------------------------------------------------------- + +-- * Exported Utils + +-------------------------------------------------------------------------------- + +{- FOURMOLU_DISABLE -} +annotateFailureNoLog :: (SomeException -> BuildFailureReason) + -> IO a -> IO a +annotateFailureNoLog annotate action = + annotateFailure Nothing annotate action + +annotateFailure :: Maybe FilePath + -> (SomeException -> BuildFailureReason) + -> IO a -> IO a +annotateFailure mlogFile annotate action = + action `catches` + -- It's not just IOException and ExitCode we have to deal with, there's + -- lots, including exceptions from the hackage-security and tar packages. + -- So we take the strategy of catching everything except async exceptions. + [ +#if MIN_VERSION_base(4,7,0) + Handler $ \async -> throwIO (async :: SomeAsyncException) +#else + Handler $ \async -> throwIO (async :: AsyncException) +#endif + , Handler $ \other -> handler (other :: SomeException) + ] + where + handler :: Exception e => e -> IO a + handler = throwIO . BuildFailure mlogFile . annotate . toException + +-------------------------------------------------------------------------------- +-- * Other Utils +-------------------------------------------------------------------------------- + +hasValidHaddockTargets :: ElaboratedConfiguredPackage -> Bool +hasValidHaddockTargets ElaboratedConfiguredPackage{..} + | not elabBuildHaddocks = False + | otherwise = any componentHasHaddocks components + where + components :: [ComponentTarget] + components = + elabBuildTargets + ++ elabTestTargets + ++ elabBenchTargets + ++ elabReplTarget + ++ elabHaddockTargets + + componentHasHaddocks :: ComponentTarget -> Bool + componentHasHaddocks (ComponentTarget name _) = + case name of + CLibName LMainLibName -> hasHaddocks + CLibName (LSubLibName _) -> elabHaddockInternal && hasHaddocks + CFLibName _ -> elabHaddockForeignLibs && hasHaddocks + CExeName _ -> elabHaddockExecutables && hasHaddocks + CTestName _ -> elabHaddockTestSuites && hasHaddocks + CBenchName _ -> elabHaddockBenchmarks && hasHaddocks + where + hasHaddocks = not (null (elabPkgDescription ^. componentModules name)) + +withTempInstalledPackageInfoFile + :: Verbosity + -> FilePath + -> (FilePath -> IO ()) + -> IO InstalledPackageInfo +withTempInstalledPackageInfoFile verbosity tempdir action = + withTempDirectory verbosity tempdir "package-registration-" $ \dir -> do + -- make absolute since @action@ will often change directory + abs_dir <- canonicalizePath dir + + let pkgConfDest = abs_dir "pkgConf" + action pkgConfDest + + readPkgConf "." pkgConfDest + where + pkgConfParseFailed :: String -> IO a + pkgConfParseFailed perror = + dieWithException verbosity $ PkgConfParseFailed perror + + readPkgConf :: FilePath -> FilePath -> IO InstalledPackageInfo + readPkgConf pkgConfDir pkgConfFile = do + pkgConfStr <- BS.readFile (pkgConfDir pkgConfFile) + (warns, ipkg) <- case Installed.parseInstalledPackageInfo pkgConfStr of + Left perrors -> pkgConfParseFailed $ unlines $ NE.toList perrors + Right (warns, ipkg) -> return (warns, ipkg) + + unless (null warns) $ + warn verbosity $ + unlines warns + + return ipkg + diff --git a/cabal-install/src/Distribution/Client/ProjectConfig.hs b/cabal-install/src/Distribution/Client/ProjectConfig.hs index 33de18f49a6..8891b40ad1b 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig.hs @@ -63,7 +63,7 @@ import Distribution.Client.Compat.Prelude import Prelude () import Distribution.Client.Glob - ( isTrivialFilePathGlob + ( isTrivialRootedGlob ) import Distribution.Client.ProjectConfig.Legacy import qualified Distribution.Client.ProjectConfig.Parsec as Parsec @@ -630,32 +630,25 @@ withGlobalConfig verbosity gcf with = do with globalConfig withProjectOrGlobalConfig - :: Verbosity - -- ^ verbosity - -> Flag Bool + :: Flag Bool -- ^ whether to ignore local project (--ignore-project flag) - -> Flag FilePath - -- ^ @--cabal-config@ -> IO a - -- ^ with project - -> (ProjectConfig -> IO a) - -- ^ without project + -- ^ continuation with project -> IO a -withProjectOrGlobalConfig verbosity (Flag True) gcf _with without = do - globalConfig <- runRebuild "" $ readGlobalConfig verbosity gcf - without globalConfig -withProjectOrGlobalConfig verbosity _ignorePrj gcf with without = - withProjectOrGlobalConfig' verbosity gcf with without + -- ^ continuation without project + -> IO a +withProjectOrGlobalConfig (Flag True) _with without = do + without +withProjectOrGlobalConfig _ignorePrj with without = + withProjectOrGlobalConfig' with without withProjectOrGlobalConfig' - :: Verbosity - -> Flag FilePath + :: IO a + -- ^ continuation with project -> IO a - -> (ProjectConfig -> IO a) + -- ^ continuation without project -> IO a -withProjectOrGlobalConfig' verbosity globalConfigFlag with without = do - globalConfig <- runRebuild "" $ readGlobalConfig verbosity globalConfigFlag - +withProjectOrGlobalConfig' with without = do catch with $ \case (BadPackageLocations prov locs) @@ -663,8 +656,8 @@ withProjectOrGlobalConfig' verbosity globalConfigFlag with without = do , let isGlobErr (BadLocGlobEmptyMatch _) = True isGlobErr _ = False - , any isGlobErr locs -> - without globalConfig + , any isGlobErr locs -> do + without err -> throwIO err -- | Read all the config relevant for a project. This includes the project @@ -1020,7 +1013,7 @@ renderBadPackageLocationMatch bplm = case bplm of ++ "' contains multiple " ++ ".cabal files (which is not currently supported)." --- | Given the project config, +-- | Determines the location of all packages mentioned in the project configuration. -- -- Throws 'BadPackageLocations'. findProjectPackages @@ -1050,11 +1043,7 @@ findProjectPackages findPackageLocation :: Bool -> String - -> Rebuild - ( Either - BadPackageLocation - [ProjectPackageLocation] - ) + -> Rebuild (Either BadPackageLocation [ProjectPackageLocation]) findPackageLocation _required@True pkglocstr = -- strategy: try first as a file:// or http(s):// URL. -- then as a file glob (usually encompassing single file) @@ -1075,13 +1064,7 @@ findProjectPackages , checkIsFileGlobPackage , checkIsSingleFilePackage :: String - -> Rebuild - ( Maybe - ( Either - BadPackageLocation - [ProjectPackageLocation] - ) - ) + -> Rebuild (Maybe (Either BadPackageLocation [ProjectPackageLocation])) checkIsUriPackage pkglocstr = case parseAbsoluteURI pkglocstr of Just @@ -1114,7 +1097,7 @@ findProjectPackages matches <- matchFileGlob glob case matches of [] - | isJust (isTrivialFilePathGlob glob) -> + | isJust (isTrivialRootedGlob glob) -> return ( Left ( BadPackageLocationFile @@ -1128,7 +1111,7 @@ findProjectPackages <$> traverse checkFilePackageMatch matches return $! case (failures, pkglocs) of ([failure], []) - | isJust (isTrivialFilePathGlob glob) -> + | isJust (isTrivialRootedGlob glob) -> Left (BadPackageLocationFile failure) (_, []) -> Left (BadLocGlobBadMatches pkglocstr failures) _ -> Right pkglocs @@ -1197,9 +1180,9 @@ findProjectPackages -- -- For a directory @some/dir/@, this is a glob of the form @some/dir/\*.cabal@. -- The directory part can be either absolute or relative. -globStarDotCabal :: FilePath -> FilePathGlob +globStarDotCabal :: FilePath -> RootedGlob globStarDotCabal dir = - FilePathGlob + RootedGlob (if isAbsolute dir then FilePathRoot root else FilePathRelative) ( foldr (\d -> GlobDir [Literal d]) @@ -1273,6 +1256,7 @@ fetchAndReadSourcePackages verbosity distDirLayout projectConfigShared + (fromFlag (projectConfigOfflineMode projectConfigBuildOnly)) [repo | ProjectPackageRemoteRepo repo <- pkgLocations] let pkgsNamed = @@ -1389,6 +1373,7 @@ syncAndReadSourcePackagesRemoteRepos :: Verbosity -> DistDirLayout -> ProjectConfigShared + -> Bool -> [SourceRepoList] -> Rebuild [PackageSpecifier (SourcePackage UnresolvedPkgLoc)] syncAndReadSourcePackagesRemoteRepos @@ -1397,6 +1382,7 @@ syncAndReadSourcePackagesRemoteRepos ProjectConfigShared { projectConfigProgPathExtra } + offlineMode repos = do repos' <- either reportSourceRepoProblems return $ @@ -1415,11 +1401,10 @@ syncAndReadSourcePackagesRemoteRepos | (repo, rloc, rtype, vcs) <- repos' ] - -- TODO: pass progPathExtra on to 'configureVCS' - let _progPathExtra = fromNubList projectConfigProgPathExtra + let progPathExtra = fromNubList projectConfigProgPathExtra getConfiguredVCS <- delayInitSharedResources $ \repoType -> let vcs = Map.findWithDefault (error $ "Unknown VCS: " ++ prettyShow repoType) repoType knownVCSs - in configureVCS verbosity {-progPathExtra-} vcs + in configureVCS verbosity progPathExtra vcs concat <$> sequenceA @@ -1452,12 +1437,18 @@ syncAndReadSourcePackagesRemoteRepos -- For syncing we don't care about different 'SourceRepo' values that -- are just different subdirs in the same repo. - syncSourceRepos - verbosity - vcs - [ (repo, repoPath) - | (repo, _, repoPath) <- repoGroupWithPaths - ] + -- Do not sync source repositories when `--offline` flag applied. + if not offlineMode + then + syncSourceRepos + verbosity + vcs + [ (repo, repoPath) + | (repo, _, repoPath) <- repoGroupWithPaths + ] + else do + liftIO . warn verbosity $ "--offline was specified, skipping sync of repositories:" + liftIO . for_ repoGroupWithPaths $ \(repo, _, _) -> warn verbosity $ srpLocation repo -- Run post-checkout-command if it is specified for_ repoGroupWithPaths $ \(repo, _, repoPath) -> diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index 026a8ae93bc..5bef482a481 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -728,6 +728,7 @@ convertLegacyPerPackageFlags , configDebugInfo = packageConfigDebugInfo , configDumpBuildInfo = packageConfigDumpBuildInfo , configRelocatable = packageConfigRelocatable + , configCoverageFor = _ } = configFlags packageConfigProgramPaths = MapLast (Map.fromList configProgramPaths) packageConfigProgramArgs = MapMappend (Map.fromListWith (++) configProgramArgs) @@ -1038,6 +1039,7 @@ convertToLegacyAllPackageConfig , configUseResponseFiles = mempty , configDumpBuildInfo = mempty , configAllowDependingOnPrivateLibs = mempty + , configCoverageFor = mempty } haddockFlags = @@ -1114,6 +1116,7 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , configUseResponseFiles = mempty , configDumpBuildInfo = packageConfigDumpBuildInfo , configAllowDependingOnPrivateLibs = mempty + , configCoverageFor = mempty } installFlags = diff --git a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs index 18ea8cf826c..c3fa259b41e 100644 --- a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs +++ b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs @@ -3,6 +3,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE ViewPatterns #-} -- | This module deals with building and incrementally rebuilding a collection -- of packages. It is what backs the @cabal build@ and @configure@ commands, @@ -230,12 +231,15 @@ data CurrentCommand = InstallCommand | HaddockCommand | BuildCommand | ReplComma deriving (Show, Eq) -- | This holds the context of a project prior to solving: the content of the --- @cabal.project@ and all the local package @.cabal@ files. +-- @cabal.project@, @cabal/config@ and all the local package @.cabal@ files. data ProjectBaseContext = ProjectBaseContext { distDirLayout :: DistDirLayout , cabalDirLayout :: CabalDirLayout , projectConfig :: ProjectConfig , localPackages :: [PackageSpecifier UnresolvedSourcePackage] + -- ^ Note: these are all the packages mentioned in the project configuration. + -- Whether or not they will be considered local to the project will be decided + -- by `shouldBeLocal` in ProjectPlanning. , buildSettings :: BuildTimeSettings , currentCommand :: CurrentCommand , installedPackages :: Maybe InstalledPackageIndex @@ -291,6 +295,7 @@ establishProjectBaseContextWithRoot verbosity cliConfig projectRoot currentComma sequenceA $ makeAbsolute <$> Setup.flagToMaybe projectConfigStoreDir + cabalDirLayout <- mkCabalDirLayout mstoreDir mlogsDir let buildSettings = @@ -642,7 +647,7 @@ resolveTargets checkTarget :: TargetSelector -> Either (TargetProblem err) [(UnitId, ComponentTarget)] -- We can ask to build any whole package, project-local or a dependency - checkTarget bt@(TargetPackage _ [pkgid] mkfilter) + checkTarget bt@(TargetPackage _ (ordNub -> [pkgid]) mkfilter) | Just ats <- fmap (maybe id filterTargetsKind mkfilter) $ Map.lookup pkgid availableTargetsByPackageId = @@ -1039,6 +1044,7 @@ printPlan showConfigureFlags elab = let fullConfigureFlags = setupHsConfigureFlags + elaboratedPlan (ReadyPackage elab) elaboratedShared verbosity diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index 44372967fdb..6344249a8a6 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -1,16 +1,41 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE NoMonoLocalBinds #-} --- | Planning how to build everything in a project. +-- | +-- /Elaborated: worked out with great care and nicety of detail; executed with great minuteness: elaborate preparations; elaborate care./ +-- +-- In this module we construct an install plan that includes all the information needed to execute it. +-- +-- Building a project is therefore split into two phases: +-- +-- 1. The construction of the install plan (which as far as possible should be pure), done here. +-- 2. The execution of the plan, done in "ProjectBuilding" +-- +-- To achieve this we need a representation of this fully elaborated install plan; this representation +-- consists of two parts: +-- +-- * A 'ElaboratedInstallPlan'. This is a 'GenericInstallPlan' with a +-- representation of source packages that includes a lot more detail about +-- that package's individual configuration +-- +-- * A 'ElaboratedSharedConfig'. Some package configuration is the same for +-- every package in a plan. Rather than duplicate that info every entry in +-- the 'GenericInstallPlan' we keep that separately. +-- +-- The division between the shared and per-package config is not set in stone +-- for all time. For example if we wanted to generalise the install plan to +-- describe a situation where we want to build some packages with GHC and some +-- with GHCJS then the platform and compiler would no longer be shared between +-- all packages but would have to be per-package (probably with some sanity +-- condition on the graph structure). module Distribution.Client.ProjectPlanning - ( -- * elaborated install plan types + ( -- * Types for the elaborated install plan ElaboratedInstallPlan , ElaboratedConfiguredPackage (..) , ElaboratedPlanPackage @@ -19,8 +44,11 @@ module Distribution.Client.ProjectPlanning , BuildStyle (..) , CabalFileText - -- * Producing the elaborated install plan + -- * Reading the project configuration + -- $readingTheProjectConfiguration , rebuildProjectConfig + + -- * Producing the elaborated install plan , rebuildInstallPlan -- * Build targets @@ -72,97 +100,77 @@ module Distribution.Client.ProjectPlanning import Distribution.Client.Compat.Prelude import Prelude () +import Distribution.Client.Config +import Distribution.Client.Dependency +import Distribution.Client.DistDirLayout +import Distribution.Client.FetchUtils import Distribution.Client.HashValue import Distribution.Client.HttpUtils +import Distribution.Client.JobControl import Distribution.Client.PackageHash import Distribution.Client.ProjectConfig import Distribution.Client.ProjectConfig.Legacy import Distribution.Client.ProjectPlanOutput +import Distribution.Client.ProjectPlanning.SetupPolicy + ( NonSetupLibDepSolverPlanPackage (..) + , mkDefaultSetupDeps + , packageSetupScriptSpecVersion + , packageSetupScriptStyle + ) import Distribution.Client.ProjectPlanning.Types as Ty import Distribution.Client.RebuildMonad -import Distribution.Client.Store - -import Distribution.Client.Config -import Distribution.Client.Dependency -import Distribution.Client.DistDirLayout -import Distribution.Client.FetchUtils -import qualified Distribution.Client.IndexUtils as IndexUtils -import qualified Distribution.Client.InstallPlan as InstallPlan -import Distribution.Client.JobControl import Distribution.Client.Setup hiding (cabalVersion, packageName) import Distribution.Client.SetupWrapper -import qualified Distribution.Client.SolverInstallPlan as SolverInstallPlan +import Distribution.Client.Store import Distribution.Client.Targets (userToPackageConstraint) import Distribution.Client.Types import Distribution.Client.Utils (incVersion) + +import qualified Distribution.Client.BuildReports.Storage as BuildReports +import qualified Distribution.Client.IndexUtils as IndexUtils +import qualified Distribution.Client.InstallPlan as InstallPlan +import qualified Distribution.Client.SolverInstallPlan as SolverInstallPlan + +import Distribution.CabalSpecVersion import Distribution.Utils.LogProgress import Distribution.Utils.MapAccum import Distribution.Utils.NubList -import qualified Hackage.Security.Client as Sec -import qualified Distribution.Client.BuildReports.Storage as BuildReports - ( fromPlanningFailure - , storeLocal - ) +import qualified Hackage.Security.Client as Sec -import Distribution.Solver.Types.ComponentDeps (ComponentDeps) -import qualified Distribution.Solver.Types.ComponentDeps as CD import Distribution.Solver.Types.ConstraintSource import Distribution.Solver.Types.InstSolverPackage import Distribution.Solver.Types.LabeledPackageConstraint import Distribution.Solver.Types.OptionalStanza import Distribution.Solver.Types.PkgConfigDb -import Distribution.Solver.Types.ResolverPackage import Distribution.Solver.Types.Settings import Distribution.Solver.Types.SolverId import Distribution.Solver.Types.SolverPackage import Distribution.Solver.Types.SourcePackage -import Distribution.CabalSpecVersion - --- TODO: [code cleanup] eliminate --- TODO: [code cleanup] eliminate - -import qualified Distribution.InstalledPackageInfo as IPI import Distribution.ModuleName import Distribution.Package -import qualified Distribution.PackageDescription as Cabal -import qualified Distribution.PackageDescription as PD -import qualified Distribution.PackageDescription.Configuration as PD import Distribution.Simple.Compiler -import qualified Distribution.Simple.Configure as Cabal -import qualified Distribution.Simple.GHC as GHC -import qualified Distribution.Simple.GHCJS as GHCJS -import qualified Distribution.Simple.InstallDirs as InstallDirs +import Distribution.Simple.Flag import Distribution.Simple.LocalBuildInfo ( Component (..) , componentBuildInfo , componentName , pkgComponents ) -import qualified Distribution.Simple.LocalBuildInfo as Cabal import Distribution.Simple.PackageIndex (InstalledPackageIndex) import Distribution.Simple.Program import Distribution.Simple.Program.Db import Distribution.Simple.Program.Find -import Distribution.Simple.Setup - ( Flag (..) - , flagToList - , flagToMaybe - , fromFlagOrDefault - , toFlag - ) -import qualified Distribution.Simple.Setup as Cabal import Distribution.System + import Distribution.Types.AnnotatedId +import Distribution.Types.ComponentInclude import Distribution.Types.ComponentName import Distribution.Types.DumpBuildInfo - ( DumpBuildInfo (..) - ) import Distribution.Types.GivenComponent - ( GivenComponent (GivenComponent) - ) import Distribution.Types.LibraryName +import qualified Distribution.Types.LocalBuildConfig as LBC import Distribution.Types.PackageVersionConstraint import Distribution.Types.PkgconfigDependency import Distribution.Types.UnqualComponentName @@ -173,12 +181,21 @@ import Distribution.Backpack.ConfiguredComponent import Distribution.Backpack.FullUnitId import Distribution.Backpack.LinkedComponent import Distribution.Backpack.ModuleShape -import Distribution.Types.ComponentInclude import Distribution.Simple.Utils import Distribution.Version -import Distribution.Compat.Graph (IsNode (..)) +import qualified Distribution.InstalledPackageInfo as IPI +import qualified Distribution.PackageDescription as PD +import qualified Distribution.PackageDescription.Configuration as PD +import qualified Distribution.Simple.Configure as Cabal +import qualified Distribution.Simple.GHC as GHC +import qualified Distribution.Simple.GHCJS as GHCJS +import qualified Distribution.Simple.InstallDirs as InstallDirs +import qualified Distribution.Simple.LocalBuildInfo as Cabal +import qualified Distribution.Simple.Setup as Cabal +import qualified Distribution.Solver.Types.ComponentDeps as CD + import qualified Distribution.Compat.Graph as Graph import Control.Exception (assert) @@ -195,61 +212,6 @@ import System.FilePath import Text.PrettyPrint (colon, comma, fsep, hang, punctuate, quotes, text, vcat, ($$)) import qualified Text.PrettyPrint as Disp ------------------------------------------------------------------------------- - --- * Elaborated install plan - ------------------------------------------------------------------------------- - --- "Elaborated" -- worked out with great care and nicety of detail; --- executed with great minuteness: elaborate preparations; --- elaborate care. --- --- So here's the idea: --- --- Rather than a miscellaneous collection of 'ConfigFlags', 'InstallFlags' etc --- all passed in as separate args and which are then further selected, --- transformed etc during the execution of the build. Instead we construct --- an elaborated install plan that includes everything we will need, and then --- during the execution of the plan we do as little transformation of this --- info as possible. --- --- So we're trying to split the work into two phases: construction of the --- elaborated install plan (which as far as possible should be pure) and --- then simple execution of that plan without any smarts, just doing what the --- plan says to do. --- --- So that means we need a representation of this fully elaborated install --- plan. The representation consists of two parts: --- - --- * A 'ElaboratedInstallPlan'. This is a 'GenericInstallPlan' with a - --- representation of source packages that includes a lot more detail about --- that package's individual configuration --- - --- * A 'ElaboratedSharedConfig'. Some package configuration is the same for - --- every package in a plan. Rather than duplicate that info every entry in --- the 'GenericInstallPlan' we keep that separately. --- --- The division between the shared and per-package config is /not set in stone --- for all time/. For example if we wanted to generalise the install plan to --- describe a situation where we want to build some packages with GHC and some --- with GHCJS then the platform and compiler would no longer be shared between --- all packages but would have to be per-package (probably with some sanity --- condition on the graph structure). --- - --- Refer to ProjectPlanning.Types for details of these important types: - --- type ElaboratedInstallPlan = ... --- type ElaboratedPlanPackage = ... --- data ElaboratedSharedConfig = ... --- data ElaboratedConfiguredPackage = ... --- data BuildStyle = - -- | Check that an 'ElaboratedConfiguredPackage' actually makes -- sense under some 'ElaboratedSharedConfig'. sanityCheckElaboratedConfiguredPackage @@ -258,7 +220,7 @@ sanityCheckElaboratedConfiguredPackage -> a -> a sanityCheckElaboratedConfiguredPackage - _sharedConfig + sharedConfig elab@ElaboratedConfiguredPackage{..} = ( case elabPkgOrComp of ElabPackage pkg -> sanityCheckElaboratedPackage elab pkg @@ -273,10 +235,12 @@ sanityCheckElaboratedConfiguredPackage -- 'installedPackageId' we assigned is consistent with -- the 'hashedInstalledPackageId' we would compute from -- the elaborated configured package - -- . assert (isInplaceBuildStyle elabBuildStyle || - -- elabComponentId == hashedInstalledPackageId - -- (packageHashInputs sharedConfig elab)) - + . assert + ( isInplaceBuildStyle elabBuildStyle + || elabComponentId + == hashedInstalledPackageId + (packageHashInputs sharedConfig elab) + ) -- the stanzas explicitly disabled should not be available . assert ( optStanzaSetNull $ @@ -331,32 +295,28 @@ sanityCheckElaboratedPackage `optStanzaSetIsSubset` pkgStanzasEnabled ) --- Note [reading project configuration] +-- $readingTheProjectConfiguration -- -- The project configuration is assembled into a ProjectConfig as follows: -- --- CLI arguments are converted using commandLineFlagsToProjectConfig in the --- v2 command entrypoints and passed to establishProjectBaseContext which --- then calls rebuildProjectConfig. --- --- rebuildProjectConfig then calls readProjectConfig to read the project --- files. Because of conditionals, this output is in the form of a --- ProjectConfigSkeleton and will be resolved by rebuildProjectConfig using --- instantiateProjectConfigSkeletonFetchingCompiler. +-- CLI arguments are converted using "commandLineFlagsToProjectConfig" in the +-- v2 command entrypoints and passed to "establishProjectBaseContext" which +-- then calls "rebuildProjectConfig". -- --- readProjectConfig also loads the global configuration, which is read with --- loadConfig and convertd to a ProjectConfig with convertLegacyGlobalConfig. +-- "rebuildProjectConfig" then calls "readProjectConfig" to read the project +-- files. Due to the presence of conditionals, this output is in the form of a +-- "ProjectConfigSkeleton" and will be resolved by "rebuildProjectConfig" using +-- "instantiateProjectConfigSkeletonFetchingCompiler". -- - --- * Important * - +-- "readProjectConfig" also loads the global configuration, which is read with +-- "loadConfig" and convertd to a "ProjectConfig" with "convertLegacyGlobalConfig". -- --- You can notice how some project config options are needed to read the --- project config! This is evident by the fact that rebuildProjectConfig --- takes HttpTransport and DistDirLayout as parameters. Two arguments are --- infact determined from the CLI alone (in establishProjectBaseContext). +-- *Important:* You can notice how some project config options are needed to read the +-- project config! This is evident by the fact that "rebuildProjectConfig" +-- takes "HttpTransport" and "DistDirLayout" as parameters. Two arguments are +-- infact determined from the CLI alone (in "establishProjectBaseContext"). -- Consequently, project files (including global configuration) cannot --- affect those parameters. +-- affect those parameters! -- -- Furthermore, the project configuration can specify a compiler to use, -- which we need to resolve the conditionals in the project configuration! @@ -449,6 +409,8 @@ rebuildProjectConfig -- Look for all the cabal packages in the project -- some of which may be local src dirs, tarballs etc -- + -- NOTE: These are all packages mentioned in the project configuration. + -- Whether or not they will be considered local to the project will be decided by `shouldBeLocal`. phaseReadLocalPackages :: ProjectConfig -> Rebuild [PackageSpecifier UnresolvedSourcePackage] @@ -509,13 +471,15 @@ configureCompiler ) $ do liftIO $ info verbosity "Compiler settings changed, reconfiguring..." - result@(_, _, progdb') <- + progdb <- liftIO $ prependProgramSearchPath verbosity (fromNubList packageConfigProgramPathExtra) defaultProgramDb + let progdb' = userSpecifyPaths (Map.toList (getMapLast packageConfigProgramPaths)) progdb + result@(_, _, progdb'') <- liftIO $ Cabal.configCompilerEx hcFlavor hcPath hcPkg - progdb + progdb' verbosity -- Note that we added the user-supplied program locations and args @@ -524,22 +488,13 @@ configureCompiler -- the compiler will configure (and it does vary between compilers). -- We do know however that the compiler will only configure the -- programs it cares about, and those are the ones we monitor here. - monitorFiles (programsMonitorFiles progdb') + monitorFiles (programsMonitorFiles progdb'') return result where hcFlavor = flagToMaybe projectConfigHcFlavor hcPath = flagToMaybe projectConfigHcPath hcPkg = flagToMaybe projectConfigHcPkg - progdb = - userSpecifyPaths (Map.toList (getMapLast packageConfigProgramPaths)) - . modifyProgramSearchPath - ( [ ProgramSearchPathDir dir - | dir <- fromNubList packageConfigProgramPathExtra - ] - ++ - ) - $ defaultProgramDb ------------------------------------------------------------------------------ @@ -754,15 +709,15 @@ rebuildInstallPlan where corePackageDbs :: [PackageDB] corePackageDbs = - applyPackageDbFlags - [GlobalPackageDB] - (projectConfigPackageDBs projectConfigShared) + Cabal.interpretPackageDbFlags False (projectConfigPackageDBs projectConfigShared) + withRepoCtx :: (RepoContext -> IO a) -> IO a withRepoCtx = projectConfigWithSolverRepoContext verbosity projectConfigShared projectConfigBuildOnly + solverSettings = resolveSolverSettings projectConfig logMsg message rest = debugNoWrap verbosity message >> rest @@ -861,6 +816,7 @@ rebuildInstallPlan liftIO $ debugNoWrap verbosity (showElaboratedInstallPlan instantiatedPlan) return (instantiatedPlan, elaboratedShared) where + withRepoCtx :: (RepoContext -> IO a) -> IO a withRepoCtx = projectConfigWithSolverRepoContext verbosity @@ -898,7 +854,7 @@ rebuildInstallPlan -> Rebuild ElaboratedInstallPlan phaseImprovePlan elaboratedPlan elaboratedShared = do liftIO $ debug verbosity "Improving the install plan..." - storePkgIdSet <- getStoreEntries cabalStoreDirLayout compid + storePkgIdSet <- getStoreEntries cabalStoreDirLayout compiler let improvedPlan = improveInstallPlanWithInstalledPackages storePkgIdSet @@ -910,7 +866,7 @@ rebuildInstallPlan -- matches up as expected, e.g. no dangling deps, files deleted. return improvedPlan where - compid = compilerId (pkgConfigCompiler elaboratedShared) + compiler = pkgConfigCompiler elaboratedShared -- | If a 'PackageSpecifier' refers to a single package, return Just that -- package. @@ -1219,13 +1175,6 @@ getPackageSourceHashes verbosity withRepoCtx solverPlan = do hashesFromRepoMetadata <> hashesFromTarballFiles --- | Append the given package databases to an existing PackageDBStack. --- A @Nothing@ entry will clear everything before it. -applyPackageDbFlags :: PackageDBStack -> [Maybe PackageDB] -> PackageDBStack -applyPackageDbFlags dbs' [] = dbs' -applyPackageDbFlags _ (Nothing : dbs) = applyPackageDbFlags [] dbs -applyPackageDbFlags dbs' (Just db : dbs) = applyPackageDbFlags (dbs' ++ [db]) dbs - -- ------------------------------------------------------------ -- * Installation planning @@ -1298,7 +1247,7 @@ planPackages . removeLowerBounds solverSettingAllowOlder . removeUpperBounds solverSettingAllowNewer . addDefaultSetupDependencies - ( defaultSetupDeps comp platform + ( mkDefaultSetupDeps comp platform . PD.packageDescription . srcpkgDescription ) @@ -1655,13 +1604,13 @@ elaborateInstallPlan buildComponent (Map.empty, Map.empty, Map.empty) (map fst src_comps) - let not_per_component_reasons = why_not_per_component src_comps - if null not_per_component_reasons - then return comps - else do - checkPerPackageOk comps not_per_component_reasons + let whyNotPerComp = why_not_per_component src_comps + case NE.nonEmpty whyNotPerComp of + Nothing -> return comps + Just notPerCompReasons -> do + checkPerPackageOk comps notPerCompReasons return - [ elaborateSolverToPackage spkg g $ + [ elaborateSolverToPackage notPerCompReasons spkg g $ comps ++ maybeToList setupComponent ] Left cns -> @@ -1673,9 +1622,8 @@ elaborateInstallPlan where -- You are eligible to per-component build if this list is empty why_not_per_component g = - cuz_buildtype ++ cuz_spec ++ cuz_length ++ cuz_flag ++ cuz_coverage + cuz_buildtype ++ cuz_spec ++ cuz_length ++ cuz_flag where - cuz reason = [text reason] -- We have to disable per-component for now with -- Configure-type scripts in order to prevent parallel -- invocation of the same `./configure` script. @@ -1688,34 +1636,29 @@ elaborateInstallPlan -- Once you've implemented this, swap it for the code below. cuz_buildtype = case PD.buildType (elabPkgDescription elab0) of - PD.Configure -> cuz "build-type is Configure" - PD.Custom -> cuz "build-type is Custom" + PD.Configure -> [CuzBuildType CuzConfigureBuildType] + PD.Custom -> [CuzBuildType CuzCustomBuildType] + PD.Make -> [CuzBuildType CuzMakeBuildType] _ -> [] -- cabal-format versions prior to 1.8 have different build-depends semantics -- for now it's easier to just fallback to legacy-mode when specVersion < 1.8 -- see, https://github.com/haskell/cabal/issues/4121 cuz_spec | PD.specVersion pd >= CabalSpecV1_8 = [] - | otherwise = cuz "cabal-version is less than 1.8" + | otherwise = [CuzCabalSpecVersion] -- In the odd corner case that a package has no components at all -- then keep it as a whole package, since otherwise it turns into -- 0 component graph nodes and effectively vanishes. We want to -- keep it around at least for error reporting purposes. cuz_length | length g > 0 = [] - | otherwise = cuz "there are no buildable components" + | otherwise = [CuzNoBuildableComponents] -- For ease of testing, we let per-component builds be toggled -- at the top level cuz_flag | fromFlagOrDefault True (projectConfigPerComponent sharedPackageConfig) = [] - | otherwise = cuz "you passed --disable-per-component" - -- Enabling program coverage introduces odd runtime dependencies - -- between components. - cuz_coverage - | fromFlagOrDefault False (packageConfigCoverage localPackagesConfig) = - cuz "program coverage is enabled" - | otherwise = [] + | otherwise = [CuzDisablePerComponent] -- \| Sometimes a package may make use of features which are only -- supported in per-package mode. If this is the case, we should @@ -1727,7 +1670,7 @@ elaborateInstallPlan dieProgress $ text "Internal libraries only supported with per-component builds." $$ text "Per-component builds were disabled because" - <+> fsep (punctuate comma reasons) + <+> fsep (punctuate comma $ map (text . whyNotPerComponent) $ toList reasons) -- TODO: Maybe exclude Backpack too elab0 = elaborateSolverToCommon spkg @@ -1755,15 +1698,23 @@ elaborateInstallPlan where compSolverName = CD.ComponentSetup compComponentName = Nothing + dep_pkgs = elaborateLibSolverId mapDep =<< CD.setupDeps deps0 + compLibDependencies = -- MP: No idea what this function does map (\cid -> (configuredId cid, False)) dep_pkgs compLinkedLibDependencies = notImpl "compLinkedLibDependencies" compOrderLibDependencies = notImpl "compOrderLibDependencies" + -- Not supported: + compExeDependencies :: [a] compExeDependencies = [] + + compExeDependencyPaths :: [a] compExeDependencyPaths = [] + + compPkgConfigDependencies :: [a] compPkgConfigDependencies = [] notImpl f = @@ -2014,11 +1965,13 @@ elaborateInstallPlan <$> executables elaborateSolverToPackage - :: SolverPackage UnresolvedPkgLoc + :: NE.NonEmpty NotPerComponentReason + -> SolverPackage UnresolvedPkgLoc -> ComponentsGraph -> [ElaboratedConfiguredPackage] -> ElaboratedConfiguredPackage elaborateSolverToPackage + pkgWhyNotPerComponent pkg@( SolverPackage (SourcePackage pkgid _gpd _srcloc _descOverride) _flags @@ -2033,7 +1986,9 @@ elaborateInstallPlan -- of the other fields of the elaboratedPackage. elab where - elab0@ElaboratedConfiguredPackage{..} = elaborateSolverToCommon pkg + elab0@ElaboratedConfiguredPackage{..} = + elaborateSolverToCommon pkg + elab1 = elab0 { elabUnitId = newSimpleUnitId pkgInstalledId @@ -2042,6 +1997,7 @@ elaborateInstallPlan , elabPkgOrComp = ElabPackage $ ElaboratedPackage{..} , elabModuleShape = modShape } + elab = elab1 { elabInstallDirs = @@ -2071,6 +2027,8 @@ elaborateInstallPlan -- correspond to anything real anymore. isExt confid = confSrcId confid /= pkgid filterExt = filter isExt + + filterExt' :: [(ConfiguredId, a)] -> [(ConfiguredId, a)] filterExt' = filter (isExt . fst) pkgLibDependencies = @@ -2079,6 +2037,7 @@ elaborateInstallPlan buildComponentDeps (filterExt . compExeDependencies) pkgExeDependencyPaths = buildComponentDeps (filterExt' . compExeDependencyPaths) + -- TODO: Why is this flat? pkgPkgConfigDependencies = CD.flatDeps $ buildComponentDeps compPkgConfigDependencies @@ -2095,13 +2054,11 @@ elaborateInstallPlan is_lib (CLibName _) = True is_lib _ = False + buildComponentDeps :: Monoid a => (ElaboratedComponent -> a) -> CD.ComponentDeps a buildComponentDeps f = CD.fromList [ (compSolverName comp, f comp) - | ElaboratedConfiguredPackage - { elabPkgOrComp = ElabComponent comp - } <- - comps + | ElaboratedConfiguredPackage{elabPkgOrComp = ElabComponent comp} <- comps ] -- NB: This is not the final setting of 'pkgStanzasEnabled'. @@ -2152,7 +2109,7 @@ elaborateInstallPlan elabFlagAssignment = flags elabFlagDefaults = PD.mkFlagAssignment - [ (Cabal.flagName flag, Cabal.flagDefault flag) + [ (PD.flagName flag, PD.flagDefault flag) | flag <- PD.genPackageFlags gdesc ] @@ -2222,14 +2179,28 @@ elaborateInstallPlan elabPkgDescriptionOverride = descOverride - elabVanillaLib = perPkgOptionFlag pkgid True packageConfigVanillaLib -- TODO: [required feature]: also needs to be handled recursively - elabSharedLib = pkgid `Set.member` pkgsUseSharedLibrary - elabStaticLib = perPkgOptionFlag pkgid False packageConfigStaticLib - elabDynExe = perPkgOptionFlag pkgid False packageConfigDynExe - elabFullyStaticExe = perPkgOptionFlag pkgid False packageConfigFullyStaticExe - elabGHCiLib = perPkgOptionFlag pkgid False packageConfigGHCiLib -- TODO: [required feature] needs to default to enabled on windows still - elabProfExe = perPkgOptionFlag pkgid False packageConfigProf - elabProfLib = pkgid `Set.member` pkgsUseProfilingLibrary + elabBuildOptions = + LBC.BuildOptions + { withVanillaLib = perPkgOptionFlag pkgid True packageConfigVanillaLib -- TODO: [required feature]: also needs to be handled recursively + , withSharedLib = pkgid `Set.member` pkgsUseSharedLibrary + , withStaticLib = perPkgOptionFlag pkgid False packageConfigStaticLib + , withDynExe = perPkgOptionFlag pkgid False packageConfigDynExe + , withFullyStaticExe = perPkgOptionFlag pkgid False packageConfigFullyStaticExe + , withGHCiLib = perPkgOptionFlag pkgid False packageConfigGHCiLib -- TODO: [required feature] needs to default to enabled on windows still + , withProfExe = perPkgOptionFlag pkgid False packageConfigProf + , withProfLib = pkgid `Set.member` pkgsUseProfilingLibrary + , exeCoverage = perPkgOptionFlag pkgid False packageConfigCoverage + , libCoverage = perPkgOptionFlag pkgid False packageConfigCoverage + , withOptimization = perPkgOptionFlag pkgid NormalOptimisation packageConfigOptimization + , splitObjs = perPkgOptionFlag pkgid False packageConfigSplitObjs + , splitSections = perPkgOptionFlag pkgid False packageConfigSplitSections + , stripLibs = perPkgOptionFlag pkgid False packageConfigStripLibs + , stripExes = perPkgOptionFlag pkgid False packageConfigStripExes + , withDebugInfo = perPkgOptionFlag pkgid NoDebugInfo packageConfigDebugInfo + , relocatable = perPkgOptionFlag pkgid False packageConfigRelocatable + , withProfLibDetail = elabProfExeDetail + , withProfExeDetail = elabProfLibDetail + } ( elabProfExeDetail , elabProfLibDetail @@ -2239,14 +2210,7 @@ elaborateInstallPlan ProfDetailDefault packageConfigProfDetail packageConfigProfLibDetail - elabCoverage = perPkgOptionFlag pkgid False packageConfigCoverage - - elabOptimization = perPkgOptionFlag pkgid NormalOptimisation packageConfigOptimization - elabSplitObjs = perPkgOptionFlag pkgid False packageConfigSplitObjs - elabSplitSections = perPkgOptionFlag pkgid False packageConfigSplitSections - elabStripLibs = perPkgOptionFlag pkgid False packageConfigStripLibs - elabStripExes = perPkgOptionFlag pkgid False packageConfigStripExes - elabDebugInfo = perPkgOptionFlag pkgid NoDebugInfo packageConfigDebugInfo + elabDumpBuildInfo = perPkgOptionFlag pkgid NoDumpBuildInfo packageConfigDumpBuildInfo -- Combine the configured compiler prog settings with the user-supplied @@ -2348,10 +2312,7 @@ elaborateInstallPlan corePackageDbs ++ [distPackageDB (compilerId compiler)] - corePackageDbs = - applyPackageDbFlags - (storePackageDBStack (compilerId compiler)) - (projectConfigPackageDBs sharedPackageConfig) + corePackageDbs = storePackageDBStack compiler (projectConfigPackageDBs sharedPackageConfig) -- For this local build policy, every package that lives in a local source -- dir (as opposed to a tarball), or depends on such a package, will be @@ -2575,22 +2536,6 @@ binDirectories layout config package = case elabBuildStyle package of distBuildDirectory layout (elabDistDirParams config package) "build" --- | A newtype for 'SolverInstallPlan.SolverPlanPackage' for which the --- dependency graph considers only dependencies on libraries which are --- NOT from setup dependencies. Used to compute the set --- of packages needed for profiling and dynamic libraries. -newtype NonSetupLibDepSolverPlanPackage = NonSetupLibDepSolverPlanPackage - {unNonSetupLibDepSolverPlanPackage :: SolverInstallPlan.SolverPlanPackage} - -instance Package NonSetupLibDepSolverPlanPackage where - packageId = packageId . unNonSetupLibDepSolverPlanPackage - -instance IsNode NonSetupLibDepSolverPlanPackage where - type Key NonSetupLibDepSolverPlanPackage = SolverId - nodeKey = nodeKey . unNonSetupLibDepSolverPlanPackage - nodeNeighbors (NonSetupLibDepSolverPlanPackage spkg) = - ordNub $ CD.nonSetupDeps (resolverPackageLibDeps spkg) - type InstS = Map UnitId ElaboratedPlanPackage type InstM a = State InstS a @@ -3207,11 +3152,11 @@ instance Package PrunedPackage where packageId (PrunedPackage elab _) = packageId elab instance HasUnitId PrunedPackage where - installedUnitId = nodeKey + installedUnitId = Graph.nodeKey -instance IsNode PrunedPackage where +instance Graph.IsNode PrunedPackage where type Key PrunedPackage = UnitId - nodeKey (PrunedPackage elab _) = nodeKey elab + nodeKey (PrunedPackage elab _) = Graph.nodeKey elab nodeNeighbors (PrunedPackage _ deps) = deps fromPrunedPackage :: PrunedPackage -> ElaboratedConfiguredPackage @@ -3266,9 +3211,6 @@ setRootTargets targetAction perPkgTargetsMap = | isSubLibComponentTarget tgt = elab{elabHaddockInternal = True} | otherwise = elab -minVersionReplFlagFile :: Version -minVersionReplFlagFile = mkVersion [3, 9] - -- | Assuming we have previously set the root build targets (i.e. the user -- targets but not rev deps yet), the first pruning pass does two things: -- @@ -3283,7 +3225,7 @@ pruneInstallPlanPass1 pruneInstallPlanPass1 pkgs -- if there are repl targets, we need to do a bit more work -- See Note [Pruning for Multi Repl] - | anyReplTarget = final_final_graph + | anyMultiReplTarget = graph_with_repl_targets -- otherwise we'll do less | otherwise = pruned_packages where @@ -3293,9 +3235,7 @@ pruneInstallPlanPass1 pkgs prune :: ElaboratedConfiguredPackage -> PrunedPackage prune elab = PrunedPackage elab' (pruneOptionalDependencies elab') where - elab' = - setDocumentation $ - addOptionalStanzas elab + elab' = addOptionalStanzas elab graph = Graph.fromDistinctList pkgs' @@ -3309,10 +3249,11 @@ pruneInstallPlanPass1 pkgs closed_graph :: Graph.Graph ElaboratedPlanPackage closed_graph = Graph.fromDistinctList pruned_packages - -- whether any package has repl targets enabled. - anyReplTarget :: Bool - anyReplTarget = any is_repl_gpp pkgs' + -- whether any package has repl targets enabled, and we need to use multi-repl. + anyMultiReplTarget :: Bool + anyMultiReplTarget = length repls > 1 where + repls = filter is_repl_gpp pkgs' is_repl_gpp (InstallPlan.Configured pkg) = is_repl_pp pkg is_repl_gpp _ = False @@ -3335,53 +3276,9 @@ pruneInstallPlanPass1 pkgs -- Add the repl target information to the ElaboratedPlanPackages graph_with_repl_targets - | anyReplTarget = map (mapConfiguredPackage add_repl_target) (Graph.toList closed_graph) + | anyMultiReplTarget = map (mapConfiguredPackage add_repl_target) (Graph.toList closed_graph) | otherwise = Graph.toList closed_graph - -- But check that all the InMemory targets have a new enough version of Cabal, - -- otherwise we will confuse Setup.hs by passing new arguments which it doesn't understand - -- later down the line. We try to remove just these edges, if it doesn't break the overall structure - -- then we just report to the user that their target will not be loaded for this reason. - - ( bad -- Nodes which we wanted to build InMemory but lack new enough version of Cabal - , _good -- Nodes we want to build in memory. - ) = partitionEithers (map go graph_with_repl_targets) - where - go :: ElaboratedPlanPackage -> Either UnitId ElaboratedPlanPackage - go (InstallPlan.Configured cp) - | BuildInplaceOnly InMemory <- elabBuildStyle cp - , elabSetupScriptCliVersion cp < minVersionReplFlagFile = - Left (elabUnitId cp) - go (InstallPlan.Configured c) = Right (InstallPlan.Configured c) - go c = Right c - - -- Now take the upwards closure from the bad nodes, and find the other `BuildInplaceOnly InMemory` packages that clobbers, - -- disables those and issue a warning to the user. Because we aren't going to be able to load those into memory as well - -- because the thing it depends on is not going to be in memory. - - disabled_repl_targets = - [ c | InstallPlan.Configured c <- fromMaybe [] $ Graph.revClosure (Graph.fromDistinctList graph_with_repl_targets) bad, BuildInplaceOnly InMemory <- [elabBuildStyle c] - ] - - remove_repl_target :: ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage - remove_repl_target ecp - | ecp `elem` disabled_repl_targets = - ecp - { elabReplTarget = [] - , elabBuildStyle = BuildInplaceOnly OnDisk - } - | otherwise = ecp - - final_graph_with_repl_targets = map (mapConfiguredPackage remove_repl_target) graph_with_repl_targets - - -- Now find what the new roots are after we have disabled things which we can't build (and the things above that) - new_roots :: [UnitId] - new_roots = mapMaybe find_root (map (mapConfiguredPackage prune) final_graph_with_repl_targets) - - -- Then take the final closure from these new roots to remove these things - -- TODO: Can probably just remove them directly in remove_repl_target. - final_final_graph = fromMaybe [] $ Graph.closure (Graph.fromDistinctList final_graph_with_repl_targets) new_roots - is_root :: PrunedPackage -> Maybe UnitId is_root (PrunedPackage elab _) = if not $ @@ -3444,24 +3341,6 @@ pruneInstallPlanPass1 pkgs <> optionalStanzasWithDepsAvailable availablePkgs elab pkg addOptionalStanzas elab = elab - setDocumentation :: ElaboratedConfiguredPackage -> ElaboratedConfiguredPackage - setDocumentation elab@ElaboratedConfiguredPackage{elabPkgOrComp = ElabComponent comp} = - elab - { elabBuildHaddocks = - elabBuildHaddocks elab && documentationEnabled (compSolverName comp) elab - } - where - documentationEnabled c = - case c of - CD.ComponentLib -> const True - CD.ComponentSubLib _ -> elabHaddockInternal - CD.ComponentFLib _ -> elabHaddockForeignLibs - CD.ComponentExe _ -> elabHaddockExecutables - CD.ComponentTest _ -> elabHaddockTestSuites - CD.ComponentBench _ -> elabHaddockBenchmarks - CD.ComponentSetup -> const False - setDocumentation elab = elab - -- Calculate package dependencies but cut out those needed only by -- optional stanzas that we've determined we will not enable. -- These pruned deps are not persisted in this pass since they're based on @@ -3526,13 +3405,6 @@ our roots (graph closure), and then from this closed graph, we calculate the reverse closure, which gives us all components that depend on 'roots'. Thus, the result is a list of components that we need to load into the repl to uphold the closure property. - -Further to this, we then check that all the enabled components are using a new enough -version of Cabal which understands the repl option to write the arguments to a file. - -If there is a package using a custom Setup.hs which is linked against a too old version -of Cabal then we need to disable that as otherwise we will end up passing unknown -arguments to `./Setup`. -} -- | Given a set of already installed packages @availablePkgs@, @@ -3614,18 +3486,28 @@ pruneInstallPlanPass2 pkgs = let stanzas = pkgStanzasEnabled pkg <> optionalStanzasWithDepsAvailable availablePkgs elab pkg + + keepNeeded :: CD.Component -> a -> Bool keepNeeded (CD.ComponentTest _) _ = TestStanzas `optStanzaSetMember` stanzas keepNeeded (CD.ComponentBench _) _ = BenchStanzas `optStanzaSetMember` stanzas keepNeeded _ _ = True in ElabPackage $ pkg - { pkgStanzasEnabled = stanzas - , pkgLibDependencies = CD.mapDeps (\_ -> map addInternal) $ CD.filterDeps keepNeeded (pkgLibDependencies pkg) - , pkgExeDependencies = CD.filterDeps keepNeeded (pkgExeDependencies pkg) - , pkgExeDependencyPaths = CD.filterDeps keepNeeded (pkgExeDependencyPaths pkg) + { pkgStanzasEnabled = + stanzas + , pkgLibDependencies = + CD.mapDeps (\_ -> map addInternal) $ + CD.filterDeps keepNeeded (pkgLibDependencies pkg) + , pkgExeDependencies = + CD.filterDeps keepNeeded (pkgExeDependencies pkg) + , pkgExeDependencyPaths = + CD.filterDeps keepNeeded (pkgExeDependencyPaths pkg) } - (ElabComponent comp) -> - ElabComponent $ comp{compLibDependencies = map addInternal (compLibDependencies comp)} + ElabComponent comp -> + ElabComponent $ + comp + { compLibDependencies = map addInternal (compLibDependencies comp) + } } where -- We initially assume that all the dependencies are external (hence the boolean is always @@ -3752,207 +3634,6 @@ newtype CannotPruneDependencies ] deriving (Show) ---------------------------- --- Setup.hs script policy --- - --- Handling for Setup.hs scripts is a bit tricky, part of it lives in the --- solver phase, and part in the elaboration phase. We keep the helper --- functions for both phases together here so at least you can see all of it --- in one place. --- --- There are four major cases for Setup.hs handling: --- --- 1. @build-type@ Custom with a @custom-setup@ section --- 2. @build-type@ Custom without a @custom-setup@ section --- 3. @build-type@ not Custom with @cabal-version > $our-cabal-version@ --- 4. @build-type@ not Custom with @cabal-version <= $our-cabal-version@ --- --- It's also worth noting that packages specifying @cabal-version: >= 1.23@ --- or later that have @build-type@ Custom will always have a @custom-setup@ --- section. Therefore in case 2, the specified @cabal-version@ will always be --- less than 1.23. --- --- In cases 1 and 2 we obviously have to build an external Setup.hs script, --- while in case 4 we can use the internal library API. --- --- TODO:In case 3 we should fail. We don't know how to talk to --- newer ./Setup.hs --- --- data SetupScriptStyle = ... -- see ProjectPlanning.Types - --- | Work out the 'SetupScriptStyle' given the package description. -packageSetupScriptStyle :: PD.PackageDescription -> SetupScriptStyle -packageSetupScriptStyle pkg - | buildType == PD.Custom - , Just setupbi <- PD.setupBuildInfo pkg -- does have a custom-setup stanza - , not (PD.defaultSetupDepends setupbi) -- but not one we added internally - = - SetupCustomExplicitDeps - | buildType == PD.Custom - , Just setupbi <- PD.setupBuildInfo pkg -- we get this case post-solver as - , PD.defaultSetupDepends setupbi -- the solver fills in the deps - = - SetupCustomImplicitDeps - | buildType == PD.Custom - , Nothing <- PD.setupBuildInfo pkg -- we get this case pre-solver - = - SetupCustomImplicitDeps - -- here we should fail. - | PD.specVersion pkg > cabalSpecLatest -- one cabal-install is built against - = - SetupNonCustomExternalLib - | otherwise = - SetupNonCustomInternalLib - where - buildType = PD.buildType pkg - --- | Part of our Setup.hs handling policy is implemented by getting the solver --- to work out setup dependencies for packages. The solver already handles --- packages that explicitly specify setup dependencies, but we can also tell --- the solver to treat other packages as if they had setup dependencies. --- That's what this function does, it gets called by the solver for all --- packages that don't already have setup dependencies. --- --- The dependencies we want to add is different for each 'SetupScriptStyle'. --- --- Note that adding default deps means these deps are actually /added/ to the --- packages that we get out of the solver in the 'SolverInstallPlan'. Making --- implicit setup deps explicit is a problem in the post-solver stages because --- we still need to distinguish the case of explicit and implicit setup deps. --- See 'rememberImplicitSetupDeps'. --- --- Note in addition to adding default setup deps, we also use --- 'addSetupCabalMinVersionConstraint' (in 'planPackages') to require --- @Cabal >= 1.20@ for Setup scripts. -defaultSetupDeps - :: Compiler - -> Platform - -> PD.PackageDescription - -> Maybe [Dependency] -defaultSetupDeps compiler platform pkg = - case packageSetupScriptStyle pkg of - -- For packages with build type custom that do not specify explicit - -- setup dependencies, we add a dependency on Cabal and a number - -- of other packages. - SetupCustomImplicitDeps -> - Just $ - [ Dependency depPkgname anyVersion mainLibSet - | depPkgname <- legacyCustomSetupPkgs compiler platform - ] - ++ [ Dependency cabalPkgname cabalConstraint mainLibSet - | packageName pkg /= cabalPkgname - ] - where - -- The Cabal dep is slightly special: - -- \* We omit the dep for the Cabal lib itself, since it bootstraps. - -- \* We constrain it to be < 1.25 - -- - -- Note: we also add a global constraint to require Cabal >= 1.20 - -- for Setup scripts (see use addSetupCabalMinVersionConstraint). - -- - cabalConstraint = - orLaterVersion (csvToVersion (PD.specVersion pkg)) - `intersectVersionRanges` earlierVersion cabalCompatMaxVer - -- The idea here is that at some point we will make significant - -- breaking changes to the Cabal API that Setup.hs scripts use. - -- So for old custom Setup scripts that do not specify explicit - -- constraints, we constrain them to use a compatible Cabal version. - cabalCompatMaxVer = mkVersion [1, 25] - - -- For other build types (like Simple) if we still need to compile an - -- external Setup.hs, it'll be one of the simple ones that only depends - -- on Cabal and base. - SetupNonCustomExternalLib -> - Just - [ Dependency cabalPkgname cabalConstraint mainLibSet - , Dependency basePkgname anyVersion mainLibSet - ] - where - cabalConstraint = orLaterVersion (csvToVersion (PD.specVersion pkg)) - - -- The internal setup wrapper method has no deps at all. - SetupNonCustomInternalLib -> Just [] - -- This case gets ruled out by the caller, planPackages, see the note - -- above in the SetupCustomImplicitDeps case. - SetupCustomExplicitDeps -> - error $ - "defaultSetupDeps: called for a package with explicit " - ++ "setup deps: " - ++ prettyShow (packageId pkg) - where - -- we require one less - -- - -- This maps e.g. CabalSpecV3_0 to mkVersion [2,5] - csvToVersion :: CabalSpecVersion -> Version - csvToVersion = mkVersion . cabalSpecMinimumLibraryVersion - --- | Work out which version of the Cabal we will be using to talk to the --- Setup.hs interface for this package. --- --- This depends somewhat on the 'SetupScriptStyle' but most cases are a result --- of what the solver picked for us, based on the explicit setup deps or the --- ones added implicitly by 'defaultSetupDeps'. -packageSetupScriptSpecVersion - :: SetupScriptStyle - -> PD.PackageDescription - -> Graph.Graph NonSetupLibDepSolverPlanPackage - -> ComponentDeps [SolverId] - -> Version --- We're going to be using the internal Cabal library, so the spec version of --- that is simply the version of the Cabal library that cabal-install has been --- built with. -packageSetupScriptSpecVersion SetupNonCustomInternalLib _ _ _ = - cabalVersion --- If we happen to be building the Cabal lib itself then because that --- bootstraps itself then we use the version of the lib we're building. -packageSetupScriptSpecVersion SetupCustomImplicitDeps pkg _ _ - | packageName pkg == cabalPkgname = - packageVersion pkg --- In all other cases we have a look at what version of the Cabal lib the --- solver picked. Or if it didn't depend on Cabal at all (which is very rare) --- then we look at the .cabal file to see what spec version it declares. -packageSetupScriptSpecVersion _ pkg libDepGraph deps = - case find ((cabalPkgname ==) . packageName) setupLibDeps of - Just dep -> packageVersion dep - Nothing -> mkVersion (cabalSpecMinimumLibraryVersion (PD.specVersion pkg)) - where - setupLibDeps = - map packageId $ - fromMaybe [] $ - Graph.closure libDepGraph (CD.setupDeps deps) - -cabalPkgname, basePkgname :: PackageName -cabalPkgname = mkPackageName "Cabal" -basePkgname = mkPackageName "base" - -legacyCustomSetupPkgs :: Compiler -> Platform -> [PackageName] -legacyCustomSetupPkgs compiler (Platform _ os) = - map mkPackageName $ - [ "array" - , "base" - , "binary" - , "bytestring" - , "containers" - , "deepseq" - , "directory" - , "filepath" - , "pretty" - , "process" - , "time" - , "transformers" - ] - ++ ["Win32" | os == Windows] - ++ ["unix" | os /= Windows] - ++ ["ghc-prim" | isGHC] - ++ ["template-haskell" | isGHC] - ++ ["old-time" | notGHC710] - where - isGHC = compilerCompatFlavor GHC compiler - notGHC710 = case compilerCompatVersion GHC compiler of - Nothing -> False - Just v -> v <= mkVersion [7, 9] - -- The other aspects of our Setup.hs policy lives here where we decide on -- the 'SetupScriptOptions'. -- @@ -4027,15 +3708,15 @@ userInstallDirTemplates compiler = do storePackageInstallDirs :: StoreDirLayout - -> CompilerId + -> Compiler -> InstalledPackageId -> InstallDirs.InstallDirs FilePath -storePackageInstallDirs storeDirLayout compid ipkgid = - storePackageInstallDirs' storeDirLayout compid $ newSimpleUnitId ipkgid +storePackageInstallDirs storeDirLayout compiler ipkgid = + storePackageInstallDirs' storeDirLayout compiler $ newSimpleUnitId ipkgid storePackageInstallDirs' :: StoreDirLayout - -> CompilerId + -> Compiler -> UnitId -> InstallDirs.InstallDirs FilePath storePackageInstallDirs' @@ -4043,12 +3724,12 @@ storePackageInstallDirs' { storePackageDirectory , storeDirectory } - compid + compiler unitid = InstallDirs.InstallDirs{..} where - store = storeDirectory compid - prefix = storePackageDirectory compid unitid + store = storeDirectory compiler + prefix = storePackageDirectory compiler unitid bindir = prefix "bin" libdir = prefix "lib" libsubdir = "" @@ -4098,7 +3779,7 @@ computeInstallDirs storeDirLayout defaultInstallDirs elaboratedShared elab -- use special simplified install dirs storePackageInstallDirs' storeDirLayout - (compilerId (pkgConfigCompiler elaboratedShared)) + (pkgConfigCompiler elaboratedShared) (elabUnitId elab) -- TODO: [code cleanup] perhaps reorder this code @@ -4106,12 +3787,14 @@ computeInstallDirs storeDirLayout defaultInstallDirs elaboratedShared elab -- make the various Setup.hs {configure,build,copy} flags setupHsConfigureFlags - :: ElaboratedReadyPackage + :: ElaboratedInstallPlan + -> ElaboratedReadyPackage -> ElaboratedSharedConfig -> Verbosity -> FilePath -> Cabal.ConfigFlags setupHsConfigureFlags + plan (ReadyPackage elab@ElaboratedConfiguredPackage{..}) sharedConfig@ElaboratedSharedConfig{..} verbosity @@ -4121,6 +3804,31 @@ setupHsConfigureFlags elab (Cabal.ConfigFlags{..}) where + Cabal.ConfigFlags + { configVanillaLib + , configSharedLib + , configStaticLib + , configDynExe + , configFullyStaticExe + , configGHCiLib + , -- , configProfExe -- overridden + configProfLib + , -- , configProf -- overridden + configProfDetail + , configProfLibDetail + , configCoverage + , configLibCoverage + , configRelocatable + , configOptimization + , configSplitSections + , configSplitObjs + , configStripExes + , configStripLibs + , configDebugInfo + } = LBC.buildOptionsConfigFlags elabBuildOptions + configProfExe = mempty + configProf = toFlag $ LBC.withProfExe elabBuildOptions + configArgs = mempty -- unused, passed via args configDistPref = toFlag builddir configCabalFilePath = mempty @@ -4162,31 +3870,6 @@ setupHsConfigureFlags configHcFlavor = toFlag (compilerFlavor pkgConfigCompiler) configHcPath = mempty -- we use configProgramPaths instead configHcPkg = mempty -- we use configProgramPaths instead - configVanillaLib = toFlag elabVanillaLib - configSharedLib = toFlag elabSharedLib - configStaticLib = toFlag elabStaticLib - - configDynExe = toFlag elabDynExe - configFullyStaticExe = toFlag elabFullyStaticExe - configGHCiLib = toFlag elabGHCiLib - configProfExe = mempty - configProfLib = toFlag elabProfLib - configProf = toFlag elabProfExe - - -- configProfDetail is for exe+lib, but overridden by configProfLibDetail - -- so we specify both so we can specify independently - configProfDetail = toFlag elabProfExeDetail - configProfLibDetail = toFlag elabProfLibDetail - - configCoverage = toFlag elabCoverage - configLibCoverage = mempty - - configOptimization = toFlag elabOptimization - configSplitSections = toFlag elabSplitSections - configSplitObjs = toFlag elabSplitObjs - configStripExes = toFlag elabStripExes - configStripLibs = toFlag elabStripLibs - configDebugInfo = toFlag elabDebugInfo configDumpBuildInfo = toFlag elabDumpBuildInfo configConfigurationsFlags = elabFlagAssignment @@ -4242,7 +3925,6 @@ setupHsConfigureFlags configExactConfiguration = toFlag True configFlagError = mempty -- TODO: [research required] appears not to be implemented - configRelocatable = mempty -- TODO: [research required] ??? configScratchDir = mempty -- never use configUserInstall = mempty -- don't rely on defaults configPrograms_ = mempty -- never use, shouldn't exist @@ -4257,6 +3939,8 @@ setupHsConfigureFlags Just _ -> error "non-library dependency" Nothing -> LMainLibName + configCoverageFor = determineCoverageFor elabPkgSourceId plan + setupHsConfigureArgs :: ElaboratedConfiguredPackage -> [String] @@ -4284,8 +3968,9 @@ setupHsBuildFlags par_strat elab _ verbosity builddir = , buildDistPref = toFlag builddir , buildNumJobs = mempty -- TODO: [nice to have] sometimes want to use toFlag (Just numBuildJobs), , buildUseSemaphore = - if elabSetupScriptCliVersion elab >= mkVersion [3, 9, 0, 0] - then par_strat + if elabSetupScriptCliVersion elab >= mkVersion [3, 11, 0, 0] + then -- Cabal 3.11 is the first version that supports parallelism semaphores + par_strat else mempty , buildArgs = mempty -- unused, passed via args not flags , buildCabalFilePath = mempty @@ -4303,11 +3988,10 @@ setupHsBuildArgs (ElaboratedConfiguredPackage{elabPkgOrComp = ElabComponent _}) setupHsTestFlags :: ElaboratedConfiguredPackage - -> ElaboratedSharedConfig -> Verbosity -> FilePath -> Cabal.TestFlags -setupHsTestFlags (ElaboratedConfiguredPackage{..}) _ verbosity builddir = +setupHsTestFlags (ElaboratedConfiguredPackage{..}) verbosity builddir = Cabal.TestFlags { testDistPref = toFlag builddir , testVerbosity = toFlag verbosity @@ -4453,17 +4137,6 @@ setupHsHaddockArgs :: ElaboratedConfiguredPackage -> [String] setupHsHaddockArgs elab = map (showComponentTarget (packageId elab)) (elabHaddockTargets elab) -{- -setupHsTestFlags :: ElaboratedConfiguredPackage - -> ElaboratedSharedConfig - -> Verbosity - -> FilePath - -> Cabal.TestFlags -setupHsTestFlags _ _ verbosity builddir = - Cabal.TestFlags { - } --} - ------------------------------------------------------------------------------ -- * Sharing installed packages @@ -4570,25 +4243,26 @@ packageHashConfigInputs packageHashConfigInputs shared@ElaboratedSharedConfig{..} pkg = PackageHashConfigInputs { pkgHashCompilerId = compilerId pkgConfigCompiler + , pkgHashCompilerABI = compilerAbiTag pkgConfigCompiler , pkgHashPlatform = pkgConfigPlatform , pkgHashFlagAssignment = elabFlagAssignment , pkgHashConfigureScriptArgs = elabConfigureScriptArgs - , pkgHashVanillaLib = elabVanillaLib - , pkgHashSharedLib = elabSharedLib - , pkgHashDynExe = elabDynExe - , pkgHashFullyStaticExe = elabFullyStaticExe - , pkgHashGHCiLib = elabGHCiLib - , pkgHashProfLib = elabProfLib - , pkgHashProfExe = elabProfExe - , pkgHashProfLibDetail = elabProfLibDetail - , pkgHashProfExeDetail = elabProfExeDetail - , pkgHashCoverage = elabCoverage - , pkgHashOptimization = elabOptimization - , pkgHashSplitSections = elabSplitSections - , pkgHashSplitObjs = elabSplitObjs - , pkgHashStripLibs = elabStripLibs - , pkgHashStripExes = elabStripExes - , pkgHashDebugInfo = elabDebugInfo + , pkgHashVanillaLib = withVanillaLib + , pkgHashSharedLib = withSharedLib + , pkgHashDynExe = withDynExe + , pkgHashFullyStaticExe = withFullyStaticExe + , pkgHashGHCiLib = withGHCiLib + , pkgHashProfLib = withProfLib + , pkgHashProfExe = withProfExe + , pkgHashProfLibDetail = withProfLibDetail + , pkgHashProfExeDetail = withProfExeDetail + , pkgHashCoverage = exeCoverage + , pkgHashOptimization = withOptimization + , pkgHashSplitSections = splitSections + , pkgHashSplitObjs = splitObjs + , pkgHashStripLibs = stripLibs + , pkgHashStripExes = stripExes + , pkgHashDebugInfo = withDebugInfo , pkgHashProgramArgs = elabProgramArgs , pkgHashExtraLibDirs = elabExtraLibDirs , pkgHashExtraLibDirsStatic = elabExtraLibDirsStatic @@ -4617,6 +4291,7 @@ packageHashConfigInputs shared@ElaboratedSharedConfig{..} pkg = } where ElaboratedConfiguredPackage{..} = normaliseConfiguredPackage shared pkg + LBC.BuildOptions{..} = elabBuildOptions -- | Given the 'InstalledPackageIndex' for a nix-style package store, and an -- 'ElaboratedInstallPlan', replace configured source packages by installed @@ -4671,3 +4346,40 @@ inplaceBinRoot inplaceBinRoot layout config package = distBuildDirectory layout (elabDistDirParams config package) "build" + +-------------------------------------------------------------------------------- +-- Configure --coverage-for flags + +-- The list of non-pre-existing libraries without module holes, i.e. the +-- main library and sub-libraries components of all the local packages in +-- the project that do not require instantiations or are instantiations. +determineCoverageFor + :: PackageId + -- ^ The 'PackageId' of the package or component being configured + -> ElaboratedInstallPlan + -> Flag [UnitId] +determineCoverageFor configuredPkgSourceId plan = + Flag + $ mapMaybe + ( \case + InstallPlan.Installed elab + | shouldCoverPkg elab -> Just $ elabUnitId elab + InstallPlan.Configured elab + | shouldCoverPkg elab -> Just $ elabUnitId elab + _ -> Nothing + ) + $ Graph.toList + $ InstallPlan.toGraph plan + where + shouldCoverPkg elab@ElaboratedConfiguredPackage{elabModuleShape, elabPkgSourceId, elabLocalToProject} = + elabLocalToProject + && not (isIndefiniteOrInstantiation elabModuleShape) + -- TODO(#9493): We can only cover libraries in the same package + -- as the testsuite + && configuredPkgSourceId == elabPkgSourceId + -- Libraries only! We don't cover testsuite modules, so we never need + -- the paths to their mix dirs. Furthermore, we do not install testsuites... + && maybe False (\case CLibName{} -> True; CNotLibName{} -> False) (elabComponentName elab) + + isIndefiniteOrInstantiation :: ModuleShape -> Bool + isIndefiniteOrInstantiation = not . Set.null . modShapeRequires diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/SetupPolicy.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/SetupPolicy.hs new file mode 100644 index 00000000000..86bc044342e --- /dev/null +++ b/cabal-install/src/Distribution/Client/ProjectPlanning/SetupPolicy.hs @@ -0,0 +1,247 @@ +{-# LANGUAGE TypeFamilies #-} + +-- | Setup.hs script policy +-- +-- Handling for Setup.hs scripts is a bit tricky, part of it lives in the +-- solver phase, and part in the elaboration phase. We keep the helper +-- functions for both phases together here so at least you can see all of it +-- in one place. +-- +-- There are four major cases for Setup.hs handling: +-- +-- 1. @build-type@ Custom with a @custom-setup@ section +-- 2. @build-type@ Custom without a @custom-setup@ section +-- 3. @build-type@ not Custom with @cabal-version > $our-cabal-version@ +-- 4. @build-type@ not Custom with @cabal-version <= $our-cabal-version@ +-- +-- It's also worth noting that packages specifying @cabal-version: >= 1.23@ +-- or later that have @build-type@ Custom will always have a @custom-setup@ +-- section. Therefore in case 2, the specified @cabal-version@ will always be +-- less than 1.23. +-- +-- In cases 1 and 2 we obviously have to build an external Setup.hs script, +-- while in case 4 we can use the internal library API. +-- +-- @since 3.12.0.0 +module Distribution.Client.ProjectPlanning.SetupPolicy + ( mkDefaultSetupDeps + , packageSetupScriptStyle + , packageSetupScriptSpecVersion + , NonSetupLibDepSolverPlanPackage (..) + ) +where + +import Distribution.Client.Compat.Prelude +import Prelude () + +import Distribution.Client.ProjectPlanning.Types (SetupScriptStyle (..)) +import Distribution.Client.SolverInstallPlan (SolverPlanPackage) +import Distribution.Solver.Types.ComponentDeps (ComponentDeps) +import qualified Distribution.Solver.Types.ComponentDeps as CD +import Distribution.Solver.Types.ResolverPackage (resolverPackageLibDeps) +import Distribution.Solver.Types.SolverId (SolverId) + +import Distribution.CabalSpecVersion + +import Distribution.Package +import Distribution.PackageDescription +import Distribution.Simple.Compiler +import Distribution.System + +import Distribution.Simple.Utils +import Distribution.Version + +import Distribution.Compat.Graph (IsNode (..)) +import qualified Distribution.Compat.Graph as Graph + +-- | Work out the 'SetupScriptStyle' given the package description. +-- +-- @since 3.12.0.0 +packageSetupScriptStyle :: PackageDescription -> SetupScriptStyle +packageSetupScriptStyle pkg + | buildType pkg == Custom + , Just setupbi <- setupBuildInfo pkg -- does have a custom-setup stanza + , not (defaultSetupDepends setupbi) -- but not one we added ourselves + = + SetupCustomExplicitDeps + | buildType pkg == Custom + , Just setupbi <- setupBuildInfo pkg -- does have a custom-setup stanza + , defaultSetupDepends setupbi -- that we had to add ourselves + = + SetupCustomImplicitDeps + | buildType pkg == Custom + , Nothing <- setupBuildInfo pkg -- we get this case pre-solver + = + SetupCustomImplicitDeps + -- The specified @cabal-version@ is newer that the last we know about. + -- Here we could fail but we are optimist and build an external setup script. + | specVersion pkg > cabalSpecLatest = + SetupNonCustomExternalLib + | otherwise = + SetupNonCustomInternalLib + +-- | Part of our Setup.hs handling policy is implemented by getting the solver +-- to work out setup dependencies for packages. The solver already handles +-- packages that explicitly specify setup dependencies, but we can also tell +-- the solver to treat other packages as if they had setup dependencies. +-- That's what this function does, it gets called by 'planPackages' for all +-- packages that don't already have setup dependencies. +-- +-- The dependencies we want to add is different for each 'SetupScriptStyle'. +-- +-- Note in addition to adding setup dependencies, we also use +-- 'addSetupCabalMinVersionConstraint' (in 'planPackages') to require +-- @Cabal >= 1.20@ for Setup scripts. +-- +-- @since 3.12.0.0 +mkDefaultSetupDeps + :: Compiler + -> Platform + -> PackageDescription + -> Maybe [Dependency] +mkDefaultSetupDeps compiler platform pkg = + case packageSetupScriptStyle pkg of + -- For packages with build type custom that do not specify explicit + -- setup dependencies, we add a dependency on Cabal and a number + -- of other packages. + SetupCustomImplicitDeps -> + Just $ + [ Dependency depPkgname anyVersion mainLibSet + | depPkgname <- legacyCustomSetupPkgs compiler platform + ] + ++ [ Dependency cabalPkgname cabalConstraint mainLibSet + | packageName pkg /= cabalPkgname + ] + where + -- The Cabal dep is slightly special: + -- \* We omit the dep for the Cabal lib itself, since it bootstraps. + -- \* We constrain it to be < 1.25 + -- + -- Note: we also add a global constraint to require Cabal >= 1.20 + -- for Setup scripts (see use addSetupCabalMinVersionConstraint). + -- + cabalConstraint = + orLaterVersion (csvToVersion (specVersion pkg)) + `intersectVersionRanges` earlierVersion cabalCompatMaxVer + -- The idea here is that at some point we will make significant + -- breaking changes to the Cabal API that Setup.hs scripts use. + -- So for old custom Setup scripts that do not specify explicit + -- constraints, we constrain them to use a compatible Cabal version. + cabalCompatMaxVer = mkVersion [1, 25] + + -- For other build types (like Simple) if we still need to compile an + -- external Setup.hs, it'll be one of the simple ones that only depends + -- on Cabal and base. + SetupNonCustomExternalLib -> + Just + [ Dependency cabalPkgname cabalConstraint mainLibSet + , Dependency basePkgname anyVersion mainLibSet + ] + where + cabalConstraint = orLaterVersion (csvToVersion (specVersion pkg)) + + -- The internal setup wrapper method has no deps at all. + SetupNonCustomInternalLib -> Just [] + -- This case gets ruled out by the caller, planPackages, see the note + -- above in the SetupCustomImplicitDeps case. + SetupCustomExplicitDeps -> + error $ + "mkDefaultSetupDeps: called for a package with explicit " + ++ "setup deps: " + ++ prettyShow (packageId pkg) + where + -- we require one less + -- + -- This maps e.g. CabalSpecV3_0 to mkVersion [2,5] + csvToVersion :: CabalSpecVersion -> Version + csvToVersion = mkVersion . cabalSpecMinimumLibraryVersion + +-- | A newtype for 'SolverPlanPackage' for which the +-- dependency graph considers only dependencies on libraries which are +-- NOT from setup dependencies. Used to compute the set +-- of packages needed for profiling and dynamic libraries. +-- +-- @since 3.12.0.0 +newtype NonSetupLibDepSolverPlanPackage = NonSetupLibDepSolverPlanPackage + {unNonSetupLibDepSolverPlanPackage :: SolverPlanPackage} + +instance Package NonSetupLibDepSolverPlanPackage where + packageId (NonSetupLibDepSolverPlanPackage spkg) = + packageId spkg + +instance IsNode NonSetupLibDepSolverPlanPackage where + type Key NonSetupLibDepSolverPlanPackage = SolverId + + nodeKey (NonSetupLibDepSolverPlanPackage spkg) = + nodeKey spkg + + nodeNeighbors (NonSetupLibDepSolverPlanPackage spkg) = + ordNub $ CD.nonSetupDeps (resolverPackageLibDeps spkg) + +-- | Work out which version of the Cabal we will be using to talk to the +-- Setup.hs interface for this package. +-- +-- This depends somewhat on the 'SetupScriptStyle' but most cases are a result +-- of what the solver picked for us, based on the explicit setup deps or the +-- ones added implicitly by 'mkDefaultSetupDeps'. +-- +-- @since 3.12.0.0 +packageSetupScriptSpecVersion + :: SetupScriptStyle + -> PackageDescription + -> Graph.Graph NonSetupLibDepSolverPlanPackage + -> ComponentDeps [SolverId] + -> Version +-- We're going to be using the internal Cabal library, so the spec version of +-- that is simply the version of the Cabal library that cabal-install has been +-- built with. +packageSetupScriptSpecVersion SetupNonCustomInternalLib _ _ _ = + cabalVersion +-- If we happen to be building the Cabal lib itself then because that +-- bootstraps itself then we use the version of the lib we're building. +packageSetupScriptSpecVersion SetupCustomImplicitDeps pkg _ _ + | packageName pkg == cabalPkgname = + packageVersion pkg +-- In all other cases we have a look at what version of the Cabal lib the +-- solver picked. Or if it didn't depend on Cabal at all (which is very rare) +-- then we look at the .cabal file to see what spec version it declares. +packageSetupScriptSpecVersion _ pkg libDepGraph deps = + case find ((cabalPkgname ==) . packageName) setupLibDeps of + Just dep -> packageVersion dep + Nothing -> mkVersion (cabalSpecMinimumLibraryVersion (specVersion pkg)) + where + setupLibDeps = + map packageId $ + fromMaybe [] $ + Graph.closure libDepGraph (CD.setupDeps deps) + +cabalPkgname, basePkgname :: PackageName +cabalPkgname = mkPackageName "Cabal" +basePkgname = mkPackageName "base" + +legacyCustomSetupPkgs :: Compiler -> Platform -> [PackageName] +legacyCustomSetupPkgs compiler (Platform _ os) = + map mkPackageName $ + [ "array" + , "base" + , "binary" + , "bytestring" + , "containers" + , "deepseq" + , "directory" + , "filepath" + , "pretty" + , "process" + , "time" + , "transformers" + ] + ++ ["Win32" | os == Windows] + ++ ["unix" | os /= Windows] + ++ ["ghc-prim" | isGHC] + ++ ["template-haskell" | isGHC] + ++ ["old-time" | notGHC710] + where + isGHC = compilerCompatFlavor GHC compiler + notGHC710 = case compilerCompatVersion GHC compiler of + Nothing -> False + Just v -> v <= mkVersion [7, 9] diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs index 28af81774eb..178ffdcbc76 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs @@ -2,7 +2,9 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} -- | Types used while planning how to build everything in a project. @@ -41,6 +43,9 @@ module Distribution.Client.ProjectPlanning.Types , MemoryOrDisk (..) , isInplaceBuildStyle , CabalFileText + , NotPerComponentReason (..) + , NotPerComponentBuildType (..) + , whyNotPerComponent -- * Build targets , ComponentTarget (..) @@ -103,6 +108,7 @@ import Distribution.Simple.Setup ) import Distribution.System import Distribution.Types.ComponentRequestedSpec +import qualified Distribution.Types.LocalBuildConfig as LBC import Distribution.Types.PackageDescription (PackageDescription (..)) import Distribution.Types.PkgconfigVersion import Distribution.Verbosity (normal) @@ -115,6 +121,7 @@ import qualified Distribution.Solver.Types.ComponentDeps as CD import Distribution.Solver.Types.OptionalStanza import qualified Data.ByteString.Lazy as LBS +import qualified Data.List.NonEmpty as NE import qualified Data.Map as Map import qualified Data.Monoid as Mon import System.FilePath (()) @@ -264,23 +271,7 @@ data ElaboratedConfiguredPackage = ElaboratedConfiguredPackage , elabInplaceRegisterPackageDBStack :: PackageDBStack , elabPkgDescriptionOverride :: Maybe CabalFileText , -- TODO: make per-component variants of these flags - elabVanillaLib :: Bool - , elabSharedLib :: Bool - , elabStaticLib :: Bool - , elabDynExe :: Bool - , elabFullyStaticExe :: Bool - , elabGHCiLib :: Bool - , elabProfLib :: Bool - , elabProfExe :: Bool - , elabProfLibDetail :: ProfDetailLevel - , elabProfExeDetail :: ProfDetailLevel - , elabCoverage :: Bool - , elabOptimization :: OptimisationLevel - , elabSplitObjs :: Bool - , elabSplitSections :: Bool - , elabStripLibs :: Bool - , elabStripExes :: Bool - , elabDebugInfo :: DebugInfoLevel + elabBuildOptions :: LBC.BuildOptions , elabDumpBuildInfo :: DumpBuildInfo , elabProgramPaths :: Map String FilePath , elabProgramArgs :: Map String [String] @@ -542,7 +533,7 @@ elabDistDirParams shared elab = ElabPackage _ -> Nothing , distParamCompilerId = compilerId (pkgConfigCompiler shared) , distParamPlatform = pkgConfigPlatform shared - , distParamOptimization = elabOptimization elab + , distParamOptimization = LBC.withOptimization $ elabBuildOptions elab } -- | The full set of dependencies which dictate what order we @@ -738,12 +729,53 @@ data ElaboratedPackage = ElaboratedPackage , pkgStanzasEnabled :: OptionalStanzaSet -- ^ Which optional stanzas (ie testsuites, benchmarks) will actually -- be enabled during the package configure step. + , pkgWhyNotPerComponent :: NE.NonEmpty NotPerComponentReason + -- ^ Why is this not a per-component build? } deriving (Eq, Show, Generic) instance Binary ElaboratedPackage instance Structured ElaboratedPackage +-- | Why did we fall-back to a per-package build, instead of using +-- a per-component build? +data NotPerComponentReason + = -- | The build-type does not support per-component builds. + CuzBuildType !NotPerComponentBuildType + | -- | The Cabal spec version is too old for per-component builds. + CuzCabalSpecVersion + | -- | There are no buildable components, so we fall-back to a per-package + -- build for error-reporting purposes. + CuzNoBuildableComponents + | -- | The user passed @--disable-per-component@. + CuzDisablePerComponent + deriving (Eq, Show, Generic) + +data NotPerComponentBuildType + = CuzConfigureBuildType + | CuzCustomBuildType + | CuzMakeBuildType + deriving (Eq, Show, Generic) + +instance Binary NotPerComponentBuildType +instance Structured NotPerComponentBuildType + +instance Binary NotPerComponentReason +instance Structured NotPerComponentReason + +-- | Display the reason we had to fall-back to a per-package build instead +-- of a per-component build. +whyNotPerComponent :: NotPerComponentReason -> String +whyNotPerComponent = \case + CuzBuildType bt -> + "build-type is " ++ case bt of + CuzConfigureBuildType -> "Configure" + CuzCustomBuildType -> "Custom" + CuzMakeBuildType -> "Make" + CuzCabalSpecVersion -> "cabal-version is less than 1.8" + CuzNoBuildableComponents -> "there are no buildable components" + CuzDisablePerComponent -> "you passed --disable-per-component" + -- | See 'elabOrderDependencies'. This gives the unflattened version, -- which can be useful in some circumstances. pkgOrderDependencies :: ElaboratedPackage -> ComponentDeps [UnitId] diff --git a/cabal-install/src/Distribution/Client/RebuildMonad.hs b/cabal-install/src/Distribution/Client/RebuildMonad.hs index 89378922d66..33303ea3243 100644 --- a/cabal-install/src/Distribution/Client/RebuildMonad.hs +++ b/cabal-install/src/Distribution/Client/RebuildMonad.hs @@ -32,9 +32,9 @@ module Distribution.Client.RebuildMonad -- ** Monitoring file globs , monitorFileGlob , monitorFileGlobExistence - , FilePathGlob (..) + , RootedGlob (..) , FilePathRoot (..) - , FilePathGlobRel (..) + , Glob (..) , GlobPiece (..) -- * Using a file monitor @@ -63,6 +63,7 @@ import Prelude () import Distribution.Client.FileMonitor import Distribution.Client.Glob hiding (matchFileGlob) import qualified Distribution.Client.Glob as Glob (matchFileGlob) +import Distribution.Simple.PreProcess.Types (Suffix (..)) import Distribution.Simple.Utils (debug) @@ -232,7 +233,7 @@ delayInitSharedResources action = do -- -- Since this operates in the 'Rebuild' monad, it also monitors the given glob -- for changes. -matchFileGlob :: FilePathGlob -> Rebuild [FilePath] +matchFileGlob :: RootedGlob -> Rebuild [FilePath] matchFileGlob glob = do root <- askRoot monitorFiles [monitorFileGlobExistence glob] @@ -296,7 +297,7 @@ needIfExists f = do -- | Like 'findFileWithExtension', but in the 'Rebuild' monad. findFileWithExtensionMonitored - :: [String] + :: [Suffix] -> [FilePath] -> FilePath -> Rebuild (Maybe FilePath) @@ -305,7 +306,7 @@ findFileWithExtensionMonitored extensions searchPath baseName = id [ path baseName <.> ext | path <- nub searchPath - , ext <- nub extensions + , Suffix ext <- nub extensions ] -- | Like 'findFirstFile', but in the 'Rebuild' monad. diff --git a/cabal-install/src/Distribution/Client/Run.hs b/cabal-install/src/Distribution/Client/Run.hs index a5214b39780..6784e3bfe18 100644 --- a/cabal-install/src/Distribution/Client/Run.hs +++ b/cabal-install/src/Distribution/Client/Run.hs @@ -32,6 +32,7 @@ import Distribution.Simple.Compiler (CompilerFlavor (..), compilerFlavor) import Distribution.Simple.LocalBuildInfo ( ComponentName (..) , LocalBuildInfo (..) + , buildDir , depLibraryPaths ) import Distribution.Simple.Utils diff --git a/cabal-install/src/Distribution/Client/ScriptUtils.hs b/cabal-install/src/Distribution/Client/ScriptUtils.hs index eacf9cd5afe..1793f6aa07d 100644 --- a/cabal-install/src/Distribution/Client/ScriptUtils.hs +++ b/cabal-install/src/Distribution/Client/ScriptUtils.hs @@ -37,7 +37,8 @@ import Distribution.Client.DistDirLayout ) import Distribution.Client.HashValue ( hashValue - , showHashValueBase64 + , showHashValue + , truncateHash ) import Distribution.Client.HttpUtils ( HttpTransport @@ -218,18 +219,15 @@ import qualified Text.Parsec as P -- repl to deal with the fact that the repl is relative to the working directory and not -- the project root. --- | Get the hash of a script's absolute path) +-- | Get the hash of a script's absolute path. -- -- Two hashes will be the same as long as the absolute paths -- are the same. getScriptHash :: FilePath -> IO String getScriptHash script = - -- Base64 is shorter than Base16, which helps avoid long path issues on windows - -- but it can contain /'s which aren't valid in file paths so replace them with - -- %'s. 26 chars / 130 bits is enough to practically avoid collisions. - map (\c -> if c == '/' then '%' else c) - . take 26 - . showHashValueBase64 + -- Truncation here tries to help with long path issues on Windows. + showHashValue + . truncateHash 26 . hashValue . fromString <$> canonicalizePath script @@ -294,7 +292,11 @@ withContextAndSelectors -> IO b withContextAndSelectors noTargets kind flags@NixStyleFlags{..} targetStrings globalFlags cmd act = withTemporaryTempDirectory $ \mkTmpDir -> do - (tc, ctx) <- withProjectOrGlobalConfig verbosity ignoreProject globalConfigFlag withProject (withoutProject mkTmpDir) + (tc, ctx) <- + withProjectOrGlobalConfig + ignoreProject + withProject + (withGlobalConfig verbosity globalConfigFlag $ withoutProject mkTmpDir) (tc', ctx', sels) <- case targetStrings of -- Only script targets may contain spaces and or end with ':'. diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index 6d04d401a8a..85f00dd9609 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -66,6 +66,7 @@ module Distribution.Client.Setup , unpackCommand , GetFlags (..) , checkCommand + , CheckFlags (..) , formatCommand , uploadCommand , UploadFlags (..) @@ -85,6 +86,10 @@ module Distribution.Client.Setup , cleanCommand , copyCommand , registerCommand + , Path (..) + , pathName + , PathFlags (..) + , pathCommand , liftOptions , yesNoOpt ) where @@ -142,6 +147,7 @@ import Distribution.PackageDescription , LibraryName (..) , RepoKind (..) ) +import Distribution.PackageDescription.Check (CheckExplanationIDString) import Distribution.Parsec ( parsecCommaList ) @@ -167,6 +173,7 @@ import Distribution.Simple.Flag , flagToMaybe , fromFlagOrDefault , maybeToFlag + , mergeListFlag , toFlag ) import Distribution.Simple.InstallDirs @@ -282,8 +289,10 @@ globalCommand commands = , "gen-bounds" , "outdated" , "haddock" + , "haddock-project" , "hscolour" , "exec" + , "path" , "new-build" , "new-configure" , "new-repl" @@ -297,6 +306,7 @@ globalCommand commands = , "new-install" , "new-clean" , "new-sdist" + , "new-haddock-project" , "list-bin" , -- v1 commands, stateful style "v1-build" @@ -325,6 +335,7 @@ globalCommand commands = , "v2-test" , "v2-bench" , "v2-haddock" + , "v2-haddock-project" , "v2-exec" , "v2-update" , "v2-install" @@ -343,6 +354,7 @@ globalCommand commands = ++ unlines ( [ startGroup "global" , addCmd "user-config" + , addCmd "path" , addCmd "help" , par , startGroup "package database" @@ -671,6 +683,11 @@ filterConfigureFlags flags cabalLibVersion -- We add a Cabal>=3.11 constraint before solving when multi-repl is -- enabled, so this should never trigger. configPromisedDependencies = assert (null $ configPromisedDependencies flags) [] + , -- Cabal < 3.11 does not understand '--coverage-for', which is OK + -- because previous versions of Cabal using coverage implied + -- whole-package builds (cuz_coverage), and determine the path to + -- libraries mix dirs from the testsuite root with a small hack. + configCoverageFor = NoFlag } flags_3_7_0 = @@ -1530,6 +1547,56 @@ genBoundsCommand = ] } +-- ------------------------------------------------------------ +-- Check command +-- ------------------------------------------------------------ + +data CheckFlags = CheckFlags + { checkVerbosity :: Flag Verbosity + , checkIgnore :: [CheckExplanationIDString] + } + deriving (Show, Typeable) + +defaultCheckFlags :: CheckFlags +defaultCheckFlags = + CheckFlags + { checkVerbosity = Flag normal + , checkIgnore = [] + } + +checkCommand :: CommandUI CheckFlags +checkCommand = + CommandUI + { commandName = "check" + , commandSynopsis = "Check the package for common mistakes." + , commandDescription = Just $ \_ -> + wrapText $ + "Expects a .cabal package file in the current directory.\n" + ++ "\n" + ++ "Some checks correspond to the requirements to packages on Hackage. " + ++ "If no `Error` is reported, Hackage should accept the " + ++ "package. If errors are present, `check` exits with 1 and Hackage " + ++ "will refuse the package.\n" + , commandNotes = Nothing + , commandUsage = usageFlags "check" + , commandDefaultFlags = defaultCheckFlags + , commandOptions = checkOptions' + } + +checkOptions' :: ShowOrParseArgs -> [OptionField CheckFlags] +checkOptions' _showOrParseArgs = + [ optionVerbosity + checkVerbosity + (\v flags -> flags{checkVerbosity = v}) + , option + ['i'] + ["ignore"] + "ignore a specific warning (e.g. --ignore=missing-upper-bounds)" + checkIgnore + (\v c -> c{checkIgnore = v ++ checkIgnore c}) + (reqArg' "WARNING" (: []) (const [])) + ] + -- ------------------------------------------------------------ -- * Update command @@ -1562,25 +1629,6 @@ cleanCommand = "Usage: " ++ pname ++ " v1-clean [FLAGS]\n" } -checkCommand :: CommandUI (Flag Verbosity) -checkCommand = - CommandUI - { commandName = "check" - , commandSynopsis = "Check the package for common mistakes." - , commandDescription = Just $ \_ -> - wrapText $ - "Expects a .cabal package file in the current directory.\n" - ++ "\n" - ++ "Some checks correspond to the requirements to packages on Hackage. " - ++ "If no `Error` is reported, Hackage should accept the " - ++ "package. If errors are present, `check` exits with 1 and Hackage " - ++ "will refuse the package.\n" - , commandNotes = Nothing - , commandUsage = usageFlags "check" - , commandDefaultFlags = toFlag normal - , commandOptions = \_ -> [optionVerbosity id const] - } - formatCommand :: CommandUI (Flag Verbosity) formatCommand = CommandUI @@ -3159,10 +3207,6 @@ initOptions _ = ("Cannot parse dependencies: " ++) (parsecCommaList parsec) - mergeListFlag :: Flag [a] -> Flag [a] -> Flag [a] - mergeListFlag currentFlags v = - Flag $ concat (flagToList currentFlags ++ flagToList v) - -- ------------------------------------------------------------ -- * Copy and Register @@ -3322,6 +3366,73 @@ userConfigCommand = -- ------------------------------------------------------------ +-- * Dirs + +-- ------------------------------------------------------------ + +-- | A path that can be retrieved by the @cabal path@ command. +data Path + = PathCacheDir + | PathLogsDir + | PathStoreDir + | PathConfigFile + | PathInstallDir + deriving (Eq, Ord, Show, Enum, Bounded) + +-- | The configuration name for this path. +pathName :: Path -> String +pathName PathCacheDir = "cache-dir" +pathName PathLogsDir = "logs-dir" +pathName PathStoreDir = "store-dir" +pathName PathConfigFile = "config-file" +pathName PathInstallDir = "installdir" + +data PathFlags = PathFlags + { pathVerbosity :: Flag Verbosity + , pathDirs :: Flag [Path] + } + deriving (Generic) + +instance Monoid PathFlags where + mempty = + PathFlags + { pathVerbosity = toFlag normal + , pathDirs = toFlag [] + } + mappend = (<>) + +instance Semigroup PathFlags where + (<>) = gmappend + +pathCommand :: CommandUI PathFlags +pathCommand = + CommandUI + { commandName = "path" + , commandSynopsis = "Display paths used by cabal." + , commandDescription = Just $ \_ -> + wrapText $ + "This command prints the directories that are used by cabal," + ++ " taking into account the contents of the configuration file and any" + ++ " environment variables." + , commandNotes = Nothing + , commandUsage = \pname -> "Usage: " ++ pname ++ " path\n" + , commandDefaultFlags = mempty + , commandOptions = \_ -> + map pathOption [minBound .. maxBound] + ++ [optionVerbosity pathVerbosity (\v flags -> flags{pathVerbosity = v})] + } + where + pathOption s = + option + [] + [pathName s] + ("Print " <> pathName s) + pathDirs + (\v flags -> flags{pathDirs = Flag $ concat (flagToList (pathDirs flags) ++ flagToList v)}) + (noArg (Flag [s])) + +-- ------------------------------------------------------------ + -- * GetOpt Utils -- ------------------------------------------------------------ diff --git a/cabal-install/src/Distribution/Client/SetupWrapper.hs b/cabal-install/src/Distribution/Client/SetupWrapper.hs index 8a9b1c01707..b3174c96751 100644 --- a/cabal-install/src/Distribution/Client/SetupWrapper.hs +++ b/cabal-install/src/Distribution/Client/SetupWrapper.hs @@ -88,9 +88,11 @@ import Distribution.Simple.Program , ghcjsProgram , runDbProgram ) +import Distribution.Simple.Program.Db + ( prependProgramSearchPath + ) import Distribution.Simple.Program.Find - ( ProgramSearchPathEntry (ProgramSearchPathDir) - , programSearchPathAsPATHVar + ( programSearchPathAsPATHVar ) import Distribution.Simple.Program.Run ( getEffectiveEnvironment @@ -537,11 +539,11 @@ invoke verbosity path args options = do Nothing -> return () Just logHandle -> info verbosity $ "Redirecting build log to " ++ show logHandle + progDb <- prependProgramSearchPath verbosity (useExtraPathEnv options) (useProgramDb options) + searchpath <- - programSearchPathAsPATHVar - ( map ProgramSearchPathDir (useExtraPathEnv options) - ++ getProgramSearchPath (useProgramDb options) - ) + programSearchPathAsPATHVar $ getProgramSearchPath progDb + env <- getEffectiveEnvironment $ [ ("PATH", Just searchpath) diff --git a/cabal-install/src/Distribution/Client/SourceFiles.hs b/cabal-install/src/Distribution/Client/SourceFiles.hs index ddff8dad99f..f8fdcdcc9f9 100644 --- a/cabal-install/src/Distribution/Client/SourceFiles.hs +++ b/cabal-install/src/Distribution/Client/SourceFiles.hs @@ -167,8 +167,8 @@ needBuildInfo :: PackageDescription -> BuildInfo -> [ModuleName] -> Rebuild () needBuildInfo pkg_descr bi modules = do -- NB: These are separate because there may be both A.hs and -- A.hs-boot; need to track both. - findNeededModules ["hs", "lhs", "hsig", "lhsig"] - findNeededModules ["hs-boot", "lhs-boot"] + findNeededModules builtinHaskellSuffixes + findNeededModules builtinHaskellBootSuffixes root <- askRoot expandedExtraSrcFiles <- liftIO $ fmap concat . for (extraSrcFiles pkg_descr) $ \fpath -> matchDirFileGlobWithDie normal (\_ _ -> return []) (specVersion pkg_descr) root fpath traverse_ needIfExists $ @@ -184,12 +184,12 @@ needBuildInfo pkg_descr bi modules = do findFileMonitored ("." : includeDirs bi) f >>= maybe (return ()) need where - findNeededModules :: [String] -> Rebuild () + findNeededModules :: [Suffix] -> Rebuild () findNeededModules exts = traverse_ (findNeededModule exts) (modules ++ otherModules bi) - findNeededModule :: [String] -> ModuleName -> Rebuild () + findNeededModule :: [Suffix] -> ModuleName -> Rebuild () findNeededModule exts m = findFileWithExtensionMonitored (ppSuffixes knownSuffixHandlers ++ exts) diff --git a/cabal-install/src/Distribution/Client/Store.hs b/cabal-install/src/Distribution/Client/Store.hs index d678e137090..4e7d97d97cc 100644 --- a/cabal-install/src/Distribution/Client/Store.hs +++ b/cabal-install/src/Distribution/Client/Store.hs @@ -26,8 +26,8 @@ import Prelude () import Distribution.Client.DistDirLayout import Distribution.Client.RebuildMonad -import Distribution.Compiler (CompilerId) import Distribution.Package (UnitId, mkUnitId) +import Distribution.Simple.Compiler (Compiler (..)) import Distribution.Simple.Utils ( debug @@ -129,15 +129,15 @@ import GHC.IO.Handle.Lock (hUnlock) -- or replace, i.e. not failing if the db entry already exists. -- | Check if a particular 'UnitId' exists in the store. -doesStoreEntryExist :: StoreDirLayout -> CompilerId -> UnitId -> IO Bool -doesStoreEntryExist StoreDirLayout{storePackageDirectory} compid unitid = - doesDirectoryExist (storePackageDirectory compid unitid) +doesStoreEntryExist :: StoreDirLayout -> Compiler -> UnitId -> IO Bool +doesStoreEntryExist StoreDirLayout{storePackageDirectory} compiler unitid = + doesDirectoryExist (storePackageDirectory compiler unitid) -- | Return the 'UnitId's of all packages\/components already installed in the -- store. -getStoreEntries :: StoreDirLayout -> CompilerId -> Rebuild (Set UnitId) -getStoreEntries StoreDirLayout{storeDirectory} compid = do - paths <- getDirectoryContentsMonitored (storeDirectory compid) +getStoreEntries :: StoreDirLayout -> Compiler -> Rebuild (Set UnitId) +getStoreEntries StoreDirLayout{storeDirectory} compiler = do + paths <- getDirectoryContentsMonitored (storeDirectory compiler) return $! mkEntries paths where mkEntries = @@ -174,7 +174,7 @@ data NewStoreEntryOutcome newStoreEntry :: Verbosity -> StoreDirLayout - -> CompilerId + -> Compiler -> UnitId -> (FilePath -> IO (FilePath, [FilePath])) -- ^ Action to place files. @@ -184,20 +184,20 @@ newStoreEntry newStoreEntry verbosity storeDirLayout@StoreDirLayout{..} - compid + compiler unitid copyFiles register = -- See $concurrency above for an explanation of the concurrency protocol - withTempIncomingDir storeDirLayout compid $ \incomingTmpDir -> do + withTempIncomingDir storeDirLayout compiler $ \incomingTmpDir -> do -- Write all store entry files within the temp dir and return the prefix. (incomingEntryDir, otherFiles) <- copyFiles incomingTmpDir -- Take a lock named after the 'UnitId' in question. - withIncomingUnitIdLock verbosity storeDirLayout compid unitid $ do + withIncomingUnitIdLock verbosity storeDirLayout compiler unitid $ do -- Check for the existence of the final store entry directory. - exists <- doesStoreEntryExist storeDirLayout compid unitid + exists <- doesStoreEntryExist storeDirLayout compiler unitid if exists then -- If the entry exists then we lost the race and we must abandon, @@ -217,7 +217,7 @@ newStoreEntry -- Atomically rename the temp dir to the final store entry location. renameDirectory incomingEntryDir finalEntryDir for_ otherFiles $ \file -> do - let finalStoreFile = storeDirectory compid makeRelative (incomingTmpDir (dropDrive (storeDirectory compid))) file + let finalStoreFile = storeDirectory compiler makeRelative (incomingTmpDir (dropDrive (storeDirectory compiler))) file createDirectoryIfMissing True (takeDirectory finalStoreFile) renameFile file finalStoreFile @@ -225,64 +225,67 @@ newStoreEntry "Installed store entry " ++ prettyShow compid prettyShow unitid return UseNewStoreEntry where - finalEntryDir = storePackageDirectory compid unitid + compid = compilerId compiler + + finalEntryDir = storePackageDirectory compiler unitid withTempIncomingDir :: StoreDirLayout - -> CompilerId + -> Compiler -> (FilePath -> IO a) -> IO a -withTempIncomingDir StoreDirLayout{storeIncomingDirectory} compid action = do +withTempIncomingDir StoreDirLayout{storeIncomingDirectory} compiler action = do createDirectoryIfMissing True incomingDir withTempDirectory silent incomingDir "new" action where - incomingDir = storeIncomingDirectory compid + incomingDir = storeIncomingDirectory compiler withIncomingUnitIdLock :: Verbosity -> StoreDirLayout - -> CompilerId + -> Compiler -> UnitId -> IO a -> IO a withIncomingUnitIdLock verbosity StoreDirLayout{storeIncomingLock} - compid + compiler unitid action = bracket takeLock releaseLock (\_hnd -> action) where + compid = compilerId compiler #ifdef MIN_VERSION_lukko - takeLock - | fileLockingSupported = do - fd <- fdOpen (storeIncomingLock compid unitid) - gotLock <- fdTryLock fd ExclusiveLock - unless gotLock $ do - info verbosity $ "Waiting for file lock on store entry " - ++ prettyShow compid prettyShow unitid - fdLock fd ExclusiveLock - return fd + takeLock + | fileLockingSupported = do + fd <- fdOpen (storeIncomingLock compiler unitid) + gotLock <- fdTryLock fd ExclusiveLock + unless gotLock $ do + info verbosity $ "Waiting for file lock on store entry " + ++ prettyShow compid prettyShow unitid + fdLock fd ExclusiveLock + return fd - -- if there's no locking, do nothing. Be careful on AIX. - | otherwise = return undefined -- :( + -- if there's no locking, do nothing. Be careful on AIX. + | otherwise = return undefined -- :( - releaseLock fd - | fileLockingSupported = do - fdUnlock fd - fdClose fd - | otherwise = return () + releaseLock fd + | fileLockingSupported = do + fdUnlock fd + fdClose fd + | otherwise = return () #else - takeLock = do - h <- openFile (storeIncomingLock compid unitid) ReadWriteMode - -- First try non-blocking, but if we would have to wait then - -- log an explanation and do it again in blocking mode. - gotlock <- hTryLock h ExclusiveLock - unless gotlock $ do - info verbosity $ "Waiting for file lock on store entry " - ++ prettyShow compid prettyShow unitid - hLock h ExclusiveLock - return h + takeLock = do + h <- openFile (storeIncomingLock compiler unitid) ReadWriteMode + -- First try non-blocking, but if we would have to wait then + -- log an explanation and do it again in blocking mode. + gotlock <- hTryLock h ExclusiveLock + unless gotlock $ do + info verbosity $ "Waiting for file lock on store entry " + ++ prettyShow compid prettyShow unitid + hLock h ExclusiveLock + return h - releaseLock h = hUnlock h >> hClose h + releaseLock h = hUnlock h >> hClose h #endif diff --git a/cabal-install/src/Distribution/Client/Tar.hs b/cabal-install/src/Distribution/Client/Tar.hs index 313821a6b1a..4c5957d89d3 100644 --- a/cabal-install/src/Distribution/Client/Tar.hs +++ b/cabal-install/src/Distribution/Client/Tar.hs @@ -19,7 +19,7 @@ module Distribution.Client.Tar ( -- * @tar.gz@ operations createTarGzFile - , extractTarGzFile + , TarComp.extractTarGzFile -- * Other local utils , buildTreeRefTypeCode @@ -34,11 +34,10 @@ import Distribution.Client.Compat.Prelude import Prelude () import qualified Codec.Archive.Tar as Tar -import qualified Codec.Archive.Tar.Check as Tar import qualified Codec.Archive.Tar.Entry as Tar import qualified Codec.Compression.GZip as GZip import qualified Data.ByteString.Lazy as BS -import qualified Distribution.Client.GZipUtils as GZipUtils +import qualified Distribution.Client.Compat.Tar as TarComp -- for foldEntries... import Control.Exception (throw) @@ -60,32 +59,6 @@ createTarGzFile createTarGzFile tar base dir = BS.writeFile tar . GZip.compress . Tar.write =<< Tar.pack base [dir] -extractTarGzFile - :: FilePath - -- ^ Destination directory - -> FilePath - -- ^ Expected subdir (to check for tarbombs) - -> FilePath - -- ^ Tarball - -> IO () -extractTarGzFile dir expected tar = - Tar.unpack dir - . Tar.checkTarbomb expected - . Tar.read - . GZipUtils.maybeDecompress - =<< BS.readFile tar - -instance (Exception a, Exception b) => Exception (Either a b) where - toException (Left e) = toException e - toException (Right e) = toException e - - fromException e = - case fromException e of - Just e' -> Just (Left e') - Nothing -> case fromException e of - Just e' -> Just (Right e') - Nothing -> Nothing - -- | Type code for the local build tree reference entry type. We don't use the -- symbolic link entry type because it allows only 100 ASCII characters for the -- path. diff --git a/cabal-install/src/Distribution/Client/Types/PackageSpecifier.hs b/cabal-install/src/Distribution/Client/Types/PackageSpecifier.hs index 5f25be4aa77..a803a85b429 100644 --- a/cabal-install/src/Distribution/Client/Types/PackageSpecifier.hs +++ b/cabal-install/src/Distribution/Client/Types/PackageSpecifier.hs @@ -5,14 +5,15 @@ module Distribution.Client.Types.PackageSpecifier ( PackageSpecifier (..) , pkgSpecifierTarget , pkgSpecifierConstraints + , mkNamedPackage ) where import Distribution.Client.Compat.Prelude import Prelude () -import Distribution.Package (Package (..), packageName, packageVersion) +import Distribution.Package (Package (..), PackageIdentifier (..), packageName, packageVersion) import Distribution.Types.PackageName (PackageName) -import Distribution.Version (thisVersion) +import Distribution.Version (nullVersion, thisVersion) import Distribution.Solver.Types.ConstraintSource import Distribution.Solver.Types.LabeledPackageConstraint @@ -53,3 +54,12 @@ pkgSpecifierConstraints (SpecificSourcePackage pkg) = PackageConstraint (ScopeTarget $ packageName pkg) (PackagePropertyVersion $ thisVersion (packageVersion pkg)) + +mkNamedPackage :: PackageIdentifier -> PackageSpecifier pkg +mkNamedPackage pkgId = + NamedPackage + (pkgName pkgId) + ( if pkgVersion pkgId == nullVersion + then [] + else [PackagePropertyVersion (thisVersion (pkgVersion pkgId))] + ) diff --git a/cabal-install/src/Distribution/Client/Types/RepoName.hs b/cabal-install/src/Distribution/Client/Types/RepoName.hs index 2eb2fb15fc8..1a9b8012aa9 100644 --- a/cabal-install/src/Distribution/Client/Types/RepoName.hs +++ b/cabal-install/src/Distribution/Client/Types/RepoName.hs @@ -29,7 +29,7 @@ instance Pretty RepoName where -- | -- -- >>> simpleParsec "hackage.haskell.org" :: Maybe RepoName --- Just (RepoName "hackage.haskell.org") +-- Just (RepoName {unRepoName = "hackage.haskell.org"}) -- -- >>> simpleParsec "0123" :: Maybe RepoName -- Nothing diff --git a/cabal-install/src/Distribution/Client/Upload.hs b/cabal-install/src/Distribution/Client/Upload.hs index c7abe8b91e4..6e96fa0eafd 100644 --- a/cabal-install/src/Distribution/Client/Upload.hs +++ b/cabal-install/src/Distribution/Client/Upload.hs @@ -1,7 +1,7 @@ module Distribution.Client.Upload (upload, uploadDoc, report) where import Distribution.Client.Compat.Prelude -import qualified Prelude as Unsafe (head, read, tail) +import qualified Prelude as Unsafe (read) import Distribution.Client.HttpUtils ( HttpTransport (..) @@ -155,11 +155,13 @@ uploadDoc verbosity repoCtxt mToken mUsername mPassword isCandidate path = do break (== '-') (reverse (takeFileName path)) - pkgid = reverse $ Unsafe.tail reversePkgid + pkgid = reverse $ drop 1 reversePkgid when ( reverse reverseSuffix /= "docs.tar.gz" - || null reversePkgid - || Unsafe.head reversePkgid /= '-' + || ( case reversePkgid of + [] -> True + (c : _) -> c /= '-' + ) ) $ dieWithException verbosity ExpectedMatchingFileName diff --git a/cabal-install/src/Distribution/Client/Utils.hs b/cabal-install/src/Distribution/Client/Utils.hs index 59158ffd2a5..f5a10da789a 100644 --- a/cabal-install/src/Distribution/Client/Utils.hs +++ b/cabal-install/src/Distribution/Client/Utils.hs @@ -28,7 +28,6 @@ module Distribution.Client.Utils , existsAndIsMoreRecentThan , tryFindAddSourcePackageDesc , tryFindPackageDesc - , findOpenProgramLocation , relaxEncodingErrors , ProgressPhase (..) , progressMessage @@ -69,13 +68,11 @@ import Distribution.Compat.Environment import Distribution.Compat.Time (getModTime) import Distribution.Simple.Setup (Flag (..)) import Distribution.Simple.Utils (dieWithException, findPackageDesc, noticeNoWrap) -import Distribution.System (OS (..), Platform (..)) import Distribution.Version import System.Directory ( canonicalizePath , doesDirectoryExist , doesFileExist - , findExecutable , getCurrentDirectory , getDirectoryContents , removeFile @@ -397,26 +394,6 @@ tryFindPackageDesc verbosity depPath err = do Right file -> return file Left _ -> dieWithException verbosity $ TryFindPackageDescErr err -findOpenProgramLocation :: Platform -> IO (Either String FilePath) -findOpenProgramLocation (Platform _ os) = - let - locate name = do - exe <- findExecutable name - case exe of - Just s -> pure (Right s) - Nothing -> pure (Left ("Couldn't find file-opener program `" <> name <> "`")) - xdg = locate "xdg-open" - in - case os of - Windows -> pure (Right "start") - OSX -> locate "open" - Linux -> xdg - FreeBSD -> xdg - OpenBSD -> xdg - NetBSD -> xdg - DragonFly -> xdg - _ -> pure (Left ("Couldn't determine file-opener program for " <> show os)) - -- | Phase of building a dependency. Represents current status of package -- dependency processing. See #4040 for details. data ProgressPhase diff --git a/cabal-install/src/Distribution/Client/VCS.hs b/cabal-install/src/Distribution/Client/VCS.hs index 7322253e692..7c071de31eb 100644 --- a/cabal-install/src/Distribution/Client/VCS.hs +++ b/cabal-install/src/Distribution/Client/VCS.hs @@ -61,6 +61,9 @@ import Distribution.Simple.Program , runProgramInvocation , simpleProgram ) +import Distribution.Simple.Program.Db + ( prependProgramSearchPath + ) import Distribution.Types.SourceRepo ( KnownRepoType (..) , RepoType (..) @@ -198,18 +201,23 @@ validateSourceRepos rs = configureVCS :: Verbosity + -> [FilePath] + -- ^ Extra prog paths -> VCS Program -> IO (VCS ConfiguredProgram) -configureVCS verbosity vcs@VCS{vcsProgram = prog} = - asVcsConfigured <$> requireProgram verbosity prog emptyProgramDb +configureVCS verbosity progPaths vcs@VCS{vcsProgram = prog} = do + progPath <- prependProgramSearchPath verbosity progPaths emptyProgramDb + asVcsConfigured <$> requireProgram verbosity prog progPath where asVcsConfigured (prog', _) = vcs{vcsProgram = prog'} configureVCSs :: Verbosity + -> [FilePath] + -- ^ Extra prog paths -> Map RepoType (VCS Program) -> IO (Map RepoType (VCS ConfiguredProgram)) -configureVCSs verbosity = traverse (configureVCS verbosity) +configureVCSs verbosity progPaths = traverse (configureVCS verbosity progPaths) -- ------------------------------------------------------------ diff --git a/cabal-install/src/Distribution/Client/Version.hs b/cabal-install/src/Distribution/Client/Version.hs index dc06552350f..f5c6bec510d 100644 --- a/cabal-install/src/Distribution/Client/Version.hs +++ b/cabal-install/src/Distribution/Client/Version.hs @@ -5,11 +5,9 @@ module Distribution.Client.Version import Distribution.Version --- This value determines the `cabal-install --version` output. --- --- It is used in several places throughout the project, including anonymous build reports, client configuration, --- and project planning output. Historically, this was a @Paths_*@ module, however, this conflicted with --- program coverage information generated by HPC, and hence was moved to be a standalone value. --- +import qualified Paths_cabal_install as PackageInfo + +-- | +-- This value determines the output of `cabal-install --version`. cabalInstallVersion :: Version -cabalInstallVersion = mkVersion [3, 11] +cabalInstallVersion = mkVersion' PackageInfo.version diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs index bf6e25c5b87..55ea3747b9f 100644 --- a/cabal-install/tests/IntegrationTests2.hs +++ b/cabal-install/tests/IntegrationTests2.hs @@ -80,7 +80,6 @@ import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.Options import Data.Tagged (Tagged(..)) -import qualified Data.List as L import qualified Data.ByteString as BS import Distribution.Client.GlobalFlags (GlobalFlags, globalNix) @@ -2180,9 +2179,10 @@ testConfigOptionComments = do where -- | Find lines containing a target string. findLineWith :: Bool -> String -> String -> String - findLineWith isComment target text - | not . null $ findLinesWith isComment target text = removeCommentValue . L.head $ findLinesWith isComment target text - | otherwise = text + findLineWith isComment target text = + case findLinesWith isComment target text of + [] -> text + (l : _) -> removeCommentValue l findLinesWith :: Bool -> String -> String -> [String] findLinesWith isComment target | isComment = filter (isInfixOf (" " ++ target ++ ":")) . lines diff --git a/cabal-install/tests/IntegrationTests2/.gitignore b/cabal-install/tests/IntegrationTests2/.gitignore new file mode 100644 index 00000000000..7df6974cf10 --- /dev/null +++ b/cabal-install/tests/IntegrationTests2/.gitignore @@ -0,0 +1 @@ +config/default-config diff --git a/cabal-install/tests/IntegrationTests2/build/ignore-project/cabal.project b/cabal-install/tests/IntegrationTests2/build/ignore-project/cabal.project index 3b1b4b67d20..f704d26df20 100644 --- a/cabal-install/tests/IntegrationTests2/build/ignore-project/cabal.project +++ b/cabal-install/tests/IntegrationTests2/build/ignore-project/cabal.project @@ -1,3 +1,3 @@ packages: . -coverage: true \ No newline at end of file +coverage: true diff --git a/cabal-install/tests/IntegrationTests2/config/default-config b/cabal-install/tests/IntegrationTests2/config/default-config deleted file mode 100644 index 7ea0ac65d56..00000000000 --- a/cabal-install/tests/IntegrationTests2/config/default-config +++ /dev/null @@ -1,247 +0,0 @@ --- This is the configuration file for the 'cabal' command line tool. --- --- The available configuration options are listed below. --- Some of them have default values listed. --- --- Lines (like this one) beginning with '--' are comments. --- Be careful with spaces and indentation because they are --- used to indicate layout for nested sections. --- --- This config file was generated using the following versions --- of Cabal and cabal-install: --- Cabal library version: 3.11.0.0 --- cabal-install version: 3.11 - - -repository hackage.haskell.org - url: http://hackage.haskell.org/ - -- secure: True - -- root-keys: - -- key-threshold: 3 - --- ignore-expiry: False --- http-transport: --- nix: --- store-dir: --- active-repositories: --- local-no-index-repo: -remote-repo-cache: /home/colton/.cabal/packages --- logs-dir: /home/colton/.cabal/logs --- default-user-config: --- verbose: 1 --- compiler: ghc --- cabal-file: --- with-compiler: --- with-hc-pkg: --- program-prefix: --- program-suffix: --- library-vanilla: True --- library-profiling: --- shared: --- static: --- executable-dynamic: False --- executable-static: False --- profiling: --- executable-profiling: --- profiling-detail: --- library-profiling-detail: --- optimization: True --- debug-info: False --- build-info: --- library-for-ghci: --- split-sections: False --- split-objs: False --- executable-stripping: --- library-stripping: --- configure-option: --- user-install: True --- package-db: --- flags: --- extra-include-dirs: --- deterministic: --- cid: --- extra-lib-dirs: --- extra-lib-dirs-static: --- extra-framework-dirs: --- extra-prog-path: --- instantiate-with: --- tests: False --- coverage: False --- library-coverage: --- exact-configuration: False --- benchmarks: False --- relocatable: False --- response-files: --- allow-depending-on-private-libs: --- cabal-lib-version: --- append: --- backup: --- constraint: --- preference: --- solver: modular --- allow-older: False --- allow-newer: False --- write-ghc-environment-files: --- documentation: False --- doc-index-file: $datadir/doc/$arch-$os-$compiler/index.html --- only-download: False --- target-package-db: --- max-backjumps: 4000 --- reorder-goals: False --- count-conflicts: True --- fine-grained-conflicts: True --- minimize-conflict-set: False --- independent-goals: False --- prefer-oldest: False --- shadow-installed-packages: False --- strong-flags: False --- allow-boot-library-installs: False --- reject-unconstrained-dependencies: none --- reinstall: False --- avoid-reinstalls: False --- force-reinstalls: False --- upgrade-dependencies: False --- index-state: --- root-cmd: --- symlink-bindir: -build-summary: /home/colton/.cabal/logs/build.log --- build-log: -remote-build-reporting: none --- report-planning-failure: False --- per-component: True --- run-tests: -jobs: $ncpus --- keep-going: False --- offline: False --- lib: False --- package-env: --- overwrite-policy: --- install-method: -installdir: /home/colton/.cabal/bin --- token: --- username: --- password: --- password-command: --- builddir: - -haddock - -- keep-temp-files: False - -- hoogle: False - -- html: False - -- html-location: - -- executables: False - -- tests: False - -- benchmarks: False - -- foreign-libraries: False - -- all: - -- internal: False - -- css: - -- hyperlink-source: False - -- quickjump: False - -- hscolour-css: - -- contents-location: - -- index-location: - -- base-url: - -- lib: - -- output-dir: - -init - -- interactive: False - -- quiet: False - -- no-comments: False - -- minimal: False - -- cabal-version: 3.0 - -- license: - -- extra-doc-file: - -- tests: - -- test-dir: - -- simple: False - -- language: Haskell2010 - -- application-dir: app - -- source-dir: src - -install-dirs user - -- prefix: /home/colton/.cabal - -- bindir: $prefix/bin - -- libdir: $prefix/lib - -- libsubdir: $abi/$libname - -- dynlibdir: $libdir/$abi - -- libexecdir: $prefix/libexec - -- libexecsubdir: $abi/$pkgid - -- datadir: $prefix/share - -- datasubdir: $abi/$pkgid - -- docdir: $datadir/doc/$abi/$pkgid - -- htmldir: $docdir/html - -- haddockdir: $htmldir - -- sysconfdir: $prefix/etc - -install-dirs global - -- prefix: /usr/local - -- bindir: $prefix/bin - -- libdir: $prefix/lib - -- libsubdir: $abi/$libname - -- dynlibdir: $libdir/$abi - -- libexecdir: $prefix/libexec - -- libexecsubdir: $abi/$pkgid - -- datadir: $prefix/share - -- datasubdir: $abi/$pkgid - -- docdir: $datadir/doc/$abi/$pkgid - -- htmldir: $docdir/html - -- haddockdir: $htmldir - -- sysconfdir: $prefix/etc - -program-locations - -- alex-location: - -- ar-location: - -- c2hs-location: - -- cpphs-location: - -- doctest-location: - -- gcc-location: - -- ghc-location: - -- ghc-pkg-location: - -- ghcjs-location: - -- ghcjs-pkg-location: - -- greencard-location: - -- haddock-location: - -- happy-location: - -- haskell-suite-location: - -- haskell-suite-pkg-location: - -- hmake-location: - -- hpc-location: - -- hsc2hs-location: - -- hscolour-location: - -- jhc-location: - -- ld-location: - -- pkg-config-location: - -- runghc-location: - -- strip-location: - -- tar-location: - -- uhc-location: - -program-default-options - -- alex-options: - -- ar-options: - -- c2hs-options: - -- cpphs-options: - -- doctest-options: - -- gcc-options: - -- ghc-options: - -- ghc-pkg-options: - -- ghcjs-options: - -- ghcjs-pkg-options: - -- greencard-options: - -- haddock-options: - -- happy-options: - -- haskell-suite-options: - -- haskell-suite-pkg-options: - -- hmake-options: - -- hpc-options: - -- hsc2hs-options: - -- hscolour-options: - -- jhc-options: - -- ld-options: - -- pkg-config-options: - -- runghc-options: - -- strip-options: - -- tar-options: - -- uhc-options: diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs b/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs index bcd6e4134d1..6acc63072d1 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ArbitraryInstances.hs @@ -32,7 +32,7 @@ import Distribution.Types.Flag (mkFlagAssignment) import Distribution.Client.BuildReports.Types (BuildReport, InstallOutcome, Outcome, ReportLevel (..)) import Distribution.Client.CmdInstall.ClientInstallFlags (InstallMethod) -import Distribution.Client.Glob (FilePathGlob (..), FilePathGlobRel (..), FilePathRoot (..), GlobPiece (..)) +import Distribution.Client.Glob (FilePathRoot (..), Glob (..), GlobPiece (..), RootedGlob (..)) import Distribution.Client.IndexUtils.ActiveRepos (ActiveRepoEntry (..), ActiveRepos (..), CombineStrategy (..)) import Distribution.Client.IndexUtils.IndexState (RepoIndexState (..), TotalIndexState, makeTotalIndexState) import Distribution.Client.IndexUtils.Timestamp (Timestamp, epochTimeToTimestamp) @@ -184,7 +184,7 @@ instance Arbitrary Timestamp where -- >>> utcTimeToPOSIXSeconds $ UTCTime (fromGregorian 100000 01 01) 0 -- >>> 3093527980800s -- - arbitrary = maybe (toEnum 0) id . epochTimeToTimestamp . (`mod` 3093527980800) . abs <$> arbitrary + arbitrary = epochTimeToTimestamp . (`mod` 3093527980800) . abs <$> arbitrary instance Arbitrary RepoIndexState where arbitrary = @@ -344,19 +344,19 @@ instance Arbitrary Outcome where -- Glob ------------------------------------------------------------------------------- -instance Arbitrary FilePathGlob where +instance Arbitrary RootedGlob where arbitrary = - (FilePathGlob <$> arbitrary <*> arbitrary) + (RootedGlob <$> arbitrary <*> arbitrary) `suchThat` validFilePathGlob - shrink (FilePathGlob root pathglob) = - [ FilePathGlob root' pathglob' + shrink (RootedGlob root pathglob) = + [ RootedGlob root' pathglob' | (root', pathglob') <- shrink (root, pathglob) - , validFilePathGlob (FilePathGlob root' pathglob') + , validFilePathGlob (RootedGlob root' pathglob') ] -validFilePathGlob :: FilePathGlob -> Bool -validFilePathGlob (FilePathGlob FilePathRelative pathglob) = +validFilePathGlob :: RootedGlob -> Bool +validFilePathGlob (RootedGlob FilePathRelative pathglob) = case pathglob of GlobDirTrailing -> False GlobDir [Literal "~"] _ -> False @@ -381,7 +381,7 @@ instance Arbitrary FilePathRoot where shrink (FilePathRoot _) = [FilePathRelative] shrink FilePathHomeDir = [FilePathRelative] -instance Arbitrary FilePathGlobRel where +instance Arbitrary Glob where arbitrary = sized $ \sz -> oneof $ take @@ -403,6 +403,9 @@ instance Arbitrary FilePathGlobRel where : [ GlobDir (getGlobPieces glob') pathglob' | (glob', pathglob') <- shrink (GlobPieces glob, pathglob) ] + shrink (GlobDirRecursive glob) = + GlobDirTrailing + : [GlobFile (getGlobPieces glob') | glob' <- shrink (GlobPieces glob)] newtype GlobPieces = GlobPieces {getGlobPieces :: [GlobPiece]} deriving (Eq) diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Configure.hs b/cabal-install/tests/UnitTests/Distribution/Client/Configure.hs index c570d7a738a..52a23a80ef2 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Configure.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Configure.hs @@ -23,13 +23,22 @@ tests = [ configureTests ] +defaultTestFlags :: NixStyleFlags () +defaultTestFlags = + (defaultNixStyleFlags ()) + { projectFlags = + mempty + { flagProjectDir = Flag projectDir + } + } + configureTests :: TestTree configureTests = testGroup "Configure tests" [ testCase "New config" $ do let flags = - (defaultNixStyleFlags ()) + defaultTestFlags { configFlags = mempty { configOptimization = Flag MaximumOptimisation @@ -42,7 +51,7 @@ configureTests = @=? (packageConfigOptimization . projectConfigLocalPackages $ snd projConfig) , testCase "Replacement + new config" $ do let flags = - (defaultNixStyleFlags ()) + defaultTestFlags { configExFlags = mempty { configAppend = Flag True @@ -52,10 +61,6 @@ configureTests = { configOptimization = Flag NoOptimisation , configVerbosity = Flag silent } - , projectFlags = - mempty - { flagProjectDir = Flag projectDir - } } (_, ProjectConfig{..}) <- configureAction' flags [] defaultGlobalFlags @@ -63,7 +68,7 @@ configureTests = Flag silent @=? projectConfigVerbosity projectConfigBuildOnly , testCase "Old + new config" $ do let flags = - (defaultNixStyleFlags ()) + defaultTestFlags { configExFlags = mempty { configAppend = Flag True @@ -72,10 +77,6 @@ configureTests = mempty { configVerbosity = Flag silent } - , projectFlags = - mempty - { flagProjectDir = Flag projectDir - } } (_, ProjectConfig{..}) <- configureAction' flags [] defaultGlobalFlags @@ -83,15 +84,11 @@ configureTests = Flag silent @=? projectConfigVerbosity projectConfigBuildOnly , testCase "Old + new config, no appending" $ do let flags = - (defaultNixStyleFlags ()) + defaultTestFlags { configFlags = mempty { configVerbosity = Flag silent } - , projectFlags = - mempty - { flagProjectDir = Flag projectDir - } } (_, ProjectConfig{..}) <- configureAction' flags [] defaultGlobalFlags @@ -99,15 +96,11 @@ configureTests = Flag silent @=? projectConfigVerbosity projectConfigBuildOnly , testCase "Old + new config, backup check" $ do let flags = - (defaultNixStyleFlags ()) + defaultTestFlags { configFlags = mempty { configVerbosity = Flag silent } - , projectFlags = - mempty - { flagProjectDir = Flag projectDir - } } backup = projectDir "cabal.project.local~" @@ -122,16 +115,12 @@ configureTests = , testCase "Local program options" $ do let ghcFlags = ["-fno-full-laziness"] flags = - (defaultNixStyleFlags ()) + defaultTestFlags { configFlags = mempty { configVerbosity = Flag silent , configProgramArgs = [("ghc", ghcFlags)] } - , projectFlags = - mempty - { flagProjectDir = Flag projectDir - } } (_, ProjectConfig{..}) <- configureAction' flags [] defaultGlobalFlags diff --git a/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs b/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs index 66b9649db11..7e52d25173f 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/DescribedInstances.hs @@ -13,7 +13,7 @@ import Distribution.Types.PackageName (PackageName) import Distribution.Types.VersionRange (VersionRange) import Distribution.Client.BuildReports.Types (InstallOutcome, Outcome) -import Distribution.Client.Glob (FilePathGlob) +import Distribution.Client.Glob (RootedGlob) import Distribution.Client.IndexUtils.ActiveRepos (ActiveRepoEntry, ActiveRepos, CombineStrategy) import Distribution.Client.IndexUtils.IndexState (RepoIndexState, TotalIndexState) import Distribution.Client.IndexUtils.Timestamp (Timestamp) @@ -51,7 +51,7 @@ instance Described Outcome where ------------------------------------------------------------------------------- -- This instance is incorrect as it may generate C:\dir\{foo,bar} -instance Described FilePathGlob where +instance Described RootedGlob where describe _ = REUnion [root, relative, homedir] where root = diff --git a/cabal-install/tests/UnitTests/Distribution/Client/FetchUtils.hs b/cabal-install/tests/UnitTests/Distribution/Client/FetchUtils.hs index 4131f01a70c..c14682c2bcb 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/FetchUtils.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/FetchUtils.hs @@ -16,12 +16,12 @@ import Distribution.Client.Types.Repo (Repo (..), emptyRemoteRepo) import Distribution.Client.Types.RepoName (RepoName (..)) import Distribution.Types.PackageId (PackageIdentifier (..)) import Distribution.Types.PackageName (mkPackageName) -import Distribution.Utils.TempTestDir (withTestDir) import qualified Distribution.Verbosity as Verbosity import Distribution.Version (mkVersion) import Network.URI (URI, uriPath) import Test.Tasty import Test.Tasty.HUnit +import Test.Utils.TempTestDir (withTestDir) tests :: [TestTree] tests = diff --git a/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs b/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs index 39f508040c3..f3c8145bc49 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/FileMonitor.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE CPP #-} + module UnitTests.Distribution.Client.FileMonitor (tests) where import Distribution.Parsec (simpleParsec) @@ -31,8 +33,8 @@ tests mtimeChange = [ testGroup "Structured hashes" [ testCase "MonitorStateFile" $ structureHash (Proxy :: Proxy MonitorStateFile) @?= Fingerprint 0xe4108804c34962f6 0x06e94f8fc9e48e13 - , testCase "MonitorStateGlob" $ structureHash (Proxy :: Proxy MonitorStateGlob) @?= Fingerprint 0xfd8f6be0e8258fe7 0xdb5fac737139bca6 - , testCase "MonitorStateFileSet" $ structureHash (Proxy :: Proxy MonitorStateFileSet) @?= Fingerprint 0xb745f4ea498389a5 0x70db6adb5078aa27 + , testCase "MonitorStateGlob" $ structureHash (Proxy :: Proxy MonitorStateGlob) @?= Fingerprint fingerprintStateGlob1 fingerprintStateGlob2 + , testCase "MonitorStateFileSet" $ structureHash (Proxy :: Proxy MonitorStateFileSet) @?= Fingerprint fingerprintStateFileSet1 fingerprintStateFileSet2 ] , testCase "sanity check mtimes" $ testFileMTimeSanity mtimeChange , testCase "sanity check dirs" $ testDirChangeSanity mtimeChange @@ -85,6 +87,18 @@ tests mtimeChange = knownBrokenInWindows msg = case buildOS of Windows -> expectFailBecause msg _ -> id + fingerprintStateGlob1, fingerprintStateGlob2, fingerprintStateFileSet1, fingerprintStateFileSet2 :: Word64 +#if MIN_VERSION_base(4,19,0) + fingerprintStateGlob1 = 0x4ebc6a7d12bb2132 + fingerprintStateGlob2 = 0x2c2292eeda0a9319 + fingerprintStateFileSet1 = 0x01df5796f9030851 + fingerprintStateFileSet2 = 0x2f5c472be17bee98 +#else + fingerprintStateGlob1 = 0xf32c0d1644dd9ee5 + fingerprintStateGlob2 = 0x0f2494f7b6031fb6 + fingerprintStateFileSet1 = 0x06d4a13275c24282 + fingerprintStateFileSet2 = 0x791b2a88684b5f37 +#endif -- Check the file system behaves the way we expect it to diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Get.hs b/cabal-install/tests/UnitTests/Distribution/Client/Get.hs index fadca21d0cb..c033c05f93a 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Get.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Get.hs @@ -20,9 +20,9 @@ import System.Exit import System.FilePath import System.IO.Error -import Distribution.Utils.TempTestDir (withTestDir) import Test.Tasty import Test.Tasty.HUnit +import Test.Utils.TempTestDir (withTestDir) import UnitTests.Options (RunNetworkTests (..)) tests :: [TestTree] @@ -64,7 +64,7 @@ testNoRepos :: Assertion testNoRepos = do e <- assertException $ - clonePackagesFromSourceRepo verbosity "." Nothing pkgrepos + clonePackagesFromSourceRepo verbosity "." Nothing [] pkgrepos e @?= ClonePackageNoSourceRepos pkgidfoo where pkgrepos = [(pkgidfoo, [])] @@ -73,7 +73,7 @@ testNoReposOfKind :: Assertion testNoReposOfKind = do e <- assertException $ - clonePackagesFromSourceRepo verbosity "." repokind pkgrepos + clonePackagesFromSourceRepo verbosity "." repokind [] pkgrepos e @?= ClonePackageNoSourceReposOfKind pkgidfoo repokind where pkgrepos = [(pkgidfoo, [repo])] @@ -84,7 +84,7 @@ testNoRepoType :: Assertion testNoRepoType = do e <- assertException $ - clonePackagesFromSourceRepo verbosity "." Nothing pkgrepos + clonePackagesFromSourceRepo verbosity "." Nothing [] pkgrepos e @?= ClonePackageNoRepoType pkgidfoo repo where pkgrepos = [(pkgidfoo, [repo])] @@ -94,7 +94,7 @@ testUnsupportedRepoType :: Assertion testUnsupportedRepoType = do e <- assertException $ - clonePackagesFromSourceRepo verbosity "." Nothing pkgrepos + clonePackagesFromSourceRepo verbosity "." Nothing [] pkgrepos e @?= ClonePackageUnsupportedRepoType pkgidfoo repo' repotype where pkgrepos = [(pkgidfoo, [repo])] @@ -118,7 +118,7 @@ testNoRepoLocation :: Assertion testNoRepoLocation = do e <- assertException $ - clonePackagesFromSourceRepo verbosity "." Nothing pkgrepos + clonePackagesFromSourceRepo verbosity "." Nothing [] pkgrepos e @?= ClonePackageNoRepoLocation pkgidfoo repo where pkgrepos = [(pkgidfoo, [repo])] @@ -139,7 +139,7 @@ testSelectRepoKind = e' @?= ClonePackageNoRepoType pkgidfoo expectedRepo | let test rt rs = assertException $ - clonePackagesFromSourceRepo verbosity "." rt rs + clonePackagesFromSourceRepo verbosity "." rt [] rs , (requestedRepoType, expectedRepo) <- cases ] where @@ -161,14 +161,14 @@ testRepoDestinationExists = createDirectory pkgdir e1 <- assertException $ - clonePackagesFromSourceRepo verbosity tmpdir Nothing pkgrepos + clonePackagesFromSourceRepo verbosity tmpdir Nothing [] pkgrepos e1 @?= ClonePackageDestinationExists pkgidfoo pkgdir True {- isdir -} removeDirectory pkgdir writeFile pkgdir "" e2 <- assertException $ - clonePackagesFromSourceRepo verbosity tmpdir Nothing pkgrepos + clonePackagesFromSourceRepo verbosity tmpdir Nothing [] pkgrepos e2 @?= ClonePackageDestinationExists pkgidfoo pkgdir False {- isfile -} where pkgrepos = [(pkgidfoo, [repo])] @@ -199,7 +199,7 @@ testGitFetchFailed = pkgrepos = [(pkgidfoo, [repo])] e1 <- assertException $ - clonePackagesFromSourceRepo verbosity tmpdir Nothing pkgrepos + clonePackagesFromSourceRepo verbosity tmpdir Nothing [] pkgrepos e1 @?= ClonePackageFailedWithExitCode pkgidfoo repo' "git" (ExitFailure 128) testNetworkGitClone :: Assertion @@ -214,6 +214,7 @@ testNetworkGitClone = verbosity tmpdir Nothing + [] [(mkpkgid "zlib1", [repo1])] assertFileContains (tmpdir "zlib1/zlib.cabal") ["name:", "zlib"] @@ -226,6 +227,7 @@ testNetworkGitClone = verbosity tmpdir Nothing + [] [(mkpkgid "zlib2", [repo2])] assertFileContains (tmpdir "zlib2/zlib.cabal") ["name:", "zlib"] @@ -239,6 +241,7 @@ testNetworkGitClone = verbosity tmpdir Nothing + [] [(mkpkgid "zlib3", [repo3])] assertFileContains (tmpdir "zlib3/zlib.cabal") ["version:", "0.5.0.0"] where diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Glob.hs b/cabal-install/tests/UnitTests/Distribution/Client/Glob.hs index 8d77b6784ef..c51ce7e2448 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Glob.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Glob.hs @@ -22,16 +22,16 @@ tests = , testGroup "Structured hashes" [ testCase "GlobPiece" $ structureHash (Proxy :: Proxy GlobPiece) @?= Fingerprint 0xd5e5361866a30ea2 0x31fbfe7b58864782 - , testCase "FilePathGlobRel" $ structureHash (Proxy :: Proxy FilePathGlobRel) @?= Fingerprint 0x76fa5bcb865a8501 0xb152f68915316f98 + , testCase "Glob" $ structureHash (Proxy :: Proxy Glob) @?= Fingerprint 0x3a5af41e8194eaa3 0xd8e461fdfdb0e07b , testCase "FilePathRoot" $ structureHash (Proxy :: Proxy FilePathRoot) @?= Fingerprint 0x713373d51426ec64 0xda7376a38ecee5a5 - , testCase "FilePathGlob" $ structureHash (Proxy :: Proxy FilePathGlob) @?= Fingerprint 0x3c11c41f3f03a1f0 0x96e69d85c37d0024 + , testCase "RootedGlob" $ structureHash (Proxy :: Proxy RootedGlob) @?= Fingerprint 0x0031d198379cd1bf 0x7246ab9b6c6e0e7d ] ] -- TODO: [nice to have] tests for trivial globs, tests for matching, -- tests for windows style file paths -prop_roundtrip_printparse :: FilePathGlob -> Property +prop_roundtrip_printparse :: RootedGlob -> Property prop_roundtrip_printparse pathglob = counterexample (prettyShow pathglob) $ eitherParsec (prettyShow pathglob) === Right pathglob @@ -39,35 +39,35 @@ prop_roundtrip_printparse pathglob = -- first run, where we don't even call updateMonitor testParseCases :: Assertion testParseCases = do - FilePathGlob (FilePathRoot "/") GlobDirTrailing <- testparse "/" - FilePathGlob FilePathHomeDir GlobDirTrailing <- testparse "~/" + RootedGlob (FilePathRoot "/") GlobDirTrailing <- testparse "/" + RootedGlob FilePathHomeDir GlobDirTrailing <- testparse "~/" - FilePathGlob (FilePathRoot "A:\\") GlobDirTrailing <- testparse "A:/" - FilePathGlob (FilePathRoot "Z:\\") GlobDirTrailing <- testparse "z:/" - FilePathGlob (FilePathRoot "C:\\") GlobDirTrailing <- testparse "C:\\" - FilePathGlob FilePathRelative (GlobFile [Literal "_:"]) <- testparse "_:" + RootedGlob (FilePathRoot "A:\\") GlobDirTrailing <- testparse "A:/" + RootedGlob (FilePathRoot "Z:\\") GlobDirTrailing <- testparse "z:/" + RootedGlob (FilePathRoot "C:\\") GlobDirTrailing <- testparse "C:\\" + RootedGlob FilePathRelative (GlobFile [Literal "_:"]) <- testparse "_:" - FilePathGlob + RootedGlob FilePathRelative (GlobFile [Literal "."]) <- testparse "." - FilePathGlob + RootedGlob FilePathRelative (GlobFile [Literal "~"]) <- testparse "~" - FilePathGlob + RootedGlob FilePathRelative (GlobDir [Literal "."] GlobDirTrailing) <- testparse "./" - FilePathGlob + RootedGlob FilePathRelative (GlobFile [Literal "foo"]) <- testparse "foo" - FilePathGlob + RootedGlob FilePathRelative ( GlobDir [Literal "foo"] @@ -75,7 +75,7 @@ testParseCases = do ) <- testparse "foo/bar" - FilePathGlob + RootedGlob FilePathRelative ( GlobDir [Literal "foo"] @@ -83,7 +83,7 @@ testParseCases = do ) <- testparse "foo/bar/" - FilePathGlob + RootedGlob (FilePathRoot "/") ( GlobDir [Literal "foo"] @@ -91,7 +91,7 @@ testParseCases = do ) <- testparse "/foo/bar/" - FilePathGlob + RootedGlob (FilePathRoot "C:\\") ( GlobDir [Literal "foo"] @@ -99,26 +99,26 @@ testParseCases = do ) <- testparse "C:\\foo\\bar\\" - FilePathGlob + RootedGlob FilePathRelative (GlobFile [WildCard]) <- testparse "*" - FilePathGlob + RootedGlob FilePathRelative (GlobFile [WildCard, WildCard]) <- testparse "**" -- not helpful but valid - FilePathGlob + RootedGlob FilePathRelative (GlobFile [WildCard, Literal "foo", WildCard]) <- testparse "*foo*" - FilePathGlob + RootedGlob FilePathRelative (GlobFile [Literal "foo", WildCard, Literal "bar"]) <- testparse "foo*bar" - FilePathGlob + RootedGlob FilePathRelative (GlobFile [Union [[WildCard], [Literal "foo"]]]) <- testparse "{*,foo}" @@ -135,7 +135,7 @@ testParseCases = do return () -testparse :: String -> IO FilePathGlob +testparse :: String -> IO RootedGlob testparse s = case eitherParsec s of Right p -> return p @@ -143,6 +143,6 @@ testparse s = parseFail :: String -> Assertion parseFail s = - case eitherParsec s :: Either String FilePathGlob of + case eitherParsec s :: Either String RootedGlob of Right p -> throwIO $ HUnitFailure Nothing ("expected no parse of: " ++ s ++ " -- " ++ show p) Left _ -> return () diff --git a/cabal-install/tests/UnitTests/Distribution/Client/IndexUtils/Timestamp.hs b/cabal-install/tests/UnitTests/Distribution/Client/IndexUtils/Timestamp.hs index 3b53e66c219..29c9fe587e0 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/IndexUtils/Timestamp.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/IndexUtils/Timestamp.hs @@ -23,23 +23,19 @@ tests = prop_timestamp1 :: NonNegative Int -> Bool prop_timestamp1 (NonNegative t0) = Just t == simpleParsec ('@' : show t0) where - t = toEnum t0 :: Timestamp + t = epochTimeToTimestamp $ toEnum t0 :: Timestamp -- test prettyShow/simpleParse roundtrip prop_timestamp2 :: Int -> Bool -prop_timestamp2 t0 - | t /= nullTimestamp = simpleParsec (prettyShow t) == Just t - | otherwise = prettyShow t == "" +prop_timestamp2 t0 = simpleParsec (prettyShow t) == Just t where - t = toEnum t0 :: Timestamp + t = epochTimeToTimestamp $ toEnum t0 :: Timestamp -- test prettyShow against reference impl prop_timestamp3 :: Int -> Bool -prop_timestamp3 t0 - | t /= nullTimestamp = refDisp t == prettyShow t - | otherwise = prettyShow t == "" +prop_timestamp3 t0 = refDisp t == prettyShow t where - t = toEnum t0 :: Timestamp + t = epochTimeToTimestamp $ toEnum t0 :: Timestamp refDisp = maybe undefined (formatTime undefined "%FT%TZ") @@ -47,16 +43,13 @@ prop_timestamp3 t0 -- test utcTimeToTimestamp/timestampToUTCTime roundtrip prop_timestamp4 :: Int -> Bool -prop_timestamp4 t0 - | t /= nullTimestamp = (utcTimeToTimestamp =<< timestampToUTCTime t) == Just t - | otherwise = timestampToUTCTime t == Nothing +prop_timestamp4 t0 = + (utcTimeToTimestamp <$> timestampToUTCTime t) == Just t where - t = toEnum t0 :: Timestamp + t = epochTimeToTimestamp $ toEnum t0 :: Timestamp prop_timestamp5 :: Int -> Bool -prop_timestamp5 t0 - | t /= nullTimestamp = timestampToUTCTime t == Just ut - | otherwise = timestampToUTCTime t == Nothing +prop_timestamp5 t0 = timestampToUTCTime t == Just ut where - t = toEnum t0 :: Timestamp + t = epochTimeToTimestamp $ toEnum t0 :: Timestamp ut = posixSecondsToUTCTime (fromIntegral t0) diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Init/Interactive.hs b/cabal-install/tests/UnitTests/Distribution/Client/Init/Interactive.hs index c0e0bc7dcc8..15714bba952 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Init/Interactive.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Init/Interactive.hs @@ -1014,19 +1014,19 @@ interactiveTests srcDb = [ testNumberedPrompt "Language indices" (`languagePrompt` "test") - [Haskell2010, Haskell98, GHC2021] + [Haskell2010, Haskell98, GHC2021, GHC2024] , testSimplePrompt "Other language" (`languagePrompt` "test") (UnknownLanguage "Haskell2022") - [ "4" + [ "5" , "Haskell2022" ] , testSimplePrompt "Invalid language" (`languagePrompt` "test") (UnknownLanguage "Lang_TS!") - [ "4" + [ "5" , "Lang_TS!" ] ] diff --git a/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs b/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs index b708ea80302..39c719f2e1f 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/InstallPlan.hs @@ -5,7 +5,6 @@ module UnitTests.Distribution.Client.InstallPlan (tests) where import Distribution.Client.Compat.Prelude -import qualified Prelude as Unsafe (tail) import Distribution.Client.InstallPlan (GenericInstallPlan, IsUnit) import qualified Distribution.Client.InstallPlan as InstallPlan @@ -285,7 +284,7 @@ arbitraryAcyclicGraph genNRanks genNPerRank edgeChance = do nranks <- genNRanks rankSizes <- replicateM nranks genNPerRank let rankStarts = scanl (+) 0 rankSizes - rankRanges = drop 1 (zip rankStarts (Unsafe.tail rankStarts)) + rankRanges = drop 1 (zip rankStarts (drop 1 rankStarts)) totalRange = sum rankSizes rankEdges <- traverse (uncurry genRank) rankRanges return $ buildG (0, totalRange - 1) (concat rankEdges) diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Store.hs b/cabal-install/tests/UnitTests/Distribution/Client/Store.hs index 7268b4c8c34..976bd97a4cb 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Store.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Store.hs @@ -9,8 +9,8 @@ import System.FilePath -- import System.Random -import Distribution.Compiler (CompilerFlavor (..), CompilerId (..)) import Distribution.Package (UnitId, mkUnitId) +import Distribution.Simple.Compiler (AbiTag (..), Compiler (..), CompilerFlavor (..), CompilerId (..)) import Distribution.Simple.Utils (withTempDirectory) import Distribution.Verbosity (Verbosity, silent) import Distribution.Version (mkVersion) @@ -34,10 +34,20 @@ testListEmpty = withTempDirectory verbosity "." "store-" $ \tmp -> do let storeDirLayout = defaultStoreDirLayout (tmp "store") - assertStoreEntryExists storeDirLayout compid unitid False - assertStoreContent tmp storeDirLayout compid Set.empty + assertStoreEntryExists storeDirLayout compiler unitid False + assertStoreContent tmp storeDirLayout compiler Set.empty where - compid = CompilerId GHC (mkVersion [1, 0]) + compiler :: Compiler + compiler = + Compiler + { compilerId = CompilerId GHC (mkVersion [1, 0]) + , compilerAbiTag = NoAbiTag + , compilerCompat = [] + , compilerLanguages = [] + , compilerExtensions = [] + , compilerProperties = mempty + } + unitid = mkUnitId "foo-1.0-xyz" testInstallSerial :: Assertion @@ -54,7 +64,7 @@ testInstallSerial = assertNewStoreEntry tmp storeDirLayout - compid + compiler unitid1 (copyFiles "file1" "content-foo") (return ()) @@ -63,7 +73,7 @@ testInstallSerial = assertNewStoreEntry tmp storeDirLayout - compid + compiler unitid1 (copyFiles "file1" "content-foo") (return ()) @@ -72,18 +82,28 @@ testInstallSerial = assertNewStoreEntry tmp storeDirLayout - compid + compiler unitid2 (copyFiles "file2" "content-bar") (return ()) UseNewStoreEntry let pkgDir :: UnitId -> FilePath - pkgDir = storePackageDirectory storeDirLayout compid + pkgDir = storePackageDirectory storeDirLayout compiler assertFileEqual (pkgDir unitid1 "file1") "content-foo" assertFileEqual (pkgDir unitid2 "file2") "content-bar" where - compid = CompilerId GHC (mkVersion [1, 0]) + compiler :: Compiler + compiler = + Compiler + { compilerId = CompilerId GHC (mkVersion [1, 0]) + , compilerAbiTag = NoAbiTag + , compilerCompat = [] + , compilerLanguages = [] + , compilerExtensions = [] + , compilerProperties = mempty + } + unitid1 = mkUnitId "foo-1.0-xyz" unitid2 = mkUnitId "bar-2.0-xyz" @@ -150,7 +170,7 @@ testInstallParallel = assertNewStoreEntry :: FilePath -> StoreDirLayout - -> CompilerId + -> Compiler -> UnitId -> (FilePath -> IO (FilePath, [FilePath])) -> IO () @@ -159,43 +179,43 @@ assertNewStoreEntry assertNewStoreEntry tmp storeDirLayout - compid + compiler unitid copyFiles register expectedOutcome = do - entries <- runRebuild tmp $ getStoreEntries storeDirLayout compid + entries <- runRebuild tmp $ getStoreEntries storeDirLayout compiler outcome <- newStoreEntry verbosity storeDirLayout - compid + compiler unitid copyFiles register assertEqual "newStoreEntry outcome" expectedOutcome outcome - assertStoreEntryExists storeDirLayout compid unitid True + assertStoreEntryExists storeDirLayout compiler unitid True let expected = Set.insert unitid entries - assertStoreContent tmp storeDirLayout compid expected + assertStoreContent tmp storeDirLayout compiler expected assertStoreEntryExists :: StoreDirLayout - -> CompilerId + -> Compiler -> UnitId -> Bool -> Assertion -assertStoreEntryExists storeDirLayout compid unitid expected = do - actual <- doesStoreEntryExist storeDirLayout compid unitid +assertStoreEntryExists storeDirLayout compiler unitid expected = do + actual <- doesStoreEntryExist storeDirLayout compiler unitid assertEqual "store entry exists" expected actual assertStoreContent :: FilePath -> StoreDirLayout - -> CompilerId + -> Compiler -> Set.Set UnitId -> Assertion -assertStoreContent tmp storeDirLayout compid expected = do - actual <- runRebuild tmp $ getStoreEntries storeDirLayout compid +assertStoreContent tmp storeDirLayout compiler expected = do + actual <- runRebuild tmp $ getStoreEntries storeDirLayout compiler assertEqual "store content" actual expected assertFileEqual :: FilePath -> String -> Assertion diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Tar.hs b/cabal-install/tests/UnitTests/Distribution/Client/Tar.hs index 6295de6ace8..8bb8801c04e 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Tar.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Tar.hs @@ -3,13 +3,10 @@ module UnitTests.Distribution.Client.Tar ) where import Codec.Archive.Tar - ( Entries (..) - , foldEntries + ( foldEntries ) import Codec.Archive.Tar.Entry - ( Entry (..) - , EntryContent (..) - , simpleEntry + ( simpleEntry , toTarPath ) import Distribution.Client.Tar @@ -24,6 +21,8 @@ import Control.Monad.Writer.Lazy (runWriterT, tell) import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Lazy.Char8 as BS.Char8 +import Distribution.Client.Compat.Tar + tests :: [TestTree] tests = [ testCase "filterEntries" filterTest diff --git a/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs b/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs index 060dbdffe4f..ac6d96cc159 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/Targets.hs @@ -43,7 +43,10 @@ tests = "readUserConstraints" (uncurry readUserConstraintsTest) [ -- First example only. - (head exampleStrs, take 1 exampleUcs) + + ( case exampleStrs of (e : _) -> e; _ -> error "empty examples" + , take 1 exampleUcs + ) , -- All examples separated by commas. (intercalate ", " exampleStrs, exampleUcs) ] diff --git a/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs b/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs index f75441e12c9..0bd49355913 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/VCS.hs @@ -16,8 +16,8 @@ import Distribution.Client.Types.SourceRepo (SourceRepoProxy, SourceRepositoryPa import Distribution.Client.VCS import Distribution.Simple.Program import Distribution.System (OS (Windows), buildOS) -import Distribution.Utils.TempTestDir (removeDirectoryRecursiveHack, withTestDir) import Distribution.Verbosity as Verbosity +import Test.Utils.TempTestDir (removeDirectoryRecursiveHack, withTestDir) import Data.List (mapAccumL) import qualified Data.Map as Map @@ -57,7 +57,7 @@ tests :: MTimeChange -> [TestTree] tests mtimeChange = map (localOption $ QuickCheckTests 10) - [ ignoreInWindows "See issue #8048" $ + [ ignoreInWindows "See issue #8048 and #9519" $ testGroup "git" [ testProperty "check VCS test framework" prop_framework_git @@ -227,7 +227,7 @@ testSetup -> IO a testSetup vcs mkVCSTestDriver repoRecipe theTest = do -- test setup - vcs' <- configureVCS verbosity vcs + vcs' <- configureVCS verbosity [] vcs withTestDir verbosity "vcstest" $ \tmpdir -> do let srcRepoPath = tmpdir "src" submodulesPath = tmpdir "submodules" diff --git a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs index db3bff2640b..9307aae8feb 100644 --- a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs +++ b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs @@ -491,7 +491,7 @@ exAvSrcPkg ex = -- Furthermore we ignore missing upper bound warnings because -- they are not related to this test suite, and are tested -- with golden tests. - let checks = C.checkPackage (srcpkgDescription package) Nothing + let checks = C.checkPackage (srcpkgDescription package) in filter (\x -> not (isMissingUpperBound x) && not (isUnknownLangExt x)) checks in if null pkgCheckErrors then package diff --git a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs index 123979921b1..3d5b965ba06 100644 --- a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs +++ b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/Solver.hs @@ -615,7 +615,7 @@ tests = , "[__2] unknown package: unknown2 (dependency of B)" , "[__2] fail (backjumping, conflict set: B, unknown2)" , "[__1] fail (backjumping, conflict set: A, B, unknown1, unknown2)" - , "[__0] skipping: A-3.0.0, A-2.0.0 (has the same characteristics that " + , "[__0] skipping: A; 3.0.0, 2.0.0 (has the same characteristics that " ++ "caused the previous version to fail: depends on 'B')" , "[__0] trying: A-1.0.0" , "[__1] done" @@ -644,7 +644,7 @@ tests = , "[__1] next goal: B (dependency of A)" , "[__1] rejecting: B-11.0.0 (conflict: A => B==14.0.0)" , "[__1] fail (backjumping, conflict set: A, B)" - , "[__0] skipping: A-3.0.0, A-2.0.0 (has the same characteristics that " + , "[__0] skipping: A; 3.0.0, 2.0.0 (has the same characteristics that " ++ "caused the previous version to fail: depends on 'B' but excludes " ++ "version 11.0.0)" , "[__0] trying: A-1.0.0" @@ -769,7 +769,7 @@ tests = , "[__2] next goal: C (dependency of A)" , "[__2] rejecting: C-2.0.0 (conflict: A => C==1.0.0)" , "[__2] fail (backjumping, conflict set: A, C)" - , "[__0] skipping: A-3.0.0, A-2.0.0 (has the same characteristics that caused the " + , "[__0] skipping: A; 3.0.0, 2.0.0 (has the same characteristics that caused the " ++ "previous version to fail: depends on 'C' but excludes version 2.0.0)" , "[__0] trying: A-1.0.0" , "[__1] next goal: C (dependency of A)" @@ -912,6 +912,51 @@ tests = msg = "rejecting: other-package-2.0.0/installed-AbCdEfGhIj0123456789" in mkTest db "show full installed package ABI hash (issue #5892)" ["my-package"] $ solverFailure (isInfixOf msg) + , testGroup + "package versions abbreviation (issue #9559.)" + [ runTest $ + let db = + [ Right $ exAv "A" 1 [] + , Right $ exAv "A" 2 [] + , Right $ exAv "B" 1 [ExFix "A" 3] + ] + rejecting = "rejecting: A-2.0.0" + skipping = "skipping: A-1.0.0" + in mkTest db "show skipping singleton" ["B"] $ + solverFailure (\msg -> rejecting `isInfixOf` msg && skipping `isInfixOf` msg) + , runTest $ + let db = + [ Left $ exInst "A" 1 "A-1.0.0" [] + , Left $ exInst "A" 2 "A-2.0.0" [] + , Right $ exAv "B" 1 [ExFix "A" 3] + ] + rejecting = "rejecting: A-2.0.0/installed-2.0.0" + skipping = "skipping: A-1.0.0/installed-1.0.0" + in mkTest db "show skipping singleton, installed" ["B"] $ + solverFailure (\msg -> rejecting `isInfixOf` msg && skipping `isInfixOf` msg) + , runTest $ + let db = + [ Right $ exAv "A" 1 [] + , Right $ exAv "A" 2 [] + , Right $ exAv "A" 3 [] + , Right $ exAv "B" 1 [ExFix "A" 4] + ] + rejecting = "rejecting: A-3.0.0" + skipping = "skipping: A; 2.0.0, 1.0.0" + in mkTest db "show skipping versions list" ["B"] $ + solverFailure (\msg -> rejecting `isInfixOf` msg && skipping `isInfixOf` msg) + , runTest $ + let db = + [ Left $ exInst "A" 1 "A-1.0.0" [] + , Left $ exInst "A" 2 "A-2.0.0" [] + , Left $ exInst "A" 3 "A-3.0.0" [] + , Right $ exAv "B" 1 [ExFix "A" 4] + ] + rejecting = "rejecting: A-3.0.0/installed-3.0.0" + skipping = "skipping: A-2.0.0/installed-2.0.0, A-1.0.0/installed-1.0.0" + in mkTest db "show skipping versions list, installed" ["B"] $ + solverFailure (\msg -> rejecting `isInfixOf` msg && skipping `isInfixOf` msg) + ] ] ] where diff --git a/cabal-install/tests/fixtures/configure/cabal.project b/cabal-install/tests/fixtures/configure/cabal.project index 863b8879eb7..8d7afa6e902 100644 --- a/cabal-install/tests/fixtures/configure/cabal.project +++ b/cabal-install/tests/fixtures/configure/cabal.project @@ -1,2 +1,2 @@ ignore-project: False -optimization: 2 \ No newline at end of file +optimization: 2 diff --git a/cabal-testsuite/LICENSE b/cabal-testsuite/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/cabal-testsuite/LICENSE +++ b/cabal-testsuite/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.out b/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.out index 2e491b9c348..057b79b0de6 100644 --- a/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.out +++ b/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.out @@ -1,82 +1,82 @@ # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo bar/configure', contains the character ' ' (space). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo bar/configure', contains the character ' ' (space). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo bar/configure', contains the character ' ' (tab). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo bar/configure', contains the character ' ' (tab). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo +Warning: The path to the './configure' script, '//foo bar/configure', contains the character ' ' (newline). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo"bar/configure', contains the character '"' (double quote). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo"bar/configure', contains the character '"' (double quote). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo#bar/configure', contains the character '#' (hash). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo#bar/configure', contains the character '#' (hash). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo$bar/configure', contains the character '$' (dollar sign). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo$bar/configure', contains the character '$' (dollar sign). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo&bar/configure', contains the character '&' (ampersand). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo&bar/configure', contains the character '&' (ampersand). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo'bar/configure', contains the character ''' (single quote). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo'bar/configure', contains the character ''' (single quote). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo(bar/configure', contains the character '(' (left bracket). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo(bar/configure', contains the character '(' (left bracket). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo)bar/configure', contains the character ')' (right bracket). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo)bar/configure', contains the character ')' (right bracket). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo*bar/configure', contains the character '*' (star). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo*bar/configure', contains the character '*' (star). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo;bar/configure', contains the character ';' (semicolon). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo;bar/configure', contains the character ';' (semicolon). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo/foo/cabal.dist/foo=bar/configure', contains the character '=' (equals sign). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo=bar/configure', contains the character '=' (equals sign). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo>bar/configure', contains the character '>' (greater-than sign). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo>bar/configure', contains the character '>' (greater-than sign). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo?bar/configure', contains the character '?' (question mark). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo?bar/configure', contains the character '?' (question mark). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo[bar/configure', contains the character '[' (left square bracket). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo[bar/configure', contains the character '[' (left square bracket). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo/bar/configure', contains the character '/' (backslash). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo/bar/configure', contains the character '/' (backslash). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo`bar/configure', contains the character '`' (backtick). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo`bar/configure', contains the character '`' (backtick). This may cause the script to fail with an obscure error, or for building the package to fail later. # cabal v1-configure Resolving dependencies... Configuring test-0... -Warning: The path to the './configure' script, '//cabal.dist/foo|bar/configure', contains the character '|' (pipe). This may cause the script to fail with an obscure error, or for building the package to fail later. +Warning: The path to the './configure' script, '//foo|bar/configure', contains the character '|' (pipe). This may cause the script to fail with an obscure error, or for building the package to fail later. diff --git a/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.test.hs b/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.test.hs index 74c9d8806b8..7325eb0684c 100644 --- a/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.test.hs +++ b/cabal-testsuite/PackageTests/AutoconfBadPaths/cabal.test.hs @@ -1,5 +1,7 @@ import Test.Cabal.Prelude import Data.Foldable (traverse_) +import Distribution.Simple.Utils +import System.Directory main = cabalTest $ do -- Test the forbidden characters except NUL. Reference: -- https://www.gnu.org/software/autoconf/manual/autoconf.html#File-System-Conventions @@ -31,11 +33,21 @@ main = cabalTest $ do , "foo|bar" ] where + setup dir = do + env <- getTestEnv + let cwd = testCurrentDir env + liftIO $ createDirectory (testCurrentDir env dir) + liftIO $ copyFiles minBound (testCurrentDir env dir) + [ (cwd, "configure") + , (cwd, "Setup.hs") + , (cwd, "test.cabal") + ] -- 'cabal' from the prelude requires the command to succeed; we -- don't mind if it fails, so long as we get the warning. This is -- an inlined+specialised version of 'cabal' for v1-configure. - check dir = withSourceCopyDir dir $ + check dir = defaultRecordMode RecordMarked $ do + setup dir recordHeader ["cabal", "v1-configure"] env <- getTestEnv let args = @@ -46,7 +58,7 @@ main = cabalTest $ do ] configured_prog <- requireProgramM cabalProgram r <- liftIO $ run (testVerbosity env) - (Just (testCurrentDir env)) + (Just (testCurrentDir env dir)) (testEnvironment env) (programPath configured_prog) args Nothing diff --git a/cabal-testsuite/PackageTests/AutogenModules/Package/my.cabal b/cabal-testsuite/PackageTests/AutogenModules/Package/my.cabal index 37dfcbf7bce..103b8d7b7a1 100644 --- a/cabal-testsuite/PackageTests/AutogenModules/Package/my.cabal +++ b/cabal-testsuite/PackageTests/AutogenModules/Package/my.cabal @@ -1,20 +1,20 @@ +cabal-version: 3.12 name: AutogenModules version: 0.1 -license: BSD3 +license: BSD-3-Clause license-file: LICENSE author: Federico Mastellone maintainer: Federico Mastellone synopsis: AutogenModules category: PackageTests build-type: Simple -cabal-version: 2.0 description: Check that Cabal recognizes the autogen-modules fields below. Library default-language: Haskell2010 - build-depends: base + build-depends: base == 4.* exposed-modules: MyLibrary PackageInfo_AutogenModules @@ -28,7 +28,7 @@ Library Executable Exe default-language: Haskell2010 main-is: Dummy.hs - build-depends: base + build-depends: base == 4.* other-modules: MyExeModule PackageInfo_AutogenModules @@ -41,7 +41,7 @@ Test-Suite Test default-language: Haskell2010 main-is: Dummy.hs type: exitcode-stdio-1.0 - build-depends: base + build-depends: base == 4.* other-modules: MyTestModule PackageInfo_AutogenModules @@ -54,7 +54,7 @@ Benchmark Bench default-language: Haskell2010 main-is: Dummy.hs type: exitcode-stdio-1.0 - build-depends: base + build-depends: base == 4.* other-modules: MyBenchModule PackageInfo_AutogenModules diff --git a/cabal-testsuite/PackageTests/AutogenModules/Package/setup.cabal.out b/cabal-testsuite/PackageTests/AutogenModules/Package/setup.cabal.out index dd76b493185..3cb109d47b6 100644 --- a/cabal-testsuite/PackageTests/AutogenModules/Package/setup.cabal.out +++ b/cabal-testsuite/PackageTests/AutogenModules/Package/setup.cabal.out @@ -1,22 +1,22 @@ # Setup configure Configuring AutogenModules-0.1... Error: [Cabal-5559] -An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. +[autogen-not-exposed] An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. -On executable 'Exe' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On executable 'Exe' an 'autogen-module' is not on 'other-modules' -On test suite 'Test' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On test suite 'Test' an 'autogen-module' is not on 'other-modules' -On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' # Setup sdist Distribution quality errors: -An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. -On executable 'Exe' an 'autogen-module' is not on 'other-modules' -On test suite 'Test' an 'autogen-module' is not on 'other-modules' -On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' -Packages using 'cabal-version: 2.0' and the autogenerated module Paths_* must include it also on the 'autogen-modules' field besides 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. -Packages using 'cabal-version: 2.0' and the autogenerated module PackageInfo_* must include it in 'autogen-modules' as well as 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. -The filename './my.cabal' does not match package name (expected: 'AutogenModules.cabal') +[autogen-not-exposed] An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. +[autogen-other-modules] On executable 'Exe' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On test suite 'Test' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' +[no-autogen-paths] Packages using 'cabal-version: 2.0' and the autogenerated module Paths_* must include it also on the 'autogen-modules' field besides 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. +[no-autogen-pinfo] Packages using 'cabal-version: 2.0' and the autogenerated module PackageInfo_* must include it in 'autogen-modules' as well as 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. +[name-no-match] The filename './my.cabal' does not match package name (expected: 'AutogenModules.cabal') Note: the public hackage server would reject this package. Building source dist for AutogenModules-0.1... Error: [Cabal-6421] diff --git a/cabal-testsuite/PackageTests/AutogenModules/Package/setup.out b/cabal-testsuite/PackageTests/AutogenModules/Package/setup.out index dd76b493185..3cb109d47b6 100644 --- a/cabal-testsuite/PackageTests/AutogenModules/Package/setup.out +++ b/cabal-testsuite/PackageTests/AutogenModules/Package/setup.out @@ -1,22 +1,22 @@ # Setup configure Configuring AutogenModules-0.1... Error: [Cabal-5559] -An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. +[autogen-not-exposed] An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. -On executable 'Exe' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On executable 'Exe' an 'autogen-module' is not on 'other-modules' -On test suite 'Test' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On test suite 'Test' an 'autogen-module' is not on 'other-modules' -On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' # Setup sdist Distribution quality errors: -An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. -On executable 'Exe' an 'autogen-module' is not on 'other-modules' -On test suite 'Test' an 'autogen-module' is not on 'other-modules' -On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' -Packages using 'cabal-version: 2.0' and the autogenerated module Paths_* must include it also on the 'autogen-modules' field besides 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. -Packages using 'cabal-version: 2.0' and the autogenerated module PackageInfo_* must include it in 'autogen-modules' as well as 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. -The filename './my.cabal' does not match package name (expected: 'AutogenModules.cabal') +[autogen-not-exposed] An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. +[autogen-other-modules] On executable 'Exe' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On test suite 'Test' an 'autogen-module' is not on 'other-modules' +[autogen-other-modules] On benchmark 'Bench' an 'autogen-module' is not on 'other-modules' +[no-autogen-paths] Packages using 'cabal-version: 2.0' and the autogenerated module Paths_* must include it also on the 'autogen-modules' field besides 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. +[no-autogen-pinfo] Packages using 'cabal-version: 2.0' and the autogenerated module PackageInfo_* must include it in 'autogen-modules' as well as 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. +[name-no-match] The filename './my.cabal' does not match package name (expected: 'AutogenModules.cabal') Note: the public hackage server would reject this package. Building source dist for AutogenModules-0.1... Error: [Cabal-6421] diff --git a/cabal-testsuite/PackageTests/AutogenModules/SrcDist/AutogenModules.cabal b/cabal-testsuite/PackageTests/AutogenModules/SrcDist/AutogenModules.cabal index 8c8f1a98b89..9a12877cd6b 100644 --- a/cabal-testsuite/PackageTests/AutogenModules/SrcDist/AutogenModules.cabal +++ b/cabal-testsuite/PackageTests/AutogenModules/SrcDist/AutogenModules.cabal @@ -1,20 +1,20 @@ +cabal-version: 3.12 name: AutogenModules version: 0.1 -license: BSD3 +license: BSD-3-Clause license-file: LICENSE author: Federico Mastellone maintainer: Federico Mastellone synopsis: AutogenModules category: PackageTests build-type: Simple -cabal-version: 2.0 description: Check that Cabal recognizes the autogen-modules fields below. Library default-language: Haskell2010 - build-depends: base + build-depends: base == 4.* exposed-modules: MyLibrary PackageInfo_AutogenModules @@ -30,7 +30,7 @@ Library Executable Exe default-language: Haskell2010 main-is: Dummy.hs - build-depends: base + build-depends: base == 4.* other-modules: MyExeModule PackageInfo_AutogenModules @@ -45,7 +45,7 @@ Test-Suite Test default-language: Haskell2010 main-is: Dummy.hs type: exitcode-stdio-1.0 - build-depends: base + build-depends: base == 4.* other-modules: MyTestModule PackageInfo_AutogenModules @@ -60,7 +60,7 @@ Benchmark Bench default-language: Haskell2010 main-is: Dummy.hs type: exitcode-stdio-1.0 - build-depends: base + build-depends: base == 4.* other-modules: MyBenchModule PackageInfo_AutogenModules diff --git a/cabal-testsuite/PackageTests/AutogenModulesToggling/Setup.hs b/cabal-testsuite/PackageTests/AutogenModulesToggling/Setup.hs index 2eab853cdfb..76fec15e076 100644 --- a/cabal-testsuite/PackageTests/AutogenModulesToggling/Setup.hs +++ b/cabal-testsuite/PackageTests/AutogenModulesToggling/Setup.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE OverloadedStrings #-} module Main (main) where diff --git a/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.out b/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.out deleted file mode 100644 index 3b848ef431a..00000000000 --- a/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.out +++ /dev/null @@ -1,22 +0,0 @@ -# cabal v2-run -Resolving dependencies... -Build profile: -w ghc- -O1 -In order, the following will be built: - - test-0.1 (exe:autogen-toggle-test) (first run) -Configuring test-0.1... -Preprocessing library for test-0.1... -Building library for test-0.1... -Preprocessing executable 'autogen-toggle-test' for test-0.1... -Building executable 'autogen-toggle-test' for test-0.1... -The module says: Real module, ship to production -# cabal v2-run -Resolving dependencies... -Build profile: -w ghc- -O1 -In order, the following will be built: - - test-0.1 (exe:autogen-toggle-test) (configuration changed) -Configuring test-0.1... -Preprocessing library for test-0.1... -Building library for test-0.1... -Preprocessing executable 'autogen-toggle-test' for test-0.1... -Building executable 'autogen-toggle-test' for test-0.1... -The module says: Prebuilt module, don't use in production diff --git a/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.test.hs b/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.test.hs index 4b0e1639c12..5c6e866b2d1 100644 --- a/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.test.hs +++ b/cabal-testsuite/PackageTests/AutogenModulesToggling/cabal.test.hs @@ -1,7 +1,12 @@ import Test.Cabal.Prelude main :: IO () -main = cabalTest . recordMode RecordMarked $ do - skipUnlessGhcVersion ">= 9.7" - cabal "v2-run" ["-fgenerate", "autogen-toggle-test"] - cabal "v2-run" ["-f-generate", "autogen-toggle-test"] +main = setupTest . recordMode DoNotRecord . withPackageDb $ do + -- This test exposes a recompilation bug in ghc versions 9.0.2 and 9.2.8 + skipIfGhcVersion "== 9.0.2 || == 9.2.8 || < 8.0 " + setup_install ["-fgenerate"] + r1 <- runInstalledExe' "autogen-toggle-test" [] + setup_install ["-f-generate"] + r2 <- runInstalledExe' "autogen-toggle-test" [] + assertOutputContains "Real module, ship to production" r1 + assertOutputContains "Prebuilt module, don't use in production" r2 diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/Includes2.cabal b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/Includes2.cabal new file mode 100644 index 00000000000..102a48b97fe --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/Includes2.cabal @@ -0,0 +1,35 @@ +name: fail +version: 0.1.0.0 +license: BSD3 +author: Edward Z. Yang +maintainer: ezyang@cs.stanford.edu +build-type: Simple +cabal-version: 2.0 + +library mylib + build-depends: base + signatures: Database + exposed-modules: Mine + hs-source-dirs: mylib + default-language: Haskell2010 + +library mysql + build-depends: base + exposed-modules: Database.MySQL + hs-source-dirs: mysql + default-language: Haskell2010 + +library postgresql + build-depends: base + exposed-modules: Database.PostgreSQL + hs-source-dirs: postgresql + default-language: Haskell2010 + +library + build-depends: base, mysql, postgresql, mylib + mixins: + mysql (Database.MySQL as Database), + postgresql (Database.PostgreSQL as Database) + exposed-modules: App + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/mylib b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/mylib new file mode 120000 index 00000000000..9b3246e6442 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/mylib @@ -0,0 +1 @@ +../mylib \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/mysql b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/mysql new file mode 120000 index 00000000000..057b59f7601 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/mysql @@ -0,0 +1 @@ +../mysql \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/postgresql b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/postgresql new file mode 120000 index 00000000000..d9c4a17c5cf --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/postgresql @@ -0,0 +1 @@ +../postgresql \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/src b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/src new file mode 120000 index 00000000000..5cd551cf269 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2-fail/src @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2.cabal b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2.cabal index 7a02fcd961c..e6aa6169e68 100644 --- a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2.cabal +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2.cabal @@ -39,3 +39,10 @@ executable exe main-is: Main.hs hs-source-dirs: exe default-language: Haskell2010 + +test-suite includes2-test + type: exitcode-stdio-1.0 + build-depends: base, Includes2 + main-is: test.hs + hs-source-dirs: test + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/Includes2.cabal b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/Includes2.cabal new file mode 100644 index 00000000000..7a02fcd961c --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/Includes2.cabal @@ -0,0 +1,41 @@ +name: Includes2 +version: 0.1.0.0 +license: BSD3 +author: Edward Z. Yang +maintainer: ezyang@cs.stanford.edu +build-type: Simple +cabal-version: 2.0 + +library mylib + build-depends: base + signatures: Database + exposed-modules: Mine + hs-source-dirs: mylib + default-language: Haskell2010 + +library mysql + build-depends: base + exposed-modules: Database.MySQL + hs-source-dirs: mysql + default-language: Haskell2010 + +library postgresql + build-depends: base + exposed-modules: Database.PostgreSQL + hs-source-dirs: postgresql + default-language: Haskell2010 + +library + build-depends: base, mysql, postgresql, mylib + mixins: + mylib (Mine as Mine.MySQL) requires (Database as Database.MySQL), + mylib (Mine as Mine.PostgreSQL) requires (Database as Database.PostgreSQL) + exposed-modules: App + hs-source-dirs: src + default-language: Haskell2010 + +executable exe + build-depends: base, Includes2 + main-is: Main.hs + hs-source-dirs: exe + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/exe b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/exe new file mode 120000 index 00000000000..a94459effa2 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/exe @@ -0,0 +1 @@ +../exe \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/mylib b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/mylib new file mode 120000 index 00000000000..9b3246e6442 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/mylib @@ -0,0 +1 @@ +../mylib \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/mysql b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/mysql new file mode 120000 index 00000000000..057b59f7601 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/mysql @@ -0,0 +1 @@ +../mysql \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/postgresql b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/postgresql new file mode 120000 index 00000000000..d9c4a17c5cf --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/postgresql @@ -0,0 +1 @@ +../postgresql \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/src b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/src new file mode 120000 index 00000000000..5cd551cf269 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/Includes2/src @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.internal.project b/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.internal.project index e6fdbadb439..acefc12cc2f 100644 --- a/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.internal.project +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.internal.project @@ -1 +1 @@ -packages: . +packages: ./Includes2 diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.project b/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/cov.out b/cabal-testsuite/PackageTests/Backpack/Includes2/cov.out new file mode 100644 index 00000000000..784baff09e7 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/cov.out @@ -0,0 +1,48 @@ +# cabal test +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - Includes2-0.1.0.0 (lib:mylib) (first run) + - Includes2-0.1.0.0 (lib:mysql) (first run) + - Includes2-0.1.0.0 (lib:postgresql) (first run) + - Includes2-0.1.0.0 (lib:mylib with Database=Includes2-0.1.0.0-inplace-mysql:Database.MySQL) (first run) + - Includes2-0.1.0.0 (lib:mylib with Database=Includes2-0.1.0.0-inplace-postgresql:Database.PostgreSQL) (first run) + - Includes2-0.1.0.0 (lib) (first run) + - Includes2-0.1.0.0 (test:includes2-test) (first run) +Configuring library 'mylib' for Includes2-0.1.0.0... +Preprocessing library 'mylib' for Includes2-0.1.0.0... +Building library 'mylib' instantiated with Database = +for Includes2-0.1.0.0... +Configuring library 'mysql' for Includes2-0.1.0.0... +Preprocessing library 'mysql' for Includes2-0.1.0.0... +Building library 'mysql' for Includes2-0.1.0.0... +Configuring library 'postgresql' for Includes2-0.1.0.0... +Preprocessing library 'postgresql' for Includes2-0.1.0.0... +Building library 'postgresql' for Includes2-0.1.0.0... +Configuring library 'mylib' instantiated with + Database = Includes2-0.1.0.0-inplace-mysql:Database.MySQL +for Includes2-0.1.0.0... +Preprocessing library 'mylib' for Includes2-0.1.0.0... +Building library 'mylib' instantiated with + Database = Includes2-0.1.0.0-inplace-mysql:Database.MySQL +for Includes2-0.1.0.0... +Configuring library 'mylib' instantiated with + Database = Includes2-0.1.0.0-inplace-postgresql:Database.PostgreSQL +for Includes2-0.1.0.0... +Preprocessing library 'mylib' for Includes2-0.1.0.0... +Building library 'mylib' instantiated with + Database = Includes2-0.1.0.0-inplace-postgresql:Database.PostgreSQL +for Includes2-0.1.0.0... +Configuring library for Includes2-0.1.0.0... +Preprocessing library for Includes2-0.1.0.0... +Building library for Includes2-0.1.0.0... +Configuring test suite 'includes2-test' for Includes2-0.1.0.0... +Preprocessing test suite 'includes2-test' for Includes2-0.1.0.0... +Building test suite 'includes2-test' for Includes2-0.1.0.0... +Running 1 test suites... +Test suite includes2-test: RUNNING... +Test suite includes2-test: PASS +Test suite logged to: /cov.dist/work/./dist/build//ghc-/Includes2-0.1.0.0/t/includes2-test/test/Includes2-0.1.0.0-includes2-test.log +Package coverage report written to /cov.dist/work/./dist/build//ghc-/Includes2-0.1.0.0/t/includes2-test/hpc/vanilla/html/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /cov.dist/work/./dist/build//ghc-/Includes2-0.1.0.0/t/includes2-test/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/cov.test.hs b/cabal-testsuite/PackageTests/Backpack/Includes2/cov.test.hs new file mode 100644 index 00000000000..24c1662c375 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/cov.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude +main = cabalTest $ do + skipUnlessGhcVersion ">= 8.1" + skipIfWindows -- TODO: https://github.com/haskell/cabal/issues/6271 + -- #6397 + cabal "test" ["--enable-coverage", "includes2-test"] diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal-fail.test.hs b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal-fail.test.hs index d624dfcac06..7c8116ff62f 100644 --- a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal-fail.test.hs +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal-fail.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipUnlessGhcVersion ">= 8.1" - r <- fails $ setup' "configure" ["--cabal-file", "Includes2.cabal.fail"] + r <- fails $ withDirectory "Includes2-fail" $ setup' "configure" [] assertOutputContains "mysql" r diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal.test.hs b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal.test.hs index ab1853753e2..707dbbacced 100644 --- a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal.test.hs +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-internal.test.hs @@ -1,7 +1,8 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipUnlessGhcVersion ">= 8.1" - withPackageDb $ do - setup_install ["--cabal-file", "Includes2.cabal"] - -- TODO: haddock for internal method doesn't work - runExe "exe" [] + withPackageDb $ + withDirectory "Includes2" $ do + setup_install [] + -- TODO: haddock for internal method doesn't work + runExe "exe" [] diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.out b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.out index 33ac75b0a99..01888faed97 100644 --- a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.out +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.out @@ -8,7 +8,7 @@ for Includes2-0.1.0.0... Preprocessing library 'mylib' for Includes2-0.1.0.0... Running Haddock on library 'mylib' instantiated with Database = for Includes2-0.1.0.0... -Documentation created: setup-per-component.dist/work/dist/doc/html/Includes2/ +Documentation created: ../setup-per-component.dist/work/Includes2/dist/doc/html/Includes2/ # Setup copy Installing internal library mylib in # Setup register @@ -22,7 +22,7 @@ Building library 'mysql' for Includes2-0.1.0.0... # Setup haddock Preprocessing library 'mysql' for Includes2-0.1.0.0... Running Haddock on library 'mysql' for Includes2-0.1.0.0... -Documentation created: setup-per-component.dist/work/dist/doc/html/Includes2/ +Documentation created: ../setup-per-component.dist/work/Includes2/dist/doc/html/Includes2/ # Setup copy Installing internal library mysql in # Setup register @@ -35,7 +35,7 @@ Building library 'postgresql' for Includes2-0.1.0.0... # Setup haddock Preprocessing library 'postgresql' for Includes2-0.1.0.0... Running Haddock on library 'postgresql' for Includes2-0.1.0.0... -Documentation created: setup-per-component.dist/work/dist/doc/html/Includes2/ +Documentation created: ../setup-per-component.dist/work/Includes2/dist/doc/html/Includes2/ # Setup copy Installing internal library postgresql in # Setup register @@ -54,7 +54,7 @@ Preprocessing library 'mylib' for Includes2-0.1.0.0... Running Haddock on library 'mylib' instantiated with Database = mysql-0.1.0.0:Database.MySQL for Includes2-0.1.0.0... -Documentation created: setup-per-component.dist/work/dist/doc/html/Includes2/ +Documentation created: ../setup-per-component.dist/work/Includes2/dist/doc/html/Includes2/ # Setup copy Installing internal library mylib in # Setup register @@ -75,7 +75,7 @@ Preprocessing library 'mylib' for Includes2-0.1.0.0... Running Haddock on library 'mylib' instantiated with Database = postgresql-0.1.0.0:Database.PostgreSQL for Includes2-0.1.0.0... -Documentation created: setup-per-component.dist/work/dist/doc/html/Includes2/ +Documentation created: ../setup-per-component.dist/work/Includes2/dist/doc/html/Includes2/ # Setup copy Installing internal library mylib in # Setup register @@ -90,7 +90,7 @@ Building library for Includes2-0.1.0.0... # Setup haddock Preprocessing library for Includes2-0.1.0.0... Running Haddock on library for Includes2-0.1.0.0... -Documentation created: setup-per-component.dist/work/dist/doc/html/Includes2/ +Documentation created: ../setup-per-component.dist/work/Includes2/dist/doc/html/Includes2/ # Setup copy Installing library in # Setup register diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.test.hs b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.test.hs index 5196d404f65..5bbb1b02af2 100644 --- a/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.test.hs +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/setup-per-component.test.hs @@ -4,15 +4,16 @@ main = setupTest $ do skipUnlessGhcVersion ">= 8.1" ghc <- isGhcVersion "== 9.0.2 || == 9.2.* || == 9.4.* || == 9.6.*" expectBrokenIf ghc 7987 $ - withPackageDb $ do - let setup_install' args = setup_install_with_docs (["--cabal-file", "Includes2.cabal"] ++ args) - setup_install' ["mylib", "--cid", "mylib-0.1.0.0"] - setup_install' ["mysql", "--cid", "mysql-0.1.0.0"] - setup_install' ["postgresql", "--cid", "postgresql-0.1.0.0"] - setup_install' ["mylib", "--cid", "mylib-0.1.0.0", - "--instantiate-with", "Database=mysql-0.1.0.0:Database.MySQL"] - setup_install' ["mylib", "--cid", "mylib-0.1.0.0", - "--instantiate-with", "Database=postgresql-0.1.0.0:Database.PostgreSQL"] - setup_install' ["Includes2"] - setup_install' ["exe"] - runExe' "exe" [] >>= assertOutputContains "minemysql minepostgresql" + withPackageDb $ + withDirectory "Includes2" $ do + let setup_install' args = setup_install_with_docs args + setup_install' ["mylib", "--cid", "mylib-0.1.0.0"] + setup_install' ["mysql", "--cid", "mysql-0.1.0.0"] + setup_install' ["postgresql", "--cid", "postgresql-0.1.0.0"] + setup_install' ["mylib", "--cid", "mylib-0.1.0.0", + "--instantiate-with", "Database=mysql-0.1.0.0:Database.MySQL"] + setup_install' ["mylib", "--cid", "mylib-0.1.0.0", + "--instantiate-with", "Database=postgresql-0.1.0.0:Database.PostgreSQL"] + setup_install' ["Includes2"] + setup_install' ["exe"] + runExe' "exe" [] >>= assertOutputContains "minemysql minepostgresql" diff --git a/cabal-testsuite/PackageTests/Backpack/Includes2/test/test.hs b/cabal-testsuite/PackageTests/Backpack/Includes2/test/test.hs new file mode 100644 index 00000000000..c90460e80f4 --- /dev/null +++ b/cabal-testsuite/PackageTests/Backpack/Includes2/test/test.hs @@ -0,0 +1,2 @@ +import App +main = putStrLn app diff --git a/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.cabal.out b/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.cabal.out index 75bc0f494a7..38c474264aa 100644 --- a/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.cabal.out +++ b/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.cabal.out @@ -1,4 +1,4 @@ # Setup configure Configuring Reexport2-1.0... Error: [Cabal-5559] -Duplicate modules in library: Asdf +[duplicate-modules] Duplicate modules in library: Asdf diff --git a/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.out b/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.out index 75bc0f494a7..38c474264aa 100644 --- a/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.out +++ b/cabal-testsuite/PackageTests/Backpack/Reexport2/setup.out @@ -1,4 +1,4 @@ # Setup configure Configuring Reexport2-1.0... Error: [Cabal-5559] -Duplicate modules in library: Asdf +[duplicate-modules] Duplicate modules in library: Asdf diff --git a/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.out b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.out new file mode 100644 index 00000000000..512a50e37ee --- /dev/null +++ b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.out @@ -0,0 +1,10 @@ +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - pkg-0 (lib) (first run) +Configuring library for pkg-0... +Error: [Cabal-5559] +[autogen-guard] To use the autogenerated module PackageInfo_* you need to specify `cabal-version: 3.12` or higher. +Error: [Cabal-7125] +Failed to build pkg-0-inplace. The failure occurred during the configure step. diff --git a/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.project b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.project new file mode 100644 index 00000000000..b764c340a62 --- /dev/null +++ b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.project @@ -0,0 +1,2 @@ +packages: . + diff --git a/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.test.hs b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.test.hs new file mode 100644 index 00000000000..0711dcccfe1 --- /dev/null +++ b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/cabal.test.hs @@ -0,0 +1,8 @@ +import Test.Cabal.Prelude + +-- #9331, guard PackageInfo functionality behind 3.12: make it a +-- build failure. +main = cabalTest $ do + withProjectFile "cabal.project" $ do + fails $ cabal "v2-build" ["pkg"] + diff --git a/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/pkg.cabal b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/pkg.cabal new file mode 100644 index 00000000000..5babc9759cb --- /dev/null +++ b/cabal-testsuite/PackageTests/BuildAutogenPackageGuard/pkg.cabal @@ -0,0 +1,17 @@ +cabal-version: 2.4 +name: pkg +version: 0 +license: GPL-3.0-or-later +maintainer: Someone +category: Example +synopsis: Foo +description: FooBar +build-type: Simple + +library + default-language: Haskell2010 + build-depends: base == 4.* + -- ☞ N.B.: PackageInfo packages must contain the same name of + -- of the package! (In this example: `pkg`). + autogen-modules: PackageInfo_pkg + exposed-modules: PackageInfo_pkg diff --git a/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.cabal.out b/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.cabal.out index da5c074772e..3762dda7c78 100644 --- a/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.cabal.out +++ b/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.cabal.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-tool-depends-missing-0.1.0.0... Error: [Cabal-5559] -The package depends on a missing internal executable: build-tool-depends-missing:hello-world +[no-internal-exe] The package depends on a missing internal executable: build-tool-depends-missing:hello-world diff --git a/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.out b/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.out index da5c074772e..3762dda7c78 100644 --- a/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.out +++ b/cabal-testsuite/PackageTests/BuildToolDependsInternalMissing/setup.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-tool-depends-missing-0.1.0.0... Error: [Cabal-5559] -The package depends on a missing internal executable: build-tool-depends-missing:hello-world +[no-internal-exe] The package depends on a missing internal executable: build-tool-depends-missing:hello-world diff --git a/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc b/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc index 67a1a91cdb2..fa41c1c4c88 100755 --- a/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc +++ b/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if which cc >/dev/null 2>&1; then cc -DNOERROR6 "${@}" diff --git a/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc-clang.bat b/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc-clang.bat new file mode 100644 index 00000000000..72012c9c9d0 --- /dev/null +++ b/cabal-testsuite/PackageTests/CCompilerOverride/custom-cc-clang.bat @@ -0,0 +1,11 @@ +@echo OFF + +where /q clang.exe + +IF %ERRORLEVEL% EQU 0 ( + call clang.exe -DNOERROR6 %* + EXIT /B %ERRORLEVEL% +) + +ECHO "Cannot find C compiler" +EXIT /B 1 diff --git a/cabal-testsuite/PackageTests/CCompilerOverride/setup.cabal.out b/cabal-testsuite/PackageTests/CCompilerOverride/setup.cabal.out index 456d6805574..21981fd9b76 100644 --- a/cabal-testsuite/PackageTests/CCompilerOverride/setup.cabal.out +++ b/cabal-testsuite/PackageTests/CCompilerOverride/setup.cabal.out @@ -1,4 +1,4 @@ # Setup configure Configuring my-0.1... -Warning: Instead of 'ghc-options: -DNOERROR4' use 'cpp-options: -DNOERROR4' +Warning: [misplaced-c-opt] Instead of 'ghc-options: -DNOERROR4' use 'cpp-options: -DNOERROR4' # Setup build diff --git a/cabal-testsuite/PackageTests/CCompilerOverride/setup.out b/cabal-testsuite/PackageTests/CCompilerOverride/setup.out index 456d6805574..21981fd9b76 100644 --- a/cabal-testsuite/PackageTests/CCompilerOverride/setup.out +++ b/cabal-testsuite/PackageTests/CCompilerOverride/setup.out @@ -1,4 +1,4 @@ # Setup configure Configuring my-0.1... -Warning: Instead of 'ghc-options: -DNOERROR4' use 'cpp-options: -DNOERROR4' +Warning: [misplaced-c-opt] Instead of 'ghc-options: -DNOERROR4' use 'cpp-options: -DNOERROR4' # Setup build diff --git a/cabal-testsuite/PackageTests/CCompilerOverride/setup.test.hs b/cabal-testsuite/PackageTests/CCompilerOverride/setup.test.hs index dbc10efa7a3..5843cb2b7df 100644 --- a/cabal-testsuite/PackageTests/CCompilerOverride/setup.test.hs +++ b/cabal-testsuite/PackageTests/CCompilerOverride/setup.test.hs @@ -6,16 +6,17 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipUnlessGhcVersion ">= 8.8" isWin <- isWindows - ghc94 <- isGhcVersion "== 9.4.*" + ghc94 <- isGhcVersion ">= 9.4.1" env <- getTestEnv let pwd = testCurrentDir env - customCC = pwd ++ "/custom-cc" ++ if isWin then ".bat" else "" + win_suffix = if ghc94 then "-clang.bat" else ".bat" + customCC = + pwd ++ "/custom-cc" ++ if isWin then win_suffix else "" - expectBrokenIf (isWin && ghc94) 8451 $ do - setup "configure" - [ "--ghc-option=-DNOERROR1" - , "--ghc-option=-optc=-DNOERROR2" - , "--ghc-option=-optP=-DNOERROR3" - , "--with-gcc=" ++ customCC - ] - setup "build" ["-v2"] + setup "configure" + [ "--ghc-option=-DNOERROR1" + , "--ghc-option=-optc=-DNOERROR2" + , "--ghc-option=-optP=-DNOERROR3" + , "--with-gcc=" ++ customCC + ] + setup "build" ["-v2"] diff --git a/cabal-testsuite/PackageTests/Check/Cond/After/cabal.out b/cabal-testsuite/PackageTests/Check/Cond/After/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/After/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/Cond/After/cabal.test.hs b/cabal-testsuite/PackageTests/Check/Cond/After/cabal.test.hs new file mode 100644 index 00000000000..c920553d855 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/After/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- `main-is` in both branches is not missing (after). +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/Cond/After/pkg.cabal b/cabal-testsuite/PackageTests/Check/Cond/After/pkg.cabal new file mode 100644 index 00000000000..3d4925b9a26 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/After/pkg.cabal @@ -0,0 +1,26 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +flag my-flag + description: Test for branches. + default: False + manual: True + +executable exe + if os(windows) + ghc-options: -pgml misc/static-libstdc++ + + if flag(my-flag) + main-is: Main.hs + build-depends: async, unix + c-sources: executable/link.c + else + main-is: ParallelMain.hs + + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Check/Cond/Before/cabal.out b/cabal-testsuite/PackageTests/Check/Cond/Before/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/Before/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/Cond/Before/cabal.test.hs b/cabal-testsuite/PackageTests/Check/Cond/Before/cabal.test.hs new file mode 100644 index 00000000000..777f542cd27 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/Before/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- `main-is` in both branches is not missing. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/Cond/Before/pkg.cabal b/cabal-testsuite/PackageTests/Check/Cond/Before/pkg.cabal new file mode 100644 index 00000000000..28a8369d248 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/Before/pkg.cabal @@ -0,0 +1,26 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +flag my-flag + description: Test for branches. + default: False + manual: True + +executable exe + if flag(my-flag) + main-is: Main.hs + build-depends: async, unix + c-sources: executable/link.c + else + main-is: ParallelMain.hs + + if os(windows) + ghc-options: -pgml misc/static-libstdc++ + + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Check/Cond/Deep/cabal.out b/cabal-testsuite/PackageTests/Check/Cond/Deep/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/Deep/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/Cond/Deep/cabal.test.hs b/cabal-testsuite/PackageTests/Check/Cond/Deep/cabal.test.hs new file mode 100644 index 00000000000..28f534e4037 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/Deep/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- `main-is` in both branches is not missing (deep). +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/Cond/Deep/pkg.cabal b/cabal-testsuite/PackageTests/Check/Cond/Deep/pkg.cabal new file mode 100644 index 00000000000..2eca675b720 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/Deep/pkg.cabal @@ -0,0 +1,34 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +flag my-flag + description: Test for branches. + default: False + manual: True + +flag another-flag + description: Deep test for branches. + default: False + manual: True + +executable exe + if flag(my-flag) + if flag(another-flag) + main-is: Main.hs + build-depends: async, unix + c-sources: executable/link.c + else + main-is: AnotherMain.hs + else + main-is: ParallelMain.hs + + if os(windows) + ghc-options: -pgml misc/static-libstdc++ + + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/cabal.out b/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/cabal.out new file mode 100644 index 00000000000..3144e6704d1 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/cabal.out @@ -0,0 +1,5 @@ +# cabal check +The package will not build sanely due to these errors: +Error: [no-main-is] No 'main-is' field found for executable exe +Error: Hackage would reject this package. + diff --git a/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/cabal.test.hs b/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/cabal.test.hs new file mode 100644 index 00000000000..f0509f39750 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- `main-is` in both branches is not missing (deep, actually missing). +main = cabalTest $ + fails $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/pkg.cabal b/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/pkg.cabal new file mode 100644 index 00000000000..241e92623c9 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/Cond/DeepMissing/pkg.cabal @@ -0,0 +1,35 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +flag my-flag + description: Test for branches. + default: False + manual: True + +flag another-flag + description: Deep test for branches. + default: False + manual: True + +executable exe + if flag(my-flag) + if flag(another-flag) + main-is: Main.hs + build-depends: async, unix + c-sources: executable/link.c + else + build-depends: async, unix + c-sources: executable/link.c + else + main-is: ParallelMain.hs + + if os(windows) + ghc-options: -pgml misc/static-libstdc++ + + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsExtraLibDirs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsExtraLibDirs/cabal.out index 11968358ef8..5ce08cca6be 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsExtraLibDirs/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsExtraLibDirs/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Instead of 'cc-options: -Llibdir' use 'extra-lib-dirs: libdir' +Error: [misplaced-c-opt] Instead of 'cc-options: -Llibdir' use 'extra-lib-dirs: libdir' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsInclude/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsInclude/cabal.out index 1886f29f4e4..fbbd3004595 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsInclude/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CCOptionsInclude/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Instead of 'cc-options: -Ifolder' use 'include-dirs: folder' +Error: [misplaced-c-opt] Instead of 'cc-options: -Ifolder' use 'include-dirs: folder' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CppNotPortable/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CppNotPortable/cabal.out index 1d018c9105d..c98755ad49e 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CppNotPortable/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CppNotPortable/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: 'cpp-options: -Q' is not a portable C-preprocessor flag. +Error: [cpp-options] 'cpp-options: -Q' is not a portable C-preprocessor flag. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOptionsExtraLibraries/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOptionsExtraLibraries/cabal.out index 03a1fe95381..6f3593c9f38 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOptionsExtraLibraries/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOptionsExtraLibraries/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Instead of 'cxx-options: -lgame' use 'extra-libraries: game' +Error: [misplaced-c-opt] Instead of 'cxx-options: -lgame' use 'extra-libraries: game' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOs/cabal.out index 70b9e563c8c..6a1e83afa2b 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOs/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/COptions/CxxOs/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: 'cxx-options: -O[n]' is generally not needed. When building with optimisations Cabal automatically adds '-O2' for C++ code. Setting it yourself interferes with the --disable-optimization flag. +Warning: [option-opt-c] 'cxx-options: -O[n]' is generally not needed. When building with optimisations Cabal automatically adds '-O2' for C++ code. Setting it yourself interferes with the --disable-optimization flag. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/cabal.out index 8d0799bafc4..6efbee4bb39 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/cabal.out @@ -1,5 +1,5 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Packages using 'cabal-version: 2.0' and the autogenerated module Paths_* must include it also on the 'autogen-modules' field besides 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. -Error: Packages using 'cabal-version: 2.0' and the autogenerated module PackageInfo_* must include it in 'autogen-modules' as well as 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. +Error: [no-autogen-paths] Packages using 'cabal-version: 2.0' and the autogenerated module Paths_* must include it also on the 'autogen-modules' field besides 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. +Error: [no-autogen-pinfo] Packages using 'cabal-version: 2.0' and the autogenerated module PackageInfo_* must include it in 'autogen-modules' as well as 'exposed-modules' and 'other-modules'. This specifies that the module does not come with the package and is generated on setup. Modules built with a custom Setup.hs script also go here to ensure that commands like sdist don't fail. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/pkg.cabal index 8486891a3e3..027133f9223 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/pkg.cabal +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/AutoGenMods/pkg.cabal @@ -1,4 +1,4 @@ -cabal-version: 2.0 +cabal-version: 3.12 build-type: Simple name: pkg synopsis: synopsis @@ -6,7 +6,7 @@ description: description version: 0 category: example maintainer: none@example.com -license: GPL-3 +license: GPL-3.0-or-later license-file: LICENSE library diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/CustomSetup/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/CustomSetup/cabal.out index a6136b65ff1..eed850f9a7f 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/CustomSetup/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/CustomSetup/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: From version 1.24 cabal supports specifying explicit dependencies for Custom setup scripts. Consider using 'cabal-version: 1.24' or higher and adding a 'custom-setup' section with a 'setup-depends' field that specifies the dependencies of the Setup.hs script itself. The 'setup-depends' field uses the same syntax as 'build-depends', so a simple example would be 'setup-depends: base, Cabal'. +Warning: [dependencies-setup] From version 1.24 cabal supports specifying explicit dependencies for Custom setup scripts. Consider using 'cabal-version: 1.24' or higher and adding a 'custom-setup' section with a 'setup-depends' field that specifies the dependencies of the Setup.hs script itself. The 'setup-depends' field uses the same syntax as 'build-depends', so a simple example would be 'setup-depends: base, Cabal'. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultExtension/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultExtension/cabal.out index 158f22274a1..6eab2b4cf95 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultExtension/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultExtension/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:14:3: The field "default-extensions" is available only since the Cabal specification version 1.10. This field will be ignored. +Warning: [parser-warning] pkg.cabal:14:3: The field "default-extensions" is available only since the Cabal specification version 1.10. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguage/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguage/cabal.out index e6777f75f91..1a27476d804 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguage/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguage/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:14:3: The field "default-language" is available only since the Cabal specification version 1.10. This field will be ignored. +Warning: [parser-warning] pkg.cabal:14:3: The field "default-language" is available only since the Cabal specification version 1.10. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/cabal.out new file mode 100644 index 00000000000..a45ec56e686 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/cabal.out @@ -0,0 +1,4 @@ +# cabal check +The following errors will cause portability problems on other environments: +Error: [add-language] Without `default-language`, cabal will default to Haskell98, which is probably not what you want. Please add `default-language` to all targets. +Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/RelativeOutsideInner/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/cabal.test.hs similarity index 63% rename from cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/RelativeOutsideInner/cabal.test.hs rename to cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/cabal.test.hs index 09a670ffb24..dc290190595 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/RelativeOutsideInner/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/cabal.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude --- Relative filepath outside source tree. +-- Please specify `default-language`. main = cabalTest $ fails $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/pkg.cabal new file mode 100644 index 00000000000..f89c160813a --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSoft/pkg.cabal @@ -0,0 +1,11 @@ +cabal-version: 3.4 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +library + exposed-modules: Module diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSpec/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSpec/cabal.out index d15028bdca2..cc237924935 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSpec/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/DefaultLanguageSpec/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +Error: [no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtensionBreak/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtensionBreak/cabal.out index e585e23095a..cbbc63dfeec 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtensionBreak/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtensionBreak/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Unfortunately the language extensions 'MonoPatBinds' break the parser in earlier Cabal versions so you need to specify 'cabal-version: >= 1.4'. Alternatively if you require compatibility with earlier Cabal versions then you may be able to use an equivalent compiler-specific flag. +Error: [incompatible-extension] Unfortunately the language extensions 'MonoPatBinds' break the parser in earlier Cabal versions so you need to specify 'cabal-version: >= 1.4'. Alternatively if you require compatibility with earlier Cabal versions then you may be able to use an equivalent compiler-specific flag. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Extensions/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Extensions/cabal.out index 5d1206fb865..e81f62d757f 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Extensions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Extensions/cabal.out @@ -1,6 +1,6 @@ # cabal check The following errors are likely to affect your build negatively: -Error: For packages using 'cabal-version: >= 1.10' the 'extensions' field is deprecated. The new 'default-extensions' field lists extensions that are used in all modules in the component, while the 'other-extensions' field lists extensions that are used in some modules, e.g. via the {-# LANGUAGE #-} pragma. +Error: [extensions-field] For packages using 'cabal-version: >= 1.10' the 'extensions' field is deprecated. The new 'default-extensions' field lists extensions that are used in all modules in the component, while the 'other-extensions' field lists extensions that are used in some modules, e.g. via the {-# LANGUAGE #-} pragma. These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:14:3: The field "extensions" is deprecated in the Cabal specification version 1.12. Please use 'default-extensions' or 'other-extensions' fields. +Warning: [parser-warning] pkg.cabal:14:3: The field "extensions" is deprecated in the Cabal specification version 1.12. Please use 'default-extensions' or 'other-extensions' fields. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDoc/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDoc/cabal.out index e278c388c68..ed7c7b175d8 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDoc/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDoc/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: To use the 'extra-doc-files' field the package needs to specify 'cabal-version: 1.18' or higher. +Error: [extra-doc-files] To use the 'extra-doc-files' field the package needs to specify 'cabal-version: 1.18' or higher. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDynamicLibraryFlavour/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDynamicLibraryFlavour/cabal.out index 8653d8052b7..1134c50f5ee 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDynamicLibraryFlavour/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraDynamicLibraryFlavour/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:14:3: The field "extra-dynamic-library-flavours" is available only since the Cabal specification version 3.0. This field will be ignored. +Warning: [parser-warning] pkg.cabal:14:3: The field "extra-dynamic-library-flavours" is available only since the Cabal specification version 3.0. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraFrameworkDirs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraFrameworkDirs/cabal.out index 4787a8d3906..9d7702781fd 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraFrameworkDirs/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/ExtraFrameworkDirs/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: To use the 'extra-framework-dirs' field the package needs to specify 'cabal-version: 1.24' or higher. +Warning: [extra-framework-dirs] To use the 'extra-framework-dirs' field the package needs to specify 'cabal-version: 1.24' or higher. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Mixins/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Mixins/cabal.out index b3cdf60b8fb..35c4a9ac71b 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Mixins/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Mixins/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:15:3: The field "mixins" is available only since the Cabal specification version 2.0. This field will be ignored. +Warning: [parser-warning] pkg.cabal:15:3: The field "mixins" is available only since the Cabal specification version 2.0. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/MultiLibs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/MultiLibs/cabal.out index 781eb79249c..ff4813b9d61 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/MultiLibs/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/MultiLibs/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: To use multiple 'library' sections or a named library section the package needs to specify at least 'cabal-version: 2.0'. +Error: [multilib] To use multiple 'library' sections or a named library section the package needs to specify at least 'cabal-version: 2.0'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Reexported/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Reexported/cabal.out index c8744b4247d..1d41c7f1668 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Reexported/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Reexported/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: To use the 'reexported-module' field the package needs to specify 'cabal-version: 1.22' or higher. +Error: [reexported-modules] To use the 'reexported-module' field the package needs to specify 'cabal-version: 1.22' or higher. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/SourceRepository/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/SourceRepository/cabal.out index 3bbf94940a2..ade484c6e98 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/SourceRepository/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/SourceRepository/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The 'source-repository' section is new in Cabal 1.6. Unfortunately it messes up the parser in earlier Cabal versions so you need to specify 'cabal-version: >= 1.6'. +Error: [source-repository] The 'source-repository' section is new in Cabal 1.6. Unfortunately it messes up the parser in earlier Cabal versions so you need to specify 'cabal-version: >= 1.6'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Sources/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Sources/cabal.out index 22b9a8325d2..731cf4b5b92 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Sources/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Sources/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:14:3: The field "cmm-sources" is available only since the Cabal specification version 3.0. This field will be ignored. +Warning: [parser-warning] pkg.cabal:14:3: The field "cmm-sources" is available only since the Cabal specification version 3.0. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Testsuite1.8/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Testsuite1.8/cabal.out index e11f45f88a1..6ec9ae7a2ff 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Testsuite1.8/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/Testsuite1.8/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The 'test-suite' section is new in Cabal 1.10. Unfortunately it messes up the parser in older Cabal versions so you must specify at least 'cabal-version: >= 1.8', but note that only Cabal 1.10 and later can actually run such test suites. +Error: [test-cabal-ver] The 'test-suite' section is new in Cabal 1.10. Unfortunately it messes up the parser in older Cabal versions so you must specify at least 'cabal-version: >= 1.8', but note that only Cabal 1.10 and later can actually run such test suites. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/VirtualModules/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/VirtualModules/cabal.out index 0d294b7fa40..8b58c8122f0 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/VirtualModules/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/CabalVersion/VirtualModules/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:14:3: The field "virtual-modules" is available only since the Cabal specification version 2.2. This field will be ignored. +Warning: [parser-warning] pkg.cabal:14:3: The field "virtual-modules" is available only since the Cabal specification version 2.2. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/DeprecatedExtension/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/DeprecatedExtension/cabal.out index 312b6054a67..4b84de207fe 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/DeprecatedExtension/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/DeprecatedExtension/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: Deprecated extensions: 'RecordPuns'. Instead of 'RecordPuns' use 'NamedFieldPuns'. +Warning: [deprecated-extensions] Deprecated extensions: 'RecordPuns'. Instead of 'RecordPuns' use 'NamedFieldPuns'. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/cabal.out index 5710d84e88c..c037b09c0f5 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: The package has an impossible version range for a dependency on an internal library: pkg:internal >1.0. This version range does not include the current package, and must be removed as the current package's library will always be used. +Error: [impossible-dep] The package has an impossible version range for a dependency on an internal library: pkg:internal >1.0 && <2.0. This version range does not include the current package, and must be removed as the current package's library will always be used. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/pkg.cabal index 71c35a369a3..ffebdd5ee04 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/pkg.cabal +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ImpossibleVersionRangeLib/pkg.cabal @@ -10,7 +10,7 @@ license: GPL-3.0-or-later library exposed-modules: Module build-depends: base == 4.*, - internal > 1.0 + internal > 1.0 && < 2.0 default-language: Haskell2010 library internal diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/InvalidTestedWithRange/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/InvalidTestedWithRange/cabal.out index 42ba46392e1..10302be399d 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/InvalidTestedWithRange/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/InvalidTestedWithRange/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Invalid 'tested-with' version range: ghc ==6.10 && ==7.1. To indicate that you have tested a package with multiple different versions of the same compiler use multiple entries, for example 'tested-with: GHC==6.10.4, GHC==6.12.3' and not 'tested-with: GHC==6.10.4 && ==6.12.3'. +Error: [invalid-range-tested] Invalid 'tested-with' version range: ghc ==6.10 && ==7.1. To indicate that you have tested a package with multiple different versions of the same compiler use multiple entries, for example 'tested-with: GHC==6.10.4, GHC==6.12.3' and not 'tested-with: GHC==6.10.4 && ==6.12.3'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/LanguageAsExtension/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/LanguageAsExtension/cabal.out index b9fc6aad35b..abe57ea0117 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/LanguageAsExtension/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/LanguageAsExtension/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Languages listed as extensions: Haskell98. Languages must be specified in either the 'default-language' or the 'other-languages' field. +Error: [languages-as-extensions] Languages listed as extensions: Haskell98. Languages must be specified in either the 'default-language' or the 'other-languages' field. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoBuildTypeSpecified/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoBuildTypeSpecified/cabal.out index db55a3ca9d2..a8f63c2e114 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoBuildTypeSpecified/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoBuildTypeSpecified/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: No 'build-type' specified. If you do not need a custom Setup.hs or ./configure script then use 'build-type: Simple'. +Error: [no-build-type] No 'build-type' specified. If you do not need a custom Setup.hs or ./configure script then use 'build-type: Simple'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCategory/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCategory/cabal.out index 212ddc826c1..b458ed6d1b6 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCategory/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCategory/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: No 'category' field. +Warning: [no-category] No 'category' field. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCustom/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCustom/cabal.out index 26779e22ed2..8d4059d241e 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCustom/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoCustom/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Ignoring the 'custom-setup' section because the 'build-type' is not 'Custom'. Use 'build-type: Custom' if you need to use a custom Setup.hs script. +Error: [undeclared-custom-setup] Ignoring the 'custom-setup' section because the 'build-type' is not 'Custom'. Use 'build-type: Custom' if you need to use a custom Setup.hs script. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoDescription/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoDescription/cabal.out index 3754003ebd5..90308bb925e 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoDescription/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoDescription/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: No 'description' field. +Warning: [no-description] No 'description' field. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoMaintainer/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoMaintainer/cabal.out index 18f1b2e50ae..42cc2c2f15f 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoMaintainer/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoMaintainer/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: No 'maintainer' field. +Warning: [no-maintainer] No 'maintainer' field. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoSynopsis/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoSynopsis/cabal.out index 7c5e82873a1..cbe4fb78ae3 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoSynopsis/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoSynopsis/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: No 'synopsis' field. +Warning: [no-synopsis] No 'synopsis' field. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoZPrefix/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoZPrefix/cabal.out index 61998a26253..927476c9569 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoZPrefix/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/NoZPrefix/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Package names with the prefix 'z-' are reserved by Cabal and cannot be used. +Error: [reserved-z-prefix] Package names with the prefix 'z-' are reserved by Cabal and cannot be used. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ShortDescription/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ShortDescription/cabal.out index 6ab4a3c38b4..da4e609be7a 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ShortDescription/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/ShortDescription/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: The 'description' field should be longer than the 'synopsis' field. It's useful to provide an informative 'description' to allow Haskell programmers who have never heard about your package to understand the purpose of your package. The 'description' field content is typically shown by tooling (e.g. 'cabal info', Haddock, Hackage) below the 'synopsis' which serves as a headline. Please refer to for more details. +Warning: [short-description] The 'description' field should be longer than the 'synopsis' field. It's useful to provide an informative 'description' to allow Haskell programmers who have never heard about your package to understand the purpose of your package. The 'description' field content is typically shown by tooling (e.g. 'cabal info', Haddock, Hackage) below the 'synopsis' which serves as a headline. Please refer to for more details. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownCompiler/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownCompiler/cabal.out index 2859433cf4d..a9ea6b85ef8 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownCompiler/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownCompiler/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Unknown compiler 'figforth' in 'tested-with' field. +Error: [unknown-compiler-tested] Unknown compiler 'figforth' in 'tested-with' field. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownExtension/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownExtension/cabal.out index 7b44b7da37f..61d9f7e4fe0 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownExtension/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownExtension/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Unknown extensions: ObliqueTypes +Error: [unknown-extension] Unknown extensions: ObliqueTypes Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownLanguage/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownLanguage/cabal.out index 38512b53c70..acc60085f69 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownLanguage/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Fields/UnknownLanguage/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: Unknown languages: Haskell2030 +Error: [unknown-languages] Unknown languages: Haskell2030 Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCOptions/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCOptions/cabal.out index 1227df464c0..3ff40908e34 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCOptions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCOptions/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'ghc-options: -fasm' is unnecessary and will not work on CPU architectures other than x86, x86-64, ppc or sparc. +Error: [option-fasm] 'ghc-options: -fasm' is unnecessary and will not work on CPU architectures other than x86, x86-64, ppc or sparc. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCProfOptions/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCProfOptions/cabal.out index eff6f0352a7..0c49fb8c1d6 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCProfOptions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCProfOptions/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: 'ghc-prof-options: -o' is not needed. The output files are named automatically. +Error: [option-o] 'ghc-prof-options: -o' is not needed. The output files are named automatically. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCSharedOptions/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCSharedOptions/cabal.out index 996af558dce..44d0a6ecfd2 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCSharedOptions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/GHCSharedOptions/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: Instead of 'ghc-shared-options: -fglasgow-exts' it is preferable to use the 'extensions' field. +Warning: [use-extension] Instead of 'ghc-shared-options: -fglasgow-exts' it is preferable to use the 'extensions' field. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/cabal.test.hs new file mode 100644 index 00000000000..856a1aaad81 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/cabal.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +-- Do not output warning when an -O2 is behind a cabal flag. +main = cabalTest $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/pkg.cabal new file mode 100644 index 00000000000..da87e698285 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlag/pkg.cabal @@ -0,0 +1,18 @@ +cabal-version: 2.2 +name: pkg +version: 0 +category: example +maintainer: none@example.com +synopsis: synopsys +description: description +license: GPL-3.0-or-later + +flag force-O2 + default: False + manual: True + +library + exposed-modules: Foo + default-language: Haskell2010 + if flag(force-O2) + ghc-options: -O2 diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/cabal.out new file mode 100644 index 00000000000..077d7e9e85c --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/cabal.out @@ -0,0 +1,3 @@ +# cabal check +These warnings may cause trouble when distributing the package: +Warning: [option-o2] 'ghc-options: -O2' is rarely needed. Check that it is giving a real benefit and not just imposing longer compile times on your users. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/cabal.test.hs new file mode 100644 index 00000000000..e9e0fe10b47 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Output warning when an -O2 inside a cabal flag, but the flag is not +-- marked as `manual: True`. +main = cabalTest $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/pkg.cabal new file mode 100644 index 00000000000..415422cff12 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagManual/pkg.cabal @@ -0,0 +1,17 @@ +cabal-version: 2.2 +name: pkg +version: 0 +category: example +maintainer: none@example.com +synopsis: synopsys +description: description +license: GPL-3.0-or-later + +flag force-O2 + default: False + +library + exposed-modules: Foo + default-language: Haskell2010 + if flag(force-O2) + ghc-options: -O2 diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/cabal.out new file mode 100644 index 00000000000..077d7e9e85c --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/cabal.out @@ -0,0 +1,3 @@ +# cabal check +These warnings may cause trouble when distributing the package: +Warning: [option-o2] 'ghc-options: -O2' is rarely needed. Check that it is giving a real benefit and not just imposing longer compile times on your users. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/cabal.test.hs new file mode 100644 index 00000000000..8cfba826bd7 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/cabal.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +-- Output warning when an -O2 outside a cabal flag, along with one inside. +main = cabalTest $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/pkg.cabal new file mode 100644 index 00000000000..cec9eec5fe9 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/GHCOptions/NoWarnFlagOut/pkg.cabal @@ -0,0 +1,19 @@ +cabal-version: 2.2 +name: pkg +version: 0 +category: example +maintainer: none@example.com +synopsis: synopsys +description: description +license: GPL-3.0-or-later + +flag force-O2 + default: False + manual: True + +library + exposed-modules: Foo + default-language: Haskell2010 + ghc-options: -O2 + if flag(force-O2) + ghc-options: -O2 diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/Compatibility/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/Compatibility/cabal.out index e41ad1c8b5d..a5f9fe9b670 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/Compatibility/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/Compatibility/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Unfortunately the license 'ISC' messes up the parser in earlier Cabal versions so you need to specify 'cabal-version: >= 1.4'. Alternatively if you require compatibility with earlier Cabal versions then use 'OtherLicense'. +Error: [license-parse] Unfortunately the license 'ISC' messes up the parser in earlier Cabal versions so you need to specify 'cabal-version: >= 1.4'. Alternatively if you require compatibility with earlier Cabal versions then use 'OtherLicense'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoFileSpecified/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoFileSpecified/cabal.out index a21a032fdc5..aba9738f1d5 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoFileSpecified/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoFileSpecified/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: A 'license-file' is not specified. +Warning: [no-license-file] A 'license-file' is not specified. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoLicense/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoLicense/cabal.out index b5b98a177f9..21fe34be8c0 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoLicense/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoLicense/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The 'license' field is missing or is NONE. +Error: [license-none] The 'license' field is missing or is NONE. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoneLicense/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoneLicense/cabal.out index b5b98a177f9..21fe34be8c0 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoneLicense/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/NoneLicense/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The 'license' field is missing or is NONE. +Error: [license-none] The 'license' field is missing or is NONE. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousLicense/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousLicense/cabal.out index 5c3e9dcfc94..890c548b3e7 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousLicense/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousLicense/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: Using 'license: BSD4' is almost always a misunderstanding. 'BSD4' refers to the old 4-clause BSD license with the advertising clause. 'BSD3' refers the new 3-clause BSD license. +Warning: [bsd4-license] Using 'license: BSD4' is almost always a misunderstanding. 'BSD4' refers to the old 4-clause BSD license with the advertising clause. 'BSD3' refers the new 3-clause BSD license. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousVersion/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousVersion/cabal.out index e42fa129f7b..262947562a1 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousVersion/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/SuspiciousVersion/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: 'license: GPL-5' is not a known version of that license. The known versions are 2, 3. If this is not a mistake and you think it should be a known version then please file a ticket. +Warning: [unknown-license-version] 'license: GPL-5' is not a known version of that license. The known versions are 2, 3. If this is not a mistake and you think it should be a known version then please file a ticket. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/UnknownLicence/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/UnknownLicence/cabal.out index f5cb98a415e..82915b6973c 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/UnknownLicence/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/UnknownLicence/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: 'license: Illiberal' is not a recognised license. The known licenses are: GPL, GPL-2, GPL-3, LGPL, LGPL-2.1, LGPL-3, AGPL, AGPL-3, BSD2, BSD3, MIT, ISC, MPL-2.0, Apache, Apache-2.0, PublicDomain, AllRightsReserved, OtherLicense +Error: [unknown-license] 'license: Illiberal' is not a recognised license. The known licenses are: GPL, GPL-2, GPL-3, LGPL, LGPL-2.1, LGPL-3, AGPL, AGPL-3, BSD2, BSD3, MIT, ISC, MPL-2.0, Apache, Apache-2.0, PublicDomain, AllRightsReserved, OtherLicense Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/WarnAllRightsReserved/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/WarnAllRightsReserved/cabal.out index a3bae9860eb..0dfd27c6aae 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/WarnAllRightsReserved/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/License/WarnAllRightsReserved/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: The 'license' is AllRightsReserved. Is that really what you want? +Warning: [all-rights-reserved] The 'license' is AllRightsReserved. Is that really what you want? diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePath/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePath/cabal.out index 23af99ec09a..562f6f4d4f7 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePath/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePath/cabal.out @@ -1,7 +1,7 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: In 'extra-source-files': the pattern '/home/user/file' does not match any files. +Warning: [glob-missing-dir] In 'extra-source-files': the pattern '/home/user/file' attempts to match files in the directory '/home/user', but there is no directory by that name. The following errors will cause portability problems on other environments: -Error: 'extra-source-files: /home/user/file' specifies an absolute path, but the 'extra-source-files' field must use relative paths. -Error: 'extra-source-files: /home/user/file' is not a good relative path: "posix absolute path" +Error: [absolute-path] 'extra-source-files: /home/user/file' specifies an absolute path, but the 'extra-source-files' field must use relative paths. +Error: [malformed-relative-path] 'extra-source-files: /home/user/file' is not a good relative path: "posix absolute path" Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/cabal.test.hs new file mode 100644 index 00000000000..a6da4f86777 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Absolute paths can be used in `extra-lib-dirs`. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/pkg.cabal new file mode 100644 index 00000000000..087e00b080b --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/AbsolutePathExtraLibDirs/pkg.cabal @@ -0,0 +1,13 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +library + exposed-modules: Module + default-language: Haskell2010 + extra-lib-dirs: /home/ diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/DistPoint/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/DistPoint/cabal.out index 81f9ada5773..da3b67b4433 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/DistPoint/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/DistPoint/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'ghc-options' path 'dist/file' points inside the 'dist' directory. This is not reliable because the location of this directory is configurable by the user (or package manager). In addition the layout of the 'dist' directory is subject to change in future versions of Cabal. +Error: [unreliable-dist-path] 'ghc-options' path 'dist/file' points inside the 'dist' directory. This is not reliable because the location of this directory is configurable by the user (or package manager). In addition, the layout of the 'dist' directory is subject to change in future versions of Cabal. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.out index 55661e48010..93ecfd3c969 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The path 'n?ul/*.a' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". +Error: [invalid-path-win] The path 'n?ul/*.a' is invalid on Windows, which would cause portability problems for this package. Windows file names cannot contain any of the characters ":*?<>|" and there a few reserved names including "aux", "nul", "con", "prn", "com1-9", "lpt1-9" and "clock$". Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.test.hs index e99fccc6bc4..2201d7c73dc 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/InvalidWin/cabal.test.hs @@ -3,7 +3,7 @@ import Test.Cabal.Prelude import System.Directory (createDirectoryIfMissing) -- Invalid Windows filepath. -main = cabalTest . withSourceCopy $ do +main = cabalTest $ do skipIfWindows cwd <- testCurrentDir <$> getTestEnv liftIO $ createDirectoryIfMissing False $ cwd "n?ul" diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/a.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/a.hs new file mode 100644 index 00000000000..6ca9a1fce6e --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/a.hs @@ -0,0 +1 @@ +module Main where diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/cabal.out index e2506317dc1..8da49655e16 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RecursiveGlobInRoot/cabal.out @@ -1,5 +1,5 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: In the 'data-files': glob '**/*.dat' starts at project root directory, this might include `.git/`, ``dist-newstyle/``, or other large directories! -Warning: In the 'extra-source-files': glob '**/*.hs' starts at project root directory, this might include `.git/`, ``dist-newstyle/``, or other large directories! -Warning: In the 'extra-doc-files': glob '**/*.md' starts at project root directory, this might include `.git/`, ``dist-newstyle/``, or other large directories! +Warning: [recursive-glob] In the 'data-files': glob '**/*.dat' starts at project root directory, this might include `.git/`, ``dist-newstyle/``, or other large directories! +Warning: [recursive-glob] In the 'extra-doc-files': glob '**/*.md' starts at project root directory, this might include `.git/`, ``dist-newstyle/``, or other large directories! +Warning: [recursive-glob] In the 'extra-source-files': glob '**/*.hs' starts at project root directory, this might include `.git/`, ``dist-newstyle/``, or other large directories! diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/RelativeOutsideInner/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/RelativeOutsideInner/cabal.out deleted file mode 100644 index 8cadbcb8dac..00000000000 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/RelativeOutsideInner/cabal.out +++ /dev/null @@ -1,6 +0,0 @@ -# cabal check -The following errors are likely to affect your build negatively: -Error: 'extra-source-files: ../outside' is a relative path outside of the source tree. This will not work when generating a tarball with 'sdist'. -The following errors will cause portability problems on other environments: -Error: 'extra-source-files: ../outside' is not a good relative path: "parent directory segment: .." -Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/cabal.out new file mode 100644 index 00000000000..8ad6abfabfa --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/cabal.out @@ -0,0 +1,6 @@ +# cabal check +The following errors are likely to affect your build negatively: +Error: [relative-path-outside] 'extra-source-files: ../outside' is a relative path outside of the source tree. This will not work when generating a tarball with 'sdist'. +The following errors will cause portability problems on other environments: +Error: [malformed-relative-path] 'extra-source-files: ../outside' is not a good relative path: "parent directory segment: .." +Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/cabal.test.hs new file mode 100644 index 00000000000..8da253ff8b4 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Paths/RelativeOutside/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Relative filepath outside source tree. +main = cabalTest $ + fails $ withDirectory "RelativeOutsideInner" $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOther/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOther/cabal.out index 94c22120311..d9f8024aff9 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOther/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOther/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. +Error: [autogen-not-exposed] An 'autogen-module' is neither on 'exposed-modules' nor 'other-modules'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherBenchmark/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherBenchmark/cabal.out index a44b9f6880e..8df661d2d7c 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherBenchmark/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherBenchmark/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: On benchmark 'benchmark' an 'autogen-module' is not on 'other-modules' +Error: [autogen-other-modules] On benchmark 'benchmark' an 'autogen-module' is not on 'other-modules' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherExe/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherExe/cabal.out index f31c3ad2803..6626c28605a 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherExe/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherExe/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: On executable 'exe' an 'autogen-module' is not on 'other-modules' +Error: [autogen-other-modules] On executable 'exe' an 'autogen-module' is not on 'other-modules' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherTestsuite/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherTestsuite/cabal.out index f62322ba72b..708f8cb0d19 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherTestsuite/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenExposedOtherTestsuite/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: On test suite 'test' an 'autogen-module' is not on 'other-modules' +Error: [autogen-other-modules] On test suite 'test' an 'autogen-module' is not on 'other-modules' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludes/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludes/cabal.out index b4977e9d6c6..986ba6008f8 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludes/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludes/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: An include in 'autogen-includes' is neither in 'includes' or 'install-includes'. +Error: [autogen-not-included] An include in 'autogen-includes' is neither in 'includes' nor 'install-includes'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesBenchmark/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesBenchmark/cabal.out index a1b2bc17f2d..f96159eaed6 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesBenchmark/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesBenchmark/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: An include in 'autogen-includes' is not in 'includes'. +Error: [autogen-exe] An include in 'autogen-includes' is not in 'includes'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesExe/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesExe/cabal.out index a1b2bc17f2d..f96159eaed6 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesExe/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesExe/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: An include in 'autogen-includes' is not in 'includes'. +Error: [autogen-exe] An include in 'autogen-includes' is not in 'includes'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesTestsuite/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesTestsuite/cabal.out index a1b2bc17f2d..f96159eaed6 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesTestsuite/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenIncludesTestsuite/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: An include in 'autogen-includes' is not in 'includes'. +Error: [autogen-exe] An include in 'autogen-includes' is not in 'includes'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/cabal.out new file mode 100644 index 00000000000..31ef4966d03 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/cabal.out @@ -0,0 +1,4 @@ +# cabal check +The package will not build sanely due to these errors: +Error: [autogen-guard] To use the autogenerated module PackageInfo_* you need to specify `cabal-version: 3.12` or higher. +Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/cabal.test.hs new file mode 100644 index 00000000000..c9c2e56de21 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/cabal.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- #9331: PackageInfo functionality should be guarded by cabal-version. +main = cabalTest $ + fails $ cabal "check" [] + diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/pkg.cabal new file mode 100644 index 00000000000..aeef460f7f0 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersion/pkg.cabal @@ -0,0 +1,16 @@ +cabal-version: 2.4 +name: pkg +version: 0 +license: GPL-3.0-or-later +maintainer: Someone +category: Example +synopsis: Foo +description: FooBar +build-type: Simple + +library + default-language: Haskell2010 + build-depends: base <5 + autogen-modules: PackageInfo_pkg + exposed-modules: PackageInfo_pkg + diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/cabal.test.hs b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/cabal.test.hs new file mode 100644 index 00000000000..baa6f988ea0 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/cabal.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +-- #9331: PackageInfo functionality should be guarded by cabal-version, +-- does not error when cabal-version is 3.12 or higher. +main = cabalTest $ + cabal "check" [] + diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/pkg.cabal b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/pkg.cabal new file mode 100644 index 00000000000..f2183649526 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/AutogenVersionOk/pkg.cabal @@ -0,0 +1,16 @@ +cabal-version: 3.12 +name: pkg +version: 0 +license: GPL-3.0-or-later +maintainer: Someone +category: Example +synopsis: Foo +description: FooBar +build-type: Simple + +library + default-language: Haskell2010 + build-depends: base <5 + autogen-modules: PackageInfo_pkg + exposed-modules: PackageInfo_pkg + diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersion/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersion/cabal.out index 5e09174e51b..153c5f76ca9 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersion/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersion/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The package uses a C/C++/obj-C source file for the 'main-is' field. To use this feature you need to specify 'cabal-version: 1.18' or higher. +Error: [c-like-main] The package uses a C/C++/obj-C source file for the 'main-is' field. To use this feature you need to specify 'cabal-version: 1.18' or higher. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersionTestsuite/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersionTestsuite/cabal.out index 5e09174e51b..153c5f76ca9 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersionTestsuite/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/CMainIsVersionTestsuite/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The package uses a C/C++/obj-C source file for the 'main-is' field. To use this feature you need to specify 'cabal-version: 1.18' or higher. +Error: [c-like-main] The package uses a C/C++/obj-C source file for the 'main-is' field. To use this feature you need to specify 'cabal-version: 1.18' or higher. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIs/cabal.out index 6bc2ecc6449..a512bdbde70 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIs/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIs/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: The 'main-is' field must specify a '.hs' or '.lhs' file (even if it is generated by a preprocessor), or it may specify a C/C++/obj-C source file. +Error: [unknown-extension-main] The 'main-is' field must specify a '.hs' or '.lhs' file (even if it is generated by a preprocessor), or it may specify a C/C++/obj-C source file. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsBenchmark/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsBenchmark/cabal.out index 1eb6a2febe9..c118f5ca4b3 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsBenchmark/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsBenchmark/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: The 'main-is' field must specify a '.hs' or '.lhs' file (even if it is generated by a preprocessor). +Error: [bench-unknown-extension] The 'main-is' field must specify a '.hs' or '.lhs' file (even if it is generated by a preprocessor). Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsTestsuite/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsTestsuite/cabal.out index 6bc2ecc6449..a512bdbde70 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsTestsuite/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/MalformedMainIsTestsuite/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: The 'main-is' field must specify a '.hs' or '.lhs' file (even if it is generated by a preprocessor), or it may specify a C/C++/obj-C source file. +Error: [unknown-extension-main] The 'main-is' field must specify a '.hs' or '.lhs' file (even if it is generated by a preprocessor), or it may specify a C/C++/obj-C source file. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoBody/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoBody/cabal.out index 8655087550d..ea20496c0bb 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoBody/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoBody/cabal.out @@ -1,6 +1,6 @@ # cabal check The package will not build sanely due to these errors: -Error: No executables, libraries, tests, or benchmarks found. Nothing to do. +Error: [no-target] No executables, libraries, tests, or benchmarks found. Nothing to do. These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:0:0: A package using 'cabal-version: 2.2' must use section syntax. See the Cabal user guide for details. +Warning: [parser-warning] pkg.cabal:0:0: A package using 'cabal-version: 2.2' must use section syntax. See the Cabal user guide for details. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoDupNames/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoDupNames/cabal.out index be0d14356f6..b55258a3f28 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoDupNames/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoDupNames/cabal.out @@ -1 +1,4 @@ # cabal check +The package will not build sanely due to these errors: +Error: [duplicate-sections] Duplicate sections: dup. The name of every library, executable, test suite, and benchmark section in the package must be unique. +Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoExposedModules/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoExposedModules/cabal.out index 3ae23450b99..7ece70213f9 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoExposedModules/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoExposedModules/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: library does not expose any modules +Warning: [no-modules-exposed] library does not expose any modules diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoInternalNameClash/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoInternalNameClash/cabal.out index 9366f5237f0..275672a9865 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoInternalNameClash/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoInternalNameClash/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: Illegal internal library name pkg. Internal libraries cannot have the same name as the package. Maybe you wanted a non-internal library? If so, rewrite the section stanza from 'library: 'pkg' to 'library'. +Error: [illegal-library-name] Illegal internal library name pkg. Internal libraries cannot have the same name as the package. Maybe you wanted a non-internal library? If so, rewrite the section stanza from 'library: 'pkg' to 'library'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoMainIs/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoMainIs/cabal.out index ba56af15c08..f1f7cfe863b 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoMainIs/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/NoMainIs/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: No 'main-is' field found for executable exe +Error: [no-main-is] No 'main-is' field found for executable exe Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/VersionSignatures/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/VersionSignatures/cabal.out index 2583cecb229..335e87962e3 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/VersionSignatures/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/Sanity/VersionSignatures/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:17:3: The field "signatures" is available only since the Cabal specification version 2.0. This field will be ignored. +Warning: [parser-warning] pkg.cabal:17:3: The field "signatures" is available only since the Cabal specification version 2.0. This field will be ignored. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoGoodRelative/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoGoodRelative/cabal.out index 9d466d9b746..5cf561d9b47 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoGoodRelative/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoGoodRelative/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The 'subdir' field of a source-repository is not a good relative path: "empty path segment" +Error: [repo-malformed-subdir] The 'subdir' field of a source-repository is not a good relative path: "empty path segment" Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoLocation/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoLocation/cabal.out index 024e9692a50..1af7aa00f75 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoLocation/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoLocation/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The source-repository 'location' is a required field. +Error: [repo-no-location] The source-repository 'location' is a required field. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoModuleCVS/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoModuleCVS/cabal.out index a4ed5c844b5..25b389de331 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoModuleCVS/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoModuleCVS/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: For a CVS source-repository, the 'module' is a required field. +Error: [repo-no-module] For a CVS source-repository, the 'module' is a required field. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoType/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoType/cabal.out index 252f5fb7f8b..d5fedfd3a4d 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoType/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NoType/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The source-repository 'type' is a required field. +Error: [repo-no-type] The source-repository 'type' is a required field. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NonRecognisedRepo/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NonRecognisedRepo/cabal.out index 0bd66421809..614be86180e 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NonRecognisedRepo/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/NonRecognisedRepo/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'tail' is not a recognised kind of source-repository. The repo kind is usually 'head' or 'this' +Error: [unrecognised-repo-type] 'tail' is not a recognised kind of source-repository. The repo kind is usually 'head' or 'this' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/SubdirRelative/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/SubdirRelative/cabal.out index 56b53170135..6c5e3f356c2 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/SubdirRelative/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/SubdirRelative/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The 'subdir' field of a source-repository must be a relative path. +Error: [repo-relative-dir] The 'subdir' field of a source-repository must be a relative path. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/ThisTag/cabal.out b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/ThisTag/cabal.out index 32bcf334cf5..b9185de3002 100644 --- a/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/ThisTag/cabal.out +++ b/cabal-testsuite/PackageTests/Check/ConfiguredPackage/SourceRepos/ThisTag/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: For the 'this' kind of source-repository, the 'tag' is a required field. It should specify the tag corresponding to this version or release of the package. +Error: [repo-no-tag] For the 'this' kind of source-repository, the 'tag' is a required field. It should specify the tag corresponding to this version or release of the package. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/DifferentGhcOptions/cabal.out b/cabal-testsuite/PackageTests/Check/DifferentGhcOptions/cabal.out index eb51a7165be..c8f48453a0c 100644 --- a/cabal-testsuite/PackageTests/Check/DifferentGhcOptions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/DifferentGhcOptions/cabal.out @@ -1,8 +1,8 @@ # cabal check The following errors are likely to affect your build negatively: -Error: 'ghc-shared-options: -hide-package' is never needed. Cabal hides all packages. +Error: [option-hide-package] 'ghc-shared-options: -hide-package' is never needed. Cabal hides all packages. The following errors will cause portability problems on other environments: -Error: 'ghc-options: -fasm' is unnecessary and will not work on CPU architectures other than x86, x86-64, ppc or sparc. -Error: 'ghc-prof-options: -fhpc' is not necessary. Use the configure flag --enable-coverage instead. -Error: 'ghc-shared-options: -Werror' makes the package easy to break with future GHC versions because new GHC versions often add new warnings. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Error: [option-fasm] 'ghc-options: -fasm' is unnecessary and will not work on CPU architectures other than x86, x86-64, ppc or sparc. +Error: [option-fhpc] 'ghc-prof-options: -fhpc' is not necessary. Use the configure flag --enable-coverage instead. +Error: [werror] 'ghc-shared-options: -Werror' makes the package easy to break with future GHC versions because new GHC versions often add new warnings. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/cabal.out b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/cabal.out new file mode 100644 index 00000000000..2c662d91fd5 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/cabal.out @@ -0,0 +1,4 @@ +# cabal check +Warning: Unrecognised ignore "foo" +These warnings will likely cause trouble when distributing the package: +Warning: [short-description] The 'description' field should be longer than the 'synopsis' field. It's useful to provide an informative 'description' to allow Haskell programmers who have never heard about your package to understand the purpose of your package. The 'description' field content is typically shown by tooling (e.g. 'cabal info', Haddock, Hackage) below the 'synopsis' which serves as a headline. Please refer to for more details. diff --git a/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/cabal.test.hs b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/cabal.test.hs new file mode 100644 index 00000000000..c0e53a59ceb --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/cabal.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +-- Warns (but does not error) when an ignore option is not recognised. +main = cabalTest $ cabal "check" ["--ignore=foo"] diff --git a/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/pkg.cabal b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/pkg.cabal new file mode 100644 index 00000000000..a017b6f56bd --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Missing/pkg.cabal @@ -0,0 +1,13 @@ +cabal-version: 2.2 +name: pkg +version: 0 +category: example +maintainer: none@example.com +synopsis: very big synopsis +description: short desc +license: BSD-3-Clause + +library + exposed-modules: Foo + default-language: Haskell2010 + diff --git a/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/cabal.out b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/cabal.test.hs b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/cabal.test.hs new file mode 100644 index 00000000000..7b06be026b6 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/cabal.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +-- Should ignore warnings if instructed so. +main = cabalTest $ cabal "check" ["--ignore=short-description"] diff --git a/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/pkg.cabal b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/pkg.cabal new file mode 100644 index 00000000000..a017b6f56bd --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/IgnoreWarning/Ok/pkg.cabal @@ -0,0 +1,13 @@ +cabal-version: 2.2 +name: pkg +version: 0 +category: example +maintainer: none@example.com +synopsis: very big synopsis +description: short desc +license: BSD-3-Clause + +library + exposed-modules: Foo + default-language: Haskell2010 + diff --git a/cabal-testsuite/PackageTests/Check/InvalidGlob/cabal.out b/cabal-testsuite/PackageTests/Check/InvalidGlob/cabal.out index b97dc6df39a..7e0db864cbd 100644 --- a/cabal-testsuite/PackageTests/Check/InvalidGlob/cabal.out +++ b/cabal-testsuite/PackageTests/Check/InvalidGlob/cabal.out @@ -1,5 +1,5 @@ # cabal check The following errors will cause portability problems on other environments: -Error: No 'synopsis' or 'description' field. -Error: In the 'extra-doc-files' field: invalid file glob '***.html'. Wildcards '*' may only totally replace the file's base name, not only parts of it. +Error: [no-syn-desc] No 'synopsis' or 'description' field. +Error: [glob-syntax-error] In the 'extra-doc-files' field: invalid file glob '***.html'. Wildcards '*' may only totally replace the file's base name, not only parts of it. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/MissingGlobDirectory/cabal.out b/cabal-testsuite/PackageTests/Check/MissingGlobDirectory/cabal.out index 8b7eb933524..7c5a77b0af7 100644 --- a/cabal-testsuite/PackageTests/Check/MissingGlobDirectory/cabal.out +++ b/cabal-testsuite/PackageTests/Check/MissingGlobDirectory/cabal.out @@ -1,6 +1,6 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: In 'data-files': the pattern 'another-non-existent-directory/**/*.dat' attempts to match files in the directory 'another-non-existent-directory', but there is no directory by that name. -Warning: In 'extra-doc-files': the pattern 'non-existent-directory/*.html' attempts to match files in the directory 'non-existent-directory', but there is no directory by that name. -Warning: In 'extra-doc-files': the pattern 'present/present/missing/*.tex' attempts to match files in the directory 'present/present/missing', but there is no directory by that name. -Warning: In 'extra-source-files': the pattern 'file-not-a-directory/*.js' attempts to match files in the directory 'file-not-a-directory', but there is no directory by that name. +Warning: [glob-missing-dir] In 'data-files': the pattern 'another-non-existent-directory/**/*.dat' attempts to match files in the directory 'another-non-existent-directory', but there is no directory by that name. +Warning: [glob-missing-dir] In 'extra-doc-files': the pattern 'non-existent-directory/*.html' attempts to match files in the directory 'non-existent-directory', but there is no directory by that name. +Warning: [glob-missing-dir] In 'extra-doc-files': the pattern 'present/present/missing/*.tex' attempts to match files in the directory 'present/present/missing', but there is no directory by that name. +Warning: [glob-missing-dir] In 'extra-source-files': the pattern 'file-not-a-directory/*.js' attempts to match files in the directory 'file-not-a-directory', but there is no directory by that name. diff --git a/cabal-testsuite/PackageTests/Check/MissingGlobDirectory2/cabal.out b/cabal-testsuite/PackageTests/Check/MissingGlobDirectory2/cabal.out index 61c410c936f..5aff271d3a7 100644 --- a/cabal-testsuite/PackageTests/Check/MissingGlobDirectory2/cabal.out +++ b/cabal-testsuite/PackageTests/Check/MissingGlobDirectory2/cabal.out @@ -1,5 +1,5 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: In 'extra-source-files': the pattern 'dir/*.html' does not match any files. -Warning: In 'extra-source-files': the pattern 'dir/*.html' does not match the file 'dir/foo.en.html' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. -Warning: In 'data-files': the pattern 'non-existent-directory/*.dat' attempts to match files in the directory 'non-existent-directory', but there is no directory by that name. +Warning: [no-glob-match] In 'extra-source-files': the pattern 'dir/*.html' does not match any files. +Warning: [glob-no-extension] In 'extra-source-files': the pattern 'dir/*.html' does not match the file 'dir/foo.en.html' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. +Warning: [glob-missing-dir] In 'data-files': the pattern 'non-existent-directory/*.dat' attempts to match files in the directory 'non-existent-directory', but there is no directory by that name. diff --git a/cabal-testsuite/PackageTests/Check/MultiDotGlob2.2/check.out b/cabal-testsuite/PackageTests/Check/MultiDotGlob2.2/check.out index 6769dd25153..ecf53a612e1 100644 --- a/cabal-testsuite/PackageTests/Check/MultiDotGlob2.2/check.out +++ b/cabal-testsuite/PackageTests/Check/MultiDotGlob2.2/check.out @@ -1,5 +1,5 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: In 'data-files': the pattern 'data/*.dat' does not match the file 'data/foo.bar.dat' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. -Warning: In 'extra-doc-files': the pattern 'doc/*.html' does not match the file 'doc/foo.en.html' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. -Warning: In 'extra-doc-files': the pattern 'doc/*.html' does not match the file 'doc/foo.fr.html' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. +Warning: [glob-no-extension] In 'data-files': the pattern 'data/*.dat' does not match the file 'data/foo.bar.dat' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. +Warning: [glob-no-extension] In 'extra-doc-files': the pattern 'doc/*.html' does not match the file 'doc/foo.en.html' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. +Warning: [glob-no-extension] In 'extra-doc-files': the pattern 'doc/*.html' does not match the file 'doc/foo.fr.html' because the extensions do not exactly match (e.g., foo.en.html does not exactly match *.html). To enable looser suffix-only matching, set 'cabal-version: 2.4' or higher. diff --git a/cabal-testsuite/PackageTests/Check/NoGlobMatches/cabal.out b/cabal-testsuite/PackageTests/Check/NoGlobMatches/cabal.out index bee06362960..f47cff76f82 100644 --- a/cabal-testsuite/PackageTests/Check/NoGlobMatches/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NoGlobMatches/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: In 'extra-doc-files': the pattern '*.html' does not match any files. +Warning: [no-glob-match] In 'extra-doc-files': the pattern '*.html' does not match any files. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownArch/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownArch/cabal.out index 38b924bc1d1..9efd7191156 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownArch/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownArch/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Unknown architecture name 'subleq' +Error: [unknown-arch] Unknown architecture name 'subleq' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownCompiler/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownCompiler/cabal.out index 58e4a87eb92..e0cb477b74a 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownCompiler/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownCompiler/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Unknown compiler name 'MHC' +Error: [unknown-compiler] Unknown compiler name 'MHC' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownOS/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownOS/cabal.out index d033025ea51..cc64fa8749f 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownOS/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/Conditionals/UnknownOS/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: Unknown operating system name 'plan9' +Error: [unknown-os] Unknown operating system name 'plan9' Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/DebugFlag/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/DebugFlag/cabal.out index d4729a6f484..4af99700027 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/DebugFlag/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/DebugFlag/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'ghc-prof-options: -d*' debug flags are not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Error: [debug-flag] 'ghc-prof-options: -d*' debug flags are not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/LICENSE b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/LICENSE new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/cabal.out new file mode 100644 index 00000000000..d74b60c5d26 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/cabal.out @@ -0,0 +1,4 @@ +# cabal check +The following errors will cause portability problems on other environments: +Error: [unneeded-j] 'ghc-options: -j[N]' can make sense for a particular user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/cabal.test.hs b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/cabal.test.hs new file mode 100644 index 00000000000..48efe554e6b --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- `check` should not be confused by an user flag. +main = cabalTest $ + fails $ cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/pkg.cabal b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/pkg.cabal new file mode 100644 index 00000000000..b0f8bc85140 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/ElseCheck/pkg.cabal @@ -0,0 +1,25 @@ +name: pkg +version: 0.0.0.1 +synopsis: The Servant +description: Various capabilities +category: prelude +maintainer: smokejumperit+rfc@gmail.com +license: MIT +license-file: LICENSE +build-type: Simple +cabal-version: >= 1.10 + +flag production + description: Disables failing. + manual: True + default: False + +library + exposed-modules: + RFC.Servant.API + ghc-options: -j + if flag(production) + ghc-options: -feager-blackholing + else + cpp-options: -DDEVELOPMENT + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/FDeferTypeErrors/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/FDeferTypeErrors/cabal.out index 1318b007be4..57bed9ce2b4 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/FDeferTypeErrors/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/FDeferTypeErrors/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'ghc-options: -fdefer-type-errors' is fine during development but is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Error: [fdefer-type-errors] 'ghc-options: -fdefer-type-errors' is fine during development but is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Jn/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Jn/cabal.out index 4024acad24e..96556490f23 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Jn/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Jn/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'ghc-shared-options: -j[N]' can make sense for specific user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Error: [unneeded-j] 'ghc-shared-options: -j[N]' can make sense for a particular user's setup, but it is not appropriate for a distributed package. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Profiling/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Profiling/cabal.out index 5426d7774e9..c6040f523c0 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Profiling/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/Profiling/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: 'ghc-shared-options: -fprof*' profiling flags are typically not appropriate for a distributed library package. These flags are useful to profile this package, but when profiling other packages that use this one these flags clutter the profile output with excessive detail. If you think other packages really want to see cost centres from this package then use '-fprof-auto-exported' which puts cost centres only on exported functions. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Warning: [fprof-flag] 'ghc-shared-options: -fprof*' profiling flags are typically not appropriate for a distributed library package. These flags are useful to profile this package, but when profiling other packages that use this one these flags clutter the profile output with excessive detail. If you think other packages really want to see cost centres from this package then use '-fprof-auto-exported' which puts cost centres only on exported functions. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WError/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WError/cabal.out index 1edd7773b26..3fae80d3802 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WError/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WError/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: 'ghc-prof-options: -Werror' makes the package easy to break with future GHC versions because new GHC versions often add new warnings. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. +Error: [werror] 'ghc-prof-options: -Werror' makes the package easy to break with future GHC versions because new GHC versions often add new warnings. Alternatively, if you want to use this, make it conditional based on a Cabal configuration flag (with 'manual: True' and 'default: False') and enable that flag during development. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/cabal.test.hs b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/cabal.test.hs new file mode 100644 index 00000000000..be0007ff8f3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Do not complain if WError is under a user, off-by-default flag. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/pkg.cabal b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/pkg.cabal new file mode 100644 index 00000000000..9a5e9b708d1 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DevOnlyFlags/WErrorGuarded/pkg.cabal @@ -0,0 +1,20 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +flag dev + description: Turn on development settings. + manual: True + default: False + +library + exposed-modules: Foo + default-language: Haskell2010 + if flag(dev) + ghc-options: -Werror + diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/DuplicatedModules/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/DuplicatedModules/cabal.out index 15bd94c337d..9c25b3cf526 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/DuplicatedModules/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/DuplicatedModules/cabal.out @@ -1,4 +1,4 @@ # cabal check The package will not build sanely due to these errors: -Error: Duplicate modules in library: Foo +Error: [duplicate-modules] Duplicate modules in library: Foo Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersions/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersions/cabal.out index 06d7bb58ed7..d87292f7506 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersions/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The dependency 'build-depends: base' does not specify an upper bound on the version number. Each major release of the 'base' package changes the API in various ways and most packages will need some changes to compile with it. The recommended practice is to specify an upper bound on the version of the 'base' package. This ensures your package will continue to build when a new major version of the 'base' package is released. If you are not sure what upper bound to use then use the next major version. For example if you have tested your package with 'base' version 4.5 and 4.6 then use 'build-depends: base >= 4.5 && < 4.7'. +Error: [missing-bounds-important] The dependency 'build-depends: base' does not specify an upper bound on the version number. Each major release of the 'base' package changes the API in various ways and most packages will need some changes to compile with it. The recommended practice is to specify an upper bound on the version of the 'base' package. This ensures your package will continue to build when a new major version of the 'base' package is released. If you are not sure what upper bound to use then use the next major version. For example if you have tested your package with 'base' version 4.5 and 4.6 then use 'build-depends: base >= 4.5 && < 4.7'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/cabal.test.hs b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/cabal.test.hs new file mode 100644 index 00000000000..1a6b28f94fc --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Unbounded (top) base with internal dependency: no warn, no error. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/pkg.cabal b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/pkg.cabal new file mode 100644 index 00000000000..91943d4987a --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternal/pkg.cabal @@ -0,0 +1,19 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +library + exposed-modules: Foo + default-language: Haskell2010 + build-depends: base <= 3.10 + +executable test-exe + main-is: Main.hs + default-language: Haskell2010 + build-depends: base, pkg + diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/cabal.out new file mode 100644 index 00000000000..2c1d8a72480 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/cabal.out @@ -0,0 +1,5 @@ +# cabal check +These warnings may cause trouble when distributing the package: +Warning: [missing-upper-bounds] On executable 'prova', these packages miss upper bounds: + - acme-box +Please add them. There is more information at https://pvp.haskell.org/ diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/cabal.test.hs b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/cabal.test.hs new file mode 100644 index 00000000000..62207619ac5 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Unbounded with internal dependency: do not warn. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/pkg.cabal b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/pkg.cabal new file mode 100644 index 00000000000..06c47e49740 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsInternalSimple/pkg.cabal @@ -0,0 +1,22 @@ +cabal-version: 3.0 +name: pkg +version: 2 +maintainer: fffaaa +category: asdasd +synopsis: asdcasdcs +description: cdscsd acs dcs dss +license: GPL-3.0-or-later + +library + exposed-modules: Foo + build-depends: text < 5.0 + default-language: Haskell2010 + +executable prova + main-is: Prova.hs + build-depends: + pkg + , text + , acme-box + default-language: Haskell2010 + diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/cabal.out new file mode 100644 index 00000000000..c9f531cbd6e --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/cabal.out @@ -0,0 +1,5 @@ +# cabal check +These warnings may cause trouble when distributing the package: +Warning: [missing-upper-bounds] On library 'int-lib', these packages miss upper bounds: + - text +Please add them. There is more information at https://pvp.haskell.org/ diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/cabal.test.hs b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/cabal.test.hs new file mode 100644 index 00000000000..597002165fb --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Internal libraries missing upper bound are correctly reported. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/pkg.cabal b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/pkg.cabal new file mode 100644 index 00000000000..3d5b861f059 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsLibInt/pkg.cabal @@ -0,0 +1,20 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +library + exposed-modules: Foo + build-depends: base <= 3.10, + int-lib + default-language: Haskell2010 + +library int-lib + exposed-modules: Bar + build-depends: text > 1 + default-language: Haskell2010 + diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/cabal.test.hs b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/cabal.test.hs new file mode 100644 index 00000000000..c0819c5841a --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/cabal.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- Straddle deps declarations (build-depends: base > 5, base < 6) +-- should not error. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/pkg.cabal b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/pkg.cabal new file mode 100644 index 00000000000..b21ffe61f12 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PackageVersionsStraddle/pkg.cabal @@ -0,0 +1,15 @@ +cabal-version: 3.0 +name: pkg +synopsis: synopsis +description: description +version: 0 +category: example +maintainer: none@example.com +license: GPL-3.0-or-later + +library + exposed-modules: Foo + default-language: Haskell2010 + build-depends: base > 2, + base <= 3.10 + diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/PathsExtensions/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/PathsExtensions/cabal.out index eb486dcb3af..b6d14b19e39 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/PathsExtensions/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/PathsExtensions/cabal.out @@ -1,5 +1,6 @@ # cabal check The package will not build sanely due to these errors: -Error: Packages using RebindableSyntax with OverloadedStrings or OverloadedLists in default-extensions, in conjunction with the autogenerated module Paths_*, are known to cause compile failures with Cabal < 2.2. To use these default-extensions with a Paths_* autogen module, specify at least 'cabal-version: 2.2'. -Error: Packages using RebindableSyntax with OverloadedStrings or OverloadedLists in default-extensions, in conjunction with the autogenerated module PackageInfo_*, are known to cause compile failures with Cabal < 2.2. To use these default-extensions with a PackageInfo_* autogen module, specify at least 'cabal-version: 2.2'. +Error: [autogen-guard] To use the autogenerated module PackageInfo_* you need to specify `cabal-version: 3.12` or higher. +Error: [rebindable-clash-paths] Packages using RebindableSyntax with OverloadedStrings or OverloadedLists in default-extensions, in conjunction with the autogenerated module Paths_*, are known to cause compile failures with Cabal < 2.2. To use these default-extensions with a Paths_* autogen module, specify at least 'cabal-version: 2.2'. +Error: [rebindable-clash-info] Packages using RebindableSyntax with OverloadedStrings or OverloadedLists in default-extensions, in conjunction with the autogenerated module PackageInfo_*, are known to cause compile failures with Cabal < 2.2. To use these default-extensions with a PackageInfo_* autogen module, specify at least 'cabal-version: 2.2'. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/SetupBounds/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/SetupBounds/cabal.out index 92ab0bfbca4..895d3a63943 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/SetupBounds/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/SetupBounds/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The dependency 'setup-depends: 'base' does not specify an upper bound on the version number. Each major release of the 'base' package changes the API in various ways and most packages will need some changes to compile with it. If you are not sure what upper bound to use then use the next major version. +Error: [missing-bounds-setup] The dependency 'setup-depends: 'base' does not specify an upper bound on the version number. Each major release of the 'base' package changes the API in various ways and most packages will need some changes to compile with it. If you are not sure what upper bound to use then use the next major version. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/NonConfCheck/UnusedFlags/cabal.out b/cabal-testsuite/PackageTests/Check/NonConfCheck/UnusedFlags/cabal.out index 0d5d79b1d42..9d1c114eaeb 100644 --- a/cabal-testsuite/PackageTests/Check/NonConfCheck/UnusedFlags/cabal.out +++ b/cabal-testsuite/PackageTests/Check/NonConfCheck/UnusedFlags/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: Declared and used flag sets differ: test-flag /= . +Warning: [unused-flag] Declared and used flag sets differ: test-flag /= . diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/BOM/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/BOM/cabal.out index 82d2a821f0a..f4375d24f23 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/BOM/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/BOM/cabal.out @@ -1,6 +1,6 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: pkg.cabal:1:1: Byte-order mark found at the beginning of the file +Warning: [parser-warning] pkg.cabal:1:1: Byte-order mark found at the beginning of the file The following errors will cause portability problems on other environments: -Error: ./pkg.cabal starts with an Unicode byte order mark (BOM). This may cause problems with older cabal versions. +Error: [bom] ./pkg.cabal starts with an Unicode byte order mark (BOM). This may cause problems with older cabal versions. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/LICENSE b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/LICENSE new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/cabal.out new file mode 100644 index 00000000000..37aa169b416 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/cabal.out @@ -0,0 +1,2 @@ +# cabal check +No errors or warnings could be found in the package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/cabal.test.hs b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/cabal.test.hs new file mode 100644 index 00000000000..967a72a460c --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- Do not warn on non-existant directory if it is absolute. +main = cabalTest $ + cabal "check" [] diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/pkg.cabal b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/pkg.cabal new file mode 100644 index 00000000000..d208bae8cd3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/DirExistAbs/pkg.cabal @@ -0,0 +1,17 @@ +Name: pkg +Version: 0.1.0.0 +Synopsis: Low +description: lallalala +License: LGPL-3 +License-File: LICENSE +Maintainer: Maksymilian.Owsianny+AwesomiumRaw@gmail.com +Bug-Reports: https://github.com/MaxOw/awesomium-raw/issues +Category: Graphics, Web +Build-Type: Simple +Cabal-Version: >=1.8 + +Library + Exposed-Modules: Graphics.UI.Awesomium.Raw + Build-Depends: base >= 3 && < 5 + Extra-Lib-Dirs: /usr/lib/awesomium-1.6.5 + diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/ExtensionMatch/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/ExtensionMatch/cabal.out index 5ff791257ae..434547b4082 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/ExtensionMatch/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/ExtensionMatch/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: In the 'extra-doc-files' field: invalid file glob '***.html'. Wildcards '*' may only totally replace the file's base name, not only parts of it. +Error: [glob-syntax-error] In the 'extra-doc-files' field: invalid file glob '***.html'. Wildcards '*' may only totally replace the file's base name, not only parts of it. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/FileName/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/FileName/cabal.out index ea4a2e848fe..40bfc4833cc 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/FileName/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/FileName/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The filename './pkg.cabal' does not match package name (expected: 'package.cabal') +Error: [name-no-match] The filename './pkg.cabal' does not match package name (expected: 'package.cabal') Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/LocalPaths/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/LocalPaths/cabal.out index f81379a29af..7525ca851e0 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/LocalPaths/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/LocalPaths/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: 'extra-lib-dirs: lib-folder' specifies a directory which does not exist. +Error: [unknown-directory] 'extra-lib-dirs: lib-folder' specifies a directory which does not exist. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V1.12/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V1.12/cabal.out index a90fc5b1975..a92251c0ad7 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V1.12/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V1.12/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: Please consider including the file './ChangeLog.md' in the 'extra-source-files' section of the .cabal file if it contains useful information for users of the package. +Warning: [no-docs] Please consider including the file './ChangeLog.md' in the 'extra-source-files' section of the .cabal file if it contains useful information for users of the package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V3.0/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V3.0/cabal.out index b8699cb6a6a..7ef1e41bdce 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V3.0/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/NotIncluded/V3.0/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: Please consider including the file './CHANGELOG.TXT' in the 'extra-doc-files' section of the .cabal file if it contains useful information for users of the package. +Warning: [no-docs] Please consider including the file './CHANGELOG.TXT' in the 'extra-doc-files' section of the .cabal file if it contains useful information for users of the package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V1.12/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V1.12/cabal.out index 729191e540a..32b8c3a1078 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V1.12/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V1.12/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: Please consider moving the file 'ChangeLog.md' from the 'data-files' section of the .cabal file to the section 'extra-source-files'. +Warning: [doc-place] Please consider moving the file 'ChangeLog.md' from the 'data-files' section of the .cabal file to the section 'extra-source-files'. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V3.0/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V3.0/cabal.out index 8ae427d7c83..81945acc86f 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V3.0/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/MissingExpectedDocFiles/ChangeLog/WrongField/V3.0/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings may cause trouble when distributing the package: -Warning: Please consider moving the file 'ChangeLog.md' from the 'extra-source-files' section of the .cabal file to the section 'extra-doc-files'. +Warning: [doc-place] Please consider moving the file 'ChangeLog.md' from the 'extra-source-files' section of the .cabal file to the section 'extra-doc-files'. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/NoConfigureFile/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/NoConfigureFile/cabal.out index 1214a8d69e6..3674c003bfc 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/NoConfigureFile/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/NoConfigureFile/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: The 'build-type' is 'Configure' but there is no 'configure' script. You probably need to run 'autoreconf -i' to generate it. +Error: [missing-conf-script] The 'build-type' is 'Configure' but there is no 'configure' script. You probably need to run 'autoreconf -i' to generate it. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/NoLicenseFile/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/NoLicenseFile/cabal.out index 4dacea81900..240be1f84f3 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/NoLicenseFile/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/NoLicenseFile/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors are likely to affect your build negatively: -Error: The 'license-file' field refers to the file 'LICENSE' which does not exist. +Error: [unknown-file] The 'license-file' field refers to the file 'LICENSE' which does not exist. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/NoSetupFile/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/NoSetupFile/cabal.out index 45e20002892..09b4b408375 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/NoSetupFile/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/NoSetupFile/cabal.out @@ -1,4 +1,4 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The package is missing a Setup.hs or Setup.lhs script. +Error: [missing-setup] The package is missing a Setup.hs or Setup.lhs script. Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/PathTooLong/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/PathTooLong/cabal.out index 12ceb0f1ffc..70d686bdd04 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/PathTooLong/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/PathTooLong/cabal.out @@ -1,6 +1,6 @@ # cabal check The following errors will cause portability problems on other environments: -Error: The following file name is too long to store in a portable POSIX format tar archive. The maximum length for the name part (including extension) is 100 ASCII characters. The maximum length for any individual directory component is 155. +Error: [long-name] The following file name is too long to store in a portable POSIX format tar archive. The maximum length for the name part (including extension) is 100 ASCII characters. The maximum length for any individual directory component is 155. The file in question is: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.hg Error: Hackage would reject this package. diff --git a/cabal-testsuite/PackageTests/Check/PackageFiles/VCSInfo/cabal.out b/cabal-testsuite/PackageTests/Check/PackageFiles/VCSInfo/cabal.out index 0b90abdd9d7..aa0542c5735 100644 --- a/cabal-testsuite/PackageTests/Check/PackageFiles/VCSInfo/cabal.out +++ b/cabal-testsuite/PackageTests/Check/PackageFiles/VCSInfo/cabal.out @@ -1,3 +1,3 @@ # cabal check These warnings will likely cause trouble when distributing the package: -Warning: When distributing packages it is encouraged to specify source control information in the .cabal file using one or more 'source-repository' sections. See the Cabal user guide for details. +Warning: [no-repository] When distributing packages, it is encouraged to specify source control information in the .cabal file using one or more 'source-repository' sections. See the Cabal user guide for details. diff --git a/cabal-testsuite/PackageTests/CmmSourcesExe/cmmexperiment.cabal b/cabal-testsuite/PackageTests/CmmSourcesExe/cmmexperiment.cabal index b26391e6e84..c07aa265b4e 100644 --- a/cabal-testsuite/PackageTests/CmmSourcesExe/cmmexperiment.cabal +++ b/cabal-testsuite/PackageTests/CmmSourcesExe/cmmexperiment.cabal @@ -20,4 +20,3 @@ executable demo else cmm-options: -ddump-cmm - diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-bad-conditional.project b/cabal-testsuite/PackageTests/ConditionalAndImport/bad-conditional.project similarity index 100% rename from cabal-testsuite/PackageTests/ConditionalAndImport/cabal-bad-conditional.project rename to cabal-testsuite/PackageTests/ConditionalAndImport/bad-conditional.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-1-hop.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-1-hop.project new file mode 100644 index 00000000000..2226718af43 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-1-hop.project @@ -0,0 +1,3 @@ +packages: . + +import: cabal-cyclical-1-hop.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop-1.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop-1.config new file mode 100644 index 00000000000..7fafa443a0f --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop-1.config @@ -0,0 +1 @@ +import: cabal-cyclical-2-hop-2.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop-2.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop-2.config new file mode 100644 index 00000000000..380765a8b0b --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop-2.config @@ -0,0 +1 @@ +import: cabal-cyclical-2-hop.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop.project new file mode 100644 index 00000000000..031f6bbb504 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical-2-hop.project @@ -0,0 +1,3 @@ +packages: . + +import: cabal-cyclical-2-hop-1.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical.project deleted file mode 100644 index db226311abc..00000000000 --- a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cyclical.project +++ /dev/null @@ -1,3 +0,0 @@ -packages: . - -import: cabal-cyclical.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cylical-1-hop.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cylical-1-hop.config new file mode 100644 index 00000000000..22d20fe7f30 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal-cylical-1-hop.config @@ -0,0 +1 @@ +import: cabal-cyclical-1-hop.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.out b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.out index c6dbf79d5d5..fa224a62cae 100644 --- a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.out +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.out @@ -10,11 +10,66 @@ Preprocessing executable 'some-exe' for some-exe-0.0.1.0... Building executable 'some-exe' for some-exe-0.0.1.0... Installing executable some-exe in Warning: The directory /cabal.dist/home/.cabal/store/ghc-/incoming/new-/cabal.dist/home/.cabal/store/ghc-/-/bin is not in the system search path. +# checking cyclical loopback of a project importing itself # cabal v2-build Error: [Cabal-7090] -Error parsing project file /cabal-cyclical.project:3: -cyclical import of cabal-cyclical.project +Error parsing project file /cyclical-0-self.project:3: +cyclical import of cyclical-0-self.project +# checking cyclical with hops; out and back # cabal v2-build Error: [Cabal-7090] -Error parsing project file /cabal-bad-conditional.project: +Error parsing project file /cyclical-1-out-back.project:3: +cyclical import of cyclical-1-out-back.config +# checking cyclical with hops; out to a config that imports itself +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-1-out-self.project:1: +cyclical import of cyclical-1-out-self.config +# checking cyclical with hops; out, out, twice back +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-2-out-out-backback.project:3: +cyclical import of cyclical-2-out-out-backback-a.config +# checking cyclical with hops; out, out, once back +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-2-out-out-back.project:1: +cyclical import of cyclical-2-out-out-back-a.config +# checking cyclical with hops; out, out to a config that imports itself +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-2-out-out-self.project:1: +cyclical import of cyclical-2-out-out-self-b.config +# checking that cyclical check doesn't false-positive on same file names in different folders; hoping within a folder and then into a subfolder +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - my-0.1 (lib:my) (first run) +Configuring my-0.1... +Preprocessing library for my-0.1... +Building library for my-0.1... +# checking that cyclical check doesn't false-positive on same file names in different folders; hoping into a subfolder and then back out again +# cabal v2-build +# checking that cyclical check catches a same file name that imports itself +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-same-filename-out-out-self.project:1: +cyclical import of cyclical-same-filename-out-out-self.config +# checking that cyclical check catches importing its importer (with the same file name) +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-same-filename-out-out-backback.project:3: +cyclical import of cyclical-same-filename-out-out-backback.config +# checking that cyclical check catches importing its importer's importer (hopping over same file names) +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /cyclical-same-filename-out-out-back.project:1: +cyclical import of same-filename/cyclical-same-filename-out-out-back.config +# checking that imports work skipping into a subfolder and then back out again and again +# cabal v2-build +# checking bad conditional +# cabal v2-build +Error: [Cabal-7090] +Error parsing project file /bad-conditional.project: Cannot set compiler in a conditional clause of a cabal project file diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.test.hs b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.test.hs index 92ad43e8ba1..7998ee8075d 100644 --- a/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.test.hs +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cabal.test.hs @@ -1,6 +1,132 @@ import Test.Cabal.Prelude -main = cabalTest $ - withRepo "repo" $ do - cabal "v2-run" [ "some-exe" ] - fails $ cabal "v2-build" [ "--project-file=cabal-cyclical.project" ] - fails $ cabal "v2-build" [ "--project-file=cabal-bad-conditional.project" ] + +main = cabalTest . withRepo "repo" . recordMode RecordMarked $ do + let log = recordHeader . pure + + cabal "v2-run" [ "some-exe" ] + + -- +-- cyclical-0-self.project (imports cyclical-0-self.project) + -- +-- cyclical-0-self.project (already processed) + -- +-- etc + log "checking cyclical loopback of a project importing itself" + cyclical0 <- fails $ cabal' "v2-build" [ "--project-file=cyclical-0-self.project" ] + assertOutputContains "cyclical import of cyclical-0-self.project" cyclical0 + + -- +-- cyclical-1-out-back.project + -- +-- cyclical-1-out-back.config (imports cyclical-1-out-back.project) + -- +-- cyclical-1-out-back.project (already processed) + -- +-- etc + log "checking cyclical with hops; out and back" + cyclical1a <- fails $ cabal' "v2-build" [ "--project-file=cyclical-1-out-back.project" ] + -- This test should pass the following check but doesn't: + -- assertOutputContains "cyclical import of cyclical-1-out-back.project" cyclical1a + + -- +-- cyclical-1-out-self.project + -- +-- cyclical-1-out-self.config (imports cyclical-1-out-self.config) + -- +-- cyclical-1-out-self.config (already processed) + -- +-- etc + log "checking cyclical with hops; out to a config that imports itself" + cyclical1b <- fails $ cabal' "v2-build" [ "--project-file=cyclical-1-out-self.project" ] + assertOutputContains "cyclical import of cyclical-1-out-self.config" cyclical1b + + -- +-- cyclical-2-out-out-backback.project + -- +-- cyclical-2-out-out-backback-a.config + -- +-- cyclical-2-out-out-backback-b.config (imports cyclical-2-out-out-backback.project) + -- +-- cyclical-2-out-out-backback.project (already processed) + -- +-- etc + log "checking cyclical with hops; out, out, twice back" + cyclical2a <- fails $ cabal' "v2-build" [ "--project-file=cyclical-2-out-out-backback.project" ] + -- This test should pass the following check but doesn't: + -- assertOutputContains "cyclical import of cyclical-2-out-out-backback.project" cyclical2a + + -- +-- cyclical-2-out-out-back.project + -- +-- cyclical-2-out-out-back-a.config + -- +-- cyclical-2-out-out-back-b.config (imports cyclical-2-out-out-back-a.config) + -- +-- cyclical-2-out-out-back-a.config (already processed) + -- +-- etc + log "checking cyclical with hops; out, out, once back" + cyclical2b <- fails $ cabal' "v2-build" [ "--project-file=cyclical-2-out-out-back.project" ] + assertOutputContains "cyclical import of cyclical-2-out-out-back-a.config" cyclical2b + + -- +-- cyclical-2-out-out-self.project + -- +-- cyclical-2-out-out-self-a.config + -- +-- cyclical-2-out-out-self-b.config (imports cyclical-2-out-out-self-b.config) + -- +-- cyclical-2-out-out-self-b.config (already processed) + -- +-- etc + log "checking cyclical with hops; out, out to a config that imports itself" + cyclical2c <- fails $ cabal' "v2-build" [ "--project-file=cyclical-2-out-out-self.project" ] + assertOutputContains "cyclical import of cyclical-2-out-out-self-b.config" cyclical2c + + -- +-- noncyclical-same-filename-a.project + -- +-- noncyclical-same-filename-a.config + -- +-- same-filename/noncyclical-same-filename-a.config (no further imports so not cyclical) + log "checking that cyclical check doesn't false-positive on same file names in different folders; hoping within a folder and then into a subfolder" + cyclical3b <- cabal' "v2-build" [ "--project-file=noncyclical-same-filename-a.project" ] + assertOutputDoesNotContain "cyclical import of" cyclical3b + + -- +-- noncyclical-same-filename-b.project + -- +-- same-filename/noncyclical-same-filename-b.config + -- +-- noncyclical-same-filename-b.config (no further imports so not cyclical) + log "checking that cyclical check doesn't false-positive on same file names in different folders; hoping into a subfolder and then back out again" + cyclical3c <- fails $ cabal' "v2-build" [ "--project-file=noncyclical-same-filename-b.project" ] + assertOutputDoesNotContain "cyclical import of" cyclical3c + + -- +-- cyclical-same-filename-out-out-self.project + -- +-- cyclical-same-filename-out-out-self.config + -- +-- same-filename/cyclical-same-filename-out-out-self.config + -- +-- same-filename/cyclical-same-filename-out-out-self.config (already processed) + -- +-- etc + log "checking that cyclical check catches a same file name that imports itself" + cyclical4a <- fails $ cabal' "v2-build" [ "--project-file=cyclical-same-filename-out-out-self.project" ] + assertOutputContains "cyclical import of cyclical-same-filename-out-out-self.config" cyclical4a + + -- +-- cyclical-same-filename-out-out-backback.project + -- +-- cyclical-same-filename-out-out-backback.config + -- +-- same-filename/cyclical-same-filename-out-out-backback.config + -- +-- cyclical-same-filename-out-out-backback.project (already processed) + -- +-- etc + log "checking that cyclical check catches importing its importer (with the same file name)" + cyclical4b <- fails $ cabal' "v2-build" [ "--project-file=cyclical-same-filename-out-out-backback.project" ] + -- This test should pass the following check but doesn't: + -- assertOutputContains "cyclical import of cyclical-same-filename-out-out-backback.project" cyclical4b + + -- +-- cyclical-same-filename-out-out-back.project + -- +-- cyclical-same-filename-out-out-back.config + -- +-- same-filename/cyclical-same-filename-out-out-back.config + -- +-- cyclical-same-filename-out-out-back.config (already processed) + -- +-- etc + log "checking that cyclical check catches importing its importer's importer (hopping over same file names)" + cyclical4c <- fails $ cabal' "v2-build" [ "--project-file=cyclical-same-filename-out-out-back.project" ] + -- This test should pass the following check but doesn't: + -- assertOutputContains "cyclical import of cyclical-same-filename-out-out-back.config" cyclical4c + + -- +-- hops-0.project + -- +-- hops/hops-1.config + -- +-- hops-2.config + -- +-- hops/hops-3.config + -- +-- hops-4.config + -- +-- hops/hops-5.config + -- +-- hops-6.config + -- +-- hops/hops-7.config + -- +-- hops-8.config + -- +-- hops/hops-9.config (no further imports so not cyclical) + log "checking that imports work skipping into a subfolder and then back out again and again" + -- This test should pass the following checks but doesn't, it fails (but it shouldn't): + hopping <- fails $ cabal' "v2-build" [ "--project-file=hops-0.project" ] + -- assertOutputContains "this build was affected by the following (project) config files:" hopping + -- assertOutputContains "hops-0.project" hopping + -- assertOutputContains "../hops-2.config" hopping + -- assertOutputContains "../hops-4.config" hopping + -- assertOutputContains "../hops-6.config" hopping + -- assertOutputContains "../hops-8.config" hopping + -- assertOutputContains "hops/hops-1.config" hopping + -- assertOutputContains "hops/hops-3.config" hopping + -- assertOutputContains "hops/hops-5.config" hopping + -- assertOutputContains "hops/hops-7.config" hopping + -- assertOutputContains "hops/hops-9.config" hopping + + log "checking bad conditional" + badIf <- fails $ cabal' "v2-build" [ "--project-file=bad-conditional.project" ] + assertOutputContains "Cannot set compiler in a conditional clause of a cabal project file" badIf + + return () diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-0-self.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-0-self.project new file mode 100644 index 00000000000..4c3a5a211dc --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-0-self.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-0-self.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-back.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-back.config new file mode 100644 index 00000000000..379de005bce --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-back.config @@ -0,0 +1 @@ +import: cyclical-1-out-back.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-back.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-back.project new file mode 100644 index 00000000000..73e932def60 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-back.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-1-out-back.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-self.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-self.config new file mode 100644 index 00000000000..76e7261fe84 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-self.config @@ -0,0 +1 @@ +import: cyclical-1-out-self.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-self.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-self.project new file mode 100644 index 00000000000..c6a455c3167 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-1-out-self.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-1-out-self.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back-a.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back-a.config new file mode 100644 index 00000000000..8c5017c0cd9 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back-a.config @@ -0,0 +1 @@ +import: cyclical-2-out-out-back-b.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back-b.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back-b.config new file mode 100644 index 00000000000..ce0f8e99bcf --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back-b.config @@ -0,0 +1 @@ +import: cyclical-2-out-out-back-a.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back.project new file mode 100644 index 00000000000..7f1597c1240 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-back.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-2-out-out-back-a.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback-a.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback-a.config new file mode 100644 index 00000000000..4f7247a39d9 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback-a.config @@ -0,0 +1 @@ +import: cyclical-2-out-out-backback-b.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback-b.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback-b.config new file mode 100644 index 00000000000..f6073739b48 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback-b.config @@ -0,0 +1 @@ +import: cyclical-2-out-out-backback.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback.project new file mode 100644 index 00000000000..e434aaa7201 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-backback.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-2-out-out-backback-a.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self-a.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self-a.config new file mode 100644 index 00000000000..cfe64e7c44d --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self-a.config @@ -0,0 +1 @@ +import: cyclical-2-out-out-self-b.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self-b.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self-b.config new file mode 100644 index 00000000000..cfe64e7c44d --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self-b.config @@ -0,0 +1 @@ +import: cyclical-2-out-out-self-b.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self.project new file mode 100644 index 00000000000..e029ad5bcde --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-2-out-out-self.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-2-out-out-self-a.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-back.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-back.config new file mode 100644 index 00000000000..19f9a545278 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-back.config @@ -0,0 +1 @@ +import: same-filename/cyclical-same-filename-out-out-back.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-back.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-back.project new file mode 100644 index 00000000000..191cef0ef43 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-back.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-same-filename-out-out-back.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-backback.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-backback.config new file mode 100644 index 00000000000..dd5c2829921 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-backback.config @@ -0,0 +1 @@ +import: same-filename/cyclical-same-filename-out-out-backback.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-backback.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-backback.project new file mode 100644 index 00000000000..9a44d881444 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-backback.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-same-filename-out-out-backback.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-self.config b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-self.config new file mode 100644 index 00000000000..c633ee14042 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-self.config @@ -0,0 +1 @@ +import: same-filename/cyclical-same-filename-out-out-self.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-self.project b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-self.project new file mode 100644 index 00000000000..9822deca267 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/cyclical-same-filename-out-out-self.project @@ -0,0 +1,3 @@ +packages: . + +import: cyclical-same-filename-out-out-self.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops-0.project b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-0.project new file mode 100644 index 00000000000..82a2aee5f94 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-0.project @@ -0,0 +1,3 @@ +packages: . + +import: hops/hops-1.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops-2.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-2.config new file mode 100644 index 00000000000..fb98b6487a4 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-2.config @@ -0,0 +1 @@ +import: hops/hops-3.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops-4.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-4.config new file mode 100644 index 00000000000..e36dcb233d4 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-4.config @@ -0,0 +1 @@ +import: hops/hops-5.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops-6.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-6.config new file mode 100644 index 00000000000..2f4c8304f05 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-6.config @@ -0,0 +1 @@ +import: hops/hops-7.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops-8.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-8.config new file mode 100644 index 00000000000..29e2c3fc41d --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops-8.config @@ -0,0 +1 @@ +import: hops/hops-9.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-1.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-1.config new file mode 100644 index 00000000000..708f36b06bd --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-1.config @@ -0,0 +1 @@ +import: ../hops-2.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-3.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-3.config new file mode 100644 index 00000000000..af6ab5fa914 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-3.config @@ -0,0 +1 @@ +import: ../hops-4.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-5.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-5.config new file mode 100644 index 00000000000..9bf4c8161b0 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-5.config @@ -0,0 +1 @@ +import: ../hops-6.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-7.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-7.config new file mode 100644 index 00000000000..912c0dabf69 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-7.config @@ -0,0 +1 @@ +import: ../hops-8.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-9.config b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-9.config new file mode 100644 index 00000000000..61813df4e2c --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/hops/hops-9.config @@ -0,0 +1 @@ +-- No imports here diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-a.config b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-a.config new file mode 100644 index 00000000000..e571f335068 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-a.config @@ -0,0 +1 @@ +import: same-filename/noncyclical-same-filename-a.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-a.project b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-a.project new file mode 100644 index 00000000000..b0aa70e4bab --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-a.project @@ -0,0 +1,3 @@ +packages: . + +import: noncyclical-same-filename-a.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-b.config b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-b.config new file mode 100644 index 00000000000..61813df4e2c --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-b.config @@ -0,0 +1 @@ +-- No imports here diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-b.project b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-b.project new file mode 100644 index 00000000000..aa65dd03b5d --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/noncyclical-same-filename-b.project @@ -0,0 +1,3 @@ +packages: . + +import: same-filename/noncyclical-same-filename-b.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-back.config b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-back.config new file mode 100644 index 00000000000..543ce57365b --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-back.config @@ -0,0 +1 @@ +import: ../cyclical-same-filename-out-out-back.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-backback.config b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-backback.config new file mode 100644 index 00000000000..3d244f4eff6 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-backback.config @@ -0,0 +1 @@ +import: ../cyclical-same-filename-out-out-backback.project diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-self.config b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-self.config new file mode 100644 index 00000000000..5b162a3f68f --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/cyclical-same-filename-out-out-self.config @@ -0,0 +1 @@ +import: cyclical-same-filename-out-out-self.config diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/noncyclical-same-filename-a.config b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/noncyclical-same-filename-a.config new file mode 100644 index 00000000000..61813df4e2c --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/noncyclical-same-filename-a.config @@ -0,0 +1 @@ +-- No imports here diff --git a/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/noncyclical-same-filename-b.config b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/noncyclical-same-filename-b.config new file mode 100644 index 00000000000..dc692490257 --- /dev/null +++ b/cabal-testsuite/PackageTests/ConditionalAndImport/same-filename/noncyclical-same-filename-b.config @@ -0,0 +1 @@ +import: ../noncylical-same-filename-b.config diff --git a/cabal-testsuite/PackageTests/Configure/.gitignore b/cabal-testsuite/PackageTests/Configure/.gitignore index 0714c2e1e8a..86206627b2d 100644 --- a/cabal-testsuite/PackageTests/Configure/.gitignore +++ b/cabal-testsuite/PackageTests/Configure/.gitignore @@ -4,3 +4,4 @@ autom4te.cache/ *.status configure include/HsZlibConfig.h +include/HsZlibConfig.h.in diff --git a/cabal-testsuite/PackageTests/CustomDep/cabal.test.hs b/cabal-testsuite/PackageTests/CustomDep/cabal.test.hs index b1c3aa98802..9058afe19c0 100644 --- a/cabal-testsuite/PackageTests/CustomDep/cabal.test.hs +++ b/cabal-testsuite/PackageTests/CustomDep/cabal.test.hs @@ -1,7 +1,5 @@ import Test.Cabal.Prelude main = cabalTest $ do - -- NB: This variant seems to use the bootstrapped Cabal? - skipUnless "no Cabal for GHC" =<< hasCabalForGhc -- implicit setup-depends conflict with GHC >= 8.2; c.f. #415 skipUnlessGhcVersion "< 8.2" -- This test depends heavily on what packages are in the global diff --git a/cabal-testsuite/PackageTests/CustomPlain/setup.out b/cabal-testsuite/PackageTests/CustomPlain/setup.out index ba0be271fc7..3fdfe2b7f77 100644 --- a/cabal-testsuite/PackageTests/CustomPlain/setup.out +++ b/cabal-testsuite/PackageTests/CustomPlain/setup.out @@ -1,6 +1,6 @@ # Setup configure Configuring plain-0.1.0.0... -Warning: No 'build-type' specified. If you do not need a custom Setup.hs or ./configure script then use 'build-type: Simple'. +Warning: [no-build-type] No 'build-type' specified. If you do not need a custom Setup.hs or ./configure script then use 'build-type: Simple'. # Setup build Preprocessing library for plain-0.1.0.0... Building library for plain-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/CustomPlain/setup.test.hs b/cabal-testsuite/PackageTests/CustomPlain/setup.test.hs index 2b4a27b1388..abf668397b8 100644 --- a/cabal-testsuite/PackageTests/CustomPlain/setup.test.hs +++ b/cabal-testsuite/PackageTests/CustomPlain/setup.test.hs @@ -1,5 +1,4 @@ import Test.Cabal.Prelude main = setupTest $ do - skipUnless "no Cabal for GHC" =<< hasCabalForGhc setup' "configure" [] >>= assertOutputContains "ThisIsCustomYeah" setup' "build" [] >>= assertOutputContains "ThisIsCustomYeah" diff --git a/cabal-testsuite/PackageTests/CustomPreProcess/Setup.hs b/cabal-testsuite/PackageTests/CustomPreProcess/Setup.hs index 93ff6a015e9..2b7d59d6297 100644 --- a/cabal-testsuite/PackageTests/CustomPreProcess/Setup.hs +++ b/cabal-testsuite/PackageTests/CustomPreProcess/Setup.hs @@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -Wall #-} -- The logic here is tricky. diff --git a/cabal-testsuite/PackageTests/CustomPreProcess/cabal.test.hs b/cabal-testsuite/PackageTests/CustomPreProcess/cabal.test.hs index 93588d88c3f..3c20b50a160 100644 --- a/cabal-testsuite/PackageTests/CustomPreProcess/cabal.test.hs +++ b/cabal-testsuite/PackageTests/CustomPreProcess/cabal.test.hs @@ -1,8 +1,6 @@ import Test.Cabal.Prelude -- Test internal custom preprocessor main = cabalTest $ do - skipUnless "no Cabal for GHC" =<< hasCabalForGhc - -- old Cabal's ./Setup.hs output is difficult to normalise recordMode DoNotRecord $ cabal "v2-build" [] diff --git a/cabal-testsuite/PackageTests/CustomPreProcess/setup.test.hs b/cabal-testsuite/PackageTests/CustomPreProcess/setup.test.hs index 2dab697b8d4..b3d1f3c0a46 100644 --- a/cabal-testsuite/PackageTests/CustomPreProcess/setup.test.hs +++ b/cabal-testsuite/PackageTests/CustomPreProcess/setup.test.hs @@ -1,7 +1,6 @@ import Test.Cabal.Prelude -- Test internal custom preprocessor main = setupTest $ do - skipUnless "no Cabal for GHC" =<< hasCabalForGhc setup_build [] runExe' "hello-world" [] >>= assertOutputContains "hello from A" diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/A.hs b/cabal-testsuite/PackageTests/CustomTestCoverage/A.hs new file mode 100644 index 00000000000..e0ba50b355f --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/A.hs @@ -0,0 +1,3 @@ +module A where + +str = "A" diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/Setup.hs b/cabal-testsuite/PackageTests/CustomTestCoverage/Setup.hs new file mode 100644 index 00000000000..20b960ede90 --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/Setup.hs @@ -0,0 +1,3 @@ +import Distribution.Simple +import System.IO +main = hPutStrLn stderr "ThisIsCustomYeah" >> defaultMain diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.out b/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.out new file mode 100644 index 00000000000..a650ce81c42 --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.out @@ -0,0 +1,17 @@ +# cabal test +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - plain-0.1.0.0 *test (first run) +Configuring plain-0.1.0.0... +Preprocessing library for plain-0.1.0.0.. +Building library for plain-0.1.0.0.. +Preprocessing test suite 'test' for plain-0.1.0.0.. +Building test suite 'test' for plain-0.1.0.0.. +Running 1 test suites... +Test suite test: RUNNING... +Test suite test: PASS +Test suite logged to: /cabal.dist/work/./dist/build//ghc-/plain-0.1.0.0/test/plain-0.1.0.0-test.log +Test coverage report written to /cabal.dist/work/./dist/build//ghc-/plain-0.1.0.0/hpc/vanilla/html/test/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/plain-0.1.0.0/hpc/vanilla/html/plain-0.1.0.0/hpc_index.html diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.project b/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.test.hs b/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.test.hs new file mode 100644 index 00000000000..6f3f5586c62 --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/cabal.test.hs @@ -0,0 +1,3 @@ +import Test.Cabal.Prelude +main = cabalTest $ do + cabal "test" ["--enable-coverage"] diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/plain.cabal b/cabal-testsuite/PackageTests/CustomTestCoverage/plain.cabal new file mode 100644 index 00000000000..c14b6534f32 --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/plain.cabal @@ -0,0 +1,23 @@ +cabal-version: 2.2 +name: plain +version: 0.1.0.0 +license: BSD-3-Clause +author: Edward Z. Yang +maintainer: ezyang@cs.stanford.edu +build-type: Custom + +custom-setup + setup-depends: + base, Cabal + +library + exposed-modules: A + build-depends: base + default-language: Haskell2010 + +test-suite test + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Test.hs + default-language: Haskell2010 + build-depends: base, plain diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/setup.test.hs b/cabal-testsuite/PackageTests/CustomTestCoverage/setup.test.hs new file mode 100644 index 00000000000..86cc6a258ab --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/setup.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude +main = setupTest $ do + skipIfGhcVersion "== 7.8.4" + recordMode DoNotRecord $ do + setup' "configure" ["--enable-tests", "--enable-coverage"] >>= assertOutputContains "ThisIsCustomYeah" + setup' "build" [] + setup' "test" [] >>= assertOutputContains "Package coverage report written to" diff --git a/cabal-testsuite/PackageTests/CustomTestCoverage/test/Test.hs b/cabal-testsuite/PackageTests/CustomTestCoverage/test/Test.hs new file mode 100644 index 00000000000..80881436d49 --- /dev/null +++ b/cabal-testsuite/PackageTests/CustomTestCoverage/test/Test.hs @@ -0,0 +1,2 @@ +import A +main = print str diff --git a/cabal-testsuite/PackageTests/DuplicateModuleName/setup.test.hs b/cabal-testsuite/PackageTests/DuplicateModuleName/setup.test.hs index 3739c793e8f..005578ce184 100644 --- a/cabal-testsuite/PackageTests/DuplicateModuleName/setup.test.hs +++ b/cabal-testsuite/PackageTests/DuplicateModuleName/setup.test.hs @@ -2,7 +2,7 @@ import Test.Cabal.Prelude -- Test that if two components have the same module name, they do not -- clobber each other. main = setupAndCabalTest $ do - skipUnless "no Cabal for GHC" =<< hasCabalForGhc -- use of library test suite + skipIfAllCabalVersion "< 2.2" setup_build ["--enable-tests"] r1 <- fails $ setup' "test" ["foo"] assertOutputContains "test B" r1 diff --git a/cabal-testsuite/PackageTests/ExternalCommand/cabal.out b/cabal-testsuite/PackageTests/ExternalCommand/cabal.out new file mode 100644 index 00000000000..1c4c24db55c --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/cabal.out @@ -0,0 +1,8 @@ +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - setup-test-0.1.0.0 (exe:cabal-aaaa) (first run) +Configuring executable 'cabal-aaaa' for setup-test-0.1.0.0... +Preprocessing executable 'cabal-aaaa' for setup-test-0.1.0.0... +Building executable 'cabal-aaaa' for setup-test-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/ExternalCommand/cabal.project b/cabal-testsuite/PackageTests/ExternalCommand/cabal.project new file mode 100644 index 00000000000..1a33bb5a25e --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/cabal.project @@ -0,0 +1 @@ +packages: setup-test/ diff --git a/cabal-testsuite/PackageTests/ExternalCommand/cabal.test.hs b/cabal-testsuite/PackageTests/ExternalCommand/cabal.test.hs new file mode 100644 index 00000000000..d9535b60507 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/cabal.test.hs @@ -0,0 +1,47 @@ +import Test.Cabal.Prelude +import qualified System.Process as Process +import Control.Concurrent (threadDelay) +import System.Directory (removeFile) +import Control.Exception (catch, throwIO) +import System.IO.Error (isDoesNotExistError) +import qualified Data.Time.Clock as Time +import qualified Data.Time.Format as Time +import Data.Maybe +import System.Environment +import System.FilePath + +main = do + cabalTest $ do + res <- cabalWithStdin "v2-build" ["all"] "" + exe_path <- withPlan $ planExePath "setup-test" "cabal-aaaa" + addToPath (takeDirectory exe_path) $ do + -- Test that the thing works at all + res <- cabal_raw_action ["aaaa"] (\h -> () <$ Process.waitForProcess h) + assertOutputContains "aaaa" res + + -- Test that the extra arguments are passed on + res <- cabal_raw_action ["aaaa", "--foobaz"] (\h -> () <$ Process.waitForProcess h) + assertOutputContains "--foobaz" res + + -- Test what happens with "global" flags + res <- cabal_raw_action ["aaaa", "--version"] (\h -> () <$ Process.waitForProcess h) + assertOutputContains "--version" res + + -- Test what happens with "global" flags + res <- cabal_raw_action ["aaaa", "--config-file", "abc"] (\h -> () <$ Process.waitForProcess h) + assertOutputContains "--config-file" res + + +cabal_raw_action :: [String] -> (Process.ProcessHandle -> IO ()) -> TestM Result +cabal_raw_action args action = do + configured_prog <- requireProgramM cabalProgram + env <- getTestEnv + r <- liftIO $ runAction (testVerbosity env) + (Just (testCurrentDir env)) + (testEnvironment env) + (programPath configured_prog) + args + Nothing + action + recordLog r + requireSuccess r diff --git a/cabal-testsuite/PackageTests/ExternalCommand/setup-test/AAAA.hs b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/AAAA.hs new file mode 100644 index 00000000000..c2d121c9a39 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/AAAA.hs @@ -0,0 +1,5 @@ +module Main where + +import System.Environment + +main = getArgs >>= print diff --git a/cabal-testsuite/PackageTests/ExternalCommand/setup-test/CHANGELOG.md b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/CHANGELOG.md new file mode 100644 index 00000000000..7ae8ff6113d --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for setup-test + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ExternalCommand/setup-test/LICENSE b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/LICENSE new file mode 100644 index 00000000000..cd8ad2ac8ae --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2023, Matthew Pickering + +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 Matthew Pickering nor the names of 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. diff --git a/cabal-testsuite/PackageTests/ExternalCommand/setup-test/setup-test.cabal b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/setup-test.cabal new file mode 100644 index 00000000000..8deb0577a16 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommand/setup-test/setup-test.cabal @@ -0,0 +1,25 @@ +cabal-version: 3.0 +name: setup-test +version: 0.1.0.0 +-- synopsis: +-- description: +license: BSD-3-Clause +license-file: LICENSE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +-- copyright: +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable cabal-aaaa + import: warnings + main-is: AAAA.hs + -- other-modules: + -- other-extensions: + build-depends: base + hs-source-dirs: . + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.out b/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.out new file mode 100644 index 00000000000..1c4c24db55c --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.out @@ -0,0 +1,8 @@ +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - setup-test-0.1.0.0 (exe:cabal-aaaa) (first run) +Configuring executable 'cabal-aaaa' for setup-test-0.1.0.0... +Preprocessing executable 'cabal-aaaa' for setup-test-0.1.0.0... +Building executable 'cabal-aaaa' for setup-test-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.project b/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.project new file mode 100644 index 00000000000..1a33bb5a25e --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.project @@ -0,0 +1 @@ +packages: setup-test/ diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.test.hs b/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.test.hs new file mode 100644 index 00000000000..4344076398a --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/cabal.test.hs @@ -0,0 +1,36 @@ +import Test.Cabal.Prelude +import qualified System.Process as Process +import Control.Concurrent (threadDelay) +import System.Directory (removeFile) +import Control.Exception (catch, throwIO) +import System.IO.Error (isDoesNotExistError) +import qualified Data.Time.Clock as Time +import qualified Data.Time.Format as Time +import Data.Maybe +import System.Environment + +main = do + cabalTest $ do + res <- cabalWithStdin "v2-build" ["all"] "" + exe_path <- withPlan $ planExePath "setup-test" "cabal-aaaa" + env <- getTestEnv + let new_env = (("OTHER_VAR", Just "is set") : (testEnvironment env)) + withEnv new_env $ addToPath (takeDirectory exe_path) $ do + res <- cabal_raw_action ["aaaa"] (\h -> () <$ Process.waitForProcess h) + assertOutputContains "cabal-install" res + assertOutputContains "is set" res + + +cabal_raw_action :: [String] -> (Process.ProcessHandle -> IO ()) -> TestM Result +cabal_raw_action args action = do + configured_prog <- requireProgramM cabalProgram + env <- getTestEnv + r <- liftIO $ runAction (testVerbosity env) + (Just (testCurrentDir env)) + (testEnvironment env) + (programPath configured_prog) + args + Nothing + action + recordLog r + requireSuccess r diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/AAAA.hs b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/AAAA.hs new file mode 100644 index 00000000000..99af61e9c03 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/AAAA.hs @@ -0,0 +1,11 @@ +module Main where + +import System.Environment +import System.Process + +main = do + cabal_proc <- getEnv "CABAL" + other_var <- getEnv "OTHER_VAR" + putStrLn ("OTHER_VAR is set to: " ++ other_var) + callProcess cabal_proc ["--version"] + diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/CHANGELOG.md b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/CHANGELOG.md new file mode 100644 index 00000000000..7ae8ff6113d --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for setup-test + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/LICENSE b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/LICENSE new file mode 100644 index 00000000000..cd8ad2ac8ae --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2023, Matthew Pickering + +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 Matthew Pickering nor the names of 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. diff --git a/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/setup-test.cabal b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/setup-test.cabal new file mode 100644 index 00000000000..a5feea69112 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandEnv/setup-test/setup-test.cabal @@ -0,0 +1,25 @@ +cabal-version: 3.0 +name: setup-test +version: 0.1.0.0 +-- synopsis: +-- description: +license: BSD-3-Clause +license-file: LICENSE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +-- copyright: +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable cabal-aaaa + import: warnings + main-is: AAAA.hs + -- other-modules: + -- other-extensions: + build-depends: base, process + hs-source-dirs: . + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.out b/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.out new file mode 100644 index 00000000000..1c4c24db55c --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.out @@ -0,0 +1,8 @@ +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - setup-test-0.1.0.0 (exe:cabal-aaaa) (first run) +Configuring executable 'cabal-aaaa' for setup-test-0.1.0.0... +Preprocessing executable 'cabal-aaaa' for setup-test-0.1.0.0... +Building executable 'cabal-aaaa' for setup-test-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.project b/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.project new file mode 100644 index 00000000000..1a33bb5a25e --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.project @@ -0,0 +1 @@ +packages: setup-test/ diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.test.hs b/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.test.hs new file mode 100644 index 00000000000..96e69bbbd6e --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/cabal.test.hs @@ -0,0 +1,33 @@ +import Test.Cabal.Prelude +import qualified System.Process as Process +import Control.Concurrent (threadDelay) +import System.Directory (removeFile) +import Control.Exception (catch, throwIO) +import System.IO.Error (isDoesNotExistError) +import qualified Data.Time.Clock as Time +import qualified Data.Time.Format as Time +import Data.Maybe +import System.Environment + +main = do + cabalTest $ do + res <- cabalWithStdin "v2-build" ["all"] "" + exe_path <- withPlan $ planExePath "setup-test" "cabal-aaaa" + addToPath (takeDirectory exe_path) $ do + res <- cabal_raw_action ["help", "aaaa"] (\h -> () <$ Process.waitForProcess h) + assertOutputContains "I am helping with the aaaa command" res + + +cabal_raw_action :: [String] -> (Process.ProcessHandle -> IO ()) -> TestM Result +cabal_raw_action args action = do + configured_prog <- requireProgramM cabalProgram + env <- getTestEnv + r <- liftIO $ runAction (testVerbosity env) + (Just (testCurrentDir env)) + (testEnvironment env) + (programPath configured_prog) + args + Nothing + action + recordLog r + requireSuccess r diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/AAAA.hs b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/AAAA.hs new file mode 100644 index 00000000000..dd139b905da --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/AAAA.hs @@ -0,0 +1,9 @@ +module Main where + +import System.Environment + +main = do + args <- getArgs + case args of + ["aaaa" , "--help"] -> putStrLn "I am helping with the aaaa command" + _ -> putStrLn "aaaa" diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/CHANGELOG.md b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/CHANGELOG.md new file mode 100644 index 00000000000..7ae8ff6113d --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for setup-test + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/LICENSE b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/LICENSE new file mode 100644 index 00000000000..cd8ad2ac8ae --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2023, Matthew Pickering + +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 Matthew Pickering nor the names of 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. diff --git a/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/setup-test.cabal b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/setup-test.cabal new file mode 100644 index 00000000000..8deb0577a16 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandHelp/setup-test/setup-test.cabal @@ -0,0 +1,25 @@ +cabal-version: 3.0 +name: setup-test +version: 0.1.0.0 +-- synopsis: +-- description: +license: BSD-3-Clause +license-file: LICENSE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +-- copyright: +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable cabal-aaaa + import: warnings + main-is: AAAA.hs + -- other-modules: + -- other-extensions: + build-depends: base + hs-source-dirs: . + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/LICENSE b/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/LICENSE new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/Main.hs b/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/Main.hs new file mode 100644 index 00000000000..b3fcf560699 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/Main.hs @@ -0,0 +1,3 @@ +module Main where + +main = putStrLn "aaaa" diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/aaaa.cabal b/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/aaaa.cabal new file mode 100644 index 00000000000..cafeabd5855 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/aaaa/aaaa.cabal @@ -0,0 +1,22 @@ +cabal-version: 3.0 +name: aaaa +version: 0.1.0.0 +license: BSD-3-Clause +license-file: LICENSE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable cabal-aaaa + import: warnings + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base + hs-source-dirs: . + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/CHANGELOG.md b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/CHANGELOG.md new file mode 100644 index 00000000000..063fef7c698 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for custom + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/LICENSE b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/LICENSE new file mode 100644 index 00000000000..cd8ad2ac8ae --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2023, Matthew Pickering + +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 Matthew Pickering nor the names of 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. diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/Setup.hs b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/Setup.hs new file mode 100644 index 00000000000..e8efd11bddb --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/Setup.hs @@ -0,0 +1,3 @@ +module Main where +import Distribution.Simple +main = defaultMain diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/custom.cabal b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/custom.cabal new file mode 100644 index 00000000000..0dbc609439b --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/custom/custom.cabal @@ -0,0 +1,29 @@ +cabal-version: 3.0 +name: custom +version: 0.1.0.0 +-- synopsis: +-- description: +license: BSD-3-Clause +license-file: LICENSE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +-- copyright: +build-type: Custom +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings + ghc-options: -Wall + +custom-setup + build-depends: base, Cabal + +library + import: warnings + exposed-modules: MyLib + -- other-modules: + -- other-extensions: + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 + diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/setup.cabal.hs b/cabal-testsuite/PackageTests/ExternalCommandSetup/setup.cabal.hs new file mode 100644 index 00000000000..7fb49a41923 --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/setup.cabal.hs @@ -0,0 +1,13 @@ +import Test.Cabal.Prelude +import System.Environment + +main = setupTest $ do + withPackageDb $ do + withDirectory "aaaa" $ setup_install [] + r <- runInstalledExe' "cabal-aaaa" [] + env <- getTestEnv + let exe_path = testPrefixDir env "bin" + addToPath exe_path $ do + res <- fails $ withDirectory "custom" $ setup' "aaaa" [] + assertOutputContains "unrecognised command" res + diff --git a/cabal-testsuite/PackageTests/ExternalCommandSetup/setup.out b/cabal-testsuite/PackageTests/ExternalCommandSetup/setup.out new file mode 100644 index 00000000000..6600ad3ca2f --- /dev/null +++ b/cabal-testsuite/PackageTests/ExternalCommandSetup/setup.out @@ -0,0 +1,13 @@ +# Setup configure +Configuring aaaa-0.1.0.0... +# Setup build +Preprocessing executable 'cabal-aaaa' for aaaa-0.1.0.0... +Building executable 'cabal-aaaa' for aaaa-0.1.0.0... +# Setup copy +Installing executable cabal-aaaa in +Warning: The directory /setup.dist/usr/bin is not in the system search path. +# Setup register +Package contains no library to register: aaaa-0.1.0.0... +# cabal-aaaa +aaaa +# Setup aaaa diff --git a/cabal-testsuite/PackageTests/ExtraProgPath/cabal.project b/cabal-testsuite/PackageTests/ExtraProgPath/cabal.project index 5a93e28e878..0d7f076e888 100644 --- a/cabal-testsuite/PackageTests/ExtraProgPath/cabal.project +++ b/cabal-testsuite/PackageTests/ExtraProgPath/cabal.project @@ -1 +1 @@ -packages: *.cabal \ No newline at end of file +packages: *.cabal diff --git a/cabal-testsuite/PackageTests/ExtraProgPath/pkg-config b/cabal-testsuite/PackageTests/ExtraProgPath/pkg-config index 7c5fafbf0ca..195df7c2c41 100755 --- a/cabal-testsuite/PackageTests/ExtraProgPath/pkg-config +++ b/cabal-testsuite/PackageTests/ExtraProgPath/pkg-config @@ -1,3 +1,3 @@ -#!/usr/bin/sh +#!/bin/sh exit 1; diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/Lib.hs b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/Lib.hs new file mode 100644 index 00000000000..9535fcd23fb --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/Lib.hs @@ -0,0 +1,13 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +module Lib where + +import Foreign.C (CInt (..)) + +hello :: IO CInt +hello = do + putStrLn "hello!" + return 11 + +foreign export ccall "hello" hello :: IO CInt + diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/Main.hs b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/Main.hs new file mode 100644 index 00000000000..2234f9e4ab2 --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/Main.hs @@ -0,0 +1,16 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +module Main where + +import Foreign.C (CInt (..)) + +foreign import ccall "meaning_of_life_c" + meaning_of_life_c :: IO CInt + +main :: IO () +main = do + secret <- meaning_of_life_c + -- The value 11 comes from the exported Lib.hello + if (secret == 11) + then putStrLn ("The secret is " ++ show secret) + else error ("Expected value 11, got " ++ show secret) diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.out b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.out new file mode 100644 index 00000000000..cdfe4ab10de --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.out @@ -0,0 +1,12 @@ +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - csourcedepsstub-0.1 (lib) (first run) + - csourcedepsstub-0.1 (exe:csourcedeps-exe) (first run) +Configuring library for csourcedepsstub-0.1... +Preprocessing library for csourcedepsstub-0.1... +Building library for csourcedepsstub-0.1... +Configuring executable 'csourcedeps-exe' for csourcedepsstub-0.1... +Preprocessing executable 'csourcedeps-exe' for csourcedepsstub-0.1... +Building executable 'csourcedeps-exe' for csourcedepsstub-0.1... diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.project b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.test.hs b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.test.hs new file mode 100644 index 00000000000..fcfdc963f44 --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cabal.test.hs @@ -0,0 +1,6 @@ +-- Tests whether an extra C source can depend on a _stub header generated by +-- GHC compiling a Haskell module with a foreign export declaration + +import Test.Cabal.Prelude +main = cabalTest $ do + cabal "v2-build" [] diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cbits/clib.c b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cbits/clib.c new file mode 100644 index 00000000000..3589ade00f3 --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/cbits/clib.c @@ -0,0 +1,5 @@ +#include "Lib_stub.h" + +int meaning_of_life_c() { + return hello(); +} diff --git a/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/csourcedepsstub.cabal b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/csourcedepsstub.cabal new file mode 100644 index 00000000000..61f0266993d --- /dev/null +++ b/cabal-testsuite/PackageTests/FFI/CSourceDependsStub/csourcedepsstub.cabal @@ -0,0 +1,16 @@ +cabal-version: 2.2 +name: csourcedepsstub +version: 0.1 +build-type: Simple + +library + build-depends: base + default-language: Haskell2010 + include-dirs: cbits + c-sources: cbits/clib.c + exposed-modules: Lib + +executable csourcedeps-exe + main-is: Main.hs + build-depends: base, csourcedepsstub + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/ForeignLibs/setup.test.hs b/cabal-testsuite/PackageTests/ForeignLibs/setup.test.hs index 2bd17605b72..f667c93eb91 100644 --- a/cabal-testsuite/PackageTests/ForeignLibs/setup.test.hs +++ b/cabal-testsuite/PackageTests/ForeignLibs/setup.test.hs @@ -17,6 +17,7 @@ import Distribution.Simple.Program.Types import Distribution.System import Distribution.Verbosity import Distribution.Version +import System.Directory import Test.Cabal.Prelude @@ -27,8 +28,9 @@ main = setupAndCabalTest . recordMode DoNotRecord $ do -- Foreign libraries don't work with GHC 7.6 and earlier skipUnlessGhcVersion ">= 7.8" win <- isWindows - ghc94 <- isGhcVersion "== 9.4.*" - expectBrokenIf (win && ghc94) 8451 $ + ghc94 <- isGhcVersion ">= 9.4.1" + ghc844 <- isGhcVersion "== 8.4.4" + expectBrokenIf (ghc844 || (win && ghc94)) 8451 $ withPackageDb $ do setup_install [] setup "copy" [] -- regression test #4156 diff --git a/cabal-testsuite/PackageTests/Freeze/disable-benchmarks.test.hs b/cabal-testsuite/PackageTests/Freeze/disable-benchmarks.test.hs index 52ef66110de..ae5dca1369c 100644 --- a/cabal-testsuite/PackageTests/Freeze/disable-benchmarks.test.hs +++ b/cabal-testsuite/PackageTests/Freeze/disable-benchmarks.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withRepo "repo" . withSourceCopy $ do + withRepo "repo" $ do cabal "v1-freeze" ["--disable-benchmarks"] cwd <- fmap testCurrentDir getTestEnv assertFileDoesNotContain (cwd "cabal.config") "criterion" diff --git a/cabal-testsuite/PackageTests/Freeze/disable-tests.test.hs b/cabal-testsuite/PackageTests/Freeze/disable-tests.test.hs index a959240586c..0d56e932614 100644 --- a/cabal-testsuite/PackageTests/Freeze/disable-tests.test.hs +++ b/cabal-testsuite/PackageTests/Freeze/disable-tests.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withRepo "repo" . withSourceCopy $ do + withRepo "repo" $ do cabal "v1-freeze" ["--disable-tests"] cwd <- fmap testCurrentDir getTestEnv assertFileDoesNotContain (cwd "cabal.config") "test-framework" diff --git a/cabal-testsuite/PackageTests/Freeze/dry-run.test.hs b/cabal-testsuite/PackageTests/Freeze/dry-run.test.hs index 11130ba8c2c..89a650496a8 100644 --- a/cabal-testsuite/PackageTests/Freeze/dry-run.test.hs +++ b/cabal-testsuite/PackageTests/Freeze/dry-run.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withRepo "repo" . withSourceCopy $ do + withRepo "repo" $ do recordMode DoNotRecord $ cabal "v1-freeze" ["--dry-run"] cwd <- fmap testCurrentDir getTestEnv shouldNotExist (cwd "cabal.config") diff --git a/cabal-testsuite/PackageTests/Freeze/enable-benchmarks.test.hs b/cabal-testsuite/PackageTests/Freeze/enable-benchmarks.test.hs index d525c1d26ff..995b9102555 100644 --- a/cabal-testsuite/PackageTests/Freeze/enable-benchmarks.test.hs +++ b/cabal-testsuite/PackageTests/Freeze/enable-benchmarks.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withRepo "repo" . withSourceCopy $ do + withRepo "repo" $ do cabal "v1-freeze" ["--enable-benchmarks"] cwd <- fmap testCurrentDir getTestEnv assertFileDoesContain (cwd "cabal.config") "criterion" diff --git a/cabal-testsuite/PackageTests/Freeze/enable-tests.test.hs b/cabal-testsuite/PackageTests/Freeze/enable-tests.test.hs index 8a43b5b6daf..d24eb5ee9ab 100644 --- a/cabal-testsuite/PackageTests/Freeze/enable-tests.test.hs +++ b/cabal-testsuite/PackageTests/Freeze/enable-tests.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withRepo "repo" . withSourceCopy $ do + withRepo "repo" $ do cabal "v1-freeze" ["--enable-tests"] cwd <- fmap testCurrentDir getTestEnv assertFileDoesContain (cwd "cabal.config") "test-framework" diff --git a/cabal-testsuite/PackageTests/Freeze/freeze.test.hs b/cabal-testsuite/PackageTests/Freeze/freeze.test.hs index 2961a0e0055..e669febbd41 100644 --- a/cabal-testsuite/PackageTests/Freeze/freeze.test.hs +++ b/cabal-testsuite/PackageTests/Freeze/freeze.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withRepo "repo" . withSourceCopy $ do + withRepo "repo" $ do cabal "v1-freeze" [] cwd <- fmap testCurrentDir getTestEnv assertFileDoesNotContain (cwd "cabal.config") "exceptions" diff --git a/cabal-testsuite/PackageTests/Get/OnlyDescription/cabal.test.hs b/cabal-testsuite/PackageTests/Get/OnlyDescription/cabal.test.hs index 3b4a36553c7..359d29a33de 100644 --- a/cabal-testsuite/PackageTests/Get/OnlyDescription/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Get/OnlyDescription/cabal.test.hs @@ -9,3 +9,4 @@ main = cabalTest $ withRepo "repo" $ do cabal "get" [ "criterion", "--only-package-description" ] + void (shell "rm" ["criterion-1.1.4.0.cabal"]) diff --git a/cabal-testsuite/PackageTests/Get/T7248/cabal.out b/cabal-testsuite/PackageTests/Get/T7248/cabal.out index 0c6e3ce035c..a172b425d4d 100644 --- a/cabal-testsuite/PackageTests/Get/T7248/cabal.out +++ b/cabal-testsuite/PackageTests/Get/T7248/cabal.out @@ -1,6 +1,4 @@ # cabal get Warning: /cabal.config: Unrecognized stanza on line 3 -Warning: The package list for 'repo.invalid' does not exist. Run 'cabal update' to download it. -Error: [Cabal-7100] -There is no package named 'a-b-s-e-n-t'. -You may need to run 'cabal update' to get the latest list of available packages. +Error: [Cabal-7160] +The package list for 'repo.invalid' does not exist. Run 'cabal update' to download it. diff --git a/cabal-testsuite/PackageTests/HaddockArgs/cabal.project b/cabal-testsuite/PackageTests/HaddockArgs/cabal.project index 5356e76f67c..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/HaddockArgs/cabal.project +++ b/cabal-testsuite/PackageTests/HaddockArgs/cabal.project @@ -1 +1 @@ -packages: . \ No newline at end of file +packages: . diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/a.cabal b/cabal-testsuite/PackageTests/HaddockBuildDepends/a.cabal new file mode 100644 index 00000000000..552ef337ea6 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/a.cabal @@ -0,0 +1,10 @@ +name: a +version: 0.1.0.0 +build-type: Simple +cabal-version: >= 1.10 + +library + exposed-modules: MyLib + build-depends: base, lib + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.out b/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.out new file mode 100644 index 00000000000..bb6754c14a6 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.out @@ -0,0 +1,27 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - exe-1 (exe:exe) (requires build) + - lib-1 (lib) (requires build) + - a-0.1.0.0 (lib) (first run) +Configuring executable 'exe' for exe-1... +Preprocessing executable 'exe' for exe-1... +Building executable 'exe' for exe-1... +Installing executable exe in +Warning: The directory /cabal.dist/home/.cabal/store/ghc-/incoming/new-/cabal.dist/home/.cabal/store/ghc-/-/bin is not in the system search path. +Configuring library for lib-1... +Preprocessing library for lib-1... +Building library for lib-1... +Preprocessing library for lib-1... +Running Haddock on library for lib-1... +Documentation created: dist/doc/html/lib/ +Installing library in +Configuring library for a-0.1.0.0... +Preprocessing library for a-0.1.0.0... +Building library for a-0.1.0.0... +Preprocessing library for a-0.1.0.0... +Running Haddock on library for a-0.1.0.0... +Documentation created: /cabal.dist/work/dist/build//ghc-/a-0.1.0.0/doc/html/a/ diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.project b/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.test.hs b/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.test.hs new file mode 100644 index 00000000000..28821c5e858 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/cabal.test.hs @@ -0,0 +1,22 @@ +import Test.Cabal.Prelude + + +main = cabalTest . withRepo "repo" $ do + cabal "build" ["--enable-documentation"] + + env <- getTestEnv + let storeDir = testCabalDir env "store" + + -- Check properties of executable component + libDir <- liftIO $ findDependencyInStore storeDir "exe" + -- Documentation is enabled.. + assertFileDoesContain (libDir "cabal-hash.txt") "documentation: True" + -- But not built + shouldDirectoryNotExist ( libDir "share" "doc" ) + + -- Check properties of library + libDir <- liftIO $ findDependencyInStore storeDir "lib" + -- Documentation is enabled.. + assertFileDoesContain (libDir "cabal-hash.txt") "documentation: True" + -- and has been built + shouldDirectoryExist ( libDir "share" "doc" ) diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/exe-1/Main.hs b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/exe-1/Main.hs new file mode 100644 index 00000000000..de106fe48f9 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/exe-1/Main.hs @@ -0,0 +1,3 @@ +module Main where + +main = return () diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/exe-1/exe.cabal b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/exe-1/exe.cabal new file mode 100644 index 00000000000..a5c1b537d7b --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/exe-1/exe.cabal @@ -0,0 +1,12 @@ +name: exe +version: 1 +license: BSD3 +author: Edward Z. Yang +maintainer: ezyang@cs.stanford.edu +build-type: Simple +cabal-version: 2.0 + +executable exe + build-depends: base + main-is: Main.hs + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/lib-1/Lib.hs b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/lib-1/Lib.hs new file mode 100644 index 00000000000..6d85a26fe10 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/lib-1/Lib.hs @@ -0,0 +1 @@ +module Lib where diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/lib-1/lib.cabal b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/lib-1/lib.cabal new file mode 100644 index 00000000000..526338f344f --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/repo/lib-1/lib.cabal @@ -0,0 +1,13 @@ +name: lib +version: 1 +license: BSD3 +author: Edward Z. Yang +maintainer: ezyang@cs.stanford.edu +build-type: Simple +cabal-version: 2.0 + +library + build-depends: base + build-tool-depends: exe:exe + exposed-modules: Lib + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/HaddockBuildDepends/src/MyLib.hs b/cabal-testsuite/PackageTests/HaddockBuildDepends/src/MyLib.hs new file mode 100644 index 00000000000..bbaef0a6d64 --- /dev/null +++ b/cabal-testsuite/PackageTests/HaddockBuildDepends/src/MyLib.hs @@ -0,0 +1,4 @@ +module MyLib (someFunc) where + +someFunc :: IO () +someFunc = return () diff --git a/cabal-testsuite/PackageTests/HaddockProject/haddock-project.out b/cabal-testsuite/PackageTests/HaddockProject/haddock-project.out index a2f14d6a6f2..cde81e2c2ba 100644 --- a/cabal-testsuite/PackageTests/HaddockProject/haddock-project.out +++ b/cabal-testsuite/PackageTests/HaddockProject/haddock-project.out @@ -21,5 +21,5 @@ Installing library in Configuring library for a-0.1.0.0... Preprocessing library for a-0.1.0.0... Running Haddock on library for a-0.1.0.0... -Documentation created: /haddock-project.dist/source/dist-newstyle/build//ghc-/a-0.1.0.0/doc/html/a/ +Documentation created: /dist-newstyle/build//ghc-/a-0.1.0.0/doc/html/a/ Documentation created: haddocks/index.html diff --git a/cabal-testsuite/PackageTests/HaddockProject/haddock-project.test.hs b/cabal-testsuite/PackageTests/HaddockProject/haddock-project.test.hs index 6d889a14163..923b1ad8704 100644 --- a/cabal-testsuite/PackageTests/HaddockProject/haddock-project.test.hs +++ b/cabal-testsuite/PackageTests/HaddockProject/haddock-project.test.hs @@ -1,7 +1,7 @@ import Test.Cabal.Prelude import System.Directory (doesFileExist, removeDirectory) -main = cabalTest . withRepo "repo" . withSourceCopy $ do +main = cabalTest . withRepo "repo" $ do skipUnlessGhcVersion ">= 9.4.0" env <- getTestEnv let testDir = testCurrentDir env diff --git a/cabal-testsuite/PackageTests/HaddockWarn/cabal.project b/cabal-testsuite/PackageTests/HaddockWarn/cabal.project index 5356e76f67c..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/HaddockWarn/cabal.project +++ b/cabal-testsuite/PackageTests/HaddockWarn/cabal.project @@ -1 +1 @@ -packages: . \ No newline at end of file +packages: . diff --git a/cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/help-prints-config-file.out b/cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/help-prints-config-file.out new file mode 100644 index 00000000000..9b5b68a2db9 --- /dev/null +++ b/cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/help-prints-config-file.out @@ -0,0 +1,2 @@ +# cabal --help +# cabal --help diff --git a/cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/help-prints-config-file.test.hs b/cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/help-prints-config-file.test.hs new file mode 100644 index 00000000000..171560419c3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Help/HelpPrintsConfigFile/help-prints-config-file.test.hs @@ -0,0 +1,52 @@ +-- Andreas Abel, 2024-01-13, 2024-01-28 +-- +-- Ensure that the help text prints the name of the config file, following a fixed text. +-- This invariant is used by clients such as the Haskell setup github action. +-- See: https://github.com/haskell-actions/setup/pull/63 + +-- The end of the help text should look like: +-- +-- > You can edit the cabal configuration file to set defaults: +-- > <>/.cabal/config +-- > This file will be generated with sensible defaults if you run 'cabal update'. +-- +-- The last line is only present when the file does *not* exist. +-- +-- So while usually the last line is the name of the config file, +-- the correct way is to take the line after the fixed text "You can edit...". + +import Distribution.Utils.String (trim) +import System.Directory (removeFile) +import Test.Cabal.Prelude + +main = cabalTest $ do + env <- getTestEnv + let configFile = testUserCabalConfigFile env + + -- Test 1: with config file present. + test configFile "Case: config file exists." + + -- Test 2: with config file absent. + liftIO $ removeFile configFile + test configFile "Case: config file does not exist." + +test configFile info = do + res <- cabal' "--help" [] + assertEqual (unwords ["Help text contains name of the config file after the marker.", info]) + configFile + (configFileFromHelpText $ resultOutput res) + +-- | The config file is the line following the fixed text: +-- "You can edit the cabal configuration file to set defaults:" +-- +-- If this marker is not found, return the empty string. +configFileFromHelpText :: String -> FilePath +configFileFromHelpText txt = + case found of + _marker : l : _ -> l + _ -> "" + where + marker = "You can edit the cabal configuration file to set defaults:" + (_before, found) = break (marker ==) $ map trim $ lines txt + -- Note: 'trim' lines to get rid of CR on Windows; + -- 'lines' does not seem to remove it. diff --git a/cabal-testsuite/PackageTests/Init/init-backup.test.hs b/cabal-testsuite/PackageTests/Init/init-backup.test.hs index f1c4ab0fc74..e9e5c129358 100644 --- a/cabal-testsuite/PackageTests/Init/init-backup.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-backup.test.hs @@ -1,11 +1,10 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv +main = cabalTest $ do + cwd <- fmap testCurrentDir getTestEnv - (initOut, buildOut) <- withDirectory cwd $ do - initOut <- cabalWithStdin "init" ["-i"] + (initOut, buildOut) <- do + initOut <- cabalWithStdin "init" ["-i", "-p", "app"] "2\ny\n5\n\n\n2\n\n\n\n\n\n\n\n\n\n" setup "configure" [] buildOut <- setup' "build" ["app"] diff --git a/cabal-testsuite/PackageTests/Init/init-interactive-empty-folder.test.hs b/cabal-testsuite/PackageTests/Init/init-interactive-empty-folder.test.hs index 4c438244651..87472bdc416 100644 --- a/cabal-testsuite/PackageTests/Init/init-interactive-empty-folder.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-interactive-empty-folder.test.hs @@ -1,8 +1,10 @@ import Test.Cabal.Prelude +import System.Directory main = cabalTest $ do - tmpDir <- testTmpDir <$> getTestEnv - withDirectory tmpDir $ do + tmpDir <- testCurrentDir <$> getTestEnv + liftIO $ createDirectory (tmpDir "empty") + withDirectory (tmpDir "empty") $ do res <- cabalWithStdin "init" ["-i"] (replicate 20 '\n') -- Default all the way down. diff --git a/cabal-testsuite/PackageTests/Init/init-interactive-ghc2021.test.hs b/cabal-testsuite/PackageTests/Init/init-interactive-ghc2021.test.hs index 8b53ce18b30..7df3f662212 100644 --- a/cabal-testsuite/PackageTests/Init/init-interactive-ghc2021.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-interactive-ghc2021.test.hs @@ -1,11 +1,9 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv +main = cabalTest $ do + env <- getTestEnv + buildOut <- + cabalWithStdin "init" ["-i", "-p", "app"] + "2\n\n5\n\n\n2\n\n\n\n\n\n\n3\n\n" - buildOut <- withDirectory cwd $ do - cabalWithStdin "init" ["-i"] - "2\n\n5\n\n\n2\n\n\n\n\n\n\n\n3\n\n" - - assertFileDoesContain (cwd "app.cabal") "GHC2021" + assertFileDoesContain (testCurrentDir env "app.cabal") "GHC2021" diff --git a/cabal-testsuite/PackageTests/Init/init-interactive-legacy.test.hs b/cabal-testsuite/PackageTests/Init/init-interactive-legacy.test.hs index 3fd9415d570..75b6472e142 100644 --- a/cabal-testsuite/PackageTests/Init/init-interactive-legacy.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-interactive-legacy.test.hs @@ -1,12 +1,10 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv - - buildOut <- withDirectory cwd $ do - cabalWithStdin "init" ["-i"] - "2\n\n1\n\n\n10\n\n\n\n\n\n\n\n\n\n" +main = cabalTest $ do + cwd <- testCurrentDir <$> getTestEnv + buildOut <- do + cabalWithStdin "init" ["-i", "-p", "app"] + "2\n\n1\n\n10\n\n\n\n\n\n\n\n\n\n" setup "configure" [] setup' "build" ["app"] diff --git a/cabal-testsuite/PackageTests/Init/init-interactive.test.hs b/cabal-testsuite/PackageTests/Init/init-interactive.test.hs index 86bda8b028a..4e1cbf816cf 100644 --- a/cabal-testsuite/PackageTests/Init/init-interactive.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-interactive.test.hs @@ -1,11 +1,10 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv +main = cabalTest $ do + cwd <- fmap testCurrentDir getTestEnv buildOut <- withDirectory cwd $ do - cabalWithStdin "init" ["-i"] + cabalWithStdin "init" ["-i", "-p", "app"] "2\n\n5\n\n\n\n\n\n\n\n\n\n\n\n\n" setup "configure" [] setup' "build" ["app"] diff --git a/cabal-testsuite/PackageTests/Init/init-legacy.test.hs b/cabal-testsuite/PackageTests/Init/init-legacy.test.hs index eac7b312fb5..e3153157428 100644 --- a/cabal-testsuite/PackageTests/Init/init-legacy.test.hs +++ b/cabal-testsuite/PackageTests/Init/init-legacy.test.hs @@ -1,11 +1,10 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv +main = cabalTest $ do + cwd <- fmap testCurrentDir getTestEnv - buildOut <- withDirectory cwd $ do - cabal "init" ["-n", "--exe", "--application-dir=app", "--main-is=Main.hs", "--cabal-version=1.24"] + buildOut <- do + cabal "init" ["-n", "--exe", "-p", "app", "--application-dir=app", "--main-is=Main.hs", "--cabal-version=1.24"] setup "configure" [] setup' "build" ["app"] diff --git a/cabal-testsuite/PackageTests/Init/init.test.hs b/cabal-testsuite/PackageTests/Init/init.test.hs index 83a512d5893..c7739c4fcb2 100644 --- a/cabal-testsuite/PackageTests/Init/init.test.hs +++ b/cabal-testsuite/PackageTests/Init/init.test.hs @@ -1,11 +1,11 @@ import Test.Cabal.Prelude +import System.Directory -main = cabalTest $ - withSourceCopyDir "app" $ do - cwd <- fmap testSourceCopyDir getTestEnv +main = cabalTest $ do + cwd <- fmap testCurrentDir getTestEnv - buildOut <- withDirectory cwd $ do - cabal "init" ["-n", "--exe", "--application-dir=app", "--main-is=Main.hs"] + buildOut <- do + cabal "init" ["-n", "--exe", "-p", "app", "--application-dir=app", "--main-is=Main.hs"] setup "configure" [] setup' "build" ["app"] diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/Main.hs b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/Main.hs new file mode 100644 index 00000000000..38bfcb0221f --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/Main.hs @@ -0,0 +1,25 @@ +{-# LANGUAGE CPP #-} + +#ifdef TEST1 +main = putStrLn "hi1" +#endif + +#ifdef TEST2 +main = putStrLn "hi2" +#endif + +#ifdef TEST3 +main = putStrLn "hi3" +#endif + +#ifdef TEST4 +main = putStrLn "hi4" +#endif + +#ifdef TEST5 +main = putStrLn "hi5" +#endif + +#ifdef TEST6 +main = putStrLn "hi6" +#endif diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/cabal.project b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/cabal.test.hs b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/cabal.test.hs new file mode 100644 index 00000000000..2583cdac2e3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/cabal.test.hs @@ -0,0 +1,28 @@ +import Test.Cabal.Prelude + +main = cabalTest $ do + env <- getTestEnv + recordMode DoNotRecord $ do + let + installdir = testPrefixDir env "bin" + commonOpts v = ["--ghc-options=-DTEST" ++ show v, "--overwrite-policy=always", "--installdir=" ++ installdir] + installWithTgt tgt v = do + cabal "install" (tgt:commonOpts v) + runInstalledExe' "my-exe" [] + >>= assertOutputContains ("hi" ++ show v) + + installExternalWithTgt tgt v = withRepo "repo" (installWithTgt tgt v) + + + cabal "install" (commonOpts 1) -- no target + runInstalledExe' "my-exe" [] + >>= assertOutputContains "hi1" + + installWithTgt "t7297-89097236a" 2 + installWithTgt "exe:my-exe" 3 + installWithTgt "my-exe" 4 + installWithTgt "all" 5 + installWithTgt "all:exes" 6 + + -- And test it works when installing from an external repo (think Hackage) + installExternalWithTgt "external-lib" 2 diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/CHANGELOG.md b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/CHANGELOG.md new file mode 100644 index 00000000000..fbf078ff958 --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for external-lib0100 + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/Main.hs b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/Main.hs new file mode 100644 index 00000000000..38bfcb0221f --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/Main.hs @@ -0,0 +1,25 @@ +{-# LANGUAGE CPP #-} + +#ifdef TEST1 +main = putStrLn "hi1" +#endif + +#ifdef TEST2 +main = putStrLn "hi2" +#endif + +#ifdef TEST3 +main = putStrLn "hi3" +#endif + +#ifdef TEST4 +main = putStrLn "hi4" +#endif + +#ifdef TEST5 +main = putStrLn "hi5" +#endif + +#ifdef TEST6 +main = putStrLn "hi6" +#endif diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/external-lib.cabal b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/external-lib.cabal new file mode 100644 index 00000000000..bc501812d3b --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/repo/external-lib-0.1.0.0/external-lib.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: external-lib +version: 0.1.0.0 +license: NONE +author: matthewtpickering@gmail.com +maintainer: Matthew Pickering +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +executable my-exe + import: warnings + main-is: Main.hs + build-depends: base + hs-source-dirs: . + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Install/T7297-8909-7236/t7297-89097236a.cabal b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/t7297-89097236a.cabal new file mode 100644 index 00000000000..84ca78363c7 --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T7297-8909-7236/t7297-89097236a.cabal @@ -0,0 +1,8 @@ +name: t7297-89097236a +version: 1.0 +build-type: Simple +cabal-version: >= 1.2 + +executable my-exe + main-is: Main.hs + build-depends: base diff --git a/cabal-testsuite/PackageTests/Install/T8848/Main.hs b/cabal-testsuite/PackageTests/Install/T8848/Main.hs new file mode 100644 index 00000000000..76a9bdb5d48 --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T8848/Main.hs @@ -0,0 +1 @@ +main = pure () diff --git a/cabal-testsuite/PackageTests/Install/T8848/cabal.project b/cabal-testsuite/PackageTests/Install/T8848/cabal.project new file mode 100644 index 00000000000..ac8175d95e0 --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T8848/cabal.project @@ -0,0 +1,2 @@ +packages: . +extra-packages: containers diff --git a/cabal-testsuite/PackageTests/Install/T8848/cabal.test.hs b/cabal-testsuite/PackageTests/Install/T8848/cabal.test.hs new file mode 100644 index 00000000000..000662fd82b --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T8848/cabal.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +main = cabalTest $ do + recordMode DoNotRecord $ + cabal' "install" ["t8848"] + >>= assertOutputContains "Wrote tarball sdist to" diff --git a/cabal-testsuite/PackageTests/Install/T8848/t8848.cabal b/cabal-testsuite/PackageTests/Install/T8848/t8848.cabal new file mode 100644 index 00000000000..df445b7d99d --- /dev/null +++ b/cabal-testsuite/PackageTests/Install/T8848/t8848.cabal @@ -0,0 +1,8 @@ +name: t8848 +version: 1.0 +build-type: Simple +cabal-version: >= 1.2 + +executable t8848 + main-is: Main.hs + build-depends: base diff --git a/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.cabal.out b/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.cabal.out index b03e6765cb0..65ea4562009 100644 --- a/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.cabal.out +++ b/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.cabal.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-depends-bad-version-0.1.0.0... Error: [Cabal-5559] -The package has an impossible version range for a dependency on an internal library: build-depends-bad-version >=2. This version range does not include the current package, and must be removed as the current package's library will always be used. +[impossible-dep] The package has an impossible version range for a dependency on an internal library: build-depends-bad-version >=2. This version range does not include the current package, and must be removed as the current package's library will always be used. diff --git a/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.out b/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.out index b03e6765cb0..65ea4562009 100644 --- a/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.out +++ b/cabal-testsuite/PackageTests/InternalVersions/BuildDependsBad/setup.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-depends-bad-version-0.1.0.0... Error: [Cabal-5559] -The package has an impossible version range for a dependency on an internal library: build-depends-bad-version >=2. This version range does not include the current package, and must be removed as the current package's library will always be used. +[impossible-dep] The package has an impossible version range for a dependency on an internal library: build-depends-bad-version >=2. This version range does not include the current package, and must be removed as the current package's library will always be used. diff --git a/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.cabal.out b/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.cabal.out index 077f750b066..872eeee78c4 100644 --- a/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.cabal.out +++ b/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.cabal.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-tool-depends-bad-version-0.1.0.0... Error: [Cabal-5559] -The package has an impossible version range for a dependency on an internal executable: build-tool-depends-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. +[impossible-dep-exe] The package has an impossible version range for a dependency on an internal executable: build-tool-depends-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. diff --git a/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.out b/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.out index 077f750b066..872eeee78c4 100644 --- a/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.out +++ b/cabal-testsuite/PackageTests/InternalVersions/BuildToolDependsBad/setup.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-tool-depends-bad-version-0.1.0.0... Error: [Cabal-5559] -The package has an impossible version range for a dependency on an internal executable: build-tool-depends-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. +[impossible-dep-exe] The package has an impossible version range for a dependency on an internal executable: build-tool-depends-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. diff --git a/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.cabal.out b/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.cabal.out index 68a45e22992..3ea7f8e2604 100644 --- a/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.cabal.out +++ b/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.cabal.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-tools-bad-version-0.1.0.0... Error: [Cabal-5559] -The package has an impossible version range for a dependency on an internal executable: build-tools-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. +[impossible-dep-exe] The package has an impossible version range for a dependency on an internal executable: build-tools-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. diff --git a/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.out b/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.out index 68a45e22992..3ea7f8e2604 100644 --- a/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.out +++ b/cabal-testsuite/PackageTests/InternalVersions/BuildToolsBad/setup.out @@ -1,4 +1,4 @@ # Setup configure Configuring build-tools-bad-version-0.1.0.0... Error: [Cabal-5559] -The package has an impossible version range for a dependency on an internal executable: build-tools-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. +[impossible-dep-exe] The package has an impossible version range for a dependency on an internal executable: build-tools-bad-version:hello-world >=2. This version range does not include the current package, and must be removed as the current package's executable will always be used. diff --git a/cabal-testsuite/PackageTests/LinkerOptions/.gitignore b/cabal-testsuite/PackageTests/LinkerOptions/.gitignore new file mode 100644 index 00000000000..e6ebf2db20b --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/.gitignore @@ -0,0 +1 @@ +T7339/clib-install/libhello.so diff --git a/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.out b/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.out index 242bb523282..ecd7f77f7c7 100644 --- a/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.out +++ b/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.out @@ -1,5 +1,6 @@ +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic0.env basic # cabal v2-install -Wrote tarball sdist to /cabal.dist/work/./basic/../dist/sdist/basic-0.1.tar.gz +Wrote tarball sdist to /cabal.dist/work/./basic0/dist/sdist/basic-0.1.tar.gz Resolving dependencies... Build profile: -w ghc- -O1 In order, the following will be built: @@ -8,8 +9,18 @@ Configuring library for basic-0.1... Preprocessing library for basic-0.1... Building library for basic-0.1... Installing library in +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic0.env basic # cabal v2-install -Wrote tarball sdist to /cabal.dist/work/./basic/../dist/sdist/basic-0.1.tar.gz +Wrote tarball sdist to /cabal.dist/work/./basic0/dist/sdist/basic-0.1.tar.gz +Error: [Cabal-7145] +Packages requested to install already exist in environment file at /cabal.dist/basic0.env. Overwriting them may break other packages. Use --force-reinstalls to proceed anyway. Packages: basic +# install options: --force-reinstalls --disable-deterministic --lib --package-env=/cabal.dist/basic0.env basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic0/dist/sdist/basic-0.1.tar.gz +Resolving dependencies... +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic1.env --enable-shared --enable-executable-dynamic --disable-library-vanilla basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic1/dist/sdist/basic-0.1.tar.gz Resolving dependencies... Build profile: -w ghc- -O1 In order, the following will be built: @@ -18,9 +29,38 @@ Configuring library for basic-0.1... Preprocessing library for basic-0.1... Building library for basic-0.1... Installing library in +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic1.env --enable-shared --enable-executable-dynamic --disable-library-vanilla basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic1/dist/sdist/basic-0.1.tar.gz +Error: [Cabal-7145] +Packages requested to install already exist in environment file at /cabal.dist/basic1.env. Overwriting them may break other packages. Use --force-reinstalls to proceed anyway. Packages: basic +# install options: --force-reinstalls --disable-deterministic --lib --package-env=/cabal.dist/basic1.env --enable-shared --enable-executable-dynamic --disable-library-vanilla basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic1/dist/sdist/basic-0.1.tar.gz +Resolving dependencies... +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic2.env basic # cabal v2-install -Wrote tarball sdist to /cabal.dist/work/./basic/../dist/sdist/basic-0.1.tar.gz +Wrote tarball sdist to /cabal.dist/work/./basic2/dist/sdist/basic-0.1.tar.gz Resolving dependencies... +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic2.env basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic2/dist/sdist/basic-0.1.tar.gz +Error: [Cabal-7145] +Packages requested to install already exist in environment file at /cabal.dist/basic2.env. Overwriting them may break other packages. Use --force-reinstalls to proceed anyway. Packages: basic +# install options: --force-reinstalls --disable-deterministic --lib --package-env=/cabal.dist/basic2.env basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic2/dist/sdist/basic-0.1.tar.gz +Resolving dependencies... +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic3.env --enable-shared --enable-executable-dynamic --disable-library-vanilla basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic3/dist/sdist/basic-0.1.tar.gz +Resolving dependencies... +# install options: --disable-deterministic --lib --package-env=/cabal.dist/basic3.env --enable-shared --enable-executable-dynamic --disable-library-vanilla basic +# cabal v2-install +Wrote tarball sdist to /cabal.dist/work/./basic3/dist/sdist/basic-0.1.tar.gz +Error: [Cabal-7145] +Packages requested to install already exist in environment file at /cabal.dist/basic3.env. Overwriting them may break other packages. Use --force-reinstalls to proceed anyway. Packages: basic +# install options: --force-reinstalls --disable-deterministic --lib --package-env=/cabal.dist/basic3.env --enable-shared --enable-executable-dynamic --disable-library-vanilla basic # cabal v2-install -Wrote tarball sdist to /cabal.dist/work/./basic/../dist/sdist/basic-0.1.tar.gz +Wrote tarball sdist to /cabal.dist/work/./basic3/dist/sdist/basic-0.1.tar.gz Resolving dependencies... diff --git a/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.test.hs b/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.test.hs index 9da924366f4..8e7c8a6391d 100644 --- a/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.test.hs +++ b/cabal-testsuite/PackageTests/LinkerOptions/NonignoredConfigs/cabal.test.hs @@ -1,4 +1,5 @@ import Test.Cabal.Prelude +import Distribution.Simple.Utils -- This test ensures the following fix holds: -- > Fix project-local build flags being ignored. @@ -59,18 +60,21 @@ main = cabalTest $ do -- dynamic flags. skipIfWindows + env <- getTestEnv withPackageDb $ do -- Phase 1: get 4 hashes according to config flags. results <- forM (zip [0..] lrun) $ \(idx, linking) -> do - withDirectory "basic" $ do - withSourceCopyDir ("basic" ++ show idx) $ do - -- (Now do ‘cd ..’, since withSourceCopyDir made our previous - -- previous such withDirectories now accumulate to be - -- relative to setup.dist/basic0, not testSourceDir - -- (see 'testCurrentDir').) - withDirectory ".." $ do + liftIO $ copyDirectoryRecursive minBound (testCurrentDir env "basic") (testCurrentDir env "basic" ++ show idx) + withDirectory ("basic" ++ show idx) $ do packageEnv <- ( ("basic" ++ show idx ++ ".env")) . testWorkDir <$> getTestEnv - cabal "v2-install" $ ["--disable-deterministic", "--lib", "--package-env=" ++ packageEnv] ++ linkConfigFlags linking ++ ["basic"] + let installOptions = ["--disable-deterministic", "--lib", "--package-env=" ++ packageEnv] ++ linkConfigFlags linking ++ ["basic"] + recordMode RecordMarked $ do + recordHeader $ "install options:" : installOptions + cabal "v2-install" installOptions + recordHeader $ "install options:" : installOptions + fails $ cabal "v2-install" installOptions + recordHeader $ "install options:" : "--force-reinstalls" : installOptions + cabal "v2-install" $ "--force-reinstalls" : installOptions let exIPID s = takeWhile (/= '\n') . head . filter (\t -> any (`isPrefixOf` t) ["basic-0.1-", "bsc-0.1-"]) $ tails s hashedIpid <- exIPID <$> liftIO (readFile packageEnv) return $ ((idx, linking), hashedIpid) diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/T19350.script b/cabal-testsuite/PackageTests/LinkerOptions/T7339/T19350.script new file mode 100644 index 00000000000..d5b619f7bff --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/T19350.script @@ -0,0 +1,3 @@ +import Hello +hello +:q diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/clib/lib.c b/cabal-testsuite/PackageTests/LinkerOptions/T7339/clib/lib.c new file mode 100644 index 00000000000..556c1dcb748 --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/clib/lib.c @@ -0,0 +1,6 @@ +#include + +void hello_world(void) { + printf("hello world!"); +} + diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/Hello.hs b/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/Hello.hs new file mode 100644 index 00000000000..0dd0de66f74 --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/Hello.hs @@ -0,0 +1,3 @@ +module Hello (hello) where + +foreign import ccall "hello_world" hello :: IO () diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/Setup.hs b/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/Setup.hs new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/T7339.cabal b/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/T7339.cabal new file mode 100644 index 00000000000..d4ea571a2c0 --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/lib/T7339.cabal @@ -0,0 +1,11 @@ +cabal-version: >=1.10 +name: T7339 +version: 1.0 +build-type: Simple + +library + build-depends: base + exposed-modules: Hello + default-language: Haskell2010 + extra-libraries: hello + diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/setup.out b/cabal-testsuite/PackageTests/LinkerOptions/T7339/setup.out new file mode 100644 index 00000000000..45a71c209da --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/setup.out @@ -0,0 +1,6 @@ +# Setup configure +# Setup build +Preprocessing library for T7339-1.0... +Building library for T7339-1.0... +# Setup register +Registering library for T7339-1.0... diff --git a/cabal-testsuite/PackageTests/LinkerOptions/T7339/setup.test.hs b/cabal-testsuite/PackageTests/LinkerOptions/T7339/setup.test.hs new file mode 100644 index 00000000000..a46921de895 --- /dev/null +++ b/cabal-testsuite/PackageTests/LinkerOptions/T7339/setup.test.hs @@ -0,0 +1,67 @@ +-- Test for #19350, #7339 originally by @bgamari +-- ============================================= +-- +-- The plan +-- --------- +-- We build a C shared library (`libhello`, contained in ./clib) and then build +-- a Haskell library (`T19350-lib`, in ./lib) which depends upon it via `foreign +-- import`. We make sure that the libhello shared object can only be found via +-- the extra-lib-dirs from the package database registration (which we do by +-- moving libhello.so from its original place). +-- +-- Finally, we enter GHCi, load the Haskell library, and try to use it to call +-- into libhello. + +import System.Directory +import Distribution.System +import Test.Cabal.Prelude + + +main = setupTest $ do + + skipIfWindows + skipUnlessGhcVersion ">= 8.4" + + withPackageDb $ do + cwd <- takeDirectory . testCurrentDir <$> getTestEnv + plat <- testPlatform <$> getTestEnv + let libExt = case plat of + Platform _ OSX -> "dylib" + Platform _ Windows -> "dll" + Platform _ _other -> "so" + + + -- Link a C program against the library + _ <- runProgramM ghcProgram + [ "-fPIC", "-c", "clib/lib.c" + , "-o", "clib/lib.o" ] + Nothing + _ <- runProgramM ghcProgram + [ "-shared", "-no-hs-main", "clib/lib.o" + , "-o", "clib/libhello" <.> libExt ] + Nothing + + withDirectory "lib" $ do + setup "configure" ["-v0" + , "--extra-lib-dirs=" ++ (cwd "clib") + , "--extra-lib-dirs=" ++ (cwd "clib-install") + , "--disable-library-vanilla" + , "--enable-shared"] + setup "build" [] + setup "register" ["--inplace"] + + -- Move libhello from its original place to ensure it isn't found via RPATH + liftIO $ do + createDirectoryIfMissing False (cwd "clib-install") + copyFile (cwd "clib/libhello" <.> libExt) ( cwd "clib-install/libhello" <.> libExt) + removeFile (cwd "clib/libhello" <.> libExt) + + pkgDb <- testPackageDbDir <$> getTestEnv + ghciScript <- liftIO $ readFile (cwd "T19350.script") + _ <- runProgramM ghcProgram + [ "--interactive" + , "-package", "T7339" + , "-package-db", pkgDb + ] (Just ghciScript) + + return () diff --git a/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.out b/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.out index f2253c67190..e69de29bb2d 100644 --- a/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.out +++ b/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.out @@ -1,11 +0,0 @@ -# cabal v2-update -Downloading the latest package list from test-local-repo -# cabal v2-repl -Resolving dependencies... -Error: [Cabal-7107] -Could not resolve dependencies: -[__0] trying: pkg-a-0 (user goal) -[__1] next goal: pkg-a:setup.Cabal (dependency of pkg-a) -[__1] rejecting: pkg-a:setup.Cabal-/installed-, pkg-a:setup.Cabal-3.8.0.0 (constraint from --enable-multi-repl requires >=3.11) -[__1] fail (backjumping, conflict set: pkg-a, pkg-a:setup.Cabal) -After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: pkg-a:setup.Cabal (3), pkg-a (2) diff --git a/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.test.hs index 978b52e72ec..2f4faa0c24d 100644 --- a/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.test.hs +++ b/cabal-testsuite/PackageTests/MultiRepl/CabalTooOld/cabal.test.hs @@ -1,5 +1,8 @@ import Test.Cabal.Prelude -main = cabalTest $ withRepo "repo" $ do +main = cabalTest $ recordMode DoNotRecord . withRepo "repo" $ do + -- For the multi-repl command skipUnlessGhcVersion ">= 9.4" - void $ fails $ cabalWithStdin "v2-repl" ["--keep-temp-files","--enable-multi-repl","pkg-a", "pkg-b"] "" + skipUnlessAnyCabalVersion "< 3.11" + res <- fails $ cabalWithStdin "v2-repl" ["--keep-temp-files","--enable-multi-repl","pkg-a", "pkg-b"] "" + assertOutputContains "constraint from --enable-multi-repl requires >=3.11" res diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.out b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.project b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.project new file mode 100644 index 00000000000..91b0dbb40ff --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.project @@ -0,0 +1,3 @@ +packages: pkg-a/*.cabal +packages: pkg-b/*.cabal +packages: pkg-c/*.cabal diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.test.hs new file mode 100644 index 00000000000..3f86e566dfa --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/cabal.test.hs @@ -0,0 +1,10 @@ +import Test.Cabal.Prelude + +main = do + cabalTest $ recordMode DoNotRecord $ do + skipUnlessAnyCabalVersion "< 3.11" + -- Note: only the last package is interactive. + -- this test should load pkg-b too. + res <- fails $ cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-c", "pkg-a"] "Quu.quu" + + assertOutputContains "constraint from --enable-multi-repl requires >=3.11" res diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-a/Foo.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-a/Foo.hs new file mode 100644 index 00000000000..997ca89eecd --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-a/Foo.hs @@ -0,0 +1,5 @@ +module Foo where + +foo :: Int +foo = 42 + diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-a/pkg-a.cabal b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-a/pkg-a.cabal new file mode 100644 index 00000000000..e5241b65621 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-a/pkg-a.cabal @@ -0,0 +1,8 @@ +cabal-version: 2.2 +name: pkg-a +version: 0 + +library + default-language: Haskell2010 + build-depends: base + exposed-modules: Foo diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/Bar.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/Bar.hs new file mode 100644 index 00000000000..958a85a057e --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/Bar.hs @@ -0,0 +1,6 @@ +module Bar where + +import Foo + +bar :: Int +bar = foo + foo diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/Setup.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/Setup.hs new file mode 100644 index 00000000000..ee48ce9a5f9 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/Setup.hs @@ -0,0 +1,5 @@ +module Setup where + +import Distribution.Simple + +main = defaultMain diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/pkg-b.cabal b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/pkg-b.cabal new file mode 100644 index 00000000000..2a10d920018 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-b/pkg-b.cabal @@ -0,0 +1,12 @@ +cabal-version: 2.2 +name: pkg-b +version: 0 +build-type: Custom + +custom-setup + setup-depends: Cabal <= 3.11 + +library + default-language: Haskell2010 + build-depends: base, pkg-a + exposed-modules: Bar diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-c/Quu.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-c/Quu.hs new file mode 100644 index 00000000000..b684b61e212 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-c/Quu.hs @@ -0,0 +1,6 @@ +module Quu where + +import Bar + +quu :: Int +quu = bar + bar diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-c/pkg-c.cabal b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-c/pkg-c.cabal new file mode 100644 index 00000000000..11363814d01 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledBadClosure/pkg-c/pkg-c.cabal @@ -0,0 +1,8 @@ +cabal-version: 2.2 +name: pkg-c +version: 0 + +library + default-language: Haskell2010 + build-depends: base, pkg-b + exposed-modules: Quu diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs index 54a0afeb91e..7bfea13c2bc 100644 --- a/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledClosure/cabal.test.hs @@ -5,13 +5,7 @@ main = do skipUnlessGhcVersion ">= 9.4" -- Note: only the last package is interactive. -- this test should load pkg-b too. - res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-a", "pkg-c"] "" - - -- we should check that pkg-c is indeed loaded, - -- but currently the unit order is non-deterministic - -- Fix this when GHC has a way to change active unit. - -- TODO: ask for pkg-c unit, print Quu.quu + res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-c", "pkg-a"] "Quu.quu" assertOutputContains "- pkg-b-0 (interactive)" res - -- assertOutputContains "168" res - return () + assertOutputContains "168" res diff --git a/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs index 640b25d0d94..7ea2f71ea49 100644 --- a/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs +++ b/cabal-testsuite/PackageTests/MultiRepl/EnabledSucc/cabal.test.hs @@ -4,9 +4,5 @@ main = do cabalTest $ do skipUnlessGhcVersion ">= 9.4" skipIfWindows -- heisenbug, see #9103 - -- the package order is non-deterministic. - -- add Bar.Bar input to test that packages are trully loaded - -- when GHC gets support for switching active units - res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-a", "pkg-b"] "" - -- assertOutputContains "3735929054" res - return () + res <- cabalWithStdin "v2-repl" ["--enable-multi-repl","pkg-b", "pkg-a"] "Bar.bar" + assertOutputContains "3735929054" res diff --git a/cabal-testsuite/PackageTests/MultipleLibraries/Successful/cabal.test.hs b/cabal-testsuite/PackageTests/MultipleLibraries/Successful/cabal.test.hs index 88606589192..c9cb80255f8 100644 --- a/cabal-testsuite/PackageTests/MultipleLibraries/Successful/cabal.test.hs +++ b/cabal-testsuite/PackageTests/MultipleLibraries/Successful/cabal.test.hs @@ -1,4 +1,4 @@ import Test.Cabal.Prelude -main = cabalTest $ +main = cabalTest $ do cabal' "v2-run" ["pkg-abc:program"] >>= assertOutputContains "pkg-def:publib" - + return () diff --git a/cabal-testsuite/PackageTests/MultipleLibraries/Successful/coverage.test.hs b/cabal-testsuite/PackageTests/MultipleLibraries/Successful/coverage.test.hs new file mode 100644 index 00000000000..491afc9ecd4 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultipleLibraries/Successful/coverage.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude +main = cabalTest $ do + -- #8609 + expectBroken 8609 $ + cabal' "v2-test" ["--enable-coverage", "all"] + + return () diff --git a/cabal-testsuite/PackageTests/MultipleLibraries/Successful/pkg-abc/pkg-abc.cabal b/cabal-testsuite/PackageTests/MultipleLibraries/Successful/pkg-abc/pkg-abc.cabal index feed99fd047..6cb377aecb4 100644 --- a/cabal-testsuite/PackageTests/MultipleLibraries/Successful/pkg-abc/pkg-abc.cabal +++ b/cabal-testsuite/PackageTests/MultipleLibraries/Successful/pkg-abc/pkg-abc.cabal @@ -8,3 +8,11 @@ executable program build-depends: , base , pkg-def:publib + +test-suite program-test + type: exitcode-stdio-1.0 + default-language: Haskell2010 + main-is: Main.hs + build-depends: + , base + , pkg-def:publib diff --git a/cabal-testsuite/PackageTests/MultipleLibraries/T7270/.gitignore b/cabal-testsuite/PackageTests/MultipleLibraries/T7270/.gitignore new file mode 100644 index 00000000000..433b63af48e --- /dev/null +++ b/cabal-testsuite/PackageTests/MultipleLibraries/T7270/.gitignore @@ -0,0 +1 @@ +p/Main diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.out b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.out new file mode 100644 index 00000000000..d581aac783e --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.out @@ -0,0 +1,7 @@ +# cabal v2-repl +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - foo-0.1.0.0 (interactive) (first run) +Configuring foo-0.1.0.0... +Preprocessing executable 'foo' for foo-0.1.0.0.. diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.project b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.project new file mode 100644 index 00000000000..4fb0af6804e --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.project @@ -0,0 +1,2 @@ +packages: foo/ + diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.test.hs b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.test.hs new file mode 100644 index 00000000000..20b9fc164aa --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/cabal.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +main = do + cabalTest $ do + -- custom-setup stanza is not supported by Cabal's bundled with GHC's before 8.8 + skipUnlessGhcVersion ">= 8.8" + skipIfGhcVersion ">= 9.10" + res <- cabalWithStdin "v2-repl" ["foo"] "" + assertOutputContains "- foo-0.1.0.0 (interactive)" res diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/CHANGELOG.md b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/CHANGELOG.md new file mode 100644 index 00000000000..4d83316c82e --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for foo + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/LICENSE b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/LICENSE new file mode 100644 index 00000000000..9f52c36c122 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2024, Teo Camarasu + +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 Teo Camarasu nor the names of 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. diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/Setup.hs b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/Setup.hs new file mode 100644 index 00000000000..5f30459ab90 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/Setup.hs @@ -0,0 +1,8 @@ +import Control.Monad +import Distribution.PackageDescription +import Distribution.Simple +import qualified Distribution.Simple as DS +import Distribution.Simple.Setup + +main :: IO () +main = DS.defaultMainWithHooks DS.simpleUserHooks diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/app/Main.hs b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/app/Main.hs new file mode 100644 index 00000000000..65ae4a05d5d --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/app/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Hello, Haskell!" diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/foo.cabal b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/foo.cabal new file mode 100644 index 00000000000..f655e2b0ee1 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRepl/CustomSetup/foo/foo.cabal @@ -0,0 +1,38 @@ +cabal-version: 3.0 +name: foo +version: 0.1.0.0 +license: BSD-3-Clause +license-file: LICENSE +author: Teo Camarasu +build-type: Custom +extra-doc-files: CHANGELOG.md + +custom-setup + setup-depends: + Cabal <= 3.11 + , base + +common warnings + ghc-options: -Wall + +executable foo + -- Import common warning flags. + import: warnings + + -- .hs or .lhs file containing the Main module. + main-is: Main.hs + + -- Modules included in this executable, other than Main. + -- other-modules: + + -- LANGUAGE extensions used by modules in this package. + -- other-extensions: + + -- Other library packages from which modules are imported. + build-depends: base + + -- Directories containing source files. + hs-source-dirs: app + + -- Base language which the package is written in. + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRun/Datafiles/foo/foo.cabal b/cabal-testsuite/PackageTests/NewBuild/CmdRun/Datafiles/foo/foo.cabal index b69379dd383..505f5078aa4 100644 --- a/cabal-testsuite/PackageTests/NewBuild/CmdRun/Datafiles/foo/foo.cabal +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRun/Datafiles/foo/foo.cabal @@ -1,7 +1,7 @@ +cabal-version: 3.12 name: foo version: 1.0 build-type: Simple -cabal-version: >= 1.10 data-dir: data data-files: hello.txt diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRun/Script/cabal.project b/cabal-testsuite/PackageTests/NewBuild/CmdRun/Script/cabal.project index 5356e76f67c..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/NewBuild/CmdRun/Script/cabal.project +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRun/Script/cabal.project @@ -1 +1 @@ -packages: . \ No newline at end of file +packages: . diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRun/ScriptLiterate/cabal.project b/cabal-testsuite/PackageTests/NewBuild/CmdRun/ScriptLiterate/cabal.project index 5356e76f67c..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/NewBuild/CmdRun/ScriptLiterate/cabal.project +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRun/ScriptLiterate/cabal.project @@ -1 +1 @@ -packages: . \ No newline at end of file +packages: . diff --git a/cabal-testsuite/PackageTests/NewBuild/CmdRun/Terminate/.gitignore b/cabal-testsuite/PackageTests/NewBuild/CmdRun/Terminate/.gitignore new file mode 100644 index 00000000000..5ddbf722b62 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewBuild/CmdRun/Terminate/.gitignore @@ -0,0 +1 @@ +exe.run diff --git a/cabal-testsuite/PackageTests/NewBuild/MonitorCabalFiles/cabal.test.hs b/cabal-testsuite/PackageTests/NewBuild/MonitorCabalFiles/cabal.test.hs index ad2600d6862..f25f5bcf21c 100644 --- a/cabal-testsuite/PackageTests/NewBuild/MonitorCabalFiles/cabal.test.hs +++ b/cabal-testsuite/PackageTests/NewBuild/MonitorCabalFiles/cabal.test.hs @@ -1,6 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ do - withSourceCopy . withDelay $ do +main = cabalTest $ withDelay $ do copySourceFileTo "q/q-broken.cabal.in" "q/q.cabal" fails $ cabal "v2-build" ["q"] delay diff --git a/cabal-testsuite/PackageTests/NewBuild/T5164/setup-lib/setup-lib.cabal b/cabal-testsuite/PackageTests/NewBuild/T5164/setup-lib/setup-lib.cabal index 8f0faefa08c..7c6b32cb8ee 100644 --- a/cabal-testsuite/PackageTests/NewBuild/T5164/setup-lib/setup-lib.cabal +++ b/cabal-testsuite/PackageTests/NewBuild/T5164/setup-lib/setup-lib.cabal @@ -1,7 +1,7 @@ +cabal-version: 3.12 name: setup-lib version: 1.0 build-type: Simple -cabal-version: >= 1.10 data-files: example.txt library diff --git a/cabal-testsuite/PackageTests/NewConfigure/ConfigFile/cabal.test.hs b/cabal-testsuite/PackageTests/NewConfigure/ConfigFile/cabal.test.hs index bc0a574738c..1e10c0fc284 100644 --- a/cabal-testsuite/PackageTests/NewConfigure/ConfigFile/cabal.test.hs +++ b/cabal-testsuite/PackageTests/NewConfigure/ConfigFile/cabal.test.hs @@ -2,7 +2,7 @@ import Test.Cabal.Prelude -- Test that 'cabal v2-configure' generates the config file appropriately main = withShorterPathForNewBuildStore $ \storeDir -> - cabalTest . withSourceCopy $ do + cabalTest $ do cwd <- fmap testCurrentDir getTestEnv let configFile = cwd "cabal.project.local" diff --git a/cabal-testsuite/PackageTests/NewConfigure/LocalConfigOverwrite/cabal.test.hs b/cabal-testsuite/PackageTests/NewConfigure/LocalConfigOverwrite/cabal.test.hs index ebb8c3d2f72..5ae99640441 100644 --- a/cabal-testsuite/PackageTests/NewConfigure/LocalConfigOverwrite/cabal.test.hs +++ b/cabal-testsuite/PackageTests/NewConfigure/LocalConfigOverwrite/cabal.test.hs @@ -1,7 +1,6 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopy $ do +main = cabalTest $ do cabal' "v2-configure" [] >>= assertOutputContains "backing it up to 'cabal.project.local~'" diff --git a/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.out b/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.out index 24724d62291..ff47b1dd0cc 100644 --- a/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.out +++ b/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.out @@ -10,7 +10,7 @@ In order, the following would be built: - my-local-package-1.0 (lib) (first run) # cabal v2-freeze Resolving dependencies... -Wrote freeze file: /new_freeze.dist/source/cabal.project.freeze +Wrote freeze file: /cabal.project.freeze # cabal v2-build Resolving dependencies... Build profile: -w ghc- -O1 diff --git a/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.test.hs b/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.test.hs index ff35d59f53e..ca1b4c180ee 100644 --- a/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.test.hs +++ b/cabal-testsuite/PackageTests/NewFreeze/BuildTools/new_freeze.test.hs @@ -9,7 +9,7 @@ import System.Directory -- is one local package, which requires >= 2, and a library dependency of the -- local package, which requires < 2, so cabal should pick versions 1.0 and 3.0 -- of the build tool when there are no constraints. -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do withRepo "repo" $ do cabal' "v2-build" ["--dry-run"] >>= assertUsesLatestBuildTool diff --git a/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.out b/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.out index fdaca207030..d0cc7e4ee0c 100644 --- a/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.out +++ b/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.out @@ -9,7 +9,7 @@ In order, the following would be built: - my-local-package-1.0 (lib) (first run) # cabal v2-freeze Resolving dependencies... -Wrote freeze file: /new_freeze.dist/source/cabal.project.freeze +Wrote freeze file: /cabal.project.freeze # cabal v2-build Resolving dependencies... Build profile: -w ghc- -O1 diff --git a/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.test.hs b/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.test.hs index 3aef354e222..f05f941b86c 100644 --- a/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.test.hs +++ b/cabal-testsuite/PackageTests/NewFreeze/Flags/new_freeze.test.hs @@ -6,7 +6,7 @@ import System.Directory -- Test that 'cabal v2-freeze' freezes flag choices. my-local-package depends -- on my-library-dep. my-library-dep has a flag, my-flag, which defaults to -- true. -main = cabalTest $ withSourceCopy $ +main = cabalTest $ withRepo "repo" $ do cabal' "v2-build" ["--dry-run"] >>= assertDependencyFlagChoice True diff --git a/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.out b/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.out index e768c91b531..36278f47542 100644 --- a/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.out +++ b/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.out @@ -12,7 +12,7 @@ Freeze file not written due to flag(s) Freeze file not written due to flag(s) # cabal v2-freeze Resolving dependencies... -Wrote freeze file: /new_freeze.dist/source/cabal.project.freeze +Wrote freeze file: /cabal.project.freeze # cabal v2-build Resolving dependencies... Build profile: -w ghc- -O1 @@ -27,7 +27,7 @@ Configuring executable 'my-exe' for my-local-package-1.0... Preprocessing executable 'my-exe' for my-local-package-1.0... Building executable 'my-exe' for my-local-package-1.0... # cabal v2-freeze -Wrote freeze file: /new_freeze.dist/source/cabal.project.freeze +Wrote freeze file: /cabal.project.freeze # cabal v2-build Resolving dependencies... Build profile: -w ghc- -O1 @@ -35,4 +35,4 @@ In order, the following would be built: - my-library-dep-2.0 (lib) (requires build) - my-local-package-1.0 (exe:my-exe) (configuration changed) # cabal v2-freeze -Wrote freeze file: /new_freeze.dist/source/cabal.project.freeze +Wrote freeze file: /cabal.project.freeze diff --git a/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.test.hs b/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.test.hs index 912649bba8c..b59c0ee7f31 100644 --- a/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.test.hs +++ b/cabal-testsuite/PackageTests/NewFreeze/FreezeFile/new_freeze.test.hs @@ -6,7 +6,7 @@ import System.Directory -- Test for 'cabal v2-freeze' with only a single library dependency. -- my-local-package depends on my-library-dep, which has versions 1.0 and 2.0. main = withShorterPathForNewBuildStore $ \storeDir -> - cabalTest $ withSourceCopy $ + cabalTest $ withRepo "repo" $ do cwd <- fmap testCurrentDir getTestEnv let freezeFile = cwd "cabal.project.freeze" diff --git a/cabal-testsuite/PackageTests/NewHaddock/Fails/Example.hs b/cabal-testsuite/PackageTests/NewHaddock/Fails/Example.hs index 76287b43f72..c29012fc826 100644 --- a/cabal-testsuite/PackageTests/NewHaddock/Fails/Example.hs +++ b/cabal-testsuite/PackageTests/NewHaddock/Fails/Example.hs @@ -1,6 +1,6 @@ -module Example where - -import Prelude - -example :: Int -example = False +module Example where + +import Prelude + +example :: Int +example = False diff --git a/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.project b/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.project index 5356e76f67c..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.project +++ b/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.project @@ -1 +1 @@ -packages: . \ No newline at end of file +packages: . diff --git a/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputCmd/cabal.test.hs b/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputCmd/cabal.test.hs index 47e4c5c38e8..1bfe939dab9 100644 --- a/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputCmd/cabal.test.hs +++ b/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputCmd/cabal.test.hs @@ -4,7 +4,7 @@ import Test.Cabal.Prelude -- Test that `cabal haddock --haddock-output-dir` works from the command line. main = cabalTest . withRepo "repo" $ do - testDir <- testSourceDir <$> getTestEnv + testDir <- testCurrentDir <$> getTestEnv let docsDir = testDir "docs" liftIO (removePathForcibly docsDir) r <- cabal' "haddock" ["--haddock-output-dir=docs", "A"] diff --git a/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputConfig/cabal.test.hs b/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputConfig/cabal.test.hs index cd57928ff81..ba3a957ef60 100644 --- a/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputConfig/cabal.test.hs +++ b/cabal-testsuite/PackageTests/NewHaddock/HaddockOutput/HaddockOutputConfig/cabal.test.hs @@ -4,7 +4,7 @@ import Test.Cabal.Prelude -- Test that `cabal haddock --haddock-output-dir` works from the config file. main = cabalTest . withRepo "repo" $ do - testDir <- testSourceDir <$> getTestEnv + testDir <- testCurrentDir <$> getTestEnv let docsDir = testDir "docs" liftIO (removePathForcibly docsDir) r <- cabal' "haddock" ["A"] diff --git a/cabal-testsuite/PackageTests/NewSdist/DeterministicTrivial/cabal.project b/cabal-testsuite/PackageTests/NewSdist/DeterministicTrivial/cabal.project index 5356e76f67c..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/NewSdist/DeterministicTrivial/cabal.project +++ b/cabal-testsuite/PackageTests/NewSdist/DeterministicTrivial/cabal.project @@ -1 +1 @@ -packages: . \ No newline at end of file +packages: . diff --git a/cabal-testsuite/PackageTests/NewSdist/Globbing/cabal.test.hs b/cabal-testsuite/PackageTests/NewSdist/Globbing/cabal.test.hs index 832177dc84f..c6fe551841b 100644 --- a/cabal-testsuite/PackageTests/NewSdist/Globbing/cabal.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/Globbing/cabal.test.hs @@ -1,4 +1,4 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cabal "v2-sdist" ["a", "--list-only"] diff --git a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/Main.hs b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/Main.hs index ed19e6004cc..8e366f26a96 100644 --- a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/Main.hs +++ b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/Main.hs @@ -1,4 +1,4 @@ -module Main (main) where - -main :: IO () -main = putStrLn "Hello, World!" +module Main (main) where + +main :: IO () +main = putStrLn "Hello, World!" diff --git a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/cabal.project b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/cabal.project index f95e96bf5b5..e6fdbadb439 100644 --- a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/cabal.project +++ b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/cabal.project @@ -1 +1 @@ -packages: . +packages: . diff --git a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.cabal b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.cabal index 4bc31217b98..3ac52d11163 100644 --- a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.cabal +++ b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.cabal @@ -1,9 +1,9 @@ -cabal-version: 2.2 -name: many-data-files -version: 0 - -data-files: data/*.txt - -executable dummy - default-language: Haskell2010 - main-is: Main.hs +cabal-version: 2.2 +name: many-data-files +version: 0 + +data-files: data/*.txt + +executable dummy + default-language: Haskell2010 + main-is: Main.hs diff --git a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.out b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.out index d1d7884f33a..926e5a2560e 100644 --- a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.out +++ b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.out @@ -1,2 +1,2 @@ -# cabal v2-sdist -Wrote tarball sdist to /many-data-files.dist/source/dist-newstyle/sdist/many-data-files-0.tar.gz +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/many-data-files-0.tar.gz diff --git a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.test.hs b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.test.hs index 2db0070c4ed..36192da93ec 100644 --- a/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/ManyDataFiles/many-data-files.test.hs @@ -1,17 +1,17 @@ -import Test.Cabal.Prelude - -import Control.Applicative ((<$>)) -import System.Directory ( createDirectoryIfMissing ) -import qualified Data.ByteString.Char8 as BS - -main = cabalTest . withSourceCopy $ do - limit <- getOpenFilesLimit - cwd <- testCurrentDir <$> getTestEnv - - case limit of - Just n -> do - liftIO $ createDirectoryIfMissing False (cwd "data") - forM_ [1 .. n + 100] $ \i -> - liftIO $ BS.writeFile (cwd "data" ("data-file-" ++ show i) <.> "txt") (BS.pack "a data file\n") - cabal "v2-sdist" ["many-data-files"] - Nothing -> skip "no open file limit" +import Test.Cabal.Prelude + +import Control.Applicative ((<$>)) +import System.Directory ( createDirectoryIfMissing ) +import qualified Data.ByteString.Char8 as BS + +main = cabalTest $ do + limit <- getOpenFilesLimit + cwd <- testCurrentDir <$> getTestEnv + + case limit of + Just n -> do + liftIO $ createDirectoryIfMissing False (cwd "data") + forM_ [1 .. n + 100] $ \i -> + liftIO $ BS.writeFile (cwd "data" ("data-file-" ++ show i) <.> "txt") (BS.pack "a data file\n") + cabal "v2-sdist" ["many-data-files"] + Nothing -> skip "no open file limit" diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.out b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.out index 005c24ef822..abcbfc25590 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.out +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.out @@ -1,3 +1,3 @@ # cabal v2-sdist -Wrote tarball sdist to /all-output-dir.dist/source/archives/a-0.1.tar.gz -Wrote tarball sdist to /all-output-dir.dist/source/archives/b-0.1.tar.gz +Wrote tarball sdist to /archives/a-0.1.tar.gz +Wrote tarball sdist to /archives/b-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.test.hs index 97a48c56892..5ebe61befbe 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-output-dir.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude import System.Directory -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv liftIO $ createDirectoryIfMissing False $ cwd "archives" cabal "v2-sdist" ["all", "--output-dir", "archives"] diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-test-sute.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-test-sute.test.hs index 92bfd9522f4..736e326e1dd 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-test-sute.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all-test-sute.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv fails $ cabal "v2-sdist" ["all:tests"] shouldNotExist $ cwd "dist-newstyle/sdist/a-0.1.tar.gz" diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.out b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.out index 0bcab0b2531..e370f410fe4 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.out +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.out @@ -1,3 +1,3 @@ # cabal v2-sdist -Wrote tarball sdist to /all.dist/source/dist-newstyle/sdist/a-0.1.tar.gz -Wrote tarball sdist to /all.dist/source/dist-newstyle/sdist/b-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/a-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/b-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.test.hs index d5b8c4420d9..4423095bb87 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/all.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv cabal "v2-sdist" ["all"] shouldExist $ cwd "dist-newstyle/sdist/a-0.1.tar.gz" diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.out b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.out index c6e7a37818a..64b8452177f 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.out +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.out @@ -1,3 +1,3 @@ # cabal v2-sdist -Wrote source list to /list-sources-output-dir.dist/source/lists/a-0.1.list -Wrote source list to /list-sources-output-dir.dist/source/lists/b-0.1.list +Wrote source list to /lists/a-0.1.list +Wrote source list to /lists/b-0.1.list diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.test.hs index 3f119909e0f..55af8b872cc 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/list-sources-output-dir.test.hs @@ -1,7 +1,7 @@ import Test.Cabal.Prelude import System.Directory import System.FilePath -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv liftIO $ createDirectoryIfMissing False $ cwd "lists" cabal "v2-sdist" ["all", "--list-only", "--output-dir", "lists"] diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-archive-to-stdout.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-archive-to-stdout.test.hs index fdc3db695b2..c9d20e9e70f 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-archive-to-stdout.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-archive-to-stdout.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv fails $ cabal "v2-sdist" ["a", "b", "--output-dir", "-"] shouldNotExist $ cwd "dist-newstyle/sdist/a-0.1.tar.gz" diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-list-sources.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-list-sources.test.hs index 2686d035980..d8a0237f399 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-list-sources.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-list-sources.test.hs @@ -1,4 +1,4 @@ import Test.Cabal.Prelude import Data.List -main = cabalTest $ withSourceCopy $ +main = cabalTest $ cabal "v2-sdist" ["a", "b", "--list-only"] diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.out b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.out index 567f028b032..e370f410fe4 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.out +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.out @@ -1,3 +1,3 @@ # cabal v2-sdist -Wrote tarball sdist to /multi-target.dist/source/dist-newstyle/sdist/a-0.1.tar.gz -Wrote tarball sdist to /multi-target.dist/source/dist-newstyle/sdist/b-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/a-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/b-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.test.hs index 92b50dd5b52..517c93e64e7 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/multi-target.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv cabal "v2-sdist" ["a", "b"] shouldExist $ cwd "dist-newstyle/sdist/a-0.1.tar.gz" diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/target-remote-package.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/target-remote-package.test.hs index 45639a2aa23..324781b1171 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/target-remote-package.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/target-remote-package.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv fails $ cabal "v2-sdist" ["a", "base"] shouldNotExist $ cwd "dist-newstyle/sdist/a-0.1.tar.gz" diff --git a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/valid-and-test-suite.test.hs b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/valid-and-test-suite.test.hs index 0e2c15193c5..4950fde708a 100644 --- a/cabal-testsuite/PackageTests/NewSdist/MultiTarget/valid-and-test-suite.test.hs +++ b/cabal-testsuite/PackageTests/NewSdist/MultiTarget/valid-and-test-suite.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ withSourceCopy $ do +main = cabalTest $ do cwd <- fmap testCurrentDir getTestEnv fails $ cabal "v2-sdist" ["a", "b", "a-tests"] shouldNotExist $ cwd "dist-newstyle/sdist/a-0.1.tar.gz" diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/.gitignore b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/.gitignore new file mode 100644 index 00000000000..6a79f9c97c3 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/.gitignore @@ -0,0 +1,5 @@ +# Ignore cabal.out and cabal.out'' file, generated by: +# shell "cp" ["cabal.out.in", "cabal.out"] +# shell "sed" ["-i''", "-e", "s/REPLACEME/" <> output <> "/g", "cabal.out"] +cabal.out +cabal.out'' diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.out.in b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.out.in new file mode 100644 index 00000000000..969b189c7b8 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.out.in @@ -0,0 +1,13 @@ +# cabal build +Error: [Cabal-7159] +Latest known index-state for 'repository.localhost' (REPLACEME) is older than the requested index-state (4000-01-01T00:00:00Z). +Run 'cabal update' or set the index-state to a value at or before REPLACEME. +# cabal build +Warning: There is no index-state for 'repository.localhost' exactly at the requested timestamp (2023-01-01T00:00:00Z). Also, there are no index-states before the one requested, so the repository 'repository.localhost' will be empty. +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: fake-pkg-1.0 (user goal) +[__1] unknown package: pkg (dependency of fake-pkg) +[__1] fail (backjumping, conflict set: fake-pkg, pkg) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: fake-pkg (2), pkg (1) diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.project b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.project new file mode 100644 index 00000000000..a6de7296b36 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.project @@ -0,0 +1 @@ +packages: fake-pkg diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.test.hs b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.test.hs new file mode 100644 index 00000000000..8d22aed3494 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/cabal.test.hs @@ -0,0 +1,22 @@ +import Test.Cabal.Prelude +import Data.List (isPrefixOf) + +main = cabalTest $ withProjectFile "cabal.project" $ withRemoteRepo "repo" $ do + + skip "Flaky test failing in `curl`, see #9530" + + output <- last + . words + . head + . filter ("Index cache updated to index-state " `isPrefixOf`) + . lines + . resultOutput + <$> recordMode DoNotRecord (cabal' "update" []) + -- update golden output with actual timestamp + shell "cp" ["cabal.out.in", "cabal.out"] + shell "sed" ["-i''", "-e", "s/REPLACEME/" <> output <> "/g", "cabal.out"] + -- This shall fail with an error message as specified in `cabal.out` + fails $ cabal "build" ["--index-state=4000-01-01T00:00:00Z", "fake-pkg"] + -- This shall fail by not finding the package, what indicates that it + -- accepted an older index-state. + fails $ cabal "build" ["--index-state=2023-01-01T00:00:00Z", "fake-pkg"] diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/fake-pkg/Main.hs b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/fake-pkg/Main.hs new file mode 100644 index 00000000000..e5f1c882aeb --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/fake-pkg/Main.hs @@ -0,0 +1,3 @@ +module Main where + +main = print "hello" diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/fake-pkg/fake-pkg.cabal b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/fake-pkg/fake-pkg.cabal new file mode 100644 index 00000000000..813542d87f3 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/fake-pkg/fake-pkg.cabal @@ -0,0 +1,8 @@ +version: 1.0 +name: fake-pkg +build-type: Simple +cabal-version: >= 1.2 + +executable my-exe + main-is: Main.hs + build-depends: base, pkg diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/repo/pkg-1.0/Foo.hs b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/repo/pkg-1.0/Foo.hs new file mode 100644 index 00000000000..9bb6374ab6c --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/repo/pkg-1.0/Foo.hs @@ -0,0 +1,3 @@ +module Foo (someFunc) where + +someFunc = "hello" diff --git a/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/repo/pkg-1.0/pkg.cabal b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/repo/pkg-1.0/pkg.cabal new file mode 100644 index 00000000000..b046359bf55 --- /dev/null +++ b/cabal-testsuite/PackageTests/NewUpdate/RejectFutureIndexStates/repo/pkg-1.0/pkg.cabal @@ -0,0 +1,8 @@ +name: pkg +version: 1.0 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: Foo + build-depends: base diff --git a/cabal-testsuite/PackageTests/NewUpdate/UpdateIndexState/update-index-state.test.hs b/cabal-testsuite/PackageTests/NewUpdate/UpdateIndexState/update-index-state.test.hs index 2be563c6bec..24b1e7b5dd6 100644 --- a/cabal-testsuite/PackageTests/NewUpdate/UpdateIndexState/update-index-state.test.hs +++ b/cabal-testsuite/PackageTests/NewUpdate/UpdateIndexState/update-index-state.test.hs @@ -1,6 +1,9 @@ import Test.Cabal.Prelude main = cabalTest $ withRemoteRepo "repo" $ do + + skip "Flaky test failing in `curl`, see #9530" + -- The _first_ update call causes a warning about missing mirrors, the warning -- is platform-dependent and it's not part of the test expectations, so we -- check the output manually. diff --git a/cabal-testsuite/PackageTests/PackageDB/cabal-fail-no-packagedbs.test.hs b/cabal-testsuite/PackageTests/PackageDB/cabal-fail-no-packagedbs.test.hs index 1cc0f54d159..5335d960ab8 100644 --- a/cabal-testsuite/PackageTests/PackageDB/cabal-fail-no-packagedbs.test.hs +++ b/cabal-testsuite/PackageTests/PackageDB/cabal-fail-no-packagedbs.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = cabalTest $ do - withPackageDb $ do + noCabalPackageDb . withPackageDb $ do withDirectory "p-no-package-dbs" $ do res <- fails $ cabal' "v2-build" [] assertOutputContains "No package databases have been specified." res diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/cabal.test.hs b/cabal-testsuite/PackageTests/PackageDB/t9678/cabal.test.hs new file mode 100644 index 00000000000..5cb73595452 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/cabal.test.hs @@ -0,0 +1,11 @@ +import Test.Cabal.Prelude +main = cabalTest $ do + recordMode DoNotRecord $ withRepo "repo" $ withPackageDb $ do + withDirectory "p1" $ + setup_install [] + + env <- getTestEnv + let pkgDbPath = testPackageDbDir env + + withDirectory "p2" $ do + void $ cabal' "v2-build" ["--package-db=" ++ pkgDbPath] diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p1/CHANGELOG.md b/cabal-testsuite/PackageTests/PackageDB/t9678/p1/CHANGELOG.md new file mode 100644 index 00000000000..877394c57bd --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p1/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for p1 + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p1/p1.cabal b/cabal-testsuite/PackageTests/PackageDB/t9678/p1/p1.cabal new file mode 100644 index 00000000000..d9fa27e0b88 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p1/p1.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: p1 +version: 0.1.0.0 +license: NONE +author: matthewtpickering@gmail.com +maintainer: Matthew Pickering +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +library + import: warnings + exposed-modules: MyLib + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p1/src/MyLib.hs b/cabal-testsuite/PackageTests/PackageDB/t9678/p1/src/MyLib.hs new file mode 100644 index 00000000000..e657c4403f6 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p1/src/MyLib.hs @@ -0,0 +1,4 @@ +module MyLib (someFunc) where + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p2/CHANGELOG.md b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/CHANGELOG.md new file mode 100644 index 00000000000..e603f1bd4b2 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for p2 + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p2/cabal.project b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p2/p2.cabal b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/p2.cabal new file mode 100644 index 00000000000..c466c6ef99b --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/p2.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: p2 +version: 0.1.0.0 +license: NONE +author: matthewtpickering@gmail.com +maintainer: Matthew Pickering +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +library + import: warnings + exposed-modules: MyLib + build-depends: base, p1, p3 + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/p2/src/MyLib.hs b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/src/MyLib.hs new file mode 100644 index 00000000000..e657c4403f6 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/p2/src/MyLib.hs @@ -0,0 +1,4 @@ +module MyLib (someFunc) where + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/CHANGELOG.md b/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/CHANGELOG.md new file mode 100644 index 00000000000..877394c57bd --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for p1 + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/p3.cabal b/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/p3.cabal new file mode 100644 index 00000000000..86bbdb40477 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/p3.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: p3 +version: 0.1.0.0 +license: NONE +author: matthewtpickering@gmail.com +maintainer: Matthew Pickering +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +library + import: warnings + exposed-modules: MyLib + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/src/MyLib.hs b/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/src/MyLib.hs new file mode 100644 index 00000000000..e657c4403f6 --- /dev/null +++ b/cabal-testsuite/PackageTests/PackageDB/t9678/repo/p3-0.1.0.0/src/MyLib.hs @@ -0,0 +1,4 @@ +module MyLib (someFunc) where + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/cabal-testsuite/PackageTests/PackageInfoModule/Executable/my.cabal b/cabal-testsuite/PackageTests/PackageInfoModule/Executable/my.cabal index f04d2696c6c..a2aa9da5270 100644 --- a/cabal-testsuite/PackageTests/PackageInfoModule/Executable/my.cabal +++ b/cabal-testsuite/PackageTests/PackageInfoModule/Executable/my.cabal @@ -1,11 +1,11 @@ +Cabal-version: 3.12 name: PackageInfoModule version: 0.1 -license: BSD3 +license: BSD-3-Clause author: Gautier DI FOLCO stability: stable category: PackageTests build-type: Simple -Cabal-version: >= 1.2 description: Check that the generated package info module compiles. diff --git a/cabal-testsuite/PackageTests/PackageInfoModule/ImportQualifiedPost/my.cabal b/cabal-testsuite/PackageTests/PackageInfoModule/ImportQualifiedPost/my.cabal index 7704aaa15b8..c0020ed46ac 100644 --- a/cabal-testsuite/PackageTests/PackageInfoModule/ImportQualifiedPost/my.cabal +++ b/cabal-testsuite/PackageTests/PackageInfoModule/ImportQualifiedPost/my.cabal @@ -1,10 +1,10 @@ +Cabal-version: 3.12 name: PackageInfoModule version: 0.1 -license: BSD3 +license: BSD-3-Clause author: Gautier DI FOLCO category: PackageTests build-type: Simple -Cabal-version: >= 1.2 description: Check that the generated package info module compiles. diff --git a/cabal-testsuite/PackageTests/PackageInfoModule/Library/my.cabal b/cabal-testsuite/PackageTests/PackageInfoModule/Library/my.cabal index b356e8929ea..bee4b863949 100644 --- a/cabal-testsuite/PackageTests/PackageInfoModule/Library/my.cabal +++ b/cabal-testsuite/PackageTests/PackageInfoModule/Library/my.cabal @@ -1,4 +1,4 @@ -Cabal-version: 2.2 +Cabal-version: 3.12 name: PackageInfoModule version: 0.1 license: BSD-3-Clause diff --git a/cabal-testsuite/PackageTests/Path/All/cabal.out b/cabal-testsuite/PackageTests/Path/All/cabal.out new file mode 100644 index 00000000000..55d8b94bc3a --- /dev/null +++ b/cabal-testsuite/PackageTests/Path/All/cabal.out @@ -0,0 +1,6 @@ +# cabal path +cache-dir: /cabal.dist/home/.cabal/packages +logs-dir: /cabal.dist/home/.cabal/logs +store-dir: /cabal.dist/home/.cabal/store +config-file: /cabal.dist/home/.cabal/config +installdir: /cabal.dist/home/.cabal/bin diff --git a/cabal-testsuite/PackageTests/Path/All/cabal.test.hs b/cabal-testsuite/PackageTests/Path/All/cabal.test.hs new file mode 100644 index 00000000000..b8157a83ee8 --- /dev/null +++ b/cabal-testsuite/PackageTests/Path/All/cabal.test.hs @@ -0,0 +1,3 @@ +import Test.Cabal.Prelude + +main = cabalTest . void $ cabal "path" [] diff --git a/cabal-testsuite/PackageTests/Path/Single/cabal.out b/cabal-testsuite/PackageTests/Path/Single/cabal.out new file mode 100644 index 00000000000..1ae82037846 --- /dev/null +++ b/cabal-testsuite/PackageTests/Path/Single/cabal.out @@ -0,0 +1,2 @@ +# cabal path +/cabal.dist/home/.cabal/bin diff --git a/cabal-testsuite/PackageTests/Path/Single/cabal.test.hs b/cabal-testsuite/PackageTests/Path/Single/cabal.test.hs new file mode 100644 index 00000000000..8eac59024f3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Path/Single/cabal.test.hs @@ -0,0 +1,3 @@ +import Test.Cabal.Prelude + +main = cabalTest . void $ cabal "path" ["--installdir"] diff --git a/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/my.cabal b/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/my.cabal index 04337c3f3f7..e1bcba8ba4f 100644 --- a/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/my.cabal +++ b/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/my.cabal @@ -1,11 +1,11 @@ +Cabal-version: 3.12 name: PathsModule version: 0.1 -license: BSD3 +license: BSD-3-Clause author: Johan Tibell stability: stable category: PackageTests build-type: Simple -Cabal-version: >= 1.2 description: Check that the generated paths module compiles. diff --git a/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/setup.test.hs b/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/setup.test.hs index 76a4db87db3..ea88c7f9e41 100644 --- a/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/setup.test.hs +++ b/cabal-testsuite/PackageTests/PathsModule/Executable-Relocatable/setup.test.hs @@ -4,4 +4,4 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipIfWindows skipUnlessGhcVersion ">= 8.0" - setup_build ["--enable-relocatable"] + withPackageDb $ setup_build ["--enable-relocatable"] diff --git a/cabal-testsuite/PackageTests/PathsModule/Executable/my.cabal b/cabal-testsuite/PackageTests/PathsModule/Executable/my.cabal index 04337c3f3f7..e1bcba8ba4f 100644 --- a/cabal-testsuite/PackageTests/PathsModule/Executable/my.cabal +++ b/cabal-testsuite/PackageTests/PathsModule/Executable/my.cabal @@ -1,11 +1,11 @@ +Cabal-version: 3.12 name: PathsModule version: 0.1 -license: BSD3 +license: BSD-3-Clause author: Johan Tibell stability: stable category: PackageTests build-type: Simple -Cabal-version: >= 1.2 description: Check that the generated paths module compiles. diff --git a/cabal-testsuite/PackageTests/PathsModule/ImportQualifiedPost/my.cabal b/cabal-testsuite/PackageTests/PathsModule/ImportQualifiedPost/my.cabal index faacd4f1ff0..a5573b4c6e6 100644 --- a/cabal-testsuite/PackageTests/PathsModule/ImportQualifiedPost/my.cabal +++ b/cabal-testsuite/PackageTests/PathsModule/ImportQualifiedPost/my.cabal @@ -1,10 +1,10 @@ +Cabal-version: 3.12 name: PathsModule version: 0.1 -license: BSD3 +license: BSD-3-Clause author: Martijn Bastiaan category: PackageTests build-type: Simple -Cabal-version: >= 1.2 description: Check that the generated paths module compiles. diff --git a/cabal-testsuite/PackageTests/PathsModule/Library/my.cabal b/cabal-testsuite/PackageTests/PathsModule/Library/my.cabal index 47ee1f942d1..8e1d789d101 100644 --- a/cabal-testsuite/PackageTests/PathsModule/Library/my.cabal +++ b/cabal-testsuite/PackageTests/PathsModule/Library/my.cabal @@ -1,4 +1,4 @@ -Cabal-version: 2.2 +Cabal-version: 3.12 name: PathsModule version: 0.1 license: BSD-3-Clause diff --git a/cabal-testsuite/PackageTests/PathsModule/MissingSafeHaskellMode/my.cabal b/cabal-testsuite/PackageTests/PathsModule/MissingSafeHaskellMode/my.cabal index 44140ee9019..3851d160491 100644 --- a/cabal-testsuite/PackageTests/PathsModule/MissingSafeHaskellMode/my.cabal +++ b/cabal-testsuite/PackageTests/PathsModule/MissingSafeHaskellMode/my.cabal @@ -1,4 +1,4 @@ -cabal-version: 2.2 +cabal-version: 3.12 name: PathsModule version: 0.1 license: BSD-3-Clause diff --git a/cabal-testsuite/PackageTests/PkgConfigParse/MyLibrary.hs b/cabal-testsuite/PackageTests/PkgConfigParse/MyLibrary.hs new file mode 100644 index 00000000000..a51c414bcd2 --- /dev/null +++ b/cabal-testsuite/PackageTests/PkgConfigParse/MyLibrary.hs @@ -0,0 +1 @@ +module MyLibrary () where diff --git a/cabal-testsuite/PackageTests/PkgConfigParse/cabal.project b/cabal-testsuite/PackageTests/PkgConfigParse/cabal.project new file mode 100644 index 00000000000..0d7f076e888 --- /dev/null +++ b/cabal-testsuite/PackageTests/PkgConfigParse/cabal.project @@ -0,0 +1 @@ +packages: *.cabal diff --git a/cabal-testsuite/PackageTests/PkgConfigParse/my.cabal b/cabal-testsuite/PackageTests/PkgConfigParse/my.cabal new file mode 100644 index 00000000000..38b7020b8a1 --- /dev/null +++ b/cabal-testsuite/PackageTests/PkgConfigParse/my.cabal @@ -0,0 +1,19 @@ +name: PkgConfigParse +version: 0.1 +license: BSD3 +author: Tom Smeding +maintainer: Tom Smeding +synopsis: Pkg Config Parse +category: PackageTests +build-type: Simple +cabal-version: 2.0 + +description: + Check that Cabal does not crash when pkg-config outputs invalid Unicode. + +Library + pkgconfig-depends: vpl + default-language: Haskell2010 + build-depends: base <5.0 + exposed-modules: + MyLibrary diff --git a/cabal-testsuite/PackageTests/PkgConfigParse/pkg-config b/cabal-testsuite/PackageTests/PkgConfigParse/pkg-config new file mode 100755 index 00000000000..183d08e0a00 --- /dev/null +++ b/cabal-testsuite/PackageTests/PkgConfigParse/pkg-config @@ -0,0 +1,49 @@ +#!/bin/sh + +set -eu + +# ugly, but "good enough" for this test +# This will need to be updated whenever cabal invokes pkg-config +# in new ways +case "$*" in + '--version') + echo 2.1.0 # whatever + ;; + + '--variable pc_path pkg-config') + echo '.' + ;; + + '--list-all') + printf 'zlib zlib - zlib compression library\n' + # \256 = \xAE is the iso-8859-1 (latin-1) encoded version of U+00AE, + # i.e. the "registered sign": ® + # This resulted in problems, see #9608 + printf 'vpl Intel\256 Video Processing Library - Accelerated video decode, encode, and frame processing capabilities on Intel\256 GPUs\n' + # \360 = \xF0 is latin-1 for ð; this is orð, Icelandic for "word"/"words". + printf 'or\360 Icelandic characters\n' + ;; + + '--modversion '*) + shift # drop the --modversion + for arg; do + case "$arg" in + zlib) echo 1.3; ;; # whatever + vpl) echo 2.10; ;; # whatever + # No entry for orð here; let's not even try to match on that + *) + echo >&2 "Package $arg was not found in the pkg-config search path." + exit 1 + esac + done + ;; + + # Ignore some stuff we're not implementing + '--cflags '*) ;; + '--libs '*) ;; + + *) + echo >&2 "pkg-config: unrecognised arguments $* (this is an incomplete shim)" + exit 1 + ;; +esac diff --git a/cabal-testsuite/PackageTests/PkgConfigParse/setup.out b/cabal-testsuite/PackageTests/PkgConfigParse/setup.out new file mode 100644 index 00000000000..92fd8204a40 --- /dev/null +++ b/cabal-testsuite/PackageTests/PkgConfigParse/setup.out @@ -0,0 +1 @@ +# cabal v2-build diff --git a/cabal-testsuite/PackageTests/PkgConfigParse/setup.test.hs b/cabal-testsuite/PackageTests/PkgConfigParse/setup.test.hs new file mode 100644 index 00000000000..0f860ab637a --- /dev/null +++ b/cabal-testsuite/PackageTests/PkgConfigParse/setup.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +-- Test that invalid unicode in pkg-config output doesn't trip up cabal very much +main = cabalTest $ do + -- skipped on windows because using a script to dummy up an executable doesn't work the same. + skipIfWindows + cdir <- testCurrentDir `fmap` getTestEnv + res <- cabal' "v2-build" ["--extra-prog-path="++cdir, "-v2"] + assertOutputContains "Some pkg-config packages have names containing invalid unicode: or" res diff --git a/cabal-testsuite/PackageTests/ProfLate/cabal.out b/cabal-testsuite/PackageTests/ProfLate/cabal.out index e420dc33c70..e6a1d4ad751 100644 --- a/cabal-testsuite/PackageTests/ProfLate/cabal.out +++ b/cabal-testsuite/PackageTests/ProfLate/cabal.out @@ -1,2 +1,2 @@ -# cabal clean -# cabal build +# cabal clean +# cabal build diff --git a/cabal-testsuite/PackageTests/ProfLate/setup.cabal.out b/cabal-testsuite/PackageTests/ProfLate/setup.cabal.out index 2ec51f2ad09..12c885de8ff 100644 --- a/cabal-testsuite/PackageTests/ProfLate/setup.cabal.out +++ b/cabal-testsuite/PackageTests/ProfLate/setup.cabal.out @@ -1,5 +1,5 @@ -# Setup configure -Configuring profLate-0.1... -# Setup build -Preprocessing executable 'main' for profLate-0.1... -Building executable 'main' for profLate-0.1... +# Setup configure +Configuring profLate-0.1... +# Setup build +Preprocessing executable 'main' for profLate-0.1... +Building executable 'main' for profLate-0.1... diff --git a/cabal-testsuite/PackageTests/ProfLate/setup.out b/cabal-testsuite/PackageTests/ProfLate/setup.out index 2ec51f2ad09..12c885de8ff 100644 --- a/cabal-testsuite/PackageTests/ProfLate/setup.out +++ b/cabal-testsuite/PackageTests/ProfLate/setup.out @@ -1,5 +1,5 @@ -# Setup configure -Configuring profLate-0.1... -# Setup build -Preprocessing executable 'main' for profLate-0.1... -Building executable 'main' for profLate-0.1... +# Setup configure +Configuring profLate-0.1... +# Setup build +Preprocessing executable 'main' for profLate-0.1... +Building executable 'main' for profLate-0.1... diff --git a/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.out b/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.out new file mode 100644 index 00000000000..1278857b31d --- /dev/null +++ b/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.out @@ -0,0 +1,21 @@ +# cabal test +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - pkg-a-0.1 (lib) (first run) + - pkg-a-0.1 (test:testing) (first run) +Configuring library for pkg-a-0.1... +Warning: [no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +Preprocessing library for pkg-a-0.1... +Building library for pkg-a-0.1... +Configuring test suite 'testing' for pkg-a-0.1... +Warning: [no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +Preprocessing test suite 'testing' for pkg-a-0.1... +Building test suite 'testing' for pkg-a-0.1... +Running 1 test suites... +Test suite testing: RUNNING... +Test suite testing: PASS +Test suite logged to: /cabal.dist/work/./dist/build//ghc-/pkg-a-0.1/t/testing/test/pkg-a-0.1-testing.log +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/pkg-a-0.1/t/testing/hpc/vanilla/html/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/pkg-a-0.1/t/testing/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.project b/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.project new file mode 100644 index 00000000000..180d5248b39 --- /dev/null +++ b/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.project @@ -0,0 +1 @@ +packages: pkg-a diff --git a/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.test.hs b/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.test.hs new file mode 100644 index 00000000000..2ddbd37916f --- /dev/null +++ b/cabal-testsuite/PackageTests/Project/CoverageProject/cabal.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +main = cabalTest $ do + cabal "test" ["--enable-coverage", "testing"] diff --git a/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/Lib.hs b/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/Lib.hs new file mode 100644 index 00000000000..bc776e49d1d --- /dev/null +++ b/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/Lib.hs @@ -0,0 +1,3 @@ +module Lib where + +lib = "lib" diff --git a/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/pkg-a.cabal b/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/pkg-a.cabal new file mode 100644 index 00000000000..4a064d3389c --- /dev/null +++ b/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/pkg-a.cabal @@ -0,0 +1,23 @@ +cabal-version: 3.0 + +name: pkg-a +version: 0.1 +build-type: Simple +category: Test +maintainer: Joe +synopsis: Test input +description: Test input +license: BSD-3-Clause + +library + build-depends: base + default-language: Haskell2010 + exposed-modules: Lib + hs-source-dirs: . + +test-suite testing + type: exitcode-stdio-1.0 + build-depends: base, pkg-a + main-is: Main.hs + hs-source-dirs: test + diff --git a/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/test/Main.hs b/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/test/Main.hs new file mode 100644 index 00000000000..6ee3fb933aa --- /dev/null +++ b/cabal-testsuite/PackageTests/Project/CoverageProject/pkg-a/test/Main.hs @@ -0,0 +1,2 @@ +import Lib +main = putStrLn lib diff --git a/cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.out b/cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.project.out similarity index 100% rename from cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.out rename to cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.project.out diff --git a/cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.test.hs b/cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.project.test.hs similarity index 100% rename from cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.test.hs rename to cabal-testsuite/PackageTests/Project/WarnBuilddir/cabal.project.test.hs diff --git a/cabal-testsuite/PackageTests/ReexportedModules/p/p.cabal.fail-ambiguous b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-ambiguous/p.cabal similarity index 100% rename from cabal-testsuite/PackageTests/ReexportedModules/p/p.cabal.fail-ambiguous rename to cabal-testsuite/PackageTests/ReexportedModules/p-fail-ambiguous/p.cabal diff --git a/cabal-testsuite/PackageTests/ReexportedModules/p/p.cabal.fail-missing b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-missing/p.cabal similarity index 100% rename from cabal-testsuite/PackageTests/ReexportedModules/p/p.cabal.fail-missing rename to cabal-testsuite/PackageTests/ReexportedModules/p-fail-missing/p.cabal diff --git a/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/Private.hs b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/Private.hs new file mode 120000 index 00000000000..58b599a697a --- /dev/null +++ b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/Private.hs @@ -0,0 +1 @@ +../p/Private.hs \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/Public.hs b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/Public.hs new file mode 120000 index 00000000000..23baea4b6ad --- /dev/null +++ b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/Public.hs @@ -0,0 +1 @@ +../p/Public.hs \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/ReexportedModules/p/p.cabal.fail-other b/cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/p.cabal similarity index 100% rename from cabal-testsuite/PackageTests/ReexportedModules/p/p.cabal.fail-other rename to cabal-testsuite/PackageTests/ReexportedModules/p-fail-other/p.cabal diff --git a/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-ambiguous.test.hs b/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-ambiguous.test.hs index 232ca3b1395..c3e2d204564 100644 --- a/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-ambiguous.test.hs +++ b/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-ambiguous.test.hs @@ -4,6 +4,6 @@ main = setupAndCabalTest $ do withPackageDb $ do withDirectory "containers-dupe" $ setup_install [] - withDirectory "p" $ do - r <- fails $ setup' "configure" ["--cabal-file", "p.cabal.fail-ambiguous"] + withDirectory "p-fail-ambiguous" $ do + r <- fails $ setup' "configure" [] assertOutputContains "Data.Map" r diff --git a/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-missing.test.hs b/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-missing.test.hs index eb4d30f55e0..a7025e57ba7 100644 --- a/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-missing.test.hs +++ b/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-missing.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipUnlessGhcVersion ">= 7.9" - withDirectory "p" $ do - r <- fails $ setup' "configure" ["--cabal-file", "p.cabal.fail-missing"] + withDirectory "p-fail-missing" $ do + r <- fails $ setup' "configure" [] assertOutputContains "Missing" r diff --git a/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-other.test.hs b/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-other.test.hs index 4c46fe76646..b3014d1589d 100644 --- a/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-other.test.hs +++ b/cabal-testsuite/PackageTests/ReexportedModules/setup-fail-other.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipUnlessGhcVersion ">= 7.9" - withDirectory "p" $ do - r <- fails $ setup' "configure" ["--cabal-file", "p.cabal.fail-other"] + withDirectory "p-fail-other" $ do + r <- fails $ setup' "configure" [] assertOutputContains "Private" r diff --git a/cabal-testsuite/PackageTests/ReexportedModules/setup.test.hs b/cabal-testsuite/PackageTests/ReexportedModules/setup.test.hs index c3ae77e43f6..4c769bbc010 100644 --- a/cabal-testsuite/PackageTests/ReexportedModules/setup.test.hs +++ b/cabal-testsuite/PackageTests/ReexportedModules/setup.test.hs @@ -3,5 +3,5 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do skipUnlessGhcVersion ">= 7.9" withPackageDb $ do - withDirectory "p" $ setup_install ["--cabal-file", "p.cabal"] + withDirectory "p" $ setup_install [] withDirectory "q" $ setup_build [] diff --git a/cabal-testsuite/PackageTests/Regression/HadrianT634/setup.test.hs b/cabal-testsuite/PackageTests/Regression/HadrianT634/setup.test.hs index 0cf02afb4c4..5f2c37f33bc 100644 --- a/cabal-testsuite/PackageTests/Regression/HadrianT634/setup.test.hs +++ b/cabal-testsuite/PackageTests/Regression/HadrianT634/setup.test.hs @@ -1,4 +1,5 @@ import Test.Cabal.Prelude import Test.Cabal.Script main = setupTest $ - void $ setup'' "pkg" "configure" ["--cabal-file", "pkg/a.cabal"] + withDirectory "pkg" $ + void $ setup' "configure" [] diff --git a/cabal-testsuite/PackageTests/Regression/T3294/setup.test.hs b/cabal-testsuite/PackageTests/Regression/T3294/setup.test.hs index 810a4202b3a..b3ebe0c147c 100644 --- a/cabal-testsuite/PackageTests/Regression/T3294/setup.test.hs +++ b/cabal-testsuite/PackageTests/Regression/T3294/setup.test.hs @@ -3,7 +3,7 @@ import Control.Monad.IO.Class -- Test that executable recompilation works -- https://github.com/haskell/setup/issues/3294 main = setupAndCabalTest $ do - withSourceCopy . withDelay $ do + withDelay $ do writeSourceFile "Main.hs" "main = putStrLn \"aaa\"" setup "configure" [] setup "build" [] diff --git a/cabal-testsuite/PackageTests/Regression/T3847/setup.cabal.out b/cabal-testsuite/PackageTests/Regression/T3847/setup.cabal.out index df940b2d616..70fdaf03c9f 100644 --- a/cabal-testsuite/PackageTests/Regression/T3847/setup.cabal.out +++ b/cabal-testsuite/PackageTests/Regression/T3847/setup.cabal.out @@ -1,3 +1,3 @@ # Setup configure Configuring T3847-1.0... -Warning: Unknown extensions: ThisDoesNotExist +Warning: [unknown-extension] Unknown extensions: ThisDoesNotExist diff --git a/cabal-testsuite/PackageTests/Regression/T3847/setup.out b/cabal-testsuite/PackageTests/Regression/T3847/setup.out index df940b2d616..70fdaf03c9f 100644 --- a/cabal-testsuite/PackageTests/Regression/T3847/setup.out +++ b/cabal-testsuite/PackageTests/Regression/T3847/setup.out @@ -1,3 +1,3 @@ # Setup configure Configuring T3847-1.0... -Warning: Unknown extensions: ThisDoesNotExist +Warning: [unknown-extension] Unknown extensions: ThisDoesNotExist diff --git a/cabal-testsuite/PackageTests/Regression/T4202/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T4202/cabal.test.hs index f7943be335f..7b2aac05b27 100644 --- a/cabal-testsuite/PackageTests/Regression/T4202/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Regression/T4202/cabal.test.hs @@ -1,6 +1,5 @@ import Test.Cabal.Prelude -main = cabalTest $ - withSourceCopy . withDelay $ do +main = cabalTest $ withDelay $ do writeSourceFile ("p/P.hs") "module P where\np = \"AAA\"" cabal "v2-build" ["p","q"] delay diff --git a/cabal-testsuite/PackageTests/Regression/T4270/setup.test.hs b/cabal-testsuite/PackageTests/Regression/T4270/setup.test.hs index cf3d7afbdfb..258dcc21e16 100644 --- a/cabal-testsuite/PackageTests/Regression/T4270/setup.test.hs +++ b/cabal-testsuite/PackageTests/Regression/T4270/setup.test.hs @@ -3,9 +3,9 @@ import Test.Cabal.Prelude -- when linked dynamically -- See https://github.com/haskell/cabal/issues/4270 main = setupAndCabalTest $ do + skipIfAllCabalVersion "< 2.2" skipUnless "no shared libs" =<< hasSharedLibraries skipUnless "no shared Cabal" =<< hasCabalShared - skipUnless "no Cabal for GHC" =<< hasCabalForGhc ghc <- isGhcVersion "== 8.0.2" osx <- isOSX expectBrokenIf (osx && ghc) 8028 $ do diff --git a/cabal-testsuite/PackageTests/Regression/T4798/T4798.cabal b/cabal-testsuite/PackageTests/Regression/T4798/T4798.cabal new file mode 100644 index 00000000000..d51b290b569 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/T4798.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: T4798 +version: 0.1 + +library + exposed-modules: U2F, U2F.Types + ghc-options: -Wall + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 + +test-suite hspec-suite + type: exitcode-stdio-1.0 + main-is: test.hs + ghc-options: -Wall + hs-source-dirs: tests + default-language: Haskell2010 + build-depends: base, T4798 diff --git a/cabal-testsuite/PackageTests/Regression/T4798/cabal.out b/cabal-testsuite/PackageTests/Regression/T4798/cabal.out new file mode 100644 index 00000000000..05de54b124c --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/cabal.out @@ -0,0 +1,19 @@ +# cabal test +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - T4798-0.1 (lib) (first run) + - T4798-0.1 (test:hspec-suite) (first run) +Configuring library for T4798-0.1... +Preprocessing library for T4798-0.1... +Building library for T4798-0.1... +Configuring test suite 'hspec-suite' for T4798-0.1... +Preprocessing test suite 'hspec-suite' for T4798-0.1... +Building test suite 'hspec-suite' for T4798-0.1... +Running 1 test suites... +Test suite hspec-suite: RUNNING... +Test suite hspec-suite: PASS +Test suite logged to: /cabal.dist/work/./dist/build//ghc-/T4798-0.1/t/hspec-suite/test/T4798-0.1-hspec-suite.log +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/T4798-0.1/t/hspec-suite/hpc/vanilla/html/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/T4798-0.1/t/hspec-suite/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/Regression/T4798/cabal.project b/cabal-testsuite/PackageTests/Regression/T4798/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/Regression/T4798/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T4798/cabal.test.hs new file mode 100644 index 00000000000..0d594011fc2 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/cabal.test.hs @@ -0,0 +1,3 @@ +import Test.Cabal.Prelude +main = cabalTest $ cabal "test" ["--enable-coverage"] + diff --git a/cabal-testsuite/PackageTests/Regression/T4798/src/U2F.hs b/cabal-testsuite/PackageTests/Regression/T4798/src/U2F.hs new file mode 100644 index 00000000000..28d9b767995 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/src/U2F.hs @@ -0,0 +1,6 @@ +module U2F where + +import U2F.Types + +ourCurve :: String +ourCurve = show SEC_p256r1 diff --git a/cabal-testsuite/PackageTests/Regression/T4798/src/U2F/Types.hs b/cabal-testsuite/PackageTests/Regression/T4798/src/U2F/Types.hs new file mode 100644 index 00000000000..92accffdcff --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/src/U2F/Types.hs @@ -0,0 +1,3 @@ +module U2F.Types where + +data Curve = SEC_p256r1 deriving Show diff --git a/cabal-testsuite/PackageTests/Regression/T4798/tests/test.hs b/cabal-testsuite/PackageTests/Regression/T4798/tests/test.hs new file mode 100644 index 00000000000..e637e0cf66b --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T4798/tests/test.hs @@ -0,0 +1,6 @@ +import U2F +import U2F.Types + +main = print ourCurve +main :: IO () + diff --git a/cabal-testsuite/PackageTests/Regression/T4986/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T4986/cabal.test.hs index 8f7fe8fdfa1..b77b433a652 100644 --- a/cabal-testsuite/PackageTests/Regression/T4986/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Regression/T4986/cabal.test.hs @@ -1,4 +1,3 @@ import Test.Cabal.Prelude main = cabalTest $ - withSourceCopy $ cabal "v2-configure" [] diff --git a/cabal-testsuite/PackageTests/Regression/T5213/cabal.out b/cabal-testsuite/PackageTests/Regression/T5213/cabal.out index 38a68ce7e53..b6be4708e0d 100644 --- a/cabal-testsuite/PackageTests/Regression/T5213/cabal.out +++ b/cabal-testsuite/PackageTests/Regression/T5213/cabal.out @@ -15,6 +15,6 @@ Running 1 test suites... Test suite tests: RUNNING... Test suite tests: PASS Test suite logged to: /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/test/cabal-gh5213-0.1-tests.log -Test coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/hpc/vanilla/html/tests/hpc_index.html +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/hpc/vanilla/html/hpc_index.html 1 of 1 test suites (1 of 1 test cases) passed. -Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/hpc/vanilla/html/cabal-gh5213-0.1/hpc_index.html +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.out b/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.out index ddf36d02ef5..57cb186d882 100644 --- a/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.out +++ b/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.out @@ -14,6 +14,6 @@ Running 1 test suites... Test suite tests: RUNNING... Test suite tests: PASS Test suite logged to: /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/noopt/test/cabal-gh5213-0.1-tests.log -Test coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/noopt/hpc/vanilla/html/tests/hpc_index.html +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/noopt/hpc/vanilla/html/hpc_index.html 1 of 1 test suites (1 of 1 test cases) passed. -Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/noopt/hpc/vanilla/html/cabal-gh5213-0.1/hpc_index.html +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal-gh5213-0.1/t/tests/noopt/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.project b/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.project index ee157cb0f02..122a107db70 100644 --- a/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.project +++ b/cabal-testsuite/PackageTests/Regression/T5213ExeCoverage/cabal.project @@ -2,4 +2,4 @@ packages: . package cabal-gh5213 coverage: True - optimization: False \ No newline at end of file + optimization: False diff --git a/cabal-testsuite/PackageTests/Regression/T5318/sdist-list-sources.out b/cabal-testsuite/PackageTests/Regression/T5318/sdist-list-sources.out index 82b4544383a..faefc513fe8 100644 --- a/cabal-testsuite/PackageTests/Regression/T5318/sdist-list-sources.out +++ b/cabal-testsuite/PackageTests/Regression/T5318/sdist-list-sources.out @@ -1,2 +1,2 @@ # cabal v2-sdist -Wrote source list to /empty-data-dir-0.list +Wrote source list to /empty-data-dir-0.list diff --git a/cabal-testsuite/PackageTests/Regression/T5386/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T5386/cabal.test.hs index 565a3ce3474..e1a111cd4f3 100644 --- a/cabal-testsuite/PackageTests/Regression/T5386/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Regression/T5386/cabal.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -- See #4332, dep solving output is not deterministic -main = cabalTest . recordMode DoNotRecord $ withSourceCopyDir "9" $ +main = cabalTest . recordMode DoNotRecord $ -- Note: we bundle the configure script so no need to autoreconf while building cabal "v2-build" ["all"] diff --git a/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.project b/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.project index 0d2e55b4b44..858544b8292 100644 --- a/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.project +++ b/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.project @@ -1 +1 @@ -packages: issue5782 \ No newline at end of file +packages: issue5782 diff --git a/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.test.hs index 410a0eba1f1..2ec30f1c876 100644 --- a/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.test.hs +++ b/cabal-testsuite/PackageTests/Regression/T5782Diamond/cabal.test.hs @@ -21,8 +21,7 @@ import Test.Cabal.Prelude main = withShorterPathForNewBuildStore $ \storeDir -> - cabalTest $ - withSourceCopy . withDelay $ do + cabalTest $ withDelay $ do writeSourceFile "issue5782/src/Module.hs" "module Module where\nf = \"AAA\"" recordMode DoNotRecord $ cabalG ["--store-dir=" ++ storeDir, "--installdir=" ++ storeDir, "--overwrite-policy=always"] "v2-install" ["issue5782"] diff --git a/cabal-testsuite/PackageTests/Regression/T6440/cabal.out b/cabal-testsuite/PackageTests/Regression/T6440/cabal.out new file mode 100644 index 00000000000..5c24cecf81f --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/cabal.out @@ -0,0 +1,26 @@ +# cabal test +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - cabal6440-0.1 (lib:intern6440) (first run) + - cabal6440-0.1 (lib) (first run) + - cabal6440-0.1 (test:tests) (first run) +Configuring library 'intern6440' for cabal6440-0.1... +Warning: [no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +Preprocessing library 'intern6440' for cabal6440-0.1... +Building library 'intern6440' for cabal6440-0.1... +Configuring library for cabal6440-0.1... +Warning: [no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +Preprocessing library for cabal6440-0.1... +Building library for cabal6440-0.1... +Configuring test suite 'tests' for cabal6440-0.1... +Warning: [no-default-language] Packages using 'cabal-version: >= 1.10' and before 'cabal-version: 3.4' must specify the 'default-language' field for each component (e.g. Haskell98 or Haskell2010). If a component uses different languages in different modules then list the other ones in the 'other-languages' field. +Preprocessing test suite 'tests' for cabal6440-0.1... +Building test suite 'tests' for cabal6440-0.1... +Running 1 test suites... +Test suite tests: RUNNING... +Test suite tests: PASS +Test suite logged to: /cabal.dist/work/./dist/build//ghc-/cabal6440-0.1/t/tests/test/cabal6440-0.1-tests.log +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal6440-0.1/t/tests/hpc/vanilla/html/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /cabal.dist/work/./dist/build//ghc-/cabal6440-0.1/t/tests/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/Regression/T6440/cabal.project b/cabal-testsuite/PackageTests/Regression/T6440/cabal.project new file mode 100644 index 00000000000..b764c340a62 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/cabal.project @@ -0,0 +1,2 @@ +packages: . + diff --git a/cabal-testsuite/PackageTests/Regression/T6440/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T6440/cabal.test.hs new file mode 100644 index 00000000000..0932c665f31 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/cabal.test.hs @@ -0,0 +1,2 @@ +import Test.Cabal.Prelude +main = cabalTest $ cabal "test" ["--enable-coverage"] diff --git a/cabal-testsuite/PackageTests/Regression/T6440/cabal6440.cabal b/cabal-testsuite/PackageTests/Regression/T6440/cabal6440.cabal new file mode 100644 index 00000000000..42192a71672 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/cabal6440.cabal @@ -0,0 +1,23 @@ +cabal-version: 3.0 +name: cabal6440 +version: 0.1 + +library + exposed-modules: Top + -- other-extensions: + build-depends: base, cabal6440:intern6440 + hs-source-dirs: src + default-language: Haskell2010 + +library intern6440 + exposed-modules: Inn + build-depends: base + hs-source-dirs: srcint + + +test-suite tests + main-is: Main.hs + type: exitcode-stdio-1.0 + build-depends: base, cabal6440 + hs-source-dirs: tests + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Regression/T6440/src/Top.hs b/cabal-testsuite/PackageTests/Regression/T6440/src/Top.hs new file mode 100644 index 00000000000..66539d28e3b --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/src/Top.hs @@ -0,0 +1,5 @@ +module Top where +import Inn + +foo :: String +foo = bar diff --git a/cabal-testsuite/PackageTests/Regression/T6440/srcint/Inn.hs b/cabal-testsuite/PackageTests/Regression/T6440/srcint/Inn.hs new file mode 100644 index 00000000000..e77f8fd85a3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/srcint/Inn.hs @@ -0,0 +1,4 @@ +module Inn where + +bar :: String +bar = "internal" diff --git a/cabal-testsuite/PackageTests/Regression/T6440/tests/Main.hs b/cabal-testsuite/PackageTests/Regression/T6440/tests/Main.hs new file mode 100644 index 00000000000..89a8e05f0e5 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T6440/tests/Main.hs @@ -0,0 +1,6 @@ +module Main where + +import Top + +main :: IO () +main = print foo diff --git a/cabal-testsuite/PackageTests/Regression/T9640/CHANGELOG.md b/cabal-testsuite/PackageTests/Regression/T9640/CHANGELOG.md new file mode 100644 index 00000000000..8c1e051ba21 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for depend-on-custom-with-exe + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/Regression/T9640/LICENSE b/cabal-testsuite/PackageTests/Regression/T9640/LICENSE new file mode 100644 index 00000000000..79fd6b542e3 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2024, Rodrigo Mesquita + +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 Rodrigo Mesquita nor the names of 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. diff --git a/cabal-testsuite/PackageTests/Regression/T9640/cabal.out b/cabal-testsuite/PackageTests/Regression/T9640/cabal.out new file mode 100644 index 00000000000..8ec3628aadb --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/cabal.out @@ -0,0 +1,16 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - one-custom-0.1.0.0 (lib:one-custom) (requires build) + - depend-on-custom-with-exe-0.1.0.0 (lib) (first run) +Configuring one-custom-0.1.0.0... +Preprocessing library for one-custom-0.1.0.0.. +Building library for one-custom-0.1.0.0.. +Installing library in +Warning: depend-on-custom-with-exe.cabal:16:1: Ignoring trailing fields after sections: "ghc-options" +Configuring library for depend-on-custom-with-exe-0.1.0.0... +Preprocessing library for depend-on-custom-with-exe-0.1.0.0... +Building library for depend-on-custom-with-exe-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/Regression/T9640/cabal.project b/cabal-testsuite/PackageTests/Regression/T9640/cabal.project new file mode 100644 index 00000000000..fdb74d42728 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/cabal.project @@ -0,0 +1,2 @@ +packages: . +extra-packages: one-custom diff --git a/cabal-testsuite/PackageTests/Regression/T9640/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T9640/cabal.test.hs new file mode 100644 index 00000000000..628de12e9b8 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/cabal.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude +main = cabalTest $ withRepo "repo" $ do + skipUnlessGhcVersion ">= 8.8" + cabal "build" ["depend-on-custom-with-exe"] diff --git a/cabal-testsuite/PackageTests/Regression/T9640/depend-on-custom-with-exe.cabal b/cabal-testsuite/PackageTests/Regression/T9640/depend-on-custom-with-exe.cabal new file mode 100644 index 00000000000..64f3453c645 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/depend-on-custom-with-exe.cabal @@ -0,0 +1,23 @@ +cabal-version: 2.4 +name: depend-on-custom-with-exe +version: 0.1.0.0 +-- synopsis: +-- description: +license: BSD-3-Clause +license-file: LICENSE +author: Rodrigo Mesquita +maintainer: rodrigo.m.mesquita@gmail.com +-- copyright: +build-type: Simple +extra-doc-files: CHANGELOG.md +-- extra-source-files: + +common warnings +ghc-options: -Wall + +library + import: warnings + exposed-modules: MyLib + build-depends: base, one-custom + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/CHANGELOG.md b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/CHANGELOG.md new file mode 100644 index 00000000000..9be9ae06995 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for one-custom + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/Main.hs b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/Main.hs new file mode 100644 index 00000000000..3f3508ee0a9 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/Main.hs @@ -0,0 +1 @@ +main = putStrLn "Hello" diff --git a/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/Setup.hs b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/Setup.hs new file mode 100644 index 00000000000..9a994af677b --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/cabal.project b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/one-custom.cabal b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/one-custom.cabal new file mode 100644 index 00000000000..74a9a731de0 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/one-custom.cabal @@ -0,0 +1,24 @@ +cabal-version: 2.4 +name: one-custom +version: 0.1.0.0 +license: NONE +build-type: Custom +extra-doc-files: CHANGELOG.md + +custom-setup + setup-depends: base, Cabal + +common warnings + ghc-options: -Wall + +library + import: warnings + exposed-modules: MyLib + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 + +executable example + main-is: Main.hs + default-language: Haskell2010 + build-depends: base diff --git a/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/src/MyLib.hs b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/src/MyLib.hs new file mode 100644 index 00000000000..e657c4403f6 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/repo/one-custom-0.1.0.0/src/MyLib.hs @@ -0,0 +1,4 @@ +module MyLib (someFunc) where + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/cabal-testsuite/PackageTests/Regression/T9640/src/MyLib.hs b/cabal-testsuite/PackageTests/Regression/T9640/src/MyLib.hs new file mode 100644 index 00000000000..e657c4403f6 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9640/src/MyLib.hs @@ -0,0 +1,4 @@ +module MyLib (someFunc) where + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/cabal-testsuite/PackageTests/Regression/T9756/OK.hs b/cabal-testsuite/PackageTests/Regression/T9756/OK.hs new file mode 100644 index 00000000000..1846f8c9d0e --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/OK.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE TemplateHaskell #-} +module OK where + +import Data.List +import System.Process +import Language.Haskell.TH + +$(do + out <- runIO $ readProcess "mybuilder" [] "" + if "0.2.0.0" `isInfixOf` out then + [d| x = () |] + else + error ("Expecting Version 0.2.0.0, but got: " ++ out) + ) diff --git a/cabal-testsuite/PackageTests/Regression/T9756/cabal-bug-build-tool.cabal b/cabal-testsuite/PackageTests/Regression/T9756/cabal-bug-build-tool.cabal new file mode 100644 index 00000000000..941ac8fbca6 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/cabal-bug-build-tool.cabal @@ -0,0 +1,10 @@ +cabal-version: 1.12 +name: cabal-bug-build-tool +version: 0 +build-type: Simple + +library + exposed-modules: OK + default-language: Haskell2010 + build-depends: base, template-haskell, process + build-tool-depends: mybuilder:mybuilder >=0.2.0.0 diff --git a/cabal-testsuite/PackageTests/Regression/T9756/cabal.out b/cabal-testsuite/PackageTests/Regression/T9756/cabal.out new file mode 100644 index 00000000000..61a814acd68 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/cabal.out @@ -0,0 +1,27 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-install +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - mybuilder-0.1.0.0 (exe:mybuilder) (requires build) +Configuring executable 'mybuilder' for mybuilder-0.1.0.0... +Preprocessing executable 'mybuilder' for mybuilder-0.1.0.0... +Building executable 'mybuilder' for mybuilder-0.1.0.0... +Installing executable mybuilder in +Warning: The directory /cabal.dist/home/.cabal/store/ghc-/incoming/new-/cabal.dist/home/.cabal/store/ghc-/-/bin is not in the system search path. +Symlinking 'mybuilder' to '/cabal.dist/install/mybuilder' +# cabal v2-build +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - mybuilder-0.2.0.0 (exe:mybuilder) (requires build) + - cabal-bug-build-tool-0 (lib) (first run) +Configuring executable 'mybuilder' for mybuilder-0.2.0.0... +Preprocessing executable 'mybuilder' for mybuilder-0.2.0.0... +Building executable 'mybuilder' for mybuilder-0.2.0.0... +Installing executable mybuilder in +Warning: The directory /cabal.dist/home/.cabal/store/ghc-/incoming/new-/cabal.dist/home/.cabal/store/ghc-/-/bin is not in the system search path. +Configuring library for cabal-bug-build-tool-0... +Preprocessing library for cabal-bug-build-tool-0... +Building library for cabal-bug-build-tool-0... diff --git a/cabal-testsuite/PackageTests/Regression/T9756/cabal.project b/cabal-testsuite/PackageTests/Regression/T9756/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/Regression/T9756/cabal.test.hs b/cabal-testsuite/PackageTests/Regression/T9756/cabal.test.hs new file mode 100644 index 00000000000..65b1acb5b70 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/cabal.test.hs @@ -0,0 +1,13 @@ +import Test.Cabal.Prelude + +-- We are testing if the build-tools program is found in path before programs e.g. in extra-prog-path or the system path +-- For that, we need +-- * A repo with a build tool that is up to date +-- * An older version of the build tool in the extra-prog-path +-- * A project that requires the more up-to-date version of the build-tool + +main = cabalTest $ withRepo "repo" $ do + dir <- testWorkDir <$> getTestEnv + cabal "v2-install" ["mybuilder-0.1.0.0", "--installdir=" ++ dir ++ "/install", "--overwrite-policy=always"] + cabal "v2-build" ["cabal-bug-build-tool", "--extra-prog-path=" ++ dir ++ "/install"] + diff --git a/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/CHANGELOG.md b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/CHANGELOG.md new file mode 100644 index 00000000000..60a3351b163 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for mybuilder0100 + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/app/Main.hs b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/app/Main.hs new file mode 100644 index 00000000000..7de3bfe00bb --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/app/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "0.1.0.0" diff --git a/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/mybuilder.cabal b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/mybuilder.cabal new file mode 100644 index 00000000000..0649d81c4e0 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.1.0.0/mybuilder.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: mybuilder +version: 0.1.0.0 +license: NONE +author: Rodrigo Mesquita +maintainer: rodrigo.m.mesquita@gmail.com +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +executable mybuilder + import: warnings + main-is: Main.hs + build-depends: base + hs-source-dirs: app + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/CHANGELOG.md b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/CHANGELOG.md new file mode 100644 index 00000000000..60a3351b163 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for mybuilder0100 + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/app/Main.hs b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/app/Main.hs new file mode 100644 index 00000000000..3550f30bd2f --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/app/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "0.2.0.0" diff --git a/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/mybuilder.cabal b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/mybuilder.cabal new file mode 100644 index 00000000000..c98f493aa14 --- /dev/null +++ b/cabal-testsuite/PackageTests/Regression/T9756/repo/mybuilder-0.2.0.0/mybuilder.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.0 +name: mybuilder +version: 0.2.0.0 +license: NONE +author: Rodrigo Mesquita +maintainer: rodrigo.m.mesquita@gmail.com +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +executable mybuilder + import: warnings + main-is: Main.hs + build-depends: base + hs-source-dirs: app + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/RelativePathProjectImports/cabal.project b/cabal-testsuite/PackageTests/RelativePathProjectImports/cabal.project index 8eceb95e1a5..c95da21fb66 100644 --- a/cabal-testsuite/PackageTests/RelativePathProjectImports/cabal.project +++ b/cabal-testsuite/PackageTests/RelativePathProjectImports/cabal.project @@ -3,4 +3,4 @@ import: ./dep/cabal.project packages: main.cabal dep/dep.cabal - dep2/dep2.cabal \ No newline at end of file + dep2/dep2.cabal diff --git a/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/cabal.test.hs b/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/cabal.test.hs index 4a75ff3bc44..463357cd1b8 100644 --- a/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/cabal.test.hs +++ b/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/cabal.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude -- See #4332, dep solving output is not deterministic -main = cabalTest . recordMode DoNotRecord $ withRepo "../repo" $ do +main = cabalTest . recordMode DoNotRecord $ withRepo "repo" $ do -- other-lib is a dependency, but it's not listed in cabal.project res <- fails $ cabal' "v2-build" ["all", "--dry-run"] assertOutputContains "not a user-provided goal" res diff --git a/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/repo b/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/repo new file mode 120000 index 00000000000..2dd2305a132 --- /dev/null +++ b/cabal-testsuite/PackageTests/RequireExplicit/FlagInProject/repo @@ -0,0 +1 @@ +../repo/ \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/cabal.test.hs b/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/cabal.test.hs index 487a4a400a2..271bddebf0b 100644 --- a/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/cabal.test.hs +++ b/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/cabal.test.hs @@ -1,6 +1,6 @@ import Test.Cabal.Prelude -- See #4332, dep solving output is not deterministic -main = cabalTest . recordMode DoNotRecord $ withRepo "../repo" $ do +main = cabalTest . recordMode DoNotRecord $ withRepo "repo" $ do -- other-lib is a dependency of b, but it's not listed in cabal.project res <- fails $ cabal' "v2-build" ["all", "--dry-run", "--reject-unconstrained-dependencies", "all", "--constraint", "some-exe -any"] assertOutputContains "not a user-provided goal" res diff --git a/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/repo b/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/repo new file mode 120000 index 00000000000..2dd2305a132 --- /dev/null +++ b/cabal-testsuite/PackageTests/RequireExplicit/MultiPkg/repo @@ -0,0 +1 @@ +../repo/ \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/SDist/ListSources/list-sources.out b/cabal-testsuite/PackageTests/SDist/ListSources/list-sources.out index c7b1ba4eaa2..6f929e541fc 100644 --- a/cabal-testsuite/PackageTests/SDist/ListSources/list-sources.out +++ b/cabal-testsuite/PackageTests/SDist/ListSources/list-sources.out @@ -1,2 +1,2 @@ # Setup sdist -List of package sources written to file '/sources' +List of package sources written to file '/sources' diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/U.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/U.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/V.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/V.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out new file mode 100644 index 00000000000..3d6859f996b --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.patch new file mode 100644 index 00000000000..d16b271c934 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.patch @@ -0,0 +1,8 @@ +diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out +index 3d6859f99..a7ffc109e 100644 +--- a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out ++++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.out +@@ -1,2 +1,2 @@ + # cabal sdist +-Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/p-0.1.tar.gz ++Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/uv-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.test.hs new file mode 100644 index 00000000000..f45ed508b31 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.test.hs @@ -0,0 +1,12 @@ +import Test.Cabal.Prelude + +-- cabal.dot-uv.project has "packages: .". That package is uv.cabal but "cabal +-- sdist" writes sdist/p-0.1.tar.gz instead of the expected sdist/uv-0.1.tar.gz. +-- That is wrong, "cabal sdist" should respect the "--project-file" option but +-- instead probes the parent directory and picks up "../cabal.project" that has +-- "packages: Projects-Default-No/p". +-- +-- TODO: Fix this behaviour and apply the patch cabal.dot-uv.patch to update the +-- expected output to what we'd expect if "cabal sdist" respected the project. +main = cabalTest . withProjectFile "cabal.dot-uv.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.v2.out new file mode 100644 index 00000000000..67bd3824161 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.v2.out @@ -0,0 +1,2 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/uv-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.v2.test.hs new file mode 100644 index 00000000000..c39feac79b3 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.dot-uv.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.dot-uv.project has "packages: .". That package is uv.cabal and "cabal +-- v2-sdist" writes sdist/uv-0.1.tar.gz. This is correct. +main = cabalTest . withProjectFile "cabal.dot-uv.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.out new file mode 100644 index 00000000000..c4b60109a98 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.ignore-project.dist/work/./dist/sdist/uv-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.test.hs new file mode 100755 index 00000000000..90432e4fbb8 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- This test correctly writes sdist/uv-0.1.tar.gz for the uv.cabal package. +main = cabalTest $ do + cabal "sdist" ["all", "--ignore-project"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.v2.out new file mode 100644 index 00000000000..e6f04ba9970 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.v2.out @@ -0,0 +1,2 @@ +# cabal v2-sdist +Wrote tarball sdist to /home/philderbeast/dev/src/cabalism/cabal/cabal-testsuite/PackageTests/SDist/Respect-Project-File/dist-newstyle/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.v2.test.hs new file mode 100755 index 00000000000..94abd67e057 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.ignore-project.v2.test.hs @@ -0,0 +1,8 @@ +import Test.Cabal.Prelude + +-- This test should have written sdist/uv-0.1.tar.gz for the uv.cabal package +-- but instead it probed up the directory tree, found a default cabal.project +-- and wrote sdist/p-0.1.tar.gz. That is incorrect. It didn't ignore the +-- project. +main = cabalTest $ do + cabal "v2-sdist" ["all", "--ignore-project"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.out new file mode 100644 index 00000000000..da8d99d249f --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.no-project.dist/work/./dist/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.test.hs new file mode 100755 index 00000000000..49bd8ecf713 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +-- When no project is given, "cabal sdist" probes up the directory tree, finds a +-- default cabal.project and writes sdist/p-0.1.tar.gz. That is acceptable. An +-- alternative and reasonable expectation (but not the behaviour seen) is that +-- project probing would not occur and "cabal sdist" would work on the local +-- uv.cabal package. +main = cabalTest $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.v2.out new file mode 100644 index 00000000000..e6f04ba9970 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.v2.out @@ -0,0 +1,2 @@ +# cabal v2-sdist +Wrote tarball sdist to /home/philderbeast/dev/src/cabalism/cabal/cabal-testsuite/PackageTests/SDist/Respect-Project-File/dist-newstyle/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.v2.test.hs new file mode 100755 index 00000000000..6cdef39733a --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.no-project.v2.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +-- When no project is given, "cabal v2-sdist" probes up the directory tree, +-- finds a default cabal.project and writes sdist/p-0.1.tar.gz. That is +-- acceptable. An alternative and reasonable expectation (but not the behaviour +-- seen) is that project probing would not occur and "cabal v2-sdist" would work +-- on the local uv.cabal package. +main = cabalTest $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out new file mode 100644 index 00000000000..c96d15ee6bb --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.sub-pq.dist/work/./dist/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.patch new file mode 100644 index 00000000000..a81b0f0099d --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.patch @@ -0,0 +1,8 @@ +diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out +index c96d15ee6..12dcc1217 100644 +--- a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out ++++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.out +@@ -1,2 +1,3 @@ + # cabal sdist + Wrote tarball sdist to /cabal.sub-pq.dist/work/./dist/sdist/p-0.1.tar.gz ++Wrote tarball sdist to /cabal.sub-pq.dist/work/./dist/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.project new file mode 100644 index 00000000000..36c6791d8c2 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.project @@ -0,0 +1 @@ +packages: p/ q/ diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.test.hs new file mode 100644 index 00000000000..8ad8bbd1233 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.test.hs @@ -0,0 +1,12 @@ +import Test.Cabal.Prelude + +-- cabal.sub-pq.project has "packages: p/ q/" but "cabal sdist" only writes +-- sdist/p-0.1.tar.gz instead of the expected sdist/p-0.1.tar.gz and +-- sdist/q-0.1.tar.gz. That is wrong, "cabal sdist" should respect the +-- "--project-file" option but instead probes the parent directory and picks up +-- "../cabal.project" that has "packages: Projects-Default-No/p". +-- +-- TODO: Fix this behaviour and apply the patch cabal.sub-pq.patch to update the +-- expected output to what we'd expect if "cabal sdist" respected the project. +main = cabalTest . withProjectFile "cabal.sub-pq.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.v2.out new file mode 100644 index 00000000000..f44e24e9567 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/p-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.v2.test.hs new file mode 100644 index 00000000000..a82397a4ef6 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-pq.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.sub-pq.project has "packages: p/ q/" and "cabal v2-sdist" writes +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. This is correct. +main = cabalTest . withProjectFile "cabal.sub-pq.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out new file mode 100644 index 00000000000..3a0a8e5f403 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.patch new file mode 100644 index 00000000000..56dbbae23d5 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.patch @@ -0,0 +1,9 @@ +diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out +index 3a0a8e5f4..b4cced990 100644 +--- a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out ++++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out +@@ -1,2 +1,3 @@ + # cabal sdist +-Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/p-0.1.tar.gz ++Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/r-0.1.tar.gz ++Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/s-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.project new file mode 100644 index 00000000000..6a0bc8f2249 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.project @@ -0,0 +1 @@ +packages: r/ s/ diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.test.hs new file mode 100644 index 00000000000..d6ecf063192 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.test.hs @@ -0,0 +1,12 @@ +import Test.Cabal.Prelude + +-- cabal.sub-rs.project has "packages: r/ s/" but "cabal sdist" writes +-- sdist/p-0.1.tar.gz instead of the expected sdist/r-0.1.tar.gz and +-- sdist/s-0.1.tar.gz. That is wrong, "cabal sdist" should respect the +-- "--project-file" option but instead probes the parent directory and picks up +-- "../cabal.project" that has "packages: Projects-Default-No/p". +-- +-- TODO: Fix this behaviour and apply the patch cabal.sub-rs.patch to update the +-- expected output to what we'd expect if "cabal sdist" respected the project. +main = cabalTest . withProjectFile "cabal.sub-rs.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.v2.out new file mode 100644 index 00000000000..f6ee642cc69 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/r-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/s-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.v2.test.hs new file mode 100644 index 00000000000..a0c14d19645 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.sub-rs.project has "packages: r/ s/" and "cabal v2-sdist" writes +-- sdist/r-0.1.tar.gz and sdist/s-0.1.tar.gz. This is correct. +main = cabalTest . withProjectFile "cabal.sub-rs.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/p/P.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/p/P.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/p/p.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/p/p.cabal new file mode 100644 index 00000000000..6a10e9f9985 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/p/p.cabal @@ -0,0 +1,8 @@ +name: p +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: P + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/q/Q.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/q/Q.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/q/q.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/q/q.cabal new file mode 100644 index 00000000000..30331517425 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/q/q.cabal @@ -0,0 +1,8 @@ +name: q +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: Q + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/r/R.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/r/R.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/r/r.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/r/r.cabal new file mode 100644 index 00000000000..8143b51865f --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/r/r.cabal @@ -0,0 +1,8 @@ +name: r +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: R + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/s/S.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/s/S.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/s/s.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/s/s.cabal new file mode 100644 index 00000000000..e30a1595f81 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/s/s.cabal @@ -0,0 +1,8 @@ +name: s +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: S + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/uv.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/uv.cabal new file mode 100644 index 00000000000..3205e54e0ba --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/uv.cabal @@ -0,0 +1,14 @@ +cabal-version: 3.0 +name: uv +version: 0.1 +build-type: Simple + +library U + visibility: public + exposed-modules: U + build-depends: base + +library V + visibility: public + exposed-modules: V + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/U.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/U.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/V.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/V.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out new file mode 100644 index 00000000000..231e0d306b4 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out @@ -0,0 +1,3 @@ +# cabal sdist +Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/p-0.1.tar.gz +Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.patch new file mode 100644 index 00000000000..440c2fabf4c --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.patch @@ -0,0 +1,9 @@ +diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out +index 231e0d306..a7ffc109e 100644 +--- a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out ++++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.out +@@ -1,3 +1,2 @@ + # cabal sdist +-Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/p-0.1.tar.gz +-Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/q-0.1.tar.gz ++Wrote tarball sdist to /cabal.dot-uv.dist/work/./dist/sdist/uv-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.test.hs new file mode 100644 index 00000000000..3c0f776a70c --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.test.hs @@ -0,0 +1,12 @@ +import Test.Cabal.Prelude + +-- cabal.dot-uv.project has "packages: .". That package is uv.cabal but "cabal +-- sdist" writes sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz instead of the +-- expected sdist/uv-0.1.tar.gz. That is wrong, "cabal sdist" should respect +-- the "--project-file" option but instead picks up the default "cabal.project" +-- that has "packages: p/ q/". +-- +-- TODO: Fix this behaviour and apply the patch cabal.dot-uv.patch to update the +-- expected output to what we'd expect if "cabal sdist" respected the project. +main = cabalTest . withProjectFile "cabal.dot-uv.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.v2.out new file mode 100644 index 00000000000..67bd3824161 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.v2.out @@ -0,0 +1,2 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/uv-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.v2.test.hs new file mode 100644 index 00000000000..4f12de028e9 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.dot-uv.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.dot-uv.project has "packages: .". That package is uv.cabal and "cabal +-- v2-sdist" writes sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. That is correct. +main = cabalTest . withProjectFile "cabal.dot-uv.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.out new file mode 100644 index 00000000000..c4b60109a98 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.ignore-project.dist/work/./dist/sdist/uv-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.test.hs new file mode 100755 index 00000000000..90432e4fbb8 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- This test correctly writes sdist/uv-0.1.tar.gz for the uv.cabal package. +main = cabalTest $ do + cabal "sdist" ["all", "--ignore-project"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.out new file mode 100644 index 00000000000..f44e24e9567 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/p-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.patch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.test.hs new file mode 100755 index 00000000000..d017d47317a --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.ignore-project.v2.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +-- This test doesn't ignore the project. It should have written +-- sdist/uv-0.1.tar.gz for the uv.cabal package but instead it wrote +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. +main = cabalTest $ do + cabal "v2-sdist" ["all", "--ignore-project"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.out new file mode 100644 index 00000000000..83f4cf0c160 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.out @@ -0,0 +1,3 @@ +# cabal sdist +Wrote tarball sdist to /cabal.no-project.dist/work/./dist/sdist/p-0.1.tar.gz +Wrote tarball sdist to /cabal.no-project.dist/work/./dist/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.test.hs new file mode 100755 index 00000000000..b25efe2a0d9 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.test.hs @@ -0,0 +1,10 @@ +import Test.Cabal.Prelude + +-- When no project is given, "cabal sdist" finds a default cabal.project that +-- has "packages: p/ q/" and writes sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. +-- This is correct. +-- +-- TODO: Check that the code is behaving the same as it would have if +-- "--project-file=cabal.project" was given or if it is using project probing. +main = cabalTest $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.out new file mode 100644 index 00000000000..f44e24e9567 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/p-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.patch new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.test.hs new file mode 100755 index 00000000000..4f9189489cb --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.no-project.v2.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +-- When no project is given, "cabal v2-sdist" finds a default cabal.project that +-- has "packages: p/ q/" and writes sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. +-- This is correct. +main = cabalTest $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project new file mode 100644 index 00000000000..36c6791d8c2 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project @@ -0,0 +1 @@ +packages: p/ q/ diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.out new file mode 100644 index 00000000000..b699a53c853 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.out @@ -0,0 +1,3 @@ +# cabal sdist +Wrote tarball sdist to /cabal.project.dist/work/./dist/sdist/p-0.1.tar.gz +Wrote tarball sdist to /cabal.project.dist/work/./dist/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.test.hs new file mode 100644 index 00000000000..81b6cc511b1 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +-- The given cabal.project has has "packages: p/ q/" and "cabal sdist" writes +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. This is correct but likely +-- accidental as the default cabal.project has the same packages. +main = cabalTest . withProjectFile "cabal.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.v2.out new file mode 100644 index 00000000000..f44e24e9567 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/p-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.v2.test.hs new file mode 100644 index 00000000000..29aafe0c99d --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.project.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- The given cabal.project has has "packages: p/ q/" and "cabal v2-sdist" writes +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. This is correct. +main = cabalTest . withProjectFile "cabal.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.out new file mode 100644 index 00000000000..12dcc1217e0 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.out @@ -0,0 +1,3 @@ +# cabal sdist +Wrote tarball sdist to /cabal.sub-pq.dist/work/./dist/sdist/p-0.1.tar.gz +Wrote tarball sdist to /cabal.sub-pq.dist/work/./dist/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.project new file mode 100644 index 00000000000..36c6791d8c2 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.project @@ -0,0 +1 @@ +packages: p/ q/ diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.test.hs new file mode 100644 index 00000000000..63803ba8851 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.sub-pq.project has "packages: p/ q/" and "cabal sdist" writes +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. This is correct. +main = cabalTest . withProjectFile "cabal.sub-pq.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.v2.out new file mode 100644 index 00000000000..f44e24e9567 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/p-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.v2.test.hs new file mode 100644 index 00000000000..a82397a4ef6 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-pq.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.sub-pq.project has "packages: p/ q/" and "cabal v2-sdist" writes +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz. This is correct. +main = cabalTest . withProjectFile "cabal.sub-pq.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out new file mode 100644 index 00000000000..264d9e001ee --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out @@ -0,0 +1,3 @@ +# cabal sdist +Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/p-0.1.tar.gz +Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/q-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.patch b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.patch new file mode 100644 index 00000000000..de09911d55a --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.patch @@ -0,0 +1,10 @@ +diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out +index 264d9e001..b4cced990 100644 +--- a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out ++++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.out +@@ -1,3 +1,3 @@ + # cabal sdist +-Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/p-0.1.tar.gz +-Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/q-0.1.tar.gz ++Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/r-0.1.tar.gz ++Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/s-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.project new file mode 100644 index 00000000000..6a0bc8f2249 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.project @@ -0,0 +1 @@ +packages: r/ s/ diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.test.hs new file mode 100644 index 00000000000..e8977aa1770 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.test.hs @@ -0,0 +1,12 @@ +import Test.Cabal.Prelude + +-- cabal.sub-rs.project has "packages: r/ s/" but "cabal sdist" writes +-- sdist/p-0.1.tar.gz and sdist/q-0.1.tar.gz instead of the expected +-- sdist/r-0.1.tar.gz and sdist/s-0.1.tar.gz. That is wrong, "cabal sdist" +-- should respect the "--project-file" option but instead picks up the default +-- "cabal.project" that has "packages: p/ q/". +-- +-- TODO: Fix this behaviour and apply the patch cabal.sub-rs.patch to update the +-- expected output to what we'd expect if "cabal sdist" respected the project. +main = cabalTest . withProjectFile "cabal.sub-rs.project" $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.v2.out new file mode 100644 index 00000000000..f6ee642cc69 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.v2.out @@ -0,0 +1,3 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/r-0.1.tar.gz +Wrote tarball sdist to /dist-newstyle/sdist/s-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.v2.test.hs new file mode 100644 index 00000000000..fa7bb0b266f --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/cabal.sub-rs.v2.test.hs @@ -0,0 +1,6 @@ +import Test.Cabal.Prelude + +-- cabal.sub-rs.project has "packages: r/ s/" and "cabal v2-sdist" writes +-- sdist/r-0.1.tar.gz and sdist/s-0.1.tar.gz. That is correct. +main = cabalTest . withProjectFile "cabal.sub-rs.project" $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/p/P.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/p/P.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/p/p.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/p/p.cabal new file mode 100644 index 00000000000..6a10e9f9985 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/p/p.cabal @@ -0,0 +1,8 @@ +name: p +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: P + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/q/Q.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/q/Q.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/q/q.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/q/q.cabal new file mode 100644 index 00000000000..30331517425 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/q/q.cabal @@ -0,0 +1,8 @@ +name: q +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: Q + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/r/R.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/r/R.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/r/r.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/r/r.cabal new file mode 100644 index 00000000000..8143b51865f --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/r/r.cabal @@ -0,0 +1,8 @@ +name: r +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: R + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/s/S.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/s/S.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/s/s.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/s/s.cabal new file mode 100644 index 00000000000..e30a1595f81 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/s/s.cabal @@ -0,0 +1,8 @@ +name: s +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: S + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/uv.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/uv.cabal new file mode 100644 index 00000000000..3205e54e0ba --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-Yes/uv.cabal @@ -0,0 +1,14 @@ +cabal-version: 3.0 +name: uv +version: 0.1 +build-type: Simple + +library U + visibility: public + exposed-modules: U + build-depends: base + +library V + visibility: public + exposed-modules: V + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/README.md b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/README.md new file mode 100644 index 00000000000..e400102d3a4 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/README.md @@ -0,0 +1,85 @@ +# Tests of sdist with `--project-file` + +``` +$ tree -P '*.project|*.test.hs' --prune +. +├── cabal.ignore-project.test.hs +├── cabal.ignore-project.v2.test.hs +├── cabal.no-project.test.hs +├── cabal.no-project.v2.test.hs +├── cabal.project +├── Projects-Default-No +│   ├── cabal.dot-uv.project +│   ├── cabal.dot-uv.test.hs +│   ├── cabal.dot-uv.v2.test.hs +│   ├── cabal.ignore-project.test.hs +│   ├── cabal.ignore-project.v2.test.hs +│   ├── cabal.no-project.test.hs +│   ├── cabal.no-project.v2.test.hs +│   ├── cabal.sub-pq.project +│   ├── cabal.sub-pq.test.hs +│   ├── cabal.sub-pq.v2.test.hs +│   ├── cabal.sub-rs.project +│   ├── cabal.sub-rs.test.hs +│   └── cabal.sub-rs.v2.test.hs +└── Projects-Default-Yes + ├── cabal.dot-uv.project + ├── cabal.dot-uv.test.hs + ├── cabal.dot-uv.v2.test.hs + ├── cabal.ignore-project.test.hs + ├── cabal.ignore-project.v2.test.hs + ├── cabal.no-project.test.hs + ├── cabal.no-project.v2.test.hs + ├── cabal.project + ├── cabal.project.test.hs + ├── cabal.project.v2.test.hs + ├── cabal.sub-pq.project + ├── cabal.sub-pq.test.hs + ├── cabal.sub-pq.v2.test.hs + ├── cabal.sub-rs.project + ├── cabal.sub-rs.test.hs + └── cabal.sub-rs.v2.test.hs + +3 directories, 34 files +``` + +There are of the two subdirectories, one has a `cabal.project` and the other +doesn't. This is the default project. There are three important things to notice +with these tests. + +1. All the tests with a supplied `--project-file` option pick up a default + `cabal.project` instead; either the one one in the current directory or the + one from the parent directory, one level up. I think this behaviour is wrong + and the supplied `--project-file` option should be respected. + + Before I'd put a project there, one level up, the project probing had gone + all the way up to Cabal's own `cabal.project` as can be seen by this diff + after that change: + + ```diff + $ git diff + ... + --- a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out + +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Projects-Default-No/cabal.sub-rs.out + @@ -1,12 +1,2 @@ + # cabal sdist + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/Cabal-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/cabal-testsuite-3.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/Cabal-syntax-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/cabal-install-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/cabal-install-solver-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/solver-benchmarks-3.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/Cabal-QuickCheck-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/Cabal-tree-diff-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/Cabal-described-3.11.0.0.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/Cabal-tests-3.tar.gz + -Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/cabal-benchmarks-3.tar.gz + +Wrote tarball sdist to /cabal.sub-rs.dist/work/./dist/sdist/p-0.1.tar.gz + ``` + +2. The `--ignore-project` option works, as witnessed by each + `cabal.ignore-project.test.hs` when the package in the same directory as the + test is used. + +3. The `*.v2.test.hs` are the same as their `*.test.hs` sibling tests but they + exercise the `v2-sdist` command instead of the `sdist` command. diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Z.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/Z.hs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.out new file mode 100644 index 00000000000..bba241f8f36 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.ignore-project.dist/work/./dist/sdist/z-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.test.hs new file mode 100755 index 00000000000..3145737a646 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- This test correctly writes sdist/z-0.1.tar.gz for the z.cabal package. +main = cabalTest $ do + cabal "sdist" ["all", "--ignore-project"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.v2.out new file mode 100644 index 00000000000..dc7f939f86b --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.v2.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.ignore-project.v2.dist/work/./dist/sdist/z-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.v2.test.hs new file mode 100755 index 00000000000..3145737a646 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.ignore-project.v2.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +-- This test correctly writes sdist/z-0.1.tar.gz for the z.cabal package. +main = cabalTest $ do + cabal "sdist" ["all", "--ignore-project"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.out new file mode 100644 index 00000000000..da8d99d249f --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.out @@ -0,0 +1,2 @@ +# cabal sdist +Wrote tarball sdist to /cabal.no-project.dist/work/./dist/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.test.hs new file mode 100755 index 00000000000..8f440b78ca6 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +-- When no project is given, "cabal sdist" finds a default cabal.project that +-- has "packages: Projects-Default-No/p" and writes sdist/p-0.1.tar.gz. This is +-- correct. +main = cabalTest $ do + cabal "sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.v2.out b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.v2.out new file mode 100644 index 00000000000..63c0f0c36f1 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.v2.out @@ -0,0 +1,2 @@ +# cabal v2-sdist +Wrote tarball sdist to /dist-newstyle/sdist/p-0.1.tar.gz diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.v2.test.hs b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.v2.test.hs new file mode 100755 index 00000000000..54cc62f9608 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.no-project.v2.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +-- When no project is given, "cabal v2-sdist" finds a default cabal.project that +-- has "packages: Projects-Default-No/p" and writes sdist/p-0.1.tar.gz. This is +-- correct. +main = cabalTest $ do + cabal "v2-sdist" ["all"] diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.project b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.project new file mode 100644 index 00000000000..87a9ca689a2 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/cabal.project @@ -0,0 +1 @@ +packages: Projects-Default-No/p diff --git a/cabal-testsuite/PackageTests/SDist/Respect-Project-File/z.cabal b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/z.cabal new file mode 100644 index 00000000000..9a0cada3b71 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/Respect-Project-File/z.cabal @@ -0,0 +1,8 @@ +name: z +version: 0.1 +build-type: Simple +cabal-version: >= 1.2 + +library + exposed-modules: Z + build-depends: base diff --git a/cabal-testsuite/PackageTests/SDist/T5195/cabal.out b/cabal-testsuite/PackageTests/SDist/T5195/cabal.out deleted file mode 100644 index 5b329c9c75b..00000000000 --- a/cabal-testsuite/PackageTests/SDist/T5195/cabal.out +++ /dev/null @@ -1,3 +0,0 @@ -# cabal v2-sdist -Error: [Cabal-6661] -filepath wildcard './actually-a-directory' does not match any files. \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/SDist/T5195/cabal.project b/cabal-testsuite/PackageTests/SDist/T5195/cabal.project deleted file mode 100644 index bfe62896560..00000000000 --- a/cabal-testsuite/PackageTests/SDist/T5195/cabal.project +++ /dev/null @@ -1 +0,0 @@ -packages: ./ \ No newline at end of file diff --git a/cabal-testsuite/PackageTests/SDist/T5195/cabal.test.hs b/cabal-testsuite/PackageTests/SDist/T5195/cabal.test.hs deleted file mode 100644 index c0ff953560b..00000000000 --- a/cabal-testsuite/PackageTests/SDist/T5195/cabal.test.hs +++ /dev/null @@ -1,5 +0,0 @@ -import Test.Cabal.Prelude -main = cabalTest $ do - tmpdir <- fmap testTmpDir getTestEnv - res <- fails $ cabal' "v2-sdist" ["--list-only", "--output-directory", tmpdir] - assertOutputContains "filepath wildcard './actually-a-directory' does not match any files" res diff --git a/cabal-testsuite/PackageTests/SDist/T5195/t5195.cabal b/cabal-testsuite/PackageTests/SDist/T5195/t5195.cabal deleted file mode 100644 index 5d9a759dd71..00000000000 --- a/cabal-testsuite/PackageTests/SDist/T5195/t5195.cabal +++ /dev/null @@ -1,10 +0,0 @@ -cabal-version: 2.2 -name: t5195 -version: 0 - -extra-source-files: - ./actually-a-directory - -executable foo - default-language: Haskell2010 - main-is: Main.hs diff --git a/cabal-testsuite/PackageTests/SDist/T5195/Main.hs b/cabal-testsuite/PackageTests/SDist/T5195and5349/Main.hs similarity index 100% rename from cabal-testsuite/PackageTests/SDist/T5195/Main.hs rename to cabal-testsuite/PackageTests/SDist/T5195and5349/Main.hs diff --git a/cabal-testsuite/PackageTests/SDist/T5195/actually-a-directory/some-file b/cabal-testsuite/PackageTests/SDist/T5195and5349/actually-a-directory/some-file similarity index 100% rename from cabal-testsuite/PackageTests/SDist/T5195/actually-a-directory/some-file rename to cabal-testsuite/PackageTests/SDist/T5195and5349/actually-a-directory/some-file diff --git a/cabal-testsuite/PackageTests/SDist/T5195and5349/actually-a-file b/cabal-testsuite/PackageTests/SDist/T5195and5349/actually-a-file new file mode 100644 index 00000000000..b14df6442ea --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/T5195and5349/actually-a-file @@ -0,0 +1 @@ +Hi diff --git a/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.out b/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.out new file mode 100644 index 00000000000..f42c4e98177 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.out @@ -0,0 +1,5 @@ +# cabal v2-sdist +Warning: Ignoring directory '././actually-a-directory' listed in a Cabal package field which should only include files (not directories). +Warning: Ignoring directory './actually-a-directory' listed in a Cabal package field which should only include files (not directories). +Warning: Ignoring directory './actually-a-directory' listed in a Cabal package field which should only include files (not directories). +Wrote source list to /t5195and5349-0.list diff --git a/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.project b/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.project new file mode 100644 index 00000000000..6f920794c80 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.project @@ -0,0 +1 @@ +packages: ./ diff --git a/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.test.hs b/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.test.hs new file mode 100644 index 00000000000..da391fad328 --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/T5195and5349/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude +main = cabalTest $ do + tmpdir <- fmap testTmpDir getTestEnv + cabal' "v2-sdist" ["--list-only", "--output-directory", tmpdir] + return () diff --git a/cabal-testsuite/PackageTests/SDist/T5195and5349/t5195and5349.cabal b/cabal-testsuite/PackageTests/SDist/T5195and5349/t5195and5349.cabal new file mode 100644 index 00000000000..5df90b3562d --- /dev/null +++ b/cabal-testsuite/PackageTests/SDist/T5195and5349/t5195and5349.cabal @@ -0,0 +1,19 @@ +cabal-version: 2.2 +name: t5195and5349 +version: 0 + +extra-source-files: + ./actually-a-directory + ./actually-a-file + +extra-doc-files: + ./actually-a-directory + ./actually-a-file + +data-files: + ./actually-a-directory + ./actually-a-file + +executable foo + default-language: Haskell2010 + main-is: Main.hs diff --git a/cabal-testsuite/PackageTests/SDist/T7028/cabal.out b/cabal-testsuite/PackageTests/SDist/T7028/cabal.out index 55fc123d51d..222d3c33c8b 100644 --- a/cabal-testsuite/PackageTests/SDist/T7028/cabal.out +++ b/cabal-testsuite/PackageTests/SDist/T7028/cabal.out @@ -1,2 +1,2 @@ # cabal v2-sdist -Wrote source list to /t7028-0.list +Wrote source list to /t7028-0.list diff --git a/cabal-testsuite/PackageTests/SDist/T7124/cabal-list.out b/cabal-testsuite/PackageTests/SDist/T7124/cabal-list.out index 8ebea21b6f4..cb65c326a56 100644 --- a/cabal-testsuite/PackageTests/SDist/T7124/cabal-list.out +++ b/cabal-testsuite/PackageTests/SDist/T7124/cabal-list.out @@ -1,4 +1,4 @@ # cabal v2-sdist -Wrote source list to /pkg-a-0.list +Wrote source list to /pkg-a-0.list Error: [Cabal-6661] -filepath wildcard './data.txt' does not match any files. \ No newline at end of file +filepath wildcard './data.txt' does not match any files. diff --git a/cabal-testsuite/PackageTests/SDist/T7124/cabal.out b/cabal-testsuite/PackageTests/SDist/T7124/cabal.out index f212d6951c1..5dbaee755bc 100644 --- a/cabal-testsuite/PackageTests/SDist/T7124/cabal.out +++ b/cabal-testsuite/PackageTests/SDist/T7124/cabal.out @@ -1,4 +1,4 @@ # cabal v2-sdist -Wrote tarball sdist to /pkg-a-0.tar.gz +Wrote tarball sdist to /pkg-a-0.tar.gz Error: [Cabal-6661] -filepath wildcard './data.txt' does not match any files. \ No newline at end of file +filepath wildcard './data.txt' does not match any files. diff --git a/cabal-testsuite/PackageTests/SDist/T7698/cabal.out b/cabal-testsuite/PackageTests/SDist/T7698/cabal.out index f04864ea871..99370eb5dd6 100644 --- a/cabal-testsuite/PackageTests/SDist/T7698/cabal.out +++ b/cabal-testsuite/PackageTests/SDist/T7698/cabal.out @@ -1,2 +1,2 @@ # cabal v2-sdist -Wrote source list to /t7698-0.list +Wrote source list to /t7698-0.list diff --git a/cabal-testsuite/PackageTests/SetupDep/Setup.hs b/cabal-testsuite/PackageTests/SetupDep/Setup.hs new file mode 100644 index 00000000000..89d816ae6d9 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupDep/Setup.hs @@ -0,0 +1,6 @@ +module Main where + +import SetupDep ( depMain ) + +main :: IO () +main = depMain diff --git a/cabal-testsuite/PackageTests/SetupDep/SetupDep.hs b/cabal-testsuite/PackageTests/SetupDep/SetupDep.hs new file mode 100644 index 00000000000..55220d8ba41 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupDep/SetupDep.hs @@ -0,0 +1,6 @@ +module SetupDep where + +import Distribution.Simple + +depMain :: IO () +depMain = defaultMain diff --git a/cabal-testsuite/PackageTests/SetupDep/cabal.project b/cabal-testsuite/PackageTests/SetupDep/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupDep/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/SetupDep/setup-dep.cabal b/cabal-testsuite/PackageTests/SetupDep/setup-dep.cabal new file mode 100644 index 00000000000..78d47d16da3 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupDep/setup-dep.cabal @@ -0,0 +1,16 @@ +cabal-version: 2.2 +name: setup-dep +version: 0.1.0.0 +synopsis: Test for a Setup.hs with a dependency +license: BSD-3-Clause +author: NA +maintainer: NA +category: Testing +build-type: Custom + +custom-setup + setup-depends: Cabal, base + +library + build-depends: base + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/SetupDep/setup.out b/cabal-testsuite/PackageTests/SetupDep/setup.out new file mode 100644 index 00000000000..1e49680dc04 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupDep/setup.out @@ -0,0 +1,5 @@ +# Setup configure +Configuring setup-dep-0.1.0.0... +# Setup build +Preprocessing library for setup-dep-0.1.0.0... +Building library for setup-dep-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/SetupDep/setup.test.hs b/cabal-testsuite/PackageTests/SetupDep/setup.test.hs new file mode 100644 index 00000000000..2df426a5dbf --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupDep/setup.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude +main = setupTest $ do + setup "configure" [] + setup "build" [] diff --git a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/single.out b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/single.out index 81f5bc74a66..110b6052642 100644 --- a/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/single.out +++ b/cabal-testsuite/PackageTests/ShowBuildInfo/Complex/single.out @@ -7,11 +7,11 @@ In order, the following will be built: - Complex-0.1.0.0 (lib) (first run) - Complex-0.1.0.0 (exe:Complex) (first run) Configuring library for Complex-0.1.0.0... -Warning: 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. +Warning: [unknown-directory] 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. Preprocessing library for Complex-0.1.0.0... Building library for Complex-0.1.0.0... Configuring executable 'Complex' for Complex-0.1.0.0... -Warning: 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. +Warning: [unknown-directory] 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. Preprocessing executable 'Complex' for Complex-0.1.0.0... Building executable 'Complex' for Complex-0.1.0.0... # show-build-info Complex exe:Complex @@ -30,7 +30,7 @@ Preprocessing library for criterion-1.1.4.0... Building library for criterion-1.1.4.0... Installing library in Configuring benchmark 'complex-benchmarks' for Complex-0.1.0.0... -Warning: 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. +Warning: [unknown-directory] 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. Preprocessing benchmark 'complex-benchmarks' for Complex-0.1.0.0... Building benchmark 'complex-benchmarks' for Complex-0.1.0.0... # show-build-info Complex bench:complex-benchmarks @@ -45,7 +45,7 @@ Preprocessing library for test-framework-0.8.1.1... Building library for test-framework-0.8.1.1... Installing library in Configuring test suite 'func-test' for Complex-0.1.0.0... -Warning: 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. +Warning: [unknown-directory] 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. Preprocessing test suite 'func-test' for Complex-0.1.0.0... Building test suite 'func-test' for Complex-0.1.0.0... # show-build-info Complex test:func-test @@ -60,7 +60,7 @@ Preprocessing library for another-framework-0.8.1.1... Building library for another-framework-0.8.1.1... Installing library in Configuring test suite 'unit-test' for Complex-0.1.0.0... -Warning: 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. +Warning: [unknown-directory] 'hs-source-dirs: doesnt-exist' specifies a directory which does not exist. Preprocessing test suite 'unit-test' for Complex-0.1.0.0... Building test suite 'unit-test' for Complex-0.1.0.0... # show-build-info Complex test:unit-test diff --git a/cabal-testsuite/PackageTests/TestNameCollision/setup.test.hs b/cabal-testsuite/PackageTests/TestNameCollision/setup.test.hs index 19d2fc90468..93e8a820b30 100644 --- a/cabal-testsuite/PackageTests/TestNameCollision/setup.test.hs +++ b/cabal-testsuite/PackageTests/TestNameCollision/setup.test.hs @@ -3,7 +3,7 @@ import Test.Cabal.Prelude -- which is in the database, we can still use the test case (they -- should NOT shadow). main = setupAndCabalTest $ do - skipUnless "cabal for ghc" =<< hasCabalForGhc -- use of library test suite + skipIfAllCabalVersion "< 2.2" withPackageDb $ do withDirectory "parent" $ setup_install [] withDirectory "child" $ do diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/coverage.out b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/coverage.out new file mode 100644 index 00000000000..872dbd57eaf --- /dev/null +++ b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/coverage.out @@ -0,0 +1,30 @@ +# cabal v2-test +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - my-0.1 (lib) (first run) + - my-0.1 (test:test-Short) (first run) + - my-0.1 (test:test-Foo) (first run) +Configuring library for my-0.1... +Preprocessing library for my-0.1... +Building library for my-0.1... +Configuring test suite 'test-Short' for my-0.1... +Preprocessing test suite 'test-Short' for my-0.1... +Building test suite 'test-Short' for my-0.1... +Running 1 test suites... +Test suite test-Short: RUNNING... +Test suite test-Short: PASS +Test suite logged to: /coverage.dist/work/./dist/build//ghc-/my-0.1/t/test-Short/test/my-0.1-test-Short.log +Package coverage report written to /coverage.dist/work/./dist/build//ghc-/my-0.1/t/test-Short/hpc/vanilla/html/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /coverage.dist/work/./dist/build//ghc-/my-0.1/t/test-Short/hpc/vanilla/html/hpc_index.html +Configuring test suite 'test-Foo' for my-0.1... +Preprocessing test suite 'test-Foo' for my-0.1... +Building test suite 'test-Foo' for my-0.1... +Running 1 test suites... +Test suite test-Foo: RUNNING... +Test suite test-Foo: PASS +Test suite logged to: /coverage.dist/work/./dist/build//ghc-/my-0.1/t/test-Foo/test/my-0.1-test-Foo.log +Package coverage report written to /coverage.dist/work/./dist/build//ghc-/my-0.1/t/test-Foo/hpc/vanilla/html/hpc_index.html +1 of 1 test suites (1 of 1 test cases) passed. +Package coverage report written to /coverage.dist/work/./dist/build//ghc-/my-0.1/t/test-Foo/hpc/vanilla/html/hpc_index.html diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/coverage.test.hs b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/coverage.test.hs new file mode 100644 index 00000000000..1348cd02f35 --- /dev/null +++ b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/coverage.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +main = cabalTest $ do + cabal "v2-test" ["--enable-coverage"] diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-markup.test.hs b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-markup.test.hs index 99140253d55..4db84dcec46 100644 --- a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-markup.test.hs +++ b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-markup.test.hs @@ -13,4 +13,4 @@ main = setupAndCabalTest $ do , "--ghc-option=-hpcdir" , "--ghc-option=" ++ dist_dir ++ "/hpc/vanilla" ] setup "test" ["test-Short", "--show-details=direct"] - shouldNotExist $ htmlDir dist_dir Vanilla "test-Short" "hpc_index.html" + shouldNotExist $ htmlDir dist_dir Vanilla "hpc_index.html" diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.cabal.out b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.cabal.out index 6432eca3a14..1a0105f8cd7 100644 --- a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.cabal.out +++ b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.cabal.out @@ -11,5 +11,5 @@ Building test suite 'test-Short' for my-0.1... Running 1 test suites... Test suite test-Short: RUNNING... Test suite test-Short: PASS -Test suite logged to: ../work/dist/test/my-0.1-test-Short.log +Test suite logged to: setup-no-tix.cabal.dist/work/dist/test/my-0.1-test-Short.log 1 of 1 test suites (1 of 1 test cases) passed. diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.out b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.out index 6432eca3a14..6fd1e91bd00 100644 --- a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.out +++ b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.out @@ -11,5 +11,5 @@ Building test suite 'test-Short' for my-0.1... Running 1 test suites... Test suite test-Short: RUNNING... Test suite test-Short: PASS -Test suite logged to: ../work/dist/test/my-0.1-test-Short.log +Test suite logged to: setup-no-tix.dist/work/dist/test/my-0.1-test-Short.log 1 of 1 test suites (1 of 1 test cases) passed. diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.test.hs b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.test.hs index 073af976d56..12db5895dd1 100644 --- a/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.test.hs +++ b/cabal-testsuite/PackageTests/TestSuiteTests/ExeV10/setup-no-tix.test.hs @@ -12,9 +12,6 @@ import Distribution.Simple.Hpc -- at all.) -- main = setupAndCabalTest $ do - -- Source copy is necessary as GHC defaults to dumping tix - -- file in the CWD, and we do NOT clean it up after the fact. - withSourceCopy $ do dist_dir <- fmap testDistDir getTestEnv setup_build [ "--enable-tests" diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup-deadlock.test.hs b/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup-deadlock.test.hs index 69529404d97..d9b8f3c3d15 100644 --- a/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup-deadlock.test.hs +++ b/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup-deadlock.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude main = setupAndCabalTest $ do - skipUnless "no Cabal for GHC" =<< hasCabalForGhc + skipIfAllCabalVersion "< 2.2" setup_build ["--enable-tests"] fails $ setup "test" [] diff --git a/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup.test.hs b/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup.test.hs index 1a50e4d67e4..42c5556cfa3 100644 --- a/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup.test.hs +++ b/cabal-testsuite/PackageTests/TestSuiteTests/LibV09/setup.test.hs @@ -1,5 +1,5 @@ import Test.Cabal.Prelude -- Test if detailed-0.9 builds correctly main = setupAndCabalTest $ do - skipUnless "no Cabal for GHC" =<< hasCabalForGhc + skipIfAllCabalVersion "< 1.20" setup_build ["--enable-tests"] diff --git a/cabal-testsuite/PackageTests/VersionPriority/0-local.out b/cabal-testsuite/PackageTests/VersionPriority/0-local.out new file mode 100644 index 00000000000..309b61103e3 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/0-local.out @@ -0,0 +1,12 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /0-local.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config /0-local.project requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) diff --git a/cabal-testsuite/PackageTests/VersionPriority/0-local.project b/cabal-testsuite/PackageTests/VersionPriority/0-local.project new file mode 100644 index 00000000000..262cd6eefbc --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/0-local.project @@ -0,0 +1,3 @@ +packages: . +constraints: hashable ==1.4.3.0 +constraints: hashable ==1.4.2.0 diff --git a/cabal-testsuite/PackageTests/VersionPriority/0-local.test.hs b/cabal-testsuite/PackageTests/VersionPriority/0-local.test.hs new file mode 100644 index 00000000000..cb94faaa1e2 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/0-local.test.hs @@ -0,0 +1,4 @@ +import Test.Cabal.Prelude + +main = cabalTest . withRepo "repo" . withProjectFile "0-local.project" $ do + fails $ cabal "v2-build" ["--dry-run"] diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-local-constraints-import.project b/cabal-testsuite/PackageTests/VersionPriority/1-local-constraints-import.project new file mode 100644 index 00000000000..986ca4376f2 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-local-constraints-import.project @@ -0,0 +1,4 @@ +packages: . +allow-newer: hashable:* +constraints: hashable ==1.4.2.0 +import: stackage-local.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-local-import-constraints.project b/cabal-testsuite/PackageTests/VersionPriority/1-local-import-constraints.project new file mode 100644 index 00000000000..1ee9a90cccc --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-local-import-constraints.project @@ -0,0 +1,4 @@ +packages: . +allow-newer: hashable:* +import: stackage-local.config +constraints: hashable ==1.4.2.0 diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-local.out b/cabal-testsuite/PackageTests/VersionPriority/1-local.out new file mode 100644 index 00000000000..c9aca7097d4 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-local.out @@ -0,0 +1,22 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /1-local-constraints-import.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config stackage-local.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /1-local-import-constraints.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config stackage-local.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-local.test.hs b/cabal-testsuite/PackageTests/VersionPriority/1-local.test.hs new file mode 100644 index 00000000000..2b19536eb30 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-local.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +testVersionWin project = + withProjectFile project $ do + fails $ cabal "v2-build" ["--dry-run"] + +main = cabalTest . withRepo "repo" $ do + testVersionWin "1-local-constraints-import.project" + testVersionWin "1-local-import-constraints.project" diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-web-constraints-import.project b/cabal-testsuite/PackageTests/VersionPriority/1-web-constraints-import.project new file mode 100644 index 00000000000..765094255cc --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-web-constraints-import.project @@ -0,0 +1,11 @@ +packages: . +allow-newer: hashable:* +constraints: hashable ==1.4.2.0 + +-- NOTE: We could have grabbed this config from stackage but we don't to avoid +-- making an HTTP request with the test. So instead we save it locally. +-- +-- $ curl https://www.stackage.org/nightly-2023-12-07/cabal.config --output project-stackage/nightly-2023-12-07.config +import: project-stackage/nightly-2023-12-07.config + +import: with-ghc.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-web-import-constraints.project b/cabal-testsuite/PackageTests/VersionPriority/1-web-import-constraints.project new file mode 100644 index 00000000000..9a61583e4b1 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-web-import-constraints.project @@ -0,0 +1,11 @@ +packages: . +allow-newer: hashable:* + +-- NOTE: We could have grabbed this config from stackage but we don't to avoid +-- making an HTTP request with the test. So instead we save it locally. +-- +-- $ curl https://www.stackage.org/nightly-2023-12-07/cabal.config --output project-stackage/nightly-2023-12-07.config +import: project-stackage/nightly-2023-12-07.config + +constraints: hashable ==1.4.2.0 +import: with-ghc.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-web.out b/cabal-testsuite/PackageTests/VersionPriority/1-web.out new file mode 100644 index 00000000000..9fb08252222 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-web.out @@ -0,0 +1,22 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /1-web-constraints-import.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config project-stackage/nightly-2023-12-07.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /1-web-import-constraints.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config project-stackage/nightly-2023-12-07.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) diff --git a/cabal-testsuite/PackageTests/VersionPriority/1-web.test.hs b/cabal-testsuite/PackageTests/VersionPriority/1-web.test.hs new file mode 100644 index 00000000000..b31f0fd8788 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/1-web.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +testVersionWin project = + withProjectFile project $ do + fails $ cabal "v2-build" ["--dry-run"] + +main = cabalTest . withRepo "repo" $ do + testVersionWin "1-web-constraints-import.project" + testVersionWin "1-web-import-constraints.project" diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-local-constraints-import.project b/cabal-testsuite/PackageTests/VersionPriority/2-local-constraints-import.project new file mode 100644 index 00000000000..b34145826a6 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-local-constraints-import.project @@ -0,0 +1,4 @@ +packages: . +allow-newer: hashable:* +constraints: hashable ==1.4.2.0 +import: hop-local.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-local-import-constraints.project b/cabal-testsuite/PackageTests/VersionPriority/2-local-import-constraints.project new file mode 100644 index 00000000000..783f5f24617 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-local-import-constraints.project @@ -0,0 +1,4 @@ +packages: . +allow-newer: hashable:* +import: hop-local.config +constraints: hashable ==1.4.2.0 diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-local.out b/cabal-testsuite/PackageTests/VersionPriority/2-local.out new file mode 100644 index 00000000000..cefdd961637 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-local.out @@ -0,0 +1,22 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /2-local-constraints-import.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config stackage-local.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /2-local-import-constraints.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config stackage-local.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-local.test.hs b/cabal-testsuite/PackageTests/VersionPriority/2-local.test.hs new file mode 100644 index 00000000000..9289e16d0d6 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-local.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +testVersionWin project = + withProjectFile project $ do + fails $ cabal "v2-build" ["--dry-run"] + +main = cabalTest . withRepo "repo" $ do + testVersionWin "2-local-constraints-import.project" + testVersionWin "2-local-import-constraints.project" diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-web-constraints-import.project b/cabal-testsuite/PackageTests/VersionPriority/2-web-constraints-import.project new file mode 100644 index 00000000000..ccc8878de7e --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-web-constraints-import.project @@ -0,0 +1,5 @@ +packages: . +allow-newer: hashable:* +constraints: hashable ==1.4.2.0 +import: stackage-web.config +import: with-ghc.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-web-import-constraints.project b/cabal-testsuite/PackageTests/VersionPriority/2-web-import-constraints.project new file mode 100644 index 00000000000..a953355471d --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-web-import-constraints.project @@ -0,0 +1,5 @@ +packages: . +allow-newer: hashable:* +import: stackage-web.config +constraints: hashable ==1.4.2.0 +import: with-ghc.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-web.out b/cabal-testsuite/PackageTests/VersionPriority/2-web.out new file mode 100644 index 00000000000..0b6fd6cf30f --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-web.out @@ -0,0 +1,22 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /2-web-constraints-import.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config project-stackage/nightly-2023-12-07.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /2-web-import-constraints.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config project-stackage/nightly-2023-12-07.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) diff --git a/cabal-testsuite/PackageTests/VersionPriority/2-web.test.hs b/cabal-testsuite/PackageTests/VersionPriority/2-web.test.hs new file mode 100644 index 00000000000..d88328b436e --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/2-web.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +testVersionWin project = + withProjectFile project $ do + fails $ cabal "v2-build" ["--dry-run"] + +main = cabalTest . withRepo "repo" $ do + testVersionWin "2-web-constraints-import.project" + testVersionWin "2-web-import-constraints.project" diff --git a/cabal-testsuite/PackageTests/VersionPriority/3-web-constraints-import.project b/cabal-testsuite/PackageTests/VersionPriority/3-web-constraints-import.project new file mode 100644 index 00000000000..b9d046a4c59 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/3-web-constraints-import.project @@ -0,0 +1,5 @@ +packages: . +allow-newer: hashable:* +constraints: hashable ==1.4.2.0 +import: hop-web.config +import: with-ghc.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/3-web-import-constraints.project b/cabal-testsuite/PackageTests/VersionPriority/3-web-import-constraints.project new file mode 100644 index 00000000000..b37fb3bbb72 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/3-web-import-constraints.project @@ -0,0 +1,5 @@ +packages: . +allow-newer: hashable:* +import: hop-web.config +constraints: hashable ==1.4.2.0 +import: with-ghc.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/3-web.out b/cabal-testsuite/PackageTests/VersionPriority/3-web.out new file mode 100644 index 00000000000..13d974b8605 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/3-web.out @@ -0,0 +1,22 @@ +# cabal v2-update +Downloading the latest package list from test-local-repo +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /3-web-constraints-import.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config project-stackage/nightly-2023-12-07.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) +# cabal v2-build +Resolving dependencies... +Error: [Cabal-7107] +Could not resolve dependencies: +[__0] trying: cabal-version-override-0.1.0.0 (user goal) +[__1] next goal: hashable (dependency of cabal-version-override) +[__1] rejecting: hashable-1.4.3.0 (constraint from project config /3-web-import-constraints.project requires ==1.4.2.0) +[__1] rejecting: hashable-1.4.2.0 (constraint from project config project-stackage/nightly-2023-12-07.config requires ==1.4.3.0) +[__1] fail (backjumping, conflict set: cabal-version-override, hashable) +After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: hashable (3), cabal-version-override (2) diff --git a/cabal-testsuite/PackageTests/VersionPriority/3-web.test.hs b/cabal-testsuite/PackageTests/VersionPriority/3-web.test.hs new file mode 100644 index 00000000000..984165dcf20 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/3-web.test.hs @@ -0,0 +1,9 @@ +import Test.Cabal.Prelude + +testVersionWin project = + withProjectFile project $ do + fails $ cabal "v2-build" ["--dry-run"] + +main = cabalTest . withRepo "repo" $ do + testVersionWin "3-web-constraints-import.project" + testVersionWin "3-web-import-constraints.project" diff --git a/cabal-testsuite/PackageTests/VersionPriority/README.md b/cabal-testsuite/PackageTests/VersionPriority/README.md new file mode 100644 index 00000000000..8f76f53f3ac --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/README.md @@ -0,0 +1,51 @@ +# Version Priority Tests + +The `1-` prefix projects have an import depth of 1, the `2-` prefix projects +have a depth of 2 and `3-` prefix has depth 3. The `0-` prefix project have any +imports. Only projects have the `.project` extension. Imported configuration +has a `.config` extension. + +- *0-local.project* + ``` + . + └── 0-local.project + ``` + +- *1-local.project* + ``` + . + └── 1-local.project + └── stackage-local.config + ``` + +- *2-local.project* + ``` + . + └── 2-local.project + └── hop-local.config + └── stackage-local.config + ``` + +- *1-web.project* + ``` + . + └── 1-web.project + └── https://www.stackage.org/nightly-2023-12-07/cabal.config + ``` + +- *2-web.project* + ``` + . + └── 2-web.project + └── stackage-web.config + └── https://www.stackage.org/nightly-2023-12-07/cabal.config + ``` + +- *3-web.project* + ``` + . + └── 3-web.project + └── hop-web.config + └── stackage-web.config + └── https://www.stackage.org/nightly-2023-12-07/cabal.config + ``` diff --git a/cabal-testsuite/PackageTests/VersionPriority/app/Main.hs b/cabal-testsuite/PackageTests/VersionPriority/app/Main.hs new file mode 100644 index 00000000000..a170ab7732d --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/app/Main.hs @@ -0,0 +1,6 @@ +module Main where + +import Data.Hashable + +main :: IO () +main = print $ hash "foo" diff --git a/cabal-testsuite/PackageTests/VersionPriority/cabal-version-override.cabal b/cabal-testsuite/PackageTests/VersionPriority/cabal-version-override.cabal new file mode 100644 index 00000000000..181bdef8e7d --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/cabal-version-override.cabal @@ -0,0 +1,17 @@ +cabal-version: 3.0 +name: cabal-version-override +version: 0.1.0.0 +license: MPL-2.0 +author: Phil de Joux +category: Development +build-type: Simple + +common warnings + ghc-options: -Wall + +executable cabal-version-override + import: warnings + main-is: Main.hs + build-depends: base, hashable + hs-source-dirs: app + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/VersionPriority/hop-local.config b/cabal-testsuite/PackageTests/VersionPriority/hop-local.config new file mode 100644 index 00000000000..fc9024b3bb5 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/hop-local.config @@ -0,0 +1 @@ +import: stackage-local.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/hop-web.config b/cabal-testsuite/PackageTests/VersionPriority/hop-web.config new file mode 100644 index 00000000000..848f0c5920d --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/hop-web.config @@ -0,0 +1 @@ +import: stackage-web.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/project-stackage/nightly-2023-12-07.config b/cabal-testsuite/PackageTests/VersionPriority/project-stackage/nightly-2023-12-07.config new file mode 100644 index 00000000000..92da73baf11 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/project-stackage/nightly-2023-12-07.config @@ -0,0 +1,3334 @@ +-- NOTE: Due to revisions, this file may not work. See: +-- https://github.com/fpco/stackage-server/issues/232 + +-- Stackage snapshot from: http://www.stackage.org/snapshot/nightly-2023-12-07 +-- Please place this file next to your .cabal file as cabal.config +-- To only use tested packages, uncomment the following line: +-- remote-repo: stackage-nightly-2023-12-07:http://www.stackage.org/nightly-2023-12-07 +with-compiler: ghc-9.6.3 +constraints: abstract-deque ==0.3, + abstract-deque-tests ==0.3, + abstract-par ==0.3.3, + AC-Angle ==1.0, + acc ==0.2.0.3, + ace ==0.6, + acid-state ==0.16.1.3, + action-permutations ==0.0.0.1, + active ==0.2.0.18, + ad ==4.5.4, + ad-delcont ==0.5.0.0, + adjunctions ==4.4.2, + adler32 ==0.1.2.0, + aern2-mp ==0.2.15.1, + aern2-real ==0.2.15, + aeson ==2.1.2.1, + aeson-attoparsec ==0.0.0, + aeson-casing ==0.2.0.0, + aeson-combinators ==0.1.1.0, + aeson-diff ==1.1.0.13, + aeson-extra ==0.5.1.3, + aeson-generic-compat ==0.0.2.0, + aeson-iproute ==0.3.0, + aeson-optics ==1.2.1, + aeson-picker ==0.1.0.6, + aeson-pretty ==0.8.10, + aeson-qq ==0.8.4, + aeson-schemas ==1.4.1.0, + aeson-typescript ==0.6.1.0, + aeson-unqualified-ast ==1.0.0.3, + aeson-value-parser ==0.19.7.1, + aeson-warning-parser ==0.1.0, + aeson-yak ==0.1.1.3, + aeson-yaml ==1.1.0.1, + Agda ==2.6.4.1, + agda2lagda ==0.2023.6.9, + agreeing ==0.2.2.0, + alarmclock ==0.7.0.6, + alex ==3.4.0.1, + alex-meta ==0.3.0.13, + alex-tools ==0.6.1, + algebra ==4.3.1, + algebraic-graphs ==0.7, + align-audio ==0.0.0.1, + Allure ==0.11.0.0, + almost-fix ==0.0.2, + alsa-core ==0.5.0.1, + alsa-mixer ==0.3.0, + alsa-pcm ==0.6.1.1, + alsa-seq ==0.6.0.9, + alternative-vector ==0.0.0, + alternators ==1.0.0.0, + ALUT ==2.4.0.3, + amazonka ==2.0, + amazonka-accessanalyzer ==2.0, + amazonka-account ==2.0, + amazonka-amp ==2.0, + amazonka-amplify ==2.0, + amazonka-amplifybackend ==2.0, + amazonka-amplifyuibuilder ==2.0, + amazonka-apigateway ==2.0, + amazonka-apigatewaymanagementapi ==2.0, + amazonka-apigatewayv2 ==2.0, + amazonka-appconfig ==2.0, + amazonka-appconfigdata ==2.0, + amazonka-appflow ==2.0, + amazonka-appintegrations ==2.0, + amazonka-application-autoscaling ==2.0, + amazonka-applicationcostprofiler ==2.0, + amazonka-application-insights ==2.0, + amazonka-appmesh ==2.0, + amazonka-apprunner ==2.0, + amazonka-appstream ==2.0, + amazonka-arc-zonal-shift ==2.0, + amazonka-athena ==2.0, + amazonka-auditmanager ==2.0, + amazonka-autoscaling ==2.0, + amazonka-backup ==2.0, + amazonka-backup-gateway ==2.0, + amazonka-backupstorage ==2.0, + amazonka-billingconductor ==2.0, + amazonka-braket ==2.0, + amazonka-budgets ==2.0, + amazonka-certificatemanager ==2.0, + amazonka-chime ==2.0, + amazonka-chime-sdk-identity ==2.0, + amazonka-chime-sdk-media-pipelines ==2.0, + amazonka-chime-sdk-meetings ==2.0, + amazonka-chime-sdk-messaging ==2.0, + amazonka-chime-sdk-voice ==2.0, + amazonka-cloudcontrol ==2.0, + amazonka-cloudformation ==2.0, + amazonka-cloudfront ==2.0, + amazonka-cloudhsm ==2.0, + amazonka-cloudsearch ==2.0, + amazonka-cloudsearch-domains ==2.0, + amazonka-cloudtrail ==2.0, + amazonka-cloudwatch ==2.0, + amazonka-cloudwatch-events ==2.0, + amazonka-cloudwatch-logs ==2.0, + amazonka-codeartifact ==2.0, + amazonka-codebuild ==2.0, + amazonka-codecommit ==2.0, + amazonka-codedeploy ==2.0, + amazonka-codeguruprofiler ==2.0, + amazonka-codeguru-reviewer ==2.0, + amazonka-codepipeline ==2.0, + amazonka-codestar-connections ==2.0, + amazonka-codestar-notifications ==2.0, + amazonka-cognito-identity ==2.0, + amazonka-cognito-idp ==2.0, + amazonka-cognito-sync ==2.0, + amazonka-comprehendmedical ==2.0, + amazonka-compute-optimizer ==2.0, + amazonka-config ==2.0, + amazonka-connectcampaigns ==2.0, + amazonka-connectcases ==2.0, + amazonka-connect-contact-lens ==2.0, + amazonka-connectparticipant ==2.0, + amazonka-controltower ==2.0, + amazonka-core ==2.0, + amazonka-customer-profiles ==2.0, + amazonka-databrew ==2.0, + amazonka-dataexchange ==2.0, + amazonka-datapipeline ==2.0, + amazonka-datasync ==2.0, + amazonka-detective ==2.0, + amazonka-devicefarm ==2.0, + amazonka-devops-guru ==2.0, + amazonka-directconnect ==2.0, + amazonka-discovery ==2.0, + amazonka-dlm ==2.0, + amazonka-dms ==2.0, + amazonka-docdb ==2.0, + amazonka-docdb-elastic ==2.0, + amazonka-drs ==2.0, + amazonka-ds ==2.0, + amazonka-dynamodb ==2.0, + amazonka-dynamodb-streams ==2.0, + amazonka-ebs ==2.0, + amazonka-ec2 ==2.0, + amazonka-ec2-instance-connect ==2.0, + amazonka-ecr ==2.0, + amazonka-ecr-public ==2.0, + amazonka-ecs ==2.0, + amazonka-efs ==2.0, + amazonka-eks ==2.0, + amazonka-elasticache ==2.0, + amazonka-elasticbeanstalk ==2.0, + amazonka-elastic-inference ==2.0, + amazonka-elasticsearch ==2.0, + amazonka-elastictranscoder ==2.0, + amazonka-elb ==2.0, + amazonka-elbv2 ==2.0, + amazonka-emr ==2.0, + amazonka-emr-containers ==2.0, + amazonka-emr-serverless ==2.0, + amazonka-evidently ==2.0, + amazonka-finspace ==2.0, + amazonka-finspace-data ==2.0, + amazonka-fis ==2.0, + amazonka-forecast ==2.0, + amazonka-forecastquery ==2.0, + amazonka-frauddetector ==2.0, + amazonka-fsx ==2.0, + amazonka-gamelift ==2.0, + amazonka-gamesparks ==2.0, + amazonka-glacier ==2.0, + amazonka-globalaccelerator ==2.0, + amazonka-glue ==2.0, + amazonka-grafana ==2.0, + amazonka-greengrassv2 ==2.0, + amazonka-groundstation ==2.0, + amazonka-health ==2.0, + amazonka-healthlake ==2.0, + amazonka-honeycode ==2.0, + amazonka-iam ==2.0, + amazonka-identitystore ==2.0, + amazonka-imagebuilder ==2.0, + amazonka-importexport ==2.0, + amazonka-inspector ==2.0, + amazonka-inspector2 ==2.0, + amazonka-iot ==2.0, + amazonka-iot1click-devices ==2.0, + amazonka-iot1click-projects ==2.0, + amazonka-iot-dataplane ==2.0, + amazonka-iotdeviceadvisor ==2.0, + amazonka-iotevents ==2.0, + amazonka-iotevents-data ==2.0, + amazonka-iotfleethub ==2.0, + amazonka-iotfleetwise ==2.0, + amazonka-iot-roborunner ==2.0, + amazonka-iotsecuretunneling ==2.0, + amazonka-iotsitewise ==2.0, + amazonka-iotthingsgraph ==2.0, + amazonka-iottwinmaker ==2.0, + amazonka-iotwireless ==2.0, + amazonka-ivs ==2.0, + amazonka-ivschat ==2.0, + amazonka-kafka ==2.0, + amazonka-kafkaconnect ==2.0, + amazonka-kendra ==2.0, + amazonka-keyspaces ==2.0, + amazonka-kinesis ==2.0, + amazonka-kinesis-analytics ==2.0, + amazonka-kinesisanalyticsv2 ==2.0, + amazonka-kinesis-firehose ==2.0, + amazonka-kinesis-video-signaling ==2.0, + amazonka-kinesis-video-webrtc-storage ==2.0, + amazonka-kms ==2.0, + amazonka-lakeformation ==2.0, + amazonka-lambda ==2.0, + amazonka-lexv2-models ==2.0, + amazonka-license-manager ==2.0, + amazonka-license-manager-linux-subscriptions ==2.0, + amazonka-license-manager-user-subscriptions ==2.0, + amazonka-lightsail ==2.0, + amazonka-location ==2.0, + amazonka-lookoutequipment ==2.0, + amazonka-lookoutmetrics ==2.0, + amazonka-lookoutvision ==2.0, + amazonka-m2 ==2.0, + amazonka-macie ==2.0, + amazonka-maciev2 ==2.0, + amazonka-managedblockchain ==2.0, + amazonka-marketplace-analytics ==2.0, + amazonka-marketplace-catalog ==2.0, + amazonka-marketplace-metering ==2.0, + amazonka-mediaconnect ==2.0, + amazonka-mediapackage-vod ==2.0, + amazonka-mediatailor ==2.0, + amazonka-memorydb ==2.0, + amazonka-mgn ==2.0, + amazonka-migrationhub-config ==2.0, + amazonka-migrationhuborchestrator ==2.0, + amazonka-migration-hub-refactor-spaces ==2.0, + amazonka-migrationhubstrategy ==2.0, + amazonka-ml ==2.0, + amazonka-mwaa ==2.0, + amazonka-neptune ==2.0, + amazonka-network-firewall ==2.0, + amazonka-networkmanager ==2.0, + amazonka-nimble ==2.0, + amazonka-oam ==2.0, + amazonka-omics ==2.0, + amazonka-opensearch ==2.0, + amazonka-opensearchserverless ==2.0, + amazonka-opsworks ==2.0, + amazonka-opsworks-cm ==2.0, + amazonka-outposts ==2.0, + amazonka-panorama ==2.0, + amazonka-personalize ==2.0, + amazonka-personalize-events ==2.0, + amazonka-personalize-runtime ==2.0, + amazonka-pi ==2.0, + amazonka-pinpoint ==2.0, + amazonka-pinpoint-email ==2.0, + amazonka-pinpoint-sms-voice ==2.0, + amazonka-pinpoint-sms-voice-v2 ==2.0, + amazonka-pipes ==2.0, + amazonka-polly ==2.0, + amazonka-privatenetworks ==2.0, + amazonka-proton ==2.0, + amazonka-qldb ==2.0, + amazonka-qldb-session ==2.0, + amazonka-quicksight ==2.0, + amazonka-ram ==2.0, + amazonka-rbin ==2.0, + amazonka-rds ==2.0, + amazonka-rds-data ==2.0, + amazonka-redshift ==2.0, + amazonka-redshift-data ==2.0, + amazonka-redshift-serverless ==2.0, + amazonka-rekognition ==2.0, + amazonka-resiliencehub ==2.0, + amazonka-resource-explorer-v2 ==2.0, + amazonka-robomaker ==2.0, + amazonka-rolesanywhere ==2.0, + amazonka-route53 ==2.0, + amazonka-route53-domains ==2.0, + amazonka-route53-recovery-cluster ==2.0, + amazonka-route53-recovery-control-config ==2.0, + amazonka-route53-recovery-readiness ==2.0, + amazonka-route53resolver ==2.0, + amazonka-rum ==2.0, + amazonka-s3 ==2.0, + amazonka-s3outposts ==2.0, + amazonka-sagemaker-a2i-runtime ==2.0, + amazonka-sagemaker-edge ==2.0, + amazonka-sagemaker-featurestore-runtime ==2.0, + amazonka-sagemaker-geospatial ==2.0, + amazonka-sagemaker-metrics ==2.0, + amazonka-savingsplans ==2.0, + amazonka-scheduler ==2.0, + amazonka-schemas ==2.0, + amazonka-sdb ==2.0, + amazonka-securityhub ==2.0, + amazonka-securitylake ==2.0, + amazonka-servicecatalog ==2.0, + amazonka-servicecatalog-appregistry ==2.0, + amazonka-service-quotas ==2.0, + amazonka-ses ==2.0, + amazonka-sesv2 ==2.0, + amazonka-shield ==2.0, + amazonka-signer ==2.0, + amazonka-simspaceweaver ==2.0, + amazonka-sms ==2.0, + amazonka-sms-voice ==2.0, + amazonka-snowball ==2.0, + amazonka-snow-device-management ==2.0, + amazonka-sns ==2.0, + amazonka-sqs ==2.0, + amazonka-ssm ==2.0, + amazonka-ssm-contacts ==2.0, + amazonka-ssm-incidents ==2.0, + amazonka-ssm-sap ==2.0, + amazonka-sso ==2.0, + amazonka-sso-admin ==2.0, + amazonka-sso-oidc ==2.0, + amazonka-stepfunctions ==2.0, + amazonka-storagegateway ==2.0, + amazonka-sts ==2.0, + amazonka-support ==2.0, + amazonka-support-app ==2.0, + amazonka-swf ==2.0, + amazonka-synthetics ==2.0, + amazonka-test ==2.0, + amazonka-textract ==2.0, + amazonka-timestream-query ==2.0, + amazonka-timestream-write ==2.0, + amazonka-transfer ==2.0, + amazonka-voice-id ==2.0, + amazonka-waf ==2.0, + amazonka-wafv2 ==2.0, + amazonka-wellarchitected ==2.0, + amazonka-wisdom ==2.0, + amazonka-worklink ==2.0, + amazonka-workmailmessageflow ==2.0, + amazonka-workspaces ==2.0, + amazonka-workspaces-web ==2.0, + amazonka-xray ==2.0, + amqp ==0.22.2, + amqp-utils ==0.6.4.0, + annotated-exception ==0.2.0.5, + annotated-wl-pprint ==0.7.0, + ansi-terminal ==1.0, + ansi-terminal-game ==1.9.2.0, + ansi-terminal-types ==0.11.5, + ansi-wl-pprint ==1.0.2, + ANum ==0.2.0.2, + aos-signature ==0.1.1, + apecs ==0.9.5, + apecs-gloss ==0.2.4, + apecs-physics ==0.4.6, + api-field-json-th ==0.1.0.2, + ap-normalize ==0.1.0.1, + appar ==0.1.8, + appendful ==0.1.0.0, + appendful-persistent ==0.1.0.1, + appendmap ==0.1.5, + apply-refact ==0.13.0.0, + apportionment ==0.0.0.4, + approximate ==0.3.5, + approximate-equality ==1.1.0.2, + arbor-lru-cache ==0.1.1.1, + arithmoi ==0.13.0.0, + array installed, + array-memoize ==0.6.0, + arrow-extras ==0.1.0.1, + arrows ==0.4.4.2, + ascii ==1.7.0.1, + ascii-case ==1.0.1.3, + ascii-caseless ==0.0.0.1, + ascii-char ==1.0.1.0, + ascii-group ==1.0.0.16, + ascii-numbers ==1.2.0.1, + ascii-predicates ==1.0.1.3, + ascii-progress ==0.3.3.0, + ascii-superset ==1.3.0.1, + ascii-th ==1.2.0.1, + asn1-encoding ==0.9.6, + asn1-parse ==0.9.5, + asn1-types ==0.3.4, + assert-failure ==0.1.3.0, + assoc ==1.1, + astro ==0.4.3.0, + async ==2.2.5, + async-extra ==0.2.0.0, + async-pool ==0.9.2, + async-refresh ==0.3.0.0, + async-refresh-tokens ==0.4.0.0, + atom-basic ==0.2.5, + atom-conduit ==0.9.0.1, + atomic-counter ==0.1.2.1, + atomic-primops ==0.8.4, + atomic-write ==0.2.0.7, + attoparsec ==0.14.4, + attoparsec-aeson ==2.1.0.0, + attoparsec-base64 ==0.0.0, + attoparsec-binary ==0.2, + attoparsec-data ==1.0.5.3, + attoparsec-expr ==0.1.1.2, + attoparsec-framer ==0.1.0.1, + attoparsec-iso8601 ==1.1.0.1, + attoparsec-path ==0.0.0.1, + attoparsec-run ==0.0.2.0, + attoparsec-time ==1.0.3, + attoparsec-uri ==0.0.9, + audacity ==0.0.2.1, + authenticate ==1.3.5.2, + authenticate-oauth ==1.7, + autodocodec ==0.2.2.0, + autodocodec-openapi3 ==0.2.1.1, + autodocodec-schema ==0.1.0.3, + autodocodec-yaml ==0.2.0.3, + autoexporter ==2.0.0.9, + auto-update ==0.1.6, + avro ==0.6.1.2, + aws ==0.24.1, + aws-cloudfront-signed-cookies ==0.2.0.12, + aws-sns-verify ==0.0.0.3, + aws-xray-client ==0.1.0.2, + aws-xray-client-persistent ==0.1.0.5, + aws-xray-client-wai ==0.1.0.2, + backprop ==0.2.6.5, + backtracking ==0.1.0, + bank-holidays-england ==0.2.0.9, + barbies ==2.0.5.0, + barrier ==0.1.1, + base installed, + base16 ==1.0, + base16-bytestring ==1.0.2.0, + base32 ==0.4, + base32string ==0.9.1, + base58-bytestring ==0.1.0, + base58string ==0.10.0, + base64 ==0.4.2.4, + base64-bytestring ==1.2.1.0, + base64-bytestring-type ==1.0.1, + base64-string ==0.2, + base-compat ==0.13.1, + base-compat-batteries ==0.13.1, + basement ==0.0.16, + base-orphans ==0.9.1, + base-prelude ==1.6.1.1, + base-unicode-symbols ==0.2.4.2, + basic-prelude ==0.7.0, + battleship-combinatorics ==0.0.1, + bazel-runfiles ==0.12, + bbdb ==0.8, + bcp47 ==0.2.0.6, + bcp47-orphans ==0.1.0.6, + bcrypt ==0.0.11, + beam-core ==0.10.1.0, + bech32 ==1.1.4, + bech32-th ==1.1.1, + benchpress ==0.2.2.23, + bencode ==0.6.1.1, + benri-hspec ==0.1.0.1, + between ==0.11.0.0, + bibtex ==0.1.0.7, + bifunctor-classes-compat ==0.1, + bifunctors ==5.6.1, + bimap ==0.5.0, + bimaps ==0.1.0.2, + bin ==0.1.3, + binance-exports ==0.1.2.0, + binary installed, + binary-conduit ==1.3.1, + binaryen ==0.0.6.0, + binary-generic-combinators ==0.4.4.0, + binary-ieee754 ==0.1.0.0, + binary-instances ==1.0.4, + binary-list ==1.1.1.2, + binary-orphans ==1.0.4.1, + binary-parser ==0.5.7.4, + binary-search ==2.0.0, + binary-shared ==0.8.3, + binary-tagged ==0.3.1, + bindings-DSL ==1.0.25, + bindings-GLFW ==3.3.2.0, + bindings-libzip ==1.0.1, + bindings-uname ==0.1, + BiobaseEnsembl ==0.2.0.1, + BiobaseNewick ==0.0.0.2, + bitarray ==0.0.1.1, + bits ==0.6, + bitset-word8 ==0.1.1.2, + bitvec ==1.1.5.0, + bitwise-enum ==1.0.1.2, + blake2 ==0.3.0.1, + Blammo ==1.1.2.1, + blank-canvas ==0.7.4, + blanks ==0.5.0, + blas-carray ==0.1.0.2, + blas-comfort-array ==0.0.0.3, + blas-ffi ==0.1, + blas-hs ==0.1.1.0, + blaze-bootstrap ==0.1.0.1, + blaze-builder ==0.4.2.3, + blaze-colonnade ==1.2.2.1, + blaze-html ==0.9.1.2, + blaze-markup ==0.8.3.0, + blaze-svg ==0.3.7, + blaze-textual ==0.2.3.1, + bloodhound ==0.21.0.0, + bloomfilter ==2.0.1.2, + bm ==0.2.0.0, + bmp ==1.2.6.3, + bnb-staking-csvs ==0.2.1.0, + BNFC ==2.9.5, + BNFC-meta ==0.6.1, + board-games ==0.4, + bodhi ==0.1.0, + boltzmann-samplers ==0.1.1.0, + Boolean ==0.2.4, + boolsimplifier ==0.1.8, + boomerang ==1.4.9, + boomwhacker ==0.0.1, + bordacount ==0.1.0.0, + boring ==0.2.1, + bound ==2.0.7, + BoundedChan ==1.0.3.0, + bounded-qsem ==0.1.0.1, + bounded-queue ==1.0.0, + boundingboxes ==0.2.3, + box ==0.9.2.1, + boxes ==0.1.5, + breakpoint ==0.1.3.0, + brick ==1.10, + broadcast-chan ==0.2.1.2, + brotli ==0.0.0.1, + brotli-streams ==0.0.0.0, + bsb-http-chunked ==0.0.0.4, + bson ==0.4.0.1, + bson-lens ==0.1.1, + btrfs ==0.2.1.0, + buffer-builder ==0.2.4.8, + buffer-pipe ==0.0, + bugsnag ==1.0.0.1, + bugsnag-haskell ==0.0.4.4, + bugsnag-hs ==0.2.0.12, + bugsnag-wai ==1.0.0.1, + bugsnag-yesod ==1.0.1.0, + bugzilla-redhat ==1.0.1.1, + burrito ==2.0.1.7, + bv ==0.5, + bv-little ==1.3.2, + byteable ==0.1.1, + bytebuild ==0.3.14.0, + byte-count-reader ==0.10.1.10, + bytedump ==1.0, + bytehash ==0.1.1.0, + byte-order ==0.1.3.0, + byteorder ==1.0.4, + bytes ==0.17.3, + byteset ==0.1.1.1, + byteslice ==0.2.11.1, + bytesmith ==0.3.10.0, + bytestring installed, + bytestring-builder ==0.10.8.2.0, + bytestring-conversion ==0.3.2, + bytestring-lexing ==0.5.0.11, + bytestring-strict-builder ==0.4.5.7, + bytestring-to-vector ==0.3.0.1, + bytestring-tree-builder ==0.2.7.11, + bytestring-trie ==0.2.7.2, + bz2 ==1.0.1.0, + bzlib ==0.5.1.0, + bzlib-conduit ==0.3.0.2, + c14n ==0.1.0.3, + c2hs ==0.28.8, + Cabal installed, + cabal2nix ==2.19.1, + cabal2spec ==2.7.0, + cabal-appimage ==0.4.0.2, + cabal-clean ==0.2.20230609, + cabal-debian ==5.2.2, + cabal-doctest ==1.0.9, + cabal-file ==0.1.1, + cabal-install ==3.10.2.1, + cabal-install-solver ==3.10.2.1, + cabal-plan ==0.7.3.0, + cabal-rpm ==2.1.5, + cabal-sort ==0.1.2, + Cabal-syntax installed, + cache ==0.1.3.0, + cached-json-file ==0.1.1, + cacophony ==0.10.1, + cairo ==0.13.10.0, + calendar-recycling ==0.0.0.1, + call-alloy ==0.4.0.3, + calligraphy ==0.1.6, + call-plantuml ==0.0.1.3, + call-stack ==0.4.0, + can-i-haz ==0.3.1.1, + capability ==0.5.0.1, + ca-province-codes ==1.0.0.0, + cardano-coin-selection ==1.0.1, + carray ==0.1.6.8, + casa-client ==0.0.2, + casa-types ==0.0.2, + cased ==0.1.0.0, + case-insensitive ==1.2.1.0, + cases ==0.1.4.2, + casing ==0.1.4.1, + cassava ==0.5.3.0, + cassava-conduit ==0.6.5, + cassava-megaparsec ==2.0.4, + cast ==0.1.0.2, + cborg ==0.2.10.0, + cborg-json ==0.2.6.0, + cdar-mBound ==0.1.0.4, + c-enum ==0.1.1.3, + cereal ==0.5.8.3, + cereal-conduit ==0.8.0, + cereal-text ==0.1.0.2, + cereal-unordered-containers ==0.1, + cereal-vector ==0.2.0.1, + cfenv ==0.1.0.0, + cgi ==3001.5.0.1, + chan ==0.0.4.1, + ChannelT ==0.0.0.7, + character-cases ==0.1.0.6, + charset ==0.3.10, + charsetdetect-ae ==1.1.0.4, + Chart ==1.9.5, + Chart-cairo ==1.9.4.1, + Chart-diagrams ==1.9.5.1, + chart-svg ==0.5.2.0, + ChasingBottoms ==1.3.1.12, + check-email ==1.0.2, + checkers ==0.6.0, + checksum ==0.0.0.1, + chimera ==0.3.4.0, + choice ==0.2.3, + chronologique ==0.3.1.3, + chronos ==1.1.5.1, + chronos-bench ==0.2.0.2, + chunked-data ==0.3.1, + cipher-aes ==0.2.11, + cipher-camellia ==0.0.2, + cipher-rc4 ==0.1.4, + circle-packing ==0.1.0.6, + circular ==0.4.0.3, + citeproc ==0.8.1, + clash-prelude ==1.8.1, + classy-prelude ==1.5.0.3, + classy-prelude-conduit ==1.5.0, + classy-prelude-yesod ==1.5.0, + clay ==0.14.0, + cleff ==0.3.3.0, + clientsession ==0.9.2.0, + Clipboard ==2.3.2.0, + clock ==0.8.4, + closed ==0.2.0.2, + clumpiness ==0.17.0.2, + ClustalParser ==1.3.0, + cmark ==0.6.1, + cmark-gfm ==0.2.6, + cmark-lucid ==0.1.0.0, + cmdargs ==0.10.22, + codec-beam ==0.2.0, + code-conjure ==0.5.6, + code-page ==0.2.1, + coinor-clp ==0.0.0.1, + cointracking-imports ==0.1.0.2, + collect-errors ==0.1.5.0, + co-log ==0.6.0.2, + co-log-concurrent ==0.5.1.0, + co-log-core ==0.3.2.1, + co-log-polysemy ==0.0.1.4, + colonnade ==1.2.0.2, + Color ==0.3.3, + colorful-monoids ==0.2.1.3, + colorize-haskell ==1.0.1, + colour ==2.3.6, + colourista ==0.1.0.2, + columnar ==1.0.0.0, + combinatorial ==0.1.1, + comfort-array ==0.5.3, + comfort-array-shape ==0.0, + comfort-blas ==0.0.1, + comfort-fftw ==0.0.0.1, + comfort-glpk ==0.1, + comfort-graph ==0.0.4, + commonmark ==0.2.4, + commonmark-extensions ==0.2.4, + commonmark-pandoc ==0.2.1.3, + commutative ==0.0.2, + commutative-semigroups ==0.1.0.1, + comonad ==5.0.8, + compact ==0.2.0.0, + compactmap ==0.1.4.3, + companion ==0.1.0, + compdata ==0.13.1, + compensated ==0.8.3, + compiler-warnings ==0.1.0, + componentm ==0.0.0.2, + componentm-devel ==0.0.0.2, + composable-associations ==0.1.0.0, + composite-base ==0.8.2.1, + composite-binary ==0.8.2.2, + composite-hashable ==0.8.2.2, + composite-tuple ==0.1.2.0, + composite-xstep ==0.1.0.0, + composition ==1.0.2.2, + composition-extra ==2.1.0, + composition-prelude ==3.0.0.2, + concise ==0.1.0.1, + concurrency ==1.11.0.3, + concurrent-extra ==0.7.0.12, + concurrent-output ==1.10.20, + concurrent-split ==0.0.1.1, + concurrent-supply ==0.1.8, + cond ==0.5.1, + conduit ==1.3.5, + conduit-aeson ==0.1.0.1, + conduit-combinators ==1.3.0, + conduit-concurrent-map ==0.1.3, + conduit-extra ==1.3.6, + conduit-parse ==0.2.1.1, + conduit-zstd ==0.0.2.0, + conferer ==1.1.0.0, + conferer-aeson ==1.1.0.2, + conferer-warp ==1.1.0.1, + config-ini ==0.2.7.0, + configuration-tools ==0.7.0, + configurator ==0.3.0.0, + configurator-export ==0.1.0.1, + constraints ==0.13.4, + constraints-extras ==0.4.0.0, + constraint-tuples ==0.1.2, + containers installed, + context ==0.2.0.2, + context-http-client ==0.2.0.2, + context-resource ==0.2.0.2, + context-wai-middleware ==0.2.0.2, + contiguous ==0.6.4.0, + contravariant ==1.5.5, + contravariant-extras ==0.3.5.4, + control-bool ==0.2.1, + control-dsl ==0.2.1.3, + control-monad-free ==0.6.2, + control-monad-omega ==0.3.2, + convertible ==1.1.1.1, + cookie ==0.4.6, + copr-api ==0.2.0, + core-data ==0.3.9.1, + core-program ==0.7.0.0, + core-telemetry ==0.2.9.4, + core-text ==0.3.8.1, + countable ==1.2, + country ==0.2.4.1, + covariance ==0.2.0.1, + cpphs ==1.20.9.1, + cpu ==0.1.2, + cpuinfo ==0.1.0.2, + cql ==4.0.4, + cql-io ==1.1.1, + crackNum ==3.4, + crc32c ==0.1.0, + credential-store ==0.1.2, + criterion ==1.6.3.0, + criterion-measurement ==0.2.1.0, + crypto-api ==0.13.3, + crypto-api-tests ==0.3, + crypto-cipher-tests ==0.0.11, + crypto-cipher-types ==0.0.9, + cryptocompare ==0.1.2, + cryptohash ==0.11.9, + cryptohash-cryptoapi ==0.1.4, + cryptohash-md5 ==0.11.101.0, + cryptohash-sha1 ==0.11.101.0, + cryptohash-sha256 ==0.11.102.1, + cryptohash-sha512 ==0.11.102.0, + crypton ==0.33, + crypton-conduit ==0.2.3, + crypton-connection ==0.3.1, + cryptonite ==0.30, + cryptonite-conduit ==0.2.2, + cryptonite-openssl ==0.7, + crypton-x509 ==1.7.6, + crypton-x509-store ==1.6.9, + crypton-x509-system ==1.6.7, + crypton-x509-validation ==1.6.12, + crypto-pubkey-types ==0.4.3, + crypto-random-api ==0.2.0, + cryptostore ==0.3.0.1, + crypt-sha512 ==0, + csp ==1.4.0, + css-syntax ==0.1.0.1, + css-text ==0.1.3.0, + c-struct ==0.1.3.0, + csv ==0.1.2, + ctrie ==0.2, + cubicbezier ==0.6.0.7, + cubicspline ==0.1.2, + cue-sheet ==2.0.2, + curl ==1.3.8, + currency ==0.2.0.0, + currycarbon ==0.3.0.0, + cursor ==0.3.2.0, + cursor-brick ==0.1.0.1, + cursor-fuzzy-time ==0.0.0.0, + cursor-gen ==0.4.0.0, + cutter ==0.0, + cyclotomic ==1.1.2, + data-accessor ==0.2.3.1, + data-accessor-mtl ==0.2.0.5, + data-accessor-transformers ==0.2.1.8, + data-array-byte ==0.1.0.1, + data-binary-ieee754 ==0.4.4, + data-bword ==0.1.0.2, + data-checked ==0.3, + data-clist ==0.2, + data-default ==0.7.1.1, + data-default-class ==0.1.2.0, + data-default-instances-base ==0.1.0.1, + data-default-instances-bytestring ==0.0.1, + data-default-instances-case-insensitive ==0.0.1, + data-default-instances-containers ==0.0.1, + data-default-instances-dlist ==0.0.1, + data-default-instances-old-locale ==0.0.1, + data-default-instances-unordered-containers ==0.0.1, + data-default-instances-vector ==0.0.1, + data-diverse ==4.7.1.0, + datadog ==0.3.0.0, + data-dword ==0.3.2.1, + data-endian ==0.1.1, + data-fix ==0.3.2, + data-forest ==0.1.0.12, + data-functor-logistic ==0.0, + data-has ==0.4.0.0, + data-hash ==0.2.0.1, + data-interval ==2.1.1, + data-inttrie ==0.1.4, + data-lens-light ==0.1.2.4, + data-memocombinators ==0.5.1, + data-msgpack ==0.0.13, + data-msgpack-types ==0.0.3, + data-or ==1.0.0.7, + data-ordlist ==0.4.7.0, + data-ref ==0.1, + data-reify ==0.6.3, + data-serializer ==0.3.5, + data-sketches ==0.3.1.0, + data-sketches-core ==0.1.0.0, + data-textual ==0.3.0.3, + dataurl ==0.1.0.0, + DAV ==1.3.4, + dbcleaner ==0.1.3, + DBFunctor ==0.1.2.1, + dbus ==1.3.1, + dbus-hslogger ==0.1.0.1, + debian ==4.0.5, + debian-build ==0.10.2.1, + debug-trace-var ==0.2.0, + dec ==0.0.5, + Decimal ==0.5.2, + declarative ==0.5.4, + deepseq installed, + deepseq-generics ==0.2.0.0, + deferred-folds ==0.9.18.6, + dejafu ==2.4.0.5, + dense-linear-algebra ==0.1.0.0, + dependent-map ==0.4.0.0, + dependent-sum ==0.7.2.0, + dependent-sum-template ==0.1.1.1, + depq ==0.4.2, + deque ==0.4.4.1, + deriveJsonNoPrefix ==0.1.0.1, + derive-storable ==0.3.1.0, + derive-topdown ==0.0.3.0, + deriving-aeson ==0.2.9, + deriving-compat ==0.6.5, + deriving-trans ==0.9.1.0, + detour-via-sci ==1.0.0, + df1 ==0.4.2, + dhall ==1.42.1, + dhall-bash ==1.0.41, + di ==1.3, + diagrams ==1.4.1, + diagrams-builder ==0.8.0.6, + diagrams-cairo ==1.4.2.1, + diagrams-canvas ==1.4.1.2, + diagrams-contrib ==1.4.5.1, + diagrams-core ==1.5.1.1, + diagrams-gtk ==1.4, + diagrams-html5 ==1.4.2, + diagrams-lib ==1.4.6, + diagrams-postscript ==1.5.1.1, + diagrams-rasterific ==1.4.2.3, + diagrams-solve ==0.1.3, + diagrams-svg ==1.4.3.1, + dice ==0.1.1, + di-core ==1.0.4, + dictionary-sharing ==0.1.0.0, + di-df1 ==1.2.1, + Diff ==0.4.1, + diff-loc ==0.1.0.0, + digest ==0.0.1.7, + digits ==0.3.1, + di-handle ==1.0.1, + dimensional ==1.5, + di-monad ==1.3.5, + directory installed, + directory-ospath-streaming ==0.1.0.1, + directory-tree ==0.12.1, + direct-sqlite ==2.3.28, + dirichlet ==0.1.0.7, + discount ==0.1.1, + discover-instances ==0.1.0.0, + discrimination ==0.5, + disk-free-space ==0.1.0.1, + distributed-closure ==0.5.0.0, + distributed-static ==0.3.9, + distribution-nixpkgs ==1.7.0.1, + distribution-opensuse ==1.1.4, + distributive ==0.6.2.1, + diversity ==0.8.1.0, + djinn-lib ==0.0.1.4, + dl-fedora ==1.0, + dlist ==1.0, + dlist-instances ==0.1.1.1, + dlist-nonempty ==0.1.3, + dns ==4.2.0, + dockerfile ==0.2.0, + doclayout ==0.4.0.1, + doctemplates ==0.11, + doctest ==0.22.2, + doctest-discover ==0.2.0.0, + doctest-driver-gen ==0.3.0.8, + doctest-exitcode-stdio ==0.0, + doctest-extract ==0.1.1.1, + doctest-lib ==0.1, + doctest-parallel ==0.3.1, + doldol ==0.4.1.2, + do-list ==1.0.1, + domain ==0.1.1.4, + domain-aeson ==0.1.1.1, + domain-cereal ==0.1, + domain-core ==0.1.0.3, + domain-optics ==0.1.0.3, + do-notation ==0.1.0.2, + dot ==0.3, + dotenv ==0.11.0.2, + dotgen ==0.4.3, + dotnet-timespan ==0.0.1.0, + double-conversion ==2.0.4.2, + download ==0.3.2.7, + download-curl ==0.1.4, + DPutils ==0.1.1.0, + drawille ==0.1.3.0, + drifter ==0.3.0, + drifter-postgresql ==0.2.1, + drifter-sqlite ==0.1.0.0, + dsp ==0.2.5.2, + dual-tree ==0.2.3.1, + dublincore-xml-conduit ==0.1.0.3, + duration ==0.2.0.0, + dvorak ==0.1.0.0, + dynamic-state ==0.3.1, + dyre ==0.9.2, + eap ==0.9.0.2, + Earley ==0.13.0.1, + easy-file ==0.2.5, + easy-logger ==0.1.0.7, + Ebnf2ps ==1.0.15, + echo ==0.1.4, + ecstasy ==0.2.1.0, + ed25519 ==0.0.5.0, + edit-distance ==0.2.2.1, + edit-distance-vector ==1.0.0.4, + editor-open ==0.6.0.0, + effectful ==2.3.0.0, + effectful-core ==2.3.0.1, + effectful-plugin ==1.1.0.2, + effectful-th ==1.0.0.1, + egison-pattern-src ==0.2.1.2, + either ==5.0.2, + either-unwrap ==1.1, + ekg-core ==0.1.1.7, + elerea ==2.9.0, + elf ==0.31, + eliminators ==0.9.3, + elm-bridge ==0.8.2, + elm-core-sources ==1.0.0, + elm-export ==0.6.0.1, + elm-street ==0.2.1.1, + elynx ==0.7.2.2, + elynx-markov ==0.7.2.2, + elynx-nexus ==0.7.2.2, + elynx-seq ==0.7.2.2, + elynx-tools ==0.7.2.2, + elynx-tree ==0.7.2.2, + emacs-module ==0.2.1, + email-validate ==2.3.2.19, + emojis ==0.1.3, + enclosed-exceptions ==1.0.3, + ENIG ==0.0.1.0, + entropy ==0.4.1.10, + enummapset ==0.7.2.0, + enumset ==0.1, + enum-subset-generate ==0.1.0.1, + enum-text ==0.5.3.0, + envelope ==0.2.2.0, + envparse ==0.5.0, + envy ==2.1.2.0, + epub-metadata ==5.2, + eq ==4.3, + equal-files ==0.0.5.4, + equational-reasoning ==0.7.0.1, + equivalence ==0.4.1, + erf ==2.0.0.0, + errata ==0.4.0.1, + error ==1.0.0.0, + errorcall-eq-instance ==0.3.0, + error-or ==0.3.0, + error-or-utils ==0.2.0, + errors ==2.3.0, + errors-ext ==0.4.2, + ersatz ==0.5, + esqueleto ==3.5.11.0, + event-list ==0.1.2.1, + every ==0.0.1, + evm-opcodes ==0.1.2, + exact-combinatorics ==0.2.0.11, + exact-pi ==0.5.0.2, + exception-hierarchy ==0.1.0.10, + exception-mtl ==0.4.0.2, + exceptions installed, + exception-transformers ==0.4.0.12, + exception-via ==0.2.0.0, + executable-hash ==0.2.0.4, + executable-path ==0.0.3.1, + exinst ==0.9, + exit-codes ==1.0.0, + exomizer ==1.0.0, + exon ==1.6.1.0, + expiring-cache-map ==0.0.6.1, + explainable-predicates ==0.1.2.4, + explicit-exception ==0.2, + exp-pairs ==0.2.1.0, + express ==1.0.12, + extended-reals ==0.2.4.0, + extensible ==0.9, + extensible-effects ==5.0.0.1, + extensible-exceptions ==0.1.1.4, + extra ==1.7.14, + extractable-singleton ==0.0.1, + extra-data-yj ==0.1.0.0, + extrapolate ==0.4.6, + fail ==4.9.0.0, + FailT ==0.1.2.0, + fakedata ==1.0.3, + fakedata-parser ==0.1.0.0, + fakedata-quickcheck ==0.2.0, + fakefs ==0.3.0.2, + fakepull ==0.3.0.2, + faktory ==1.1.2.5, + fasta ==0.10.4.2, + fast-digits ==0.3.2.0, + fast-logger ==3.2.2, + fast-math ==1.0.2, + fast-myers-diff ==0.0.0, + fb ==2.1.1.1, + fcf-family ==0.2.0.0, + fclabels ==2.0.5.1, + fdo-notify ==0.3.1, + feature-flags ==0.1.0.1, + fedora-dists ==2.1.1, + fedora-haskell-tools ==1.1, + feed ==1.3.2.1, + FenwickTree ==0.1.2.1, + fft ==0.1.8.7, + fftw-ffi ==0.1, + fgl ==5.8.2.0, + fields-json ==0.4.0.0, + file-embed ==0.0.15.0, + file-embed-lzma ==0.0.1, + filelock ==0.1.1.7, + filemanip ==0.3.6.3, + file-modules ==0.1.2.4, + filepath installed, + filepath-bytestring ==1.4.2.1.13, + file-path-th ==0.1.0.0, + filepattern ==0.1.3, + fileplow ==0.1.0.0, + filter-logger ==0.6.0.0, + filtrable ==0.1.6.0, + fin ==0.3, + FindBin ==0.0.5, + fingertree ==0.1.5.0, + finite-typelits ==0.1.6.0, + first-class-families ==0.8.0.1, + fits-parse ==0.3.6, + fitspec ==0.4.10, + fixed ==0.3, + fixed-length ==0.2.3.1, + fixed-vector ==1.2.3.0, + fixed-vector-hetero ==0.6.1.1, + fix-whitespace ==0.1, + flac ==0.2.1, + flac-picture ==0.1.2, + flags-applicative ==0.1.0.3, + flat ==0.6, + flatparse ==0.5.0.1, + flay ==0.4, + flexible-defaults ==0.0.3, + FloatingHex ==0.5, + floatshow ==0.2.4, + flow ==2.0.0.4, + flush-queue ==1.0.0, + fmlist ==0.9.4, + fmt ==0.6.3.0, + fn ==0.3.0.2, + focus ==1.0.3.2, + focuslist ==0.1.1.0, + foldable1-classes-compat ==0.1, + fold-debounce ==0.2.0.11, + foldl ==1.4.15, + folds ==0.7.8, + FontyFruity ==0.5.3.5, + force-layout ==0.4.0.6, + foreign-store ==0.2, + ForestStructures ==0.0.1.1, + forkable-monad ==0.2.0.3, + forma ==1.2.0, + formatn ==0.3.0.1, + format-numbers ==0.1.0.1, + formatting ==7.2.0, + foundation ==0.0.30, + fourmolu ==0.14.0.0, + Frames ==0.7.4.2, + free ==5.2, + free-categories ==0.2.0.2, + freenect ==1.2.1, + freer-par-monad ==0.1.0.0, + freetype2 ==0.2.0, + free-vl ==0.1.4, + friday ==0.2.3.2, + friday-juicypixels ==0.1.2.4, + friendly-time ==0.4.1, + frisby ==0.2.5, + from-sum ==0.2.3.0, + frontmatter ==0.1.0.2, + fsnotify ==0.4.1.0, + funcmp ==1.9, + function-builder ==0.3.0.1, + functor-classes-compat ==2.0.0.2, + fused-effects ==1.1.2.2, + fusion-plugin ==0.2.7, + fusion-plugin-types ==0.1.0, + fuzzcheck ==0.1.1, + fuzzy ==0.1.0.1, + fuzzy-dates ==0.1.1.2, + fuzzyset ==0.3.1, + fuzzy-time ==0.2.0.3, + gauge ==0.2.5, + gd ==3000.7.3, + gdp ==0.0.3.0, + gemini-exports ==0.1.0.0, + general-games ==1.1.1, + generically ==0.1.1, + generic-arbitrary ==1.0.1, + generic-constraints ==1.1.1.1, + generic-data ==1.1.0.0, + generic-data-surgery ==0.3.0.0, + generic-deriving ==1.14.5, + generic-functor ==1.1.0.0, + generic-lens ==2.2.2.0, + generic-lens-core ==2.2.1.0, + generic-monoid ==0.1.0.1, + generic-optics ==2.2.1.0, + GenericPretty ==1.2.2, + generic-random ==1.5.0.1, + generics-eot ==0.4.0.1, + generics-sop ==0.5.1.3, + generics-sop-lens ==0.2.0.1, + genvalidity ==1.1.0.0, + genvalidity-aeson ==1.0.0.1, + genvalidity-appendful ==0.1.0.0, + genvalidity-bytestring ==1.0.0.1, + genvalidity-case-insensitive ==0.0.0.1, + genvalidity-containers ==1.0.0.1, + genvalidity-criterion ==1.1.0.0, + genvalidity-hspec ==1.0.0.3, + genvalidity-hspec-aeson ==1.0.0.0, + genvalidity-hspec-binary ==1.0.0.0, + genvalidity-hspec-cereal ==1.0.0.0, + genvalidity-hspec-hashable ==1.0.0.1, + genvalidity-hspec-optics ==1.0.0.0, + genvalidity-hspec-persistent ==1.0.0.0, + genvalidity-mergeful ==0.3.0.1, + genvalidity-mergeless ==0.3.0.0, + genvalidity-network-uri ==0.0.0.0, + genvalidity-path ==1.0.0.1, + genvalidity-persistent ==1.0.0.2, + genvalidity-property ==1.0.0.0, + genvalidity-scientific ==1.0.0.0, + genvalidity-sydtest ==1.0.0.0, + genvalidity-sydtest-aeson ==1.0.0.0, + genvalidity-sydtest-hashable ==1.0.0.1, + genvalidity-sydtest-lens ==1.0.0.0, + genvalidity-sydtest-persistent ==1.0.0.0, + genvalidity-text ==1.0.0.1, + genvalidity-time ==1.0.0.1, + genvalidity-typed-uuid ==0.1.0.1, + genvalidity-unordered-containers ==1.0.0.1, + genvalidity-uuid ==1.0.0.1, + genvalidity-vector ==1.0.0.0, + geodetics ==0.1.2, + geojson ==4.1.1, + getopt-generics ==0.13.1.0, + ghc installed, + ghc-bignum installed, + ghc-bignum-orphans ==0.1.1, + ghc-boot installed, + ghc-boot-th installed, + ghc-byteorder ==4.11.0.0.10, + ghc-check ==0.5.0.8, + ghc-compact ==0.1.0.0, + ghc-core ==0.5.6, + ghc-events ==0.19.0.1, + ghc-exactprint ==1.7.0.1, + ghc-heap installed, + ghc-hs-meta ==0.1.3.0, + ghcid ==0.8.9, + ghci-hexcalc ==0.1.1.0, + ghcjs-codemirror ==0.0.0.2, + ghcjs-perch ==0.3.3.3, + ghc-lib ==9.6.3.20231121, + ghc-lib-parser ==9.6.3.20231121, + ghc-lib-parser-ex ==9.6.0.2, + ghc-parser ==0.2.6.0, + ghc-paths ==0.1.0.12, + ghc-prim installed, + ghc-syntax-highlighter ==0.0.10.0, + ghc-tcplugins-extra ==0.4.5, + ghc-trace-events ==0.1.2.7, + ghc-typelits-extra ==0.4.6, + ghc-typelits-knownnat ==0.7.10, + ghc-typelits-natnormalise ==0.7.9, + ghc-typelits-presburger ==0.7.2.0, + ghost-buster ==0.1.1.0, + ghostscript-parallel ==0.0, + gi-atk ==2.0.27, + gi-cairo ==1.0.29, + gi-cairo-render ==0.1.2, + gi-dbusmenu ==0.4.13, + gi-dbusmenugtk3 ==0.4.14, + gi-freetype2 ==2.0.4, + gi-gdk ==3.0.28, + gi-gdkpixbuf ==2.0.31, + gi-gdkx11 ==3.0.15, + gi-gio ==2.0.32, + gi-glib ==2.0.29, + gi-gmodule ==2.0.5, + gi-gobject ==2.0.30, + gi-graphene ==1.0.7, + gi-gtk ==3.0.41, + gi-gtk-hs ==0.3.16, + gi-gtksource ==3.0.28, + gi-harfbuzz ==0.0.9, + gi-javascriptcore ==4.0.27, + ginger ==0.10.5.2, + gio ==0.13.10.0, + gi-pango ==1.0.29, + gi-soup ==2.4.28, + git-annex ==10.20231129, + githash ==0.1.7.0, + github ==0.29, + github-release ==2.0.0.9, + github-rest ==1.1.4, + github-types ==0.2.1, + github-webhooks ==0.17.0, + git-lfs ==1.2.1, + gitlib ==3.1.3, + git-mediate ==1.0.9, + gitrev ==1.3.1, + gi-vte ==2.91.31, + gi-webkit2 ==4.0.30, + gi-xlib ==2.0.13, + gl ==0.9, + glabrous ==2.0.6.2, + glasso ==0.1.0, + GLFW-b ==3.3.0.0, + glib ==0.13.10.0, + Glob ==0.10.2, + glob-posix ==0.2.0.1, + gloss ==1.13.2.2, + gloss-algorithms ==1.13.0.3, + gloss-rendering ==1.13.1.2, + glpk-headers ==0.5.1, + GLURaw ==2.0.0.5, + GLUT ==2.7.0.16, + gmail-simple ==0.1.0.5, + gnuplot ==0.5.7, + goldplate ==0.2.1.1, + google-isbn ==1.0.3, + gopher-proxy ==0.1.1.3, + gpolyline ==0.1.0.1, + graph-core ==0.3.0.0, + graphite ==0.10.0.1, + graphql ==1.2.0.1, + graphql-client ==1.2.2, + graphs ==0.7.2, + graphula ==2.0.2.2, + graphviz ==2999.20.1.0, + graph-wrapper ==0.2.6.0, + gravatar ==0.8.1, + gridtables ==0.1.0.0, + groom ==0.1.2.1, + group-by-date ==0.1.0.5, + groups ==0.5.3, + gtk ==0.15.8, + gtk2hs-buildtools ==0.13.10.0, + gtk3 ==0.15.8, + gtk-strut ==0.1.3.2, + guarded-allocation ==0.0.1, + H ==1.0.0, + hackage-cli ==0.1.0.1, + hackage-db ==2.1.3, + hackage-security ==0.6.2.3, + haddock-library ==1.11.0, + haha ==0.3.1.1, + hakyll ==4.16.2.0, + hakyllbars ==1.0.1.0, + hakyll-convert ==0.3.0.4, + hal ==1.0.0.1, + half ==0.3.1, + hall-symbols ==0.1.0.6, + hamilton ==0.1.0.3, + hamlet ==1.2.0, + hamtsolo ==1.0.4, + HandsomeSoup ==0.4.2, + handwriting ==0.1.0.3, + happstack-jmacro ==7.0.12.5, + happstack-server ==7.8.0.2, + happstack-server-tls ==7.2.1.3, + happy ==1.20.1.1, + happy-meta ==0.2.1.0, + HasBigDecimal ==0.2.0.0, + hashable ==1.4.3.0, + hashids ==1.1.0.1, + hashing ==0.1.1.0, + hashmap ==1.3.3, + hashtables ==1.3.1, + haskeline installed, + haskell-gi ==0.26.7, + haskell-gi-base ==0.26.4, + haskell-gi-overloading ==1.0, + haskell-lexer ==1.1.1, + HaskellNet ==0.6.1.2, + haskell-src ==1.0.4, + haskell-src-exts ==1.23.1, + haskell-src-exts-simple ==1.23.0.0, + haskell-src-exts-util ==0.2.5, + haskell-src-meta ==0.8.13, + haskintex ==0.8.0.2, + haskoin-core ==1.0.2, + haskoin-node ==1.0.1, + haskoin-store-data ==1.2.2, + hasktags ==0.73.0, + hasql ==1.6.3.4, + hasql-dynamic-statements ==0.3.1.2, + hasql-implicits ==0.1.1, + hasql-interpolate ==0.2.1.0, + hasql-listen-notify ==0.1.0, + hasql-migration ==0.3.0, + hasql-notifications ==0.2.0.6, + hasql-optparse-applicative ==0.7.1.1, + hasql-pool ==0.10, + hasql-th ==0.4.0.18, + hasql-transaction ==1.0.1.2, + has-transformers ==0.1.0.4, + hasty-hamiltonian ==1.3.4, + HaTeX ==3.22.4.1, + HaXml ==1.25.13, + haxr ==3000.11.5, + HCodecs ==0.5.2, + hdaemonize ==0.5.7, + HDBC ==2.4.0.4, + HDBC-session ==0.1.2.1, + headed-megaparsec ==0.2.1.2, + heap ==1.0.4, + heaps ==0.4, + heatshrink ==0.1.0.0, + hebrew-time ==0.1.2, + hedgehog ==1.4, + hedgehog-classes ==0.2.5.4, + hedgehog-corpus ==0.2.0, + hedgehog-fn ==1.0, + hedgehog-quickcheck ==0.1.1, + hedis ==0.15.2, + hedn ==0.3.0.4, + hegg ==0.5.0.0, + heist ==1.1.1.2, + here ==1.2.14, + heredoc ==0.2.0.0, + heterocephalus ==1.0.5.7, + hetzner ==0.6.0.0, + hex ==0.2.0, + hexml ==0.3.4, + hexml-lens ==0.2.2, + hexpat ==0.20.13, + hex-text ==0.1.0.9, + hformat ==0.3.3.1, + hfsevents ==0.1.6, + hgal ==2.0.0.3, + hidapi ==0.1.8, + hie-bios ==0.13.1, + hi-file-parser ==0.1.6.0, + hindent ==6.1.1, + hinfo ==0.0.3.0, + hinotify ==0.4.1, + hint ==0.9.0.8, + histogram-fill ==0.9.1.0, + hjsmin ==0.2.1, + hkd-default ==1.1.0.0, + hkgr ==0.4.3.2, + hledger ==1.32, + hledger-interest ==1.6.6, + hledger-lib ==1.32, + hledger-stockquotes ==0.1.2.1, + hledger-ui ==1.32, + hledger-web ==1.32, + hlibcpuid ==0.2.0, + hlibgit2 ==0.18.0.16, + hlibsass ==0.1.10.1, + hlint ==3.6.1, + hmatrix ==0.20.2, + hmatrix-backprop ==0.1.3.0, + hmatrix-gsl ==0.19.0.1, + hmatrix-gsl-stats ==0.4.1.8, + hmatrix-morpheus ==0.1.1.2, + hmatrix-special ==0.19.0.0, + hmatrix-vector-sized ==0.1.3.0, + hmm-lapack ==0.5.0.1, + HMock ==0.5.1.2, + hmpfr ==0.4.5, + hnix-store-core ==0.7.0.0, + hoauth2 ==2.10.0, + hopenssl ==2.2.5, + hopfli ==0.2.2.1, + horizontal-rule ==0.6.0.0, + hosc ==0.20, + hostname ==1.0, + hostname-validate ==1.0.0, + hourglass ==0.2.12, + hourglass-orphans ==0.1.0.0, + hp2pretty ==0.10, + hpack ==0.36.0, + hpc installed, + hpc-codecov ==0.5.0.0, + hpc-lcov ==1.1.1, + HPDF ==1.6.2, + hpp ==0.6.5, + hpqtypes ==1.11.1.2, + hpqtypes-extras ==1.16.4.4, + hreader ==1.1.1, + hreader-lens ==0.1.3.0, + hruby ==0.5.1.0, + hsass ==0.8.0, + hs-bibutils ==6.10.0.0, + hsc2hs ==0.68.10, + hscolour ==1.25, + hsdns ==1.8, + hse-cpp ==0.2, + hsemail ==2.2.1, + hset ==2.2.0, + HSet ==0.0.2, + hsexif ==0.6.1.10, + hs-GeoIP ==0.3, + hsignal ==0.2.7.5, + hsini ==0.5.2.2, + hsinstall ==2.8, + HSlippyMap ==3.0.1, + hslogger ==1.3.1.0, + hslua ==2.3.0, + hslua-aeson ==2.3.0.1, + hslua-classes ==2.3.0, + hslua-cli ==1.4.1, + hslua-core ==2.3.1, + hslua-list ==1.1.1, + hslua-marshalling ==2.3.0, + hslua-module-doclayout ==1.1.0, + hslua-module-path ==1.1.0, + hslua-module-system ==1.1.0.1, + hslua-module-text ==1.1.0.1, + hslua-module-version ==1.1.0, + hslua-module-zip ==1.1.0, + hslua-objectorientation ==2.3.0, + hslua-packaging ==2.3.0, + hslua-repl ==0.1.1, + hslua-typing ==0.1.0, + hsndfile ==0.8.0, + hsndfile-vector ==0.5.2, + HsOpenSSL ==0.11.7.6, + HsOpenSSL-x509-system ==0.1.0.4, + hspec ==2.11.7, + hspec-api ==2.11.7, + hspec-attoparsec ==0.1.0.2, + hspec-checkers ==0.1.0.2, + hspec-contrib ==0.5.2, + hspec-core ==2.11.7, + hspec-discover ==2.11.7, + hspec-expectations ==0.8.4, + hspec-expectations-json ==1.0.2.1, + hspec-expectations-lifted ==0.10.0, + hspec-expectations-pretty-diff ==0.7.2.6, + hspec-golden ==0.2.1.0, + hspec-golden-aeson ==0.9.0.0, + hspec-hedgehog ==0.1.1.0, + hspec-junit-formatter ==1.1.0.2, + hspec-leancheck ==0.0.6, + hspec-megaparsec ==2.2.1, + hspec-meta ==2.11.7, + hspec-parsec ==0, + hspec-smallcheck ==0.5.3, + hspec-tmp-proc ==0.5.2.0, + hspec-wai ==0.11.1, + hspec-wai-json ==0.11.0, + hspec-webdriver ==1.2.2, + hs-php-session ==0.0.9.3, + hstatistics ==0.3.1, + HStringTemplate ==0.8.8, + HSvm ==0.1.1.3.25, + HsYAML ==0.2.1.3, + HsYAML-aeson ==0.2.0.1, + hsyslog ==5.0.2, + htaglib ==1.2.1, + HTF ==0.15.0.1, + html ==1.0.1.2, + html-conduit ==1.3.2.2, + html-email-validate ==0.2.0.0, + html-entities ==1.1.4.6, + html-entity-map ==0.1.0.0, + HTTP ==4000.4.1, + http2 ==5.0.0, + http-api-data ==0.5.1, + http-api-data-qq ==0.1.0.0, + http-client ==0.7.15, + http-client-openssl ==0.3.3, + http-client-overrides ==0.1.1.0, + http-client-restricted ==0.1.0, + http-client-tls ==0.3.6.3, + http-common ==0.8.3.4, + http-conduit ==2.3.8.3, + http-date ==0.0.11, + http-directory ==0.1.10, + http-download ==0.2.1.0, + httpd-shed ==0.4.1.1, + http-io-streams ==0.1.6.3, + http-link-header ==1.2.1, + http-media ==0.8.1.1, + http-query ==0.1.3, + http-reverse-proxy ==0.6.0.1, + http-streams ==0.8.9.9, + http-types ==0.12.4, + human-readable-duration ==0.2.1.4, + HUnit ==1.6.2.0, + HUnit-approx ==1.1.1.1, + hunit-dejafu ==2.0.0.6, + hvect ==0.4.0.1, + hvega ==0.12.0.7, + hw-bits ==0.7.2.2, + hw-conduit ==0.2.1.1, + hw-conduit-merges ==0.2.1.0, + hw-diagnostics ==0.0.1.0, + hweblib ==0.6.3, + hw-fingertree ==0.1.2.1, + hw-fingertree-strict ==0.1.2.1, + hw-hspec-hedgehog ==0.1.1.1, + hw-int ==0.0.2.0, + hwk ==0.6, + hw-kafka-client ==5.3.0, + hworker ==0.1.0.1, + hw-parser ==0.1.1.0, + hw-prim ==0.6.3.2, + hw-string-parse ==0.0.0.5, + hxt ==9.3.1.22, + hxt-charproperties ==9.5.0.0, + hxt-css ==0.1.0.3, + hxt-curl ==9.1.1.1, + hxt-expat ==9.1.1, + hxt-http ==9.1.5.2, + hxt-regex-xmlschema ==9.2.0.7, + hxt-tagsoup ==9.1.4, + hxt-unicode ==9.0.2.4, + hybrid-vectors ==0.2.4, + hyper ==0.2.1.1, + hyperloglog ==0.4.6, + hyphenation ==0.8.2, + iconv ==0.4.1.3, + identicon ==0.2.2, + ieee754 ==0.8.0, + if ==0.1.0.0, + IfElse ==0.85, + iff ==0.0.6.1, + ihaskell ==0.10.4.0, + ihaskell-hvega ==0.5.0.4, + ihs ==0.1.0.3, + ilist ==0.4.0.1, + imagesize-conduit ==1.1, + Imlib ==0.1.2, + immortal ==0.3, + immortal-queue ==0.1.0.1, + inbox ==0.2.0, + incipit-base ==0.5.1.0, + incipit-core ==0.5.1.0, + include-file ==0.1.0.4, + incremental ==0.3.1, + indents ==0.5.0.1, + indexed ==0.1.3, + indexed-containers ==0.1.0.2, + indexed-list-literals ==0.2.1.3, + indexed-profunctors ==0.1.1.1, + indexed-traversable ==0.1.3, + indexed-traversable-instances ==0.1.1.2, + inf-backprop ==0.1.0.2, + infer-license ==0.2.0, + infinite-list ==0.1, + inflections ==0.4.0.7, + influxdb ==1.9.3, + ini ==0.4.2, + inj ==1.0, + inline-c ==0.9.1.10, + inline-c-cpp ==0.5.0.2, + inline-r ==1.0.1, + input-parsers ==0.3.0.2, + insert-ordered-containers ==0.2.5.3, + inspection-testing ==0.5.0.2, + int-cast ==0.2.0.0, + integer-conversion ==0.1.0.1, + integer-gmp installed, + integer-logarithms ==1.0.3.1, + integer-roots ==1.0.2.0, + integer-types ==0.1.4.0, + integration ==0.2.1, + intern ==0.9.5, + interpolate ==0.2.1, + interpolatedstring-perl6 ==1.0.2, + interpolation ==0.1.1.2, + Interpolation ==0.3.0, + IntervalMap ==0.6.2.1, + intervals ==0.9.2, + intset-imperative ==0.1.0.0, + int-supply ==1.0.0, + invariant ==0.6.2, + invert ==1.0.0.4, + invertible ==0.2.0.8, + invertible-grammar ==0.1.3.5, + io-machine ==0.2.0.0, + io-manager ==0.1.0.4, + io-memoize ==1.1.1.0, + io-region ==0.1.1, + io-storage ==0.3, + io-streams ==1.5.2.2, + io-streams-haproxy ==1.0.1.0, + ip ==1.7.7, + ip6addr ==1.0.3, + iproute ==1.7.12, + IPv6Addr ==2.0.5.1, + ipynb ==0.2, + ipython-kernel ==0.11.0.0, + irc ==0.6.1.0, + irc-ctcp ==0.1.3.1, + isbn ==1.1.0.4, + islink ==0.1.0.0, + iso3166-country-codes ==0.20140203.8, + iso639 ==0.1.0.3, + iso8601-time ==0.1.5, + isocline ==1.0.9, + isomorphism-class ==0.1.0.12, + ixset-typed ==0.5.1.0, + ixset-typed-binary-instance ==0.1.0.2, + ixset-typed-hashable-instance ==0.1.0.2, + ix-shapable ==0.1.0, + jack ==0.7.2.2, + jailbreak-cabal ==1.4, + jalaali ==1.0.0.0, + java-adt ==1.0.20231204, + jira-wiki-markup ==1.5.1, + jmacro ==0.6.18, + jose ==0.10.0.1, + jose-jwt ==0.9.6, + journalctl-stream ==0.6.0.5, + jsaddle ==0.9.8.3, + js-chart ==2.9.4.1, + js-dgtable ==0.5.2, + js-flot ==0.8.3, + js-jquery ==3.3.1, + json ==0.11, + json-feed ==2.0.0.10, + jsonifier ==0.2.1.2, + jsonpath ==0.3.0.0, + json-rpc ==1.0.4, + json-stream ==0.4.5.3, + JuicyPixels ==3.3.8, + JuicyPixels-extra ==0.6.0, + JuicyPixels-scale-dct ==0.1.2, + junit-xml ==0.1.0.3, + justified-containers ==0.3.0.0, + jwt ==0.11.0, + kan-extensions ==5.2.5, + kansas-comet ==0.4.2, + katip ==0.8.8.0, + katip-logstash ==0.1.0.2, + katip-wai ==0.1.2.2, + kazura-queue ==0.1.0.4, + kdt ==0.2.5, + keep-alive ==0.2.1.0, + keter ==2.1.2, + keycode ==0.2.2, + keyed-vals ==0.2.2.0, + keyed-vals-hspec-tests ==0.2.2.0, + keyed-vals-mem ==0.2.2.0, + keyed-vals-redis ==0.2.2.0, + keys ==3.12.3, + ki ==1.0.1.1, + kind-apply ==0.4.0.0, + kind-generics ==0.5.0.0, + kind-generics-th ==0.2.3.3, + ki-unlifted ==1.0.0.2, + kleene ==0.1, + kmeans ==0.1.3, + knob ==0.2.2, + koji ==0.0.2, + koji-tool ==1.1.1, + labels ==0.3.3, + lackey ==2.0.0.7, + lambdabot-core ==5.3.1.2, + lambdabot-irc-plugins ==5.3.1.2, + LambdaHack ==0.11.0.1, + lame ==0.2.2, + language-avro ==0.1.4.0, + language-c ==0.9.2, + language-c-quote ==0.13.0.1, + language-docker ==12.1.0, + language-dot ==0.1.2, + language-glsl ==0.3.0, + language-java ==0.2.9, + language-javascript ==0.7.1.0, + language-lua ==0.11.0.1, + language-nix ==2.2.0, + language-protobuf ==1.0.1, + language-python ==0.5.8, + lapack ==0.5.1, + lapack-carray ==0.0.3, + lapack-comfort-array ==0.0.1, + lapack-ffi ==0.0.3, + lapack-ffi-tools ==0.1.3.1, + lapack-hmatrix ==0.0.0.2, + largeword ==1.2.5, + latex ==0.1.0.4, + lattices ==2.2, + lawful ==0.1.0.0, + lazy-csv ==0.5.1, + lazyio ==0.1.0.4, + lazysmallcheck ==0.6, + lca ==0.4, + leancheck ==1.0.0, + leancheck-instances ==0.0.5, + leapseconds-announced ==2017.1.0.1, + learn-physics ==0.6.6, + leb128-cereal ==1.2, + lens ==5.2.3, + lens-action ==0.2.6, + lens-aeson ==1.2.3, + lens-csv ==0.1.1.0, + lens-family ==2.1.2, + lens-family-core ==2.1.2, + lens-misc ==0.0.2.0, + lens-properties ==4.11.1, + lens-regex ==0.1.3, + lens-regex-pcre ==1.1.0.0, + lentil ==1.5.6.0, + LetsBeRational ==1.0.0.0, + leveldb-haskell ==0.6.5, + lexer-applicative ==2.1.0.2, + libBF ==0.6.7, + libffi ==0.2.1, + libiserv installed, + liboath-hs ==0.0.1.2, + libyaml ==0.1.2, + lifted-async ==0.10.2.5, + lifted-base ==0.2.3.12, + lift-generics ==0.2.1, + lift-type ==0.1.1.1, + line ==4.0.1, + linear ==1.22, + linear-base ==0.4.0, + linear-circuit ==0.1.0.4, + linear-generics ==0.2.2, + linear-programming ==0.0.0.1, + linebreak ==1.1.0.4, + linux-capabilities ==0.1.1.0, + linux-file-extents ==0.2.0.1, + linux-namespaces ==0.1.3.1, + List ==0.6.2, + ListLike ==4.7.8.2, + list-predicate ==0.1.0.1, + listsafe ==0.1.0.1, + list-shuffle ==1.0.0, + list-t ==1.0.5.7, + list-transformer ==1.1.0, + ListTree ==0.2.3, + ListZipper ==1.2.0.2, + literatex ==0.3.0.0, + little-logger ==1.0.2, + little-rio ==2.0.1, + lmdb ==0.2.5, + load-env ==0.2.1.0, + loc ==0.2.0.0, + locators ==0.3.0.3, + loch-th ==0.2.2, + lockfree-queue ==0.2.4, + log-base ==0.12.0.1, + log-domain ==0.13.2, + logfloat ==0.14.0, + logger-thread ==0.1.0.2, + logging ==3.0.5, + logging-effect ==1.4.0, + logging-facade ==0.3.1, + logging-facade-syslog ==1, + logict ==0.8.1.0, + logstash ==0.1.0.4, + loop ==0.3.0, + lpeg ==1.0.4, + LPFP ==1.1.1, + LPFP-core ==1.1.1, + lrucache ==1.2.0.1, + lsp ==2.3.0.0, + lsp-test ==0.16.0.1, + lsp-types ==2.1.0.0, + lua ==2.3.1, + lua-arbitrary ==1.0.1.1, + lucid ==2.11.20230408, + lucid2 ==0.0.20230706, + lucid-cdn ==0.2.2.0, + lucid-extras ==0.2.2, + lukko ==0.1.1.3, + lz4 ==0.2.3.1, + lz4-frame-conduit ==0.1.0.1, + lzma ==0.0.1.0, + lzma-clib ==5.2.2, + machines ==0.7.3, + magic ==1.1, + magico ==0.0.2.3, + mailtrap ==0.1.2.0, + mainland-pretty ==0.7.1, + main-tester ==0.2.0.1, + managed ==1.0.10, + mandrill ==0.5.7.0, + mappings ==0.2.2.0, + map-syntax ==0.3, + markdown ==0.1.17.5, + markdown-unlit ==0.6.0, + markov-chain ==0.0.3.4, + markov-chain-usage-model ==0.0.0, + markup-parse ==0.1.1, + mason ==0.2.6, + massiv ==1.0.4.0, + massiv-io ==1.0.0.1, + massiv-serialise ==1.0.0.2, + massiv-test ==1.0.0.0, + matchable ==0.1.2.1, + mathexpr ==0.3.1.0, + math-extras ==0.1.1.0, + math-functions ==0.3.4.3, + mathlist ==0.2.0.0, + matplotlib ==0.7.7, + matrices ==0.5.0, + matrix ==0.3.6.3, + matrix-as-xyz ==0.1.2.2, + matrix-market-attoparsec ==0.1.1.3, + matrix-static ==0.3, + maximal-cliques ==0.1.1, + mbox-utility ==0.0.3.1, + mcmc ==0.8.2.0, + mcmc-types ==1.0.3, + median-stream ==0.7.0.0, + med-module ==0.1.3, + megaparsec ==9.4.1, + megaparsec-tests ==9.4.1, + mega-sdist ==0.4.3.0, + membership ==0.0.1, + memcache ==0.3.0.1, + memfd ==1.0.1.3, + memory ==0.18.0, + MemoTrie ==0.6.11, + mergeful ==0.3.0.0, + mergeful-persistent ==0.3.0.1, + mergeless ==0.4.0.0, + mergeless-persistent ==0.1.0.1, + merkle-tree ==0.1.1, + mersenne-random ==1.0.0.1, + mersenne-random-pure64 ==0.2.2.0, + messagepack ==0.5.5, + metrics ==0.4.1.1, + mfsolve ==0.3.2.2, + microaeson ==0.1.0.1, + microlens ==0.4.13.1, + microlens-aeson ==2.5.1, + microlens-contra ==0.1.0.3, + microlens-ghc ==0.4.14.2, + microlens-mtl ==0.2.0.3, + microlens-platform ==0.4.3.4, + microlens-th ==0.4.3.14, + microspec ==0.2.1.3, + microstache ==1.0.2.3, + midair ==0.2.0.1, + midi ==0.2.2.4, + midi-alsa ==0.2.1, + midi-music-box ==0.0.1.2, + mighty-metropolis ==2.0.0, + mime-mail ==0.5.1, + mime-mail-ses ==0.4.3, + mime-types ==0.1.2.0, + minimal-configuration ==0.1.4, + minimorph ==0.3.0.1, + minisat-solver ==0.1, + miniterion ==0.1.1.0, + miniutter ==0.5.1.2, + min-max-pqueue ==0.1.0.2, + mintty ==0.1.4, + misfortune ==0.1.2.1, + miso ==1.8.3.0, + missing-foreign ==0.1.1, + MissingH ==1.6.0.1, + mixed-types-num ==0.5.12, + mmap ==0.5.9, + mmark ==0.0.7.6, + mmark-cli ==0.0.5.1, + mmark-ext ==0.2.1.5, + mmorph ==1.2.0, + mnist-idx ==0.1.3.2, + mnist-idx-conduit ==0.4.0.0, + mockery ==0.3.5, + mod ==0.2.0.1, + modern-uri ==0.3.6.1, + modular ==0.1.0.8, + moffy ==0.1.1.0, + monad-chronicle ==1.0.1, + monad-control ==1.0.3.1, + monad-control-aligned ==0.0.2.1, + monad-control-identity ==0.2.0.0, + monad-coroutine ==0.9.2, + monad-extras ==0.6.0, + monad-interleave ==0.2.0.1, + monadlist ==0.0.2, + monad-logger ==0.3.40, + monad-logger-aeson ==0.4.1.1, + monad-logger-json ==0.1.0.0, + monad-logger-logstash ==0.2.0.2, + monad-loops ==0.4.3, + monad-memo ==0.5.4, + monad-metrics ==0.2.2.1, + monadoid ==0.0.3, + monadology ==0.3, + monad-par ==0.3.6, + monad-parallel ==0.8, + monad-par-extras ==0.3.3, + monad-peel ==0.3, + MonadPrompt ==1.0.0.5, + MonadRandom ==0.6, + monad-resumption ==0.1.4.0, + monad-schedule ==0.1.2.1, + monad-st ==0.2.4.1, + monads-tf ==0.3.0.1, + monad-time ==0.4.0.0, + mongoDB ==2.7.1.2, + monoidal-containers ==0.6.4.0, + monoidal-functors ==0.2.3.0, + monoid-extras ==0.6.2, + monoid-subclasses ==1.2.4.1, + monoid-transformer ==0.0.4, + monomer ==1.6.0.0, + mono-traversable ==1.0.15.3, + mono-traversable-instances ==0.1.1.0, + mono-traversable-keys ==0.3.0, + more-containers ==0.2.2.2, + morpheus-graphql-app ==0.27.3, + morpheus-graphql-client ==0.27.3, + morpheus-graphql-code-gen-utils ==0.27.3, + morpheus-graphql-core ==0.27.3, + morpheus-graphql-server ==0.27.3, + morpheus-graphql-subscriptions ==0.27.3, + morpheus-graphql-tests ==0.27.3, + moss ==0.2.0.1, + mountpoints ==1.0.2, + mpi-hs ==0.7.2.0, + mpi-hs-binary ==0.1.1.0, + mpi-hs-cereal ==0.1.0.0, + msgpack ==1.0.1.0, + mtl installed, + mtl-compat ==0.2.2, + mtl-prelude ==2.0.3.2, + multiarg ==0.30.0.10, + multi-containers ==0.2, + multimap ==1.2.1, + multipart ==0.2.1, + MultipletCombiner ==0.0.7, + multiset ==0.3.4.3, + multistate ==0.8.0.4, + murmur3 ==1.0.5, + murmur-hash ==0.1.0.10, + MusicBrainz ==0.4.1, + mustache ==2.4.2, + mutable-containers ==0.3.4.1, + mwc-probability ==2.3.1, + mwc-random ==0.15.0.2, + mx-state-codes ==1.0.0.0, + myers-diff ==0.3.0.0, + mysql ==0.2.1, + mysql-haskell ==1.1.3, + mysql-haskell-nem ==0.1.0.0, + mysql-json-table ==0.1.2.0, + mysql-simple ==0.4.9, + n2o ==0.11.1, + n2o-nitro ==0.11.2, + nagios-check ==0.3.2, + named ==0.3.0.1, + names-th ==0.3.0.1, + nano-erl ==0.1.0.1, + nanospec ==0.2.2, + nanovg ==0.8.1.0, + nats ==1.1.2, + natural-arithmetic ==0.1.4.0, + natural-induction ==0.2.0.0, + natural-sort ==0.1.2, + natural-transformation ==0.4, + ndjson-conduit ==0.1.0.5, + neat-interpolation ==0.5.1.4, + netcode-io ==0.0.3, + netlib-carray ==0.1, + netlib-comfort-array ==0.0.0.2, + netlib-ffi ==0.1.1, + net-mqtt ==0.8.6.0, + net-mqtt-lens ==0.1.1.0, + netpbm ==1.0.4, + netrc ==0.2.0.0, + nettle ==0.3.0, + netwire ==5.0.3, + netwire-input ==0.0.7, + network ==3.1.4.0, + network-bsd ==2.8.1.0, + network-byte-order ==0.1.7, + network-conduit-tls ==1.4.0, + network-control ==0.0.2, + network-info ==0.2.1, + network-ip ==0.3.0.3, + network-messagepack-rpc ==0.1.2.0, + network-messagepack-rpc-websocket ==0.1.1.1, + network-multicast ==0.3.2, + network-run ==0.2.6, + network-simple ==0.4.5, + network-transport ==0.5.6, + network-uri ==2.6.4.2, + network-wait ==0.2.0.0, + newtype ==0.2.2.0, + newtype-generics ==0.6.2, + nfc ==0.1.1, + nicify-lib ==1.0.1, + NineP ==0.0.2.1, + nix-derivation ==1.1.3, + nix-paths ==1.0.1, + NoHoed ==0.1.1, + nonce ==1.0.7, + nondeterminism ==1.5, + non-empty ==0.3.5, + nonempty-containers ==0.3.4.5, + non-empty-sequence ==0.2.0.4, + nonempty-vector ==0.2.3, + nonempty-zipper ==1.0.0.4, + non-negative ==0.1.2, + normaldistribution ==1.1.0.3, + nothunks ==0.1.5, + no-value ==1.0.0.0, + nowdoc ==0.1.1.0, + nqe ==0.6.5, + nsis ==0.3.3, + n-tuple ==0.0.3, + numbers ==3000.2.0.2, + numeric-extras ==0.1, + numeric-limits ==0.1.0.0, + numeric-prelude ==0.4.4, + numeric-quest ==0.2.0.2, + numhask ==0.11.1.0, + numhask-array ==0.11.0.1, + numhask-space ==0.11.1.0, + NumInstances ==1.4, + numtype-dk ==0.5.0.3, + nuxeo ==0.3.2, + nvim-hs ==2.3.2.3, + nvim-hs-contrib ==2.0.0.2, + nvim-hs-ghcid ==2.0.1.0, + ObjectName ==1.1.0.2, + oblivious-transfer ==0.1.0, + o-clock ==1.4.0, + ods2csv ==0.1, + ofx ==0.4.4.0, + old-locale ==1.0.0.7, + old-time ==1.1.0.3, + once ==0.4, + one-liner ==2.1, + one-liner-instances ==0.1.3.0, + OneTuple ==0.4.1.1, + Only ==0.1, + oo-prototypes ==0.1.0.0, + oops ==0.2.0.1, + opaleye ==0.10.2.0, + OpenAL ==1.7.0.5, + openapi3 ==3.2.4, + open-browser ==0.2.1.0, + openexr-write ==0.1.0.2, + OpenGL ==3.0.3.0, + OpenGLRaw ==3.3.4.1, + openpgp-asciiarmor ==0.1.2, + opensource ==0.1.1.0, + openssl-streams ==1.2.3.0, + opentelemetry ==0.8.0, + opentelemetry-extra ==0.8.0, + opentelemetry-lightstep ==0.8.0, + opentelemetry-wai ==0.8.0, + open-witness ==0.6, + operational ==0.2.4.2, + opml-conduit ==0.9.0.0, + optics ==0.4.2.1, + optics-core ==0.4.1.1, + optics-extra ==0.4.2.1, + optics-operators ==0.1.0.1, + optics-th ==0.4.1, + optics-vl ==0.2.1, + optima ==0.4.0.4, + optional-args ==1.0.2, + options ==1.2.1.2, + optparse-applicative ==0.18.1.0, + optparse-enum ==1.0.0.0, + optparse-generic ==1.5.2, + optparse-simple ==0.1.1.4, + optparse-text ==0.1.1.0, + OrderedBits ==0.0.2.0, + ordered-containers ==0.2.3, + ormolu ==0.7.2.0, + overhang ==1.0.0, + packcheck ==0.6.0, + pager ==0.1.1.0, + pagination ==0.2.2, + pagure ==0.1.1, + pagure-cli ==0.2.1, + palette ==0.3.0.3, + pandoc ==3.1.9, + pandoc-cli ==0.1.1.1, + pandoc-dhall-decoder ==0.1.0.1, + pandoc-lua-engine ==0.2.1.2, + pandoc-lua-marshal ==0.2.2, + pandoc-plot ==1.8.0, + pandoc-server ==0.1.0.3, + pandoc-throw ==0.1.0.0, + pandoc-types ==1.23.1, + pango ==0.13.10.0, + pantry ==0.9.3, + parallel ==3.2.2.0, + parallel-io ==0.3.5, + parameterized ==0.5.0.0, + park-bench ==0.1.1.0, + parseargs ==0.2.0.9, + parsec installed, + parsec-class ==1.0.0.0, + parsec-numbers ==0.1.0, + parsec-numeric ==0.1.0.0, + ParsecTools ==0.0.2.0, + parser-combinators ==1.3.0, + parser-combinators-tests ==1.3.0, + parsers ==0.12.11, + partial-handler ==1.0.3, + partial-isomorphisms ==0.2.3.0, + partialord ==0.0.2, + partial-order ==0.2.0.0, + partial-semigroup ==0.6.0.2, + password ==3.0.2.1, + password-instances ==3.0.0.0, + password-types ==1.0.0.0, + path ==0.9.5, + path-binary-instance ==0.1.0.1, + path-dhall-instance ==0.2.1.0, + path-extensions ==0.1.1.0, + path-extra ==0.3.1, + path-io ==1.8.1, + path-like ==0.2.0.2, + path-pieces ==0.2.1, + pathtype ==0.8.1.2, + path-utils ==0.1.1.0, + pathwalk ==0.3.1.2, + patrol ==1.0.0.6, + pava ==0.1.1.4, + pcf-font ==0.2.2.1, + pcg-random ==0.1.4.0, + pcre2 ==2.2.1, + pcre-heavy ==1.0.0.3, + pcre-light ==0.4.1.2, + pcre-utils ==0.1.9, + pdc ==0.1.1, + pdf-toolbox-content ==0.1.1, + pdf-toolbox-core ==0.1.1, + pdf-toolbox-document ==0.1.2, + peano ==0.1.0.2, + pedersen-commitment ==0.2.0, + pem ==0.2.4, + percent-format ==0.0.4, + peregrin ==0.4.2, + perf ==0.12.0.0, + perfect-hash-generator ==1.0.0, + persistable-record ==0.6.0.6, + persistable-types-HDBC-pg ==0.0.3.5, + persistent ==2.14.6.0, + persistent-discover ==0.1.0.7, + persistent-iproute ==0.2.5, + persistent-lens ==1.0.0, + persistent-mongoDB ==2.13.0.1, + persistent-mysql ==2.13.1.4, + persistent-pagination ==0.1.1.2, + persistent-postgresql ==2.13.6.1, + persistent-qq ==2.12.0.6, + persistent-redis ==2.13.0.1, + persistent-sqlite ==2.13.2.0, + persistent-template ==2.12.0.0, + persistent-test ==2.13.1.3, + persistent-typed-db ==0.1.0.7, + pg-harness-client ==0.6.0, + pg-transact ==0.3.2.0, + phantom-state ==0.2.1.4, + phatsort ==0.6.0.0, + pid1 ==0.1.3.1, + pinch ==0.5.0.0, + pipes ==4.3.16, + pipes-attoparsec ==0.6.0, + pipes-binary ==0.4.4, + pipes-bytestring ==2.1.7, + pipes-concurrency ==2.0.14, + pipes-csv ==1.4.3, + pipes-extras ==1.0.15, + pipes-fastx ==0.3.0.0, + pipes-fluid ==0.6.0.1, + pipes-group ==1.0.12, + pipes-http ==1.0.6, + pipes-mongodb ==0.1.0.0, + pipes-ordered-zip ==1.2.1, + pipes-parse ==3.0.9, + pipes-random ==1.0.0.5, + pipes-safe ==2.3.5, + pipes-text ==1.0.1, + pipes-wai ==3.2.0, + pkgtreediff ==0.6.0, + place-cursor-at ==1.0.1, + placeholders ==0.1, + plaid ==0.1.0.4, + plotlyhs ==0.2.3, + Plural ==0.0.2, + pointed ==5.0.4, + pointedlist ==0.6.1, + pointless-fun ==1.1.0.8, + poll ==0.0.0.2, + poly ==0.5.1.0, + poly-arity ==0.1.0, + polynomials-bernstein ==1.1.2, + polyparse ==1.13, + polysemy ==1.9.1.3, + polysemy-fs ==0.1.0.0, + polysemy-plugin ==0.4.5.1, + polysemy-webserver ==0.2.1.2, + pontarius-xmpp ==0.5.6.8, + pooled-io ==0.0.2.3, + portable-lines ==0.1, + port-utils ==0.2.1.0, + posix-paths ==0.3.0.0, + posix-pty ==0.2.2, + possibly ==1.0.0.0, + postgres-options ==0.2.1.0, + postgresql-binary ==0.13.1.2, + postgresql-libpq ==0.10.0.0, + postgresql-libpq-notify ==0.2.0.0, + postgresql-migration ==0.2.1.7, + postgresql-query ==3.10.0, + postgresql-schema ==0.1.14, + postgresql-simple ==0.7.0.0, + postgresql-simple-url ==0.2.1.0, + postgresql-syntax ==0.4.1, + postgresql-typed ==0.6.2.5, + post-mess-age ==0.2.1.0, + pptable ==0.3.0.0, + pqueue ==1.5.0.0, + pred-set ==0.0.1, + prefix-units ==0.3.0.1, + prelude-compat ==0.0.0.2, + prelude-safeenum ==0.1.1.3, + pretty installed, + pretty-class ==1.0.1.1, + prettyclass ==1.0.0.0, + pretty-hex ==1.1, + prettyprinter ==1.7.1, + prettyprinter-ansi-terminal ==1.1.3, + prettyprinter-combinators ==0.1.2, + prettyprinter-compat-annotated-wl-pprint ==1.1, + prettyprinter-compat-ansi-wl-pprint ==1.0.2, + prettyprinter-compat-wl-pprint ==1.0.1, + prettyprinter-interp ==0.2.0.0, + pretty-relative-time ==0.3.0.0, + pretty-show ==1.10, + pretty-simple ==4.1.2.0, + pretty-sop ==0.2.0.3, + pretty-terminal ==0.1.0.0, + primecount ==0.1.0.1, + primes ==0.2.1.0, + primitive ==0.8.0.0, + primitive-addr ==0.1.0.2, + primitive-extras ==0.10.1.10, + primitive-offset ==0.2.0.0, + primitive-serial ==0.1, + primitive-unaligned ==0.1.1.2, + primitive-unlifted ==2.1.0.0, + prim-uniq ==0.2, + print-console-colors ==0.1.0.0, + probability ==0.2.8, + process installed, + process-extras ==0.7.4, + product-isomorphic ==0.0.3.4, + product-profunctors ==0.11.1.1, + profunctors ==5.6.2, + projectroot ==0.2.0.1, + project-template ==0.2.1.0, + prometheus ==2.2.4, + prometheus-client ==1.1.1, + prometheus-metrics-ghc ==1.0.1.2, + promises ==0.3, + prospect ==0.1.0.0, + protobuf ==0.2.1.3, + protobuf-simple ==0.1.1.1, + protocol-radius ==0.0.1.1, + protocol-radius-test ==0.1.0.1, + proto-lens ==0.7.1.3, + proto-lens-runtime ==0.7.0.4, + protolude ==0.3.3, + proxied ==0.3.1, + psql-helpers ==0.1.0.0, + PSQueue ==1.2.0, + psqueues ==0.2.8.0, + pthread ==0.2.1, + ptr ==0.16.8.5, + ptr-poker ==0.1.2.13, + pulse-simple ==0.1.14, + pureMD5 ==2.1.4, + purescript-bridge ==0.15.0.0, + purview ==0.2.0.2, + pusher-http-haskell ==2.1.0.17, + pvar ==1.0.0.0, + pwstore-fast ==2.4.4, + PyF ==0.11.2.1, + qchas ==1.1.0.1, + qm-interpolated-string ==0.3.1.0, + qrcode-core ==0.9.9, + qrcode-juicypixels ==0.8.5, + quaalude ==0.0.0.1, + quadratic-irrational ==0.1.1, + QuasiText ==0.1.2.6, + QuickCheck ==2.14.3, + quickcheck-arbitrary-adt ==0.3.1.0, + quickcheck-assertions ==0.3.0, + quickcheck-classes ==0.6.5.0, + quickcheck-classes-base ==0.6.2.0, + quickcheck-groups ==0.0.1.0, + quickcheck-higherorder ==0.1.0.1, + quickcheck-instances ==0.3.30, + quickcheck-io ==0.2.0, + quickcheck-monoid-subclasses ==0.3.0.0, + quickcheck-simple ==0.1.1.1, + quickcheck-special ==0.1.0.6, + quickcheck-state-machine ==0.8.0, + quickcheck-text ==0.1.2.1, + quickcheck-transformer ==0.3.1.2, + quickcheck-unicode ==1.0.1.0, + quicklz ==1.5.0.11, + quiet ==0.2, + quote-quot ==0.2.1.0, + radius ==0.7.1.0, + rainbow ==0.34.2.2, + rainbox ==0.26.0.0, + ral ==0.2.1, + rampart ==2.0.0.7, + ramus ==0.1.2, + rando ==0.0.0.4, + random ==1.2.1.1, + random-bytestring ==0.1.4, + random-fu ==0.3.0.1, + random-shuffle ==0.0.4, + random-tree ==0.6.0.5, + range ==0.3.0.2, + ranged-list ==0.1.2.1, + Ranged-sets ==0.4.0, + ranges ==0.2.4, + range-set-list ==0.1.3.1, + rank1dynamic ==0.4.1, + rank2classes ==1.5.3, + Rasterific ==0.7.5.4, + rasterific-svg ==0.3.3.2, + ratel ==2.0.0.10, + rate-limit ==1.4.3, + ratel-wai ==2.0.0.5, + ratio-int ==0.1.2, + rattle ==0.2, + rattletrap ==12.1.2, + Rattus ==0.5.1.1, + rawfilepath ==1.1.0, + rawstring-qm ==0.2.3.0, + raw-strings-qq ==1.1, + rcu ==0.2.7, + rdtsc ==1.3.0.1, + re2 ==0.3, + reactive-balsa ==0.4.0.1, + reactive-banana ==1.3.2.0, + reactive-banana-bunch ==1.0.0.1, + reactive-jack ==0.4.1.2, + reactive-midyim ==0.4.1.1, + readable ==0.3.1, + read-editor ==0.1.0.2, + read-env-var ==1.0.0.0, + rebase ==1.20.1.1, + rec-def ==0.2.2, + record-hasfield ==1.0, + records-sop ==0.1.1.1, + recursion-schemes ==5.2.2.5, + recv ==0.1.0, + redact ==0.5.0.0, + redis-glob ==0.1.0.6, + redis-resp ==1.0.0, + reducers ==3.12.4, + refact ==0.3.0.2, + ref-fd ==0.5.0.1, + refined ==0.8.1, + reflection ==2.1.7, + RefSerialize ==0.4.0, + ref-tf ==0.5.0.1, + regex ==1.1.0.2, + regex-applicative ==0.3.4, + regex-base ==0.94.0.2, + regex-compat ==0.95.2.1, + regex-pcre ==0.95.0.0, + regex-pcre-builtin ==0.95.2.3.8.44, + regex-posix ==0.96.0.1, + regex-posix-clib ==2.7, + regex-tdfa ==1.3.2.2, + regex-with-pcre ==1.1.0.2, + regression-simple ==0.2.1, + reinterpret-cast ==0.1.0, + relapse ==1.0.0.1, + relational-query ==0.12.3.1, + relational-query-HDBC ==0.7.2.1, + relational-record ==0.2.2.0, + relational-schemas ==0.1.8.1, + reliable-io ==0.0.2, + relude ==1.2.1.0, + renderable ==0.2.0.1, + replace-attoparsec ==1.5.0.0, + replace-megaparsec ==1.5.0.1, + repline ==0.4.2.0, + req ==3.13.1, + req-conduit ==1.0.1, + rerebase ==1.20.1.1, + reroute ==0.7.0.0, + resistor-cube ==0.0.1.4, + resolv ==0.2.0.2, + resource-pool ==0.4.0.0, + resourcet ==1.3.0, + rest-rewrite ==0.4.2, + result ==0.2.6.0, + retry ==0.9.3.1, + rex ==0.6.2, + rfc1751 ==0.1.3, + rfc5051 ==0.2, + rg ==1.4.0.0, + riak-protobuf ==0.25.0.0, + richenv ==0.1.0.1, + rio ==0.1.22.0, + rio-orphans ==0.1.2.0, + rio-prettyprint ==0.1.7.0, + rng-utils ==0.3.1, + roc-id ==0.2.0.0, + rocksdb-haskell ==1.0.1, + rocksdb-haskell-jprupp ==2.1.6, + rocksdb-query ==0.4.2, + roles ==0.2.1.0, + rollbar ==1.1.3, + rope-utf16-splay ==0.4.0.0, + rosezipper ==0.2, + rot13 ==0.2.0.1, + row-types ==1.0.1.2, + rpmbuild-order ==0.4.10, + rpm-nvr ==0.1.2, + rp-tree ==0.7.1, + rrb-vector ==0.2.1.0, + RSA ==2.4.1, + rss ==3000.2.0.7, + rss-conduit ==0.6.0.1, + run-haskell-module ==0.0.2, + runmemo ==1.0.0.1, + run-st ==0.1.3.2, + rvar ==0.3.0.2, + rzk ==0.6.7, + s3-signer ==0.5.0.0, + safe ==0.3.19, + safe-coloured-text ==0.2.0.1, + safe-coloured-text-gen ==0.0.0.1, + safe-coloured-text-layout ==0.0.0.0, + safe-coloured-text-layout-gen ==0.0.0.0, + safe-coloured-text-terminfo ==0.1.0.0, + safecopy ==0.10.4.2, + safe-decimal ==0.2.1.0, + safe-exceptions ==0.1.7.4, + safe-foldable ==0.1.0.0, + safe-gen ==1.0.1, + safeio ==0.0.6.0, + safe-json ==1.2.0.0, + safe-money ==0.9.1, + SafeSemaphore ==0.10.1, + saltine ==0.2.1.0, + salve ==2.0.0.4, + sample-frame ==0.0.4, + sample-frame-np ==0.0.5, + sampling ==0.3.5, + sandi ==0.5, + sandwich ==0.1.5.2, + sandwich-hedgehog ==0.1.3.0, + sandwich-quickcheck ==0.1.0.7, + sandwich-slack ==0.1.2.0, + sandwich-webdriver ==0.2.3.1, + say ==0.1.0.1, + sbp ==5.0.1, + sbv ==10.2, + scanf ==0.1.0.0, + scanner ==0.3.1, + scheduler ==2.0.0.1, + SciBaseTypes ==0.1.1.0, + scientific ==0.3.7.0, + scientist ==0.0.0.0, + scotty ==0.20.1, + scrypt ==0.5.0, + sdl2 ==2.5.5.0, + sdl2-gfx ==0.3.0.0, + sdl2-image ==2.1.0.0, + sdl2-mixer ==1.2.0.0, + sdl2-ttf ==2.1.3, + search-algorithms ==0.3.2, + secp256k1-haskell ==1.1.0, + securemem ==0.1.10, + selections ==0.3.0.0, + selective ==0.7, + semialign ==1.3, + semigroupoids ==6.0.0.1, + semigroups ==0.20, + semirings ==0.6, + semiring-simple ==1.0.0.1, + semver ==0.4.0.1, + sendfile ==0.7.11.4, + sendgrid-v3 ==1.0.0.1, + seqalign ==0.2.0.4, + seqid ==0.6.3, + seqid-streams ==0.7.2, + sequence-formats ==1.8.0.0, + sequenceTools ==1.5.3.1, + serialise ==0.2.6.1, + servant ==0.20.1, + servant-auth ==0.4.1.0, + servant-auth-client ==0.4.1.1, + servant-auth-docs ==0.2.10.1, + servant-auth-server ==0.4.8.0, + servant-auth-swagger ==0.2.10.2, + servant-blaze ==0.9.1, + servant-checked-exceptions ==2.2.0.1, + servant-checked-exceptions-core ==2.2.0.1, + servant-client ==0.20, + servant-client-core ==0.20, + servant-conduit ==0.16, + servant-docs ==0.13, + servant-elm ==0.7.3, + servant-exceptions ==0.2.1, + servant-exceptions-server ==0.2.1, + servant-foreign ==0.16, + servant-http-streams ==0.20, + servant-JuicyPixels ==0.3.1.1, + servant-lucid ==0.9.0.6, + servant-machines ==0.16, + servant-multipart ==0.12.1, + servant-multipart-api ==0.12.1, + servant-multipart-client ==0.12.2, + servant-openapi3 ==2.0.1.6, + servant-pipes ==0.16, + servant-rate-limit ==0.2.0.0, + servant-rawm ==1.0.0.0, + servant-server ==0.20, + servant-static-th ==1.0.0.0, + servant-subscriber ==0.7.0.0, + servant-swagger ==1.2, + servant-swagger-ui ==0.3.5.5.0.0, + servant-swagger-ui-core ==0.3.5, + servant-swagger-ui-redoc ==0.3.4.1.22.3, + servant-websockets ==2.0.0, + servant-xml ==1.0.2, + serversession ==1.0.3, + serversession-backend-redis ==1.0.5, + serversession-frontend-wai ==1.0.1, + serversession-frontend-yesod ==1.0.1, + servius ==1.2.3.0, + ses-html ==0.4.0.0, + set-cover ==0.1.1, + setenv ==0.1.1.3, + setlocale ==1.0.0.10, + set-monad ==0.3.0.0, + sexp-grammar ==2.3.4.2, + SHA ==1.6.4.4, + shake ==0.19.7, + shake-language-c ==0.12.0, + shake-plus ==0.3.4.0, + shake-plus-extended ==0.4.1.0, + shakespeare ==2.1.0.1, + shakespeare-text ==1.1.0, + shared-memory ==0.2.0.1, + ShellCheck ==0.9.0, + shell-conduit ==5.0.0, + shell-escape ==0.2.0, + shellify ==0.11.0.0, + shellmet ==0.0.4.1, + shelltestrunner ==1.10, + shell-utility ==0.1, + shellwords ==0.1.3.1, + shelly ==1.12.1, + should-not-typecheck ==2.1.0, + show-combinators ==0.2.0.0, + siggy-chardust ==1.0.0, + signal ==0.1.0.4, + silently ==1.2.5.3, + simple ==2.0.0, + simple-affine-space ==0.2.1, + simple-cabal ==0.1.3.1, + simple-cmd ==0.2.7, + simple-cmd-args ==0.1.8, + simple-expr ==0.1.1.0, + simple-media-timestamp ==0.2.1.0, + simple-media-timestamp-attoparsec ==0.1.0.0, + simple-prompt ==0.2.2, + simple-reflect ==0.3.3, + simple-sendfile ==0.2.32, + simple-session ==2.0.0, + simple-templates ==2.0.0, + simple-vec3 ==0.6.0.1, + since ==0.0.0, + singleton-bool ==0.1.7, + singleton-nats ==0.4.7, + singletons ==3.0.2, + singletons-base ==3.2, + singletons-presburger ==0.7.2.0, + singletons-th ==3.2, + Sit ==0.2023.8.3, + sitemap-gen ==0.1.0.0, + size-based ==0.1.3.2, + sized ==1.1.0.0, + skein ==1.0.9.4, + skews ==0.1.0.3, + skip-var ==0.1.1.0, + skylighting ==0.14.1, + skylighting-core ==0.14.1, + skylighting-format-ansi ==0.1, + skylighting-format-blaze-html ==0.1.1.1, + skylighting-format-context ==0.1.0.2, + skylighting-format-latex ==0.1, + slave-thread ==1.1.0.3, + slick ==1.2.1.0, + slist ==0.2.1.0, + slynx ==0.7.2.2, + smallcheck ==1.2.1.1, + snap ==1.1.3.3, + snap-blaze ==0.2.1.5, + snap-core ==1.0.5.1, + snap-server ==1.1.2.1, + snowflake ==0.1.1.1, + socket ==0.8.3.0, + socks ==0.6.1, + solana-staking-csvs ==0.1.2.0, + some ==1.0.6, + some-dict-of ==0.1.0.2, + sop-core ==0.5.0.2, + sort ==1.0.0.0, + sorted-list ==0.2.2.0, + sound-collage ==0.2.1, + sourcemap ==0.1.7, + sox ==0.2.3.2, + soxlib ==0.0.3.2, + spacecookie ==1.0.0.2, + SpatialMath ==0.2.7.1, + special-values ==0.1.0.0, + speculate ==0.4.14, + speedy-slice ==0.3.2, + splice ==0.6.1.1, + split ==0.2.4, + splitmix ==0.1.0.5, + splitmix-distributions ==1.0.0, + split-record ==0.1.1.4, + Spock-api ==0.14.0.0, + spoon ==0.3.1, + spreadsheet ==0.1.3.10, + sqids ==0.2.0.0, + sqlite-simple ==0.4.18.2, + sql-words ==0.1.6.5, + squeal-postgresql ==0.9.1.3, + squeather ==0.8.0.0, + srcloc ==0.6.0.1, + srt ==0.1.2.0, + srtree ==1.0.0.5, + stache ==2.3.4, + stack ==2.13.1, + stack-all ==0.4.2, + stack-clean-old ==0.5, + stack-templatizer ==0.1.1.0, + state-codes ==0.1.3, + stateref ==0.3, + statestack ==0.3.1.1, + StateVar ==1.2.2, + stateWriter ==0.4.0, + static-bytes ==0.1.0, + static-canvas ==0.2.0.3, + static-text ==0.2.0.7, + statistics ==0.16.2.1, + statistics-linreg ==0.3, + status-notifier-item ==0.3.1.0, + step-function ==0.2.0.1, + stitch ==0.6.0.0, + stm installed, + stm-chans ==3.0.0.9, + stm-conduit ==4.0.1, + stm-containers ==1.2.0.3, + stm-delay ==0.1.1.1, + stm-extras ==0.1.0.3, + stm-hamt ==1.2.0.14, + STMonadTrans ==0.4.7, + stm-split ==0.0.2.1, + stm-supply ==0.2.0.0, + storable-complex ==0.2.3.0, + storable-endian ==0.2.6.1, + storable-record ==0.0.7, + storable-tuple ==0.1, + storablevector ==0.2.13.2, + store ==0.7.18, + store-core ==0.4.4.6, + store-streaming ==0.2.0.5, + stratosphere ==0.60.0, + Stream ==0.4.7.2, + streaming ==0.2.4.0, + streaming-attoparsec ==1.0.0.1, + streaming-bytestring ==0.3.2, + streaming-commons ==0.2.2.6, + streaming-wai ==0.1.1, + streamly ==0.10.0, + streamly-core ==0.2.0, + streams ==3.3.2, + strict ==0.5, + strict-base-types ==0.8, + strict-concurrency ==0.2.4.3, + strict-lens ==0.4.0.3, + strict-list ==0.1.7.4, + strict-tuple ==0.1.5.3, + strict-wrapper ==0.0.0.0, + stringable ==0.1.3, + stringbuilder ==0.5.1, + string-class ==0.1.7.1, + string-combinators ==0.6.0.5, + string-conv ==0.2.0, + string-conversions ==0.4.0.1, + string-interpolate ==0.3.2.1, + stringprep ==1.0.0, + string-qq ==0.0.5, + string-random ==0.1.4.3, + stringsearch ==0.3.6.6, + string-transform ==1.1.1, + stripe-concepts ==1.0.3.3, + stripe-signature ==1.0.0.16, + stripe-wreq ==1.0.1.16, + strive ==6.0.0.10, + structs ==0.1.9, + structured ==0.1.1, + stylish-haskell ==0.14.5.0, + subcategories ==0.2.0.1, + sundown ==0.6, + superbuffer ==0.3.1.2, + svg-builder ==0.1.1, + SVGFonts ==1.8.0.1, + svg-tree ==0.6.2.4, + swagger2 ==2.8.7, + swish ==0.10.7.0, + syb ==0.7.2.4, + sydtest ==0.15.1.1, + sydtest-aeson ==0.1.0.0, + sydtest-amqp ==0.1.0.0, + sydtest-autodocodec ==0.0.0.0, + sydtest-discover ==0.0.0.4, + sydtest-hedgehog ==0.4.0.0, + sydtest-hedis ==0.0.0.0, + sydtest-hspec ==0.4.0.2, + sydtest-mongo ==0.0.0.0, + sydtest-persistent ==0.0.0.2, + sydtest-persistent-sqlite ==0.2.0.3, + sydtest-process ==0.0.0.0, + sydtest-rabbitmq ==0.1.0.0, + sydtest-servant ==0.2.0.2, + sydtest-typed-process ==0.0.0.0, + sydtest-wai ==0.2.0.1, + sydtest-webdriver ==0.0.0.1, + sydtest-webdriver-screenshot ==0.0.0.2, + sydtest-webdriver-yesod ==0.0.0.1, + sydtest-yesod ==0.3.0.2, + symbol ==0.2.4, + symengine ==0.1.2.0, + symmetry-operations-symbols ==0.0.2.1, + synthesizer-alsa ==0.5.0.6, + synthesizer-core ==0.8.3, + synthesizer-dimensional ==0.8.1.1, + synthesizer-midi ==0.6.1.2, + sysinfo ==0.1.1, + system-argv0 ==0.1.1, + systemd ==2.3.0, + systemd-socket-activation ==1.1.0.1, + system-fileio ==0.3.16.4, + system-filepath ==0.4.14, + system-info ==0.5.2, + system-linux-proc ==0.1.1.1, + tabular ==0.2.2.8, + tagchup ==0.4.1.2, + tagged ==0.8.7, + tagged-binary ==0.2.0.1, + tagged-identity ==0.1.4, + tagged-transformer ==0.8.2, + tagsoup ==0.14.8, + tagstream-conduit ==0.5.6, + tao ==1.0.0, + tao-example ==1.0.0, + tar ==0.5.1.1, + tar-conduit ==0.4.0, + tasty ==1.4.3, + tasty-ant-xml ==1.1.9, + tasty-autocollect ==0.4.1, + tasty-bench ==0.3.5, + tasty-bench-fit ==0.1, + tasty-dejafu ==2.1.0.1, + tasty-discover ==5.0.0, + tasty-expected-failure ==0.12.3, + tasty-fail-fast ==0.0.3, + tasty-focus ==1.0.1, + tasty-golden ==2.3.5, + tasty-hedgehog ==1.4.0.2, + tasty-hslua ==1.1.0, + tasty-hspec ==1.2.0.4, + tasty-html ==0.4.2.1, + tasty-hunit ==0.10.1, + tasty-hunit-compat ==0.2.0.1, + tasty-inspection-testing ==0.2, + tasty-kat ==0.0.3, + tasty-leancheck ==0.0.2, + tasty-lua ==1.1.0, + tasty-program ==1.1.0, + tasty-quickcheck ==0.10.2, + tasty-rerun ==1.1.19, + tasty-silver ==3.3.1.3, + tasty-smallcheck ==0.8.2, + tasty-tap ==0.1.0, + tasty-th ==0.1.7, + tasty-wai ==0.1.2.0, + tce-conf ==1.3, + tdigest ==0.3, + teardown ==0.5.0.1, + tempgres-client ==1.0.0, + template ==0.2.0.10, + template-haskell installed, + template-haskell-compat-v0208 ==0.1.9.3, + temporary ==1.3, + temporary-rc ==1.2.0.3, + temporary-resourcet ==0.1.0.1, + tensorflow-test ==0.1.0.0, + tensors ==0.1.5, + termbox ==2.0.0.1, + termbox-banana ==2.0.0, + termbox-bindings-c ==0.1.0.1, + termbox-bindings-hs ==1.0.0, + termbox-tea ==1.0.0, + terminal-progress-bar ==0.4.2, + terminal-size ==0.3.4, + terminfo installed, + termonad ==4.5.0.0, + test-framework ==0.8.2.0, + test-framework-hunit ==0.3.0.2, + test-framework-leancheck ==0.0.4, + test-framework-quickcheck2 ==0.3.0.5, + test-framework-smallcheck ==0.2, + test-fun ==0.1.0.0, + testing-feat ==1.1.1.1, + testing-type-modifiers ==0.1.0.1, + texmath ==0.12.8.4, + text installed, + text-ansi ==0.3.0.1, + text-binary ==0.2.1.1, + text-builder ==0.6.7.2, + text-builder-dev ==0.3.4.2, + text-builder-linear ==0.1.2, + text-conversions ==0.3.1.1, + text-format ==0.3.2.1, + text-icu ==0.8.0.4, + text-iso8601 ==0.1, + text-latin1 ==0.3.1, + text-ldap ==0.1.1.14, + textlocal ==0.1.0.5, + text-manipulate ==0.3.1.0, + text-metrics ==0.3.2, + text-postgresql ==0.0.3.1, + text-printer ==0.5.0.2, + text-regex-replace ==0.1.1.5, + text-rope ==0.2, + text-short ==0.1.5, + text-show ==3.10.4, + text-show-instances ==3.9.7, + text-zipper ==0.13, + tfp ==1.0.2, + tf-random ==0.5, + th-abstraction ==0.5.0.0, + th-bang-compat ==0.0.1.0, + th-compat ==0.1.4, + th-constraint-compat ==0.0.1.0, + th-data-compat ==0.1.3.0, + th-desugar ==1.15, + th-env ==0.1.1, + these ==1.2, + these-lens ==1.0.1.3, + these-optics ==1.0.1.2, + these-skinny ==0.7.5, + th-expand-syns ==0.4.11.0, + th-extras ==0.0.0.6, + th-lego ==0.3.0.2, + th-lift ==0.8.4, + th-lift-instances ==0.1.20, + th-nowq ==0.1.0.5, + th-orphans ==0.13.14, + th-printf ==0.8, + thread-hierarchy ==0.3.0.2, + thread-local-storage ==0.2, + threads ==0.5.1.8, + threads-extras ==0.1.0.3, + thread-supervisor ==0.2.0.0, + threepenny-gui ==0.9.4.0, + th-reify-compat ==0.0.1.5, + th-reify-many ==0.1.10, + th-strict-compat ==0.1.0.1, + th-test-utils ==1.2.1, + th-utilities ==0.2.5.0, + thyme ==0.4, + tidal ==1.9.4, + tidal-link ==1.0.1, + tile ==0.3.0.0, + time installed, + time-compat ==1.9.6.1, + time-domain ==0.1.0.2, + timeit ==2.0, + time-lens ==0.4.0.2, + timelens ==0.2.0.2, + time-locale-compat ==0.1.1.5, + time-locale-vietnamese ==1.0.0.0, + time-manager ==0.0.1, + time-parsers ==0.2, + timerep ==2.1.0.0, + timers-tick ==0.5.0.4, + timer-wheel ==1.0.0, + timespan ==0.4.0.0, + time-units ==1.0.0, + time-units-types ==0.2.0.1, + timezone-olson ==0.2.1, + timezone-olson-th ==0.1.0.11, + timezone-series ==0.1.13, + titlecase ==1.0.1, + tldr ==0.9.2, + tls ==1.8.0, + tls-session-manager ==0.0.4, + tlynx ==0.7.2.2, + tmapchan ==0.0.3, + tmapmvar ==0.0.4, + tmp-proc ==0.5.3.0, + tmp-proc-postgres ==0.5.3.1, + tmp-proc-rabbitmq ==0.5.3.1, + tmp-proc-redis ==0.5.3.1, + token-bucket ==0.1.0.1, + toml-parser ==1.3.1.0, + toml-reader ==0.2.1.0, + toml-reader-parse ==0.1.1.1, + tophat ==1.0.7.0, + topograph ==1.0.0.2, + torrent ==10000.1.3, + torsor ==0.1, + tostring ==0.2.1.1, + tracing ==0.0.7.3, + transaction ==0.1.1.4, + transformers installed, + transformers-base ==0.4.6, + transformers-compat ==0.7.2, + transformers-either ==0.1.4, + traverse-with-class ==1.0.1.1, + tree-diff ==0.3.0.1, + tree-fun ==0.8.1.0, + tree-view ==0.5.1, + trie-simple ==0.4.2, + trifecta ==2.1.3, + trimdent ==0.1.0.0, + trivial-constraint ==0.7.0.0, + tsv2csv ==0.1.0.2, + ttc ==1.4.0.0, + ttrie ==0.1.2.2, + tuple ==0.3.0.2, + tuples ==0.1.0.0, + tuples-homogenous-h98 ==0.1.1.0, + tuple-sop ==0.3.1.0, + tuple-th ==0.2.5, + turtle ==1.6.2, + twitter-conduit ==0.6.1, + twitter-types ==0.11.0, + twitter-types-lens ==0.11.0, + typecheck-plugin-nat-simple ==0.1.0.9, + typed-process ==0.2.11.1, + typed-uuid ==0.2.0.0, + type-equality ==1, + type-errors ==0.2.0.2, + type-flip ==0.1.0.0, + type-fun ==0.1.3, + type-hint ==0.1, + type-level-integers ==0.0.1, + type-level-kv-list ==2.0.2.0, + type-level-natural-number ==2.0, + type-level-numbers ==0.1.1.2, + typelits-witnesses ==0.4.0.1, + type-map ==0.1.7.0, + type-natural ==1.3.0.0, + typenums ==0.1.4, + type-of-html ==1.6.2.0, + type-of-html-static ==0.1.0.2, + type-rig ==0.1, + type-set ==0.1.0.0, + type-spec ==0.4.0.0, + typography-geometry ==1.0.1.0, + typst ==0.3.2.1, + typst-symbols ==0.1.4, + tz ==0.1.3.6, + tzdata ==0.2.20230322.0, + tztime ==0.1.1.0, + ua-parser ==0.7.7.0, + uglymemo ==0.1.0.1, + ulid ==0.3.2.0, + unagi-chan ==0.4.1.4, + unbounded-delays ==0.1.1.1, + unboxed-ref ==0.4.0.0, + unboxing-vector ==0.2.0.0, + uncaught-exception ==0.1.0, + unconstrained ==0.1.0.2, + unexceptionalio ==0.5.1, + unfork ==1.0.0.1, + unicode ==0.0.1.1, + unicode-collation ==0.1.3.5, + unicode-data ==0.4.0.1, + unicode-show ==0.1.1.1, + unicode-transforms ==0.4.0.1, + unidecode ==0.1.0.4, + union-angle ==0.1.0.1, + unipatterns ==0.0.0.0, + uniplate ==1.6.13, + uniq-deep ==1.2.1, + unique ==0.0.1, + unique-logic ==0.4.0.1, + unique-logic-tf ==0.5.1, + unit-constraint ==0.0.0, + units-parser ==0.1.1.5, + universe ==1.2.2, + universe-base ==1.1.3.1, + universe-dependent-sum ==1.3, + universe-instances-extended ==1.1.3, + universe-reverse-instances ==1.1.1, + universe-some ==1.2.1, + universum ==1.8.2, + unix installed, + unix-bytestring ==0.4.0, + unix-compat ==0.7.1, + unix-time ==0.4.11, + unjson ==0.15.4, + unliftio ==0.2.25.0, + unliftio-core ==0.2.1.0, + unliftio-path ==0.0.2.0, + unliftio-streams ==0.2.0.0, + unlit ==0.4.0.0, + unordered-containers ==0.2.19.1, + unsafe ==0.0, + uri-bytestring ==0.3.3.1, + uri-bytestring-aeson ==0.1.0.8, + uri-encode ==1.5.0.7, + url ==2.1.3, + urlpath ==11.0.2, + users ==0.5.0.0, + users-test ==0.5.0.1, + utf8-light ==0.4.4.0, + utf8-string ==1.0.2, + utility-ht ==0.0.17, + uuid ==1.3.15, + uuid-types ==1.0.5.1, + valida ==1.1.0, + valida-base ==0.2.0, + validate-input ==0.5.0.0, + validation ==1.1.3, + validity ==0.12.0.2, + validity-aeson ==0.2.0.5, + validity-bytestring ==0.4.1.1, + validity-case-insensitive ==0.0.0.0, + validity-containers ==0.5.0.4, + validity-network-uri ==0.0.0.1, + validity-path ==0.4.0.1, + validity-persistent ==0.0.0.0, + validity-primitive ==0.0.0.1, + validity-scientific ==0.2.0.3, + validity-text ==0.3.1.3, + validity-time ==0.5.0.0, + validity-unordered-containers ==0.2.0.3, + validity-uuid ==0.1.0.3, + validity-vector ==0.2.0.3, + valor ==1.0.0.0, + varying ==0.8.1.0, + vault ==0.3.1.5, + vcs-ignore ==0.0.2.0, + vec ==0.5, + vector ==0.13.1.0, + vector-algorithms ==0.9.0.1, + vector-binary-instances ==0.2.5.2, + vector-buffer ==0.4.1, + vector-builder ==0.3.8.4, + vector-bytes-instances ==0.1.1, + vector-extras ==0.2.8.1, + vector-hashtables ==0.1.1.3, + vector-instances ==3.4.2, + vector-mmap ==0.0.3, + vector-rotcev ==0.1.0.2, + vector-sized ==1.5.0, + vector-space ==0.16, + vector-split ==1.0.0.3, + vector-stream ==0.1.0.0, + vector-th-unbox ==0.2.2, + verbosity ==0.4.0.0, + versions ==6.0.3, + vformat ==0.14.1.0, + vformat-time ==0.1.0.0, + ViennaRNAParser ==1.3.3, + vinyl ==0.14.3, + vinyl-loeb ==0.0.1.0, + Vis ==0.7.7.0, + vivid-osc ==0.5.0.0, + vivid-supercollider ==0.4.1.2, + void ==0.7.3, + vty ==5.39, + wai ==3.2.3, + wai-app-static ==3.1.8, + wai-cli ==0.2.3, + wai-conduit ==3.0.0.4, + wai-control ==0.2.0.0, + wai-cors ==0.2.7, + wai-enforce-https ==1.0.0.0, + wai-eventsource ==3.0.0, + wai-extra ==3.1.13.0, + wai-feature-flags ==0.1.0.7, + wai-handler-launch ==3.0.3.1, + wai-logger ==2.4.0, + wai-middleware-bearer ==1.0.3, + wai-middleware-caching ==0.1.0.2, + wai-middleware-caching-lru ==0.1.0.0, + wai-middleware-caching-redis ==0.2.0.0, + wai-middleware-clacks ==0.1.0.1, + wai-middleware-delegate ==0.1.4.0, + wai-middleware-metrics ==0.2.4, + wai-middleware-prometheus ==1.0.0.1, + wai-middleware-static ==0.9.2, + wai-middleware-throttle ==0.3.0.1, + wai-rate-limit ==0.3.0.0, + wai-rate-limit-redis ==0.2.0.1, + wai-saml2 ==0.5, + wai-session ==0.3.3, + wai-session-postgresql ==0.2.1.3, + wai-session-redis ==0.1.0.5, + wai-slack-middleware ==0.2.0, + wai-transformers ==0.1.0, + wai-websockets ==3.0.1.2, + wakame ==0.1.0.0, + warp ==3.3.31, + warp-tls ==3.4.3, + wave ==0.2.1, + wcwidth ==0.0.2, + webdriver ==0.12.0.0, + webex-teams-api ==0.2.0.1, + webex-teams-conduit ==0.2.0.1, + webgear-core ==1.0.5, + webgear-openapi ==1.0.5, + webpage ==0.0.5.1, + webrtc-vad ==0.1.0.3, + websockets ==0.12.7.3, + websockets-simple ==0.2.0, + websockets-snap ==0.10.3.1, + weigh ==0.0.17, + welford-online-mean-variance ==0.2.0.0, + wide-word ==0.1.6.0, + Win32 installed, + Win32-notify ==0.3.0.3, + windns ==0.1.0.1, + witch ==1.2.0.3, + withdependencies ==0.3.0, + witherable ==0.4.2, + within ==0.2.0.1, + with-location ==0.1.0, + with-utf8 ==1.0.2.4, + witness ==0.6.2, + wizards ==1.0.3, + wl-pprint ==1.2.1, + wl-pprint-annotated ==0.1.0.1, + wl-pprint-text ==1.2.0.2, + word8 ==0.1.3, + word-compat ==0.0.6, + word-trie ==0.3.0, + word-wrap ==0.5, + world-peace ==1.0.2.0, + wrap ==0.0.0, + wraxml ==0.5, + wreq ==0.5.4.2, + wreq-stringless ==0.5.9.1, + writer-cps-transformers ==0.5.6.1, + ws ==0.0.6, + wss-client ==0.3.0.0, + wuss ==2.0.1.5, + X11 ==1.10.3, + X11-xft ==0.3.4, + x11-xim ==0.0.9.0, + x509 ==1.7.7, + x509-store ==1.6.9, + x509-system ==1.6.7, + x509-validation ==1.6.12, + Xauth ==0.1, + xdg-basedir ==0.2.2, + xdg-userdirs ==0.1.0.2, + xeno ==0.6, + xhtml installed, + xlsx ==1.1.1, + xml ==1.3.14, + xml-basic ==0.1.3.2, + xmlbf ==0.7, + xmlbf-xeno ==0.2.2, + xmlbf-xmlhtml ==0.2.2, + xml-conduit ==1.9.1.3, + xmlgen ==0.6.2.2, + xml-hamlet ==0.5.0.2, + xml-helpers ==1.0.0, + xmlhtml ==0.2.5.4, + xml-html-qq ==0.1.0.1, + xml-indexed-cursor ==0.1.1.0, + xml-lens ==0.3.1, + xml-picklers ==0.3.6, + xml-to-json-fast ==2.0.0, + xml-types ==0.3.8, + xmonad ==0.17.2, + xor ==0.0.1.2, + xss-sanitize ==0.3.7.2, + xxhash-ffi ==0.2.0.0, + yaml ==0.11.11.2, + yaml-unscrambler ==0.1.0.17, + Yampa ==0.14.5, + yarn-lock ==0.6.5, + yeshql-core ==4.2.0.0, + yesod ==1.6.2.1, + yesod-auth ==1.6.11.2, + yesod-auth-basic ==0.1.0.3, + yesod-auth-hashdb ==1.7.1.7, + yesod-auth-oauth2 ==0.7.1.3, + yesod-core ==1.6.25.1, + yesod-eventsource ==1.6.0.1, + yesod-fb ==0.6.1, + yesod-form ==1.7.6, + yesod-form-bootstrap4 ==3.0.1.1, + yesod-gitrepo ==0.3.0, + yesod-gitrev ==0.2.2, + yesod-markdown ==0.12.6.13, + yesod-middleware-csp ==1.2.0, + yesod-newsfeed ==1.7.0.0, + yesod-page-cursor ==2.0.1.0, + yesod-paginator ==1.1.2.2, + yesod-persistent ==1.6.0.8, + yesod-recaptcha2 ==1.0.2.1, + yesod-routes-flow ==3.0.0.2, + yesod-sitemap ==1.6.0, + yesod-static ==1.6.1.0, + yesod-test ==1.6.16, + yesod-websockets ==0.3.0.3, + yes-precure5-command ==5.5.3, + yi-rope ==0.11, + yjsvg ==0.2.0.1, + yjtools ==0.9.18, + yoga ==0.0.0.5, + youtube ==0.2.1.1, + zenacy-html ==2.1.0, + zenacy-unicode ==1.0.2, + zeromq4-haskell ==0.8.0, + zeromq4-patterns ==0.3.1.0, + zigzag ==0.0.1.0, + zim-parser ==0.2.1.0, + zip ==2.0.0, + zip-archive ==0.4.3, + zippers ==0.3.2, + zip-stream ==0.2.2.0, + zlib ==0.6.3.0, + zlib-bindings ==0.1.1.5, + zot ==0.0.3, + zstd ==0.1.3.0, + zxcvbn-hs ==0.3.6 diff --git a/cabal-testsuite/PackageTests/VersionPriority/repo/hashable-1.4.2.0/hashable.cabal b/cabal-testsuite/PackageTests/VersionPriority/repo/hashable-1.4.2.0/hashable.cabal new file mode 100644 index 00000000000..be8d96b783d --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/repo/hashable-1.4.2.0/hashable.cabal @@ -0,0 +1,186 @@ +cabal-version: 1.12 +name: hashable +version: 1.4.2.0 +synopsis: A class for types that can be converted to a hash value +description: + This package defines a class, 'Hashable', for types that + can be converted to a hash value. This class + exists for the benefit of hashing-based data + structures. The package provides instances for + basic types and a way to combine hash values. + +homepage: http://github.com/haskell-unordered-containers/hashable + +-- SPDX-License-Identifier : BSD-3-Clause +license: BSD3 +license-file: LICENSE +author: + Milan Straka + Johan Tibell + +maintainer: Oleg Grenrus +bug-reports: + https://github.com/haskell-unordered-containers/hashable/issues + +stability: Provisional +category: Data +build-type: Simple +tested-with: + GHC ==8.2.2 + || ==8.4.4 + || ==8.6.5 + || ==8.8.3 + || ==8.10.4 + || ==8.10.7 + || ==9.0.1 + || ==9.0.2 + || ==9.2.5 + || ==9.4.4 + +extra-source-files: + CHANGES.md + include/HsHashable.h + README.md + +flag integer-gmp + description: + Are we using @integer-gmp@ to provide fast Integer instances? No effect on GHC-9.0 or later. + + manual: False + default: True + +flag random-initial-seed + description: + Randomly initialize the initial seed on each final executable invocation + This is useful for catching cases when you rely on (non-existent) + stability of hashable's hash functions. + This is not a security feature. + + manual: True + default: False + +library + exposed-modules: + Data.Hashable + Data.Hashable.Generic + Data.Hashable.Lifted + + other-modules: + Data.Hashable.Class + Data.Hashable.Generic.Instances + Data.Hashable.Imports + Data.Hashable.LowLevel + + c-sources: cbits/fnv.c + include-dirs: include + hs-source-dirs: src + build-depends: + -- REMOVED constraint on base for test + -- base >=4.10.1.0 && <4.18 + base + , bytestring >=0.10.8.2 && <0.12 + , containers >=0.5.10.2 && <0.7 + , deepseq >=1.4.3.0 && <1.5 + , filepath >=1.4.1.2 && <1.5 + , ghc-prim + , text >=1.2.3.0 && <1.3 || >=2.0 && <2.1 + + -- REMOVED conditional compilation pulling in extra dependencies + -- if !impl(ghc >=9.2) + -- build-depends: base-orphans >=0.8.6 && <0.9 + + -- if !impl(ghc >=9.4) + -- build-depends: data-array-byte >=0.1.0.1 && <0.2 + + -- Integer internals + if impl(ghc >=9) + build-depends: ghc-bignum >=1.0 && <1.4 + + if !impl(ghc >=9.0.2) + build-depends: ghc-bignum-orphans >=0.1 && <0.2 + + else + if flag(integer-gmp) + build-depends: integer-gmp >=0.4 && <1.1 + + else + -- this is needed for the automatic flag to be well-balanced + build-depends: integer-simple + + if (flag(random-initial-seed) && impl(ghc)) + cpp-options: -DHASHABLE_RANDOM_SEED=1 + + if os(windows) + c-sources: cbits-win/init.c + + else + c-sources: cbits-unix/init.c + + default-language: Haskell2010 + other-extensions: + BangPatterns + CPP + DeriveDataTypeable + FlexibleContexts + FlexibleInstances + GADTs + KindSignatures + MagicHash + MultiParamTypeClasses + ScopedTypeVariables + Trustworthy + TypeOperators + UnliftedFFITypes + + ghc-options: -Wall -fwarn-tabs + + if impl(ghc >=9.0) + -- these flags may abort compilation with GHC-8.10 + -- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3295 + ghc-options: -Winferred-safe-imports -Wmissing-safe-haskell-mode + +test-suite hashable-tests + type: exitcode-stdio-1.0 + hs-source-dirs: tests + main-is: Main.hs + other-modules: + Properties + Regress + + build-depends: + base + , bytestring + , ghc-prim + , hashable + , HUnit + , QuickCheck >=2.4.0.1 + , random >=1.0 && <1.3 + , test-framework >=0.3.3 + , test-framework-hunit + , test-framework-quickcheck2 >=0.2.9 + , text >=0.11.0.5 + + if !os(windows) + build-depends: unix + cpp-options: -DHAVE_MMAP + other-modules: Regress.Mmap + other-extensions: CApiFFI + + ghc-options: -Wall -fno-warn-orphans + default-language: Haskell2010 + +test-suite hashable-examples + type: exitcode-stdio-1.0 + build-depends: + base + , ghc-prim + , hashable + + hs-source-dirs: examples + main-is: Main.hs + default-language: Haskell2010 + +source-repository head + type: git + location: + https://github.com/haskell-unordered-containers/hashable.git diff --git a/cabal-testsuite/PackageTests/VersionPriority/repo/hashable-1.4.3.0/hashable.cabal b/cabal-testsuite/PackageTests/VersionPriority/repo/hashable-1.4.3.0/hashable.cabal new file mode 100644 index 00000000000..69efe15c086 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/repo/hashable-1.4.3.0/hashable.cabal @@ -0,0 +1,188 @@ +cabal-version: 1.12 +name: hashable +version: 1.4.3.0 +synopsis: A class for types that can be converted to a hash value +description: + This package defines a class, 'Hashable', for types that + can be converted to a hash value. This class + exists for the benefit of hashing-based data + structures. The package provides instances for + basic types and a way to combine hash values. + . + The 'Hashable' 'hash' values are not guaranteed to be stable across library versions, operating systems or architectures. For stable hashing use named hashes: SHA256, CRC32 etc. + +homepage: http://github.com/haskell-unordered-containers/hashable + +-- SPDX-License-Identifier : BSD-3-Clause +license: BSD3 +license-file: LICENSE +author: + Milan Straka + Johan Tibell + +maintainer: Oleg Grenrus +bug-reports: + https://github.com/haskell-unordered-containers/hashable/issues + +stability: Provisional +category: Data +build-type: Simple +tested-with: + GHC ==8.2.2 + || ==8.4.4 + || ==8.6.5 + || ==8.8.3 + || ==8.10.4 + || ==8.10.7 + || ==9.0.1 + || ==9.0.2 + || ==9.2.5 + || ==9.4.4 + || ==9.6.1 + +extra-source-files: + CHANGES.md + include/HsHashable.h + README.md + +flag integer-gmp + description: + Are we using @integer-gmp@ to provide fast Integer instances? No effect on GHC-9.0 or later. + + manual: False + default: True + +flag random-initial-seed + description: + Randomly initialize the initial seed on each final executable invocation + This is useful for catching cases when you rely on (non-existent) + stability of hashable's hash functions. + This is not a security feature. + + manual: True + default: False + +library + exposed-modules: + Data.Hashable + Data.Hashable.Generic + Data.Hashable.Lifted + + other-modules: + Data.Hashable.Class + Data.Hashable.Generic.Instances + Data.Hashable.Imports + Data.Hashable.LowLevel + + c-sources: cbits/fnv.c + include-dirs: include + hs-source-dirs: src + build-depends: + -- REMOVED constraint on base for test + -- base >=4.10.1.0 && <4.19 + base + , bytestring >=0.10.8.2 && <0.12 + , containers >=0.5.10.2 && <0.7 + , deepseq >=1.4.3.0 && <1.5 + , filepath >=1.4.1.2 && <1.5 + , ghc-prim + , text >=1.2.3.0 && <1.3 || >=2.0 && <2.1 + + if !impl(ghc >=9.2) + build-depends: base-orphans >=0.8.6 && <0.10 + + if !impl(ghc >=9.4) + build-depends: data-array-byte >=0.1.0.1 && <0.2 + + -- Integer internals + if impl(ghc >=9) + build-depends: ghc-bignum >=1.0 && <1.4 + + if !impl(ghc >=9.0.2) + build-depends: ghc-bignum-orphans >=0.1 && <0.2 + + else + if flag(integer-gmp) + build-depends: integer-gmp >=0.4 && <1.1 + + else + -- this is needed for the automatic flag to be well-balanced + build-depends: integer-simple + + if (flag(random-initial-seed) && impl(ghc)) + cpp-options: -DHASHABLE_RANDOM_SEED=1 + + if os(windows) + c-sources: cbits-win/init.c + + else + c-sources: cbits-unix/init.c + + default-language: Haskell2010 + other-extensions: + BangPatterns + CPP + DeriveDataTypeable + FlexibleContexts + FlexibleInstances + GADTs + KindSignatures + MagicHash + MultiParamTypeClasses + ScopedTypeVariables + Trustworthy + TypeOperators + UnliftedFFITypes + + ghc-options: -Wall -fwarn-tabs + + if impl(ghc >=9.0) + -- these flags may abort compilation with GHC-8.10 + -- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3295 + ghc-options: -Winferred-safe-imports -Wmissing-safe-haskell-mode + +test-suite hashable-tests + type: exitcode-stdio-1.0 + hs-source-dirs: tests + main-is: Main.hs + other-modules: + Properties + Regress + + build-depends: + base + , bytestring + , ghc-prim + , hashable + , HUnit + , QuickCheck >=2.4.0.1 + , random >=1.0 && <1.3 + , test-framework >=0.3.3 + , test-framework-hunit + , test-framework-quickcheck2 >=0.2.9 + , text >=0.11.0.5 + + if !os(windows) + build-depends: unix + cpp-options: -DHAVE_MMAP + other-modules: Regress.Mmap + other-extensions: CApiFFI + + ghc-options: -Wall -fno-warn-orphans + default-language: Haskell2010 + +test-suite hashable-examples + type: exitcode-stdio-1.0 + build-depends: + base + , ghc-prim + , hashable + + hs-source-dirs: examples + main-is: Main.hs + default-language: Haskell2010 + +source-repository head + type: git + location: + https://github.com/haskell-unordered-containers/hashable.git diff --git a/cabal-testsuite/PackageTests/VersionPriority/stackage-local.config b/cabal-testsuite/PackageTests/VersionPriority/stackage-local.config new file mode 100644 index 00000000000..23e32e2f5a8 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/stackage-local.config @@ -0,0 +1,2 @@ +-- Same constraint as on stackage at https://www.stackage.org/nightly-2023-12-07/cabal.config +constraints: hashable ==1.4.3.0 diff --git a/cabal-testsuite/PackageTests/VersionPriority/stackage-web.config b/cabal-testsuite/PackageTests/VersionPriority/stackage-web.config new file mode 100644 index 00000000000..8f7904cbc5f --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/stackage-web.config @@ -0,0 +1,5 @@ +-- NOTE: We could have grabbed this config from stackage but we don't to avoid +-- making an HTTP request with the test. So instead we save it locally. +-- +-- $ curl https://www.stackage.org/nightly-2023-12-07/cabal.config --output project-stackage/nightly-2023-12-07.config +import: project-stackage/nightly-2023-12-07.config diff --git a/cabal-testsuite/PackageTests/VersionPriority/with-ghc.config b/cabal-testsuite/PackageTests/VersionPriority/with-ghc.config new file mode 100644 index 00000000000..140a00be1b9 --- /dev/null +++ b/cabal-testsuite/PackageTests/VersionPriority/with-ghc.config @@ -0,0 +1,7 @@ +-- WARNING: Override the `with-compiler: ghc-x.y.z` of the stackage import, of +-- https://www.stackage.org/nightly-yyyy-mm-dd/cabal.config. Otherwise tests +-- will fail with: +-- -Error: [Cabal-5490] +-- -Cannot find the program 'ghc'. User-specified path 'ghc-x.y.z' does not +-- refer to an executable and the program is not on the system path. +with-compiler: ghc diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/WarnEarlyOverwrite.cabal b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/WarnEarlyOverwrite.cabal new file mode 100644 index 00000000000..a630a95551e --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/WarnEarlyOverwrite.cabal @@ -0,0 +1,16 @@ +cabal-version: 3.0 +name: WarnEarlyOverwrite +version: 0.1.0.0 +license: BSD-3-Clause +author: Phil de Joux +build-type: Simple + +common warnings + ghc-options: -Wall + +executable warn-early-overwrite + import: warnings + main-is: Main.hs + build-depends: base + hs-source-dirs: app + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/app/Main.hs b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/app/Main.hs new file mode 100644 index 00000000000..9e6d506d89d --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/app/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = putStrLn "Early warning" diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/cabal.project b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-copy.out b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-copy.out new file mode 100644 index 00000000000..16279ab51e4 --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-copy.out @@ -0,0 +1,12 @@ +# cabal v2-install +Wrote tarball sdist to /clean-install-by-copy.dist/work/./dist/sdist/WarnEarlyOverwrite-0.1.0.0.tar.gz +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - WarnEarlyOverwrite-0.1.0.0 (exe:warn-early-overwrite) (requires build) +Configuring executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Preprocessing executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Building executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Installing executable warn-early-overwrite in +Warning: The directory /ghc-/incoming/new-/ghc-/-/bin is not in the system search path. +Copying 'warn-early-overwrite' to '/warn-early-overwrite' diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-copy.test.hs b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-copy.test.hs new file mode 100644 index 00000000000..700421fcedb --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-copy.test.hs @@ -0,0 +1,13 @@ +import Test.Cabal.Prelude + +main = withShorterPathForNewBuildStore $ \storeDir -> cabalTest $ do + let options = ["--store-dir=" ++ storeDir, "--installdir=" ++ storeDir] + -- Use install method copy that should surely work on Windows too but our + -- path normalization for testing is not good enough yet as can be seen in + -- this CI failure snippet diff: + -- -Warning: The directory /ghc-/incoming/new-/ghc-/-/bin is not in the system search path. + -- -Copying 'warn-early-overwrite' to '/warn-early-overwrite' + -- +Warning: The directory /incoming/new-2448/Users/RUNNER~1/AppData/Local/Temp/cabal-test-store-28260/ghc-/WarnEarlyOver_-0.1.0.0-4c19059e06a32b93b2812983631117e77a2d3833/bin is not in the system search path. + -- +Copying 'warn-early-overwrite' to '' + skipIfWindows + cabalG options "v2-install" ["--install-method=copy"] diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-symlink.out b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-symlink.out new file mode 100644 index 00000000000..ad487891384 --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-symlink.out @@ -0,0 +1,12 @@ +# cabal v2-install +Wrote tarball sdist to /clean-install-by-symlink.dist/work/./dist/sdist/WarnEarlyOverwrite-0.1.0.0.tar.gz +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - WarnEarlyOverwrite-0.1.0.0 (exe:warn-early-overwrite) (requires build) +Configuring executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Preprocessing executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Building executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Installing executable warn-early-overwrite in +Warning: The directory /ghc-/incoming/new-/ghc-/-/bin is not in the system search path. +Symlinking 'warn-early-overwrite' to '/warn-early-overwrite' diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-symlink.test.hs b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-symlink.test.hs new file mode 100644 index 00000000000..c2d12c0caf1 --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/clean-install-by-symlink.test.hs @@ -0,0 +1,7 @@ +import Test.Cabal.Prelude + +main = withShorterPathForNewBuildStore $ \storeDir -> cabalTest $ do + -- The default install method is symlink that may not work on Windows. + skipIfWindows + let options = ["--store-dir=" ++ storeDir, "--installdir=" ++ storeDir] + cabalG options "v2-install" [] diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/dirty-install.out b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/dirty-install.out new file mode 100644 index 00000000000..3a813eebf45 --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/dirty-install.out @@ -0,0 +1,20 @@ +# cabal v2-install +Wrote tarball sdist to /dirty-install.dist/work/./dist/sdist/WarnEarlyOverwrite-0.1.0.0.tar.gz +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - WarnEarlyOverwrite-0.1.0.0 (exe:warn-early-overwrite) (requires build) +Error: [Cabal-7149] +Path '/warn-early-overwrite' already exists. Use --overwrite-policy=always to overwrite. +# cabal v2-install +Wrote tarball sdist to /dirty-install.dist/work/./dist/sdist/WarnEarlyOverwrite-0.1.0.0.tar.gz +Resolving dependencies... +Build profile: -w ghc- -O1 +In order, the following will be built: + - WarnEarlyOverwrite-0.1.0.0 (exe:warn-early-overwrite) (requires build) +Configuring executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Preprocessing executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Building executable 'warn-early-overwrite' for WarnEarlyOverwrite-0.1.0.0... +Installing executable warn-early-overwrite in +Warning: The directory /ghc-/incoming/new-/ghc-/-/bin is not in the system search path. +Symlinking 'warn-early-overwrite' to '/warn-early-overwrite' diff --git a/cabal-testsuite/PackageTests/WarnEarlyOverwrite/dirty-install.test.hs b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/dirty-install.test.hs new file mode 100644 index 00000000000..c91ee226ba9 --- /dev/null +++ b/cabal-testsuite/PackageTests/WarnEarlyOverwrite/dirty-install.test.hs @@ -0,0 +1,13 @@ +import Test.Cabal.Prelude + +import System.FilePath + +main = withShorterPathForNewBuildStore $ \storeDir -> cabalTest $ do + -- Windows does not natively include a touch command. + -- SEE: https://stackoverflow.com/questions/30011267/create-an-empty-file-on-the-commandline-in-windows-like-the-linux-touch-command + skipIfWindows + let options = ["--store-dir=" ++ storeDir, "--installdir=" ++ storeDir] + -- Touch the target to see if the warning is made early before the build. + _ <- runM "touch" [storeDir "warn-early-overwrite"] Nothing + fails $ cabalG options "v2-install" [] + cabalG options "v2-install" ["--overwrite-policy=always"] diff --git a/cabal-testsuite/README.md b/cabal-testsuite/README.md index 1fba1d85446..afe08e499dc 100644 --- a/cabal-testsuite/README.md +++ b/cabal-testsuite/README.md @@ -25,6 +25,34 @@ There are a few useful flags: the autodetection doesn't work correctly (which may be the case for old versions of GHC.) +* `--keep-tmp-files` can be used to keep the temporary directories that tests + are run in. + +## Which Cabal library version do cabal-install tests use? + +By default the `cabal-install` tests will use the `Cabal` library which comes with +the boot compiler when it needs to build a custom `Setup.hs`. + +This can be very confusing if you are modifying the Cabal library, writing a test +which relies on a custom setup script and you are wondering why the test is not +responding at all to your changes. + +There are some flags which allow you to instruct `cabal-install` to use a different +`Cabal` library version. + +1. `--boot-cabal-lib` specifies to use the Cabal library bundled with the + test compiler, this is the default. +2. `--intree-cabal-lib=` specifies to use Cabal and Cabal-syntax + from a specific directory, and `--test-tmp` indicates where to put + the package database they are built into. +3. `--specific-cabal-lib=` specifies to use a specific Cabal + version from hackage (ie 3.10.2.0) and installs the package database + into `--test-tmp=` + +The CI scripts use the `--intree-cabal-lib` option for the most part but in +the future there should be a variety of jobs which test `cabal-install` built +against newer `Cabal` versions but forced to interact with older `Cabal` versions. + ### How to run the doctests You need to install the `doctest` tool. Make sure it's compiled with your current @@ -55,6 +83,16 @@ see the full contents of various commits which added a test for various functionality. See if you can find an existing test that is similar to what you want to test. +Tests are all run in temporary system directories. At the start of a test +all the files which are in the same folder as the test script are copied into +a system temporary directory and then the rest of the script operates in this +directory. + +**NOTE:** only files which are known to git are copied, so you have to +`git add` any files which are part of a test before running the test. +You can use the `--keep-tmp-files` flag to keep the temporary directories in +order to inspect the result of running a test. + Otherwise, here is a walkthrough: 1. Create the package(s) that you need for your test in a @@ -96,6 +134,15 @@ Otherwise, here is a walkthrough: ... ``` + The dependencies which your test is allowed to use are listed in the + cabal file under the `test-runtime-deps` executable. At compile-time there is + a custom Setup.hs script which inspects this list and records the versions of + each package in a generated file. These are then used when `cabal-tests` runs + when it invokes `runghc` to run each test. + We ensure they are built and available by listing `test-runtime-deps` in the + build-tool-depends section of the cabal-tests executable. + + 3. Run your tests using `cabal-tests` (no need to rebuild when you add or modify a test; it is automatically picked up). The first time you run a test, assuming everything else is @@ -119,11 +166,6 @@ test output?** Only "marked" output is picked up by Cabal; currently, only `notice`, `warn` and `die` produce marked output. Use those combinators for your output. -**How do I safely let my test modify version-controlled source files?** -Use `withSourceCopy`. Note that you MUST `git add` -all files which are relevant to the test; otherwise they will not be -available when running the test. - **How can I add a dependency on a package from Hackage in a test?** By default, the test suite is completely independent of the contents of Hackage, to ensure that it keeps working across all GHC versions. @@ -156,8 +198,7 @@ and stderr. **How do I skip running a test in some environments?** Use the `skipIf` and `skipUnless` combinators. Useful parameters to test these with include `hasSharedLibraries`, `hasProfiledLibraries`, -`hasCabalShared`, `isGhcVersion`, `isWindows`, `isLinux`, `isOSX` -and `hasCabalForGhc`. +`hasCabalShared`, `isGhcVersion`, `isWindows`, `isLinux`, `isOSX`. **I programmatically modified a file in my test suite, but Cabal/GHC doesn't seem to be picking it up.** You need to sleep sufficiently @@ -173,14 +214,8 @@ string output test, if that is how your test is "failing." Hermetic tests -------------- -By default, we run tests directly on the source code that is checked into the -source code repository. However, some tests require programmatically -modifying source files, or interact with Cabal commands which are -not hermetic (e.g., `cabal freeze`). In this case, cabal-testsuite -supports opting into a hermetic test, where we first make copy of all -the relevant source code before starting the test. You can opt into -this mode using the `withSourceCopy` combinator (search for examples!) -This mode is subject to the following limitations: +Tests are run in a fresh temporary system directory. This attempts to isolate the +tests from anything specific to do with your directory structure. In particular * You must be running the test inside a valid Git checkout of the test suite (`withSourceCopy` uses Git to determine which files should be copied.) @@ -188,9 +223,6 @@ This mode is subject to the following limitations: * You must `git add` all files which are relevant to the test, otherwise they will not be copied. -* The source copy is still made at a well-known location, so running - a test is still not reentrant. (See also Known Limitations.) - Design notes ------------ @@ -335,11 +367,3 @@ Here are some things we do not currently plan on supporting: of our tests need substantial setup; for example, tests that have to setup a package repository. In this case, because there already is a setup necessary, we might consider making things easier here.) - -Known limitations ------------------ - -* Tests are NOT reentrant: test build products are always built into - the same location, and if you run the same test at the same time, - you will clobber each other. This is convenient for debugging and - doesn't seem to be a problem in practice. diff --git a/cabal-testsuite/Setup.hs b/cabal-testsuite/Setup.hs index 2b212906a60..d83f9dc60e8 100644 --- a/cabal-testsuite/Setup.hs +++ b/cabal-testsuite/Setup.hs @@ -73,7 +73,7 @@ canonicalizePackageDB x = return x -- non-Backpack. cabalTestsPackages :: LocalBuildInfo -> [(OpenUnitId, ModuleRenaming)] cabalTestsPackages lbi = - case componentNameCLBIs lbi (CExeName (mkUnqualComponentName "cabal-tests")) of + case componentNameCLBIs lbi (CExeName (mkUnqualComponentName "test-runtime-deps")) of [clbi] -> -- [ (unUnitId $ unDefUnitId duid,rn) | (DefiniteUnitId duid, rn) <- componentIncludes clbi ] componentIncludes clbi _ -> error "cabalTestsPackages" diff --git a/cabal-testsuite/cabal-testsuite.cabal b/cabal-testsuite/cabal-testsuite.cabal index 125ba5ecd55..cb5a3fe605d 100644 --- a/cabal-testsuite/cabal-testsuite.cabal +++ b/cabal-testsuite/cabal-testsuite.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: cabal-testsuite version: 3 -copyright: 2003-2023, Cabal Development Team (see AUTHORS file) +copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team @@ -26,10 +26,11 @@ common shared default-language: Haskell2010 build-depends: - , base >= 4.9 && <4.19 + , base >= 4.9 && <4.20 -- this needs to match the in-tree lib:Cabal version , Cabal ^>= 3.11.0.0 , Cabal-syntax ^>= 3.11.0.0 + , Cabal-tests ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns @@ -57,25 +58,25 @@ library Test.Cabal.ScriptEnv0 build-depends: - , aeson ^>= 1.4.2.0 || ^>=1.5.0.0 || ^>= 2.0.0.0 || ^>= 2.1.0.0 + , aeson ^>= 1.4.2.0 || ^>=1.5.0.0 || ^>= 2.0.0.0 || ^>= 2.1.0.0 || ^>= 2.2.1.0 , async ^>= 2.2.1 , attoparsec ^>= 0.13.2.2 || ^>=0.14.1 - , base64-bytestring ^>= 1.0.0.0 || ^>= 1.1.0.0 || ^>= 1.2.0.0 + , base16-bytestring ^>= 0.1.1.5 || ^>= 1.0 , bytestring ^>= 0.10.0.2 || ^>= 0.11.0.0 || ^>= 0.12.0.0 - , containers ^>= 0.5.0.0 || ^>= 0.6.0.1 + , containers ^>= 0.5.0.0 || ^>= 0.6.0.1 || ^>= 0.7 , cryptohash-sha256 ^>= 0.11.101.0 , directory ^>= 1.2.0.1 || ^>= 1.3.0.0 , exceptions ^>= 0.10.0 - , filepath ^>= 1.3.0.1 || ^>= 1.4.0.0 + , filepath ^>= 1.3.0.1 || ^>= 1.4.0.0 || ^>= 1.5.0.0 , network-wait ^>= 0.1.2.0 || ^>= 0.2.0.0 - , optparse-applicative ^>= 0.14.3.0 || ^>=0.15.1.0 || ^>=0.16.0.0 || ^>= 0.17.0.0 + , optparse-applicative ^>= 0.14.3.0 || ^>=0.15.1.0 || ^>=0.16.0.0 || ^>= 0.17.0.0 || ^>= 0.18.1.0 , process ^>= 1.2.1.0 || ^>= 1.4.2.0 || ^>= 1.6.1.0 , regex-base ^>= 0.94.0.1 , regex-tdfa ^>= 1.2.3.1 || ^>=1.3.1.0 , retry ^>= 0.9.1.0 , array ^>= 0.4.0.1 || ^>= 0.5.0.0 , temporary ^>= 1.3 - , text ^>= 1.2.3.1 || ^>= 2.0.1 + , text ^>= 1.2.3.1 || ^>= 2.0.1 || ^>= 2.1 , transformers ^>= 0.3.0.0 || ^>= 0.4.2.0 || ^>= 0.5.2.0 || ^>= 0.6.0.2 if !os(windows) @@ -90,6 +91,8 @@ executable cabal-tests main-is: cabal-tests.hs hs-source-dirs: main ghc-options: -threaded + -- Make sure these are built before the executable is run + build-tool-depends: cabal-testsuite:test-runtime-deps build-depends: , cabal-testsuite -- constraints inherited via lib:cabal-testsuite component @@ -101,6 +104,7 @@ executable cabal-tests , transformers -- dependencies specific to exe:cabal-tests , clock ^>= 0.7.2 || ^>=0.8 + , directory build-tool-depends: cabal-testsuite:setup default-extensions: TypeOperators @@ -110,6 +114,33 @@ executable setup import: shared main-is: Setup.simple.hs +-- This executable component is used to describe the runtime dependencies of +-- the tests. The Main.hs file and resulting executable are not useful in any way. + +-- Ideally this would be an empty library, but because build-type: Custom, we can't +-- have sublibraries. + +-- If you require an external dependency for a test it must be listed here. +executable test-runtime-deps + default-language: Haskell2010 + build-depends: cabal-testsuite, + base, + directory, + Cabal, + Cabal-syntax, + filepath, + transformers, + bytestring, + time, + process, + exceptions + main-is: static/Main.hs + if !os(windows) + build-depends: unix + else + build-depends: + , Win32 + custom-setup -- we only depend on even stable releases of lib:Cabal -- and due to Custom complexity and ConstraintSetupCabalMaxVersion diff --git a/cabal-testsuite/cabal.project b/cabal-testsuite/cabal.project new file mode 100644 index 00000000000..17b04a2b56f --- /dev/null +++ b/cabal-testsuite/cabal.project @@ -0,0 +1,6 @@ +-- This intercepting project is here to avoid tests picking up a cabal.project +-- from a parent directory, such as the one in the root of the `haskell/cabal` +-- project itself. Having `optional-packages: .` avoids the folowing warning +-- being added to the `.out` file: +-- Warning: There are no packages or optional-packages in the project +optional-packages: . diff --git a/cabal-testsuite/main/cabal-tests.hs b/cabal-testsuite/main/cabal-tests.hs index 2ea070bff07..b6a76ccf485 100644 --- a/cabal-testsuite/main/cabal-tests.hs +++ b/cabal-testsuite/main/cabal-tests.hs @@ -11,6 +11,7 @@ import Test.Cabal.TestCode import Distribution.Verbosity (normal, verbose, Verbosity) import Distribution.Simple.Utils (getDirectoryContentsRecursive) +import Distribution.Simple.Program import Options.Applicative import Control.Concurrent.MVar @@ -26,6 +27,9 @@ import System.IO import System.FilePath import System.Exit import System.Process (callProcess, showCommandForUser) +import System.Directory +import Distribution.Pretty +import Data.Maybe #if !MIN_VERSION_base(4,12,0) import Data.Monoid ((<>)) @@ -34,6 +38,35 @@ import Data.Monoid ((<>)) import Data.Monoid (mempty) #endif +{- Note [Testsuite package environments] + +There are three different package environments which are used when running the +testsuite. + +1. Environment used to compile `cabal-tests` executable +2. Environment used to run test scripts "setup.test.hs" +3. Environment made available to tests themselves via `./Setup configure` + +These are all distinct from each other and should be specified separately. + +Where are these environments specified: + +1. The build-depends on `cabal-tests` executable in `cabal-testsuite.cabal` +2. The build-depends of `test-runtime-deps` executable in `cabal-testsuite.cabal` + These dependencies are injected in a special module (`Test.Cabal.ScriptEnv0`) which + then is consulted in `Test.Cabal.Monad` in order to pass the right environmnet. + This is mechanism by which the `./Setup` tests have access to the in-tree `Cabal` + and `Cabal-syntax` libraries. +3. No specification, only the `GlobalPackageDb` is available (see + `testPackageDBStack`) unless the test itself augments the environment with + `withPackageDb`. + +At the moment, `cabal-install` tests always use the bootstrap cabal, which is a +bit confusing but `cabal-install` is not flexible enough to be given additional +package databases (yet). + +-} + -- | Record for arguments that can be passed to @cabal-tests@ executable. data MainArgs = MainArgs { mainArgThreads :: Int, @@ -42,9 +75,22 @@ data MainArgs = MainArgs { mainArgVerbose :: Bool, mainArgQuiet :: Bool, mainArgDistDir :: Maybe FilePath, + mainArgCabalSpec :: Maybe CabalLibSpec, mainCommonArgs :: CommonArgs } +data CabalLibSpec = BootCabalLib | InTreeCabalLib FilePath FilePath | SpecificCabalLib String FilePath + +cabalLibSpecParser :: Parser CabalLibSpec +cabalLibSpecParser = bootParser <|> intreeParser <|> specificParser + where + bootParser = flag' BootCabalLib (long "boot-cabal-lib") + intreeParser = InTreeCabalLib <$> strOption (long "intree-cabal-lib" <> metavar "ROOT") + <*> option str ( help "Test TMP" <> long "test-tmp" ) + specificParser = SpecificCabalLib <$> strOption (long "specific-cabal-lib" <> metavar "VERSION") + <*> option str ( help "Test TMP" <> long "test-tmp" ) + + -- | optparse-applicative parser for 'MainArgs' mainArgParser :: Parser MainArgs mainArgParser = MainArgs @@ -73,8 +119,52 @@ mainArgParser = MainArgs ( help "Dist directory we were built with" <> long "builddir" <> metavar "DIR")) + <*> optional cabalLibSpecParser <*> commonArgParser +-- Unpack and build a specific released version of Cabal and Cabal-syntax libraries +buildCabalLibsProject :: String -> Verbosity -> Maybe FilePath -> FilePath -> IO FilePath +buildCabalLibsProject projString verb mbGhc dir = do + let prog_db = userSpecifyPaths [("ghc", path) | Just path <- [mbGhc] ] defaultProgramDb + (cabal, _) <- requireProgram verb (simpleProgram "cabal") prog_db + (ghc, _) <- requireProgram verb ghcProgram prog_db + + let pv = fromMaybe (error "no ghc version") (programVersion ghc) + let final_package_db = dir "dist-newstyle" "packagedb" "ghc-" ++ prettyShow pv + createDirectoryIfMissing True dir + writeFile (dir "cabal.project-test") projString + + runProgramInvocation verb + ((programInvocation cabal + ["--store-dir", dir "store" + , "--project-file=" ++ dir "cabal.project-test" + , "build" + , "-w", programPath ghc + , "Cabal", "Cabal-syntax"] ) { progInvokeCwd = Just dir }) + return final_package_db + + +buildCabalLibsSpecific :: String -> Verbosity -> Maybe FilePath -> FilePath -> IO FilePath +buildCabalLibsSpecific ver verb mbGhc builddir_rel = do + let prog_db = userSpecifyPaths [("ghc", path) | Just path <- [mbGhc] ] defaultProgramDb + (cabal, _) <- requireProgram verb (simpleProgram "cabal") prog_db + dir <- canonicalizePath (builddir_rel "specific" ver) + cgot <- doesDirectoryExist (dir "Cabal-" ++ ver) + unless cgot $ + runProgramInvocation verb ((programInvocation cabal ["get", "Cabal-" ++ ver]) { progInvokeCwd = Just dir }) + csgot <- doesDirectoryExist (dir "Cabal-syntax-" ++ ver) + unless csgot $ + runProgramInvocation verb ((programInvocation cabal ["get", "Cabal-syntax-" ++ ver]) { progInvokeCwd = Just dir }) + + buildCabalLibsProject ("packages: Cabal-" ++ ver ++ " Cabal-syntax-" ++ ver) verb mbGhc dir + + +buildCabalLibsIntree :: String -> Verbosity -> Maybe FilePath -> FilePath -> IO FilePath +buildCabalLibsIntree root verb mbGhc builddir_rel = do + dir <- canonicalizePath (builddir_rel "intree") + buildCabalLibsProject ("packages: " ++ root "Cabal" ++ " " ++ root "Cabal-syntax") verb mbGhc dir + + main :: IO () main = do -- By default, stderr is not buffered. This isn't really necessary @@ -86,6 +176,27 @@ main = do args <- execParser $ info (mainArgParser <**> helper) mempty let verbosity = if mainArgVerbose args then verbose else normal + mpkg_db <- + -- Not path to cabal-install so we're not going to run cabal-install tests so we + -- can skip setting up a Cabal library to use with cabal-install. + case argCabalInstallPath (mainCommonArgs args) of + Nothing -> do + when (isJust $ mainArgCabalSpec args) + (putStrLn "Ignoring Cabal library specification as cabal-install tests are not running") + return Nothing + -- Path to cabal-install is passed, so need to install the requested relevant version of Cabal + -- library. + Just {} -> + case mainArgCabalSpec args of + Nothing -> do + putStrLn "No Cabal library specified, using boot Cabal library with cabal-install tests" + return Nothing + Just BootCabalLib -> return Nothing + Just (InTreeCabalLib root build_dir) -> + Just <$> buildCabalLibsIntree root verbosity (argGhcPath (mainCommonArgs args)) build_dir + Just (SpecificCabalLib ver build_dir) -> + Just <$> buildCabalLibsSpecific ver verbosity (argGhcPath (mainCommonArgs args)) build_dir + -- To run our test scripts, we need to be able to run Haskell code -- linked against the Cabal library under test. The most efficient -- way to get this information is by querying the *host* build @@ -111,7 +222,7 @@ main = do -> IO result runTest runner path = runner Nothing [] path $ - ["--builddir", dist_dir, path] ++ renderCommonArgs (mainCommonArgs args) + ["--builddir", dist_dir, path] ++ ["--extra-package-db=" ++ pkg_db | Just pkg_db <- [mpkg_db]] ++ renderCommonArgs (mainCommonArgs args) case mainArgTestPaths args of [path] -> do diff --git a/cabal-testsuite/src/Test/Cabal/Monad.hs b/cabal-testsuite/src/Test/Cabal/Monad.hs index 8ed40dc416f..3896ee18b0b 100644 --- a/cabal-testsuite/src/Test/Cabal/Monad.hs +++ b/cabal-testsuite/src/Test/Cabal/Monad.hs @@ -20,6 +20,9 @@ module Test.Cabal.Monad ( cabalProgram, diffProgram, python3Program, + requireSuccess, + initWorkDir, + recordLog, -- * The test environment TestEnv(..), getTestEnv, @@ -63,7 +66,7 @@ import Test.Cabal.TestCode import Distribution.Pretty (prettyShow) import Distribution.Simple.Compiler ( PackageDBStack, PackageDB(..), compilerFlavor - , Compiler, compilerVersion, showCompilerId ) + , Compiler, compilerVersion, showCompilerIdWithAbi ) import Distribution.System import Distribution.Simple.Program.Db import Distribution.Simple.Program @@ -72,7 +75,7 @@ import Distribution.Simple.Configure import qualified Distribution.Simple.Utils as U (cabalVersion) import Distribution.Text -import Distribution.Utils.TempTestDir (removeDirectoryRecursiveHack) +import Test.Utils.TempTestDir (removeDirectoryRecursiveHack) import Distribution.Verbosity import Distribution.Version @@ -91,15 +94,20 @@ import System.Exit import System.FilePath import System.IO import System.IO.Error (isDoesNotExistError) -import System.IO.Temp (withSystemTempDirectory) +import Distribution.Simple.Utils hiding (info) import System.Process hiding (env) import Options.Applicative +import Test.Cabal.Run +import qualified Data.ByteString.Char8 as C +import Data.List +import GHC.Stack data CommonArgs = CommonArgs { argCabalInstallPath :: Maybe FilePath, argGhcPath :: Maybe FilePath, argHackageRepoToolPath :: Maybe FilePath, argHaddockPath :: Maybe FilePath, + argKeepTmpFiles :: Bool, argAccept :: Bool, argSkipSetupTests :: Bool } @@ -127,6 +135,10 @@ commonArgParser = CommonArgs <> long "with-haddock" <> metavar "PATH" )) + <*> switch + ( long "keep-tmp-files" + <> help "Keep temporary files" + ) <*> switch ( long "accept" <> help "Accept output" @@ -140,10 +152,12 @@ renderCommonArgs args = maybe [] (\x -> ["--with-haddock", x]) (argHaddockPath args) ++ maybe [] (\x -> ["--with-hackage-repo-tool", x]) (argHackageRepoToolPath args) ++ (if argAccept args then ["--accept"] else []) ++ + (if argKeepTmpFiles args then ["--keep-tmp-files"] else []) ++ (if argSkipSetupTests args then ["--skip-setup-tests"] else []) data TestArgs = TestArgs { testArgDistDir :: FilePath, + testArgPackageDb :: Maybe FilePath, testArgScriptPath :: FilePath, testCommonArgs :: CommonArgs } @@ -154,6 +168,10 @@ testArgParser = TestArgs ( help "Build directory of cabal-testsuite" <> long "builddir" <> metavar "DIR") + <*> optional (option str + ( help "Package DB which contains Cabal and Cabal-syntax" + <> long "extra-package-db" + <> metavar "DIR")) <*> argument str ( metavar "FILE") <*> commonArgParser @@ -178,6 +196,7 @@ unexpectedSuccess = liftIO $ do putStrLn "UNEXPECTED OK" E.throwIO TestCodeUnexpectedOk + trySkip :: IO a -> IO (Either String a) trySkip m = fmap Right m `E.catch` \e -> case e of TestCodeSkip msg -> return (Left msg) @@ -228,11 +247,19 @@ python3Program = simpleProgram "python3" -- | Run a test in the test monad according to program's arguments. runTestM :: String -> TestM a -> IO a -runTestM mode m = withSystemTempDirectory "cabal-testsuite" $ \tmp_dir -> do - args <- execParser (info testArgParser Data.Monoid.mempty) +runTestM mode m = + liftIO $ getTemporaryDirectory >>= \systemTmpDir -> + execParser (info testArgParser Data.Monoid.mempty) >>= \args -> + withTempDirectoryEx verbosity (defaultTempFileOptions { optKeepTempFiles = argKeepTmpFiles (testCommonArgs args) }) + systemTmpDir + "cabal-testsuite" $ \tmp_dir -> do let dist_dir = testArgDistDir args (script_dir0, script_filename) = splitFileName (testArgScriptPath args) - script_base = dropExtensions script_filename + + stripped = stripExtension ".test.hs" script_filename + <|> stripExtension ".multitest.hs" script_filename + script_base = fromMaybe (dropExtensions script_filename) stripped + -- Canonicalize this so that it is stable across working directory changes script_dir <- canonicalizePath script_dir0 senv <- mkScriptEnv verbosity @@ -285,24 +312,7 @@ runTestM mode m = withSystemTempDirectory "cabal-testsuite" $ \tmp_dir -> do -- them up we must configure them program_db <- configureAllKnownPrograms verbosity program_db3 - let ghcAndRunnedGhcAreTheSame :: Bool - ghcAndRunnedGhcAreTheSame = fromMaybe False $ do - ghc_program <- lookupProgram ghcProgram program_db - runner_ghc_program <- lookupProgram ghcProgram (runnerProgramDb senv) - return $ programPath ghc_program == programPath runner_ghc_program - - let db_stack = - case argGhcPath (testCommonArgs args) of - Nothing -> runnerPackageDbStack senv -- NB: canonicalized - -- Can't use the build package db stack since they - -- are all for the wrong versions! TODO: Make - -- this configurable - -- - -- Oleg: if runner ghc and provided ghc are the same, - -- use runnerPackageDbStack. See 'hasCabalForGhc' check. - Just _ - | ghcAndRunnedGhcAreTheSame -> runnerPackageDbStack senv - | otherwise -> [GlobalPackageDB] + let db_stack = [GlobalPackageDB] env = TestEnv { testSourceDir = script_dir, testTmpDir = tmp_dir, @@ -316,6 +326,7 @@ runTestM mode m = withSystemTempDirectory "cabal-testsuite" $ \tmp_dir -> do testMtimeChangeDelay = Nothing, testScriptEnv = senv, testSetupPath = dist_dir "build" "setup" "setup", + testPackageDbPath = testArgPackageDb args, testSkipSetupTests = argSkipSetupTests (testCommonArgs args), testHaveCabalShared = runnerWithSharedLib senv, testEnvironment = @@ -326,22 +337,20 @@ runTestM mode m = withSystemTempDirectory "cabal-testsuite" $ \tmp_dir -> do -- Set CABAL_DIR in addition to HOME, since HOME has no -- effect on Windows. , ("CABAL_DIR", Just (testCabalDir env)) - , ("CABAL_CONFIG", Just $ testCabalDir env "config") + , ("CABAL_CONFIG", Just (testUserCabalConfigFile env)) ], testShouldFail = False, testRelativeCurrentDir = ".", testHavePackageDb = False, testHaveRepo = False, - testHaveSourceCopy = False, testCabalInstallAsSetup = False, - testCabalProjectFile = "cabal.project", + testCabalProjectFile = Nothing, testPlan = Nothing, testRecordDefaultMode = DoNotRecord, - testRecordUserMode = Nothing, - testSourceCopyRelativeDir = "source" + testRecordUserMode = Nothing } let go = do cleanup - r <- m + r <- withSourceCopy m check_expect (argAccept (testCommonArgs args)) return r runReaderT go env @@ -386,6 +395,105 @@ readFileOrEmpty f = readFile f `E.catch` \e -> then return "" else E.throwIO e +-- | Run an IO action, and suppress a "does not exist" error. +onlyIfExists :: MonadIO m => IO () -> m () +onlyIfExists m = + liftIO $ E.catch m $ \(e :: IOError) -> + unless (isDoesNotExistError e) $ E.throwIO e + +-- | Make a hermetic copy of the test directory. +-- +-- This requires the test repository to be a Git checkout, because +-- we use the Git metadata to figure out what files to copy into the +-- hermetic copy. +withSourceCopy :: TestM a -> TestM a +withSourceCopy m = do + env <- getTestEnv + initWorkDir + let curdir = testSourceDir env + dest = testSourceCopyDir env + fs <- getSourceFiles + when (null fs) + (error (unlines [ "withSourceCopy: No files to copy from " ++ curdir + , "You need to \"git add\" any files before they are copied by the testsuite."])) + forM_ fs $ \f -> do + unless (isTestFile f) $ liftIO $ do + putStrLn ("Copying " ++ (curdir f) ++ " to " ++ (dest f)) + createDirectoryIfMissing True (takeDirectory (dest f)) + d <- liftIO $ doesDirectoryExist (curdir f) + if d + then + copyDirectoryRecursive normal (curdir f) (dest f) + else + copyFile (curdir f) (dest f) + m + + +-- NB: Keep this synchronized with partitionTests +isTestFile :: FilePath -> Bool +isTestFile f = + case takeExtensions f of + ".test.hs" -> True + ".multitest.hs" -> True + _ -> False + + +initWorkDir :: TestM () +initWorkDir = do + env <- getTestEnv + liftIO $ createDirectoryIfMissing True (testWorkDir env) + + + +getSourceFiles :: TestM [FilePath] +getSourceFiles = do + env <- getTestEnv + configured_prog <- requireProgramM gitProgram + r <- liftIO $ run (testVerbosity env) + (Just (testSourceDir env)) + (testEnvironment env) + (programPath configured_prog) + ["ls-files", "--cached", "--modified"] + Nothing + recordLog r + _ <- requireSuccess r + return (lines $ resultOutput r) + +recordLog :: Result -> TestM () +recordLog res = do + env <- getTestEnv + let mode = testRecordMode env + initWorkDir + liftIO $ C.appendFile (testWorkDir env "test.log") + (C.pack $ "+ " ++ resultCommand res ++ "\n" + ++ resultOutput res ++ "\n\n") + liftIO . C.appendFile (testActualFile env) . C.pack $ + case mode of + RecordAll -> unlines (lines (resultOutput res)) + RecordMarked -> getMarkedOutput (resultOutput res) + DoNotRecord -> "" + +------------------------------------------------------------------------ +-- * Subprocess run results + +requireSuccess :: Result -> TestM Result +requireSuccess r@Result { resultCommand = cmd + , resultExitCode = exitCode + , resultOutput = output } = withFrozenCallStack $ do + env <- getTestEnv + when (exitCode /= ExitSuccess && not (testShouldFail env)) $ + assertFailure $ "Command " ++ cmd ++ " failed.\n" ++ + "Output:\n" ++ output ++ "\n" + when (exitCode == ExitSuccess && testShouldFail env) $ + assertFailure $ "Command " ++ cmd ++ " succeeded.\n" ++ + "Output:\n" ++ output ++ "\n" + return r + +assertFailure :: String -> m () +assertFailure msg = withFrozenCallStack $ error msg + + + -- | Runs 'diff' with some arguments on two files, outputting the -- diff to stderr, and returning true if the two files differ diff :: [String] -> FilePath -> FilePath -> TestM Bool @@ -415,11 +523,15 @@ mkNormalizerEnv = do ["list", "--global", "--simple-output"] "" tmpDir <- liftIO $ getTemporaryDirectory + canonicalizedTestTmpDir <- liftIO $ canonicalizePath (testTmpDir env) + return NormalizerEnv { normalizerRoot = addTrailingPathSeparator (testSourceDir env), normalizerTmpDir = addTrailingPathSeparator (testTmpDir env), + normalizerCanonicalTmpDir + = addTrailingPathSeparator canonicalizedTestTmpDir, normalizerGblTmpDir = addTrailingPathSeparator tmpDir, normalizerGhcVersion @@ -458,11 +570,21 @@ isAvailableProgram program = do Just _ -> return True Nothing -> return False --- | Run an IO action, and suppress a "does not exist" error. -onlyIfExists :: MonadIO m => IO () -> m () -onlyIfExists m = - liftIO $ E.catch m $ \(e :: IOError) -> - unless (isDoesNotExistError e) $ E.throwIO e + +getMarkedOutput :: String -> String -- trailing newline +getMarkedOutput out = unlines (go (lines out) False) + where + go [] _ = [] + go (x:xs) True + | "-----END CABAL OUTPUT-----" `isPrefixOf` x + = go xs False + | otherwise = x : go xs True + go (x:xs) False + -- NB: Windows has extra goo at the end + | "-----BEGIN CABAL OUTPUT-----" `isPrefixOf` x + = go xs True + | otherwise = go xs False + data TestEnv = TestEnv -- UNCHANGING: @@ -497,6 +619,9 @@ data TestEnv = TestEnv , testScriptEnv :: ScriptEnv -- | Setup script path , testSetupPath :: FilePath + -- | Setup package-db path which contains Cabal and Cabal-syntax for cabal-install to + -- use when compiling custom setups. + , testPackageDbPath :: Maybe FilePath -- | Skip Setup tests? , testSkipSetupTests :: Bool -- | Do we have shared libraries for the Cabal-under-tests? @@ -516,12 +641,10 @@ data TestEnv = TestEnv , testHavePackageDb :: Bool -- | Says if we've setup a repository , testHaveRepo :: Bool - -- | Says if we've copied the source to a hermetic directory - , testHaveSourceCopy :: Bool -- | Says if we're testing cabal-install as setup , testCabalInstallAsSetup :: Bool -- | Says what cabal.project file to use (probed) - , testCabalProjectFile :: FilePath + , testCabalProjectFile :: Maybe FilePath -- | Cached record of the plan metadata from a new-build -- invocation; controlled by 'withPlan'. , testPlan :: Maybe Plan @@ -529,9 +652,6 @@ data TestEnv = TestEnv , testRecordDefaultMode :: RecordMode -- | User explicitly set record mode. Not implemented ATM. , testRecordUserMode :: Maybe RecordMode - -- | Name of the subdirectory we copied the test's sources to, - -- relative to 'testSourceDir' - , testSourceCopyRelativeDir :: FilePath } deriving Show @@ -551,10 +671,7 @@ getTestEnv = ask -- where the Cabal file lives. This is what you want the CWD of cabal -- calls to be. testCurrentDir :: TestEnv -> FilePath -testCurrentDir env = - (if testHaveSourceCopy env - then testSourceCopyDir env - else testSourceDir env) testRelativeCurrentDir env +testCurrentDir env = testSourceCopyDir env testRelativeCurrentDir env testName :: TestEnv -> String testName env = testSubName env <.> testMode env @@ -563,8 +680,7 @@ testName env = testSubName env <.> testMode env -- files for ALL tests associated with a test (respecting -- subtests.) To clean, you ONLY need to delete this directory. testWorkDir :: TestEnv -> FilePath -testWorkDir env = - testSourceDir env (testName env <.> "dist") +testWorkDir env = testTmpDir env (testName env <.> "dist") -- | The absolute prefix where installs go. testPrefixDir :: TestEnv -> FilePath @@ -578,7 +694,7 @@ testLibInstallDir env = libDir compilerDir libDir = case os of Windows -> testPrefixDir env _ -> testPrefixDir env "lib" - compilerDir = prettyShow platform ++ "-" ++ showCompilerId (testCompiler env) + compilerDir = prettyShow platform ++ "-" ++ showCompilerIdWithAbi (testCompiler env) -- | The absolute path to the build directory that should be used -- for the current package in a test. @@ -605,7 +721,7 @@ testKeysDir env = testWorkDir env "keys" -- | If 'withSourceCopy' is used, where the source files go. testSourceCopyDir :: TestEnv -> FilePath -testSourceCopyDir env = testWorkDir env testSourceCopyRelativeDir env +testSourceCopyDir env = testTmpDir env -- | The user cabal directory testCabalDir :: TestEnv -> FilePath diff --git a/cabal-testsuite/src/Test/Cabal/OutputNormalizer.hs b/cabal-testsuite/src/Test/Cabal/OutputNormalizer.hs index a977dc7e305..a0b7d3ac669 100644 --- a/cabal-testsuite/src/Test/Cabal/OutputNormalizer.hs +++ b/cabal-testsuite/src/Test/Cabal/OutputNormalizer.hs @@ -36,8 +36,8 @@ normalizeOutput nenv = -- string search-replace. Make sure we do this before backslash -- normalization! . resub (posixRegexEscape (normalizerGblTmpDir nenv) ++ "[a-z0-9\\.-]+") "" -- note, after TMPDIR - . resub (posixRegexEscape (normalizerRoot nenv)) "/" - . resub (posixRegexEscape (normalizerTmpDir nenv)) "/" + . resub (posixRegexEscape (normalizerTmpDir nenv)) "/" + . resub (posixRegexEscape (normalizerCanonicalTmpDir nenv)) "/" -- before normalizerTmpDir . appEndo (F.fold (map (Endo . packageIdRegex) (normalizerKnownPackages nenv))) -- Look for 0.1/installed-0d6uzW7Ubh1Fb4TB5oeQ3G -- These installed packages will vary depending on GHC version @@ -58,7 +58,9 @@ normalizeOutput nenv = . (if normalizerGhcVersion nenv /= nullVersion then resub (posixRegexEscape (display (normalizerGhcVersion nenv)) -- Also glob the date, for nightly GHC builds - ++ "(\\.[0-9]+)?") + ++ "(\\.[0-9]+)?" + -- Also glob the ABI hash, for GHCs which support it + ++ "(-[a-z0-9]+)?") "" else id) -- hackage-security locks occur non-deterministically @@ -97,6 +99,9 @@ normalizeOutput nenv = data NormalizerEnv = NormalizerEnv { normalizerRoot :: FilePath , normalizerTmpDir :: FilePath + , normalizerCanonicalTmpDir :: FilePath + -- ^ May differ from 'normalizerTmpDir', especially e.g. on macos, where + -- `/var` is a symlink for `/private/var`. , normalizerGblTmpDir :: FilePath , normalizerGhcVersion :: Version , normalizerKnownPackages :: [PackageId] diff --git a/cabal-testsuite/src/Test/Cabal/Prelude.hs b/cabal-testsuite/src/Test/Cabal/Prelude.hs index e0e63ac18f6..4923b3e4884 100644 --- a/cabal-testsuite/src/Test/Cabal/Prelude.hs +++ b/cabal-testsuite/src/Test/Cabal/Prelude.hs @@ -29,17 +29,17 @@ import Distribution.Simple.Program.Types import Distribution.Simple.Program.Db import Distribution.Simple.Program import Distribution.System (OS(Windows,Linux,OSX), Arch(JavaScript), buildOS, buildArch) -import Distribution.Simple.Utils - ( withFileContents, tryFindPackageDesc ) import Distribution.Simple.Configure ( getPersistBuildConfig ) +import Distribution.Simple.Utils + ( withFileContents, tryFindPackageDesc ) import Distribution.Version import Distribution.Package -import Distribution.Parsec (eitherParsec) +import Distribution.Parsec (eitherParsec, simpleParsec) import Distribution.Types.UnqualComponentName import Distribution.Types.LocalBuildInfo import Distribution.PackageDescription -import Distribution.Utils.TempTestDir (withTestDir) +import Test.Utils.TempTestDir (withTestDir) import Distribution.Verbosity (normal) import Distribution.Compat.Stack @@ -53,23 +53,23 @@ import Control.Monad (unless, when, void, forM_, liftM2, liftM4) import Control.Monad.Trans.Reader (withReaderT, runReaderT) import Control.Monad.IO.Class (MonadIO (..)) import qualified Crypto.Hash.SHA256 as SHA256 -import qualified Data.ByteString.Base64 as Base64 +import qualified Data.ByteString.Base16 as Base16 import qualified Data.ByteString.Char8 as C import Data.List (isInfixOf, stripPrefix, isPrefixOf, intercalate) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE import Data.Maybe (mapMaybe, fromMaybe) import System.Exit (ExitCode (..)) -import System.FilePath ((), takeExtensions, takeDrive, takeDirectory, normalise, splitPath, joinPath, splitFileName, (<.>), dropTrailingPathSeparator) +import System.FilePath import Control.Concurrent (threadDelay) import qualified Data.Char as Char -import System.Directory (canonicalizePath, copyFile, copyFile, doesDirectoryExist, doesFileExist, createDirectoryIfMissing, getDirectoryContents, listDirectory) +import System.Directory import Control.Retry (exponentialBackoff, limitRetriesByCumulativeDelay) import Network.Wait (waitTcpVerbose) +import System.Environment #ifndef mingw32_HOST_OS import Control.Monad.Catch ( bracket_ ) -import System.Directory ( removeFile ) import System.Posix.Files ( createSymbolicLink ) import System.Posix.Resource #endif @@ -113,6 +113,16 @@ withDirectory f = withReaderT withEnv :: [(String, Maybe String)] -> TestM a -> TestM a withEnv e = withReaderT (\env -> env { testEnvironment = testEnvironment env ++ e }) +-- | Prepend a directory to the PATH +addToPath :: FilePath -> TestM a -> TestM a +addToPath exe_dir action = do + env <- getTestEnv + path <- liftIO $ getEnv "PATH" + let newpath = exe_dir ++ [searchPathSeparator] ++ path + let new_env = (("PATH", Just newpath) : (testEnvironment env)) + withEnv new_env action + + -- HACK please don't use me withEnvFilter :: (String -> Bool) -> TestM a -> TestM a withEnvFilter p = withReaderT (\env -> env { testEnvironment = filter (p . fst) (testEnvironment env) }) @@ -279,9 +289,6 @@ cabalG' global_args cmd args = cabalGArgs global_args cmd args Nothing cabalGArgs :: [String] -> String -> [String] -> Maybe String -> TestM Result cabalGArgs global_args cmd args input = do env <- getTestEnv - -- Freeze writes out cabal.config to source directory, this is not - -- overwritable - when (cmd == "v1-freeze") requireHasSourceCopy let extra_args | cmd `elem` [ "v1-update" @@ -295,21 +302,23 @@ cabalGArgs global_args cmd args input = do , "info" , "init" , "haddock-project" + , "path" ] = [ ] -- new-build commands are affected by testCabalProjectFile | cmd == "v2-sdist" - = [ "--project-file", testCabalProjectFile env ] + = [ "--project-file=" ++ fp | Just fp <- [testCabalProjectFile env] ] | cmd == "v2-clean" - = [ "--builddir", testDistDir env - , "--project-file", testCabalProjectFile env ] + = [ "--builddir", testDistDir env ] + ++ [ "--project-file=" ++ fp | Just fp <- [testCabalProjectFile env] ] | "v2-" `isPrefixOf` cmd = [ "--builddir", testDistDir env - , "--project-file", testCabalProjectFile env , "-j1" ] + ++ [ "--project-file=" ++ fp | Just fp <- [testCabalProjectFile env] ] + ++ ["--package-db=" ++ db | Just db <- [testPackageDbPath env]] | otherwise = [ "--builddir", testDistDir env ] ++ @@ -332,7 +341,7 @@ cabal_raw' cabal_args input = runProgramM cabalProgram cabal_args input withProjectFile :: FilePath -> TestM a -> TestM a withProjectFile fp m = - withReaderT (\env -> env { testCabalProjectFile = fp }) m + withReaderT (\env -> env { testCabalProjectFile = Just fp }) m -- | Assuming we've successfully configured a new-build project, -- read out the plan metadata so that we can use it to do other @@ -357,15 +366,21 @@ runPlanExe pkg_name cname args = void $ runPlanExe' pkg_name cname args runPlanExe' :: String {- package name -} -> String {- component name -} -> [String] -> TestM Result runPlanExe' pkg_name cname args = do + exePath <- planExePath pkg_name cname + defaultRecordMode RecordAll $ do + recordHeader [pkg_name, cname] + runM exePath args Nothing + +planExePath :: String {- package name -} -> String {- component name -} + -> TestM FilePath +planExePath pkg_name cname = do Just plan <- testPlan `fmap` getTestEnv let distDirOrBinFile = planDistDir plan (mkPackageName pkg_name) (CExeName (mkUnqualComponentName cname)) exePath = case distDirOrBinFile of DistDir dist_dir -> dist_dir "build" cname cname BinFile bin_file -> bin_file - defaultRecordMode RecordAll $ do - recordHeader [pkg_name, cname] - runM exePath args Nothing + return exePath ------------------------------------------------------------------------ -- * Running ghc-pkg @@ -385,6 +400,12 @@ withPackageDb m = do $ do ghcPkg "init" [db_path] m +-- | Don't pass `--package-db` to cabal-install, so it won't find the specific version of +-- `Cabal` which you have configured the testsuite to run with. You probably don't want to use +-- this unless you are testing the `--package-db` flag itself. +noCabalPackageDb :: TestM a -> TestM a +noCabalPackageDb m = withReaderT (\nenv -> nenv { testPackageDbPath = Nothing }) m + ghcPkg :: String -> [String] -> TestM () ghcPkg cmd args = void (ghcPkg' cmd args) @@ -650,26 +671,6 @@ withRemoteRepo repoDir m = do runReaderT m (env { testHaveRepo = True })) ------------------------------------------------------------------------- --- * Subprocess run results - -requireSuccess :: Result -> TestM Result -requireSuccess r@Result { resultCommand = cmd - , resultExitCode = exitCode - , resultOutput = output } = withFrozenCallStack $ do - env <- getTestEnv - when (exitCode /= ExitSuccess && not (testShouldFail env)) $ - assertFailure $ "Command " ++ cmd ++ " failed.\n" ++ - "Output:\n" ++ output ++ "\n" - when (exitCode == ExitSuccess && testShouldFail env) $ - assertFailure $ "Command " ++ cmd ++ " succeeded.\n" ++ - "Output:\n" ++ output ++ "\n" - return r - -initWorkDir :: TestM () -initWorkDir = do - env <- getTestEnv - liftIO $ createDirectoryIfMissing True (testWorkDir env) -- | Record a header to help identify the output to the expect -- log. Unlike the 'recordLog', we don't record all arguments; @@ -681,46 +682,21 @@ recordHeader args = do env <- getTestEnv let mode = testRecordMode env str_header = "# " ++ intercalate " " args ++ "\n" - header = C.pack str_header + rec_header = C.pack str_header case mode of DoNotRecord -> return () _ -> do initWorkDir liftIO $ putStr str_header - liftIO $ C.appendFile (testWorkDir env "test.log") header - liftIO $ C.appendFile (testActualFile env) header + liftIO $ C.appendFile (testWorkDir env "test.log") rec_header + liftIO $ C.appendFile (testActualFile env) rec_header -recordLog :: Result -> TestM () -recordLog res = do - env <- getTestEnv - let mode = testRecordMode env - initWorkDir - liftIO $ C.appendFile (testWorkDir env "test.log") - (C.pack $ "+ " ++ resultCommand res ++ "\n" - ++ resultOutput res ++ "\n\n") - liftIO . C.appendFile (testActualFile env) . C.pack $ - case mode of - RecordAll -> unlines (lines (resultOutput res)) - RecordMarked -> getMarkedOutput (resultOutput res) - DoNotRecord -> "" - -getMarkedOutput :: String -> String -- trailing newline -getMarkedOutput out = unlines (go (lines out) False) - where - go [] _ = [] - go (x:xs) True - | "-----END CABAL OUTPUT-----" `isPrefixOf` x - = go xs False - | otherwise = x : go xs True - go (x:xs) False - -- NB: Windows has extra goo at the end - | "-----BEGIN CABAL OUTPUT-----" `isPrefixOf` x - = go xs True - | otherwise = go xs False ------------------------------------------------------------------------ -- * Test helpers +------------------------------------------------------------------------ +-- * Subprocess run results assertFailure :: WithCallStack (String -> m ()) assertFailure msg = withFrozenCallStack $ error msg @@ -839,8 +815,7 @@ getScriptCacheDirectory :: FilePath -> TestM FilePath getScriptCacheDirectory script = do cabalDir <- testCabalDir `fmap` getTestEnv hashinput <- liftIO $ canonicalizePath script - let hash = map (\c -> if c == '/' then '%' else c) . take 26 - . C.unpack . Base64.encode . SHA256.hash . C.pack $ hashinput + let hash = C.unpack . Base16.encode . C.take 26 . SHA256.hash . C.pack $ hashinput return $ cabalDir "script-builds" hash ------------------------------------------------------------------------ @@ -872,6 +847,44 @@ hasCabalShared = do env <- getTestEnv return (testHaveCabalShared env) + +anyCabalVersion :: WithCallStack ( String -> TestM Bool ) +anyCabalVersion = isCabalVersion any + +allCabalVersion :: WithCallStack ( String -> TestM Bool ) +allCabalVersion = isCabalVersion all + +-- Used by cabal-install tests to determine which Cabal library versions are +-- available. Given a version range, and a predicate on version ranges, +-- are there any installed packages Cabal library +-- versions which satisfy these. +isCabalVersion :: WithCallStack (((Version -> Bool) -> [Version] -> Bool) -> String -> TestM Bool) +isCabalVersion decide range = do + env <- getTestEnv + cabal_pkgs <- ghcPkg_raw' $ ["--global", "list", "Cabal", "--simple"] ++ ["--package-db=" ++ db | Just db <- [testPackageDbPath env]] + let pkg_versions :: [PackageIdentifier] = mapMaybe simpleParsec (words (resultOutput cabal_pkgs)) + vr <- case eitherParsec range of + Left err -> fail err + Right vr -> return vr + return $ decide (`withinRange` vr) (map pkgVersion pkg_versions) + +-- | Skip a test unless any available Cabal library version matches the predicate. +skipUnlessAnyCabalVersion :: String -> TestM () +skipUnlessAnyCabalVersion range = skipUnless ("needs any Cabal " ++ range) =<< anyCabalVersion range + + +-- | Skip a test if any available Cabal library version matches the predicate. +skipIfAnyCabalVersion :: String -> TestM () +skipIfAnyCabalVersion range = skipIf ("incompatible with Cabal " ++ range) =<< anyCabalVersion range + +-- | Skip a test unless all Cabal library versions match the predicate. +skipUnlessAllCabalVersion :: String -> TestM () +skipUnlessAllCabalVersion range = skipUnless ("needs all Cabal " ++ range) =<< allCabalVersion range + +-- | Skip a test if all the Cabal library version matches a predicate. +skipIfAllCabalVersion :: String -> TestM () +skipIfAllCabalVersion range = skipIf ("incompatible with Cabal " ++ range) =<< allCabalVersion range + isGhcVersion :: WithCallStack (String -> TestM Bool) isGhcVersion range = do ghc_program <- requireProgramM ghcProgram @@ -926,24 +939,6 @@ getOpenFilesLimit = liftIO $ do _ -> return Nothing #endif -hasCabalForGhc :: TestM Bool -hasCabalForGhc = do - env <- getTestEnv - ghc_program <- requireProgramM ghcProgram - (runner_ghc_program, _) <- liftIO $ requireProgram - (testVerbosity env) - ghcProgram - (runnerProgramDb (testScriptEnv env)) - - -- TODO: I guess, to be more robust what we should check for - -- specifically is that the Cabal library we want to use - -- will be picked up by the package db stack of ghc-program - - -- liftIO $ putStrLn $ "ghc_program: " ++ show ghc_program - -- liftIO $ putStrLn $ "runner_ghc_program: " ++ show runner_ghc_program - - return (programPath ghc_program == programPath runner_ghc_program) - -- | If you want to use a Custom setup with new-build, it needs to -- be 1.20 or later. Ordinarily, Cabal can go off and build a -- sufficiently recent Cabal if necessary, but in our test suite, @@ -978,8 +973,7 @@ expectBrokenIf True ticket m = expectBroken ticket m expectBrokenUnless :: Bool -> Int -> TestM a -> TestM () expectBrokenUnless b = expectBrokenIf (not b) ------------------------------------------------------------------------- --- * Miscellaneous +-- * Programs git :: String -> [String] -> TestM () git cmd args = void $ git' cmd args @@ -1005,6 +999,12 @@ ghc' args = do recordHeader ["ghc"] runProgramM ghcProgram args Nothing +ghcPkg_raw' :: [String] -> TestM Result +ghcPkg_raw' args = do + recordHeader ["ghc-pkg"] + runProgramM ghcPkgProgram args Nothing + + python3 :: [String] -> TestM () python3 args = void $ python3' args @@ -1013,41 +1013,6 @@ python3' args = do recordHeader ["python3"] runProgramM python3Program args Nothing --- | If a test needs to modify or write out source files, it's --- necessary to make a hermetic copy of the source files to operate --- on. This function arranges for this to be done. --- --- This requires the test repository to be a Git checkout, because --- we use the Git metadata to figure out what files to copy into the --- hermetic copy. --- --- Also see 'withSourceCopyDir'. -withSourceCopy :: TestM a -> TestM a -withSourceCopy m = do - env <- getTestEnv - let cwd = testCurrentDir env - dest = testSourceCopyDir env - r <- git' "ls-files" ["--cached", "--modified"] - forM_ (lines (resultOutput r)) $ \f -> do - unless (isTestFile f) $ do - liftIO $ createDirectoryIfMissing True (takeDirectory (dest f)) - liftIO $ copyFile (cwd f) (dest f) - withReaderT (\nenv -> nenv { testHaveSourceCopy = True }) m - --- | If a test needs to modify or write out source files, it's --- necessary to make a hermetic copy of the source files to operate --- on. This function arranges for this to be done in a subdirectory --- with a given name, so that tests that are sensitive to the path --- that they're running in (e.g., autoconf tests) can run. --- --- This requires the test repository to be a Git checkout, because --- we use the Git metadata to figure out what files to copy into the --- hermetic copy. --- --- Also see 'withSourceCopy'. -withSourceCopyDir :: FilePath -> TestM a -> TestM a -withSourceCopyDir dir = - withReaderT (\nenv -> nenv { testSourceCopyRelativeDir = dir }) . withSourceCopy -- | Look up the 'InstalledPackageId' of a package name. getIPID :: String -> TestM String @@ -1109,30 +1074,14 @@ withSymlink oldpath newpath0 act = do writeSourceFile :: FilePath -> String -> TestM () writeSourceFile fp s = do - requireHasSourceCopy cwd <- fmap testCurrentDir getTestEnv liftIO $ writeFile (cwd fp) s copySourceFileTo :: FilePath -> FilePath -> TestM () copySourceFileTo src dest = do - requireHasSourceCopy cwd <- fmap testCurrentDir getTestEnv liftIO $ copyFile (cwd src) (cwd dest) -requireHasSourceCopy :: TestM () -requireHasSourceCopy = do - env <- getTestEnv - unless (testHaveSourceCopy env) $ do - error "This operation requires a source copy; use withSourceCopy and 'git add' all test files" - --- NB: Keep this synchronized with partitionTests -isTestFile :: FilePath -> Bool -isTestFile f = - case takeExtensions f of - ".test.hs" -> True - ".multitest.hs" -> True - _ -> False - -- | Work around issue #4515 (store paths exceeding the Windows path length -- limit) by creating a temporary directory for the new-build store. This -- function creates a directory immediately under the current drive on Windows. @@ -1147,7 +1096,7 @@ findDependencyInStore :: FilePath -- ^store dir -> String -- ^package name prefix -> IO FilePath -- ^package dir findDependencyInStore storeDir pkgName = do - storeDirForGhcVersion <- head <$> listDirectory storeDir + (storeDirForGhcVersion : _) <- listDirectory storeDir packageDirs <- listDirectory (storeDir storeDirForGhcVersion) -- Ideally, we should call 'hashedInstalledPackageId' from 'Distribution.Client.PackageHash'. -- But 'PackageHashInputs', especially 'PackageHashConfigInputs', is too hard to construct. @@ -1156,5 +1105,7 @@ findDependencyInStore storeDir pkgName = do then filter (not . flip elem "aeiou") pkgName -- simulates the way 'hashedInstalledPackageId' uses to compress package name else pkgName - let libDir = head $ filter (pkgName' `isPrefixOf`) packageDirs + let libDir = case filter (pkgName' `isPrefixOf`) packageDirs of + [] -> error $ "Could not find " <> pkgName' <> " when searching for " <> pkgName' <> " in\n" <> show packageDirs + (dir:_) -> dir pure (storeDir storeDirForGhcVersion libDir) diff --git a/cabal-testsuite/src/Test/Cabal/Script.hs b/cabal-testsuite/src/Test/Cabal/Script.hs index a7ce082a97b..308c390140b 100644 --- a/cabal-testsuite/src/Test/Cabal/Script.hs +++ b/cabal-testsuite/src/Test/Cabal/Script.hs @@ -77,22 +77,32 @@ runghc senv mb_cwd env_overrides script_path args = do -- script with 'runghc'. runnerCommand :: ScriptEnv -> Maybe FilePath -> [(String, Maybe String)] -> FilePath -> [String] -> IO (FilePath, [String]) -runnerCommand senv _mb_cwd _env_overrides script_path args = do +runnerCommand senv mb_cwd _env_overrides script_path args = do (prog, _) <- requireProgram verbosity runghcProgram (runnerProgramDb senv) return (programPath prog, runghc_args ++ ["--"] ++ map ("--ghc-arg="++) ghc_args ++ [script_path] ++ args) where verbosity = runnerVerbosity senv runghc_args = [] - ghc_args = runnerGhcArgs senv + ghc_args = runnerGhcArgs senv mb_cwd -- | Compute the GHC flags to invoke 'runghc' with under a 'ScriptEnv'. -runnerGhcArgs :: ScriptEnv -> [String] -runnerGhcArgs senv = +runnerGhcArgs :: ScriptEnv -> Maybe FilePath -> [String] +runnerGhcArgs senv mb_cwd = renderGhcOptions (runnerCompiler senv) (runnerPlatform senv) ghc_options where ghc_options = M.mempty { ghcOptPackageDBs = runnerPackageDbStack senv , ghcOptPackages = toNubListR (runnerPackages senv) + , ghcOptHideAllPackages = Flag True -- Avoid picking stray module files that look - -- like our imports - , ghcOptSourcePathClear = Flag True } + -- like our imports... + , ghcOptSourcePathClear = Flag True + -- ... yet retain the current directory as an included + -- directory, e.g. so that we can compile a Setup.hs + -- script which imports a locally defined module. + -- See the PackageTests/SetupDep test. + , ghcOptSourcePath = toNubListR $ + case mb_cwd of + Nothing -> [] + Just wd -> [wd] + } diff --git a/cabal-testsuite/src/Test/Cabal/Server.hs b/cabal-testsuite/src/Test/Cabal/Server.hs index 450c6f660c7..9d302237a22 100644 --- a/cabal-testsuite/src/Test/Cabal/Server.hs +++ b/cabal-testsuite/src/Test/Cabal/Server.hs @@ -215,7 +215,7 @@ runMain ref m = do startServer :: Chan ServerLogMsg -> ScriptEnv -> IO Server startServer chan senv = do (prog, _) <- requireProgram verbosity ghcProgram (runnerProgramDb senv) - let ghc_args = runnerGhcArgs senv ++ ["--interactive", "-v0", "-ignore-dot-ghci"] + let ghc_args = runnerGhcArgs senv Nothing ++ ["--interactive", "-v0", "-ignore-dot-ghci"] proc_spec = (proc (programPath prog) ghc_args) { create_group = True, -- Closing fds is VERY important to avoid diff --git a/cabal-testsuite/static/Main.hs b/cabal-testsuite/static/Main.hs new file mode 100644 index 00000000000..d82a4bd93b7 --- /dev/null +++ b/cabal-testsuite/static/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = return () diff --git a/cabal.project b/cabal.project index f98fec9889b..e368c280c99 100644 --- a/cabal.project +++ b/cabal.project @@ -1,31 +1,6 @@ -packages: Cabal/ -packages: cabal-testsuite/ -packages: Cabal-syntax/ -packages: cabal-install/ -packages: cabal-install-solver/ -packages: solver-benchmarks/ +import: project-cabal/ghc-options.config +import: project-cabal/ghc-latest.config +import: project-cabal/pkgs.config +import: project-cabal/constraints.config tests: True - -packages: Cabal-QuickCheck/ -packages: Cabal-tree-diff/ -packages: Cabal-described -packages: Cabal-tests/ -packages: cabal-benchmarks/ - -optional-packages: ./vendored/*/*.cabal - -allow-newer: - hackage-security:Cabal - --- avoiding extra dependencies -constraints: rere -rere-cfg -constraints: these -assoc - --- Andreas, 2022-08-19, https://github.com/haskell/cabal/issues/8377 --- Force latest dependencies in the development version: -constraints: text >= 2.0 -constraints: time >= 1.12 - -program-options - ghc-options: -fno-ignore-asserts diff --git a/cabal.project.buildinfo b/cabal.project.buildinfo deleted file mode 100644 index 941381117b6..00000000000 --- a/cabal.project.buildinfo +++ /dev/null @@ -1,11 +0,0 @@ -packages: Cabal-syntax/ -packages: Cabal/ -packages: Cabal-described -packages: buildinfo-reference-generator/ -tests: False -optimization: False -with-compiler: ghc-8.8.3 - --- avoiding extra dependencies -constraints: rere -rere-cfg -constraints: these -assoc diff --git a/cabal.project.coverage b/cabal.project.coverage deleted file mode 100644 index 2afe3d10df7..00000000000 --- a/cabal.project.coverage +++ /dev/null @@ -1,74 +0,0 @@ -packages: Cabal-syntax/ Cabal/ cabal-testsuite/ -packages: cabal-install/ -packages: cabal-install-solver/ -packages: solver-benchmarks/ - -tests: True - -packages: Cabal-QuickCheck/ -packages: Cabal-tree-diff/ -packages: Cabal-described -packages: Cabal-tests/ -packages: cabal-benchmarks/ - --- Uncomment to allow picking up extra local unpacked deps: ---optional-packages: */ - --- Remove after hackage-repo-tool release -allow-newer: - hackage-repo-tool:optparse-applicative - -allow-newer: - hackage-security:Cabal - --- https://github.com/haskell-hvr/windns/pull/2 -allow-newer: windns-0.1.0.1:base - --- avoiding extra dependencies -constraints: rere -rere-cfg -constraints: these - -program-options - ghc-options: -fno-ignore-asserts - --- NOTE: for library coverage in multi-project builds, --- see: --- --- * https://github.com/haskell/cabal/issues/6440 --- * https://github.com/haskell/cabal/issues/5213#issuecomment-586517129 --- --- We must mask coverage for dependencies of `cabal-install` in --- multiproject settings in order to generate coverage for --- the `cabal-install` library --- -package Cabal-syntax - coverage: False - library-coverage: False - -package Cabal - coverage: False - library-coverage: False - -package cabal-testsuite - coverage: False - library-coverage: False - -package Cabal-QuickCheck - coverage: False - library-coverage: False - -package Cabal-tree-diff - coverage: False - library-coverage: False - -package Cabal-described - coverage: False - library-coverage: False - -package cabal-install-solver - coverage: False - library-coverage: False - -package cabal-install - coverage: True - library-coverage: True diff --git a/cabal.project.doctest b/cabal.project.doctest deleted file mode 100644 index dac9b0d88a9..00000000000 --- a/cabal.project.doctest +++ /dev/null @@ -1,24 +0,0 @@ -packages: Cabal-syntax/ -packages: Cabal/ -packages: cabal-testsuite/ -packages: cabal-install/ -packages: solver-benchmarks/ - -packages: cabal-install-solver/ -packages: Cabal-QuickCheck/ -packages: Cabal-tree-diff -packages: Cabal-described -packages: Cabal-tests -packages: cabal-benchmarks - -tests: True - --- avoiding extra dependencies -constraints: rere -rere-cfg -constraints: these -assoc - -write-ghc-environment-files: never - -program-options - ghc-options: -fno-ignore-asserts - diff --git a/cabal.project.libonly b/cabal.project.libonly deleted file mode 100644 index 59873fd4ad1..00000000000 --- a/cabal.project.libonly +++ /dev/null @@ -1,14 +0,0 @@ -packages: Cabal-syntax/ Cabal/ cabal-testsuite/ - -packages: Cabal-QuickCheck/ -packages: Cabal-tree-diff -packages: Cabal-described -packages: Cabal-tests - -tests: True - --- Uncomment to allow picking up extra local unpacked deps: ---optional-packages: */ - -program-options - ghc-options: -fno-ignore-asserts diff --git a/cabal.project.meta b/cabal.project.meta index 304b2a50e58..99eaaa54359 100644 --- a/cabal.project.meta +++ b/cabal.project.meta @@ -1,2 +1 @@ packages: cabal-dev-scripts -optional-packages: diff --git a/cabal.project.release b/cabal.project.release index 8d171824287..fd4b5c333e0 100644 --- a/cabal.project.release +++ b/cabal.project.release @@ -1,8 +1,5 @@ -packages: Cabal-syntax/ -packages: Cabal/ -packages: cabal-install-solver/ -packages: cabal-install/ -tests: False -benchmarks: False -optimization: True -index-state: hackage.haskell.org 2023-10-13T10:16:13Z +import: project-cabal/pkgs/cabal.config +import: project-cabal/pkgs/install.config +import: project-cabal/pkgs/tests.config + +index-state: hackage.haskell.org 2024-02-13T10:16:13Z diff --git a/cabal.project.validate b/cabal.project.validate index 66e823f62b1..aae9375fb34 100644 --- a/cabal.project.validate +++ b/cabal.project.validate @@ -1,32 +1,7 @@ -packages: Cabal-syntax/ -packages: Cabal/ -packages: cabal-testsuite/ -packages: cabal-install/ -packages: solver-benchmarks/ - -packages: cabal-install-solver/ -packages: Cabal-QuickCheck/ -packages: Cabal-tree-diff -packages: Cabal-described -packages: Cabal-tests -packages: cabal-benchmarks +import: project-cabal/ghc-options.config +import: project-cabal/ghc-latest.config +import: project-cabal/pkgs.config +import: project-cabal/constraints.config tests: True - --- avoiding extra dependencies -constraints: rere -rere-cfg -constraints: these -assoc - write-ghc-environment-files: never - -program-options - ghc-options: -fno-ignore-asserts - -package Cabal-syntax - ghc-options: -Werror -package Cabal - ghc-options: -Werror -package cabal-testsuite - ghc-options: -Werror -package cabal-install - ghc-options: -Werror diff --git a/cabal.project.validate.libonly b/cabal.project.validate.libonly index 3baafa1661a..7c5bd38ab6b 100644 --- a/cabal.project.validate.libonly +++ b/cabal.project.validate.libonly @@ -1,28 +1,8 @@ -packages: Cabal-syntax/ -packages: Cabal/ -packages: cabal-testsuite/ -packages: Cabal-QuickCheck/ -packages: Cabal-tree-diff -packages: Cabal-described -packages: Cabal-tests +import: project-cabal/ghc-options.config +import: project-cabal/pkgs/cabal.config +import: project-cabal/pkgs/tests.config +import: project-cabal/pkgs/integration-tests.config +import: project-cabal/constraints.config tests: True - write-ghc-environment-files: never - --- avoiding extra dependencies -constraints: rere -rere-cfg -constraints: these -assoc - -program-options - ghc-options: -fno-ignore-asserts - -package Cabal-syntax - ghc-options: -Werror -package Cabal - ghc-options: -Werror -package cabal-testsuite - ghc-options: -Werror - --- https://github.com/haskell-hvr/cryptohash-sha256/issues/12 -allow-newer: cryptohash-sha256:base diff --git a/cabal.project.weeder b/cabal.project.weeder deleted file mode 100644 index 5fa8357bd6a..00000000000 --- a/cabal.project.weeder +++ /dev/null @@ -1,15 +0,0 @@ --- project file for weeder. Only Cabal and cabal install --- install weeder with --- --- cabal install -w ghc-8.8.3 weeder --- - -packages: Cabal-syntax/ -packages: Cabal/ -packages: cabal-install/ -tests: False - -with-compiler: ghc-8.8.3 - -package * - ghc-options: -fwrite-ide-info diff --git a/changelog.d/base16-script-cache b/changelog.d/base16-script-cache new file mode 100644 index 00000000000..a2473271635 --- /dev/null +++ b/changelog.d/base16-script-cache @@ -0,0 +1,9 @@ +synopsis: Script cache dir is the base16 hash of the canonical path of the script. +prs: #9459 +packages: cabal-install + +description: { + +Script cache dir is the base16 hash of the canonical path of the script. + +} diff --git a/changelog.d/config b/changelog.d/config index c78b5f5e3f3..f4f1b9e5f57 100644 --- a/changelog.d/config +++ b/changelog.d/config @@ -1,2 +1,3 @@ organization: haskell repository: cabal +required-fields: packages prs diff --git a/changelog.d/die-on-missing-pkg-list b/changelog.d/die-on-missing-pkg-list new file mode 100644 index 00000000000..78e25843197 --- /dev/null +++ b/changelog.d/die-on-missing-pkg-list @@ -0,0 +1,11 @@ +synopsis: Die if package list is missing +packages: cabal-install +prs: #8944 + +description: { + +If a package list is missing, `cabal` will now die and suggest the user to run +`cabal update` instead of continuing into not being able to find packages coming +from the remote package server. + +} diff --git a/changelog.d/index-state-cabal-update b/changelog.d/index-state-cabal-update new file mode 100644 index 00000000000..f40ae672709 --- /dev/null +++ b/changelog.d/index-state-cabal-update @@ -0,0 +1,14 @@ +synopsis: Reject index-state younger than cached index file +packages: cabal-install +prs: #8944 + +description: { + +Requesting to use an index-state younger than the cached version will now fail, +telling the user to use an index-state older or equal to the cached file, or to +run `cabal update`. + +The warning for a non-existing index-state has been also demoted to appear only +on verbose logging. + +} diff --git a/changelog.d/issue-5993 b/changelog.d/issue-5993 new file mode 100644 index 00000000000..47580dd57cb --- /dev/null +++ b/changelog.d/issue-5993 @@ -0,0 +1,9 @@ +synopsis: Warn early that overwrite policy is needed +description: + Waiting for a long build and then seeing the install fail because a flag was + missing is frustrating. With this change we skip the wait and warn early, + before the build, that an overwrite policy flag would be needed for the + install to succeed. +packages: cabal-install +prs: #9268 +issues: #5993 diff --git a/changelog.d/issue-6268 b/changelog.d/issue-6268 deleted file mode 100644 index cc78eecf884..00000000000 --- a/changelog.d/issue-6268 +++ /dev/null @@ -1,19 +0,0 @@ -synopsis: Fix parsing of password-command option -packages: cabal-install -prs: #9002 -issuesa: #6268 - -description: { - -The password-command option did not parse its value correctly. -Quotes were ignored, making many kinds of commands impossible to -express (e.g. `sh -c "foo | bar"`). Also, `cabal user-config` -treated the argument list as a *list of option values*, rather than a -*value that is a list*. As a consequence, `cabal user-config -update` corrupted the value in the config file. - -Fixed these issues by parsing the command as a space separated list -of tokens (which may be enclosed in double quotes), and treating the -parsed list-of-token as one value (not multiple). - -} diff --git a/changelog.d/issue-8577 b/changelog.d/issue-8577 deleted file mode 100644 index b7890c261ba..00000000000 --- a/changelog.d/issue-8577 +++ /dev/null @@ -1,13 +0,0 @@ -synopsis: Existence of $XDG_CONFIG_HOME/cabal/config now overrides existence of $HOME/.cabal -packages: cabal-install -issues: #8577 - -description: { - -To avoid pre-XDG backwards compatibility from triggering due to other -tools accidentally creating a $HOME/.cabal directory, the presence of -$XDG_CONFIG_HOME/cabal/config now disables pre-XDG backwards -compatibility. Presumably $XDG_CONFIG_HOME/cabal/config will never be -created by accident. - -} diff --git a/changelog.d/issue-8680 b/changelog.d/issue-8680 index 3c3604b2ca2..0511f26fe9d 100644 --- a/changelog.d/issue-8680 +++ b/changelog.d/issue-8680 @@ -1,6 +1,7 @@ synopsis: `cabal init` should not suggest Cabal < 2.0 packages: Cabal issues: #8680 +prs: #8700 description: { diff --git a/changelog.d/issue-8841 b/changelog.d/issue-8841 deleted file mode 100644 index b0bc13c1bc2..00000000000 --- a/changelog.d/issue-8841 +++ /dev/null @@ -1,15 +0,0 @@ -synopsis: Shorten script-builds paths -packages: Cabal cabal-install -prs: #8898 -issues: #8841 - -description: { - -- Use Base64 hash truncated to 26 chars for script-build cache directories. -- Use the cache directory as the dist directory. -- Use script- as the component name instead of cabal-script-<...>. -- Use cabal-script- for the executable name. -- This change is incompatible with previous cabal versions in terms of cache location, - you should manually remove your old caches once you no longer need them. - -} diff --git a/changelog.d/issue-8843 b/changelog.d/issue-8843 deleted file mode 100644 index fa1c93141fa..00000000000 --- a/changelog.d/issue-8843 +++ /dev/null @@ -1,15 +0,0 @@ -synopsis: changes to haddock-project command - -packages: cabal-install -prs: #8919 -issues: #8843 #8958 -description: { - -- cabal haddock-project by default creates self contained - documentation (formerly it required `--local` switch, which is removed). -- `--gen-contents`, `--gen-index`, `--quickjump` and `--hyperlinked-source` - options where removed as they are always passed to haddock. -- Fixes a bug which prevented to use `haddock-project` with - packages containing sublibraries. - -} diff --git a/changelog.d/issue-8892 b/changelog.d/issue-8892 deleted file mode 100644 index 4e08b86494c..00000000000 --- a/changelog.d/issue-8892 +++ /dev/null @@ -1,11 +0,0 @@ -synopsis: Regenerate Lexer.hs to avoid out-of-bound array access due to a bug in Alex -packages: Cabal-syntax -prs: #8896 -issues: #8892 - -description: { - -- Regenerate Cabal-syntax's Lexer.hs with Alex 3.2.7.3 which includes a fix for - an out-of-bound array access (only noticeable with GHC's JavaScript backend). - -} diff --git a/changelog.d/issue-8951 b/changelog.d/issue-8951 deleted file mode 100644 index 38bc8c7503b..00000000000 --- a/changelog.d/issue-8951 +++ /dev/null @@ -1,3 +0,0 @@ -synopsis: Don't add `extra-prog-path: ~/.local/bin` when initially creating `~/.config/cabal/config` -packages: cabal-install -issues: #8951 diff --git a/changelog.d/issue-9098-lexbraces b/changelog.d/issue-9098-lexbraces index 19bb0bbee35..b637c08a34b 100644 --- a/changelog.d/issue-9098-lexbraces +++ b/changelog.d/issue-9098-lexbraces @@ -1,6 +1,7 @@ synopsis: Add LexBraces lexer warning packages: Cabal-syntax -issues: #8577 +issues: #9098 +prs: #9099 description: { diff --git a/changelog.d/issue-9122 b/changelog.d/issue-9122 deleted file mode 100644 index c8d82af1d86..00000000000 --- a/changelog.d/issue-9122 +++ /dev/null @@ -1,4 +0,0 @@ -synopsis: Fix dependency on an external package when an internal library with the same name exists -packages: Cabal -issues: #9122 -prs: #9132 diff --git a/changelog.d/issue-9453 b/changelog.d/issue-9453 new file mode 100644 index 00000000000..16e7a48fa86 --- /dev/null +++ b/changelog.d/issue-9453 @@ -0,0 +1,12 @@ +synopsis: Remove Distribution.Utils.TempTestDir module from Cabal library +packages: Cabal +prs: #9454 +issues: #9453 + +description: { + +This library was only used by internal tests, and now lives in the `Cabal-tests` library +which is shared across test components. + +} + diff --git a/changelog.d/issue-9534 b/changelog.d/issue-9534 new file mode 100644 index 00000000000..3e7a887af71 --- /dev/null +++ b/changelog.d/issue-9534 @@ -0,0 +1,12 @@ +synopsis: Distinguish `powerpc64le`, by adding `PPC64LE` constructor to type `Arch` +packages: Cabal Cabal-syntax +prs: #9535 +issues: #9534 + +description: { + +Adds constructor `PPC64LE` to type `Arch` to distinguish architecture +powerpc64le from powerpc64. Existing constructor `PPC64` now exclusively +represents powerpc64. + +} diff --git a/changelog.d/issue-9641 b/changelog.d/issue-9641 new file mode 100644 index 00000000000..34666f0ad59 --- /dev/null +++ b/changelog.d/issue-9641 @@ -0,0 +1,8 @@ +synopsis: offline flag applied to `source-repository-package`s +packages: Cabal-install +prs: #9771 +issues: #9641 + +description: { +`--offline` flag is already used to block access to Hackage. Now with this PR, this also applies to remote dependency `source-repository-package` in `cabal.project`. +} diff --git a/changelog.d/issue-9678 b/changelog.d/issue-9678 new file mode 100644 index 00000000000..cdcf8405311 --- /dev/null +++ b/changelog.d/issue-9678 @@ -0,0 +1,17 @@ +synopsis: Clarify the semantics of the -package-db flag +packages: cabal-install +prs: +issues: #9678 +prs: #9683 + +description: { + +The `--package-db` flag now only applies to the default +immutable initial package stack rather than also applying to the store +package database. + +This fixes an assertion failure which was triggered when using -package-db and also +clarifies how it should interact with `--store-dir` and `--dist-dir` flags. + +} + diff --git a/changelog.d/issue-9736 b/changelog.d/issue-9736 new file mode 100644 index 00000000000..f5a9dc1abee --- /dev/null +++ b/changelog.d/issue-9736 @@ -0,0 +1,12 @@ +synopsis: Add support for `GHC2024` +packages: Cabal cabal-install +issues: #9736 +prs: #9791 + +description: { + +Support for the `GHC2024` language edition, introduced by GHC 9.10, has been +added. It can now be used in the `default-language` and `other-languages` +fields, and will be offered as an option by `cabal init`. + +} diff --git a/changelog.d/pkgconfig-envvars b/changelog.d/pkgconfig-envvars deleted file mode 100644 index 9b570693a44..00000000000 --- a/changelog.d/pkgconfig-envvars +++ /dev/null @@ -1,8 +0,0 @@ -synopsis: PkgConfig environment variables -prs: #9134 - -description: { - -- `cabal` invokes `pkg-config` with `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS` and `PKG_CONFIG_ALLOW_SYSTEM_LIBS` set - -} diff --git a/changelog.d/pkgconfig-once b/changelog.d/pkgconfig-once index c3ac3ac47e0..bdb8e4b511b 100644 --- a/changelog.d/pkgconfig-once +++ b/changelog.d/pkgconfig-once @@ -1,5 +1,6 @@ synopsis: PkgConfig individual calls prs: #9134 +packages: cabal-install-solver description: { diff --git a/changelog.d/pr-8427 b/changelog.d/pr-8427 new file mode 100644 index 00000000000..402765942d6 --- /dev/null +++ b/changelog.d/pr-8427 @@ -0,0 +1,19 @@ +synopsis: Reimplementing `cabal check` +packages: Cabal +prs: #8427 +issues: #7423 + +description: { + +- For `cabal-install` users: `cabal check` do not warn on -O2 or similar + options if under an off-by-default cabal flag. +- For `Cabal` the library users: `checkPackage` signature has been simplified, + you do not need to pass a specific configuration of the package, since + we do not flatten GenericPackageDescription no more. +- For `Cabal` the library users: `checkPackageFileNames` has been removed, + use `checkPackageFiles` instead. +- For `Cabal` the library users: `checkPackageFilesGPD` has been introduced, + a function similar to `checkPackageFiles` that works on + `GenericPackageDescription`. You do not need to use + `flattenPackageDescription` anymore. +} diff --git a/changelog.d/pr-8819 b/changelog.d/pr-8819 deleted file mode 100644 index 1398a2ca648..00000000000 --- a/changelog.d/pr-8819 +++ /dev/null @@ -1,9 +0,0 @@ -synopsis: Use compiler flags for caching project config -packages: cabal-install -prs: #8819 - -description: { - -This ensures that cached project configs with conditionals re-execute the conditional logic when the compiler changes. - -} diff --git a/changelog.d/pr-8854 b/changelog.d/pr-8854 new file mode 100644 index 00000000000..8b77d09d3ed --- /dev/null +++ b/changelog.d/pr-8854 @@ -0,0 +1,9 @@ +synopsis: Add language extension ListTuplePuns +packages: Cabal-syntax +prs: #8854 + +description: { + +- adds support for the `ListTuplePuns` language extension (GHC proposal #475) + +} diff --git a/changelog.d/pr-8878 b/changelog.d/pr-8878 deleted file mode 100644 index af3dcce15de..00000000000 --- a/changelog.d/pr-8878 +++ /dev/null @@ -1,9 +0,0 @@ -synopsis: Fix default Nix configuration option in generated ~/.cabal/config file -packages: cabal-install -prs: #8878 - -description: { - -Fixes the default for ~/.cabal/config file. The nix option should now be commented out by default. - -} diff --git a/changelog.d/pr-8879 b/changelog.d/pr-8879 new file mode 100644 index 00000000000..079d642289b --- /dev/null +++ b/changelog.d/pr-8879 @@ -0,0 +1,12 @@ +synopsis: Add `cabal path` command +packages: cabal-install +prs: #8879 + +description: { + +The `cabal path` command prints the file system paths used by Cabal. +It is intended for use by tooling that needs to read or modify Cabal +data, such that it does not need to replicate the complicated logic +for respecting `CABAL_DIR`, `CABAL_CONFIG`, etc. + +} diff --git a/changelog.d/pr-8903 b/changelog.d/pr-8903 deleted file mode 100644 index 67b1bdb19ce..00000000000 --- a/changelog.d/pr-8903 +++ /dev/null @@ -1,9 +0,0 @@ -synopsis: add base to cabal install --lib default env file -packages: cabal-install -prs: #8903 - -description: { - -This adds base by default to the env file created by `cabal install --lib`. Further it ensures that packagedbs have been created before adding them to the env file. - -} diff --git a/changelog.d/pr-9004 b/changelog.d/pr-9004 deleted file mode 100644 index 6ff90746475..00000000000 --- a/changelog.d/pr-9004 +++ /dev/null @@ -1,11 +0,0 @@ -synopsis: Do not check PVP on internal targets -packages: cabal-install -prs: #9004 -issues: #8361 - -description: { - -- `cabal check` will not check for dependencies upper bounds in internal - targets (i.e. test-suites and benchmarks) - -} diff --git a/changelog.d/pr-9018 b/changelog.d/pr-9018 index bdce59ead14..b823fc4c33a 100644 --- a/changelog.d/pr-9018 +++ b/changelog.d/pr-9018 @@ -1,11 +1,11 @@ -synopsis: Structured Errors and Error Codes for Cabal -packages: cabal -prs: #9018 -issues: #8618 #8543 - - -description: { - -This will replace the `die'` function with `dieWithException` function which will throw structured errors rather than mere strings and also assign codes to corresponding errors that can be added to the error index. - -} +synopsis: Structured Errors and Error Codes for Cabal +packages: cabal +prs: #9018 +issues: #8618 #8543 + + +description: { + +This will replace the `die'` function with `dieWithException` function which will throw structured errors rather than mere strings and also assign codes to corresponding errors that can be added to the error index. + +} diff --git a/changelog.d/pr-9049 b/changelog.d/pr-9049 deleted file mode 100644 index 41fcd0a5bb7..00000000000 --- a/changelog.d/pr-9049 +++ /dev/null @@ -1,13 +0,0 @@ -synopsis: Do not always pass --quickjump to haddock #9049 -packages: Cabal -prs: #9049 -issues: #9060 -description: { - -6d8adf13101 caused `cabal` to always pass the `--quickjump` flag to Haddock. -Not only does this waste memory for a service that user hasn't asked for, -but also leads to a failure with Haddocks shipped with GHC 9.0 and 9.2, -which had a separate bug (fixed in later versions but not backported) when -Haddock does not pass `--quickjump` recursively to the package dependencies. - -} diff --git a/changelog.d/pr-9068 b/changelog.d/pr-9068 deleted file mode 100644 index cd590c76e85..00000000000 --- a/changelog.d/pr-9068 +++ /dev/null @@ -1,12 +0,0 @@ -synopsis: Add new Hackage root keys to bootstrap set -packages: cabal-install -prs: #9068 - -description: { - -The two new [Hackage root keyholders](https://github.com/haskell-infra/hackage-root-keys/tree/master/root-keys) were added to the bootstrap set. - -- Added Hackage root key for Joachim Breitner -- Added Hackage root key for Mathieu Boespflug - -} diff --git a/changelog.d/pr-9123 b/changelog.d/pr-9123 new file mode 100644 index 00000000000..17b3b2031c6 --- /dev/null +++ b/changelog.d/pr-9123 @@ -0,0 +1,8 @@ +synopsis: Remove --cabal-file flags from v2 commands +packages: cabal-install +prs: #9123 +issues: #8395 #7225 #6880 +description: { + The --cabal-file flag was never meant for public use but only for testing. To + avoid confusing the users any further we removed the flag from v2 commands. +} diff --git a/changelog.d/pr-9242 b/changelog.d/pr-9242 deleted file mode 100644 index dfabc5fd982..00000000000 --- a/changelog.d/pr-9242 +++ /dev/null @@ -1,3 +0,0 @@ -synopsis: Support text-2.1 in Cabal and Cabal-syntax -packages: Cabal Cabal-syntax -prs: #9242 diff --git a/changelog.d/pr-9326 b/changelog.d/pr-9326 new file mode 100644 index 00000000000..33350cd86f0 --- /dev/null +++ b/changelog.d/pr-9326 @@ -0,0 +1,10 @@ +synopsis: Include the GHC "Project Unit Id" in the cabal store path +packages: Cabal cabal-install +prs: #9326 +issues: #8114 +description: { +- This allows the use of several **API incompatible builds of the same version + of GHC** without corrupting the cabal store. +- This relies on the "Project Unit Id" which is available since GHC 9.8.1, + older versions of GHC do not benefit from this change. +} diff --git a/changelog.d/pr-9332 b/changelog.d/pr-9332 index c5d4c3d4ac4..c2851a647d4 100644 --- a/changelog.d/pr-9332 +++ b/changelog.d/pr-9332 @@ -1,4 +1,4 @@ -synopsis: Don't report `index.html` file as created, if not created by Haddock -packages: Cabal cabal-install -prs: #9332 -issues: #5120 +synopsis: Don't report `index.html` file as created, if not created by Haddock +packages: Cabal cabal-install +prs: #9332 +issues: #5120 diff --git a/changelog.d/pr-9346 b/changelog.d/pr-9346 new file mode 100644 index 00000000000..3f31da43837 --- /dev/null +++ b/changelog.d/pr-9346 @@ -0,0 +1,12 @@ +synopsis: remove +packages: cabal-install +prs: #9346 +issues: #9151 +significance: significant + +description: { + +- Remove "Log" as a log level in favour of "Info". +- Remove "Show" in Severity and replace by "displaySeverity" function + +} diff --git a/changelog.d/pr-9376 b/changelog.d/pr-9376 new file mode 100644 index 00000000000..d85dc9bf49a --- /dev/null +++ b/changelog.d/pr-9376 @@ -0,0 +1,6 @@ +synopsis: Avoid a double space in "Executing install plan ..." +description: + The "Executing·install·plan··serially" and other similar "Executing install + plan··..." outputs no longer contain double spaces. +packages: cabal-install +prs: #9376 \ No newline at end of file diff --git a/changelog.d/pr-9434 b/changelog.d/pr-9434 new file mode 100644 index 00000000000..a7872ea3fb3 --- /dev/null +++ b/changelog.d/pr-9434 @@ -0,0 +1,11 @@ +synopsis: Fix the platform string for GNU/Hurd +packages: Cabal +prs: #9434 + +description: { + +Depending who you ask, GNU/Hurd will be labelled "gnu" or "hurd". The autotools +use "gnu", so ghc follows this for installed files, even if the ghc source code +uses OSHurd. We thus need to add the translation between the two. + +} diff --git a/changelog.d/pr-9441 b/changelog.d/pr-9441 new file mode 100644 index 00000000000..c47ea10da13 --- /dev/null +++ b/changelog.d/pr-9441 @@ -0,0 +1,3 @@ +synopsis: Enable using $ORIGIN in RPATH on GNU/Hurd +packages: Cabal +prs: #9441 diff --git a/changelog.d/pr-9443 b/changelog.d/pr-9443 new file mode 100644 index 00000000000..353f1fb8cbd --- /dev/null +++ b/changelog.d/pr-9443 @@ -0,0 +1,11 @@ +synopsis: Use linker capability detection to improve linker use +packages: Cabal +prs: #9443 + +description: { + +- Previously the GHC version number and platform were used as a proxy for whether + the linker can generate relocatable objects. +- Now, the ability of the linker to create relocatable objects is detected. + +} diff --git a/changelog.d/pr-9445 b/changelog.d/pr-9445 new file mode 100644 index 00000000000..37f024ea060 --- /dev/null +++ b/changelog.d/pr-9445 @@ -0,0 +1,3 @@ +synopsis: Add support for 64-bit SPARC as a separate architecture +prs: #9445 +packages: Cabal Cabal-syntax diff --git a/changelog.d/pr-9464 b/changelog.d/pr-9464 new file mode 100644 index 00000000000..f1fe8b186f8 --- /dev/null +++ b/changelog.d/pr-9464 @@ -0,0 +1,22 @@ +synopsis: Support per-component builds when coverage is enabled +packages: Cabal cabal-install +prs: #9464 +issues: #4798 #5213 #6440 #6397 +significance: significant + +description: { + +Cabal now supports per-component builds when coverage is enabled. This enables +coverage for packages with internal libraries (#6440), and enables coverage for +packages that use backpack (#6397), even though we do not get coverage for +instantiations of an indefinite module (it is not clear what it means for HPC +to support backpack, regardless of Cabal). + +To achieve this, hpc information (`.mix` files) from a library is now written +into the package database of a library under `extraCompilationArtifacts`. + +Cabal configure (via the Setup interface) now accepts --coverage-for=, +a flag which specifies which libraries should be included in the coverage +report for some testsuite. + +} diff --git a/changelog.d/pr-9481 b/changelog.d/pr-9481 new file mode 100644 index 00000000000..5572ad56eab --- /dev/null +++ b/changelog.d/pr-9481 @@ -0,0 +1,13 @@ +synopsis: Guard PackageInfo_* modules behind `cabal-version` ≥ 3.12 +packages: Cabal cabal-install +prs: #9481 +issues: #9331 + +description: { + +`cabal check` now warns whenever PackageInfo_* autogen modules are +used with `cabal-version` ≥ 3.12. +Additionally, `cabal configure` will fail if you try to use PackageInfo_* +with `cabal-version` < 3.12. + +} diff --git a/changelog.d/pr-9502 b/changelog.d/pr-9502 new file mode 100644 index 00000000000..12e5cc0e47d --- /dev/null +++ b/changelog.d/pr-9502 @@ -0,0 +1,11 @@ +synopsis: Add language extension `TypeAbstractions` +packages: Cabal-syntax +prs: #9502 +issues: #9496 + +description: { + +- Adds support for the TypeAbstractions language extension. + +} + diff --git a/changelog.d/pr-9560 b/changelog.d/pr-9560 new file mode 100644 index 00000000000..9f6ce9a4133 --- /dev/null +++ b/changelog.d/pr-9560 @@ -0,0 +1,22 @@ +synopsis: Shorten solver rejection messages by removing repetition +packages: cabal-install-solver +prs: #9560 +issues: #9559 #4251 + +description: { + +As before, we show a single rejection as hyphenated package-version. + +For multiple rejections, we show a list of versions preceded by package +semicolon, a much shorter rendering of the same information. + +```diff +- [__0] rejecting: pandoc-3.1.8, pandoc-3.1.7, pandoc-3.1.6.2, pandoc-3.1.6.1, +- pandoc-3.1.6, pandoc-3.1.5, pandoc-3.1.4, pandoc-3.1.3, pandoc-3.1.2, +- pandoc-3.1.1, pandoc-3.1, pandoc-3.0.1, pandoc-3.0, pandoc-2.19.2, +- pandoc-2.19.1, pandoc-2.19, pandoc-2.18, pandoc-2.17.1.1, pandoc-2.17.1, ++ [__0] rejecting: pandoc; 3.1.8, 3.1.7, 3.1.6.2, 3.1.6.1, 3.1.6, 3.1.5, 3.1.4, ++ 3.1.3, 3.1.2, 3.1.1, 3.1, 3.0.1, 3.0, 2.19.2, 2.19.1, 2.19, 2.18, 2.17.1.1, +``` + +} \ No newline at end of file diff --git a/changelog.d/pr-9673 b/changelog.d/pr-9673 new file mode 100644 index 00000000000..c14776b0db9 --- /dev/null +++ b/changelog.d/pr-9673 @@ -0,0 +1,19 @@ +synopsis: Merge globbing implementations +packages: Cabal cabal-install +prs: #9673 +issues: #5349 + +description: { + +The common aspects of the globbing functionality between `Cabal` and +`cabal-install` have been factored out. The only change in the user-facing API +is that we now record when a glob does not match exactly, but matches a +directory with that same name, with the new constructor `GlobMatchesDirectory` +of `GlobResult`. + +To illustrate, this change means that when `foo/dir` is a directory, the glob +`*/dir/` matches exactly `foo/dir` (as before), but now +`*/dir` produces `GlobMatchesDirectory` instead of failing. +This allows callers to decide whether to allow or discard such inexact matches. + +} diff --git a/changelog.d/pr-9766 b/changelog.d/pr-9766 new file mode 100644 index 00000000000..3d10abb659f --- /dev/null +++ b/changelog.d/pr-9766 @@ -0,0 +1,11 @@ +synopsis: Warn on missing `default-language` +packages: Cabalcabal-install +prs: #9766 +issues: #9620 + +description: { + +- To help the adoption of GHC language editions, `cabal check` will now + warn about missing `default-language`. + +} diff --git a/changelog.d/pr-9813 b/changelog.d/pr-9813 new file mode 100644 index 00000000000..fc6195ac6e5 --- /dev/null +++ b/changelog.d/pr-9813 @@ -0,0 +1,12 @@ +synopsis: Adjust BSD-2-Clause and BSD-3-Clause licence text +packages: cabal-install +prs: #9813 +issues: #9812 + +description: { + +This change matters to BSD-2-Clause and BSD-3-Clause licences. For these two +licences, `cabal init` created a licence file that slightly differed from +wording published at SPDX. This has been rectified. + +} diff --git a/changelog.d/pr-check-ignore b/changelog.d/pr-check-ignore new file mode 100644 index 00000000000..240a03f989b --- /dev/null +++ b/changelog.d/pr-check-ignore @@ -0,0 +1,18 @@ +synopsis: Add `--ignore` to `cabal check` +packages: Cabal cabal-check +prs: #9442 +issues: #8587 + +description: { + +- `cabal check` now ignores specific warnings with `--ignore`. E.g. + `--ignore=missing-upper-bounds` will not display “Missing upper + bounds” warnings. +- `cabal check` output now prints the warning identifier too + (like `[no-category]`). +- `Distribution.PackageDescription.Check.Warning` now exports + `filterPackageChecksById`, this can be used by third-party + tools to filter warnings. + +} + diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index d8ced7f65a4..7add67b61eb 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -1,8 +1,7 @@ {% extends "!layout.html" %} {% block menu %} - {{ super() }} - Reference +{{ super() }} + Cabal Syntax Quicklinks Index {% endblock %} - diff --git a/doc/bugs-and-stability.rst b/doc/bugs-and-stability.rst deleted file mode 100644 index 81d27d3dd1a..00000000000 --- a/doc/bugs-and-stability.rst +++ /dev/null @@ -1,6 +0,0 @@ -Reporting Bugs and Stability of Cabal Interfaces -================================================ - -.. toctree:: - misc - diff --git a/doc/buildinfo-fields-reference.rst b/doc/buildinfo-fields-reference.rst index 910bcf6813c..dd8c505a85e 100644 --- a/doc/buildinfo-fields-reference.rst +++ b/doc/buildinfo-fields-reference.rst @@ -164,7 +164,7 @@ Build info fields asm-options * Monoidal field * Available since ``cabal-version: 3.0``. - * Documentation of :pkg-field:`asm-options` + * Documentation of :pkg-field:`library:asm-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -172,7 +172,7 @@ asm-options asm-sources * Monoidal field * Available since ``cabal-version: 3.0``. - * Documentation of :pkg-field:`asm-sources` + * Documentation of :pkg-field:`library:asm-sources` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} @@ -180,7 +180,7 @@ asm-sources autogen-includes * Monoidal field * Available since ``cabal-version: 3.0``. - * Documentation of :pkg-field:`autogen-includes` + * Documentation of :pkg-field:`library:autogen-includes` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} @@ -188,21 +188,21 @@ autogen-includes autogen-modules * Monoidal field * Available since ``cabal-version: 2.0``. - * Documentation of :pkg-field:`autogen-modules` + * Documentation of :pkg-field:`library:autogen-modules` .. math:: \mathrm{commalist}\left({\left(\mathop{\mathit{upper}}{\left\{ \mathop{\mathit{alpha\text{-}num}}\mid[\mathop{\mathord{``}\mathtt{\text{'}}\mathord{"}}\mathop{\mathord{``}\mathtt{\text{_}}\mathord{"}}] \right\}}^\ast_{}\right)}^+_{\mathop{\mathord{``}\mathtt{\text{.}}\mathord{"}}}\right) build-depends * Monoidal field - * Documentation of :pkg-field:`build-depends` + * Documentation of :pkg-field:`library:build-depends` .. math:: \mathrm{commalist}\left(\mathop{\mathit{pkg\text{-}name}}{\left(\mathop{\mathord{``}\mathtt{\text{:}}\mathord{"}}\left\{ \mathop{\mathit{unqual\text{-}name}}\mid\mathop{\mathord{``}\mathtt{\{}\mathord{"}}\circ{\mathop{\mathit{unqual\text{-}name}}}^+_{\left(\circ\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}\circ\right)}\circ\mathop{\mathord{``}\mathtt{\}}\mathord{"}} \right\}\right)}^?{\left(\circ\mathop{\mathit{version\text{-}range}}\right)}^?\right) build-tool-depends * Monoidal field - * Documentation of :pkg-field:`build-tool-depends` + * Documentation of :pkg-field:`library:build-tool-depends` .. math:: \mathrm{commalist}\mathsf{\color{red}{TODO}} @@ -218,21 +218,21 @@ build-tools buildable * Boolean field * Default: ``True`` - * Documentation of :pkg-field:`buildable` + * Documentation of :pkg-field:`library:buildable` .. math:: \left\{ \mathop{\mathord{``}\mathtt{True}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{False}\mathord{"}} \right\} c-sources * Monoidal field - * Documentation of :pkg-field:`c-sources` + * Documentation of :pkg-field:`library:c-sources` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} cc-options * Monoidal field - * Documentation of :pkg-field:`cc-options` + * Documentation of :pkg-field:`library:cc-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -240,7 +240,7 @@ cc-options cmm-options * Monoidal field * Available since ``cabal-version: 3.0``. - * Documentation of :pkg-field:`cmm-options` + * Documentation of :pkg-field:`library:cmm-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -248,14 +248,14 @@ cmm-options cmm-sources * Monoidal field * Available since ``cabal-version: 3.0``. - * Documentation of :pkg-field:`cmm-sources` + * Documentation of :pkg-field:`library:cmm-sources` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} cpp-options * Monoidal field - * Documentation of :pkg-field:`cpp-options` + * Documentation of :pkg-field:`library:cpp-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -263,7 +263,7 @@ cpp-options cxx-options * Monoidal field * Available since ``cabal-version: 2.2``. - * Documentation of :pkg-field:`cxx-options` + * Documentation of :pkg-field:`library:cxx-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -271,7 +271,7 @@ cxx-options cxx-sources * Monoidal field * Available since ``cabal-version: 2.2``. - * Documentation of :pkg-field:`cxx-sources` + * Documentation of :pkg-field:`library:cxx-sources` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} @@ -279,7 +279,7 @@ cxx-sources default-extensions * Monoidal field * Available since ``cabal-version: 1.10``. - * Documentation of :pkg-field:`default-extensions` + * Documentation of :pkg-field:`library:default-extensions` .. math:: \mathrm{optcommalist}\mathsf{\color{red}{TODO}} @@ -287,10 +287,10 @@ default-extensions default-language * Optional field * Available since ``cabal-version: 1.10``. - * Documentation of :pkg-field:`default-language` + * Documentation of :pkg-field:`library:default-language` .. math:: - \left\{ \mathop{\mathord{``}\mathtt{Haskell98}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{Haskell2010}\mathord{"}} \right\} + \left\{ \begin{gathered}\mathop{\mathord{``}\mathtt{GHC2024}\mathord{"}}\\\mathop{\mathord{``}\mathtt{GHC2021}\mathord{"}}\\\mathop{\mathord{``}\mathtt{Haskell2010}\mathord{"}}\\\mathop{\mathord{``}\mathtt{Haskell98}\mathord{"}}\end{gathered} \right\} extensions * Monoidal field @@ -302,7 +302,7 @@ extensions extra-bundled-libraries * Monoidal field - * Documentation of :pkg-field:`extra-bundled-libraries` + * Documentation of :pkg-field:`library:extra-bundled-libraries` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} @@ -310,105 +310,107 @@ extra-bundled-libraries extra-dynamic-library-flavours * Monoidal field * Available since ``cabal-version: 3.0``. - * Documentation of :pkg-field:`extra-dynamic-library-flavours` + * Documentation of :pkg-field:`library:extra-dynamic-library-flavours` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} extra-framework-dirs * Monoidal field - * Documentation of :pkg-field:`extra-framework-dirs` + * Documentation of :pkg-field:`library:extra-framework-dirs` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} extra-ghci-libraries * Monoidal field - * Documentation of :pkg-field:`extra-ghci-libraries` + * Documentation of :pkg-field:`library:extra-ghci-libraries` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} extra-lib-dirs * Monoidal field - * Documentation of :pkg-field:`extra-lib-dirs` + * Documentation of :pkg-field:`library:extra-lib-dirs` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} extra-lib-dirs-static * Monoidal field - * Documentation of :pkg-field:`extra-lib-dirs-static` + * Available since ``cabal-version: 3.8``. + * Documentation of :pkg-field:`library:extra-lib-dirs-static` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} extra-libraries * Monoidal field - * Documentation of :pkg-field:`extra-libraries` + * Documentation of :pkg-field:`library:extra-libraries` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} -extra-library-flavours +extra-libraries-static * Monoidal field - * Documentation of :pkg-field:`extra-library-flavours` + * Available since ``cabal-version: 3.8``. + * Documentation of :pkg-field:`library:extra-libraries-static` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} -extra-libraries +extra-library-flavours * Monoidal field - * Documentation of :pkg-field:`extra-libraries-static` + * Documentation of :pkg-field:`library:extra-library-flavours` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} frameworks * Monoidal field - * Documentation of :pkg-field:`frameworks` + * Documentation of :pkg-field:`library:frameworks` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} ghc-options * Monoidal field - * Documentation of :pkg-field:`ghc-options` + * Documentation of :pkg-field:`library:ghc-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} ghc-prof-options * Monoidal field - * Documentation of :pkg-field:`ghc-prof-options` + * Documentation of :pkg-field:`library:ghc-prof-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} ghc-shared-options * Monoidal field - * Documentation of :pkg-field:`ghc-shared-options` + * Documentation of :pkg-field:`library:ghc-shared-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} ghcjs-options * Monoidal field - * Documentation of :pkg-field:`ghcjs-options` + * Documentation of :pkg-field:`library:ghcjs-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} ghcjs-prof-options * Monoidal field - * Documentation of :pkg-field:`ghcjs-prof-options` + * Documentation of :pkg-field:`library:ghcjs-prof-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} ghcjs-shared-options * Monoidal field - * Documentation of :pkg-field:`ghcjs-shared-options` + * Documentation of :pkg-field:`library:ghcjs-shared-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -423,42 +425,50 @@ hs-source-dir hs-source-dirs * Monoidal field - * Documentation of :pkg-field:`hs-source-dirs` + * Documentation of :pkg-field:`library:hs-source-dirs` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} +hsc2hs-options + * Monoidal field + * Available since ``cabal-version: 3.6``. + * Documentation of :pkg-field:`library:hsc2hs-options` + + .. math:: + {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} + include-dirs * Monoidal field - * Documentation of :pkg-field:`include-dirs` + * Documentation of :pkg-field:`library:include-dirs` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} includes * Monoidal field - * Documentation of :pkg-field:`includes` + * Documentation of :pkg-field:`library:includes` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} install-includes * Monoidal field - * Documentation of :pkg-field:`install-includes` + * Documentation of :pkg-field:`library:install-includes` .. math:: \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} js-sources * Monoidal field - * Documentation of :pkg-field:`js-sources` + * Documentation of :pkg-field:`library:js-sources` .. math:: \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} ld-options * Monoidal field - * Documentation of :pkg-field:`ld-options` + * Documentation of :pkg-field:`library:ld-options` .. math:: {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet} @@ -466,15 +476,14 @@ ld-options mixins * Monoidal field * Available since ``cabal-version: 2.0``. - * Documentation of :pkg-field:`mixins` + * Documentation of :pkg-field:`library:mixins` .. math:: \mathrm{commalist}\left(\mathop{\mathit{package\text{-}name}}{\left(\mathop{\mathord{``}\mathtt{\text{:}}\mathord{"}}\mathop{\mathit{library\text{-}name}}\right)}^?{\left(\bullet\left\{ \mid\mathop{\mathord{``}\mathtt{hiding}\mathord{"}}\circ\mathop{\mathord{``}\mathtt{\text{(}}\mathord{"}}\circ{\mathop{\mathit{module\text{-}name}}}^\ast_{\left(\circ\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}\circ\right)}\circ\mathop{\mathord{``}\mathtt{\text{)}}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{\text{(}}\mathord{"}}\circ{\left(\mathop{\mathit{module\text{-}name}}{\left(\bullet\mathop{\mathord{``}\mathtt{as}\mathord{"}}\bullet\mathop{\mathit{module\text{-}name}}\right)}^?\right)}^\ast_{\left(\circ\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}\circ\right)}\circ\mathop{\mathord{``}\mathtt{\text{)}}\mathord{"}} \right\}{\left(\circ\mathop{\mathord{``}\mathtt{requires}\mathord{"}}\bullet\left\{ \mid\mathop{\mathord{``}\mathtt{hiding}\mathord{"}}\circ\mathop{\mathord{``}\mathtt{\text{(}}\mathord{"}}\circ{\mathop{\mathit{module\text{-}name}}}^\ast_{\left(\circ\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}\circ\right)}\circ\mathop{\mathord{``}\mathtt{\text{)}}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{\text{(}}\mathord{"}}\circ{\left(\mathop{\mathit{module\text{-}name}}{\left(\bullet\mathop{\mathord{``}\mathtt{as}\mathord{"}}\bullet\mathop{\mathit{module\text{-}name}}\right)}^?\right)}^\ast_{\left(\circ\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}\circ\right)}\circ\mathop{\mathord{``}\mathtt{\text{)}}\mathord{"}} \right\}\right)}^?\right)}^?\right) other-extensions * Monoidal field - * Available since ``cabal-version: 1.10``. - * Documentation of :pkg-field:`other-extensions` + * Documentation of :pkg-field:`library:other-extensions` .. math:: \mathrm{optcommalist}\mathsf{\color{red}{TODO}} @@ -482,21 +491,21 @@ other-extensions other-languages * Monoidal field * Available since ``cabal-version: 1.10``. - * Documentation of :pkg-field:`other-languages` + * Documentation of :pkg-field:`library:other-languages` .. math:: - \mathrm{optcommalist}\left\{ \mathop{\mathord{``}\mathtt{Haskell98}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{Haskell2010}\mathord{"}} \right\} + \mathrm{optcommalist}\left\{ \begin{gathered}\mathop{\mathord{``}\mathtt{GHC2024}\mathord{"}}\\\mathop{\mathord{``}\mathtt{GHC2021}\mathord{"}}\\\mathop{\mathord{``}\mathtt{Haskell2010}\mathord{"}}\\\mathop{\mathord{``}\mathtt{Haskell98}\mathord{"}}\end{gathered} \right\} other-modules * Monoidal field - * Documentation of :pkg-field:`other-modules` + * Documentation of :pkg-field:`library:other-modules` .. math:: \mathrm{commalist}\left({\left(\mathop{\mathit{upper}}{\left\{ \mathop{\mathit{alpha\text{-}num}}\mid[\mathop{\mathord{``}\mathtt{\text{'}}\mathord{"}}\mathop{\mathord{``}\mathtt{\text{_}}\mathord{"}}] \right\}}^\ast_{}\right)}^+_{\mathop{\mathord{``}\mathtt{\text{.}}\mathord{"}}}\right) pkgconfig-depends * Monoidal field - * Documentation of :pkg-field:`pkgconfig-depends` + * Documentation of :pkg-field:`library:pkgconfig-depends` .. math:: \mathrm{commalist}\mathsf{\color{red}{TODO}} @@ -504,23 +513,12 @@ pkgconfig-depends virtual-modules * Monoidal field * Available since ``cabal-version: 2.2``. - * Documentation of :pkg-field:`virtual-modules` + * Documentation of :pkg-field:`library:virtual-modules` .. math:: \mathrm{commalist}\left({\left(\mathop{\mathit{upper}}{\left\{ \mathop{\mathit{alpha\text{-}num}}\mid[\mathop{\mathord{``}\mathtt{\text{'}}\mathord{"}}\mathop{\mathord{``}\mathtt{\text{_}}\mathord{"}}] \right\}}^\ast_{}\right)}^+_{\mathop{\mathord{``}\mathtt{\text{.}}\mathord{"}}}\right) -Library fields --------------- - -visibility - * Optional field - * Documentation of :pkg-field:`library:visibility` - - .. math:: - \left\{ \mathop{\mathord{``}\mathtt{public}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{private}\mathord{"}} \right\} - - Package description fields -------------------------- @@ -557,7 +555,7 @@ copyright data-dir * Optional field - * Default: ``""`` + * Default: ``.`` * Documentation of :pkg-field:`data-dir` .. math:: @@ -612,7 +610,7 @@ license-file * Documentation of :pkg-field:`license-file` .. math:: - \mathrm{optcommalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} + \left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} maintainer * Free text field @@ -655,6 +653,14 @@ version Test-suite fields ----------------- +code-generators + * Monoidal field + * Available since ``cabal-version: 3.8``. + * Documentation of :pkg-field:`test-suite:code-generators` + + .. math:: + \mathrm{commalist}\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}\mathop{\mathord{``}\mathtt{\text{,}}\mathord{"}}]^c}}^+_{} \right\} + main-is * Optional field * Documentation of :pkg-field:`test-suite:main-is` @@ -675,3 +681,5 @@ type .. math:: \left\{ \mathop{\mathord{``}\mathtt{exitcode\text{-}stdio\text{-}1\text{.}0}\mathord{"}}\mid\mathop{\mathord{``}\mathtt{detailed\text{-}0\text{.}9}\mathord{"}} \right\} + + diff --git a/doc/cabal-commands.rst b/doc/cabal-commands.rst index 88803232bf6..35297d2937b 100644 --- a/doc/cabal-commands.rst +++ b/doc/cabal-commands.rst @@ -19,6 +19,7 @@ Commands [global] user-config Display and update the user's global cabal configuration. help Help about commands. + path Display paths used by cabal. [package database] update Updates list of known packages. @@ -284,6 +285,38 @@ cabal preferences. It is very useful when you are e.g. first configuring Note how ``--augment`` syntax follows ``cabal user-config diff`` output. +cabal path +^^^^^^^^^^ + +``cabal path`` prints the file system paths used by ``cabal`` for +cache, store, installed binaries, and so on. When run without any +options, it will show all paths, labeled with how they are namen in +the configuration file: + +:: + $ cabal path + cache-dir: /home/haskell/.cache/cabal/packages + logs-dir: /home/haskell/.cache/cabal/logs + store-dir: /home/haskell/.local/state/cabal/store + config-file: /home/haskell/.config/cabal/config + installdir: /home/haskell/.local/bin + ... + +If ``cabal path`` is passed a single option naming a path, then that +path will be printed *without* any label: + +:: + + $ cabal path --installdir + /home/haskell/.local/bin + +This is a stable interface and is intended to be used for scripting. +For example: + +:: + $ ls $(cabal path --installdir) + ... + .. _command-group-database: Package database commands @@ -1139,6 +1172,11 @@ tricky GHC options, etc.). Run ``cabal check`` in the folder where your ``.cabal`` package file is. +.. option:: -i, --ignore=WARNING + + Ignore a specific type of warning (e.g. ``--ignore=missing-upper-bounds``). + Check the list of warnings for which constructor to use. + .. option:: -v[n], --verbose[=n] Control verbosity (n is 0--3, default verbosity level is 1). @@ -1148,6 +1186,147 @@ to Hackage requirements for uploaded packages: if no error is reported, Hackage should accept your package. If errors are present ``cabal check`` exits with ``1`` and Hackage will refuse the package. +A list of all warnings with their constructor: + +- ``parser-warning``: inherited from parser. +- ``no-name-field``: missing ``name`` field. +- ``no-version-field``: missing ``version`` field. +- ``no-target``: missing target in ``.cabal``. +- ``unnamed-internal-library``: unnamed internal library. +- ``duplicate-sections``: duplicate name in target. +- ``illegal-library-name``: internal library with same name as package. +- ``no-modules-exposed``: no module exposed in library. +- ``signatures``: ``signatures`` used with ``cabal-version`` < 2.0. +- ``autogen-not-exposed``: ``autogen-module`` neither in ``exposed-modules`` nor ``other-modules``. +- ``autogen-not-included``: ``autogen-include`` neither in ``include`` nor ``install-includes``. +- ``no-main-is``: missing ``main-is``. +- ``unknown-extension-main``: ``main-is`` is not ``.hs`` nor ``.lhs``. +- ``c-like-main``: C-like source file in ``main-is`` with ``cabal-version`` < 1.18. +- ``autogen-other-modules``: ``autogen-module`` not in ``other-modules``. +- ``autogen-exe``: ``autogen-include`` not in ``includes``. +- ``unknown-testsuite-type``: unknown test-suite type. +- ``unsupported-testsuite``: unsupported test-suite type. +- ``unknown-bench``: unknown benchmark type. +- ``unsupported-bench``: unsupported benchmark type. +- ``bench-unknown-extension``: ``main-is`` for benchmark is neither ``.hs`` nor ``.lhs``. +- ``invalid-name-win``: invalid package name on Windows. +- ``reserved-z-prefix``: package with ``z-`` prexif (reseved for Cabal. +- ``no-build-type``: missing ``build-type``. +- ``undeclared-custom-setup``: ``custom-setup`` section without ``build-type: Custom`` +- ``unknown-compiler-tested``: unknown compiler in ``tested-with``. +- ``unknown-languages``: unknown languages. +- ``unknown-extension``: unknown extensions. +- ``languages-as-extensions``: languages listed as extensions. +- ``deprecated-extensions``: deprecated extensions. +- ``no-category``: missing ``category`` field. +- ``no-maintainer``: missing ``maintainer`` field. +- ``no-synopsis``: missing ``synopsis`` field. +- ``no-description``: missing ``description`` field. +- ``no-syn-desc``: missing ``synopsis`` or ``description`` field. +- ``long-synopsis``: ``synopsis`` longer than 80 characters. +- ``short-description``: ``description`` shorter than ``synopsis``. +- ``invalid-range-tested``: invalid ``tested-with`` version range. +- ``impossible-dep``: impossible internal library version range dependency. +- ``impossible-dep-exe``: impossible internal executable version range dependency. +- ``no-internal-exe``: missing internal executable. +- ``license-none``: ``NONE`` in ``license`` field. +- ``no-license``: no ``license`` field. +- ``all-rights-reserved``: “All rights reserved” license. +- ``license-parse``: license not to be used with ``cabal-version`` < 1.4. +- ``unknown-license``: unknown license. +- ``bsd4-license``: uncommon BSD (BSD4) license. +- ``unknown-license-version``: unknown license version. +- ``no-license-file``: missing license file. +- ``unrecognised-repo-type``: unrecognised kind of source-repository. +- ``repo-no-type``: missing ``type`` in ``source-repository``. +- ``repo-no-location``: missing ``location`` in ``source-repository``. +- ``repo-no-module``: missing ``module`` in ``source-repository``. +- ``repo-no-tag``: missing ``tag`` in ``source-repository``. +- ``repo-relative-dir``: ``subdir`` in ``source-repository`` must be relative. +- ``repo-malformed-subdir``: malformed ``subdir`` in ``source-repository``. +- ``option-fasm``: unnecessary ``-fasm``. +- ``option-fhpc``: unnecessary ``-fhpc``. +- ``option-prof``: unnecessary ``-prof``. +- ``option-o``: unnecessary ``-o``. +- ``option-hide-package``: unnecessary ``-hide-package``. +- ``option-make``: unnecessary ``--make``. +- ``option-optimize``: unnecessary disable optimization flag. +- ``option-o1``: unnecessary optimisation flag (``-O1``). +- ``option-o2``: unnecessary optimisation flag (``-O2``). +- ``option-split-section``: unnecessary ``-split-section``. +- ``option-split-objs``: unnecessary ``-split-objs``. +- ``option-optl-wl``:unnecessary ``-optl-Wl,-s``. +- ``use-extension``: use ``extension`` field instead of ``-fglasgow-exts``. +- ``option-rtsopts``: unnecessary ``-rtsopts``. +- ``option-with-rtsopts``: unnecessary ``-with-rtsopts``. +- ``option-opt-c``: unnecessary ``-O[n]`` in C code. +- ``cpp-options``: unportable ``-cpp-options`` flag. +- ``misplaced-c-opt``: C-like options in wrong cabal field. +- ``relative-path-outside``: relative path outside of source tree. +- ``absolute-path``: absolute path where not allowed. +- ``malformed-relative-path``: malformed relative path. +- ``unreliable-dist-path``: unreliable path pointing inside ``dist``. +- ``glob-syntax-error``: glob syntax error. +- ``recursive-glob``: recursive glob including source control folders. +- ``invalid-path-win``: invalid path on Windows. +- ``long-path``: path too long (POSIX, 255 ASCII chars). +- ``long-name``: path *name* too long (POSIX, 100 ASCII chars). +- ``name-not-portable``: path non portable (POSIX, split requirements). +- ``empty-path``: empty path. +- ``test-cabal-ver``: ``test-suite`` used with ``cabal-version`` < 1.10. +- ``default-language``: ``default-language`` used with ``cabal-version`` < 1.10. +- ``no-default-language``: missing ``default-language``. +- ``add-default-language``: suggested ``default-language``. +- ``extra-doc-files``: ``extra-doc-files`` used with ``cabal-version`` < 1.18. +- ``multilib``: multiple ``library`` sections with ``cabal-version`` < 2.0. +- ``reexported-modules``: ``reexported-modules`` with ``cabal-version`` < 1.22. +- ``mixins``: ``mixins`` with ``cabal-version`` < 2.0. +- ``extra-framework-dirs``: ``extra-framework-dirs`` with ``cabal-version`` < 1.24. +- ``default-extensions``: ``default-extensions`` with ``cabal-version`` < 1.10. +- ``extensions-field``: deprecated ``extensions`` field used with ``cabal-version`` ≥ 1.10 +- ``unsupported-sources``: ``asm-sources``, ``cmm-sources``, ``extra-bundled-libraries`` or ``extra-library-flavours`` used with ``cabal-version`` < 3.0. +- ``extra-dynamic``: ``extra-dynamic-library-flavours`` used with cabal-version < 3.0. +- ``virtual-modules``: ``virtual-modules`` used with cabal-version < 2.2. +- ``source-repository``: ``source-repository`` used with ``cabal-version`` 1.6. +- ``incompatible-extension``: incompatible language extension with ``cabal-version``. +- ``no-setup-depends``: missing ``setup-depends`` field in ``custom-setup`` with ``cabal-version`` ≥ 1.24. +- ``dependencies-setup``: missing dependencies in ``custom-setup`` with ``cabal-version`` ≥ 1.24. +- ``no-autogen-paths``: missing autogen ``Paths_*`` modules in ``autogen-modules`` (``cabal-version`` ≥ 2.0). +- ``no-autogen-pinfo``: missing autogen ``PackageInfo_*`` modules in ``autogen-modules`` *and* ``exposed-modules``/``other-modules`` (``cabal-version`` ≥ 2.0). +- ``no-glob-match``: glob pattern not matching any file. +- ``glob-no-extension``: glob pattern not matching any file becuase of lack of extension matching (`cabal-version` < 2.4). +- ``glob-missing-dir``: glob pattern trying to match a missing directory. +- ``unknown-os``: unknown operating system name in condition. +- ``unknown-arch``: unknown architecture in condition. +- ``unknown-compiler``: unknown compiler in condition. +- ``missing-bounds-important``: missing upper bounds for important dependencies (``base``, and for ``custom-setup`` ``Cabal`` too). +- ``missing-upper-bounds``: missing upper bound in dependency (excluding test-suites and benchmarks). +- ``suspicious-flag``: troublesome flag name (e.g. starting with a dash). +- ``unused-flag``: unused user flags. +- ``non-ascii``: non-ASCII characters in custom field. +- ``rebindable-clash-paths``: ``Rebindable Syntax`` with ``OverloadedStrings``/``OverloadedStrings`` plus autogenerated ``Paths_*`` modules with ``cabal-version`` < 2.2. +- ``rebindable-clash-info``: ``Rebindable Syntax`` with ``OverloadedStrings``/``OverloadedStrings`` plus autogenerated ``PackageInfo_*`` modules with ``cabal-version`` < 2.2. +- ``werror``: ``-WError`` not under a user flag. +- ``unneeded-j``: suspicious ``-j[n]`` usage. +- ``fdefer-type-errors``: suspicious ``-fdefer-type-errors``. +- ``debug-flag``: suspicious ``-d*`` debug flag for distributed package. +- ``fprof-flag``: suspicious ``-fprof-*`` flag. +- ``missing-bounds-setup``: missing upper bounds in ``setup-depends``. +- ``duplicate-modules``: duplicate modules in target. +- ``maybe-duplicate-modules``: potential duplicate module in target (subject to conditionals). +- ``bom``: unicode byte order mark (BOM) character at start of file. +- ``name-no-match``: filename not matching ``name``. +- ``no-cabal-file``: no ``.cabal`` file found in folder. +- ``multiple-cabal-file``: multiple ``.cabal`` files found in folder. +- ``unknown-file``: path refers to a file which does not exist. +- ``missing-setup``: missing ``Setup.hs`` or ``Setup.lsh``. +- ``missing-conf-script``: missing ``configure`` script with ``build-type: Configure``. +- ``unknown-directory``: paths refer to a directory which does not exist. +- ``no-repository``: missing ``source-repository`` section. +- ``no-docs``: missing expected documentation files (changelog). +- ``doc-place``: documentation files listed in ``extra-source-files`` instead of ``extra-doc-files``. + + cabal sdist ^^^^^^^^^^^ @@ -1203,8 +1382,8 @@ to Hackage. .. option:: -t TOKEN or -tTOKEN, --token=TOKEN - Your Hackage authentication token. You can create and delete - authentication tokens on Hackage's `account management page + Your Hackage authentication token. You can create and delete + authentication tokens on Hackage's `account management page `__. .. option:: -u USERNAME or -uUSERNAME, --username=USERNAME @@ -1238,8 +1417,8 @@ cabal report .. option:: -t TOKEN or -tTOKEN, --token=TOKEN - Your Hackage authentication token. You can create and delete - authentication tokens on Hackage's `account management page + Your Hackage authentication token. You can create and delete + authentication tokens on Hackage's `account management page `__. .. option:: -u USERNAME or -uUSERNAME, --username=USERNAME diff --git a/doc/intro.rst b/doc/cabal-context.rst similarity index 98% rename from doc/intro.rst rename to doc/cabal-context.rst index d2219ab32d1..ce152cca713 100644 --- a/doc/intro.rst +++ b/doc/cabal-context.rst @@ -14,8 +14,8 @@ use Hackage_ which is Haskell's central package archive that contains thousands of libraries and applications in the Cabal package format. -Introduction -============ +What Cabal does +=============== Cabal is a package system for Haskell software. The point of a package system is to enable software developers and users to easily distribute, @@ -122,7 +122,7 @@ the package depends on. For full details on what goes in the ``.cabal`` and ``Setup.hs`` files, and for all the other features provided by the build system, see the -section on :doc:`developing packages `. +section on :doc:`How to package Haskell code `. Cabal featureset ---------------- diff --git a/doc/misc.rst b/doc/cabal-interface-stability.rst similarity index 89% rename from doc/misc.rst rename to doc/cabal-interface-stability.rst index 5d01198f0e5..2993f8ab0ff 100644 --- a/doc/misc.rst +++ b/doc/cabal-interface-stability.rst @@ -1,13 +1,3 @@ -Reporting bugs and deficiencies -=============================== - -Please report any flaws or feature requests in the `bug -tracker `__. - -For general discussion or queries email the libraries mailing list -libraries@haskell.org. There is also a development mailing list -cabal-devel@haskell.org. - Stability of Cabal interfaces ============================= diff --git a/doc/cabal-package.rst b/doc/cabal-package-description-file.rst similarity index 91% rename from doc/cabal-package.rst rename to doc/cabal-package-description-file.rst index 75ec9ff40ed..652746b216a 100644 --- a/doc/cabal-package.rst +++ b/doc/cabal-package-description-file.rst @@ -1,20 +1,17 @@ -Package Description -=================== +Package Description — .cabal File +========================================== -The Cabal package is the unit of distribution. When installed, its -purpose is to make available: +The package description file, commonly known as "the Cabal file", describes the +contents of a package. The Cabal package is the unit of distribution. When +installed, its purpose is to make available one or more: -- One or more Haskell programs (executables). +- Haskell programs (executables); and/or -- One or more libraries, exposing a number of Haskell modules. +- libraries, exposing a number of Haskell modules. -However having both a library and executables in a package does not work -very well; if the executables depend on the library, they must -explicitly list all the modules they directly or indirectly import from -that library. Fortunately, starting with Cabal 1.8.0.4, executables can -also declare the package that they are in as a dependency, and Cabal -will treat them as if they were in another package that depended on the -library. +Public library components can be depended upon by other Cabal packages and all +library components (both public and private) can be depended upon by other +components of the same package. Internally, the package may consist of much more than a bunch of Haskell modules: it may also have C source code and header files, source code @@ -203,7 +200,7 @@ builds packages for all the Haskell implementations. The simple build infrastructure can also handle packages where building is governed by system-dependent parameters, if you specify a little more (see the section on `system-dependent parameters`_). -A few packages require `more elaborate solutions `_. +A few packages require `more elaborate solutions <#more-complex-packages>`_. .. _pkg-desc: @@ -801,18 +798,65 @@ Library Build information for libraries. - A package can have one default library, which is identified by omitting the - ``name`` argument. + A package can include zero or more library components. A library can be + unnamed or named (using the ``name`` argument). It can also be depended upon + only by components in the same package (private) or by those components and + components in other packages (public). A package can have no more than one + unnamed library. - Starting with Cabal 2.0, sub-library components can be defined by setting - the ``name`` field to a name different from the current package's name; see - section on :ref:`Sublibraries ` for more information. By - default, these sub-libraries are private and internal. Since Cabal 3.0, - these sub-libraries can also be exposed and used by other packages. See the - :pkg-field:`library:visibility` field and :ref:`Multiple Public Libraries - ` for more information. + .. Note:: + + The 'cabal' executable provided by the 'cabal-install' package will not + accept dependencies on sublibraries of packages with no unnamed library. + + This guide refers to an unnamed library as the main library and a named + library as a sublibrary (such components may be considered as subidiary, or + ancillary, to the main library). It refers to a private sublibrary as an + internal library. + + A sublibrary cannot have the same name as its package. + + .. Note:: + + Before version 3.4 of the Cabal specification, a private sublibrary could + shadow a dependency on the main library of another package, if their + names clashed. + + A main library is always public and a sublibrary is private by default. + See the :pkg-field:`library:visibility` field for setting a sublibrary as + public. + + Being able to include more than one public library in a package allows the + separation of the unit of distribution (the package) from the unit of + buildable code (the library). This is useful for Haskell projects with many + libraries that are distributed together as it avoids duplication and + potential inconsistencies. + + .. Note:: + + Before version 3.0 of the Cabal specification, all sublibraries were + internal libraries. Before version 2.0, a package could not include + sublibraries. + + See :ref:`Sublibraries - Examples ` for examples. + +A library section should contain the following fields: + +.. pkg-field:: visibility: visibility specifiers + + :since: 3.0 + + :default: + ``private`` for sublibraries. Cannot be set for the main library, which + is always public. -The library section should contain the following fields: + Can be set to ``private`` or ``public``. A ``private`` library component can + only be depended on by other components of the same package. A ``public`` + component can be depended on by those components and by components of other + packages. + + See the :pkg-field:`build-depends` field for the syntax to specify a + dependency on a library component. .. pkg-field:: exposed-modules: identifier list @@ -847,23 +891,6 @@ The library section should contain the following fields: that use a flat module namespace or where it is known that the exposed modules would clash with other common modules. -.. pkg-field:: visibility: visibility specifiers - - :since: 3.0 - - :default: - ``private`` for sublibraries. Cannot be set for main - (unnamed) library, which is always public. - - Can be ``public`` or ``private``. - Makes it possible to have multiple public libraries in a single package. - If set to ``public``, depending on this library from another package is - allowed. If set to ``private``, depending on this library is allowed only - from the same package. - - See section on :ref:`Sublibraries ` for examples and more - information. - .. pkg-field:: reexported-modules: exportlist :since: 1.22 @@ -888,7 +915,7 @@ The library section should contain the following fields: Supported only in GHC 8.2 and later. A list of `module signatures `__ required by this package. - Module signatures are part of the Backpack_ extension to + Module signatures are part of the :ref:`Backpack` extension to the Haskell module system. Packages that do not export any modules and only export required signatures @@ -903,22 +930,21 @@ section on `build information`_). .. _sublibs: -**Sublibraries** +**Sublibraries - Examples** -Cabal 2.0 and later support "sublibraries", which are extra named -libraries (as opposed to the usual unnamed library section). For -example, suppose that your test suite needs access to some internal -modules in your library, which you do not otherwise want to export. You -could put these modules in a sublibrary, which the main library -and the test suite :pkg-field:`build-depends` upon. Then your Cabal file might -look something like this: +An example of the use of a private sublibrary (an internal library) is a test +suite that needs access to some internal modules in the package's main library, +which you do not otherwise want to expose. You could put those modules in an +internal library, which the main library and the test suite +:pkg-field:`build-depends` upon. Your Cabal file might then look something like +this: :: - cabal-version: 2.0 + cabal-version: 3.4 name: foo version: 0.1.0.0 - license: BSD3 + license: BSD-3-Clause license-file: LICENSE build-type: Simple @@ -931,7 +957,7 @@ look something like this: library exposed-modules: Foo.Public - build-depends: foo-internal, base >= 4.3 && < 5 + build-depends: foo:foo-internal, base >= 4.3 && < 5 default-language: Haskell2010 test-suite test-foo @@ -939,26 +965,19 @@ look something like this: main-is: test-foo.hs -- NOTE: no constraints on 'foo-internal' as same-package -- dependencies implicitly refer to the same package instance - build-depends: foo-internal, base + build-depends: foo:foo-internal, base default-language: Haskell2010 -Sublibraries are also useful for packages that define multiple -executables, but do not define a publicly accessible library. Internal -libraries are only visible internally in the package (so they can only -be added to the :pkg-field:`build-depends` of same-package libraries, -executables, test suites, etc.) Sublibraries locally shadow any -packages which have the same name; consequently, don't name an internal -library with the same name as an external dependency if you need to be -able to refer to the external dependency in a -:pkg-field:`build-depends` declaration. +Another example of the use of internal libraries is a package that includes one +or more executables but does not include a public library. -Shadowing can be used to vendor an external dependency into a package -and thus emulate *private dependencies*. Below is an example based on -a real-world use case: +Internal libraries can be used to incorporate (vendor or bundle) an external +dependency into a package, effectively simulating *private dependencies*. Below +is an example: :: - cabal-version: 3.0 + cabal-version: 3.4 name: haddock-library version: 1.6.0 license: BSD-3-Clause @@ -973,7 +992,7 @@ a real-world use case: hs-source-dirs: src -- internal sub-lib - build-depends: attoparsec + build-depends: haddock-library:attoparsec exposed-modules: Documentation.Haddock @@ -1001,25 +1020,6 @@ a real-world use case: default-language: Haskell2010 -.. note:: - For packages using ``cabal-version: 3.4`` or higher, the syntax to - specify a sublibrary in a ``build-depends:`` section is - ``package-name:internal-library-name``. - -.. _publicsublibs: - -**Multiple Public Libraries** - -Cabal 3.0 and later support exposing multiple libraries from a single package -through the field :pkg-field:`library:visibility`. -Having multiple public libraries is useful for separating the unit of -distribution (package) from the unit of buildable code (library). -For more information about the rationale and some examples, see -`this blog post `__. - -.. - TODO inline the blog post - Executables ^^^^^^^^^^^ @@ -1454,31 +1454,58 @@ system-dependent values for these fields. .. pkg-field:: build-depends: library list - Declares the *library* dependencies required to build the current - package component; see :pkg-field:`build-tool-depends` for - declaring build-time *tool* dependencies. External library - dependencies should be annotated with a version constraint. + Declares the dependencies on *library* components required to build the + current package component. See :pkg-field:`build-tool-depends` for declaring + dependencies on build-time *tools*. Dependencies on libraries from another + package should be annotated with a version constraint. **Library Names** - External libraries are identified by the package's name they're - provided by, optionally followed by a colon and the library name - (available from ``cabal-version: 3.0``). - If the library name is absent, the main (unnamed) library will be used. - To refer to the main (unnamed) library explicitly, use the name of the - package (``foo:foo``). - Multiple libraries from the same package can be specified with the shorthand - syntax ``pkg:{lib1,lib2}```. + A library is identified by the name of its package, optionally followed by a + colon and the library's name (for example, ``my-package:my-library``). If a + library name is omitted, the package's main library will be used. To refer + expressly to a package's main library, use the name of the package as the + library name (for example, ``my-package:my-package``). More than one library + from the same package can be specified with the shorthand syntax + ``my-package:{my-library1,my-library2}``. - See section on :ref:`Multiple Public Libraries ` for examples and more - information. + .. Note:: + + Before version 3.4 of the Cabal specification, from version 2.0, a + private sublibrary (an internal library) was identified by only the name + of the sublibrary. An internal library could shadow a dependency on the + main library of another package, if the names clashed. + + See the section on :pkg-section:`library` for information about how a + package can specify library components. **Version Constraints** Version constraints use the operators ``==, >=, >, <, <=`` and a version number. Multiple constraints can be combined using ``&&`` or - ``||``. If no version constraint is specified, any version is - assumed to be acceptable. For example: + ``||``. + + .. Note:: + + Even though there is no ``/=`` operator, by combining operators we can + skip over one or more versions, to skip a deprecated version or to skip + versions that narrow the constraint solving more than we'd like. + + For example, the ``time =1.12.*`` series depends on ``base >=4.13 && <5`` + but ``time-1.12.3`` bumps the lower bound on base to ``>=4.14``. If we + still want to compile with a ``ghc-8.8.*`` version of GHC that ships with + ``base-4.13`` and with later GHC versions, then we can use ``time >=1.12 + && (time <1.12.3 || time >1.12.3)``. + + Hackage shows deprecated and preferred versions for packages, such as for + `containers `_ + and `aeson `_ for + example. Deprecating package versions is not the same deprecating a + package as a whole, for which hackage keeps a `deprecated packages list + `_. + + If no version constraint is specified, any version is assumed to be + acceptable. For example: :: @@ -1703,7 +1730,8 @@ system-dependent values for these fields. The possible values are: - - ``GHC2021`` (only available for GHC version newer than ``9.2``) + - ``GHC2024`` (only available for GHC version ``9.10`` or later) + - ``GHC2021`` (only available for GHC version ``9.2`` or later) - ``Haskell2010`` - ``Haskell98`` @@ -2209,7 +2237,7 @@ system-dependent values for these fields. See the :pkg-field:`library:signatures` field for more details. - Mixin packages are part of the Backpack_ extension to the + Mixin packages are part of the :ref:`Backpack` extension to the Haskell module system. The matching of the module signatures required by a @@ -2222,7 +2250,7 @@ system-dependent values for these fields. .. Warning:: - Backpack_ has the limitation that implementation modules that instantiate + :ref:`Backpack` has the limitation that implementation modules that instantiate signatures required by a :pkg-field:`build-depends` dependency can't reside in the same component that has the dependency. They must reside in a different package dependency, or at least in a separate internal @@ -2403,6 +2431,8 @@ Configuration Flags negated value. However, if the flag is manual, then the default value (which can be overridden by commandline flags) will be used. +.. _conditional-blocks: + Conditional Blocks ^^^^^^^^^^^^^^^^^^ @@ -2461,10 +2491,15 @@ The following tests are currently supported. implementations. If the canonicalised os names match, this test evaluates to true, otherwise false. The match is case-insensitive. :samp:`arch({name})` - Tests if the current architecture is *name*. The argument is matched - against ``System.Info.arch`` on the target system. If the arch names - match, this test evaluates to true, otherwise false. The match is - case-insensitive. + Tests if the current architecture is *name*. *name* should be the name of + one of the nullary constructors of ``Distribution.System.Arch`` (e.g. + ``x86_64``, ``aarch64`` or ``i386``), otherwise it will be treated as an + 'other architecture' of the given *name*. It will be compared with + ``Distribution.System.buildArch``, which is derived from + ``System.Info.arch`` (certain architectures are treated as synonymous; e.g. + ``aarch64`` / ``arm64`` or ``powerpc64`` / ``powerpc64le`` are not + distinguished). For a match, this test evaluates to true, otherwise false. + The match is case-insensitive. :samp:`impl({compiler})` Tests for the configured Haskell implementation. An optional version constraint may be specified (for example ``impl(ghc >= 6.6.1)``). If @@ -2921,16 +2956,6 @@ Right now :pkg-field:`executable:main-is` modules are not supported on (e.g. by a ``configure`` script). Autogenerated header files are not packaged by ``sdist`` command. -Virtual modules ---------------- - -TBW - -.. pkg-field:: virtual-modules: module list - :since: 2.2 - - TBW - .. _accessing-data-files: @@ -3303,123 +3328,6 @@ a few options: library for all or part of the work. One option is to copy the source of ``Distribution.Simple``, and alter it for your needs. Good luck. -.. _Backpack: - -Backpack --------- - -Cabal and GHC jointly support Backpack, an extension to Haskell's module -system which makes it possible to parametrize a package over some -modules, which can be instantiated later arbitrarily by a user. This -means you can write a library to be agnostic over some data -representation, and then instantiate it several times with different -data representations. Like C++ templates, instantiated packages are -recompiled for each instantiation, which means you do not pay any -runtime cost for parametrizing packages in this way. Backpack modules -are somewhat experimental; while fully supported by cabal-install, they are currently -`not supported by Stack `__. - -A Backpack package is defined by use of the -:pkg-field:`library:signatures` field, or by (transitive) dependency on -a package that defines some requirements. To define a parametrized -package, define a signature file (file extension ``hsig``) that -specifies the signature of the module you want to parametrize over, and -add it to your Cabal file in the :pkg-field:`library:signatures` field. - -.. code-block:: haskell - :caption: .hsig - - signature Str where - - data Str - - concat :: [Str] -> Str - -.. code-block:: cabal - :caption: parametrized.cabal - - cabal-version: 2.2 - name: parametrized - - library - build-depends: base - signatures: Str - exposed-modules: MyModule - -You can define any number of regular modules (e.g., ``MyModule``) that -import signatures and use them as regular modules. - -If you are familiar with ML modules, you might now expect there to be -some way to apply the parametrized package with an implementation of -the ``Str`` module to get a concrete instantiation of the package. -Backpack operates slightly differently with a concept of *mix-in -linking*, where you provide an implementation of ``Str`` simply by -bringing another module into scope with the same name as the -requirement. For example, if you had a package ``str-impl`` that provided a -module named ``Str``, instantiating ``parametrized`` is as simple as -just depending on both ``str-impl`` and ``parametrized``: - -.. code-block:: cabal - :caption: combined.cabal - - cabal-version: 2.2 - name: combined - - library - build-depends: base, str-impl, parametrized - -Note that due to technical limitations, you cannot directly define -``Str`` in the ``combined`` library; it must be placed in its own -library (you can use :ref:`Sublibraries ` to conveniently -define a sub-library). - -However, a more common situation is that your names don't match up -exactly. The :pkg-field:`library:mixins` field can be used to rename -signatures and modules to line up names as necessary. If you have -a requirement ``Str`` and an implementation ``Data.Text``, you can -line up the names in one of two ways: - -* Rename the requirement to match the implementation: - ``mixins: parametrized requires (Str as Data.Text)`` -* Rename the implementation to match the requirement: - ``mixins: text (Data.Text as Str)`` - -The :pkg-field:`library:mixins` field can also be used to disambiguate -between multiple instantiations of the same package; for each -instantiation of the package, give it a separate entry in mixins with -the requirements and provided modules renamed to be distinct. - -.. code-block:: cabal - :caption: .cabal - - cabal-version: 2.2 - name: double-combined - - library - build-depends: base, text, bytestring, parametrized - mixins: - parametrized (MyModule as MyModule.Text) requires (Str as Data.Text), - parametrized (MyModule as MyModule.BS) requires (Str as Data.ByteString) - -Intensive use of Backpack sometimes involves creating lots of small -parametrized libraries; :ref:`Sublibraries ` can be used -to define all of these libraries in a single package without having to -create many separate Cabal packages. You may also find it useful to use -:pkg-field:`library:reexported-modules` to reexport instantiated -libraries to Backpack-unware users (e.g., Backpack can be used entirely -as an implementation detail.) - -Backpack imposes a limitation on Template Haskell that goes beyond the usual TH -stage restriction: it's not possible to splice TH code imported from a -compilation unit that is still "indefinite", that is, a unit for which some -module signatures still haven't been matched with implementations. The reason -is that indefinite units are typechecked, but not compiled, so there's no -actual TH code to run while splicing. Splicing TH code from a definite -compilation unit into an indefinite one works normally. - -For more information about Backpack, check out the -`GHC wiki page `__. - .. include:: references.inc .. rubric:: Footnotes diff --git a/doc/cabal-project.rst b/doc/cabal-project-description-file.rst similarity index 95% rename from doc/cabal-project.rst rename to doc/cabal-project-description-file.rst index f1e55475f6d..98a55859180 100644 --- a/doc/cabal-project.rst +++ b/doc/cabal-project-description-file.rst @@ -1,5 +1,5 @@ -cabal.project Reference -======================= +Project Description — cabal.project File +======================================== ``cabal.project`` files support a variety of options which configure the details of your build. The general syntax of a ``cabal.project`` file is @@ -40,13 +40,28 @@ directories when there is none in the current directory. Conditionals and imports ------------------------ -As of ``cabal-install`` version 3.8, cabal supports conditional logic -and imports in ``cabal.project`` files. :ref:`conditions` in cabal -may case on operating system, architecture, and -compiler (i.e. there is no support for a notion of custom flags in -project files). Imports may specify local filepaths or remote urls, -and may reference either cabal.project files or v1-style cabal.config -freeze files. As a usage example: +As of ``cabal-install`` version 3.8, cabal supports conditional logic and +imports in ``cabal.project`` files. + + .. warning:: + + While :ref:`conditional blocks` can appear anywhere + within component or common sections of a package, their placement within a + project is restricted. Conditions may only be introduced at the top level + of a project. + + Of the :ref:`condition tests`, only packages can test for + flags. Projects can test for operating system, architecture, compiler and + the boolean constants. + + - :samp:`os({name})` + - :samp:`arch({name})` + - :samp:`impl({compiler})` + - ``true`` + - ``false`` + +Imports may specify local filepaths or remote urls, and may reference either +cabal.project files or v1-style cabal.config freeze files. As a usage example: :: @@ -174,16 +189,16 @@ Formally, the format is described by the following BNF: .. code-block:: abnf - FilePathGlob ::= FilePathRoot FilePathGlobRel + RootedGlob ::= FilePathRoot Glob FilePathRoot ::= {- empty -} # relative to cabal.project | "/" # Unix root | [a-zA-Z] ":" [/\\] # Windows root | "~" # home directory - FilePathGlobRel ::= Glob "/" FilePathGlobRel # Unix directory - | Glob "\\" FilePathGlobRel # Windows directory - | Glob # file - | {- empty -} # trailing slash - Glob ::= GlobPiece * + Glob ::= GlobPieces [/\\] Glob # Unix or Windows directory + | "..[**/\\]" GlobPieces # Recursive directory glob + | GlobPieces # file + | [/\\] # trailing slash + GlobPieces ::= GlobPiece * GlobPiece ::= "*" # wildcard | [^*{},/\\] * # literal string | "\\" [*{},] # escaped reserved character @@ -193,9 +208,11 @@ Formally, the format is described by the following BNF: Specifying Packages from Remote Version Control Locations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Starting with Cabal 2.4, there is now a stanza -``source-repository-package`` for specifying packages from an external -version control. +Since version 2.4, the ``source-repository-package`` stanza allows for +specifying packages in a remote version control system that cabal should +consider during package retrieval. This allows use of a package from a +remote version control system, rather than looking for that package in +Hackage. .. code-block:: cabal @@ -218,8 +235,11 @@ version control. tag: e76fdc753e660dfa615af6c8b6a2ad9ddf6afe70 post-checkout-command: autoreconf -i -cabal-install 3.4 sdists the ``source-repository-package`` repositories and uses resulting tarballs as project packages. -This allows sharing of packages across different projects. +Since version 3.4, cabal-install creates tarballs for each package coming +from a ``source-repository-package`` stanza (effectively applying cabal +sdists to such packages). It gathers the names of the packages from the +appropriate .cabal file in the version control repository, and allows +their use just like Hackage or locally defined packages. .. cfg-field:: type: VCS kind @@ -229,7 +249,7 @@ This allows sharing of packages across different projects. .. cfg-field:: subdir: subdirectory list - Use one or more subdirectories of the repository. + Look in one or more subdirectories of the repository for cabal files, rather than the root. .. cfg-field:: post-checkout-command: command @@ -352,6 +372,11 @@ package, and thus apply globally: :synopsis: PackageDB stack manipulation :since: 3.7 + By modifying ``package-dbs`` you can modify the default package environment + which ``cabal`` will see. The package databases you add using ``package-dbs`` + will not be written into and only used as immutable package stores to initialise + the environment with additional packages that ``cabal`` can choose to use. + There are three package databases involved with most builds: global @@ -361,37 +386,42 @@ package, and thus apply globally: in-place Project-specific build directory - By default, the package stack you will have with v2 commands is: + By default, the initial package stack prefix you will have with v2 commands is: :: - -- [global, store] + -- prefix = [global] - So all remote packages required by your project will be - registered in the store package db (because it is last). + So the initial set of packages which is used by cabal is just the packages + installed in the global package database which comes with ``ghc``. - When cabal starts building your local projects, it appends the in-place db - to the end: + When cabal builds a package it will start populating the ``store`` package database, + whose packages will then be subsequently be available to be used in future runs. :: - -- [global, store, in-place] + -- prefix ++ [store] + + When cabal builds your local projects, packages are registered into the local + in-place package database. + + :: - So your local packages get put in ``dist-newstyle`` instead of the store. + -- prefix ++ [store, in-place] - This flag manipulates the default prefix: ``[global, store]`` and accepts + This flag manipulates the default prefix: ``[global]`` and accepts paths, the special value ``global`` referring to the global package db, and ``clear`` which removes all prior entries. For example, :: - -- [global, store, foo] + -- prefix = [global, foo] package-dbs: foo - -- [foo] + -- prefix = [foo] package-dbs: clear, foo - -- [bar, baz] + -- prefix = [bar, baz] package-dbs: clear, foo, clear, bar, baz The command line variant of this flag is ``--package-db=DB`` which can be diff --git a/doc/cabaldomain.py b/doc/cabaldomain.py index 19c37dea229..2d318f8508f 100644 --- a/doc/cabaldomain.py +++ b/doc/cabaldomain.py @@ -598,9 +598,9 @@ class CabalConfigFieldXRef(CabalFieldXRef): # class ConfigFieldIndex(Index): - name = 'projectindex' - localname = "Cabal reference" - shortname = "Reference" + name = 'syntax-quicklinks' + localname = "Cabal Syntax Quicklinks" + shortname = "Quicklinks" class Entry(object): def __init__(self, typ, name, doc, anchor, meta): diff --git a/doc/concepts-and-development.rst b/doc/concepts-and-development.rst deleted file mode 100644 index c0e8b481356..00000000000 --- a/doc/concepts-and-development.rst +++ /dev/null @@ -1,7 +0,0 @@ -Package Concepts and Development -================================ - -.. toctree:: - :maxdepth: 2 - - developing-packages diff --git a/doc/conf.py b/doc/conf.py index 51ab333f80e..dfe5a1b5324 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -25,7 +25,7 @@ templates_path = ['_templates'] source_suffix = '.rst' source_encoding = 'utf-8-sig' -master_doc = 'index' +root_doc = 'index' # extlinks -- see http://www.sphinx-doc.org/en/stable/ext/extlinks.html extlinks = { @@ -39,7 +39,7 @@ # General information about the project. project = u'Cabal' -copyright = u'2003-2023, Cabal Team' +copyright = u'2003-2024, Cabal Team' # N.B. version comes from ghc_config release = version # The full version, including alpha/beta/rc tags. @@ -102,8 +102,8 @@ # Output file base name for HTML help builder. htmlhelp_basename = 'CabalUsersGuide' -# MathJax to use SVG rendering by default -mathjax_path = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS-MML_SVG' +# MathJax to use HTML rendering by default (makes the text selectable, see #8453) +mathjax_path = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS_CHTML' # -- Options for LaTeX output --------------------------------------------- diff --git a/doc/config.rst b/doc/config.rst index d7717ca95a8..5c85498b181 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -120,6 +120,9 @@ file: * ``~/.local/bin`` for executables installed with ``cabal install``. +You can run ``cabal path`` to see a list of the directories that +``cabal`` will use with the active configuration. + Repository specification ------------------------ diff --git a/doc/external-commands.rst b/doc/external-commands.rst new file mode 100644 index 00000000000..e72495aa160 --- /dev/null +++ b/doc/external-commands.rst @@ -0,0 +1,22 @@ +External Commands +================= + +``cabal-install`` provides a system for external commands, akin to the ones used by tools like ``git`` or ``cargo``. + +If you execute ``cabal ``, ``cabal-install`` will search the path for an executable named ``cabal-`` and execute it. The name of the command is passed as the first argument and +the remaining arguments are passed afterwards. An error will be thrown in case the custom command is not found. + +The ``$CABAL`` environment variable is set to the path of the ``cabal-install`` executable +which invoked the subcommand. + +It is strongly recommended that you implement your custom commands by calling the +CLI via the ``$CABAL`` variable rather than linking against the ``Cabal`` library. +There is no guarantee that the subcommand will link against the same version of the +``Cabal`` library as ``cabal-install`` so it would lead to unexpected results and +incompatibilities. + +``cabal-install`` can also display the help message of the external command. +When ``cabal help `` is invoked, then ``cabal- --help`` will be called so +your external command can display a help message. + +For ideas or existing external commands, visit `this Discourse thread `_. diff --git a/doc/getting-started.rst b/doc/getting-started.rst index 4d5ebfe810f..056c4a85ebd 100644 --- a/doc/getting-started.rst +++ b/doc/getting-started.rst @@ -4,16 +4,16 @@ Getting Started Installing Cabal ---------------- -The easiest and recommended way to install the ``cabal`` command-line tool -on Linux, macOS, FreeBSD or Windows is through `ghcup `__. +The easiest and recommended way to install the ``cabal`` command-line tool +on Linux, macOS, FreeBSD or Windows is through `ghcup `__. It installs the “Haskell toolchain”, which includes Cabal, -the Haskell compiler `GHC `__ +the Haskell compiler `GHC `__ and optionally other useful Haskell tools. Creating a new application -------------------------- -We create a minimal Haskell application to get a quick overview +We create a minimal Haskell application to get a quick overview of the ``cabal`` command-line tool: 1. How to initialize a Haskell package. @@ -59,9 +59,9 @@ The ``myapp.cabal`` file is a package description file, commonly referred to as default-language: Haskell2010 It contains metadata (package name and version, author name, license, etc.) and sections -to define package components. Components can be used to split large codebases into smaller, +to define package components. Components can be used to split large codebases into smaller, more managable building blocks. -A component can be of one of several types (executable, library, etc.) and describes, +A component can be of one of several types (executable, library, etc.) and describes, among other things, the location of source files and its dependencies. The ``myapp.cabal`` file above defines a single component named ``myapp`` of the executable type. Inside the ``executable`` section, the ``build-depends`` field lists the dependencies of this component. @@ -77,7 +77,7 @@ The ``app/Main.hs`` file is where your executable's code lives: main = putStrLn "Hello, Haskell!" -To run the executable, switch into the application directory with ``cd myapp`` and run +To run the executable, switch into the application directory with ``cd myapp`` and run .. code-block:: console @@ -86,7 +86,7 @@ To run the executable, switch into the application directory with ``cd myapp`` a Hello, Haskell! This command automatically determines if the executable needs to be (re)built -before running the executable. With only one executable component in the package, +before running the executable. With only one executable component in the package, ``cabal run`` (without a component name) is smart enough to infer it, so the name can be omitted. If you just want to build the executable without running it, run: @@ -181,11 +181,11 @@ Now you can build and re-run your code to see the new output: Running a single-file Haskell script ------------------------------------ -Cabal also supports running single-file Haskell scripts like +Cabal also supports running single-file Haskell scripts like the following file named ``myscript``: .. code-block:: haskell - + #!/usr/bin/env cabal {- cabal: build-depends: @@ -228,4 +228,4 @@ What Next? Now that you know how to set up a simple Haskell package using Cabal, check out some of the resources on the Haskell website's `documentation page `__ or read more about packages and -Cabal on the :doc:`introduction ` page. +Cabal on the :doc:`What Cabal does ` page. diff --git a/doc/nix-local-build-overview.rst b/doc/how-to-build-like-nix.rst similarity index 97% rename from doc/nix-local-build-overview.rst rename to doc/how-to-build-like-nix.rst index 61e59b84d76..0714b4b02f1 100644 --- a/doc/nix-local-build-overview.rst +++ b/doc/how-to-build-like-nix.rst @@ -1,7 +1,7 @@ .. _nix-style-builds: -Nix-style Local Builds -====================== +How to build locally like in Nix +================================ Nix-style local builds are a new build system implementation inspired by Nix. The Nix-style local build system is commonly called "v2-build" for short diff --git a/doc/how-to-package-haskell-code.rst b/doc/how-to-package-haskell-code.rst new file mode 100644 index 00000000000..bd68681654b --- /dev/null +++ b/doc/how-to-package-haskell-code.rst @@ -0,0 +1,291 @@ +How to package Haskell code +=========================== + +.. TIP:: + If this is your first time using `cabal` you should check out the :doc:`Getting Started guide `. + +Starting from scratch, we're going to walk you through creating a simple +Haskell application. + +**TL;DR;** ``mkdir proglet && cd proglet && cabal init --simple --exe && cabal run proglet`` + + +Introduction +------------ + +Every application needs a name, we'll call ours "proglet" and start by +creating an empty directory. + +.. highlight:: console + +:: + + $ mkdir proglet + $ cd proglet/ + + +.. _init quickstart: + +Using ``cabal init`` +-------------------- + +The ``cabal init`` command creates the necessary files for a Cabal package, +it has both an ``--interactive`` (default) and ``--non-interactive`` +mode. The interactive mode will walk you through many of the package +options and metadata, the non-interactive mode will simply pick reasonable +defaults which is sufficient if you're just trying something out. + +.. highlight:: console + +:: + + $ cabal init --non-interactive + # You can also use -n which is the short version of --non-interactive + +If you want, you can also try out the interactive mode, for now chose +"Executable" when asked what type of package you want to build. + +.. highlight:: console + +:: + + $ cabal init + ... + What does the package build: + 1) Executable + 2) Library + 3) Library and Executable + 4) Test suite + Your choice? + +One of the important questions is whether the package contains a library +and/or an executable. Libraries are collections of Haskell modules that +can be re-used by other Haskell libraries and programs, while executables +are standalone programs. Test suites can both depend on a library or be +standalone. + +For the moment these are the only choices. For more complex packages +(e.g. a library and multiple executables) the ``.cabal`` +file can be edited afterwards. + +After you make your selection (executable; library; library +and executable; or: test suite) cabal asks us a number of questions starting with +which version of the cabal specification to use, our package's name +(for example, "proglet"), and our package's version. + +:: + + Generating CHANGELOG.md... + Generating Main.hs... + Generating proglet.cabal... + +Use the ``ls`` command to see the created files: + +:: + + $ ls + CHANGELOG.md Main.hs proglet.cabal + + +Running the program +------------------- + +Now that we have our Haskell code and the extra files that Cabal needs, we +can build and run our application. + +:: + + $ cabal build + Resolving dependencies... + ... + Linking /path/to/proglet ... + + $ cabal run proglet + ... + Hello, Haskell! + +Since we have an executable we can use ``cabal run proglet`` which will build +our executable (and re-build it if we've made any changes) and then run the +binary. The ``cabal run`` command works for any ``component-name`` (tests for +example), not just the main executable. + + +About the Cabal package structure +--------------------------------- + +It is assumed that all the files that make up a package live under a common +root directory (apart from external dependencies). This simple example has +all the package files in one directory, but most packages use one or more +subdirectories. + +Cabal needs one extra file in the package's root directory: + +- ``proglet.cabal``: contains package metadata and build information. + + +Editing the .cabal file +----------------------- + +.. highlight:: cabal + +Load up the ``.cabal`` file in a text editor. The first part of the +``.cabal`` file has the package metadata and towards the end of the file +you will find the :pkg-section:`executable` or :pkg-section:`library` +section. + +You will see that the fields that have yet to be filled in are commented +out. Cabal files use "``--``" Haskell-style comment syntax. + +.. NOTE:: + Comments are only allowed on lines on their own. Trailing comments on + other lines are not allowed because they could be confused with program + options. + + +:: + + executable proglet + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: base >=4.11 && <4.12 + -- hs-source-dirs: + default-language: Haskell2010 + + +If you selected earlier to create a library package then your ``.cabal`` +file will have a section that looks like this: + +:: + + library + exposed-modules: MyLib + -- other-modules: + -- build-depends: + build-depends: base >=4.11 && <4.12 + -- hs-source-dirs: + default-language: Haskell2010 + + +The build information fields listed (but commented out) are just the few +most important and common fields. There are many others that are covered +later in this chapter. + +Most of the build information fields are the same between libraries and +executables. The difference is that libraries have a number of "exposed" +modules that make up the public interface of the library, while +executables have a file containing a ``Main`` module. + +The name of a library always matches the name of the package, so it is +not specified in the library section. Executables often follow the name +of the package too, but this is not required and the name is given +explicitly. + + +Modules included in the package +------------------------------- + +For an executable, ``cabal init`` creates the ``Main.hs`` file which +contains your program's ``Main`` module. It will also fill in the +:pkg-field:`executable:main-is` field with the file name of your program's +``Main`` module, including the ``.hs`` (or ``.lhs``) extension. Other +modules included in the executable should be listed in the +:pkg-field:`other-modules` field. + +For a library, ``cabal init`` looks in the project directory for files +that look like Haskell modules and adds all the modules to the +:pkg-field:`library:exposed-modules` field. For modules that do not form part +of your package's public interface, you can move those modules to the +:pkg-field:`other-modules` field. Either way, all modules in the library need +to be listed. + + +Modules imported from other packages +------------------------------------ + +While your library or executable may include a number of modules, it +almost certainly also imports a number of external modules from the +standard libraries or other pre-packaged libraries. (These other +libraries are of course just Cabal packages that contain one or more libraries.) + +You have to list all of the library packages that your library or +executable imports modules from. Or to put it another way: you have to +list all the other packages that your package depends on. + +For example, suppose the example ``Proglet`` module imports the module +``Data.Map``. The ``Data.Map`` module comes from the ``containers`` +package, so we must list it: + +:: + + library + exposed-modules: Proglet + other-modules: + build-depends: containers, base >=4.11 && <4.12 + +In addition, almost every package also depends on the ``base`` library +package because it exports the standard ``Prelude`` module plus other +basic modules like ``Data.List``. + +You will notice that we have listed ``base >=4.11 && <4.12``. This gives a +constraint on the version of the base package that our package will work +with. The most common kinds of constraints are: + +- ``pkgname >=n`` +- ``pkgname ^>=n`` +- ``pkgname >=n && =4 && <5``. Please refer to the documentation +on the :pkg-field:`build-depends` field for more information. + +Also, you can factor out shared ``build-depends`` (and other fields such +as ``ghc-options``) into a ``common`` stanza which you can ``import`` in +your libraries and executable sections. For example: + +:: + + common shared-properties + default-language: Haskell2010 + build-depends: + base == 4.* + ghc-options: + -Wall + + library + import: shared-properties + exposed-modules: + Proglet + +Note that the ``import`` **must** be the first thing in the stanza. For more +information see the :ref:`common-stanzas` section. + +.. _building-packages: + +Building the package +-------------------- + +For simple packages that's it! We can now try building the package, +which also downloads and builds all required dependencies: + +.. code-block:: console + + $ cabal build + +If the package contains an executable, you can run it with: + +.. code-block:: console + + $ cabal run + +and the executable can also be installed for convenience: + +.. code-block:: console + + $ cabal install + +When installed, the executable program lands in a special directory +for binaries that may or may not already be on your system's ``PATH``. +If it is, the executable can be run by typing its filename on commandline. +For installing libraries see the :ref:`adding-libraries` section. diff --git a/doc/how-to-report-bugs.rst b/doc/how-to-report-bugs.rst new file mode 100644 index 00000000000..20910cdf1a3 --- /dev/null +++ b/doc/how-to-report-bugs.rst @@ -0,0 +1,9 @@ +How to report Cabal bugs and feature requests +============================================= + +Please report any flaws or feature requests in the `bug +tracker `__. + +For general discussion or queries email the libraries mailing list +libraries@haskell.org. There is also a development mailing list +cabal-devel@haskell.org. diff --git a/doc/how-to-use-backpack.rst b/doc/how-to-use-backpack.rst new file mode 100644 index 00000000000..23d58298b2d --- /dev/null +++ b/doc/how-to-use-backpack.rst @@ -0,0 +1,117 @@ +.. _Backpack: + +How to use Backpack modules +=========================== + +Cabal and GHC jointly support Backpack, an extension to Haskell's module +system which makes it possible to parametrize a package over some +modules, which can be instantiated later arbitrarily by a user. This +means you can write a library to be agnostic over some data +representation, and then instantiate it several times with different +data representations. Like C++ templates, instantiated packages are +recompiled for each instantiation, which means you do not pay any +runtime cost for parametrizing packages in this way. Backpack modules +are somewhat experimental; while fully supported by cabal-install, they are currently +`not supported by Stack `__. + +A Backpack package is defined by use of the +:pkg-field:`library:signatures` field, or by (transitive) dependency on +a package that defines some requirements. To define a parametrized +package, define a signature file (file extension ``hsig``) that +specifies the signature of the module you want to parametrize over, and +add it to your Cabal file in the :pkg-field:`library:signatures` field. + +.. code-block:: haskell + :caption: .hsig + + signature Str where + + data Str + + concat :: [Str] -> Str + +.. code-block:: cabal + :caption: parametrized.cabal + + cabal-version: 2.2 + name: parametrized + + library + build-depends: base + signatures: Str + exposed-modules: MyModule + +You can define any number of regular modules (e.g., ``MyModule``) that +import signatures and use them as regular modules. + +If you are familiar with ML modules, you might now expect there to be +some way to apply the parametrized package with an implementation of +the ``Str`` module to get a concrete instantiation of the package. +Backpack operates slightly differently with a concept of *mix-in +linking*, where you provide an implementation of ``Str`` simply by +bringing another module into scope with the same name as the +requirement. For example, if you had a package ``str-impl`` that provided a +module named ``Str``, instantiating ``parametrized`` is as simple as +just depending on both ``str-impl`` and ``parametrized``: + +.. code-block:: cabal + :caption: combined.cabal + + cabal-version: 2.2 + name: combined + + library + build-depends: base, str-impl, parametrized + +Note that due to technical limitations, you cannot directly define +``Str`` in the ``combined`` library; it must be placed in its own +library (you can use :ref:`Sublibraries ` to conveniently +define a sub-library). + +However, a more common situation is that your names don't match up +exactly. The :pkg-field:`library:mixins` field can be used to rename +signatures and modules to line up names as necessary. If you have +a requirement ``Str`` and an implementation ``Data.Text``, you can +line up the names in one of two ways: + +* Rename the requirement to match the implementation: + ``mixins: parametrized requires (Str as Data.Text)`` +* Rename the implementation to match the requirement: + ``mixins: text (Data.Text as Str)`` + +The :pkg-field:`library:mixins` field can also be used to disambiguate +between multiple instantiations of the same package; for each +instantiation of the package, give it a separate entry in mixins with +the requirements and provided modules renamed to be distinct. + +.. code-block:: cabal + :caption: .cabal + + cabal-version: 2.2 + name: double-combined + + library + build-depends: base, text, bytestring, parametrized + mixins: + parametrized (MyModule as MyModule.Text) requires (Str as Data.Text), + parametrized (MyModule as MyModule.BS) requires (Str as Data.ByteString) + +Intensive use of Backpack sometimes involves creating lots of small +parametrized libraries; :ref:`Sublibraries ` can be used +to define all of these libraries in a single package without having to +create many separate Cabal packages. You may also find it useful to use +:pkg-field:`library:reexported-modules` to reexport instantiated +libraries to Backpack-unware users (e.g., Backpack can be used entirely +as an implementation detail.) + +Backpack imposes a limitation on Template Haskell that goes beyond the usual TH +stage restriction: it's not possible to splice TH code imported from a +compilation unit that is still "indefinite", that is, a unit for which some +module signatures still haven't been matched with implementations. The reason +is that indefinite units are typechecked, but not compiled, so there's no +actual TH code to run while splicing. Splicing TH code from a definite +compilation unit into an indefinite one works normally. + +For more information about Backpack, check out the +`GHC wiki page `__. + diff --git a/doc/index.rst b/doc/index.rst index b97dd245346..69109a67685 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,20 +1,41 @@ - Welcome to the Cabal User Guide =============================== .. toctree:: - :maxdepth: 2 + :caption: Getting Started :numbered: + :maxdepth: 2 getting-started - intro - concepts-and-development - nix-local-build-overview + +.. toctree:: + :caption: Cabal Guide + :numbered: + :maxdepth: 2 + + how-to-package-haskell-code + how-to-build-like-nix + how-to-use-backpack + how-to-report-bugs + +.. toctree:: + :caption: Cabal Reference + :numbered: + :maxdepth: 2 + + cabal-package-description-file + cabal-project-description-file cabal-config-and-commands - cabal-package - cabal-project + external-commands setup-commands file-format-changelog buildinfo-fields-reference - bugs-and-stability - nix-integration + +.. toctree:: + :caption: Cabal Explanation + :numbered: + :maxdepth: 2 + + cabal-context + package-concepts + cabal-interface-stability diff --git a/doc/internal/multi-repl.md b/doc/internal/multi-repl.md index 5f0f731e393..1e89872886a 100644 --- a/doc/internal/multi-repl.md +++ b/doc/internal/multi-repl.md @@ -33,11 +33,12 @@ Here are some common targets which you can specify when using `cabal`. * `all`: Build all the locally defined components. * `exe:haskell-language-server`: Build the executable called `haskell-language-server` -* `lib:pkg-a lib:pkg-b`: Build the local libraries pkg-a and pkg-b. +* `lib:pkg-a lib:pkg-b`: Build the local libraries pkg-a and pkg-b. pkg-a will be the active unit. * `src/Main.hs`: Build the unit which `src/Main.hs` belongs to. After enabling multi-repl, passing a target specification to `cabal repl` which resolves to multiple units will load all those units into a single repl session. +The first "target" will be the active unit. For example: ``` @@ -203,6 +204,14 @@ At this time, the multi-repl is best used for interactive development situations you want to use the repl to obtain fast-feedback about your project. We have made sure that the multi-repl works with `ghcid` for example. +When evaluating code, make sure that the code is in the scope of the active unit, +which is the first target given on the command line. For example, to run the test suite +entrypoint, use: + +``` +ghcid --command "cabal repl --enable-multi-repl test:suite lib:pkg" --test Main.main +``` + # Conclusion Adding `cabal repl` support for multiple home units allows developers to easily diff --git a/doc/nix-integration.rst b/doc/nix-integration.rst deleted file mode 100644 index 5d4fa695cd4..00000000000 --- a/doc/nix-integration.rst +++ /dev/null @@ -1,64 +0,0 @@ -Nix Integration -=============== - -.. warning:: - - Nix integration has been deprecated and will be removed in a future release. - - The original mechanism can still be easily replicated with the following commands: - - - for a ``shell.nix``: ``nix-shell --run "cabal ..."`` - - for a ``flake.nix``: ``nix develop -c cabal ...`` - -.. note:: - - This functionality doesn't work with nix-style builds. - Nix-style builds are not related to Nix integration. - -`Nix `_ is a package manager popular with some Haskell developers due to its focus on reliability and reproducibility. ``cabal`` now has the ability to integrate with Nix for dependency management during local package development. - -Enabling Nix Integration ------------------------- - -To enable Nix integration, simply pass the ``--enable-nix`` global option when you call ``cabal`` (eg. ``cabal --enable-nix v1-build``). -To use this option everywhere, edit your :ref:`global configuration file` (default: ``~/.config/cabal/config``) to include: - -.. code-block:: cabal - - nix: True - -If the package (which must be locally unpacked) provides a ``shell.nix`` or ``default.nix`` file, this flag will cause ``cabal`` to run most commands through ``nix-shell``. If both expressions are present, ``shell.nix`` is preferred. The following commands are affected: - -- ``cabal v1-configure`` -- ``cabal v1-build`` -- ``cabal v1-repl`` -- ``cabal v1-install`` (only if installing into a sandbox) -- ``cabal v1-haddock`` -- ``cabal v1-freeze`` -- ``cabal v1-gen-bounds`` -- ``cabal v1-run`` - -If the package does not provide a Nix expression, ``cabal`` runs normally. - -Creating Nix Expressions ------------------------- - -The Nix package manager is based on a lazy, pure, functional programming language; packages are defined by expressions in this language. The fastest way to create a Nix expression for a Cabal package is with the `cabal2nix `_ tool. To create a ``shell.nix`` expression for the package in the current directory, run this command: - -.. code-block:: console - - $ cabal2nix --shell ./. >shell.nix - -Nix Expression Evaluation -------------------------- - -(This section describes for advanced users how Nix expressions are evaluated.) - -First, the Nix expression (``shell.nix`` or ``default.nix``) is instantiated with ``nix-instantiate``. The ``--add-root`` and ``--indirect`` options are used to create an indirect root in the Cabal build directory, preventing Nix from garbage collecting the derivation while in use. The ``IN_NIX_SHELL`` environment variable is set so that ``builtins.getEnv`` works as it would in ``nix-shell``. - -Next, the commands above are run through ``nix-shell`` using the instantiated derivation. Again, ``--add-root`` and ``--indirect`` are used to prevent Nix from garbage collecting the packages in the environment. The child ``cabal`` process reads the ``CABAL_IN_NIX_SHELL`` environment variable to prevent it from spawning additional child shells. - -Further Reading ----------------- - -The `Nix manual `_ provides further instructions for writing Nix expressions. The `Nixpkgs manual `_ describes the infrastructure provided for Haskell packages. diff --git a/doc/nix-local-build.rst b/doc/nix-local-build.rst index c086f642d24..7a47dacc923 100644 --- a/doc/nix-local-build.rst +++ b/doc/nix-local-build.rst @@ -5,7 +5,7 @@ Quickstart Suppose that you are in a directory containing a single Cabal package which you wish to build (if you haven't set up a package yet check -out :doc:`developing packages ` for +out :doc:`How to package Haskell code ` for instructions). You can configure and build it using Nix-style local builds with this command (configuring is not necessary): diff --git a/doc/developing-packages.rst b/doc/package-concepts.rst similarity index 56% rename from doc/developing-packages.rst rename to doc/package-concepts.rst index 28f2c7847df..25cfeb13fba 100644 --- a/doc/developing-packages.rst +++ b/doc/package-concepts.rst @@ -1,308 +1,3 @@ -Quickstart -========== - -.. TIP:: - If this is your first time using `cabal` you should check out the :doc:`Getting Started guide `. - -Starting from scratch, we're going to walk you through creating a simple -Haskell application. - -**TL;DR;** ``mkdir proglet && cd proglet && cabal init --simple --exe && cabal run proglet`` - - -Introduction ------------- - -Every application needs a name, we'll call ours "proglet" and start by -creating an empty directory. - -.. highlight:: console - -:: - - $ mkdir proglet - $ cd proglet/ - - -.. _init quickstart: - -Using ``cabal init`` --------------------- - -The ``cabal init`` command creates the necessary files for a Cabal package, -it has both an ``--interactive`` (default) and ``--non-interactive`` -mode. The interactive mode will walk you through many of the package -options and metadata, the non-interactive mode will simply pick reasonable -defaults which is sufficient if you're just trying something out. - -.. highlight:: console - -:: - - $ cabal init --non-interactive - # You can also use -n which is the short version of --non-interactive - -If you want, you can also try out the interactive mode, for now chose -"Executable" when asked what type of package you want to build. - -.. highlight:: console - -:: - - $ cabal init - ... - What does the package build: - 1) Executable - 2) Library - 3) Library and Executable - 4) Test suite - Your choice? - -One of the important questions is whether the package contains a library -and/or an executable. Libraries are collections of Haskell modules that -can be re-used by other Haskell libraries and programs, while executables -are standalone programs. Test suites can both depend on a library or be -standalonely generated. - -For the moment these are the only choices. For more complex packages -(e.g. a library and multiple executables) the ``.cabal`` -file can be edited afterwards. - -After you make your selection (executable; library; library -and executable; or: test suite) cabal asks us a number of questions starting with -which version of the cabal specification to use, our package's name -(for example, "proglet"), and our package's version. - -:: - - Generating CHANGELOG.md... - Generating Main.hs... - Generating proglet.cabal... - -Use the ``ls`` command to see the created files: - -:: - - $ ls - CHANGELOG.md Main.hs proglet.cabal - - -Running the program -------------------- - -Now that we have our Haskell code and the extra files that Cabal needs we -can build and run our application. - -:: - - $ cabal build - Resolving dependencies... - ... - Linking /path/to/proglet ... - - $ cabal run proglet - ... - Hello, Haskell! - -Since we have an executable we can use ``cabal run proglet`` which will build -our executable (and re-build it if we've made any changes) and then run the -binary. The ``cabal run`` command works for any ``component-name`` (tests for -example), not just the main executable. - - -About the Cabal package structure ---------------------------------- - -It is assumed that all the files that make up a package live under a common -root directory (apart from external dependencies). This simple example has -all the package files in one directory, but most packages use one or more -subdirectories. - -Cabal needs one extra file in the package's root directory: - -- ``proglet.cabal``: contains package metadata and build information. - - -Editing the .cabal file ------------------------ - -.. highlight:: cabal - -Load up the ``.cabal`` file in a text editor. The first part of the -``.cabal`` file has the package metadata and towards the end of the file -you will find the :pkg-section:`executable` or :pkg-section:`library` -section. - -You will see that the fields that have yet to be filled in are commented -out. Cabal files use "``--``" Haskell-style comment syntax. - -.. NOTE:: - Comments are only allowed on lines on their own. Trailing comments on - other lines are not allowed because they could be confused with program - options. - - -:: - - executable proglet - main-is: Main.hs - -- other-modules: - -- other-extensions: - build-depends: base >=4.11 && <4.12 - -- hs-source-dirs: - default-language: Haskell2010 - - -If you selected earlier to create a library package then your ``.cabal`` -file will have a section that looks like this: - -:: - - library - exposed-modules: MyLib - -- other-modules: - -- build-depends: - build-depends: base >=4.11 && <4.12 - -- hs-source-dirs: - default-language: Haskell2010 - - -The build information fields listed (but commented out) are just the few -most important and common fields. There are many others that are covered -later in this chapter. - -Most of the build information fields are the same between libraries and -executables. The difference is that libraries have a number of "exposed" -modules that make up the public interface of the library, while -executables have a file containing a ``Main`` module. - -The name of a library always matches the name of the package, so it is -not specified in the library section. Executables often follow the name -of the package too, but this is not required and the name is given -explicitly. - - -Modules included in the package -------------------------------- - -For an executable, ``cabal init`` creates the ``Main.hs`` file which -contains your program's ``Main`` module. It will also fill in the -:pkg-field:`executable:main-is` field with the file name of your program's -``Main`` module, including the ``.hs`` (or ``.lhs``) extension. Other -modules included in the executable should be listed in the -:pkg-field:`other-modules` field. - -For a library, ``cabal init`` looks in the project directory for files -that look like Haskell modules and adds all the modules to the -:pkg-field:`library:exposed-modules` field. For modules that do not form part -of your package's public interface, you can move those modules to the -:pkg-field:`other-modules` field. Either way, all modules in the library need -to be listed. - - -Modules imported from other packages ------------------------------------- - -While your library or executable may include a number of modules, it -almost certainly also imports a number of external modules from the -standard libraries or other pre-packaged libraries. (These other -libraries are of course just Cabal packages that contain a library.) - -You have to list all of the library packages that your library or -executable imports modules from. Or to put it another way: you have to -list all the other packages that your package depends on. - -For example, suppose the example ``Proglet`` module imports the module -``Data.Map``. The ``Data.Map`` module comes from the ``containers`` -package, so we must list it: - -:: - - library - exposed-modules: Proglet - other-modules: - build-depends: containers, base >=4.11 && <4.12 - -In addition, almost every package also depends on the ``base`` library -package because it exports the standard ``Prelude`` module plus other -basic modules like ``Data.List``. - -You will notice that we have listed ``base >=4.11 && <4.12``. This gives a -constraint on the version of the base package that our package will work -with. The most common kinds of constraints are: - -- ``pkgname >=n`` -- ``pkgname ^>=n`` (since Cabal 2.0) -- ``pkgname >=n && =4 && <5``. Please refer to the documentation -on the :pkg-field:`build-depends` field for more information. - -Also, you can factor out shared ``build-depends`` (and other fields such -as ``ghc-options``) into a ``common`` stanza which you can ``import`` in -your libraries and executable sections. For example: - -:: - - common shared-properties - default-language: Haskell2010 - build-depends: - base == 4.* - ghc-options: - -Wall - - library - import: shared-properties - exposed-modules: - Proglet - -Note that the ``import`` **must** be the first thing in the stanza. For more -information see the :ref:`common-stanzas` section. - -.. _building-packages: - -Building the package --------------------- - -For simple packages that's it! We can now try building the package, -which also downloads and builds all required dependencies: - -.. code-block:: console - - $ cabal build - -If the package contains an executable, you can run it with: - -.. code-block:: console - - $ cabal run - -and the executable can also be installed for convenience: - -.. code-block:: console - - $ cabal install - -When installed, the executable program lands in a special directory -for binaries that may or may not already be on your system's ``PATH``. -If it is, the executable can be run by typing its filename on commandline. -For installing libraries see the :ref:`adding-libraries` section. - -Next steps ----------- - -What we have covered so far should be enough for very simple packages -that you use on your own system. - -The next few sections cover more details needed for more complex -packages and details needed for distributing packages to other people. - -The previous chapter covers building and installing packages -- your own -packages or ones developed by other people. - - Package concepts ================ diff --git a/doc/requirements.in b/doc/requirements.in index d8de16ca602..c8a3a7692a2 100644 --- a/doc/requirements.in +++ b/doc/requirements.in @@ -8,3 +8,5 @@ Pygments >= 2.7.4 certifi >= 2023.07.22 # CVE-2023-45803 urllib3 >= 2.0.7 +# CVE-2024-22195 +jinja2 == 3.1.3 diff --git a/doc/requirements.txt b/doc/requirements.txt index 55019a68dc9..8ec8934d93e 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -23,8 +23,10 @@ idna==3.4 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.1.2 - # via sphinx +jinja2==3.1.3 + # via + # -r requirements.in + # sphinx jsonpointer==2.3 # via sphinx-jsonschema markupsafe==2.1.2 diff --git a/doc/setup-commands.rst b/doc/setup-commands.rst index 28cd9e988be..20bdafabfae 100644 --- a/doc/setup-commands.rst +++ b/doc/setup-commands.rst @@ -710,6 +710,14 @@ Miscellaneous options each module, whether top level or local. In GHC specifically, this is for non-inline toplevel or where-bound functions or values. + late-toplevel + Like top-level but costs will be assigned to top level definitions after + optimization. This lowers profiling overhead massively while giving similar + levels of detail as toplevle-functions. However it means functions introduced + by GHC during optimization will show up in profiles as well. + Corresponds to ``-fprof-late`` if supported and ``-fprof-auto-top`` otherwise. + late + Currently an alias for late-toplevel This flag is new in Cabal-1.24. Prior versions used the equivalent of ``none`` above. diff --git a/editors/vim/syntax/cabal.vim b/editors/vim/syntax/cabal.vim index 1a69bd77369..2e6361ba9cc 100644 --- a/editors/vim/syntax/cabal.vim +++ b/editors/vim/syntax/cabal.vim @@ -39,6 +39,7 @@ syn keyword cabalLanguage contained \ Haskell98 \ Haskell2010 \ GHC2021 + \ GHC2024 " To update this in Cabal, `cabal repl Cabal` and: " >>> :m *Distribution.PackageDescription.FieldGrammar @@ -209,6 +210,7 @@ syn keyword cabalExtension contained \ LexicalNegation \ LiberalTypeSynonyms \ LinearTypes + \ ListTuplePuns \ RequiredTypeArguments \ MagicHash \ MonadComprehensions @@ -268,6 +270,7 @@ syn keyword cabalExtension contained \ TraditionalRecordSyntax \ TransformListComp \ TupleSections + \ TypeAbstractions \ TypeApplications \ TypeData \ TypeFamilies @@ -408,6 +411,7 @@ syn keyword cabalExtension contained \ NoTraditionalRecordSyntax \ NoTransformListComp \ NoTupleSections + \ NoTypeAbstractions \ NoTypeApplications \ NoTypeData \ NoTypeFamilies diff --git a/fix-whitespace.yaml b/fix-whitespace.yaml index d96e84188b1..d5eb572ec62 100644 --- a/fix-whitespace.yaml +++ b/fix-whitespace.yaml @@ -40,6 +40,7 @@ included-files: - .gitattributes - AUTHORS - LICENSE + - "*.project" - "cabal.project.*" - "*.ac" - "*.bat" @@ -117,6 +118,7 @@ excluded-files: - "*.golden" - "*.log" - "*.out" + - doc/buildinfo-fields-reference.rst # Binary files - "*.a" diff --git a/fourmolu.yaml b/fourmolu.yaml index acd4a166328..40b1e42207b 100644 --- a/fourmolu.yaml +++ b/fourmolu.yaml @@ -14,7 +14,7 @@ let-style: auto fixities: # Distribution.Compat.Parsing - - infixr 0 + - infixr 0 # Distribution.FieldGrammar - infixl 5 ^^^ # Distribution.Types.InstalledPackageInfo.FieldGrammar diff --git a/project-cabal/README.md b/project-cabal/README.md new file mode 100644 index 00000000000..03f3dbdaf02 --- /dev/null +++ b/project-cabal/README.md @@ -0,0 +1,102 @@ +# Cabal Projects + +We have these projects, all in the root: + +``` +$ tree -P 'cabal.project*' --prune -L 1 +. +├── cabal.project +├── cabal.project.libonly +├── cabal.project.meta +├── cabal.project.release +├── cabal.project.validate +└── cabal.project.validate.libonly +``` + +Projects are expected to pass a `build --dry-run` standalone test, +substituting the actual project filename for `cabal.project` in +`--project-file=cabal.project`: + +``` +$ cabal build all --enable-tests --enable-benchmarks --dry-run \ + --project-file=cabal.project +``` + +The `release` project might fail to resolve dependencies with the latest GHC +compiler with its `index-state` pinned but it should build if unpinned, by +removing `index-state` from the project or setting it to `HEAD`: + +``` +$ cabal build all --enable-tests --enable-benchmarks \ + --project-file=cabal.project.release \ + --index-state="hackage.haskell.org HEAD" +``` + +## Configuration + +Any project configuration that is not itself a project should use a `.config` +extension and be put into the `project-cabal` folder: + +``` +$ tree -P '*.config' project-cabal +project-cabal +├── constraints.config +├── ghc-latest.config +├── ghc-options.config +├── pkgs +│   ├── benchmarks.config +│   ├── buildinfo.config +│   ├── cabal.config +│   ├── install.config +│   ├── integration-tests.config +│   └── tests.config +└── pkgs.config + +2 directories, 10 files +``` + +## Package Groups + +We have one `project-cabal/pkgs.config` that includes all package groups. + +``` +$ cat project-cabal/pkgs.config +import: pkgs/cabal.config +import: pkgs/install.config +import: pkgs/buildinfo.config +import: pkgs/tests.config +import: pkgs/integration-tests.config +import: pkgs/benchmarks.config +``` + +The default and `validate` projects get their packages this way. The `libonly`, +and `validate.libonly` projects import packages from `cabal` and `tests` package +groups. The `release` project also does this but also imports the `install` +package group. + +| Project | pkgs | cabal | tests | install | +|------------------|:---: |:---: |:---: |:---: | +| default | ✓ | | | | +| libonly | | ✓ | ✓ | | +| release | | ✓ | ✓ | ✓ | +| validate | ✓ | | | | +| validate.libonly | | ✓ | ✓ | | + +The `meta` project is a one-liner: + +``` +$ cat cabal.project.meta +packages: cabal-dev-scripts +``` + +## Extra Config + +Additional configuration is imported: + +| Project | ghc-options | ghc-latest | constraints | +|------------------|:---: |:---: |:---: | +| default | ✓ | ✓ | ✓ | +| libonly | ✓ | | | +| release | | | | +| validate | ✓ | ✓ | ✓ | +| validate.libonly | ✓ | | ✓ | diff --git a/project-cabal/constraints.config b/project-cabal/constraints.config new file mode 100644 index 00000000000..aba937cb9f1 --- /dev/null +++ b/project-cabal/constraints.config @@ -0,0 +1,3 @@ +-- avoiding extra dependencies +constraints: rere -rere-cfg +constraints: these -assoc diff --git a/project-cabal/ghc-latest.config b/project-cabal/ghc-latest.config new file mode 100644 index 00000000000..5132415b48c --- /dev/null +++ b/project-cabal/ghc-latest.config @@ -0,0 +1,12 @@ +-- Usually, the latest GHC requires a few allow-newer's +-- for some time after the release. This project file is meant to host these. +-- The file is supposed to be included in the main project files used for +-- Cabal development: +-- - cabal.project (day-to-day development), +-- - cabal.project.validate (Cabal CI), +-- Commented out below are the usual suspects. Feel free to add more. + +-- NOTE: don't forget to update the compiler version in the conditional +-- when upgrading to a newer GHC +if impl(ghc >= 9.8.1) + -- allow-newer: windns:* diff --git a/project-cabal/ghc-options.config b/project-cabal/ghc-options.config new file mode 100644 index 00000000000..e3ece385c5c --- /dev/null +++ b/project-cabal/ghc-options.config @@ -0,0 +1,2 @@ +program-options + ghc-options: -fno-ignore-asserts -Werror diff --git a/project-cabal/pkgs.config b/project-cabal/pkgs.config new file mode 100644 index 00000000000..5f12a02754a --- /dev/null +++ b/project-cabal/pkgs.config @@ -0,0 +1,6 @@ +import: pkgs/cabal.config +import: pkgs/install.config +import: pkgs/buildinfo.config +import: pkgs/tests.config +import: pkgs/integration-tests.config +import: pkgs/benchmarks.config diff --git a/project-cabal/pkgs/benchmarks.config b/project-cabal/pkgs/benchmarks.config new file mode 100644 index 00000000000..22941678058 --- /dev/null +++ b/project-cabal/pkgs/benchmarks.config @@ -0,0 +1,3 @@ +packages: + cabal-benchmarks + , solver-benchmarks diff --git a/project-cabal/pkgs/buildinfo.config b/project-cabal/pkgs/buildinfo.config new file mode 100644 index 00000000000..aec4e483443 --- /dev/null +++ b/project-cabal/pkgs/buildinfo.config @@ -0,0 +1 @@ +packages: buildinfo-reference-generator diff --git a/project-cabal/pkgs/cabal.config b/project-cabal/pkgs/cabal.config new file mode 100644 index 00000000000..2500cad5ecf --- /dev/null +++ b/project-cabal/pkgs/cabal.config @@ -0,0 +1,4 @@ +packages: + Cabal + , Cabal-described + , Cabal-syntax diff --git a/project-cabal/pkgs/install.config b/project-cabal/pkgs/install.config new file mode 100644 index 00000000000..9010d1f332b --- /dev/null +++ b/project-cabal/pkgs/install.config @@ -0,0 +1,3 @@ +packages: + cabal-install + , cabal-install-solver diff --git a/project-cabal/pkgs/integration-tests.config b/project-cabal/pkgs/integration-tests.config new file mode 100644 index 00000000000..00fc56f4467 --- /dev/null +++ b/project-cabal/pkgs/integration-tests.config @@ -0,0 +1 @@ +packages: cabal-testsuite diff --git a/project-cabal/pkgs/tests.config b/project-cabal/pkgs/tests.config new file mode 100644 index 00000000000..a9cec9c596f --- /dev/null +++ b/project-cabal/pkgs/tests.config @@ -0,0 +1,4 @@ +packages: + Cabal-QuickCheck + , Cabal-tests + , Cabal-tree-diff diff --git a/release-notes/Cabal-3.10.3.0.md b/release-notes/Cabal-3.10.3.0.md new file mode 100644 index 00000000000..3488616b920 --- /dev/null +++ b/release-notes/Cabal-3.10.3.0.md @@ -0,0 +1,15 @@ +Cabal and Cabal-syntax 3.10.3.0 changelog and release notes +--- + +## Release 3.10.3.0 is strictly a bug-fix release, with the fixes listed below + +- PkgConfig environment variables [#9134](https://github.com/haskell/cabal/pull/9134) + - `cabal` invokes `pkg-config` with `PKG_CONFIG_ALLOW_SYSTEM_CFLAGS` and `PKG_CONFIG_ALLOW_SYSTEM_LIBS` set + +- Support text-2.1 in Cabal and Cabal-syntax [#9242](https://github.com/haskell/cabal/pull/9242) + +- Fix extra-prog-path propagation [#7649](https://github.com/haskell/cabal/issues/7649) [#9519](https://github.com/haskell/cabal/issues/9519) [#9527](https://github.com/haskell/cabal/pull/9527) + - extra-prog-paths are now propagated to all commands. This in particular helps + when running a MinGW cabal in the PowerShell, where the MSYS2 paths are + usually not available in the PowerShell PATH. GHCup already sets them up for + us but they were sometimes lost on the way. diff --git a/release-notes/cabal-install-3.10.3.0.md b/release-notes/cabal-install-3.10.3.0.md new file mode 100644 index 00000000000..f057eb4ca53 --- /dev/null +++ b/release-notes/cabal-install-3.10.3.0.md @@ -0,0 +1,45 @@ +cabal-install and cabal-install-solver 3.10.3.0 changelog and release notes +--- + +## Release 3.10.3.0 is strictly a bug-fix release, with the fixes listed below + +- PkgConfig individual calls [#9134](https://github.com/haskell/cabal/pull/9134) + + - `cabal` invokes `pkg-config` individually for each lib if querying for all doesn't return the expected result + +- Use compiler flags for caching project config [#8819](https://github.com/haskell/cabal/pull/8819) + + This ensures that cached project configs with conditionals re-execute the conditional logic when the compiler changes. + +- Make `check` recognise `TypeAbstractions` [#9496](https://github.com/haskell/cabal/issues/9496) [#9503](https://github.com/haskell/cabal/pull/9503) + + - `cabal check` will not complain about “Unknown extension” when + finding `TypeAbstractions`. + +- `check`: add PackageInfo warning [#9331](https://github.com/haskell/cabal/issues/9331) [#9525](https://github.com/haskell/cabal/pull/9525) + + `cabal check` will warn about PackageInfo_* modules and provide an upgrade path to 3.12. + +- Fix extra-prog-path propagation [#7649](https://github.com/haskell/cabal/issues/7649) [#9519](https://github.com/haskell/cabal/issues/9519) [#9527](https://github.com/haskell/cabal/pull/9527) + + - extra-prog-paths are now propagated to all commands. This in particular helps + when running a MinGW cabal in the PowerShell, where the MSYS2 paths are + usually not available in the PowerShell PATH. GHCup already sets them up for + us but they were sometimes lost on the way. + +- fix pkgconfig-depends for pkgconf-1.9 [#8923](https://github.com/haskell/cabal/issues/8923) [#9391](https://github.com/haskell/cabal/pull/9391) + +- Ignore invalid Unicode in pkg-config descriptions [#9608](https://github.com/haskell/cabal/issues/9608) [#9609](https://github.com/haskell/cabal/pull/9609) + + Previously, cabal-install would crash when `pkg-config --list-all` contained + invalid Unicode. With this change, invalid unicode in package descriptions is + ignored, and unparseable package names are considered nonexistent. + +- Script cache dir is the base16 hash of the canonical path of the script. [#9459](https://github.com/haskell/cabal/pull/9459) + + Script cache dir is the base16 hash of the canonical path of the script. + +- Fix run command environment [#8391](https://github.com/haskell/cabal/issues/8391) [#9341](https://github.com/haskell/cabal/pull/9341) + + - The Run command will now add binary paths of dependencies + (build-tool-depends) to PATH, just like Exec and Test commands. diff --git a/scripts/release/create-release-metadata-for-ghcup.sh b/scripts/release/create-release-metadata-for-ghcup.sh new file mode 100755 index 00000000000..c8683c2b85c --- /dev/null +++ b/scripts/release/create-release-metadata-for-ghcup.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash + +# This script, when passed the cabal release number as the first and only argument +# generates the metadata in the correct format to be useable as is by GHCup +# for eg:- +# $ create-release-metadata-for-ghcup.sh 3.10.2.0 or "3.10.2.0" + +# Note:- Please run ./download-cabal-install-release-binaries.sh before running this script. +set -eu +set -o pipefail + +RELEASE=$1 +## FixMe:// What dir to use here? + +if [ -d "binary-downloads/cabal-install-${RELEASE}-binaries" ]; then + echo "binary downloads folder for release ${RELEASE} found, starting generating GHCup metadata..." +else + echo "The binary downloads for release ${RELEASE} not found." + echo "Please run the script to download them first." +fi + +cd "binary-downloads/cabal-install-${RELEASE}-binaries" + +cat < /dev/stdout + $RELEASE: + viTags: + - Latest + viChangeLog: https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-$RELEASE.md + viPostInstall: *cabal-${RELEASE//./}-post-install + viArch: + A_64: + Linux_UnknownLinux: + unknown_versioning: &cabal-${RELEASE//./}-64 + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-alpine3_12.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-alpine3_12.tar.xz" | awk '{ print $1 }') + Linux_Alpine: + unknown_versioning: &cabal-${RELEASE//./}-64 + Linux_CentOS: + unknown_versioning: &cabal-${RELEASE//./}-64-centos7 + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-centos7.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-centos7.tar.xz" | awk '{ print $1 }') + Linux_Debian: + ' ( >= 9 && < 10)': &cabal-${RELEASE//./}-64-debian + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-deb9.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-deb9.tar.xz" | awk '{ print $1 }') + ' ( == 10 && < 11)': + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-deb10.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-deb10.tar.xz" | awk '{ print $1 }') + ' ( >= 11)': + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-deb11.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-deb11.tar.xz" | awk '{ print $1 }') + unknown_versioning: &cabal-${RELEASE//./}-64-debian + Linux_Fedora: + '>= 33': + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-fedora33.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-fedora33.tar.xz" | awk '{ print $1 }') + unknown_versioning: &cabal-${RELEASE//./}-64-centos7 + Linux_Ubuntu: + '< 20': &cabal-${RELEASE//./}-64-ubuntu18 + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-ubuntu18_04.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-ubuntu18_04.tar.xz" | awk '{ print $1 }') + '>= 20': &cabal-${RELEASE//./}-64-ubuntu20 + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-linux-ubuntu20_04.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-linux-ubuntu20_04.tar.xz" | awk '{ print $1 }') + unknown_versioning: *cabal-${RELEASE//./}-64-ubuntu18 + Linux_Mint: + '< 20': *cabal-${RELEASE//./}-64-ubuntu18 + '>= 20': *cabal-${RELEASE//./}-64-ubuntu20 + unknown_versioning: *cabal-${RELEASE//./}-64-ubuntu18 + Darwin: + unknown_versioning: + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-darwin.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-darwin.tar.xz" | awk '{ print $1 }') + Windows: + unknown_versioning: + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-windows.zip + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-windows.zip" | awk '{ print $1 }') + FreeBSD: + unknown_versioning: + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-x86_64-freebsd.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-x86_64-freebsd.tar.xz" | awk '{ print $1 }') + A_32: + Linux_UnknownLinux: + unknown_versioning: &cabal-${RELEASE//./}-32 + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-i386-linux-alpine3_12.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-i386-linux-alpine3_12.tar.xz" | awk '{ print $1 }') + Linux_Alpine: + unknown_versioning: *cabal-${RELEASE//./}-32 + Linux_Debian: + '( >= 9 )': + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-i386-linux-deb9.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-i386-linux-deb9.tar.xz" | awk '{ print $1 }') + unknown_versioning: *cabal-${RELEASE//./}-32 + A_ARM64: + Darwin: + unknown_versioning: + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-aarch64-darwin.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-aarch64-darwin.tar.xz" | awk '{ print $1 }') + Linux_Debian: + '( >= 10 && < 11)': &cabal-31020-arm64 + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-aarch64-linux-deb10.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-aarch64-linux-deb10.tar.xz" | awk '{ print $1 }') + '( >= 11)': + dlUri: https://downloads.haskell.org/~cabal/cabal-install-$RELEASE/cabal-install-$RELEASE-aarch64-linux-deb11.tar.xz + dlSubdir: cabal-install-$RELEASE + dlHash: $(sha256sum "cabal-install-$RELEASE-aarch64-linux-deb11.tar.xz" | awk '{ print $1 }') + unknown_versioning: *cabal-${RELEASE//./}-arm64 + Linux_UnknownLinux: + unknown_versioning: *cabal-${RELEASE//./}-arm64 +EOF diff --git a/scripts/release/download-cabal-install-release-binaries.sh b/scripts/release/download-cabal-install-release-binaries.sh new file mode 100755 index 00000000000..4547fd910e8 --- /dev/null +++ b/scripts/release/download-cabal-install-release-binaries.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +# A script to download the release binary files for a given cabal release +# from upstream "downlods.haskell.org". +# It accepts the first and only argument as the release number. +# +# useage:- +# $ download-cabal-install-release-binaries.sh "3.10.1.0" +# +# This was initally made to be used with ./create-release-metadata-for-ghcup.sh + +set -eu +set -o pipefail + +RELEASE=$1 + +echo "RELEASE: $RELEASE" + +for com in wget sha256sum ; do + command -V ${com} >/dev/null 2>&1 +done + +[ ! -d "binary-downloads/cabal-install-${RELEASE}-binaries" ] + +mkdir -p "binary-downloads/cabal-install-${RELEASE}-binaries" + +cd "binary-downloads/cabal-install-${RELEASE}-binaries" + +## Download release files +echo "Downloading form: \"https://downloads.haskell.org/~cabal/cabal-install-${RELEASE}/\"" +wget --no-parent -r --reject "index.html*" --no-directories "https://downloads.haskell.org/~cabal/cabal-install-${RELEASE}/" + +## Verify that sha256 sums of downloaded files match the ones mentioned in the upstream SHA256SUMS file +echo "verifying checksums for downloaded files..." + +if sha256sum --check ./SHA256SUMS; then + echo "All checksums match!" + echo "Successfully downloaded binaries for release: ${RELEASE}" +else + echo "checksums of downloaded files do no match the ones listed in upstream SHA256SUMS file." + echo "please try deleting \"binary-downloads/cabal-install-${RELEASE}-binaries\" folder and downloading again." +fi diff --git a/solver-benchmarks/HackageBenchmark.hs b/solver-benchmarks/HackageBenchmark.hs index 445dc733311..37996dbfc63 100644 --- a/solver-benchmarks/HackageBenchmark.hs +++ b/solver-benchmarks/HackageBenchmark.hs @@ -1,4 +1,3 @@ -{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -19,7 +18,6 @@ import Control.Monad (forM, replicateM, unless, when) import qualified Data.ByteString as BS import Data.List (nub, unzip4) import Data.Maybe (isJust, catMaybes) -import Data.Monoid ((<>)) import Data.String (fromString) import Data.Function ((&)) import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime) @@ -187,7 +185,7 @@ hackageBenchmarkMain = do then do putStrLn $ "Obtaining the package list (using " ++ argCabal1 ++ ") ..." list <- readProcess argCabal1 ["list", "--simple-output"] "" - return $ nub [mkPackageName $ head (words line) | line <- lines list] + return $ nub [mkPackageName n | n : _ <- words <$> lines list] else do putStrLn "Using given package list ..." return argPackages @@ -220,17 +218,12 @@ runCabal timeoutSeconds cabalUnderTest cabal flags = do & Map.insert "CABAL_CONFIG" (cabalDir "config") & Map.insert "CABAL_DIR" cabalDir - -- Run cabal update, + -- Initialize the config file, whether or not it already exists + runCabalCmdWithEnv cabalDir thisEnv ["user-config", "init", "--force"] + + -- Run cabal update putStrLn $ "Running cabal update (using " ++ cabal ++ ") ..." - (ec, uout, uerr) <- readCreateProcessWithExitCode (proc cabal ["update"]) - { cwd = Just cabalDir - , env = Just thisEnv - } - "" - unless (ec == ExitSuccess) $ do - putStrLn uout - putStrLn uerr - exitWith ec + runCabalCmdWithEnv cabalDir thisEnv ["update"] -- return an actual runner return $ \pkg -> do @@ -289,6 +282,17 @@ runCabal timeoutSeconds cabalUnderTest cabal flags = do | fromString "There is no package named" `BS.isInfixOf` err = PkgNotFound | otherwise = Unknown return (CabalTrial time result) + where + runCabalCmdWithEnv cabalDir thisEnv args = do + (ec, uout, uerr) <- readCreateProcessWithExitCode (proc cabal args) + { cwd = Just cabalDir + , env = Just thisEnv + } + "" + unless (ec == ExitSuccess) $ do + putStrLn uout + putStrLn uerr + exitWith ec isSampleLargeEnough :: PValue Double -> Int -> Bool isSampleLargeEnough pvalue trials = @@ -339,7 +343,8 @@ isExpectedResult Unknown = False -- should be the same. If they aren't the same, we returns Unknown. combineTrialResults :: [CabalResult] -> CabalResult combineTrialResults rs - | allEqual rs = head rs + | r:_ <- rs + , allEqual rs = r | allEqual [r | r <- rs, r /= Timeout] = Timeout | otherwise = Unknown where diff --git a/solver-benchmarks/LICENSE b/solver-benchmarks/LICENSE index a3a25c7d9e4..edfcdbd3adc 100644 --- a/solver-benchmarks/LICENSE +++ b/solver-benchmarks/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2003-2023, Cabal Development Team. +Copyright (c) 2003-2024, Cabal Development Team. See the AUTHORS file for the full list of copyright holders. See */LICENSE for the copyright holders of the subcomponents. diff --git a/solver-benchmarks/solver-benchmarks.cabal b/solver-benchmarks/solver-benchmarks.cabal index fdcbad60718..22ef92117fd 100644 --- a/solver-benchmarks/solver-benchmarks.cabal +++ b/solver-benchmarks/solver-benchmarks.cabal @@ -1,7 +1,7 @@ cabal-version: 2.2 name: solver-benchmarks version: 3 -copyright: 2003-2023, Cabal Development Team (see AUTHORS file) +copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE author: Cabal Development Team diff --git a/validate.sh b/validate.sh index fa49edbb438..9edc87eeaf3 100755 --- a/validate.sh +++ b/validate.sh @@ -67,17 +67,27 @@ EOF OUTPUT=$(mktemp) -RED='\033[0;31m' -GREEN='\033[0;32m' -BLUE='\033[0;34m' -CYAN='\033[0;96m' -RESET='\033[0m' # No Color +# `red` and `green` are used to output also the spent time in white at the end. +# `blue` and `cyan` are used to print the spawned command, so they only have one +# argument. +red () { + printf "\033[0;31m%s\033[0m %s \n" "$1" "$2" +} +green () { + printf "\033[0;32m%s\033[0m %s \n" "$1" "$2" +} +blue () { + printf "\033[0;34m%s\033[0m\n" "$1" +} +cyan () { + printf "\033[0;96m%s\033[0m\n" "$1" +} JOB_START_TIME=$(date +%s) timed() { PRETTYCMD=$(echo "$@" | sed -E 's/\/home[^ ]*\/([^\/])/**\/\1/g') - echo "$BLUE>>> $PRETTYCMD $RESET" + blue "$PRETTYCMD" start_time=$(date +%s) if $VERBOSE; then @@ -105,7 +115,7 @@ timed() { rm -f "$OUTPUT" fi - echo "$GREEN<<< $PRETTYCMD $RESET ($duration/$tduration sec)" + green "<<< $PRETTYCMD" "($duration/$tduration sec)" # bottom-margin echo "" @@ -114,8 +124,8 @@ timed() { cat "$OUTPUT" fi - echo "$RED<<< $PRETTYCMD $RESET ($duration/$tduration sec, $RET)" - echo "$RED<<< $* $RESET ($duration/$tduration sec, $RET)" + red "<<< $PRETTYCMD" "($duration/$tduration sec, $RET)" + red "<<< $*" "($duration/$tduration sec, $RET)" rm -f "$OUTPUT" exit 1 fi @@ -124,7 +134,7 @@ timed() { print_header() { TITLE=$1 TITLEPAT="$(echo "$TITLE"|sed 's:.:=:g')" - echo "$CYAN===X============================================================ $(date +%T) ===$RESET" \ + cyan "===X========================================================================== $(date +%T) ===" \ | sed "s#X$TITLEPAT=# $TITLE #" } @@ -287,15 +297,19 @@ TESTSUITEJOBS="-j$JOBS" JOBS="-j$JOBS" # assume compiler is GHC -RUNHASKELL=$(echo $HC | sed -E 's/ghc(-[0-9.]*)$/runghc\1/') - -if [ "$OSTYPE" = "msys" ]; then - ARCH="x86_64-windows" -elif [ "$(uname)" = "Linux" ]; then - ARCH="x86_64-linux" -else - ARCH="x86_64-osx" -fi +RUNHASKELL=$(echo "$HC" | sed -E 's/ghc(-[0-9.]*)$/runghc\1/') + +case "$(uname)" in + MINGW64*) + ARCH="x86_64-windows" + ;; + Linux ) + ARCH="x86_64-linux" + ;; + *) + ARCH="x86_64-osx" + ;; +esac if $LIBONLY; then PROJECTFILE=cabal.project.validate.libonly @@ -337,11 +351,11 @@ EOF step_print_tool_versions() { print_header print-tool-versions -timed $HC --version -timed $CABAL --version +timed "$HC" --version +timed "$CABAL" --version for EXTRAHC in $EXTRAHCS; do - timed $EXTRAHC --version + timed "$EXTRAHC" --version done } @@ -351,7 +365,7 @@ step_time_summary() { JOB_END_TIME=$(date +%s) tduration=$((JOB_END_TIME - JOB_START_TIME)) - echo "$CYAN!!! Validation took $tduration seconds. $RESET" + cyan "!!! Validation took $tduration seconds." } # build @@ -454,7 +468,7 @@ CMD="$($CABALLISTBIN cabal-install:test:integration-tests2) -j1 --hide-successes step_cli_suite() { print_header "cabal-install: cabal-testsuite" -CMD="$($CABALLISTBIN cabal-testsuite:exe:cabal-tests) --builddir=$CABAL_TESTSUITE_BDIR --with-cabal=$($CABALLISTBIN cabal-install:exe:cabal) $TESTSUITEJOBS --with-ghc=$HC --hide-successes" +CMD="$($CABALLISTBIN cabal-testsuite:exe:cabal-tests) --builddir=$CABAL_TESTSUITE_BDIR --with-cabal=$($CABALLISTBIN cabal-install:exe:cabal) $TESTSUITEJOBS --with-ghc=$HC --hide-successes --intree-cabal-lib=$PWD --test-tmp=$PWD/testdb" (cd cabal-testsuite && timed $CMD) || exit 1 } diff --git a/weeder.dhall b/weeder.dhall deleted file mode 100644 index ff28bf5c995..00000000000 --- a/weeder.dhall +++ /dev/null @@ -1,9 +0,0 @@ -{ roots = - [ "^Main\\.main$" - , "^Hackage\\.Security\\." - , "^Text\\.JSON\\.Canonical\\." - , "Paths_Cabal\\." - , "Paths_cabal_install\\." - ] -, type-class-roots = True -}