packages feed

haskell-ci (empty) → 0.1.0.0

raw patch · 25 files changed

+3683/−0 lines, 25 filesdep +Cabaldep +Diffdep +ShellChecksetup-changed

Dependencies added: Cabal, Diff, ShellCheck, ansi-terminal, base, bytestring, containers, deepseq, directory, filepath, haskell-ci, tasty, tasty-golden, transformers

Files

+ LICENSE view
@@ -0,0 +1,31 @@+Copyright (c) 2017-2018, Herbert Valerio Riedel+              2017-2018, Oleg Grenrus++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 Herbert Valerio Riedel 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.
+ Main.hs view
@@ -0,0 +1,2 @@+module Main (main) where+import MakeTravisYml (main)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ fixtures/cabal.haskell-ci view
@@ -0,0 +1,57 @@+-- Most settings can be given as command line arguments+-- Config file is convinient if you maintain large amount of packages++jobs: 2:2++-- travis Caching+-- cache: True++-- remove cabal noise from test output+-- cabal-noise: False++-- Run cabal check+-- cabal-check: True++-- Install dependencies in a separate step+-- If your project has inplace packages, you want to disable this.+-- install-dependencies-step: True++-- --no-tests --no-benchmarks build is useful to verify that package+-- builds when less constrained+-- no-tests-no-bench: True++-- By default `installed` constraints are used for packages+-- in global db. Unconstrained step is a build without them.+-- Note: solver might or might not pick newer versions.+-- unconstrained-step: True++-- Options for local packages+local-ghc-options: -Werror++-- Build only these branches+branches: master++-- Enable IRC notifications to the given channel+-- name: fancy-name+-- irc-channels: irc.freenode.org#my-channel++-- Sections to fold in the build output+folds: constraint-sets++-- Run HLint (needs GHC-8.2.2 job)+hlint: True+hlint-yaml: .hlint.yaml+-- hlint-version: ==2.0.*++-- Run doctest (on GHC-8.0+ which support .ghc.environment)+doctest: True+doctest-options: --fast+-- doctest-version: ==0.13.*++-- Constraint sets+-- Package will be build with different constraints.+-- This is useful to check compatibility with older versions of dependencies.++constraint-set deepseq-1.4+  ghc: (>= 7.8 && <7.10) || == 8.2.2+  constraints: deepseq ==1.4.*
+ fixtures/cabal.project.empty-line view
@@ -0,0 +1,12 @@+packages:+  servant/+  servant-client/+  servant-docs/+  servant-server/++constraints: foundatiion >= 0.14+allow-newer:+  servant-js:servant+allow-newer:+  servant-js:servant-foreign+allow-newer:
+ fixtures/cabal.project.empty-line.stderr view
@@ -0,0 +1,1 @@+*INFO* Generating Travis-CI config for testing for GHC versions: head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.6.1
+ fixtures/cabal.project.empty-line.travis.yml view
@@ -0,0 +1,189 @@+# This Travis job script has been generated by a script via+#+#   runghc make_travis_yml_2.hs '--ghc-head' 'cabal.project.empty-line'+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+language: c+sudo: false++git:+  submodules: false  # whether to recursively clone submodules++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $HOME/.cabal/packages/head.hackage++matrix:+  include:+    - compiler: "ghc-8.6.1"+      env: GHCHEAD=true+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.1], sources: [hvr-ghc]}}+    - compiler: "ghc-head"+      env: GHCHEAD=true+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}}++  allow_failures:+    - compiler: "ghc-head"+    - compiler: "ghc-8.6.1"++before_install:+  - HC=${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - ROOTDIR=$(pwd)+  - mkdir -p $HOME/.local/bin+  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER++install:+  - cabal --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - BENCH=${BENCH---enable-benchmarks}+  - TEST=${TEST---enable-tests}+  - HADDOCK=${HADDOCK-true}+  - UNCONSTRAINED=${UNCONSTRAINED-true}+  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry cabal update -v+  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - rm -fv cabal.project cabal.project.local+  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage+  - |+    if $GHCHEAD; then+      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config+      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done++      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config+      echo '   secure: True'                                                                >> ${HOME}/.cabal/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config+      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config++      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'++      cabal new-update head.hackage -v+    fi+  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+  - "printf 'packages: \"servant\" \"servant-client\" \"servant-docs\" \"servant-server\"\\n' > cabal.project"+  - "echo 'constraints: foundatiion >= 0.14' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant, servant-js:servant-foreign' >> cabal.project"+  - touch cabal.project.local+  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - cat cabal.project || true+  - cat cabal.project.local || true+  - if [ -f "servant/configure.ac" ]; then+      (cd "servant" && autoreconf -i);+    fi+  - if [ -f "servant-client/configure.ac" ]; then+      (cd "servant-client" && autoreconf -i);+    fi+  - if [ -f "servant-docs/configure.ac" ]; then+      (cd "servant-docs" && autoreconf -i);+    fi+  - if [ -f "servant-server/configure.ac" ]; then+      (cd "servant-server" && autoreconf -i);+    fi+  - rm -f cabal.project.freeze+  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.empty-line" --dep -j2 all+  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.empty-line" --dep -j2 all+  - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+  # test that source-distributions can be generated+  - (cd "servant" && cabal sdist)+  - (cd "servant-client" && cabal sdist)+  - (cd "servant-docs" && cabal sdist)+  - (cd "servant-server" && cabal sdist)+  - mv "servant"/dist/servant-*.tar.gz "servant-client"/dist/servant-client-*.tar.gz "servant-docs"/dist/servant-docs-*.tar.gz "servant-server"/dist/servant-server-*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - "printf 'packages: servant-*/*.cabal servant-client-*/*.cabal servant-docs-*/*.cabal servant-server-*/*.cabal\\n' > cabal.project"+  - "echo 'constraints: foundatiion >= 0.14' >> cabal.project"+  - "echo 'allow-newer: servant-js:servant, servant-js:servant-foreign' >> cabal.project"+  - touch cabal.project.local+  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - cat cabal.project || true+  - cat cabal.project.local || true+  # this builds all libraries and executables (without tests/benchmarks)+  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all++  # build & run tests, build benchmarks+  - cabal new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi++  # cabal check+  - (cd servant-* && cabal check)+  - (cd servant-client-* && cabal check)+  - (cd servant-docs-* && cabal check)+  - (cd servant-server-* && cabal check)++  # haddock+  - rm -rf ./dist-newstyle+  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi++  # Build without installed constraints for packages in global-db+  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi++# REGENDATA ["--ghc-head","cabal.project.empty-line"]+# EOF
+ fixtures/cabal.project.fail-versions view
@@ -0,0 +1,7 @@+packages: servant/+  servant-client/+  servant-client-core/+  servant-docs/+  servant-foreign/+  servant-server/+  doc/tutorial/
+ fixtures/cabal.project.fail-versions.stderr view
@@ -0,0 +1,3 @@+*ERROR* servant-client-core is missing tested-with annotations for: 7.8.1,7.8.2,7.8.3,7.8.4+*ERROR* servant-foreign is missing tested-with annotations for: 7.8.1,7.8.2,7.8.3,7.8.4+*ERROR* tutorial is missing tested-with annotations for: 7.8.1,7.8.2,7.8.3,7.8.4
+ fixtures/cabal.project.messy view
@@ -0,0 +1,6 @@+packages: servant/,++  servant-client/+ + ,+     servant-docs/,servant-server/
+ fixtures/cabal.project.messy.stderr view
@@ -0,0 +1,1 @@+*INFO* Generating Travis-CI config for testing for GHC versions: head 7.8.1 7.8.2 7.8.3 7.8.4 7.10.1 7.10.2 7.10.3 8.0.1 8.0.2 8.2.1 8.2.2 8.4.1 8.4.2 8.4.3 8.6.1
+ fixtures/cabal.project.messy.travis.yml view
@@ -0,0 +1,185 @@+# This Travis job script has been generated by a script via+#+#   runghc make_travis_yml_2.hs '--ghc-head' 'cabal.project.messy'+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+language: c+sudo: false++git:+  submodules: false  # whether to recursively clone submodules++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $HOME/.cabal/packages/head.hackage++matrix:+  include:+    - compiler: "ghc-8.6.1"+      env: GHCHEAD=true+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.1], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.1"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.1], sources: [hvr-ghc]}}+    - compiler: "ghc-head"+      env: GHCHEAD=true+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-head], sources: [hvr-ghc]}}++  allow_failures:+    - compiler: "ghc-head"+    - compiler: "ghc-8.6.1"++before_install:+  - HC=${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - ROOTDIR=$(pwd)+  - mkdir -p $HOME/.local/bin+  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER++install:+  - cabal --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - BENCH=${BENCH---enable-benchmarks}+  - TEST=${TEST---enable-tests}+  - HADDOCK=${HADDOCK-true}+  - UNCONSTRAINED=${UNCONSTRAINED-true}+  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry cabal update -v+  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - rm -fv cabal.project cabal.project.local+  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage+  - |+    if $GHCHEAD; then+      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config+      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done++      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config+      echo '   secure: True'                                                                >> ${HOME}/.cabal/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config+      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config++      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'++      cabal new-update head.hackage -v+    fi+  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+  - "printf 'packages: \"servant\" \"servant-client\" \"servant-docs\" \"servant-server\"\\n' > cabal.project"+  - touch cabal.project.local+  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - cat cabal.project || true+  - cat cabal.project.local || true+  - if [ -f "servant/configure.ac" ]; then+      (cd "servant" && autoreconf -i);+    fi+  - if [ -f "servant-client/configure.ac" ]; then+      (cd "servant-client" && autoreconf -i);+    fi+  - if [ -f "servant-docs/configure.ac" ]; then+      (cd "servant-docs" && autoreconf -i);+    fi+  - if [ -f "servant-server/configure.ac" ]; then+      (cd "servant-server" && autoreconf -i);+    fi+  - rm -f cabal.project.freeze+  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project.messy" --dep -j2 all+  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project.messy" --dep -j2 all+  - rm -rf .ghc.environment.* "servant"/dist "servant-client"/dist "servant-docs"/dist "servant-server"/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+  # test that source-distributions can be generated+  - (cd "servant" && cabal sdist)+  - (cd "servant-client" && cabal sdist)+  - (cd "servant-docs" && cabal sdist)+  - (cd "servant-server" && cabal sdist)+  - mv "servant"/dist/servant-*.tar.gz "servant-client"/dist/servant-client-*.tar.gz "servant-docs"/dist/servant-docs-*.tar.gz "servant-server"/dist/servant-server-*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - "printf 'packages: servant-*/*.cabal servant-client-*/*.cabal servant-docs-*/*.cabal servant-server-*/*.cabal\\n' > cabal.project"+  - touch cabal.project.local+  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- servant | grep -vw -- servant-client | grep -vw -- servant-docs | grep -vw -- servant-server | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - cat cabal.project || true+  - cat cabal.project.local || true+  # this builds all libraries and executables (without tests/benchmarks)+  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all++  # build & run tests, build benchmarks+  - cabal new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi++  # cabal check+  - (cd servant-* && cabal check)+  - (cd servant-client-* && cabal check)+  - (cd servant-docs-* && cabal check)+  - (cd servant-server-* && cabal check)++  # haddock+  - rm -rf ./dist-newstyle+  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi++  # Build without installed constraints for packages in global-db+  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi++# REGENDATA ["--ghc-head","cabal.project.messy"]+# EOF
+ fixtures/doc/tutorial/tutorial.cabal view
@@ -0,0 +1,64 @@+name:                tutorial+version:             0.10+synopsis:            The servant tutorial+homepage:            http://haskell-servant.readthedocs.org/+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+build-type:          Simple+cabal-version:       >=1.10+tested-with:         GHC >= 7.10++library+  exposed-modules:     ApiType+                     , Authentication+                     , Client+                     , Docs+                     , Javascript+                     , Server+  build-depends:       base == 4.*+                     , base-compat+                     , text+                     , aeson+                     , aeson-compat+                     , blaze-html+                     , directory+                     , blaze-markup+                     , containers+                     , servant == 0.11.*+                     , servant-server == 0.11.*+                     , servant-client == 0.11.*+                     , servant-docs == 0.11.*+                     , servant-js >= 0.9 && <0.10+                     , warp+                     , http-api-data+                     , http-media+                     , lucid+                     , time+                     , string-conversions+                     , bytestring+                     , attoparsec+                     , mtl+                     , random+                     , js-jquery+                     , wai+                     , http-types+                     , transformers+                     , markdown-unlit >= 0.4+                     , http-client+  default-language:    Haskell2010+  ghc-options:         -Wall -pgmL markdown-unlit++test-suite spec+  type: exitcode-stdio-1.0+  ghc-options: -Wall+  default-language: Haskell2010+  hs-source-dirs: test+  main-is: Spec.hs+  other-modules: JavascriptSpec+  build-depends: base == 4.*+               , tutorial+               , hspec+               , hspec-wai+               , string-conversions
+ fixtures/haskell-ci.cabal view
@@ -0,0 +1,121 @@+cabal-version:       1.18+name:                haskell-ci+version:             0.1.0.0++synopsis:            Cabal package script generator for Travis-CI+description:+  Script generator (@make-travis-yml@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.+  .+  Included features (not limited to):+  .+  * Multiple GHC support+  * Dependency caching+  * cabal.project support (see [Nix-style local builds documentation](http://cabal.readthedocs.io/en/latest/nix-local-build-overview.html)+  * Runs tests and builds benchmarks+  * Generates Haddocks+  * macOS (OSX) support+  * building with specific constraints+  .+  === Quick Start Guide+  .+  Add a @tested-with@ line to your @.cabal@ file (e.g. @tested-with: GHC == 8.0.2 || == 8.2.2@) and then run @make-travis-yml yourpackage.cabal -o .travis.yml@ to generate the Travis-CI job script.+  .+  See @make-travis-yml --help@ for more information.++  +homepage:            http://haskell-ci.rtfd.org/+bug-reports:         https://github.com/haskell-CI/haskell-ci/issues+license:             BSD3+license-file:        LICENSE+author:              Herbert Valerio Riedel, Oleg Grenrus+maintainer:          hvr@gnu.org+category:            Development+build-type:          Simple+tested-with:+  GHC == 7.8.4,+  GHC == 7.10.3,+  GHC == 8.0.2,+  GHC == 8.2.2,+  GHC == 8.4.3,+  GHC == 8.6.1+extra-source-files:+  fixtures/cabal.haskell-ci+  fixtures/haskell-ci.cabal+  fixtures/haskell-ci.cabal.stderr+  fixtures/haskell-ci.cabal.travis.yml+  fixtures/cabal.project.empty-line+  fixtures/cabal.project.empty-line.stderr+  fixtures/cabal.project.empty-line.travis.yml+  fixtures/cabal.project.fail-versions+  fixtures/cabal.project.fail-versions.stderr+  fixtures/cabal.project.messy+  fixtures/cabal.project.messy.stderr+  fixtures/cabal.project.messy.travis.yml+  fixtures/doc/tutorial/tutorial.cabal+  fixtures/servant-client-core/*.cabal+  fixtures/servant-client/*.cabal+  fixtures/servant-docs/*.cabal+  fixtures/servant-foreign/*.cabal+  fixtures/servant-server/*.cabal+  fixtures/servant/*.cabal++source-repository head+  type: git+  location: https://github.com/haskell-CI/haskell-ci.git++flag ShellCheck+  default: True+  manual: True++library+  exposed-modules:     MakeTravisYml+  ghc-options:         -Wall+  if impl(ghc >= 8.0)+    ghc-options:+      -Wcompat+      -Wnoncanonical-monad-instances+      -Wnoncanonical-monadfail-instances+  hs-source-dirs:      src+  other-extensions:    CPP, ViewPatterns, NamedFieldPuns+  build-depends:       base         >= 4.7  && < 4.12+                     , Cabal        == 1.18.*+                                 || == 1.20.*+                                 || == 1.22.*+                                 || == 1.24.*+                                 || == 2.0.*+                                 || == 2.2.*+                     , containers   >= 0.4  && < 0.6+                     , directory    >= 1.1  && < 1.4+                     , filepath     >= 1.2  && < 1.5+                     , transformers >= 0.3  && < 0.6+                     , deepseq      >= 1.3  && < 1.5+  default-language:    Haskell2010++  -- ShellCheck. Would need newer transformers for older GHC+  if flag(ShellCheck) && impl(ghc >= 7.10 && <8.5)+    build-depends: ShellCheck == 0.5.0++executable make-travis-yml+  main-is:             Main.hs+  ghc-options:         -Wall+  build-depends:       base, haskell-ci+  default-language:    Haskell2010++test-suite golden+  type:                exitcode-stdio-1.0+  main-is:             Tests.hs+  hs-source-dirs:      test+  build-depends:       haskell-ci+                       -- inherited constraints via lib:haskell-ci+                     , base+                     , bytestring+                     , directory+                     , filepath+                     , transformers+                       -- dependencies needing explicit constraints+                     , tasty         >= 1.0      && < 1.2+                     , tasty-golden  >= 2.3.1.1  && < 2.4+                     , ansi-terminal >= 0.8.0.2  && <0.9+                     , Diff          >= 0.3.4    && < 0.4++  default-language:    Haskell2010
+ fixtures/haskell-ci.cabal.stderr view
@@ -0,0 +1,1 @@+*INFO* Generating Travis-CI config for testing for GHC versions: 7.8.4 7.10.3 8.0.2 8.2.2 8.4.3 8.6.1
+ fixtures/haskell-ci.cabal.travis.yml view
@@ -0,0 +1,166 @@+# This Travis job script has been generated by a script via+#+#   runghc make_travis_yml_2.hs '-o' '.travis.yml' '--config=cabal.haskell-ci' 'haskell-ci.cabal'+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+language: c+sudo: false++git:+  submodules: false  # whether to recursively clone submodules++branches:+  only:+    - master++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $HOME/.cabal/packages/head.hackage++matrix:+  include:+    - compiler: "ghc-8.6.1"+      env: GHCHEAD=true+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.6.1], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.4.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-2.2,ghc-7.8.4], sources: [hvr-ghc]}}++  allow_failures:+    - compiler: "ghc-8.6.1"++before_install:+  - HC=${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - ROOTDIR=$(pwd)+  - mkdir -p $HOME/.local/bin+  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER++install:+  - cabal --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - BENCH=${BENCH---enable-benchmarks}+  - TEST=${TEST---enable-tests}+  - HADDOCK=${HADDOCK-true}+  - UNCONSTRAINED=${UNCONSTRAINED-true}+  - NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry cabal update -v+  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - rm -fv cabal.project cabal.project.local+  - "sed -i.bak 's/^-- jobs:.*/jobs: 2/' ${HOME}/.cabal/config"+  - "if [ $HCNUMVER -ge 70800 ]; then sed -i.bak 's/-- ghc-options:.*/ghc-options: -j2/' ${HOME}/.cabal/config; fi"+  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage+  - |+    if $GHCHEAD; then+      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config+      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i "s/allow-newer: /allow-newer: *:$pkg, /" ${HOME}/.cabal/config; done++      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config+      echo '   secure: True'                                                                >> ${HOME}/.cabal/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config+      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config++      grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'++      cabal new-update head.hackage -v+    fi+  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+  - if [ $HCNUMVER -ge 80000 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin doctest --constraint='doctest ==0.16.*'; fi+  - if [ $HCNUMVER -eq 80403 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin hlint --constraint='hlint ==2.1.*'; fi+  - "printf 'packages: \".\"\\n' > cabal.project"+  - echo 'package haskell-ci' >> cabal.project+  - "echo '  ghc-options: -Werror' >> cabal.project"+  - touch cabal.project.local+  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- haskell-ci | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - cat cabal.project || true+  - cat cabal.project.local || true+  - if [ -f "./configure.ac" ]; then+      (cd "." && autoreconf -i);+    fi+  - rm -f cabal.project.freeze+  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all+  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file="cabal.project" --dep -j2 all+  - rm -rf .ghc.environment.* "."/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+  # test that source-distributions can be generated+  - (cd "." && cabal sdist)+  - mv "."/dist/haskell-ci-*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - "printf 'packages: haskell-ci-*/*.cabal\\n' > cabal.project"+  - echo 'package haskell-ci' >> cabal.project+  - "echo '  ghc-options: -Werror' >> cabal.project"+  - touch cabal.project.local+  - "if ! $NOINSTALLEDCONSTRAINTS; then for pkg in $($HCPKG list --simple-output); do echo $pkg  | grep -vw -- haskell-ci | sed 's/^/constraints: /' | sed 's/-[^-]*$/ installed/' >> cabal.project.local; done; fi"+  - cat cabal.project || true+  - cat cabal.project.local || true+  # this builds all libraries and executables (without tests/benchmarks)+  - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all++  # build & run tests, build benchmarks+  - cabal new-build -w ${HC} ${TEST} ${BENCH} all+  - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all; fi++  # doctest+  - if [ $HCNUMVER -ge 80000 ]; then (cd haskell-ci-* && doctest --fast src); fi++  # hlint+  - if [ $HCNUMVER -eq 80403 ]; then (cd haskell-ci-* && hlint -h ${ROOTDIR}/.hlint.yaml src); fi++  # cabal check+  - (cd haskell-ci-* && cabal check)++  # haddock+  - rm -rf ./dist-newstyle+  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi++  # Build without installed constraints for packages in global-db+  - if $UNCONSTRAINED; then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all; else echo "Not building without installed constraints"; fi++  # Constraint sets+  - rm -rf cabal.project.local++  # Constraint set deepseq-1.4+  - echo Constraint set deepseq-1.4 && echo -en 'travis_fold:start:constraint-sets-deepseq-1.4\\r'+  - if [ $HCNUMVER -ge 70800 ] && [ $HCNUMVER -lt 71000 ]  ||  [ $HCNUMVER -eq 80202 ]; then cabal new-build -w ${HC} --disable-tests --disable-benchmarks --constraint='deepseq ==1.4.*' all; else echo skipping...; fi++  - echo -en 'travis_fold:end:constraint-sets-deepseq-1.4\\r'++# REGENDATA ["-o",".travis.yml","--config=cabal.haskell-ci","haskell-ci.cabal"]+# EOF
+ fixtures/servant-client-core/servant-client-core.cabal view
@@ -0,0 +1,75 @@+name:                servant-client-core+version:             0.11+synopsis:            Core functionality and class for client function generation for servant APIs+description:+  This library provides backend-agnostic generation of client functions. For+  more information, see the README.+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+homepage:            http://haskell-servant.readthedocs.org/+bug-reports:         http://github.com/haskell-servant/servant/issues+cabal-version:       >=1.10+copyright:           2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors+category:            Web+build-type:          Simple+tested-with:         GHC >= 7.10+extra-source-files:+  include/*.h+  CHANGELOG.md+  README.md+source-repository head+  type:              git+  location:          http://github.com/haskell-servant/servant.git++library+  exposed-modules:+      Servant.Client.Core+      Servant.Client.Core.Reexport+      Servant.Client.Core.Internal.Auth+      Servant.Client.Core.Internal.BaseUrl+      Servant.Client.Core.Internal.BasicAuth+      Servant.Client.Core.Internal.Generic+      Servant.Client.Core.Internal.HasClient+      Servant.Client.Core.Internal.Request+      Servant.Client.Core.Internal.RunClient+  build-depends:+      base                  >= 4.7      && < 4.11+    , base-compat           >= 0.9.1    && < 0.10+    , base64-bytestring     >= 1.0.0.1  && < 1.1+    , bytestring            >= 0.10     && < 0.11+    , containers            >= 0.5      && < 0.6+    , exceptions            >= 0.8      && < 0.9+    , generics-sop          >= 0.1.0.0  && < 0.4+    , http-api-data         >= 0.3.6    && < 0.4+    , http-media            >= 0.6.2    && < 0.8+    , http-types            >= 0.8.6    && < 0.10+    , mtl                   >= 2.1      && < 2.3+    , network-uri           >= 2.6      && < 2.7+    , safe                  >= 0.3.9    && < 0.4+    , servant               == 0.11.*+    , text                  >= 1.2      && < 1.3+  if !impl(ghc >= 8.0)+    build-depends:+        semigroups          >=0.16.2.2 && <0.19+  hs-source-dirs:      src+  default-language:    Haskell2010+  ghc-options:         -Wall+  include-dirs:        include++test-suite spec+  type:                exitcode-stdio-1.0+  ghc-options:         -Wall+  default-language:    Haskell2010+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:+      base+    , base-compat+    , deepseq+    , servant-client-core+    , hspec == 2.*+    , QuickCheck >= 2.7 && < 2.11+  other-modules:+      Servant.Client.Core.Internal.BaseUrlSpec
+ fixtures/servant-client/servant-client.cabal view
@@ -0,0 +1,94 @@+name:                servant-client+version:             0.11+synopsis: automatical derivation of querying functions for servant webservices+description:+  This library lets you derive automatically Haskell functions that+  let you query each endpoint of a <http://hackage.haskell.org/package/servant servant> webservice.+  .+  See <http://haskell-servant.readthedocs.org/en/stable/tutorial/Client.html the client section of the tutorial>.+  .+  <https://github.com/haskell-servant/servant/blob/master/servant-client/CHANGELOG.md CHANGELOG>+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+copyright:           2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors+category:            Servant, Web+build-type:          Simple+cabal-version:       >=1.10+tested-with:         GHC >= 7.8+homepage:            http://haskell-servant.readthedocs.org/+Bug-reports:         http://github.com/haskell-servant/servant/issues+extra-source-files:+  include/*.h+  CHANGELOG.md+  README.md+source-repository head+  type: git+  location: http://github.com/haskell-servant/servant.git++library+  exposed-modules:+    Servant.Client+    Servant.Client.Internal.HttpClient+  build-depends:+      base                  >= 4.7      && < 4.11+    , base-compat           >= 0.9.1    && < 0.10+    , bytestring            >= 0.10     && < 0.11+    , aeson                 >= 0.7      && < 1.3+    , attoparsec            >= 0.12     && < 0.14+    , containers            >= 0.5      && < 0.6+    , http-client           >= 0.4.30   && < 0.6+    , http-client-tls       >= 0.2.2    && < 0.4+    , http-media            >= 0.6.2    && < 0.8+    , http-types            >= 0.8.6    && < 0.10+    , exceptions            >= 0.8      && < 0.9+    , monad-control         >= 1.0.0.4  && < 1.1+    , mtl                   >= 2.1      && < 2.3+    , semigroupoids         >= 4.3      && < 5.3+    , servant-client-core   == 0.11.*+    , text                  >= 1.2      && < 1.3+    , transformers          >= 0.3      && < 0.6+    , transformers-base     >= 0.4.4    && < 0.5+    , transformers-compat   >= 0.4      && < 0.6+  hs-source-dirs: src+  default-language: Haskell2010+  ghc-options: -Wall+  if impl(ghc >= 8.0)+    ghc-options: -Wno-redundant-constraints+  include-dirs: include++test-suite spec+  type: exitcode-stdio-1.0+  ghc-options: -Wall+  default-language: Haskell2010+  hs-source-dirs: test+  main-is: Spec.hs+  other-modules:+      Servant.ClientSpec+  build-depends:+      base == 4.*+    , aeson+    , base-compat+    , bytestring+    , containers+    , deepseq+    , hspec == 2.*+    , http-api-data+    , http-client+    , http-media+    , http-types+    , HUnit+    , mtl+    , network >= 2.6+    , QuickCheck >= 2.7+    , servant+    , servant-client+    , servant-client-core+    , servant-server == 0.11.*+    , text+    , transformers+    , transformers-compat+    , wai+    , warp+    , generics-sop
+ fixtures/servant-docs/servant-docs.cabal view
@@ -0,0 +1,88 @@+name:                servant-docs+version:             0.11+synopsis:            generate API docs for your servant webservice+description:+  Library for generating API docs from a servant API definition.+  .+  Runnable example <https://github.com/haskell-servant/servant/blob/master/servant-docs/example/greet.hs here>.+  .+  <https://github.com/haskell-servant/servant/blob/master/servant-docs/CHANGELOG.md CHANGELOG>+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+copyright:           2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors+category:            Servant, Web+build-type:          Simple+cabal-version:       >=1.10+tested-with:         GHC >= 7.8+homepage:            http://haskell-servant.readthedocs.org/+Bug-reports:         http://github.com/haskell-servant/servant/issues+extra-source-files:+  include/*.h+  CHANGELOG.md+  README.md+source-repository head+  type: git+  location: http://github.com/haskell-servant/servant.git++library+  exposed-modules:+      Servant.Docs+    , Servant.Docs.Internal+    , Servant.Docs.Internal.Pretty+  build-depends:+      base >=4.7 && <5+    , base-compat >= 0.9.1 && <0.10+    , aeson+    , aeson-pretty+    , bytestring+    , case-insensitive+    , hashable+    , http-media >= 0.6+    , http-types >= 0.7+    , lens+    , servant == 0.11.*+    , string-conversions+    , text+    , unordered-containers+    , control-monad-omega == 0.3.*+  if !impl(ghc >= 8.0)+    build-depends:+      semigroups          >=0.17 && <0.19+  hs-source-dirs: src+  default-language: Haskell2010+  ghc-options: -Wall+  if impl(ghc >= 8.0)+    ghc-options: -Wno-redundant-constraints+  include-dirs: include++executable greet-docs+  main-is: greet.hs+  hs-source-dirs: example+  ghc-options: -Wall+  build-depends:+      base+    , aeson+    , lens+    , servant+    , servant-docs+    , string-conversions+    , text+  default-language: Haskell2010++test-suite spec+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules: Servant.DocsSpec+  hs-source-dirs: test+  ghc-options: -Wall+  build-depends:+      base+    , aeson+    , hspec+    , lens+    , servant+    , servant-docs+    , string-conversions+  default-language: Haskell2010
+ fixtures/servant-foreign/servant-foreign.cabal view
@@ -0,0 +1,85 @@+name:                servant-foreign+version:             0.10.1+synopsis:            Helpers for generating clients for servant APIs in any programming language+description:+  Helper types and functions for generating client functions for servant APIs in any programming language+  .+  This package provides types and functions that collect all the data needed to generate client functions in the programming language of your choice. This effectively means you only have to write the code that "pretty-prints" this data as some code in your target language.+  .+  See the servant-js package for an example+  .+  <https://github.com/haskell-servant/servant/blob/master/servant-foreign/CHANGELOG.md CHANGELOG>+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+copyright:           2015-2016 Servant Contributors+category:            Servant, Web+build-type:          Simple+cabal-version:       >=1.10+tested-with:         GHC >= 7.10+extra-source-files:+  include/*.h+  CHANGELOG.md+  README.md+bug-reports:         http://github.com/haskell-servant/servant/issues+source-repository head+  type: git+  location: http://github.com/haskell-servant/servant.git++library+  exposed-modules:     Servant.Foreign+                     , Servant.Foreign.Internal+                     , Servant.Foreign.Inflections+  build-depends:       base       == 4.*+                     , lens       == 4.*+                     , servant    == 0.11.*+                     , text       >= 1.2  && < 1.3+                     , http-types+  hs-source-dirs:      src+  default-language:    Haskell2010+  ghc-options:         -Wall+  if impl(ghc >= 8.0)+    ghc-options: -Wno-redundant-constraints+  include-dirs: include+  default-extensions:  CPP+                     , ConstraintKinds+                     , DataKinds+                     , FlexibleContexts+                     , FlexibleInstances+                     , GeneralizedNewtypeDeriving+                     , MultiParamTypeClasses+                     , ScopedTypeVariables+                     , StandaloneDeriving+                     , TemplateHaskell+                     , TypeFamilies+                     , TypeOperators+                     , UndecidableInstances+                     , OverloadedStrings+                     , PolyKinds+++test-suite spec+  type:              exitcode-stdio-1.0+  hs-source-dirs:    test+  ghc-options:       -Wall+  include-dirs:      include+  main-is:           Spec.hs+  other-modules:     Servant.ForeignSpec+  build-depends:     base+                   , hspec >= 2.1.8+                   , servant+                   , servant-foreign+  default-language:  Haskell2010+  default-extensions:  ConstraintKinds+                     , DataKinds+                     , FlexibleContexts+                     , FlexibleInstances+                     , GeneralizedNewtypeDeriving+                     , MultiParamTypeClasses+                     , ScopedTypeVariables+                     , TypeFamilies+                     , TypeOperators+                     , UndecidableInstances+                     , OverloadedStrings+                     , PolyKinds
+ fixtures/servant-server/servant-server.cabal view
@@ -0,0 +1,165 @@+name:                servant-server+version:             0.11+synopsis:            A family of combinators for defining webservices APIs and serving them+description:+  A family of combinators for defining webservices APIs and serving them+  .+  You can learn about the basics in the <http://haskell-servant.readthedocs.org/en/stable/tutorial/index.html tutorial>.+  .+  <https://github.com/haskell-servant/servant/blob/master/servant-server/example/greet.hs Here>+  is a runnable example, with comments, that defines a dummy API and implements+  a webserver that serves this API, using this package.+  .+  <https://github.com/haskell-servant/servant/blob/master/servant-server/CHANGELOG.md CHANGELOG>+homepage:            http://haskell-servant.readthedocs.org/+Bug-reports:         http://github.com/haskell-servant/servant/issues+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+copyright:           2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors+category:            Servant, Web+build-type:          Custom+cabal-version:       >=1.10+tested-with:         GHC >= 7.8+extra-source-files:+  include/*.h+  CHANGELOG.md+  README.md+source-repository head+  type: git+  location: http://github.com/haskell-servant/servant.git++custom-setup+  setup-depends:+    base >= 4 && <5,+    Cabal,+    cabal-doctest >= 1.0.1 && <1.1++library+  exposed-modules:+    Servant+    Servant.Server+    Servant.Server.Experimental.Auth+    Servant.Server.Internal+    Servant.Server.Internal.BasicAuth+    Servant.Server.Internal.Context+    Servant.Server.Internal.Handler+    Servant.Server.Internal.Router+    Servant.Server.Internal.RoutingApplication+    Servant.Server.Internal.ServantErr+    Servant.Utils.StaticFiles+  build-depends:+        base               >= 4.7  && < 4.11+      , base-compat        >= 0.9  && < 0.10+      , aeson              >= 0.7  && < 1.3+      , attoparsec         >= 0.12 && < 0.14+      , base64-bytestring  >= 1.0  && < 1.1+      , bytestring         >= 0.10 && < 0.11+      , containers         >= 0.5  && < 0.6+      , exceptions         >= 0.8  && < 0.9+      , http-api-data      >= 0.3  && < 0.4+      , http-types         >= 0.8  && < 0.10+      , network-uri        >= 2.6  && < 2.7+      , monad-control      >= 1.0.0.4 && < 1.1+      , mtl                >= 2    && < 2.3+      , network            >= 2.6  && < 2.7+      , safe               >= 0.3  && < 0.4+      , servant            == 0.11.*+      , split              >= 0.2  && < 0.3+      , string-conversions >= 0.3  && < 0.5+      , system-filepath    >= 0.4  && < 0.5+      , filepath           >= 1    && < 1.5+      , resourcet          >= 1.1.6 && <1.2+      , tagged             >= 0.7.3 && <0.9+      , text               >= 1.2  && < 1.3+      , transformers       >= 0.3  && < 0.6+      , transformers-base  >= 0.4.4 && < 0.5+      , transformers-compat>= 0.4  && < 0.6+      , wai                >= 3.0  && < 3.3+      , wai-app-static     >= 3.1  && < 3.2+      , warp               >= 3.0  && < 3.3+      , word8              >= 0.1  && < 0.2++  hs-source-dirs: src+  default-language: Haskell2010+  ghc-options: -Wall+  if impl(ghc >= 8.0)+    ghc-options: -Wno-redundant-constraints+  include-dirs: include++executable greet+  main-is: greet.hs+  hs-source-dirs: example+  ghc-options: -Wall+  default-language: Haskell2010+  build-depends:+      base+    , servant+    , servant-server+    , aeson+    , warp+    , wai+    , text++test-suite spec+  type: exitcode-stdio-1.0+  ghc-options: -Wall+  default-language: Haskell2010+  hs-source-dirs: test+  main-is: Spec.hs+  other-modules:+      Servant.ArbitraryMonadServerSpec+      Servant.Server.ErrorSpec+      Servant.Server.Internal.ContextSpec+      Servant.Server.Internal.RoutingApplicationSpec+      Servant.Server.RouterSpec+      Servant.Server.StreamingSpec+      Servant.Server.UsingContextSpec+      Servant.Server.UsingContextSpec.TestCombinators+      Servant.ServerSpec+      Servant.Utils.StaticFilesSpec+  build-depends:+      base == 4.*+    , base-compat+    , aeson+    , base64-bytestring+    , bytestring+    , directory+    , exceptions+    , hspec == 2.*+    , hspec-wai >= 0.8 && <0.9+    , http-types+    , mtl+    , network >= 2.6+    , parsec+    , QuickCheck+    , resourcet+    , safe+    , servant+    , servant-server+    , should-not-typecheck == 2.1.*+    , string-conversions+    , temporary+    , text+    , transformers+    , transformers-compat+    , wai+    , wai-extra+    , warp++test-suite doctests+ build-depends: base+              , servant+              , doctest+              , filemanip+              , directory+              , filepath+ type: exitcode-stdio-1.0+ main-is: test/doctests.hs+ buildable: True+ default-language: Haskell2010+ ghc-options: -Wall -threaded+ if impl(ghc >= 8.2)+   x-doctest-options: -fdiagnostics-color=never+ include-dirs: include
+ fixtures/servant/servant.cabal view
@@ -0,0 +1,157 @@+name:                servant+version:             0.11+synopsis:            A family of combinators for defining webservices APIs+description:+  A family of combinators for defining webservices APIs and serving them+  .+  You can learn about the basics in the <http://haskell-servant.readthedocs.org/en/stable/tutorial/index.html tutorial>.+  .+  <https://github.com/haskell-servant/servant/blob/master/servant/CHANGELOG.md CHANGELOG>+homepage:            http://haskell-servant.readthedocs.org/+Bug-reports:         http://github.com/haskell-servant/servant/issues+license:             BSD3+license-file:        LICENSE+author:              Servant Contributors+maintainer:          haskell-servant-maintainers@googlegroups.com+copyright:           2014-2016 Zalora South East Asia Pte Ltd, Servant Contributors+category:            Servant, Web+build-type:          Custom+cabal-version:       >=1.10+tested-with:         GHC >= 7.8+extra-source-files:+  include/*.h+  CHANGELOG.md+source-repository head+  type: git+  location: http://github.com/haskell-servant/servant.git++custom-setup+  setup-depends:+    base >= 4 && <5,+    Cabal,+    cabal-doctest >= 1.0.2 && <1.1++library+  exposed-modules:+    Servant.API+    Servant.API.Alternative+    Servant.API.BasicAuth+    Servant.API.Capture+    Servant.API.ContentTypes+    Servant.API.Description+    Servant.API.Empty+    Servant.API.Experimental.Auth+    Servant.API.Header+    Servant.API.HttpVersion+    Servant.API.Internal.Test.ComprehensiveAPI+    Servant.API.IsSecure+    Servant.API.QueryParam+    Servant.API.Raw+    Servant.API.RemoteHost+    Servant.API.ReqBody+    Servant.API.ResponseHeaders+    Servant.API.Sub+    Servant.API.TypeLevel+    Servant.API.Vault+    Servant.API.Verbs+    Servant.API.WithNamedContext+    Servant.Utils.Links+    Servant.Utils.Enter+  build-depends:+      base                  >= 4.7  && < 4.11+    , base-compat           >= 0.9  && < 0.10+    , aeson                 >= 0.7  && < 1.3+    , attoparsec            >= 0.12 && < 0.14+    , bytestring            >= 0.10 && < 0.11+    , case-insensitive      >= 1.2  && < 1.3+    , http-api-data         >= 0.3  && < 0.4+    , http-media            >= 0.4  && < 0.8+    , http-types            >= 0.8  && < 0.10+    , natural-transformation >= 0.4 && < 0.5+    , mtl                   >= 2.0  && < 2.3+    , mmorph                >= 1    && < 1.2+    , tagged                >= 0.7.3 && < 0.9+    , text                  >= 1    && < 1.3+    , string-conversions    >= 0.3  && < 0.5+    , network-uri           >= 2.6  && < 2.7+    , vault                 >= 0.3  && < 0.4++  if !impl(ghc >= 8.0)+    build-depends:+      semigroups            >= 0.16 && < 0.19++  hs-source-dirs: src+  default-language: Haskell2010+  other-extensions: CPP+                  , ConstraintKinds+                  , DataKinds+                  , DeriveDataTypeable+                  , FlexibleInstances+                  , FunctionalDependencies+                  , GADTs+                  , KindSignatures+                  , MultiParamTypeClasses+                  , OverlappingInstances+                  , OverloadedStrings+                  , PolyKinds+                  , QuasiQuotes+                  , RecordWildCards+                  , ScopedTypeVariables+                  , TemplateHaskell+                  , TypeFamilies+                  , TypeOperators+                  , TypeSynonymInstances+                  , UndecidableInstances+  ghc-options: -Wall+  if impl(ghc >= 8.0)+    ghc-options: -Wno-redundant-constraints+  include-dirs: include++test-suite spec+  type: exitcode-stdio-1.0+  ghc-options: -Wall+  default-language: Haskell2010+  hs-source-dirs: test+  main-is: Spec.hs+  other-modules:+      Servant.API.ContentTypesSpec+      Servant.API.ResponseHeadersSpec+      Servant.Utils.LinksSpec+      Servant.Utils.EnterSpec+  build-depends:+      base == 4.*+    , base-compat+    , aeson+    , aeson-compat >=0.3.3 && <0.4+    , attoparsec+    , bytestring+    , hspec == 2.*+    , QuickCheck+    , quickcheck-instances+    , servant+    , string-conversions+    , text+    , url++  if !impl(ghc >= 8.0)+    build-depends:+      semigroups            >= 0.16 && < 0.19++test-suite doctests+ build-depends: base+              , servant+              , doctest+              , filemanip+              , directory+              , filepath+              , hspec+ type: exitcode-stdio-1.0+ main-is: test/doctests.hs+ buildable: True+ default-language: Haskell2010+ ghc-options: -Wall -threaded+ if impl(ghc >= 8.2)+   x-doctest-options: -fdiagnostics-color=never+ include-dirs: include+ x-doctest-source-dirs: test+ x-doctest-modules: Servant.Utils.LinksSpec
+ haskell-ci.cabal view
@@ -0,0 +1,121 @@+cabal-version:       1.18+name:                haskell-ci+version:             0.1.0.0++synopsis:            Cabal package script generator for Travis-CI+description:+  Script generator (@make-travis-yml@) for [Travis-CI](https://travis-ci.org/) for continuous-integration testing of Haskell Cabal packages.+  .+  Included features (not limited to):+  .+  * Multiple GHC support+  * Dependency caching+  * cabal.project support (see [Nix-style local builds documentation](http://cabal.readthedocs.io/en/latest/nix-local-build-overview.html)+  * Runs tests and builds benchmarks+  * Generates Haddocks+  * macOS (OSX) support+  * building with specific constraints+  .+  === Quick Start Guide+  .+  Add a @tested-with@ line to your @.cabal@ file (e.g. @tested-with: GHC == 8.0.2 || == 8.2.2@) and then run @make-travis-yml yourpackage.cabal -o .travis.yml@ to generate the Travis-CI job script.+  .+  See @make-travis-yml --help@ for more information.++  +homepage:            http://haskell-ci.rtfd.org/+bug-reports:         https://github.com/haskell-CI/haskell-ci/issues+license:             BSD3+license-file:        LICENSE+author:              Herbert Valerio Riedel, Oleg Grenrus+maintainer:          hvr@gnu.org+category:            Development+build-type:          Simple+tested-with:+  GHC == 7.8.4,+  GHC == 7.10.3,+  GHC == 8.0.2,+  GHC == 8.2.2,+  GHC == 8.4.3,+  GHC == 8.6.1+extra-source-files:+  fixtures/cabal.haskell-ci+  fixtures/haskell-ci.cabal+  fixtures/haskell-ci.cabal.stderr+  fixtures/haskell-ci.cabal.travis.yml+  fixtures/cabal.project.empty-line+  fixtures/cabal.project.empty-line.stderr+  fixtures/cabal.project.empty-line.travis.yml+  fixtures/cabal.project.fail-versions+  fixtures/cabal.project.fail-versions.stderr+  fixtures/cabal.project.messy+  fixtures/cabal.project.messy.stderr+  fixtures/cabal.project.messy.travis.yml+  fixtures/doc/tutorial/tutorial.cabal+  fixtures/servant-client-core/*.cabal+  fixtures/servant-client/*.cabal+  fixtures/servant-docs/*.cabal+  fixtures/servant-foreign/*.cabal+  fixtures/servant-server/*.cabal+  fixtures/servant/*.cabal++source-repository head+  type: git+  location: https://github.com/haskell-CI/haskell-ci.git++flag ShellCheck+  default: True+  manual: True++library+  exposed-modules:     MakeTravisYml+  ghc-options:         -Wall+  if impl(ghc >= 8.0)+    ghc-options:+      -Wcompat+      -Wnoncanonical-monad-instances+      -Wnoncanonical-monadfail-instances+  hs-source-dirs:      src+  other-extensions:    CPP, ViewPatterns, NamedFieldPuns+  build-depends:       base         >= 4.7  && < 4.12+                     , Cabal        == 1.18.*+                                 || == 1.20.*+                                 || == 1.22.*+                                 || == 1.24.*+                                 || == 2.0.*+                                 || == 2.2.*+                     , containers   >= 0.4  && < 0.6+                     , directory    >= 1.1  && < 1.4+                     , filepath     >= 1.2  && < 1.5+                     , transformers >= 0.3  && < 0.6+                     , deepseq      >= 1.3  && < 1.5+  default-language:    Haskell2010++  -- ShellCheck. Would need newer transformers for older GHC+  if flag(ShellCheck) && impl(ghc >= 7.10 && <8.5)+    build-depends: ShellCheck == 0.5.0++executable make-travis-yml+  main-is:             Main.hs+  ghc-options:         -Wall+  build-depends:       base, haskell-ci+  default-language:    Haskell2010++test-suite golden+  type:                exitcode-stdio-1.0+  main-is:             Tests.hs+  hs-source-dirs:      test+  build-depends:       haskell-ci+                       -- inherited constraints via lib:haskell-ci+                     , base+                     , bytestring+                     , directory+                     , filepath+                     , transformers+                       -- dependencies needing explicit constraints+                     , tasty         >= 1.0      && < 1.2+                     , tasty-golden  >= 2.3.1.1  && < 2.4+                     , ansi-terminal >= 0.8.0.2  && <0.9+                     , Diff          >= 0.3.4    && < 0.4++  default-language:    Haskell2010
+ src/MakeTravisYml.hs view
@@ -0,0 +1,1905 @@+{-# LANGUAGE Haskell2010 #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}++#if !defined(MIN_VERSION_Cabal)+-- As a heuristic, if the macro isn't defined, be pessimistic and+-- assume an "old" Cabal version+# define MIN_VERSION_Cabal(x,y,z) 0+#endif++-- | New-style @.travis.yml@ script generator using cabal 1.24's nix-style+-- tech-preview facilities.+--+-- See also <https://github.com/haskell-CI/haskell-ci>+--+-- NB: This code deliberately avoids relying on non-standard packages and+--     is expected to compile/work with at least GHC 7.0 through GHC 8.0+module MakeTravisYml (+    main,+    -- * for tests+    Result (..),+    Diagnostic (..),+    parseOptsNoCommands,+    formatDiagnostic, formatDiagnostics,+    travisFromConfigFile, MakeTravisOutput, Options (..), defOptions, options,+    ) where++import Control.Applicative as App ((<$>),(<|>), pure)+import Control.DeepSeq (force)+import Control.Exception (evaluate)+import Control.Monad (void, when, unless, filterM, liftM, liftM2, forM_, mzero, foldM, join)+import Data.Char (isSpace, isUpper, toLower)+import qualified Data.Foldable as F+import qualified Data.Traversable as T+import Data.Function+import Data.List+import Data.Maybe+import Data.Monoid as Mon (Monoid (..), Endo (..))+import Data.Either (partitionEithers)+import Data.Set (Set)+import qualified Data.Set as S+import qualified Data.Map as M+import System.Console.GetOpt+import System.Directory (doesDirectoryExist, getDirectoryContents, doesFileExist)+import System.Environment+import System.Exit+import System.FilePath.Posix ((</>), takeDirectory, takeFileName, takeExtension)+import System.IO+import Control.Monad.IO.Class+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Writer+import Text.Read (readMaybe)++import Distribution.Compiler (CompilerFlavor(..))+import Distribution.Package hiding (Package, pkgName)+import qualified Distribution.Package as Pkg+import Distribution.PackageDescription (GenericPackageDescription,packageDescription, testedWith, package, condLibrary, condTestSuites)+import Distribution.PackageDescription.Configuration (flattenPackageDescription)+import qualified Distribution.PackageDescription as PD+import qualified Distribution.ParseUtils as PU+import Distribution.Text+import Distribution.Version+#if MIN_VERSION_Cabal(2,2,0)+import Distribution.PackageDescription.Parsec (readGenericPackageDescription)+#elif MIN_VERSION_Cabal(2,0,0)+import Distribution.PackageDescription.Parse (readGenericPackageDescription)+#else+import Distribution.PackageDescription.Parse (readPackageDescription)+import Distribution.Verbosity (Verbosity)+#endif+import Distribution.Compat.ReadP+    ( ReadP, (<++), (+++), between, char, many1, munch1+    , pfail, readP_to_S, readS_to_P, look+    , satisfy, sepBy, sepBy1, gather, munch, skipSpaces)++#ifdef MIN_VERSION_ShellCheck+import ShellCheck.Checker (checkScript)+import qualified ShellCheck.Interface as SC+import qualified ShellCheck.Formatter.Format as SC+import qualified ShellCheck.Formatter.TTY as SC.TTY+import System.IO.Unsafe (unsafePerformIO)+#endif++#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup (..))+#else+import Data.Monoid ((<>))+#endif++#if !(MIN_VERSION_Cabal(2,0,0))+-- compat helpers for pre-2.0++readGenericPackageDescription :: Verbosity -> FilePath -> IO GenericPackageDescription+readGenericPackageDescription = readPackageDescription++mkVersion :: [Int] -> Version+mkVersion vn = Version vn []++versionNumbers :: Version -> [Int]+versionNumbers (Version vn _) = vn++#endif++-------------------------------------------------------------------------------+-- Hardcoded values+-------------------------------------------------------------------------------++knownGhcVersions :: [Version]+knownGhcVersions = fmap mkVersion+    [ [7,0,1],  [7,0,2], [7,0,3], [7,0,4]+    , [7,2,1],  [7,2,2]+    , [7,4,1],  [7,4,2]+    , [7,6,1],  [7,6,2], [7,6,3]+    , [7,8,1],  [7,8,2], [7,8,3], [7,8,4]+    , [7,10,1], [7,10,2], [7,10,3]+    , [8,0,1],  [8,0,2]+    , [8,2,1],  [8,2,2]+    , [8,4,1],  [8,4,2], [8,4,3]+    , [8,6,1]+    ]++ghcAlpha :: Maybe Version+-- ghcAlpha = Nothing+ghcAlpha = Just (mkVersion [8,6,1])++cabalVerMap :: [((Int, Int), Maybe Version)]+cabalVerMap = fmap (fmap (fmap mkVersion))+    [ ((7, 0), Just [2,2]) -- Use 2.2 for everything.+    , ((7, 2), Just [2,2])+    , ((7, 4), Just [2,2])+    , ((7, 6), Just [2,2])+    , ((7, 8), Just [2,2])+    , ((7,10), Just [2,2])+    , ((8, 0), Just [2,2])+    , ((8, 2), Just [2,2])+    , ((8, 4), Just [2,2])+    ]++defaultHLintVersion :: VersionRange+defaultHLintVersion = withinVersion (mkVersion [2,1])++defaultDoctestVersion :: VersionRange+defaultDoctestVersion = withinVersion (mkVersion [0,16])++-------------------------------------------------------------------------------+-- Script+-------------------------------------------------------------------------------++-- |  Encode shell command to be YAML safe and (optionally) ShellCheck it.+sh :: String -> String+sh = sh'+    [ 2034 -- VAR appears unused. Verify it or export it.+    , 2086 -- SC2086: Double quote to prevent globbing and word splitting.+    ]++-- | Like 'sh' but with explicit SC exclude codes.+sh' :: [Integer] -> String -> String+#ifndef MIN_VERSION_ShellCheck+sh' _ = shImpl+#else+sh' excl cmd = unsafePerformIO $ do+  res <- checkScript iface spec+  case res of+    (SC.CheckResult _ []) -> return (shImpl cmd)+    _                     -> SC.onResult scFormatter res iface >> fail "ShellCheck!"+  where+    iface = SC.SystemInterface $ \n -> return $ Left $ "cannot read file: " ++ n+    spec  = SC.emptyCheckSpec { SC.csFilename = "stdin"+                              , SC.csScript = cmd+                              , SC.csExcludedWarnings = excl+                              , SC.csShellTypeOverride = Just SC.Sh+                              }++scFormatter :: SC.Formatter+scFormatter = unsafePerformIO (SC.TTY.format (SC.FormatterOptions SC.ColorAlways))+#endif++-- Non-ShellCheck version of sh'+shImpl :: String -> String+shImpl cmd+    | ':' `elem` cmd = "  - " ++ show cmd+    | otherwise      = "  - " ++ cmd++comment :: String -> String+comment = ("  # " ++)++type MakeTravisOutput = Result Diagnostic [String]++data Diagnostic+    = Info String+    | Warn String+    | Error String+  deriving (Eq, Show)++formatDiagnostics :: [Diagnostic] -> String+formatDiagnostics = unlines . map formatDiagnostic++formatDiagnostic :: Diagnostic -> String+formatDiagnostic (Error s) = "*ERROR* " ++ s+formatDiagnostic (Warn  s) = "*WARNING* " ++ s+formatDiagnostic (Info  s) = "*INFO* " ++ s++-- MaybeT is used to preserve the short-circuiting semantics of 'putStrLnErr'.+type YamlWriter m a = MaybeT (WriterT MakeTravisOutput m) a++putStrLnErr :: Monad m => String -> YamlWriter m a+putStrLnErr m = do+    lift . tell $ Failure [Error m]+    mzero++putStrLnErrs :: Monad m => [String] -> YamlWriter m ()+putStrLnErrs [] = return ()+putStrLnErrs ms = do+    lift (tell (Failure (map Error ms)))+    mzero++putStrLnWarn, putStrLnInfo :: Monad m => String -> YamlWriter m ()+putStrLnWarn m = lift . tell $ Success [Warn m] []+putStrLnInfo m = lift . tell $ Success [Info m] []++tellStrLn :: Monad m => String -> YamlWriter m ()+tellStrLn str = lift . tell $ success [str]++tellStrLns :: Monad m => [String] -> YamlWriter m ()+tellStrLns = lift . tell . success++foldedTellStrLns+    :: Monad m+    => Fold+    -> String+    -> Set Fold+    -> YamlWriter m ()+    -> YamlWriter m ()+foldedTellStrLns label = foldedTellStrLns' label ""++foldedTellStrLns'+    :: Monad m+    => Fold+    -> String+    -> String+    -> Set Fold+    -> YamlWriter m ()+    -> YamlWriter m ()+foldedTellStrLns' label pfx prettyLabel labels output+    | label `S.notMember` labels = output+    | otherwise = tellStrLns [prologue] >> output >> tellStrLns epilogue+  where+    prologue = mconcat+        [ "  - echo ", prettyLabel+        , " && echo -en 'travis_fold:start:", showFold' label, "\\\\r'" ]+    epilogue = ["  - echo -en 'travis_fold:end:" ++ showFold' label ++ "\\\\r'" ]++    showFold' l = showFold l ++ if null pfx then "" else "-" ++ pfx++-- | Return the part after the first argument+--+-- >>> afterInfix "BAR" "FOOBAR XYZZY"+-- Just " XYZZY"+--+afterInfix :: Eq a => [a] -> [a] -> Maybe [a]+afterInfix needle haystack = findMaybe (afterPrefix needle) (tails haystack)++-- |+--+-- >>> afterPrefix "FOO" "FOOBAR"+-- Just "BAR"+--+afterPrefix :: Eq a => [a] -> [a] -> Maybe [a]+afterPrefix needle haystack+    | needle `isPrefixOf` haystack = Just (drop (length needle) haystack)+    | otherwise                    = Nothing++-- |+--+-- >>> findMaybe readMaybe ["foo", "1", "bar"] :: Maybe Int+-- Just 1+--+findMaybe :: (a -> Maybe b) -> [a] -> Maybe b+findMaybe f = foldr (\a b -> f a App.<|> b) Nothing++-- | >>> maybeReadP PU.parseTokenQ' "foo"+-- Just "foo"+maybeReadP :: ReadP a a -> String -> Maybe a+maybeReadP p s = listToMaybe $+    [ x+    | (x, rest) <- readP_to_S p s+    , all isSpace rest+    ]++main :: IO ()+main = do+    argv <- getArgs+    (opts,argv',configFile,xpkgs) <- parseOpts argv+    genTravisFromConfigFile (argv',opts) configFile xpkgs++parseOpts :: [String] -> IO (Options, [String], FilePath, [String])+parseOpts argv = case argv of+    (cmd : argv') | cmd `isPrefixOf` "regenerate" -> do+        let fp = fromMaybe  ".travis.yml" $ listToMaybe argv'+        ls <- fmap lines (readFile fp >>= evaluate . force) -- strict IO+        case findArgv ls of+            Nothing     -> dieCli [Error $ "expected REGENDATA line in " ++ fp ++ "\n"]+            Just argv'' -> parseOpts argv''+    [cmd] | cmd `isPrefixOf` "list-ghc" -> do+        putStrLn $ "Supported GHC versions:"+        forM_ groupedVersions $ \(v, vs) -> do+            putStr $ prettyMajVersion v ++ ": "+            putStrLn $ intercalate ", " (map display vs)+        exitSuccess+    _ -> parseOptsNoCommands argv+  where+    groupedVersions :: [(Version, [Version])]+    groupedVersions = map ((\vs -> (head vs, vs)) . sortBy (flip compare))+                    . groupBy ((==) `on` ghcMajVer)+                    $ sort knownGhcVersions++    prettyMajVersion :: Version -> String+    prettyMajVersion v+        | Just v == ghcAlpha = "alpha"+        | otherwise = case ghcMajVer v of (x,y) -> show x ++ "." ++ show y++    findArgv :: [String] -> Maybe [String]+    findArgv ls = do+        l <- findMaybe (afterInfix "REGENDATA") ls+        readMaybe l++-- Returns options, used argv, cabal file, xpkgs+parseOptsNoCommands :: [String] -> IO (Options, [String], FilePath, [String])+parseOptsNoCommands argv = case getOpt Permute options argv of+    (opts',configFile:xpkgs,[]) -> do+        opts <- foldOptions defOptions opts'+        return (opts,argv,configFile,xpkgs)+    (_,_,[]) -> dieCli [Error "expected .cabal or cabal.project file as first non-option argument\n"]+    (_,_,errs) -> dieCli (map Error errs)+  where+    foldOptions :: Options -> [Result Diagnostic (Options -> Options)] -> IO Options+    foldOptions def opts = case foldOptions' def opts of+        Success ws x -> do+            hPutStr stderr (formatDiagnostics ws)+            return x+        Failure errs -> dieCli errs++    foldOptions' :: Options -> [Result e (Options -> Options)] -> Result e Options+    foldOptions' opts = fmap (`appEndo` opts) . F.foldMap (fmap Endo)++dieCli ::  [Diagnostic] -> IO a+dieCli errs = hPutStrLn stderr (usageMsg errs) >> exitFailure+ where+    usageMsg errs' = formatDiagnostics errs' ++ usageInfo h options ++ ex++    h = intercalate "\n"+        [ "Usage: runghc make_travis_yml_2.hs [OPTIONS] <cabal-file | cabal.project> <extra-apt-packages...>"+        , ""+        , "Available commands:"+        , "    regenerate [TRAVIS.YAML]  Regenerate the file using the magic command in it. Default .travis.yml"+        , "    list-ghc                  List GHC versions supported by this version of make-travis-yml"+        , ""+        , "Available options:"+        ]++    ex = unlines+        [ ""+        , "Example:"+        , "    runghc make_travis_yml_2.hs -o .travis.yml someProject.cabal liblzma-dev"+        ]++runYamlWriter :: Maybe FilePath -> YamlWriter IO () -> IO ()+runYamlWriter mfp m = do+    result <- execWriterT (runMaybeT m)+    case result of+        Failure (formatDiagnostics -> errors) -> hPutStr stderr errors >> exitFailure+        Success (formatDiagnostics -> warnings) (unlines -> contents) -> do+            contents' <- evaluate (force contents)+            hPutStr stderr warnings+            case mfp of+                Nothing -> putStr contents'+                Just fp -> writeFile fp contents'++ghcMajVer :: Version -> (Int,Int)+ghcMajVer v+    | x:y:_ <- versionNumbers v = (x,y)+    | otherwise = error $ "panic: ghcMajVer called with " ++ show v++-- | Alphas, RCs and HEAD.+previewGHC :: Maybe Version -> Bool+previewGHC = maybe True $ \v -> Just v == ghcAlpha || odd (snd (ghcMajVer v))++dispGhcVersion :: Maybe Version -> String+dispGhcVersion = maybe "head" display++data Package = Pkg+    { pkgName :: String+    , pkgDir :: FilePath+    , pkgGpd :: GenericPackageDescription+    } deriving (Eq, Show)++genTravisFromConfigFile :: ([String],Options) -> FilePath -> [String] -> IO ()+genTravisFromConfigFile args@(_, opts) path xpkgs =+    runYamlWriter (optOutput opts) $ travisFromConfigFile args path xpkgs++travisFromConfigFile+    :: MonadIO m+    => ([String],Options)+    -> FilePath+    -> [String]+    -> YamlWriter m ()+travisFromConfigFile args@(_, opts) path xpkgs = do+    cabalFiles <- getCabalFiles+    config' <- maybe (return emptyConfig) readConfigFile (optConfig opts)+    let config = optConfigMorphism opts config'+    pkgs <- T.mapM (configFromCabalFile config opts) cabalFiles+    (ghcs, prj) <- checkVersions pkgs+    genTravisFromConfigs args xpkgs isCabalProject config prj ghcs+  where+    checkVersions+        :: MonadIO m+        => Project (Package, Set Version)+        -> YamlWriter m (Set Version, Project Package)+    checkVersions prj | null (prjPackages prj) = putStrLnErr "Error reading cabal file(s)!"+    checkVersions prj = do+        let (errors, names) = F.foldl' collectConfig mempty prj+        putStrLnErrs errors+        return (allVersions, prj { prjPackages = names })+      where+        allVersions = F.foldMap snd prj++        collectConfig+            :: ([String], [Package])+            -> (Package, Set Version)+            -> ([String], [Package])+        collectConfig aggregate (pkg, testWith) =+            aggregate <> (errors, [pkg])+          where+            symDiff a b = S.union a b `S.difference` S.intersection a b+            diff = symDiff testWith allVersions+            missingVersions = map display $ S.toList diff+            errors | S.null diff = []+                   | otherwise = App.pure $ mconcat+                        [ pkgName pkg+                        , " is missing tested-with annotations for: "+                        ] ++ intercalate "," missingVersions++    isCabalProject :: Maybe FilePath+    isCabalProject+        | "cabal.project" `isPrefixOf` takeFileName path = Just path+        | otherwise = Nothing++    getCabalFiles :: MonadIO m => YamlWriter m (Project FilePath)+    getCabalFiles+        | isNothing isCabalProject = return (Project [path] Nothing Nothing)+        | otherwise = do+            contents <- liftIO $ readFile path+            pkgs <- either putStrLnErr return $ parseProjectFile path contents+            overPrjPackages concat `liftM` T.mapM findProjectPackage pkgs++    rootdir = takeDirectory path++    -- See findProjectPackages in cabal-install codebase+    -- this is simple variant.+    findProjectPackage :: MonadIO m => String -> YamlWriter m [FilePath]+    findProjectPackage pkglocstr = do+        mfp <- checkisFileGlobPackage pkglocstr `mplusMaybeT`+               checkIsSingleFilePackage pkglocstr+        maybe (putStrLnErr $ "bad package location: " ++ pkglocstr) return mfp++    checkIsSingleFilePackage pkglocstr = do+        let abspath = rootdir </> pkglocstr+        isFile <- liftIO $ doesFileExist abspath+        isDir  <- liftIO $ doesDirectoryExist abspath+        if | isFile && takeExtension pkglocstr == ".cabal" -> return (Just [abspath])+           | isDir -> checkisFileGlobPackage (pkglocstr </> "*.cabal")+           | otherwise -> return Nothing++    -- if it looks like glob, glob+    checkisFileGlobPackage pkglocstr =+        case filter (null . snd) $ readP_to_S parseFilePathGlobRel pkglocstr of+            [(g, "")] -> do+                files <- liftIO $ expandRelGlob rootdir g+                let files' = filter ((== ".cabal") . takeExtension) files+                -- if nothing is matched, skip.+                if null files' then return Nothing else return (Just files')+            _         -> return Nothing++    mplusMaybeT :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)+    mplusMaybeT ma mb = do+        mx <- ma+        case mx of+            Nothing -> mb+            Just x  -> return (Just x)++configFromCabalFile+    :: MonadIO m => Config ->  Options -> FilePath -> YamlWriter m (Package, Set Version)+configFromCabalFile cfg opts cabalFile = do+    gpd <- liftIO $ readGenericPackageDescription maxBound cabalFile++    let compilers = testedWith $ packageDescription gpd+        pkgNameStr = display $ Pkg.pkgName $ package $ packageDescription gpd++    let unknownComps = nub [ c | (c,_) <- compilers, c /= GHC ]+        ghcVerConstrs = [ vc | (GHC,vc) <- compilers ]+        ghcVerConstrs' = simplifyVersionRange $ foldr unionVersionRanges noVersion ghcVerConstrs+        twoDigitGhcVerConstrs = mapMaybe isTwoDigitGhcVersion ghcVerConstrs :: [Version]+        specificGhcVers = nub $ mapMaybe isSpecificVersion ghcVerConstrs++    unless (null twoDigitGhcVerConstrs) $ do+        putStrLnWarn $ "'tested-with:' uses two digit GHC versions (which don't match any existing GHC version): " ++ intercalate ", " (map display twoDigitGhcVerConstrs)+        putStrLnInfo $ "Either use wild-card format, for example 'tested-with: GHC ==7.10.*' or a specific existing version 'tested-with: GHC ==7.10.3'"++    when (null compilers) $ do+        putStrLnErr (unlines $+                     [ "empty or missing top-level 'tested-with:' definition in " ++ cabalFile ++ " file; example definition:"+                     , ""+                     , "tested-with: " ++ intercalate ", " [ "GHC==" ++ display v | v <- lastStableGhcVers ]+                     ])++    unless (null unknownComps) $ do+        putStrLnWarn $ "ignoring unsupported compilers mentioned in tested-with: " ++ show unknownComps++    when (null ghcVerConstrs) $ do+        putStrLnErr "'tested-with:' doesn't mention any 'GHC' version"++    when (isNoVersion ghcVerConstrs') $ do+        putStrLnErr "'tested-with:' describes an empty version range for 'GHC'"++    when (isAnyVersion ghcVerConstrs') $ do+        putStrLnErr "'tested-with:' allows /any/ 'GHC' version"++    let unknownGhcVers = sort $ specificGhcVers \\ knownGhcVersions++    unless (null unknownGhcVers) $ do+        putStrLnErr ("'tested-with:' specifically refers to unknown 'GHC' versions: "+                     ++ intercalate ", " (map display unknownGhcVers) ++ "\n"+                     ++ "Known GHC versions: " ++ intercalate ", " (map display knownGhcVersions))++    let knownGhcVersions'+            | cfgLastInSeries cfg = filterLastMajor knownGhcVersions+            | otherwise           = knownGhcVersions++    let testedGhcVersions = filter (`withinRange` ghcVerConstrs') knownGhcVersions'++    when (null testedGhcVersions) $ do+        putStrLnErr "no known GHC version is allowed by the 'tested-with' specification"++    forM_ (optCollections opts) $ \c -> do+        let v = collToGhcVer c+        unless (v `elem` testedGhcVersions) $+            putStrLnErr $ unlines+               [ "collection " ++ c ++ " requires GHC " ++ display v+               , "add 'tested-width: GHC == " ++ display v ++ "' to your .cabal file"+               ]++    let pkg = Pkg pkgNameStr (takeDirectory cabalFile) gpd++    return (pkg, S.fromList testedGhcVersions)+  where+    lastStableGhcVers+        = nubBy ((==) `on` ghcMajVer)+        $ sortBy (flip compare)+        $ filter (not . previewGHC . Just)+        $ knownGhcVersions++    isTwoDigitGhcVersion :: VersionRange -> Maybe Version+    isTwoDigitGhcVersion vr = isSpecificVersion vr >>= t+      where+        t v | [_,_] <- versionNumbers v = Just v+        t _                             = Nothing++    filterLastMajor = map maximum . groupBy ((==) `on` ghcMajVer)++genTravisFromConfigs+    :: Monad m+    => ([String], Options)+    -> [String]+    -> Maybe FilePath+    -> Config+    -> Project Package+    -> Set Version+    -> YamlWriter m ()+genTravisFromConfigs (argv,opts) xpkgs isCabalProject config prj@Project { prjPackages = pkgs } versions' = do+    let folds = cfgFolds config++    putStrLnInfo $+        "Generating Travis-CI config for testing for GHC versions: " ++ ghcVersions++    unless (null $ optOsx opts) $  do+        putStrLnInfo $ "Also OSX jobs for: " ++ ghcOsxVersions+        unless (S.null omittedOsxVersions) $+            putStrLnWarn $ "Not all GHC versions specified with --osx are generated: " ++ ghcOmittedOsxVersions++    ---------------------------------------------------------------------------+    -- travis.yml generation starts here++    tellStrLns+        [ "# This Travis job script has been generated by a script via"+        , "#"+        , "#   runghc make_travis_yml_2.hs " ++ unwords [ "'" ++ a ++ "'" | a <- argv ]+        , "#"+        , "# For more information, see https://github.com/haskell-CI/haskell-ci"+        , "#"+        , "language: c"+        , "sudo: false"+        , ""+        , "git:"+        , "  submodules: false  # whether to recursively clone submodules"+        , ""+        ]++    let projectName = fromMaybe (pkgName $ head pkgs) (cfgProjectName config)+    unless (null $ cfgIrcChannels config) $ tellStrLns $+        [ "notifications:"+        , "  irc:"+        , "    channels:"+        ] +++        [ "      - \"" ++ chan ++ "\"" | chan <- cfgIrcChannels config ] +++        [ "    skip_join: true"+        , "    template:"+        , "      - \"\\x0313" ++ projectName ++ "\\x03/\\x0306%{branch}\\x03 \\x0314%{commit}\\x03 %{build_url} %{message}\""+        , ""+        ]++    unless (null $ cfgOnlyBranches config) $ tellStrLns $+        [ "branches:"+        , "  only:"+        ] +++        [ "    - " ++ branch+        | branch <- cfgOnlyBranches config+        ] +++        [ ""+        ]++    when (cfgCache config) $ tellStrLns+        [ "cache:"+        , "  directories:"+        , "    - $HOME/.cabal/packages"+        , "    - $HOME/.cabal/store"+        ]++    -- on OSX ghc is installed in $HOME so we can cache it+    -- independently of linux+    when (cfgCache config && not (null (optOsx opts))) $ tellStrLns+        [ "    - $HOME/.ghc-install"+        ]++    when (cfgCache config) $ tellStrLns+        [ ""+        , "before_cache:"+        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log"+        , "  # remove files that are regenerated by 'cabal update'"+        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*" -- legacy+        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json" -- TUF meta-data+        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache"+        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar"+        , "  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx"+        , ""+        , "  - rm -rfv $HOME/.cabal/packages/head.hackage" -- if we cache, it will break builds.+        , ""+        ]++    tellStrLn "matrix:"+    tellStrLn "  include:"++    let colls = [ (collToGhcVer cid,cid) | cid <- reverse $ optCollections opts ]++    let tellJob :: Monad m => Bool -> Maybe Version -> YamlWriter m ()+        tellJob osx gv = do+            let cvs = dispGhcVersion $ cfgCabalInstallVersion config <|> (lookupCabVer =<< gv)+                gvs = dispGhcVersion gv++                xpkgs' = concatMap (',':) xpkgs++                colls' = [ cid | (v,cid) <- colls, Just v == gv ]++            tellStrLns+                [ "    - compiler: \"ghc-" <> gvs <> "\""+                , if | Just e <- gv >>= \v -> M.lookup v (cfgEnv config)+                                     -> "      env: " ++ e+                     | previewGHC gv -> "      env: GHCHEAD=true"+                     | null colls'   -> "    # env: TEST=--disable-tests BENCH=--disable-benchmarks"+                     | otherwise     -> "      env: 'COLLECTIONS=" ++ intercalate "," colls' ++ "'"+                , "      addons: {apt: {packages: [ghc-ppa-tools,cabal-install-" <> cvs <> ",ghc-" <> gvs <> xpkgs' <> "], sources: [hvr-ghc]}}"+                ]++            when osx $ tellStrLns+                [ "      os: osx"+                ]++    -- newer GHC first, -head last (which is great).+    -- Alpha release would go first though.+    F.forM_ (reverse $ S.toList versions) $ tellJob False+    F.forM_ (reverse $ S.toList osxVersions) $ tellJob True . Just++    let allowFailures = headGhcVers `S.union` S.map Just (cfgAllowFailures config)+    unless (S.null allowFailures) $ do+        tellStrLn ""+        tellStrLn "  allow_failures:"++        F.forM_ allowFailures $ \gv -> do+            let gvs = dispGhcVersion gv+            tellStrLn $ concat [ "    - compiler: \"ghc-", gvs, "\"" ]++    tellStrLns+        [ ""+        , "before_install:"+        , sh "HC=${CC}"+        , sh' [2034,2039] "HCPKG=${HC/ghc/ghc-pkg}" -- SC2039. In POSIX sh, string replacement is undefined.+        , sh "unset CC"+        -- rootdir is useful for manual script additions+        , sh "ROOTDIR=$(pwd)"+        , sh "mkdir -p $HOME/.local/bin"+        ]++    let haskellOnMacos = "https://haskell.futurice.com/haskell-on-macos.py"++    if null (optOsx opts)+    then tellStrLns+        [ sh "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+        ]+    else tellStrLns+        [ sh $ "if [ \"$(uname)\" = \"Darwin\" ]; then brew update; brew upgrade python@3; curl " ++ haskellOnMacos ++ " | python3 - --make-dirs --install-dir=$HOME/.ghc-install --cabal-alias=head install cabal-install-head ${HC}; fi"+        , sh $ "if [ \"$(uname)\" = \"Darwin\" ]; then PATH=$HOME/.ghc-install/ghc/bin:$HOME/local/bin:$PATH; else PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH; fi"+        ]++    -- HCNUMVER, numeric HC version, e.g. ghc 7.8.4 is 70804 and 7.10.3 is 71003+    tellStrLns+        [ sh $ "HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\\.([0-9]+)\\.([0-9]+).*/\\1 * 10000 + \\2 * 100 + \\3/') ))"+        , sh "echo $HCNUMVER"+        ]++    unless (null colls) $+       tellStrLn " - IFS=', ' read -a COLLS <<< \"$COLLECTIONS\""++    tellStrLns+        [ ""+        , "install:"+        , sh "cabal --version"+        , sh "echo \"$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]\""+        , sh "BENCH=${BENCH---enable-benchmarks}"+        , sh "TEST=${TEST---enable-tests}"+        , sh "HADDOCK=${HADDOCK-true}"+        , sh "UNCONSTRAINED=${UNCONSTRAINED-true}"+        , sh "NOINSTALLEDCONSTRAINTS=${NOINSTALLEDCONSTRAINTS-false}"+        , sh "GHCHEAD=${GHCHEAD-false}"+        ]++    -- Update hackage index. Side-effect: ~/.cabal.config is created.+    tellStrLns+        [ sh "travis_retry cabal update -v"+        , sh "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+        , sh "rm -fv cabal.project cabal.project.local"+        ]++    -- Cabal jobs+    case cfgJobs config of+        (Just n, _) -> tellStrLns+            [ sh $ "sed -i.bak 's/^-- jobs:.*/jobs: " ++ show n ++ "/' ${HOME}/.cabal/config"+            ]+        _ -> return ()++    -- GHC jobs+    case cfgJobs config of+        (_, Just m) -> tellStrLns+            [ sh $ "if [ $HCNUMVER -ge 70800 ]; then sed -i.bak 's/-- ghc-options:.*/ghc-options: -j" ++ show m ++ "/' ${HOME}/.cabal/config; fi"+            ]+        _ -> return ()++    -- Add head.hackage repository to ~/.cabal/config+    -- (locally you want to add it to cabal.project)+    unless (S.null headGhcVers) $ tellStrLns+        [ "  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage"+        , "  - |"+        , "    if $GHCHEAD; then"+        , "      sed -i 's/-- allow-newer: .*/allow-newer: *:base/' ${HOME}/.cabal/config"+        , "      for pkg in $($HCPKG list --simple-output); do pkg=$(echo $pkg | sed 's/-[^-]*$//'); sed -i \"s/allow-newer: /allow-newer: *:$pkg, /\" ${HOME}/.cabal/config; done"+        , ""+        , "      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config"+        , "      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config"+        , "      echo '   secure: True'                                                                >> ${HOME}/.cabal/config"+        , "      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config"+        , "      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config"+        , "      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config"+        , "      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config"+        , ""+        , "      grep -Ev -- '^\\s*--' ${HOME}/.cabal/config | grep -Ev '^\\s*$'"+        , ""+        , "      cabal new-update head.hackage -v"+        , "    fi"+        ]++    -- Output cabal.config+    tellStrLns+        [ sh "grep -Ev -- '^\\s*--' ${HOME}/.cabal/config | grep -Ev '^\\s*$'"+        ]++    -- Install doctest+    let doctestVersionConstraint+            | isAnyVersion (cfgDoctestVersion config) = ""+            | otherwise = " --constraint='doctest " ++ display (cfgDoctestVersion config) ++ "'"+    when (cfgDoctest config) $ tellStrLns+        [ sh $ "if [ $HCNUMVER -ge 80000 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin doctest" ++ doctestVersionConstraint ++ "; fi"+        ]++    -- Install hlint+    let hlintVersionConstraint+            | isAnyVersion (cfgHLintVersion config) = ""+            | otherwise = " --constraint='hlint " ++ display (cfgHLintVersion config) ++ "'"+    when (cfgHLint config) $ tellStrLns+        [ sh $ "if [ $HCNUMVER -eq 80403 ]; then cabal new-install -w ${HC} -j2 --symlink-bindir=$HOME/.local/bin hlint" ++ hlintVersionConstraint ++ "; fi"+        ]++    -- create cabal.project file+    generateCabalProject False++    let pkgFilter = intercalate " | " $ map (wrap.pkgName) pkgs+        wrap s = "grep -Fv \"" ++ s ++ " ==\""+    unless (null colls) $ tellStrLns+        [ "  - for COLL in \"${COLLS[@]}\"; do"+        , "      echo \"== collection $COLL ==\";"+        , "      ghc-travis collection ${COLL} > /dev/null || break;"+        , "      ghc-travis collection ${COLL} | " ++ pkgFilter ++ " > cabal.project.freeze;"+        , "      grep ' collection-id' cabal.project.freeze;"+        , "      rm -rf dist-newstyle/;"+        , "      cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++ "\" --dep -j2 all;"+        , "    done"+        , ""+        ]++    forM_ pkgs $ \Pkg{pkgDir} -> tellStrLns+        [ "  - if [ -f \"" ++ pkgDir ++ "/configure.ac\" ]; then"+        , "      (cd \"" ++ pkgDir ++ "\" && autoreconf -i);"+        , "    fi"+        ]++    let quotedRmPaths =+          ".ghc.environment.*"+          ++ " " +++          quotedPaths (\Pkg{pkgDir} -> pkgDir ++ "/dist")++    tellStrLns+        [ sh $ "rm -f cabal.project.freeze"+        ]++    -- Install dependencies+    when (cfgInstallDeps config) $ do+        tellStrLns+            [ sh $ "cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file=\"" ++ projectFile ++"\" --dep -j2 all"+            ]+        when (cfgNoTestsNoBench config) $ tellStrLns+            [ sh $ "cabal new-build -w ${HC} --disable-tests --disable-benchmarks --project-file=\"" ++ projectFile ++ "\" --dep -j2 all"+            ]++    tellStrLns+        [ sh $ "rm -rf " ++ quotedRmPaths+        , sh $  "DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)"+        ]++    tellStrLns+        [ ""+        , "# Here starts the actual work to be performed for the package under test;"+        , "# any command which exits with a non-zero exit code causes the build to fail."+        , "script:"+        , "  # test that source-distributions can be generated"+        ]++    foldedTellStrLns FoldSDist "Packaging..." folds $ do+        forM_ pkgs $ \Pkg{pkgDir} -> tellStrLns+            [ sh $ "(cd \"" ++ pkgDir ++ "\" && cabal sdist)"+            ]++    let tarFiles = quotedPaths $ \Pkg{pkgDir,pkgName} ->+                pkgDir </> "dist" </> pkgName ++ "-*.tar.gz"+++    foldedTellStrLns FoldUnpack "Unpacking..." folds $ do+        tellStrLns+            [ sh $ "mv " ++ tarFiles ++ " ${DISTDIR}/"+            , sh $ "cd ${DISTDIR} || false" -- fail explicitly, makes SC happier+            , sh $ "find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \\;"+            ]+        generateCabalProject True++    when (cfgNoTestsNoBench config) $ foldedTellStrLns FoldBuild "Building..." folds $ tellStrLns+        [ comment "this builds all libraries and executables (without tests/benchmarks)"+        , sh "cabal new-build -w ${HC} --disable-tests --disable-benchmarks all"+        ]++    tellStrLns [""]+++    foldedTellStrLns FoldBuildEverything+        "Building with tests and benchmarks..." folds $ tellStrLns+        [ comment "build & run tests, build benchmarks"+        , sh "cabal new-build -w ${HC} ${TEST} ${BENCH} all"+        ]++    -- cabal new-test fails if there are no test-suites.+    when hasTests $+        foldedTellStrLns FoldTest "Testing..." folds $ tellStrLns+            [ sh $ mconcat+                [ "if [ \"x$TEST\" = \"x--enable-tests\" ]; then "+                , if cfgNoise config+                     then "cabal "+                     else "(set -o pipefail; cabal -vnormal+nowrap+markoutput "+                , "new-test -w ${HC} ${TEST} ${BENCH} all"+                , if cfgNoise config+                     then ""+                     else " 2>&1 | sed '/^-----BEGIN CABAL OUTPUT-----$/,/^-----END CABAL OUTPUT-----$/d' )"+                , "; fi"+                ]+            ]++    tellStrLns [""]++    when (cfgDoctest config) $ do+        let doctestOptions = unwords $ cfgDoctestOptions config+        tellStrLns [ comment "doctest" ]+        foldedTellStrLns FoldDoctest "Doctest..." folds $ do+            forM_ pkgs $ \Pkg{pkgName,pkgGpd} -> do+                let args = doctestArgs pkgGpd+                    args' = unwords args+                unless (null args) $ tellStrLns+                    [ sh $ "if [ $HCNUMVER -ge 80000 ]; then (cd " ++ pkgName ++ "-* && doctest " ++ doctestOptions ++ " " ++ args' ++ "); fi"+                    ]+        tellStrLns [ "" ]++    when (cfgHLint config) $ do+        let "" <+> ys = ys+            xs <+> "" = xs+            xs <+> ys = xs ++ " " ++ ys++            prependSpace "" = ""+            prependSpace xs = " " ++ xs++        let hlintOptions = prependSpace $ maybe "" ("-h ${ROOTDIR}/" ++) (cfgHLintYaml config) <+> unwords (cfgHLintOptions config)++        tellStrLns [ comment "hlint" ]+        foldedTellStrLns FoldHLint "HLint.." folds $ do+            forM_ pkgs $ \Pkg{pkgName,pkgGpd} -> do+                -- note: same arguments work so far for doctest and hlint+                let args = doctestArgs pkgGpd+                    args' = unwords args+                unless (null args) $ tellStrLns+                    [ sh $ "if [ $HCNUMVER -eq 80403 ]; then (cd " ++ pkgName ++ "-* && hlint" ++ hlintOptions ++ " " ++ args' ++ "); fi"+                    ]+        tellStrLns [ "" ]++    when (cfgCheck config) $+        foldedTellStrLns FoldCheck "cabal check..." folds $ do+            tellStrLns [ comment "cabal check" ]+            forM_ pkgs $ \Pkg{pkgName} -> tellStrLns+                [ sh $ "(cd " ++ pkgName ++ "-* && cabal check)"++                ]+            tellStrLns [ "" ]++    when hasLibrary $+        foldedTellStrLns FoldHaddock "Haddock..." folds $ tellStrLns+            [ comment "haddock"+            , sh "rm -rf ./dist-newstyle"+            , sh "if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo \"Skipping haddock generation\";fi"+            , ""+            ]++    unless (null colls) $+        foldedTellStrLns FoldStackage "Stackage builds..." folds $ tellStrLns+            [ "  # try building & testing for package collections"+            , "  - for COLL in \"${COLLS[@]}\"; do"+            , "      echo \"== collection $COLL ==\";"+            , "      ghc-travis collection ${COLL} > /dev/null || break;"+            , "      ghc-travis collection ${COLL} | " ++ pkgFilter ++ " > cabal.project.freeze;"+            , "      grep ' collection-id' cabal.project.freeze;"+            , "      rm -rf dist-newstyle/;"+            , "      cabal new-build -w ${HC} ${TEST} ${BENCH} all || break;"+            , "      if [ \"x$TEST\" = \"x--enable-tests\" ]; then cabal new-test -w ${HC} ${TEST} ${BENCH} all || break; fi;"+            , "    done"+            , ""+            ]++    -- Have to build last, as we remove cabal.project.local+    when (cfgUnconstrainted config) $ foldedTellStrLns FoldBuildInstalled+        "Building without installed constraints for packages in global-db..." folds $ tellStrLns+        [ comment "Build without installed constraints for packages in global-db"+        -- SC2046: Quote this to prevent word splitting.+        -- here we split on purpose!+        , sh' [2046, 2086] $ unwords+            [ "if $UNCONSTRAINED;"+            , "then rm -f cabal.project.local; echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks all;"+            , "else echo \"Not building without installed constraints\"; fi"+            ]+        , ""+        ]++    -- and now, as we don't have cabal.project.local;+    -- we can test with other constraint sets+    let constraintSets = cfgConstraintSets config+    unless (null constraintSets) $ do+        tellStrLns+            [ comment "Constraint sets"+            , sh "rm -rf cabal.project.local"+            , ""+            ]+        forM_ constraintSets $ \cs -> do+            let name = csName cs+            let constraintFlags = concatMap (\x ->  " --constraint='" ++ x ++ "'") (csConstraints cs)+            tellStrLns [ comment  "Constraint set " ++ name ]+            foldedTellStrLns' FoldConstraintSets name ("Constraint set " ++ name) folds $ tellStrLns+                [ sh' [2086] $ "if " ++ ghcVersionPredicate (csGhcVersions cs) ++ "; then cabal new-build -w ${HC} --disable-tests --disable-benchmarks" ++ constraintFlags ++ " all; else echo skipping...; fi"+                , ""+                ]+        tellStrLns [""]++    tellStrLns+        [ "# REGENDATA " ++ show argv+        , "# EOF"+        ]++    return ()+  where+    hasTests   = F.any (\Pkg{pkgGpd} -> not . null $ condTestSuites pkgGpd) pkgs+    hasLibrary = F.any (\Pkg{pkgGpd} -> isJust $ condLibrary pkgGpd) pkgs++    -- GHC versions which need head.hackage+    headGhcVers = S.filter previewGHC versions++    generateCabalProject dist = do+        tellStrLns+            [ sh $ "printf 'packages: " ++ cabalPaths ++ "\\n' > cabal.project"+            ]+        F.forM_ (prjConstraints prj) $ \xs -> do+            let s = concat (lines xs)+            tellStrLns+                [ sh $ "echo 'constraints: " ++ s ++ "' >> cabal.project"+                ]+        F.forM_ (prjAllowNewer prj) $ \xs -> do+            let s = concat (lines xs)+            tellStrLns+                [ sh $ "echo 'allow-newer: " ++ s ++ "' >> cabal.project"+                ]+        unless (null (cfgLocalGhcOptions config)) $ forM_ pkgs $ \Pkg{pkgName} -> do+            let s = unwords $ map (show . PU.showToken) $ cfgLocalGhcOptions config+            tellStrLns+                [ sh $ "echo 'package " ++ pkgName ++ "' >> cabal.project"+                , sh $ "echo '  ghc-options: " ++ s ++ "' >> cabal.project"+                ]++        -- also write cabal.project.local file with+        -- @+        -- constraints: base installed+        -- constraints: array installed+        -- ...+        --+        -- omitting any local package names+        tellStrLns+            [ sh $ "touch cabal.project.local"+            , sh $ unwords+                [ "if ! $NOINSTALLEDCONSTRAINTS; then"+                , "for pkg in $($HCPKG list --simple-output); do"+                , "echo $pkg"+                , concatMap (\Pkg{pkgName} -> " | grep -vw -- " ++ pkgName) pkgs+                , "| sed 's/^/constraints: /'"+                , "| sed 's/-[^-]*$/ installed/'"+                , ">> cabal.project.local; done; fi"+                ]+            ]++        tellStrLns+            [ sh $ "cat cabal.project || true"+            , sh $ "cat cabal.project.local || true"+            ]+      where+        cabalPaths+            | dist      = quotedPaths $ \Pkg{pkgName} -> pkgName ++ "-*/*.cabal"+            | otherwise = quotedPaths $ \Pkg{pkgDir}  -> pkgDir++    projectFile :: FilePath+    projectFile = fromMaybe "cabal.project" isCabalProject++    quotedPaths :: (Package -> FilePath) -> String+    quotedPaths f = unwords $ map (f . quote) pkgs+      where+        quote pkg = pkg{ pkgDir = "\"" ++ pkgDir pkg ++ "\"" }++    showVersions :: Set (Maybe Version) -> String+    showVersions = unwords . map dispGhcVersion . S.toList++    -- specified ersions+    osxVersions' :: Set Version+    osxVersions' = S.fromList $ mapMaybe simpleParse $ optOsx opts++    versions :: Set (Maybe Version)+    versions+        | cfgGhcHead config = S.insert Nothing $ S.map Just versions'+        | otherwise         = S.map Just versions'++    ghcVersions :: String+    ghcVersions = showVersions versions++    osxVersions, omittedOsxVersions :: Set Version+    (osxVersions, omittedOsxVersions) = S.partition (`S.member` versions') osxVersions'++    ghcOsxVersions :: String+    ghcOsxVersions = showVersions $ S.map Just osxVersions++    ghcOmittedOsxVersions :: String+    ghcOmittedOsxVersions = showVersions $ S.map Just omittedOsxVersions++    lookupCabVer :: Version -> Maybe Version+    lookupCabVer v = join $ lookup (ghcMajVer v) cabalVerMap++-- | Modules arguments to the library+--+-- * We check the library component+--+-- * If there are hs-source-dirs, use them+--+-- * otherwise use exposed + other modules+--+-- * Also add default-extensions+--+-- /Note:/ same argument work for hlint too!+--+doctestArgs :: GenericPackageDescription -> [String]+doctestArgs gpd = case PD.library $ flattenPackageDescription gpd of+    Nothing -> []+    Just l  -> exts ++ dirsOrMods+      where+        bi = PD.libBuildInfo l++        dirsOrMods+            | null (PD.hsSourceDirs bi) = map display (PD.exposedModules l)+            | otherwise = PD.hsSourceDirs bi++        exts = map (("-X" ++) . display) (PD.defaultExtensions bi)++collToGhcVer :: String -> Version+collToGhcVer cid = case simpleParse cid of+  Nothing -> error ("invalid collection-id syntax " ++ show cid)+  Just (PackageIdentifier n (versionNumbers -> v))+    | display n /= "lts" -> error ("unknown collection " ++ show cid)+    | isPrefixOf [0] v -> mkVersion [7,8,3]+    | isPrefixOf [1] v -> mkVersion [7,8,4]+    | isPrefixOf [2] v -> mkVersion [7,8,4]+    | isPrefixOf [3] v -> mkVersion [7,10,2]+    | isPrefixOf [4] v -> mkVersion [7,10,3]+    | isPrefixOf [5] v -> mkVersion [7,10,3]+    | isPrefixOf [6] v -> mkVersion [7,10,3]+    | isPrefixOf [7] v -> mkVersion [8,0,1]+    | otherwise -> error ("unknown collection " ++ show cid)++-------------------------------------------------------------------------------+-- Jobs+-------------------------------------------------------------------------------++-- | parse jobs defintion+--+-- * N:M - N ghcs (cabal -j), M threads (ghc -j)+--+-- >>> let parseJobs = maybeReadP parseJobsQ+-- >>> parseJobs "2:2"+-- Just (Just 2,Just 2)+--+-- >>> parseJobs ":2"+-- Just (Nothing,Just 2)+--+-- >>> parseJobs "2"+-- Just (Just 2,Nothing)+--+-- >>> parseJobs "garbage"+-- Nothing+--+parseJobsQ :: ReadP r (Maybe Int, Maybe Int)+parseJobsQ = nm <++ m <++ n <++ return (Nothing, Nothing)+  where+    nm = do+      x <- parseInt+      _ <- char ':'+      y <- parseInt+      return (Just x, Just y)++    m = do+      _ <- char ':'+      y <- parseInt+      return (Nothing, Just y)++    n = do+      x <- parseInt+      return (Just x, Nothing)++-------------------------------------------------------------------------------+-- Project file+-------------------------------------------------------------------------------++data Project a = Project+    { prjPackages    :: [a]+    , prjConstraints :: Maybe String+    , prjAllowNewer  :: Maybe String+    }+  deriving (Show, Functor, F.Foldable, T.Traversable)++overPrjPackages :: ([a] -> [b]) -> Project a -> Project b+overPrjPackages f prj = prj { prjPackages = f (prjPackages prj) }++emptyProject :: Project [a]+emptyProject = Project [] Nothing Nothing++-- | Parse project file. Extracts only @packages@ field.+--+-- >>> fmap prjPackages $ parseProjectFile "cabal.project" "packages: foo bar/*.cabal"+-- Right ["foo","bar/*.cabal"]+--+parseProjectFile :: FilePath -> String -> Either String (Project String)+parseProjectFile path contents =+    case PU.parseFields legacyProjectConfigFieldDescrs emptyProject contents of+        PU.ParseOk _ x -> Right x+        PU.ParseFailed err -> Left $ case PU.locatedErrorMsg err of+            (l, msg) -> "ERROR " ++ path ++ ":" ++ show l ++ ": " ++ msg++legacyProjectConfigFieldDescrs :: [PU.FieldDescr (Project String)]+legacyProjectConfigFieldDescrs =+    [ PU.listField "packages"+        (error "we don't pretty print") -- pretty+        parsePackageLocationTokenQ -- parse+        prjPackages+        (\x prj -> prj { prjPackages = x })+    , PU.simpleField "constraints"+        (error "we don't pretty print") -- pretty+        (fmap Just PU.parseFreeText)+        prjConstraints+        (\x prj -> prj { prjConstraints = maybeAlt2 commaConcat (prjConstraints prj) x })+    , PU.simpleField "allow-newer"+        (error "we don't pretty print") -- pretty+        (fmap Just PU.parseFreeText)+        prjAllowNewer+        (\x prj -> prj { prjAllowNewer = maybeAlt2 commaConcat (prjAllowNewer prj) x })+    ]+  where+    maybeAlt2 _ Nothing  x        = x+    maybeAlt2 _ x        Nothing  = x+    maybeAlt2 f (Just x) (Just y) = Just (f x y)++    commaConcat x y+        | all isSpace x = y+        | all isSpace y = x+        | otherwise     = x ++ ", " ++ y++-------------------------------------------------------------------------------+-- Options+-------------------------------------------------------------------------------++data Options = Options+    { optCollections :: [String]+    , optOutput :: Maybe FilePath+    , optOsx :: [String]+    , optConfig :: Maybe FilePath+    , optConfigMorphism :: Config -> Config+    }++defOptions :: Options+defOptions = Options+    { optCollections = []+    , optOutput = Nothing+    , optOsx = []+    , optConfig = Nothing+    , optConfigMorphism = id+    }++options :: [OptDescr (Result Diagnostic (Options -> Options))]+options =+    [ Option [] ["no-cache"]+      (NoArg $ successCM $ \cfg -> cfg { cfgCache = False })+      "disable Travis caching"+    , Option [] ["no-cabal-noise"]+      (NoArg $ successCM $ \cfg -> cfg { cfgNoise = False })+      "remove cabal noise from test output"+    , Option [] ["no-cabal-check"]+      (NoArg $ successCM $ \cfg -> cfg { cfgCheck = False })+      "Disable cabal check"+    , Option [] ["no-install-dependencies"]+      (NoArg $ successCM $ \cfg -> cfg { cfgInstallDeps = False })+      "Disable installing dependencies in a seperate step"+    , Option [] ["no-no-tests-no-bench"]+      (NoArg $ successCM $ \cfg -> cfg { cfgNoTestsNoBench = False })+      "Don't build with --no-tests --no-benchmarks"+    , Option [] ["no-unconstrained"]+      (NoArg $ successCM $ \cfg -> cfg { cfgUnconstrainted = False })+      "Build also without 'installed' constraints"+    , Option [] ["ghc-head"]+      (NoArg $ successCM $ \cfg -> cfg { cfgGhcHead = True })+      "Build also with ghc-head"+    , Option ['c'] ["collection"]+      (ReqArg (success' $ \arg opts -> opts { optCollections = arg : optCollections opts }) "CID")+      "enable package collection(s) (e.g. 'lts-7'), use multiple times for multiple collections"+    , Option ['f'] ["fold"]+      (flip OptArg "FOLDS" $ \arg -> case arg of+        Nothing   -> successCM $ \cfg -> cfg { cfgFolds = S.fromList possibleFolds }+        Just arg' -> case maybeReadP parseFoldQ arg' of+            Nothing -> Failure [Error $ "cannot parse --fold argument: " ++ arg' ++ "\n"]+            Just f  -> successCM $ \cfg -> cfg { cfgFolds = f (cfgFolds cfg) })+      ("build output(s) to fold, use multiple times for multiple folds. No argument defaults to 'all'. Possible values: all, all-but-test, " ++ intercalate ", " (map showFold possibleFolds))+    , Option [] ["irc-channel"]+      (ReqArg (successCM' $ \arg cfg -> cfg { cfgIrcChannels = arg : cfgIrcChannels cfg }) "HOST#CHANNEL")+      "enable IRC notifcations to given channel (e.g. 'irc.freenode.org#haskell-lens'), use multiple times for multiple channels"+    , Option ['n'] ["name"]+      (ReqArg (successCM' $ \arg cfg -> cfg { cfgProjectName = Just arg }) "NAME")+      "project name (used for IRC notifications), defaults to package name or name of first package listed in cabal.project file"+    , Option ['b'] ["branch"]+      (ReqArg (successCM' $ \arg cfg -> cfg { cfgOnlyBranches = arg : cfgOnlyBranches cfg }) "BRANCH")+      "enable builds only for specific brances, use multiple times for multiple branches"+    , Option ['o'] ["output"]+      (ReqArg (success' $ \arg opts -> opts { optOutput = Just arg }) "OUTPUT")+      "output file (stdout if omitted)"+    , Option [] ["config"]+      (OptArg (success' $ \arg opts -> opts { optConfig = Just $ fromMaybe "cabal.make-travis-yml" arg }) "CONFIG")+      "config file, currently used only to specify constraint sets"+    , Option [] ["osx"]+      (ReqArg (success' $ \arg opts -> opts { optOsx = arg : optOsx opts }) "GHC")+      "generate osx build job with ghc version"+    , Option ['j'] ["jobs"]+      (reqArgReadP parseJobsQ (\jobs cfg -> cfg { cfgJobs = jobs }) "JOBS")+      "jobs (N:M - cabal:ghc)"+    , Option [] ["local-ghc-options"]+      (reqArgReadP parseOptsQ (\xs cfg -> cfg { cfgLocalGhcOptions = xs }) "OPTIONS")+      "--ghc-options for local packages"+    , Option ['d'] ["doctest"]+      (NoArg $ successCM $ \cfg -> cfg { cfgDoctest = True })+      "Run doctest using .ghc.environment files."+    , Option [] ["doctest-options"]+      (reqArgReadP parseOptsQ (\xs cfg -> cfg { cfgDoctestOptions = xs }) "OPTIONS")+      "Additional doctest options."+    , Option [] ["doctest-version"]+      (reqArgReadP parse (\arg cfg -> cfg { cfgDoctestVersion = arg }) "VERSION")+      "Doctest version range"+    , Option ['l'] ["hlint"]+      (NoArg $ successCM $ \cfg -> cfg { cfgHLint = True })+      "Run hlint (only on GHC-8.4.3 target)"+    , Option [] ["hlint-yaml"]+      (ReqArg (successCM' $ \arg cfg -> cfg { cfgHLintYaml = Just arg }) "HLINT.YAML")+      "Relative path to .hlint.yaml."+    , Option [] ["hlint-options"]+      (reqArgReadP parseOptsQ (\xs cfg -> cfg { cfgHLintOptions = xs }) "OPTIONS")+      "Additional hlint options."+    , Option [] ["hlint-version"]+      (reqArgReadP parse (\arg cfg -> cfg { cfgHLintVersion = arg }) "VERSION")+      "HLint version range"+    , Option [] ["cabal-install-version"]+      (reqArgReadP parse (\arg cfg -> cfg { cfgCabalInstallVersion = Just arg }) "VERSION")+      "cabal-install version for all jobs, overrides default"+    , Option [] ["cabal-install-head"]+      (NoArg $ successCM $ \cfg -> cfg { cfgCabalInstallVersion = Nothing })+      "Use cabal-install-head for all jobs, overrides default"+    , Option [] ["env"]+      (reqArgReadP envP (\(k, v) cfg -> cfg { cfgEnv = M.insert k v (cfgEnv cfg) }) "ENVDECL")+      "Environment (e.g. `8.0.2:HADDOCK=false`)"+    , Option [] ["allow-failure"]+      (reqArgReadP parse (\arg cfg -> cfg { cfgAllowFailures = S.insert arg (cfgAllowFailures cfg) }) "GHCVERSION")+      "Allow failures of particular GHC version"+    , Option [] ["last-in-series"]+      (NoArg $ successCM $ \cfg -> cfg { cfgLastInSeries = True })+      "[Discouraged] Assume there are only GHCs last in major series: 8.0.* will match only 8.2.2"+    ]+  where+    overCM f opts = opts+        { optConfigMorphism = f . optConfigMorphism opts+        }++    success' f arg = success (f arg)++    successCM = success . overCM+    successCM' f arg = successCM (f arg)++    reqArgReadP :: ReadP a a -> (a -> Config -> Config) -> String -> ArgDescr (Result Diagnostic (Options -> Options))+    reqArgReadP p f n = flip ReqArg n $ \arg -> case maybeReadP  p arg of+        Nothing -> Failure [Error $  "cannot parse: " ++ arg ]+        Just x  -> successCM' f x++    envP :: ReadP r (Version, String)+    envP = do+        ghc <- parse+        skipSpaces+        _ <- char ':'+        skipSpaces+        v <- munch (const True)+        return (ghc, v)++-------------------------------------------------------------------------------+-- Result+-------------------------------------------------------------------------------++data Result e a+    = Success [e] a+    | Failure [e]+    deriving (Eq, Show, Functor)++success :: a -> Result e a+success = Success []++instance Monoid a => Mon.Monoid (Result e a) where+    mempty = success mempty+#if MIN_VERSION_base(4,9,0)+    mappend = (<>)++instance Monoid a => Semigroup (Result e a) where+    Failure err1   <> Failure err2   = Failure $ err1 <> err2+    Failure err1   <> Success err2 _ = Failure $ err1 <> err2+    Success err1 _ <> Failure err2   = Failure $ err1 <> err2+    Success l1 o1  <> Success l2 o2  = Success (mappend l1 l2) (mappend o1 o2)+#else+    Failure err1   `mappend` Failure err2   = Failure $ err1 `mappend` err2+    Failure err1   `mappend` Success err2 _ = Failure $ err1 `mappend` err2+    Success err1 _ `mappend` Failure err2   = Failure $ err1 `mappend` err2+    Success l1 o1  `mappend` Success l2 o2  = Success (mappend l1 l2) (mappend o1 o2)+#endif++-------------------------------------------------------------------------------+-- Fold+-------------------------------------------------------------------------------++data Fold+    = FoldSDist+    | FoldUnpack+    | FoldBuild+    | FoldBuildInstalled+    | FoldBuildEverything+    | FoldTest+    | FoldHaddock+    | FoldStackage+    | FoldCheck+    | FoldDoctest+    | FoldHLint+    | FoldConstraintSets+  deriving (Eq, Ord, Show, Enum, Bounded)++showFold :: Fold -> String+showFold = dashise . drop 4 . show+  where+    dashise = intercalate "-" . map (map toLower) . split++    split [] = []+    split xs0 =+        let (ys, xs1) = span isUpper xs0+            (zs, xs2) = break isUpper xs1+        in (ys ++ zs) : split xs2++possibleFolds :: [Fold]+possibleFolds = [minBound .. maxBound]++parseFoldQ :: ReadP r (Set Fold -> Set Fold)+parseFoldQ = do+    t <- PU.parseTokenQ+    case t of+        "all"          -> return $ const $ S.fromList possibleFolds+        "all-but-test" -> return $ const $ S.delete FoldTest $ S.fromList possibleFolds+        n -> case M.lookup n ps of+            Just n' -> return (S.insert n')+            Nothing -> fail $ "Illegal fold name: " ++ n+  where+    ps = M.fromList $ map (\x -> (showFold x, x)) possibleFolds++-------------------------------------------------------------------------------+-- Config file+-------------------------------------------------------------------------------++data Config = Config+    { cfgCabalInstallVersion :: Maybe Version+    , cfgHLint           :: !Bool+    , cfgHLintYaml       :: !(Maybe FilePath)+    , cfgHLintVersion    :: !VersionRange+    , cfgHLintOptions    :: [String]+    , cfgJobs            :: (Maybe Int, Maybe Int)+    , cfgDoctest         :: !Bool+    , cfgDoctestOptions  :: [String]+    , cfgDoctestVersion  :: !VersionRange+    , cfgLocalGhcOptions :: [String]+    , cfgConstraintSets  :: [ConstraintSet]+    , cfgCache           :: !Bool+    , cfgCheck           :: !Bool+    , cfgNoise           :: !Bool+    , cfgNoTestsNoBench  :: !Bool+    , cfgUnconstrainted  :: !Bool+    , cfgInstallDeps     :: !Bool+    , cfgOnlyBranches    :: [String]+    , cfgIrcChannels     :: [String]+    , cfgProjectName     :: Maybe String+    , cfgFolds           :: Set Fold+    , cfgGhcHead         :: !Bool+    , cfgEnv             :: M.Map Version String+    , cfgAllowFailures   :: S.Set Version+    , cfgLastInSeries    :: !Bool+    }+  deriving (Show)++emptyConfig :: Config+emptyConfig = Config+    { cfgCabalInstallVersion = Nothing+    , cfgHLint           = False+    , cfgHLintYaml       = Nothing+    , cfgHLintVersion    = defaultHLintVersion+    , cfgHLintOptions    = []+    , cfgJobs            = (Nothing, Nothing)+    , cfgDoctest         = False+    , cfgDoctestOptions  = []+    , cfgDoctestVersion  = defaultDoctestVersion+    , cfgLocalGhcOptions = []+    , cfgConstraintSets  = []+    , cfgCache           = True+    , cfgCheck           = True+    , cfgNoise           = True+    , cfgNoTestsNoBench  = True+    , cfgUnconstrainted  = True+    , cfgInstallDeps     = True+    , cfgOnlyBranches    = []+    , cfgIrcChannels     = []+    , cfgProjectName     = Nothing+    , cfgFolds           = S.empty+    , cfgGhcHead         = False+    , cfgEnv             = M.empty+    , cfgAllowFailures   = S.empty+    , cfgLastInSeries    = False+    }++configFieldDescrs :: [PU.FieldDescr Config]+configFieldDescrs =+    [ PU.simpleField  "jobs"+        (error "we don't pretty print")+        parseJobsQ+        cfgJobs+        (\x cfg -> cfg { cfgJobs = x })+    , PU.boolField  "hlint"+        cfgHLint+        (\b cfg -> cfg { cfgHLint = b })+    , PU.simpleField "hlint-yaml"+        (error "we don't pretty print")+        (fmap Just PU.parseFilePathQ)+        cfgHLintYaml+        (\x cfg -> cfg { cfgHLintYaml = x })+    , PU.simpleField "hlint-version"+        (error "we don't pretty print")+        parse+        cfgHLintVersion+        (\x cfg -> cfg { cfgHLintVersion = x })+    -- TODO: hlint-options+    , PU.boolField  "doctest"+        cfgDoctest+        (\b cfg -> cfg { cfgDoctest = b })+    , PU.simpleField "doctest-options"+        (error "we don't pretty print")+        parseOptsQ+        cfgDoctestOptions+        (\x cfg -> cfg { cfgDoctestOptions = cfgDoctestOptions cfg ++ x })+    , PU.simpleField "doctest-version"+        (error "we don't pretty print")+        parse+        cfgDoctestVersion+        (\x cfg -> cfg { cfgDoctestVersion = x })+    , PU.simpleField "cabal-install-version"+        (error "we don't pretty print")+        (fmap Just parse)+        cfgCabalInstallVersion+        (\x cfg -> cfg { cfgCabalInstallVersion = x })+    , PU.simpleField "local-ghc-options"+        (error "we don't pretty print")+        parseOptsQ+        cfgLocalGhcOptions+        (\x cfg -> cfg { cfgLocalGhcOptions = cfgLocalGhcOptions cfg ++ x })+    , PU.boolField  "cache"+        cfgCache+        (\b cfg -> cfg { cfgCache = b })+    , PU.boolField  "cabal-noise"+        cfgNoise+        (\b cfg -> cfg { cfgNoise = b })+    , PU.boolField  "cabal-check"+        cfgCheck+        (\b cfg -> cfg { cfgCheck = b })+    , PU.boolField  "install-dependencies-step"+        cfgInstallDeps+        (\b cfg -> cfg { cfgInstallDeps = b })+    , PU.boolField  "no-tests-no-benchmarks"+        cfgNoTestsNoBench+        (\b cfg -> cfg { cfgNoTestsNoBench = b })+    , PU.boolField  "unconstrained-step"+        cfgUnconstrainted+        (\b cfg -> cfg { cfgUnconstrainted = b })+    , PU.listField  "irc-channels"+        (error "we don't pretty print")+        PU.parseTokenQ+        cfgIrcChannels+        (\x cfg -> cfg { cfgIrcChannels = x })+    , PU.simpleField "name"+        (error "we don't pretty print")+        (fmap Just PU.parseTokenQ)+        cfgProjectName+        (\x cfg -> cfg { cfgProjectName = x })+    , PU.listField  "branches"+        (error "we don't pretty print")+        PU.parseTokenQ+        cfgOnlyBranches+        (\x cfg -> cfg { cfgOnlyBranches = x })+    , PU.simpleField  "folds"+        (error "we don't pretty print")+        (sepBy parseFoldQ (munch1 isSpace))+        (\cfg -> [\_ -> cfgFolds cfg])+        (\x cfg -> cfg { cfgFolds = foldl' (flip id) (cfgFolds cfg) x })+    , PU.boolField "ghc-head"+        cfgGhcHead+        (\b cfg -> cfg { cfgGhcHead = b })+    -- , PU.simpleField "env" -- TODO+    ]++parseOptsQ :: ReadP r [String]+parseOptsQ = sepBy PU.parseTokenQ' (munch1 isSpace)++readConfigFile :: MonadIO m => FilePath -> YamlWriter m Config+readConfigFile path = do+    contents <- liftIO $ readFile path+    parseConfigFile path contents++parseConfigFile :: Monad m => FilePath -> String -> YamlWriter m Config+parseConfigFile path contents = toWriter $ do+    fields' <- PU.readFields contents+    let (fields, sections) = partitionEithers (map classify fields')+    config <- accumFields configFieldDescrs emptyConfig fields+    go config sections+  where+    toWriter r = case r of+        PU.ParseOk ws x -> do+            forM_ ws $ \w -> putStrLnWarn (PU.showPWarning path w)+            return x+        PU.ParseFailed err -> case PU.locatedErrorMsg err of+            (l, msg) -> putStrLnErr $ path ++ ":" ++ show l ++ ": " ++ msg++    classify x@PU.IfBlock {} = Right x+    classify x@PU.Section {} = Right x+    classify x@PU.F {}       = Left x++    go :: Config -> [PU.Field] -> PU.ParseResult Config+    go  cfg [] = return cfg+    go _cfg (PU.IfBlock {} : _fields) = fail "if conditional found"+    go  cfg (PU.F {} : fields)        = go cfg fields+    go  cfg (PU.Section line name arg subfields : fields)+        | name == "constraint-set" = do+            cs <- accumFields constraintSetFieldDescrs (emptyConstraintSet arg) subfields+            let cfg' = cfg { cfgConstraintSets = cfgConstraintSets cfg ++ [cs] }+            go cfg' fields+        | otherwise = do+            PU.warning $ "Unknown section " ++ name ++ " on line " ++ show line+            go cfg fields++-------------------------------------------------------------------------------+-- ConstraintSet+-------------------------------------------------------------------------------++data ConstraintSet = ConstraintSet+    { csName        :: String+    , csGhcVersions :: VersionRange+    , csConstraints :: [String] -- we parse these simply as strings+    }+  deriving (Show)++emptyConstraintSet :: String -> ConstraintSet+emptyConstraintSet n = ConstraintSet n anyVersion []++constraintSetFieldDescrs :: [PU.FieldDescr ConstraintSet]+constraintSetFieldDescrs =+    [ PU.listField "constraints"+        (error "we don't pretty print") -- pretty+        (parseHaskellString <++ munch1 (`notElem` [',', '"']))+        csConstraints+        (\c cs -> cs { csConstraints = csConstraints cs ++ c })+    , PU.simpleField "ghc"+        (error "we don't pretty print") -- pretty+        Distribution.Text.parse+        csGhcVersions+        (\c cs -> cs { csGhcVersions = c })+    ]++ghcVersionPredicate :: VersionRange -> String+ghcVersionPredicate = conj . asVersionIntervals+  where+    conj = intercalate "  ||  " . map disj++    disj :: VersionInterval -> String+    disj (LowerBound v InclusiveBound, UpperBound u InclusiveBound)+        | v == u              = "[ $HCNUMVER -eq " ++ f v ++ " ]"+    disj (lb, NoUpperBound)   = lower lb+    disj (lb, UpperBound v b) = lower lb ++ " && " ++ upper v b++    lower (LowerBound v InclusiveBound) = "[ $HCNUMVER -ge " ++ f v ++ " ]"+    lower (LowerBound v ExclusiveBound) = "[ $HCNUMVER -gt " ++ f v ++ " ]"++    upper v InclusiveBound = "[ $HCNUMVER -le " ++ f v ++ " ]"+    upper v ExclusiveBound = "[ $HCNUMVER -lt " ++ f v ++ " ]"++    f v =  case versionNumbers v of+        []        -> "0"+        [x]       -> show (x * 10000)+        [x,y]     -> show (x * 10000 + y * 100)+        (x:y:z:_) -> show (x * 10000 + y * 100 + z)++-------------------------------------------------------------------------------+-- From Cabal+-------------------------------------------------------------------------------++accumFields :: [PU.FieldDescr a] -> a -> [PU.Field] -> PU.ParseResult a+accumFields fields = foldM setField+  where+    fieldMap = M.fromList+        [ (name, f) | f@(PU.FieldDescr name _ _) <- fields ]+    setField accum (PU.F line name value) = case M.lookup name fieldMap of+      Just (PU.FieldDescr _ _ set) -> set line value accum+      Nothing -> do+          PU.warning $ "Unrecognized field " ++ name ++ " on line " ++ show line+          return accum+    setField accum f = do+        PU.warning ("Unrecognized stanza on line " ++ show (PU.lineNo f))+        return accum++-------------------------------------------------------------------------------+-- From cabal-install+-------------------------------------------------------------------------------++-- | This is a bit tricky since it has to cover globs which have embedded @,@+-- chars. But we don't just want to parse strictly as a glob since we want to+-- allow http urls which don't parse as globs, and possibly some+-- system-dependent file paths. So we parse fairly liberally as a token, but+-- we allow @,@ inside matched @{}@ braces.+--+parsePackageLocationTokenQ :: ReadP r String+parsePackageLocationTokenQ = parseHaskellString <++ parsePackageLocationToken+  where+    parsePackageLocationToken :: ReadP r String+    parsePackageLocationToken = fmap fst (gather outerTerm)+      where+        outerTerm   = alternateEither1 outerToken (braces innerTerm)+        innerTerm   = alternateEither  innerToken (braces innerTerm)+        outerToken  = void $ munch1 outerChar+        innerToken  = void $ munch1 innerChar+        outerChar c = not (isSpace c || c == '{' || c == '}' || c == ',')+        innerChar c = not (isSpace c || c == '{' || c == '}')+        braces      = between (char '{') (char '}')++    alternateEither, alternateEither1,+      alternatePQs, alternate1PQs, alternateQsP, alternate1QsP+      :: ReadP r () -> ReadP r () -> ReadP r ()++    alternateEither1 p q = alternate1PQs p q +++ alternate1QsP q p+    alternateEither  p q = alternateEither1 p q +++ return ()+    alternate1PQs    p q = p >> alternateQsP q p+    alternatePQs     p q = alternate1PQs p q +++ return ()+    alternate1QsP    q p = many1 q >> alternatePQs p q+    alternateQsP     q p = alternate1QsP q p +++ return ()++parseHaskellString :: ReadP r String+parseHaskellString = readS_to_P reads++parseInt :: ReadP r Int+parseInt = readS_to_P reads++-------------------------------------------------------------------------------+-- Glob+-------------------------------------------------------------------------------++{-++Globbing code and grammar judiciously stolen from cabal-install:++FilePathGlob    ::= FilePathRoot FilePathGlobRel+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 *+GlobPiece ::= "*"            # wildcard+            | [^*{},/\\] *   # literal string+            | "\\" [*{},]    # escaped reserved character+            | "{" Glob "," ... "," Glob "}" # union (match any of these)+-}++data FilePathGlob = FilePathGlob FilePathRoot FilePathGlobRel+  deriving (Eq, Show)++data FilePathGlobRel+   = GlobDir  Glob FilePathGlobRel+   | GlobFile Glob+   | GlobDirTrailing -- trailing dir, a glob ending in '/'+  deriving (Eq, Show)++-- | 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)++data FilePathRoot+   = FilePathRelative+   | FilePathRoot FilePath -- e.g. '/', 'c:\' or result of 'takeDrive'+   | FilePathHomeDir+  deriving (Eq, Show)++parseFilePathGlobRel :: ReadP r FilePathGlobRel+parseFilePathGlobRel =+      parseGlob >>= \globpieces ->+          asDir globpieces+      <++ asTDir globpieces+      <++ asFile globpieces+  where+    asDir  glob = do dirSep+                     GlobDir glob <$> parseFilePathGlobRel+    asTDir glob = do dirSep+                     return (GlobDir glob GlobDirTrailing)+    asFile glob = return (GlobFile glob)++    dirSep = void (char '/')+         +++ (do _ <- char '\\'+                 -- check this isn't an escape code+                 following <- look+                 case following of+                   (c:_) | isGlobEscapedChar c -> pfail+                   _                           -> return ())++parseGlob :: ReadP r Glob+parseGlob = many1 parsePiece+  where+    parsePiece = literal +++ wildcard +++ union'++    wildcard = char '*' >> return WildCard++    union' = between (char '{') (char '}') $+              fmap Union (sepBy1 parseGlob (char ','))++    literal = Literal `fmap` litchars1++    litchar = normal +++ escape++    normal  = satisfy (\c -> not (isGlobEscapedChar c)+                                && c /= '/' && c /= '\\')+    escape  = char '\\' >> satisfy isGlobEscapedChar++    litchars1 :: ReadP r [Char]+    litchars1 = liftM2 (:) litchar litchars++    litchars :: ReadP r [Char]+    litchars = litchars1 <++ return []++isGlobEscapedChar :: Char -> Bool+isGlobEscapedChar '*'  = True+isGlobEscapedChar '{'  = True+isGlobEscapedChar '}'  = True+isGlobEscapedChar ','  = True+isGlobEscapedChar _    = False++expandRelGlob :: MonadIO m => FilePath -> FilePathGlobRel -> m [FilePath]+expandRelGlob root glob0 = liftIO $ 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 App.<$> mapM (\subdir -> go globPath (dir </> subdir)) subdirs++    go GlobDirTrailing dir = return [dir]++matchGlob :: Glob -> FilePath -> 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
+ test/Tests.hs view
@@ -0,0 +1,145 @@+{-# LANGUAGE ViewPatterns #-}+module Main (main) where++import MakeTravisYml hiding (main)++import Control.Applicative ((<$>), (<*>))+import Control.Exception (ErrorCall(..), throwIO, try)+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Writer+import Data.Algorithm.Diff (Diff (..), getGroupedDiff)+import Data.IORef+import Data.List (isPrefixOf, stripPrefix)+import Data.Maybe (mapMaybe)+import Data.Monoid (mconcat)+import System.Console.GetOpt (getOpt, ArgOrder(Permute))+import System.Directory (doesFileExist, removeFile, setCurrentDirectory)+import System.Exit (ExitCode(..), exitFailure)+import System.FilePath (addExtension, (</>))+import System.IO (hPutStrLn, stderr)+import Test.Tasty (TestName, TestTree, defaultMain, testGroup)+import Test.Tasty.Golden.Advanced (goldenTest)+import Text.Read (readMaybe)++import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BS8+import qualified System.Console.ANSI as ANSI++main :: IO ()+main = do+    setCurrentDirectory "fixtures/"+    defaultMain $ testGroup "fixtures"+        [ fixtureGoldenTest "haskell-ci.cabal"+        , fixtureGoldenTest "cabal.project.empty-line"+        , fixtureGoldenTest "cabal.project.fail-versions"+        , fixtureGoldenTest "cabal.project.messy"+        ]++linesToArgv :: String -> Maybe [String]+linesToArgv txt = case mapMaybe lineToArgv (lines txt) of+    [argv] -> Just argv+    _ -> Nothing+  where+    lineToArgv line+        | Just rest <- "# REGENDATA " `stripPrefix` line = readMaybe rest+        | otherwise = Nothing++-- |+-- @+-- travisFromConfigFile ::+--    ... => ([String],Options) -> FilePath -> [String] -> Writer [String] m ()+-- @+fixtureGoldenTest :: FilePath -> TestTree+fixtureGoldenTest fp = cabalGoldenTest fp outputRef errorRef $ do+    (argv, opts, xpkgs) <- makeTravisFlags+    let genConfig = travisFromConfigFile (argv, opts) fp xpkgs+    execWriterT (runMaybeT genConfig)+  where+    outputRef = addExtension fp "travis.yml"+    errorRef = addExtension fp "stderr"++    referenceArgv :: Bool -> IO (Maybe [String])+    referenceArgv refExists+        | refExists = (linesToArgv . BS8.unpack) `fmap` BS.readFile outputRef+        | otherwise = return $ Just [fp]++    makeTravisFlags :: IO ([String], Options, [String])+    makeTravisFlags = do+        result <- doesFileExist outputRef >>= referenceArgv+        case result of+            Nothing -> throwIO (ErrorCall "No REGENDATA in result file.")+            Just argv -> do+                (opts, _argv, _fp, xpkgs) <- parseOpts argv+                return (argv, opts, xpkgs)++parseOpts :: [String] -> IO (Options, [String], FilePath, [String])+parseOpts = parseOptsNoCommands++cabalGoldenTest+    :: TestName+    -> FilePath+    -> FilePath+    -> IO MakeTravisOutput+    -> TestTree+cabalGoldenTest name outRef errRef act = goldenTest name readGolden act' cmp upd+  where+    readData :: FilePath -> IO [String]+    readData fp = lines . BS8.unpack <$> BS.readFile fp++    act' = flip fmap act $ \r -> case r of+        Success ws x -> Success (map formatDiagnostic ws) x+        Failure errs -> Failure (map formatDiagnostic errs)++    readGolden = do+        refExists <- doesFileExist outRef+        if refExists+           then Success <$> readData errRef <*> readData outRef+           else Failure <$> readData errRef++    packData :: [String] -> BS.ByteString+    packData = BS8.pack . unlines++    upd (Failure (packData -> errs)) = BS.writeFile errRef errs+    upd (Success (packData -> warnings) (packData -> contents)) = do+        BS.writeFile outRef contents+        BS.writeFile errRef warnings++    cmp x y | x == y = return Nothing+    cmp (Failure err1) (Failure err2) = return . Just $ diff err1 err2+    cmp (Success warn1 out1) (Success warn2 out2) = return . Just . mconcat $+        [ diff warn1 warn2+        , "\n\n"+        , diff out1 out2+        ]+    cmp (Failure err) (Success warnings _) = return . Just . unlines $+        [ "Expected failure:" ] ++ err ++ ["\n\nFound success:"] ++ warnings+    cmp (Success warnings _) (Failure err) = return . Just . unlines $+        [ "Expected success:" ] ++ warnings ++ ["\n\nFound failure:"] ++ err++    diff x y =+        ansiReset -- reset tasty's red color+        ++ unlines (concatMap f (getGroupedDiff x y))++    f (First xs)  = map (withAnsiRed . cons3 '-') xs+    f (Second ys) = map (withAnsiGreen . cons3 '+') ys+    -- we print unchanged lines too.+    -- we trim the contents a little.+    f (Both xs _) = map (cons3 ' ') (shorten xs)++    -- we add three characters, so the changed lines are easier to spot+    cons3 c cs = c : c : c : ' ' : cs++    ansiReset = ANSI.setSGRCode [ ANSI.SetColor ANSI.Foreground ANSI.Dull ANSI.White] -- default color: gray+    ansiRed   = ANSI.setSGRCode [ ANSI.SetColor ANSI.Foreground ANSI.Vivid ANSI.Red]+    ansiGreen = ANSI.setSGRCode [ ANSI.SetColor ANSI.Foreground ANSI.Vivid ANSI.Green]++    withAnsiRed s   = ansiRed ++ s ++ ansiReset+    withAnsiGreen s = ansiGreen ++ s ++ ansiReset++    -- for large thunks make ellipsis in between+    shorten xs+        | l < 15    = xs+        | otherwise = as ++ ["..."] ++ drop (l - 10) bs+      where+        l = length xs+        (as, bs) = splitAt 5 xs