packages feed

stack 1.6.5 → 1.7.1

raw patch · 119 files changed

+4111/−4356 lines, 119 filesdep +mustachedep +riodep +typed-processdep −blaze-builderdep −clockdep −fast-loggerdep ~Cabaldep ~QuickCheckdep ~Win32

Dependencies added: mustache, rio, typed-process

Dependencies removed: blaze-builder, clock, fast-logger, hastache, microlens-mtl, pid1

Dependency ranges changed: Cabal, QuickCheck, Win32, aeson, annotated-wl-pprint, ansi-terminal, async, attoparsec, base, base64-bytestring, bindings-uname, bytestring, conduit, conduit-extra, containers, cryptonite, cryptonite-conduit, deepseq, directory, echo, exceptions, extra, file-embed, filelock, filepath, fsnotify, generic-deriving, gitrev, hackage-security, hashable, hpack, hpc, hspec, http-client, http-client-tls, http-conduit, http-types, memory, microlens, mintty, monad-logger, mono-traversable, mtl, neat-interpolation, network-uri, open-browser, optparse-applicative, optparse-simple, path, path-io, persistent, persistent-sqlite, persistent-template, pretty, primitive, process, project-template, regex-applicative-text, resourcet, retry, semigroups, smallcheck, split, stm, store, store-core, streaming-commons, tar, template-haskell, temporary, text, text-metrics, th-reify-many, time, tls, transformers, unicode-transforms, unix, unix-compat, unliftio, unordered-containers, vector, yaml, zip-archive, zlib

Files

CONTRIBUTING.md view
@@ -135,7 +135,7 @@ Running the integration tests is a little involved, you'll need to:  ```bash-$ stack test stack:integration-test --flag stack:stack-integration-tests+$ stack test stack:stack-integration-test --flag stack:integration-tests ```  Running an individual module works like this:@@ -159,3 +159,12 @@ Where again, `<PATTERN>` is the name of the folder listed in the [test/integration/tests/](https://github.com/commercialhaskell/stack/tree/master/test/integration/tests) folder.+++## Slack channel++If you're making deep changes and real-time communcation with the Stack team+would be helpful, we have a `#stack-collaborators` Slack channel.  Please+contact [@borsboom](https://github.com/borsboom) (manny@fpcomplete.com) or+[@snoyberg](https://github.com/snoyberg) (michael@fpcomplete.com) for an+invite.
ChangeLog.md view
@@ -1,12 +1,106 @@ # Changelog  +## v1.7.1++Release notes:++* aarch64 (64-bit ARM) bindists are now available for the first time.+* Statically linked Linux bindists are no longer available, due to difficulty with GHC 8.2.2 on Alpine Linux.+* 32-bit Linux GMP4 bindists for CentOS 6 are no longer available, since GHC 8.2.2 is no longer being built for that platform.++Major changes:++* Upgrade from Cabal 2.0 to Cabal 2.2++Behavior changes:++* `stack setup` no longer uses different GHC configure options on Linux+  distributions that use GCC with PIE enabled by default.  GHC detects+  this itself since ghc-8.0.2, and Stack's attempted workaround for older+  versions caused more problems than it solved.+* `stack new` no longer initializes a project if the project template contains+   a stack.yaml file.++Other enhancements:++* A new sub command `ls` has been introduced to stack to view+  local and remote snapshots present in the system. Use `stack ls+  snapshots --help` to get more details about it.+* `list-dependencies` has been deprecated. The functionality has+  to accessed through the new `ls dependencies` interface. See+  [#3669](https://github.com/commercialhaskell/stack/issues/3669)+  for details.+* Specify User-Agent HTTP request header on every HTTP request.+  See [#3628](https://github.com/commercialhaskell/stack/issues/3628) for details.+* `stack setup` looks for GHC bindists and installations by any OS key+  that is compatible (rather than only checking a single one).   This is+  relevant on Linux where different distributions may have different+  combinations of libtinfo 5/6, ncurses 5/6, and gmp 4/5, and will allow+  simpifying the setup-info metadata YAML for future GHC releases.+* The build progress bar reports names of packages currently building.+* `stack setup --verbose` causes verbose output of GHC configure process.+  See [#3716](https://github.com/commercialhaskell/stack/issues/3716)+* Improve the error message when an `extra-dep` from a path or git reference can't be found+  See [#3808](https://github.com/commercialhaskell/stack/pull/3808)+* Nix integration is now disabled on windows even if explicitly enabled,+  since it isn't supported. See+  [#3600](https://github.com/commercialhaskell/stack/issues/3600)+* `stack build` now supports a new flag `--keep-tmp-files` to retain intermediate+  files and directories for the purpose of debugging.+  It is best used with ghc's equivalent flag,+  i.e. `stack build --keep-tmp-files --ghc-options=-keep-tmp-files`.+  See [#3857](https://github.com/commercialhaskell/stack/issues/3857)+* Improved error messages for snapshot parse exceptions+* `stack unpack` now supports a `--to /target/directory` option to+  specify where to unpack the package into+* `stack hoogle` now supports a new flag `--server` that launches local+  Hoogle server on port 8080. See+  [#2310](https://github.com/commercialhaskell/stack/issues/2310)++Bug fixes:++* The script interpreter's implicit file arguments are now passed before other+  arguments. See [#3658](https://github.com/commercialhaskell/stack/issues/3658).+  In particular, this makes it possible to pass `-- +RTS ... -RTS` to specify+  RTS arguments used when running the script.+* Don't ignore the template `year` parameter in config files, and clarify the+  surrounding documentation. See+  [#2275](https://github.com/commercialhaskell/stack/issues/2275).+* Benchmarks used to be run concurrently with other benchmarks+  and build steps. This is non-ideal because CPU usage of other processes+  may interfere with benchmarks. It also prevented benchmark output from+  being displayed by default. This is now fixed. See+  [#3663](https://github.com/commercialhaskell/stack/issues/3663).+* `stack ghci` now allows loading multiple packages with the same+  module name, as long as they have the same filepath. See+  [#3776](https://github.com/commercialhaskell/stack/pull/3776).+* `stack ghci` no longer always adds a dependency on `base`. It is+  now only added when there are no local targets. This allows it to+  be to load code that uses replacements for `base`. See+  [#3589](https://github.com/commercialhaskell/stack/issues/3589#issuecomment)+* `stack ghci` now uses correct paths for autogen files with+  [#3791](https://github.com/commercialhaskell/stack/issues/3791)+* When a package contained sublibraries, stack was always recompiling the+  package. This has been fixed now, no recompilation is being done because of+  sublibraries. See [#3899](https://github.com/commercialhaskell/stack/issues/3899).+* The `get-stack.sh` install script now matches manual instructions+  when it comes to Debian/Fedora/CentOS install dependencies.+* Compile Cabal-simple with gmp when using Nix.+  See [#2944](https://github.com/commercialhaskell/stack/issues/2944)+* `stack ghci` now replaces the stack process with ghci. This improves+  signal handling behavior. In particular, handling of Ctrl-C.  To make+  this possible, the generated files are now left behind after exit.+  The paths are based on hashing file contents, and it's stored in the+  system temporary directory, so this shouldn't result in too much+  garbage. See+  [#3821](https://github.com/commercialhaskell/stack/issues/3821).++ ## v1.6.5  Bug fixes:-* 1.6.1 introduced a change that made some precompiled cache files use-  longer paths, sometimes causing builds to fail on windows. This has been-  fixed. See [#3649](https://github.com/commercialhaskell/stack/issues/3649)+ * Some unnecessary rebuilds when no files were changed are now avoided, by   having a separate build cache for each component of a package. See   [#3732](https://github.com/commercialhaskell/stack/issues/3732).@@ -111,7 +205,7 @@ * Stack will ask before saving hackage credentials to file. This new   prompt can be avoided by using the `save-hackage-creds` setting. Please   see [#2159](https://github.com/commercialhaskell/stack/issues/2159).-* The `GHCRTS` environment variable will no longer be passed through to +* The `GHCRTS` environment variable will no longer be passed through to   every program stack runs. Instead, it will only be passed through   commands like `exec`, `runghc`, `script`, `ghci`, etc.   See [#3444](https://github.com/commercialhaskell/stack/issues/3444).@@ -693,7 +787,7 @@   version 1.1.2 for now on those architectures.  This will be rectified soon!  * We are now releasing a-  [statically linked Stack binary for 64-bit Linux](https://www.stackage.org/stack/linux-x86_64-static).+  [statically linked Stack binary for 64-bit Linux](https://get.haskellstack.org/stable/linux-x86_64-static.tar.gz).   Please try it and let us know if you run into any trouble on your platform.  * We are planning some changes to our Linux releases, including dropping our
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2015-2017, Stack contributors+Copyright (c) 2015-2018, Stack contributors All rights reserved.  Redistribution and use in source and binary forms, with or without
README.md view
@@ -6,5 +6,5 @@  Stack is a cross-platform program for developing Haskell projects. It is intended for Haskellers both new and experienced. -See [haskellstack.org](http://haskellstack.org) or the `doc` directory for more+See [haskellstack.org](http://haskellstack.org) or the [doc](./doc) directory for more information.
doc/CONTRIBUTING.md view
@@ -135,7 +135,7 @@ Running the integration tests is a little involved, you'll need to:  ```bash-$ stack test stack:integration-test --flag stack:stack-integration-tests+$ stack test stack:stack-integration-test --flag stack:integration-tests ```  Running an individual module works like this:@@ -159,3 +159,12 @@ Where again, `<PATTERN>` is the name of the folder listed in the [test/integration/tests/](https://github.com/commercialhaskell/stack/tree/master/test/integration/tests) folder.+++## Slack channel++If you're making deep changes and real-time communcation with the Stack team+would be helpful, we have a `#stack-collaborators` Slack channel.  Please+contact [@borsboom](https://github.com/borsboom) (manny@fpcomplete.com) or+[@snoyberg](https://github.com/snoyberg) (michael@fpcomplete.com) for an+invite.
doc/ChangeLog.md view
@@ -1,12 +1,106 @@ # Changelog  +## v1.7.1++Release notes:++* aarch64 (64-bit ARM) bindists are now available for the first time.+* Statically linked Linux bindists are no longer available, due to difficulty with GHC 8.2.2 on Alpine Linux.+* 32-bit Linux GMP4 bindists for CentOS 6 are no longer available, since GHC 8.2.2 is no longer being built for that platform.++Major changes:++* Upgrade from Cabal 2.0 to Cabal 2.2++Behavior changes:++* `stack setup` no longer uses different GHC configure options on Linux+  distributions that use GCC with PIE enabled by default.  GHC detects+  this itself since ghc-8.0.2, and Stack's attempted workaround for older+  versions caused more problems than it solved.+* `stack new` no longer initializes a project if the project template contains+   a stack.yaml file.++Other enhancements:++* A new sub command `ls` has been introduced to stack to view+  local and remote snapshots present in the system. Use `stack ls+  snapshots --help` to get more details about it.+* `list-dependencies` has been deprecated. The functionality has+  to accessed through the new `ls dependencies` interface. See+  [#3669](https://github.com/commercialhaskell/stack/issues/3669)+  for details.+* Specify User-Agent HTTP request header on every HTTP request.+  See [#3628](https://github.com/commercialhaskell/stack/issues/3628) for details.+* `stack setup` looks for GHC bindists and installations by any OS key+  that is compatible (rather than only checking a single one).   This is+  relevant on Linux where different distributions may have different+  combinations of libtinfo 5/6, ncurses 5/6, and gmp 4/5, and will allow+  simpifying the setup-info metadata YAML for future GHC releases.+* The build progress bar reports names of packages currently building.+* `stack setup --verbose` causes verbose output of GHC configure process.+  See [#3716](https://github.com/commercialhaskell/stack/issues/3716)+* Improve the error message when an `extra-dep` from a path or git reference can't be found+  See [#3808](https://github.com/commercialhaskell/stack/pull/3808)+* Nix integration is now disabled on windows even if explicitly enabled,+  since it isn't supported. See+  [#3600](https://github.com/commercialhaskell/stack/issues/3600)+* `stack build` now supports a new flag `--keep-tmp-files` to retain intermediate+  files and directories for the purpose of debugging.+  It is best used with ghc's equivalent flag,+  i.e. `stack build --keep-tmp-files --ghc-options=-keep-tmp-files`.+  See [#3857](https://github.com/commercialhaskell/stack/issues/3857)+* Improved error messages for snapshot parse exceptions+* `stack unpack` now supports a `--to /target/directory` option to+  specify where to unpack the package into+* `stack hoogle` now supports a new flag `--server` that launches local+  Hoogle server on port 8080. See+  [#2310](https://github.com/commercialhaskell/stack/issues/2310)++Bug fixes:++* The script interpreter's implicit file arguments are now passed before other+  arguments. See [#3658](https://github.com/commercialhaskell/stack/issues/3658).+  In particular, this makes it possible to pass `-- +RTS ... -RTS` to specify+  RTS arguments used when running the script.+* Don't ignore the template `year` parameter in config files, and clarify the+  surrounding documentation. See+  [#2275](https://github.com/commercialhaskell/stack/issues/2275).+* Benchmarks used to be run concurrently with other benchmarks+  and build steps. This is non-ideal because CPU usage of other processes+  may interfere with benchmarks. It also prevented benchmark output from+  being displayed by default. This is now fixed. See+  [#3663](https://github.com/commercialhaskell/stack/issues/3663).+* `stack ghci` now allows loading multiple packages with the same+  module name, as long as they have the same filepath. See+  [#3776](https://github.com/commercialhaskell/stack/pull/3776).+* `stack ghci` no longer always adds a dependency on `base`. It is+  now only added when there are no local targets. This allows it to+  be to load code that uses replacements for `base`. See+  [#3589](https://github.com/commercialhaskell/stack/issues/3589#issuecomment)+* `stack ghci` now uses correct paths for autogen files with+  [#3791](https://github.com/commercialhaskell/stack/issues/3791)+* When a package contained sublibraries, stack was always recompiling the+  package. This has been fixed now, no recompilation is being done because of+  sublibraries. See [#3899](https://github.com/commercialhaskell/stack/issues/3899).+* The `get-stack.sh` install script now matches manual instructions+  when it comes to Debian/Fedora/CentOS install dependencies.+* Compile Cabal-simple with gmp when using Nix.+  See [#2944](https://github.com/commercialhaskell/stack/issues/2944)+* `stack ghci` now replaces the stack process with ghci. This improves+  signal handling behavior. In particular, handling of Ctrl-C.  To make+  this possible, the generated files are now left behind after exit.+  The paths are based on hashing file contents, and it's stored in the+  system temporary directory, so this shouldn't result in too much+  garbage. See+  [#3821](https://github.com/commercialhaskell/stack/issues/3821).++ ## v1.6.5  Bug fixes:-* 1.6.1 introduced a change that made some precompiled cache files use-  longer paths, sometimes causing builds to fail on windows. This has been-  fixed. See [#3649](https://github.com/commercialhaskell/stack/issues/3649)+ * Some unnecessary rebuilds when no files were changed are now avoided, by   having a separate build cache for each component of a package. See   [#3732](https://github.com/commercialhaskell/stack/issues/3732).@@ -111,7 +205,7 @@ * Stack will ask before saving hackage credentials to file. This new   prompt can be avoided by using the `save-hackage-creds` setting. Please   see [#2159](https://github.com/commercialhaskell/stack/issues/2159).-* The `GHCRTS` environment variable will no longer be passed through to +* The `GHCRTS` environment variable will no longer be passed through to   every program stack runs. Instead, it will only be passed through   commands like `exec`, `runghc`, `script`, `ghci`, etc.   See [#3444](https://github.com/commercialhaskell/stack/issues/3444).@@ -693,7 +787,7 @@   version 1.1.2 for now on those architectures.  This will be rectified soon!  * We are now releasing a-  [statically linked Stack binary for 64-bit Linux](https://www.stackage.org/stack/linux-x86_64-static).+  [statically linked Stack binary for 64-bit Linux](https://get.haskellstack.org/stable/linux-x86_64-static.tar.gz).   Please try it and let us know if you run into any trouble on your platform.  * We are planning some changes to our Linux releases, including dropping our
doc/GUIDE.md view
@@ -427,7 +427,7 @@ also known as *snapshots*. We mentioned the LTS resolvers, and you can get quite a bit of information about it at [https://www.stackage.org/lts](https://www.stackage.org/lts), including: -* The appropriate resolver value (`resolver: lts-10.0`, as is currently the latest LTS)+* The appropriate resolver value (`resolver: lts-11.6`, as is currently the latest LTS) * The GHC version used * A full list of all packages available in this snapshot * The ability to perform a Hoogle search on the packages in this snapshot@@ -444,7 +444,7 @@  ## Resolvers and changing your compiler version -Let's explore package sets a bit further. Instead of lts-10.0, let's change our+Let's explore package sets a bit further. Instead of lts-11.6, let's change our `stack.yaml` file to use [the latest nightly](https://www.stackage.org/nightly). Right now, this is currently 2017-12-19 - please see the resolve from the link above to get the latest. @@ -460,8 +460,8 @@ Continuous Integration (CI) setting, like on Travis. For example:  ```-michael@d30748af6d3d:~/helloworld$ stack --resolver lts-9.18 build-Downloaded lts-9.18 build plan.+michael@d30748af6d3d:~/helloworld$ stack --resolver lts-11.6 build+Downloaded lts-11.6 build plan. # build output ... ``` @@ -482,7 +482,7 @@ snapshot:  ```-michael@d30748af6d3d:~/helloworld$ stack --resolver lts-9 build+michael@d30748af6d3d:~/helloworld$ stack --resolver lts-2 build # build output ... ``` @@ -517,6 +517,15 @@ cueball:~$ cd yackage-0.8.0/ ``` +Note that you can also unpack to the directory of your liking instead of+the current one by issueing:++```+cueball:~$ stack unpack yackage-0.8.0 --to ~/work+```++This will create a `yackage-0.8.0` directory inside `~/work`+ ### stack init This new directory does not have a `stack.yaml` file, so we need to make one first. We could do it by hand, but let's be lazy instead with the `stack init`@@ -1715,7 +1724,8 @@   upstream packages available). * `stack unpack` is a command we've already used quite a bit for examples, but   most users won't use it regularly. It does what you'd expect: downloads a-  tarball and unpacks it.+  tarball and unpacks it. It accept optional `--to` argument to specify+  the destination directory. * `stack sdist` generates an uploading tarball containing your package code * `stack upload` uploads an sdist to Hackage. As of   version [1.1.0](https://docs.haskellstack.org/en/v1.1.0/ChangeLog/) stack@@ -1730,7 +1740,11 @@   library, used for performing actual builds. You shouldn't generally do this,   since new Cabal versions may introduce incompatibilities with package sets,   but it can be useful if you're trying to test a specific bugfix.-* `stack list-dependencies` lists all of the packages and versions used for a+* `stack ls snapshots` will list all the local snapshots by+  default. You can also view the remote snapshots using `stack ls+  snapshots remote`. It also supports option for viewing only lts+  (`-l`) and nightly (`-n`) snapshots.+* `stack ls dependencies` lists all of the packages and versions used for a   project * `stack sig` subcommand can help you with GPG signing & verification     * `sign` will sign an sdist tarball and submit the signature to
doc/README.md view
@@ -26,7 +26,7 @@     wget -qO- https://get.haskellstack.org/ | sh  On Windows, you can download and install the-[Windows 64-bit Installer](https://www.stackage.org/stack/windows-x86_64-installer).+[Windows 64-bit Installer](https://get.haskellstack.org/stable/windows-x86_64-installer.exe).  For detailed instructions and downloads, including many additional operating systems, check out the
doc/install_and_upgrade.md view
@@ -14,23 +14,22 @@ [Fedora](#fedora), [Arch Linux](#arch-linux) and [FreeBSD](#freebsd). Binaries for other operating systems are listed below, and available on-[the Github releases page](https://github.com/fpco/stack/releases). For the+[the GitHub release page](https://github.com/fpco/stack/releases). For the future, we are open to supporting more OSes (to request one, please [submit an issue](https://github.com/commercialhaskell/stack/issues/new)).  Binary packages are signed with this [signing key](SIGNING_KEY.md).  If you are writing a script that needs to download the latest binary, you can-find links that always point to the latest bindists-[here](https://www.stackage.org/stack).+use URLs like `https://get.haskellstack.org/stable/<PLATFORM>.<EXTENSION>` (e.g. //get.haskellstack.org/stable/linux-x86_64.tar.gz) that always point to the latest stable release.  ## Windows  We recommend installing to the default location with these installers, as that will make `stack install` and `stack upgrade` work correctly out of the box. -  * [Windows 64-bit Installer](https://www.stackage.org/stack/windows-x86_64-installer)-  * [Windows 32-bit Installer](https://www.stackage.org/stack/windows-i386-installer)+  * [Windows 64-bit Installer](https://get.haskellstack.org/stable/windows-x86_64-installer.exe)+  * [Windows 32-bit Installer](https://get.haskellstack.org/stable/windows-i386-installer.exe)  If in doubt: you should prefer the 64-bit installer. @@ -42,8 +41,8 @@  * Download the latest release: -    * [Windows 64-bit](https://www.stackage.org/stack/windows-x86_64)-    * [Windows 32-bit](https://www.stackage.org/stack/windows-i386)+    * [Windows 64-bit](https://get.haskellstack.org/stable/windows-x86_64.zip)+    * [Windows 32-bit](https://get.haskellstack.org/stable/windows-i386.zip)  * Unpack the archive and place `stack.exe` somewhere on your `%PATH%` (see   [Path section below](#path)) and you can then run `stack` on the command line.@@ -65,7 +64,7 @@ ### Manual download  * Download the latest release:-    * [macOS 64-bit](https://www.stackage.org/stack/osx-x86_64)+    * [macOS 64-bit](https://get.haskellstack.org/stable/osx-x86_64.tar.gz) * Extract the archive and place `stack` somewhere on your `$PATH` (see   [Path section below](#path)) * Now you can run `stack` from the terminal.@@ -106,7 +105,7 @@ package](http://packages.ubuntu.com/search?keywords=haskell-stack&searchon=names&suite=all&section=all) for Ubuntu 16.10 and up, but the distribution's Stack version lags behind, so we recommend running `stack upgrade --binary` after installing it. For older stack-versions which do not support `--binary`, just `stack upgrade` is fine too. The+versions which do not support `--binary`, just `stack upgrade` may work too. The version in Ubuntu 16.04 is too old to upgrade successfully, and so in that case stack should be installed from a [release tarball](https://github.com/commercialhaskell/stack/releases).@@ -119,7 +118,7 @@ package](https://packages.debian.org/search?keywords=haskell-stack&searchon=names&suite=all&section=all) for Stretch and up, but the distribution's Stack version lags behind, so running `stack upgrade --binary` is recommended after installing it. For older stack-versions which do not support `--binary`, just `stack upgrade` is fine too.+versions which do not support `--binary`, just `stack upgrade` may work too.  ## <a name="centos"></a>CentOS / Red Hat / Amazon Linux @@ -175,7 +174,7 @@     sudo pacman -S stack  Note that this version may slightly lag behind, but it should be updated within-the day. The package is also always rebuilt and updated when one of it's+the day. The package is also always rebuilt and updated when one of its dependencies gets an update.    - [stack](https://www.archlinux.org/packages/community/x86_64/stack/) _latest stable version_@@ -233,14 +232,22 @@  * Download the latest release: -    * [Linux 64-bit, static](https://www.stackage.org/stack/linux-x86_64-static)+    * [Linux 64-bit, standard](https://get.haskellstack.org/stable/linux-x86_64.tar.gz) -    * [Linux 32-bit, standard](https://www.stackage.org/stack/linux-i386)+    * [Linux 64-bit, libgmp4](https://get.haskellstack.org/stable/linux-x86_64-gmp4.tar.gz)+      (if you are on an older 64-bit distribution that only includes libgmp4+      (libgmp.so.3), such as CentOS/RHEL/Amazon Linux 6.) -    * [Linux 32-bit, libgmp4](https://www.stackage.org/stack/linux-i386-gmp4)+    * [Linux 32-bit, standard](https://get.haskellstack.org/stable/linux-i386.tar.gz)++    * [Linux 32-bit, libgmp4](https://get.haskellstack.org/stable/linux-i386-gmp4.tar.gz)       (if you are on an older 32-bit distribution that only includes libgmp4       (libgmp.so.3), such as CentOS/RHEL/Amazon Linux 6.) +    * [Linux ARMv7](https://get.haskellstack.org/stable/linux-arm.tar.gz)++    * [Linux AArch64](https://get.haskellstack.org/stable/linux-aarch64.tar.gz)+ * Extract the archive and place `stack` somewhere on your `$PATH` (see [Path section below](#path))  * Ensure you have required system dependencies installed.  These include GCC, GNU make, xz, perl, libgmp, libffi, and zlib.  We also recommend Git and GPG.  To install these using your package manager:@@ -279,7 +286,7 @@  * Download the latest release: -    * [FreeBSD 64-bit](https://www.stackage.org/stack/freebsd-x86_64)+    * [FreeBSD 64-bit](https://get.haskellstack.org/stable/freebsd-x86_64.tar.gz)  * Extract the archive and place `stack` somewhere on your `$PATH` (see [Path section below](#path)) 
doc/travis_ci.md view
@@ -71,7 +71,7 @@ # Download and unpack the stack executable - mkdir -p ~/.local/bin - export PATH=$HOME/.local/bin:$PATH-- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'+- travis_retry curl -L https://get.haskellstack.org/stable/linux-x86_64.tar.gz | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' ```  ## Installing GHC
doc/yaml_configuration.md view
@@ -164,11 +164,6 @@ number is likely simpler to use. In practice, both should guarantee equally reproducible build plans. -If unspecified, `subdirs` defaults to `['.']` (i.e. look only in the top-level-directory).  Note that if you specify a value of `subdirs`, then `'.'` is _not_-included by default and needs to be explicitly specified if a required package-is found in the top-level directory of the repository.- #### Local file path  Like `packages`, local file paths can be used in `extra-deps`, and@@ -231,8 +226,11 @@   - wai ``` -If unspecified, `subdirs` defaults to `subdirs: [.]`, or looking for a-package in the root of the repo.+If unspecified, `subdirs` defaults to `['.']` meaning looking for a+package in the root of the repo..  Note that if you specify a value of+`subdirs`, then `'.'` is _not_ included by default and needs to be+explicitly specified if a required package is found in the top-level+directory of the repository.  #### Archives (HTTP(S) or local filepath) @@ -747,6 +745,7 @@   copy-bins: false   prefetch: false   keep-going: false+  keep-tmp-files: false    # NOTE: global usage of haddock can cause build failures when documentation is   # incorrectly formatted.  This could also affect scripts which use stack.@@ -803,9 +802,10 @@  Templates used with `stack new` have a number of parameters that affect the generated code. These can be set for all new projects you create. The result of-them can be observed in the generated LICENSE and cabal files.+them can be observed in the generated LICENSE and cabal files. The value for all+of these parameters must be strings. -The 5 parameters are: `author-email`, `author-name`, `category`, `copyright` and `github-username`.+The parameters are: `author-email`, `author-name`, `category`, `copyright`, `year` and `github-username`.  * _author-email_ - sets the `maintainer` property in cabal * _author-name_ - sets the `author` property in cabal and the name used in@@ -819,6 +819,9 @@ * _copyright_ - sets the `copyright` property in cabal. It is typically the   name of the holder of the copyright on the package and the year(s) from which   copyright is claimed. For example: `Copyright (c) 2006-2007 Joe Bloggs`+* _year_ - if `copyright` is not specified, `year` and `author-name` are used+  to generate the copyright property in cabal. If `year` is not specified, it+  defaults to the current year. * _github-username_ - used to generate `homepage` and `source-repository` in   cabal. For instance `github-username: myusername` and `stack new my-project new-template`   would result:@@ -838,7 +841,7 @@     author-name: Your Name     author-email: youremail@example.com     category: Your Projects Category-    copyright: 'Copyright (c) 2017 Your Name'+    copyright: 'Copyright (c) 2018 Your Name'     github-username: yourusername ``` 
− package.yaml
@@ -1,340 +0,0 @@-name: stack-version: '1.6.5'-synopsis: The Haskell Tool Stack-description: ! 'Please see the README.md for usage information, and-  the wiki on Github for more details.  Also, note that-  the API for the library is not currently stable, and may-  change significantly, even between minor releases. It is-  currently only intended for use by the executable.'-category: Development-author: Commercial Haskell SIG-maintainer: manny@fpcomplete.com-license: BSD3-github: commercialhaskell/stack-homepage: http://haskellstack.org-custom-setup:-  dependencies:-  - base-  - Cabal-  - filepath-extra-source-files:-- CONTRIBUTING.md-- ChangeLog.md-- README.md-- doc/*.md-- package.yaml-- src/setup-shim/StackSetupShim.hs-- stack.yaml-- test/package-dump/ghc-7.10.txt-- test/package-dump/ghc-7.8.4-osx.txt-- test/package-dump/ghc-7.8.txt-ghc-options:-- -Wall-- -fwarn-tabs-- -fwarn-incomplete-uni-patterns-- -fwarn-incomplete-record-updates-dependencies:-- Cabal-- aeson-- annotated-wl-pprint-- ansi-terminal-- async-- attoparsec-- base >=4.9 && < 5-- base64-bytestring-- blaze-builder-- bytestring-- clock-- conduit-- conduit-extra-- containers-- cryptonite-- cryptonite-conduit-- deepseq-- directory-- echo-- exceptions-- extra-- fast-logger-- file-embed-- filelock-- filepath-- fsnotify-- generic-deriving-- hackage-security-- hashable-- hastache-- hpack-- hpc-- http-client-- http-client-tls-- http-conduit-- http-types-- memory-- microlens-- microlens-mtl-- mintty-- monad-logger-- mono-traversable-- mtl-- neat-interpolation-- network-uri-- open-browser-- optparse-applicative-- path-- path-io-- persistent-- persistent-sqlite-- persistent-template-- pretty-- primitive-- process-- project-template-- regex-applicative-text-- resourcet-- retry-- semigroups-- split-- stm-- store-- store-core-- streaming-commons-- tar-- template-haskell-- temporary-- text-- text-metrics-- th-reify-many-- time-- tls-- transformers-- unicode-transforms-- unix-compat-- unliftio-- unordered-containers-- vector-- yaml-- zip-archive-- zlib-when:-- condition: os(windows)-  then:-    cpp-options: -DWINDOWS-    dependencies:-    - Win32-  else:-    build-tools:-    - hsc2hs-    dependencies:-    - bindings-uname-    - pid1-    - unix-library:-  source-dirs: src/-  ghc-options:-  - -fwarn-identities-  exposed-modules:-  - Control.Concurrent.Execute-  - Data.Aeson.Extended-  - Data.Attoparsec.Args-  - Data.Attoparsec.Combinators-  - Data.Attoparsec.Interpreter-  - Data.IORef.RunOnce-  - Data.Store.VersionTagged-  - Network.HTTP.Download-  - Network.HTTP.Download.Verified-  - Options.Applicative.Args-  - Options.Applicative.Builder.Extra-  - Options.Applicative.Complicated-  - Path.CheckInstall-  - Path.Extra-  - Path.Find-  - Paths_stack-  - Stack.Build-  - Stack.Build.Cache-  - Stack.Build.ConstructPlan-  - Stack.Build.Execute-  - Stack.Build.Haddock-  - Stack.Build.Installed-  - Stack.Build.Source-  - Stack.Build.Target-  - Stack.BuildPlan-  - Stack.Clean-  - Stack.Config-  - Stack.Config.Build-  - Stack.Config.Urls-  - Stack.Config.Docker-  - Stack.Config.Nix-  - Stack.ConfigCmd-  - Stack.Constants-  - Stack.Constants.Config-  - Stack.Coverage-  - Stack.Docker-  - Stack.Docker.GlobalDB-  - Stack.Dot-  - Stack.Exec-  - Stack.Fetch-  - Stack.FileWatch-  - Stack.GhcPkg-  - Stack.Ghci-  - Stack.Ghci.Script-  - Stack.Hoogle-  - Stack.IDE-  - Stack.Image-  - Stack.Init-  - Stack.New-  - Stack.Nix-  - Stack.Options.BenchParser-  - Stack.Options.BuildMonoidParser-  - Stack.Options.BuildParser-  - Stack.Options.CleanParser-  - Stack.Options.ConfigParser-  - Stack.Options.Completion-  - Stack.Options.DockerParser-  - Stack.Options.DotParser-  - Stack.Options.ExecParser-  - Stack.Options.GhcBuildParser-  - Stack.Options.GhciParser-  - Stack.Options.GhcVariantParser-  - Stack.Options.GlobalParser-  - Stack.Options.HaddockParser-  - Stack.Options.HpcReportParser-  - Stack.Options.LogLevelParser-  - Stack.Options.NewParser-  - Stack.Options.NixParser-  - Stack.Options.PackageParser-  - Stack.Options.ResolverParser-  - Stack.Options.ScriptParser-  - Stack.Options.SDistParser-  - Stack.Options.SolverParser-  - Stack.Options.TestParser-  - Stack.Options.Utils-  - Stack.Package-  - Stack.PackageDump-  - Stack.PackageIndex-  - Stack.PackageLocation-  - Stack.Path-  - Stack.Prelude-  - Stack.PrettyPrint-  - Stack.Runners-  - Stack.Script-  - Stack.SDist-  - Stack.Setup-  - Stack.Setup.Installed-  - Stack.SetupCmd-  - Stack.Sig-  - Stack.Sig.GPG-  - Stack.Sig.Sign-  - Stack.Snapshot-  - Stack.Solver-  - Stack.StaticBytes-  - Stack.Types.Build-  - Stack.Types.BuildPlan-  - Stack.Types.CompilerBuild-  - Stack.Types.Urls-  - Stack.Types.Compiler-  - Stack.Types.Config-  - Stack.Types.Config.Build-  - Stack.Types.Docker-  - Stack.Types.FlagName-  - Stack.Types.GhcPkgId-  - Stack.Types.Image-  - Stack.Types.Nix-  - Stack.Types.Package-  - Stack.Types.PackageDump-  - Stack.Types.PackageIdentifier-  - Stack.Types.PackageIndex-  - Stack.Types.PackageName-  - Stack.Types.Resolver-  - Stack.Types.Runner-  - Stack.Types.Sig-  - Stack.Types.TemplateName-  - Stack.Types.Version-  - Stack.Types.VersionIntervals-  - Stack.Upgrade-  - Stack.Upload-  - Text.PrettyPrint.Leijen.Extended-  - System.Process.Log-  - System.Process.PagerEditor-  - System.Process.Read-  - System.Process.Run-  - System.Terminal-  other-modules:-  - Hackage.Security.Client.Repository.HttpLib.HttpClient-  when:-  - condition: 'os(windows)'-    then:-      source-dirs: src/windows/-    else:-      source-dirs: src/unix/-executables:-  stack:-    main: Main.hs-    source-dirs: src/main-    ghc-options:-    - -threaded-    dependencies:-    - stack-    other-modules:-    - Paths_stack-    when:-    - condition: flag(static)-      ld-options:-      - -static-      - -pthread-    - condition: ! '!(flag(disable-git-info))'-      cpp-options: -DUSE_GIT_INFO-      dependencies:-      - gitrev-      - optparse-simple-    - condition: flag(hide-dependency-versions)-      cpp-options: -DHIDE_DEP_VERSIONS-    - condition: flag(supported-build)-      cpp-options: -DSUPPORTED_BUILD-tests:-  stack-test:-    main: Test.hs-    source-dirs: src/test-    ghc-options:-    - -threaded-    dependencies:-    - QuickCheck-    - hspec-    - stack-    - smallcheck-  stack-integration-test:-    main: IntegrationSpec.hs-    source-dirs:-    - test/integration-    - test/integration/lib-    ghc-options:-    - -threaded-    - -rtsopts-    - -with-rtsopts=-N-    dependencies:-    - hspec-    when:-    - condition: ! '!(flag(integration-tests))'-      buildable: false-flags:-  static:-    description: Pass -static/-pthread to ghc when linking the stack binary.-    manual: true-    default: false-  disable-git-info:-    description: Disable compile-time inclusion of current git info in stack-    manual: true-    default: false-  hide-dependency-versions:-    description: Hides dependency versions from "stack --version", used only by building-      with stack.yaml-    manual: true-    default: false-  integration-tests:-    description: Run the integration test suite-    manual: true-    default: false-  supported-build:-    description: If false, causes "stack --version" to issue a warning about the build being unsupported.  True only if building with stack.yaml-    manual: true-    default: false
src/Control/Concurrent/Execute.hs view
@@ -8,32 +8,49 @@     , ActionId (..)     , ActionContext (..)     , Action (..)+    , Concurrency(..)     , runActions     ) where  import           Control.Concurrent.STM   (retry) import           Stack.Prelude+import           Data.List (sortBy) import qualified Data.Set                 as Set import           Stack.Types.PackageIdentifier  data ActionType     = ATBuild+      -- ^ Action for building a package's library and executables. If+      -- 'taskAllInOne' is 'True', then this will also build benchmarks+      -- and tests. It is 'False' when then library's benchmarks or+      -- test-suites have cyclic dependencies.     | ATBuildFinal-    | ATFinal+      -- ^ Task for building the package's benchmarks and test-suites.+      -- Requires that the library was already built.+    | ATRunTests+      -- ^ Task for running the package's test-suites.+    | ATRunBenchmarks+      -- ^ Task for running the package's benchmarks.     deriving (Show, Eq, Ord) data ActionId = ActionId !PackageIdentifier !ActionType     deriving (Show, Eq, Ord) data Action = Action-    { actionId   :: !ActionId+    { actionId :: !ActionId     , actionDeps :: !(Set ActionId)-    , actionDo   :: !(ActionContext -> IO ())+    , actionDo :: !(ActionContext -> IO ())+    , actionConcurrency :: !Concurrency     } +data Concurrency = ConcurrencyAllowed | ConcurrencyDisallowed+    deriving (Eq)+ data ActionContext = ActionContext     { acRemaining :: !(Set ActionId)     -- ^ Does not include the current action     , acDownstream :: [Action]     -- ^ Actions which depend on the current action+    , acConcurrency :: !Concurrency+    -- ^ Whether this action may be run concurrently with others     }  data ExecuteState = ExecuteState@@ -41,7 +58,6 @@     , esExceptions :: TVar [SomeException]     , esInAction   :: TVar (Set ActionId)     , esCompleted  :: TVar Int-    , esFinalLock  :: Maybe (TMVar ())     , esKeepGoing  :: Bool     } @@ -56,26 +72,34 @@  runActions :: Int -- ^ threads            -> Bool -- ^ keep going after one task has failed-           -> Bool -- ^ run final actions concurrently?            -> [Action]-           -> (TVar Int -> IO ()) -- ^ progress updated+           -> (TVar Int -> TVar (Set ActionId) -> IO ()) -- ^ progress updated            -> IO [SomeException]-runActions threads keepGoing concurrentFinal actions0 withProgress = do+runActions threads keepGoing actions0 withProgress = do     es <- ExecuteState-        <$> newTVarIO actions0+        <$> newTVarIO (sortActions actions0)         <*> newTVarIO []         <*> newTVarIO Set.empty         <*> newTVarIO 0-        <*> (if concurrentFinal-                then pure Nothing-                else Just <$> atomically (newTMVar ()))         <*> pure keepGoing-    _ <- async $ withProgress $ esCompleted es+    _ <- async $ withProgress (esCompleted es) (esInAction es)     if threads <= 1         then runActions' es         else replicateConcurrently_ threads $ runActions' es     readTVarIO $ esExceptions es +-- | Sort actions such that those that can't be run concurrently are at+-- the end.+sortActions :: [Action] -> [Action]+sortActions = sortBy (compareConcurrency `on` actionConcurrency)+  where+    -- NOTE: Could derive Ord. However, I like to make this explicit so+    -- that changes to the datatype must consider how it's affecting+    -- this.+    compareConcurrency ConcurrencyAllowed ConcurrencyDisallowed = LT+    compareConcurrency ConcurrencyDisallowed ConcurrencyAllowed = GT+    compareConcurrency _ _ = EQ+ runActions' :: ExecuteState -> IO () runActions' ExecuteState {..} =     loop@@ -101,16 +125,12 @@                         return $ return ()                     else retry             (xs, action:ys) -> do-                unlock <--                    case (actionId action, esFinalLock) of-                        (ActionId _ ATFinal, Just lock) -> do-                            takeTMVar lock-                            return $ putTMVar lock ()-                        _ -> return $ return ()--                let as' = xs ++ ys                 inAction <- readTVar esInAction-                let remaining = Set.union+                case actionConcurrency action of+                  ConcurrencyAllowed -> return ()+                  ConcurrencyDisallowed -> unless (Set.null inAction) retry+                let as' = xs ++ ys+                    remaining = Set.union                         (Set.fromList $ map actionId as')                         inAction                 writeTVar esActions as'@@ -119,9 +139,9 @@                     eres <- try $ restore $ actionDo action ActionContext                         { acRemaining = remaining                         , acDownstream = downstreamActions (actionId action) as'+                        , acConcurrency = actionConcurrency action                         }                     atomically $ do-                        unlock                         modifyTVar esInAction (Set.delete $ actionId action)                         modifyTVar esCompleted (+1)                         case eres of
src/Data/Aeson/Extended.hs view
@@ -100,10 +100,10 @@  -- | Log JSON warnings. logJSONWarnings-    :: MonadLogger m+    :: (MonadReader env m, HasLogFunc env, HasCallStack, MonadIO m)     => FilePath -> [JSONWarning] -> m () logJSONWarnings fp =-    mapM_ (\w -> logWarn ("Warning: " <> T.pack fp <> ": " <> T.pack (show w)))+    mapM_ (\w -> logWarn ("Warning: " <> fromString fp <> ": " <> displayShow w))  -- | Handle warnings in a sub-object. jsonSubWarnings :: WarningParser (WithJSONWarnings a) -> WarningParser a@@ -142,24 +142,29 @@     { wpmExpectedFields :: !(Set Text)     , wpmWarnings :: [JSONWarning]     } deriving Generic+instance Semigroup WarningParserMonoid where+    (<>) = mappenddefault instance Monoid WarningParserMonoid where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>) instance IsString WarningParserMonoid where     fromString s = mempty { wpmWarnings = [fromString s] }  -- Parsed JSON value with its warnings data WithJSONWarnings a = WithJSONWarnings a [JSONWarning]-    deriving Generic+    deriving (Eq, Generic, Show) instance Functor WithJSONWarnings where     fmap f (WithJSONWarnings x w) = WithJSONWarnings (f x) w+instance Monoid a => Semigroup (WithJSONWarnings a) where+    (<>) = mappenddefault instance Monoid a => Monoid (WithJSONWarnings a) where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  -- | Warning output from 'WarningParser'. data JSONWarning = JSONUnrecognizedFields String [Text]                  | JSONGeneralWarning !Text+    deriving Eq instance Show JSONWarning where     show (JSONUnrecognizedFields obj [field]) =         "Unrecognized field in " <> obj <> ": " <> T.unpack field
src/Data/Attoparsec/Combinators.hs view
@@ -6,7 +6,7 @@ import Stack.Prelude  -- | Concatenate two parsers.-appending :: (Applicative f,Monoid a)+appending :: (Applicative f,Semigroup a)                  => f a -> f a -> f a appending a b = (<>) <$> a <*> b 
src/Data/Attoparsec/Interpreter.hs view
@@ -60,7 +60,6 @@ import           Data.Char (isSpace) import           Data.Conduit import           Data.Conduit.Attoparsec-import qualified Data.Conduit.Binary as CB import           Data.Conduit.Text (decodeUtf8) import           Data.List (intercalate) import           Data.Text (pack)@@ -113,15 +112,16 @@ -- comment when it is being used as an interpreter getInterpreterArgs :: String -> IO [String] getInterpreterArgs file = do-  eArgStr <- withBinaryFile file ReadMode parseFile+  eArgStr <- withSourceFile file parseFile   case eArgStr of     Left err -> handleFailure $ decodeError err     Right str -> parseArgStr str   where-    parseFile h =-      CB.sourceHandle h-      =$= decodeUtf8-      $$ sinkParserEither (interpreterArgsParser isLiterate stackProgName)+    parseFile src =+         runConduit+       $ src+      .| decodeUtf8+      .| sinkParserEither (interpreterArgsParser isLiterate stackProgName)      isLiterate = takeExtension file == ".lhs" 
src/Data/Store/VersionTagged.hs view
@@ -22,7 +22,6 @@ import Data.Store import Data.Store.Core (unsafeEncodeWith) import Data.Store.Version-import qualified Data.Text as T import Language.Haskell.TH import Path import Path.IO (ensureDir)@@ -37,14 +36,14 @@ versionedDecodeFile vc = [e| versionedDecodeFileImpl $(decodeWithVersionQ vc) |]  -- | Write to the given file.-storeEncodeFile :: (Store a, MonadIO m, MonadLogger m, Eq a)+storeEncodeFile :: (Store a, MonadIO m, MonadReader env m, HasCallStack, HasLogFunc env, Eq a)                 => (a -> (Int, Poke ()))                 -> Peek a                 -> Path Abs File                 -> a                 -> m () storeEncodeFile pokeFunc peekFunc fp x = do-    let fpt = T.pack (toFilePath fp)+    let fpt = fromString (toFilePath fp)     logDebug $ "Encoding " <> fpt     ensureDir (parent fp)     let (sz, poker) = pokeFunc x@@ -55,14 +54,14 @@ -- | Read from the given file. If the read fails, run the given action and -- write that back to the file. Always starts the file off with the -- version tag.-versionedDecodeOrLoadImpl :: (Store a, Eq a, MonadUnliftIO m, MonadLogger m)+versionedDecodeOrLoadImpl :: (Store a, Eq a, MonadUnliftIO m, MonadReader env m, HasCallStack, HasLogFunc env)                           => (a -> (Int, Poke ()))                           -> Peek a                           -> Path Abs File                           -> m a                           -> m a versionedDecodeOrLoadImpl pokeFunc peekFunc fp mx = do-    let fpt = T.pack (toFilePath fp)+    let fpt = fromString (toFilePath fp)     logDebug $ "Trying to decode " <> fpt     mres <- versionedDecodeFileImpl peekFunc fp     case mres of@@ -75,20 +74,20 @@             storeEncodeFile pokeFunc peekFunc fp x             return x -versionedDecodeFileImpl :: (Store a, MonadUnliftIO m, MonadLogger m)+versionedDecodeFileImpl :: (Store a, MonadUnliftIO m, MonadReader env m, HasCallStack, HasLogFunc env)                         => Peek a                         -> Path loc File                         -> m (Maybe a) versionedDecodeFileImpl peekFunc fp = do     mbs <- liftIO (Just <$> BS.readFile (toFilePath fp)) `catch` \(err :: IOException) -> do-        logDebug ("Exception ignored when attempting to load " <> T.pack (toFilePath fp) <> ": " <> T.pack (show err))+        logDebug ("Exception ignored when attempting to load " <> fromString (toFilePath fp) <> ": " <> displayShow err)         return Nothing     case mbs of         Nothing -> return Nothing         Just bs ->             liftIO (Just <$> decodeIOWith peekFunc bs) `catch` \(err :: PeekException) -> do-                 let fpt = T.pack (toFilePath fp)-                 logDebug ("Error while decoding " <> fpt <> ": " <> T.pack (show err) <> " (this might not be an error, when switching between stack versions)")+                 let fpt = fromString (toFilePath fp)+                 logDebug ("Error while decoding " <> fpt <> ": " <> displayShow err <> " (this might not be an error, when switching between stack versions)")                  return Nothing  storeVersionConfig :: String -> String -> VersionConfig a
src/Hackage/Security/Client/Repository/HttpLib/HttpClient.hs view
@@ -22,6 +22,7 @@ import qualified Data.ByteString.Char8        as BS.C8 import qualified Network.HTTP.Client          as HttpClient import qualified Network.HTTP.Client.Internal as HttpClient+import qualified Network.HTTP.StackClient     as StackClient import qualified Network.HTTP.Types           as HttpClient  import Hackage.Security.Client hiding (Header)@@ -69,7 +70,7 @@     -- the URI contains URL auth. Not sure if this is a concern.     request' <- HttpClient.setUri HttpClient.defaultRequest uri     let request = setRequestHeaders reqHeaders request'-    checkHttpException $ HttpClient.withResponse request manager $ \response -> do+    checkHttpException $ StackClient.withResponseByManager request manager $ \response -> do       let br = wrapCustomEx $ HttpClient.responseBody response       callback (getResponseHeaders response) br @@ -82,7 +83,7 @@     request' <- HttpClient.setUri HttpClient.defaultRequest uri     let request = setRange from to                 $ setRequestHeaders reqHeaders request'-    checkHttpException $ HttpClient.withResponse request manager $ \response -> do+    checkHttpException $ StackClient.withResponseByManager request manager $ \response -> do       let br = wrapCustomEx $ HttpClient.responseBody response       case () of          () | HttpClient.responseStatus response == HttpClient.partialContent206 ->
src/Network/HTTP/Download.hs view
@@ -15,23 +15,26 @@     , download     , redownload     , httpJSON+    , httpLbs+    , httpLBS     , parseRequest     , parseUrlThrow     , setGithubHeaders+    , withResponse     ) where  import           Stack.Prelude import           Stack.Types.Runner import qualified Data.ByteString.Lazy        as L import           Data.Conduit                (yield)-import           Data.Conduit.Binary         (sourceHandle) import qualified Data.Conduit.Binary         as CB import           Data.Text.Encoding.Error    (lenientDecode) import           Data.Text.Encoding          (decodeUtf8With) import           Network.HTTP.Client         (Request, Response, path, checkResponse, parseUrlThrow, parseRequest) import           Network.HTTP.Client.Conduit (requestHeaders) import           Network.HTTP.Download.Verified-import           Network.HTTP.Simple         (httpJSON, withResponse, getResponseBody, getResponseHeaders, getResponseStatusCode,+import           Network.HTTP.StackClient    (httpJSON, httpLbs, httpLBS, withResponse)+import           Network.HTTP.Simple         (getResponseBody, getResponseHeaders, getResponseStatusCode,                                               setRequestHeader) import           Path.IO                     (doesFileExist) import           System.Directory            (createDirectoryIfMissing,@@ -44,10 +47,10 @@ -- appropriate destination. -- -- Throws an exception if things go wrong-download :: (MonadUnliftIO m, MonadLogger m, HasRunner env, MonadReader env m)+download :: HasRunner env          => Request          -> Path Abs File -- ^ destination-         -> m Bool -- ^ Was a downloaded performed (True) or did the file already exist (False)?+         -> RIO env Bool -- ^ Was a downloaded performed (True) or did the file already exist (False)? download req destpath = do     let downloadReq = DownloadRequest             { drRequest = req@@ -61,12 +64,12 @@ -- | Same as 'download', but will download a file a second time if it is already present. -- -- Returns 'True' if the file was downloaded, 'False' otherwise-redownload :: (MonadUnliftIO m, MonadLogger m, HasRunner env, MonadReader env m)+redownload :: HasRunner env            => Request            -> Path Abs File -- ^ destination-           -> m Bool+           -> RIO env Bool redownload req0 dest = do-    logDebug $ "Downloading " <> decodeUtf8With lenientDecode (path req0)+    logDebug $ "Downloading " <> display (decodeUtf8With lenientDecode (path req0))     let destFilePath = toFilePath dest         etagFilePath = destFilePath <.> "etag" @@ -75,8 +78,7 @@       if not exists         then return Nothing         else liftIO $ handleIO (const $ return Nothing) $ fmap Just $-                 withBinaryFile etagFilePath ReadMode $ \h ->-                     runConduit $ sourceHandle h .| CB.take 512+                 withSourceFile etagFilePath $ \src -> runConduit $ src .| CB.take 512      let req1 =             case metag of@@ -97,10 +99,12 @@           -- force the download to happen again.           handleIO (const $ return ()) $ removeFile etagFilePath -          runConduitRes $ getResponseBody res .| CB.sinkFileCautious destFilePath+          withSinkFileCautious destFilePath $ \sink ->+            runConduit $ getResponseBody res .| sink            forM_ (lookup "ETag" (getResponseHeaders res)) $ \e ->-            runConduitRes $ yield e .| CB.sinkFileCautious etagFilePath+            withSinkFileCautious etagFilePath $ \sink ->+            runConduit $ yield e .| sink            return True         304 -> return False@@ -112,5 +116,4 @@  -- | Set the user-agent request header setGithubHeaders :: Request -> Request-setGithubHeaders = setRequestHeader "User-Agent" ["The Haskell Stack"]-                 . setRequestHeader "Accept" ["application/vnd.github.v3+json"]+setGithubHeaders = setRequestHeader "Accept" ["application/vnd.github.v3+json"]
src/Network/HTTP/Download/Verified.hs view
@@ -37,12 +37,13 @@ import              Data.ByteArray.Encoding as Mem (convertToBase, Base(Base16)) import              Data.ByteString.Char8 (readInteger) import              Data.Conduit-import              Data.Conduit.Binary (sourceHandle, sinkHandle)+import              Data.Conduit.Binary (sourceHandle) import              Data.Text.Encoding (decodeUtf8With) import              Data.Text.Encoding.Error (lenientDecode) import              GHC.IO.Exception (IOException(..),IOErrorType(..)) import              Network.HTTP.Client (getUri, path)-import              Network.HTTP.Simple (Request, HttpException, httpSink, getResponseHeaders)+import              Network.HTTP.StackClient (httpSink)+import              Network.HTTP.Simple (Request, HttpException, getResponseHeaders) import              Network.HTTP.Types.Header (hContentLength, hContentMD5) import              Path import              Stack.Types.Runner@@ -142,7 +143,7 @@ sinkCheckHash :: MonadThrow m     => Request     -> HashCheck-    -> Consumer ByteString m ()+    -> ConduitM ByteString o m () sinkCheckHash req HashCheck{..} = do     digest <- sinkHashUsing hashCheckAlgorithm     let actualDigestString = show digest@@ -172,7 +173,7 @@     throwM $ WrongStreamLength req expectedStreamLength actualStreamLength  -- | A more explicitly type-guided sinkHash.-sinkHashUsing :: (Monad m, HashAlgorithm a) => a -> Consumer ByteString m (Digest a)+sinkHashUsing :: (Monad m, HashAlgorithm a) => a -> ConduitM ByteString o m (Digest a) sinkHashUsing _ = sinkHash  -- | Turns a list of hash checks into a ZipSink that checks all of them.@@ -180,8 +181,7 @@ hashChecksToZipSink req = traverse_ (ZipSink . sinkCheckHash req)  -- 'Control.Retry.recovering' customized for HTTP failures-recoveringHttp :: (MonadUnliftIO m, MonadLogger m, HasRunner env, MonadReader env m)-               => RetryPolicy -> m a -> m a+recoveringHttp :: forall env a. HasRunner env => RetryPolicy -> RIO env a -> RIO env a recoveringHttp retryPolicy = #if MIN_VERSION_retry(0,7,0)     helper $ \run -> recovering retryPolicy (handlers run) . const@@ -189,15 +189,15 @@     helper $ \run -> recovering retryPolicy (handlers run) #endif   where-    helper :: (MonadUnliftIO m, HasRunner env, MonadReader env m) => (UnliftIO m -> IO a -> IO a) -> m a -> m a+    helper :: (UnliftIO (RIO env) -> IO a -> IO a) -> RIO env a -> RIO env a     helper wrapper action = withUnliftIO $ \run -> wrapper run (unliftIO run action) -    handlers :: (MonadLogger m, HasRunner env, MonadReader env m) => UnliftIO m -> [RetryStatus -> Handler IO Bool]-    handlers run = [Handler . alwaysRetryHttp (unliftIO run),const $ Handler retrySomeIO]+    handlers :: UnliftIO (RIO env) -> [RetryStatus -> Handler IO Bool]+    handlers u = [Handler . alwaysRetryHttp u,const $ Handler retrySomeIO] -    alwaysRetryHttp :: (MonadLogger m', Monad m, HasRunner env, MonadReader env m') => (m' () -> m ()) -> RetryStatus -> HttpException -> m Bool-    alwaysRetryHttp run rs _ = do-      run $+    alwaysRetryHttp :: UnliftIO (RIO env) -> RetryStatus -> HttpException -> IO Bool+    alwaysRetryHttp u rs _ = do+      unliftIO u $         prettyWarn $ vcat           [ flow $ unwords             [ "Retry number"@@ -234,19 +234,19 @@ -- Throws VerifiedDownloadException. -- Throws IOExceptions related to file system operations. -- Throws HttpException.-verifiedDownload :: (MonadUnliftIO m, MonadLogger m, HasRunner env, MonadReader env m)+verifiedDownload+         :: HasRunner env          => DownloadRequest          -> Path Abs File -- ^ destination-         -> (Maybe Integer -> Sink ByteString IO ()) -- ^ custom hook to observe progress-         -> m Bool -- ^ Whether a download was performed+         -> (Maybe Integer -> ConduitM ByteString Void (RIO env) ()) -- ^ custom hook to observe progress+         -> RIO env Bool -- ^ Whether a download was performed verifiedDownload DownloadRequest{..} destpath progressSink = do     let req = drRequest     whenM' (liftIO getShouldDownload) $ do-        logDebug $ "Downloading " <> decodeUtf8With lenientDecode (path req)+        logDebug $ "Downloading " <> Stack.Prelude.display (decodeUtf8With lenientDecode (path req))         liftIO $ createDirectoryIfMissing True dir-        recoveringHttp drRetryPolicy $ liftIO $ -            withBinaryFile fptmp WriteMode $ \h ->-                httpSink req (go h)+        recoveringHttp drRetryPolicy $+            withSinkFile fptmp $ httpSink req . go         liftIO $ renameFile fptmp fp   where     whenM' mp m = do@@ -274,7 +274,9 @@      checkExpectations = withBinaryFile fp ReadMode $ \h -> do         for_ drLengthCheck $ checkFileSizeExpectations h-        sourceHandle h $$ getZipSink (hashChecksToZipSink drRequest drHashChecks)+        runConduit+            $ sourceHandle h+           .| getZipSink (hashChecksToZipSink drRequest drHashChecks)      -- doesn't move the handle     checkFileSizeExpectations h expectedFileSize = do@@ -293,7 +295,7 @@                 throwM $ WrongContentLength drRequest expectedContentLength lengthBS             _ -> return () -    go h res = do+    go sink res = do         let headers = getResponseHeaders res             mcontentLength = do               hLength <- List.lookup hContentLength headers@@ -310,9 +312,9 @@                 Nothing -> []                 ) ++ drHashChecks -        maybe id (\len -> (CB.isolate len =$=)) drLengthCheck+        maybe id (\len -> (CB.isolate len .|)) drLengthCheck             $ getZipSink                 ( hashChecksToZipSink drRequest hashChecks                   *> maybe (pure ()) (assertLengthSink drRequest) drLengthCheck-                  *> ZipSink (sinkHandle h)+                  *> ZipSink sink                   *> ZipSink (progressSink mcontentLength))
+ src/Network/HTTP/StackClient.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Wrapper functions of 'Network.HTTP.Simple' and 'Network.HTTP.Client' to+-- add the 'User-Agent' HTTP request header to each request.++module Network.HTTP.StackClient+  ( httpJSON+  , httpLbs+  , httpLBS+  , httpNoBody+  , httpSink+  , setUserAgent+  , withResponse+  , withResponseByManager+  ) where++import           Data.Aeson (FromJSON)+import qualified Data.ByteString as Strict+import           Data.ByteString.Lazy (ByteString)+import           Data.Conduit (ConduitM, transPipe)+import           Data.Void (Void)+import qualified Network.HTTP.Client+import           Network.HTTP.Client (BodyReader, Manager, Request, Response)+import           Network.HTTP.Simple (setRequestHeader)+import qualified Network.HTTP.Simple+import           UnliftIO (MonadIO, MonadUnliftIO, withRunInIO, withUnliftIO, unliftIO)+++setUserAgent :: Request -> Request+setUserAgent = setRequestHeader "User-Agent" ["The Haskell Stack"]+++httpJSON :: (MonadIO m, FromJSON a) => Request -> m (Response a)+httpJSON = Network.HTTP.Simple.httpJSON . setUserAgent+++httpLbs :: MonadIO m => Request -> m (Response ByteString)+httpLbs = Network.HTTP.Simple.httpLbs . setUserAgent+++httpLBS :: MonadIO m => Request -> m (Response ByteString)+httpLBS = httpLbs+++httpNoBody :: MonadIO m => Request -> m (Response ())+httpNoBody = Network.HTTP.Simple.httpNoBody . setUserAgent+++httpSink+  :: MonadUnliftIO m+  => Request+  -> (Response () -> ConduitM Strict.ByteString Void m a)+  -> m a+httpSink req inner = withUnliftIO $ \u ->+  Network.HTTP.Simple.httpSink (setUserAgent req) (transPipe (unliftIO u) . inner)+++withResponse+  :: (MonadUnliftIO m, MonadIO n)+  => Request -> (Response (ConduitM i Strict.ByteString n ()) -> m a) -> m a+withResponse req inner = withRunInIO $ \run ->+  Network.HTTP.Simple.withResponse (setUserAgent req) (run . inner)+++withResponseByManager :: MonadUnliftIO m => Request -> Manager -> (Response BodyReader -> m a) -> m a+withResponseByManager req man inner = withRunInIO $ \run ->+  Network.HTTP.Client.withResponse (setUserAgent req) man (run . inner)
src/Options/Applicative/Builder/Extra.hs view
@@ -32,7 +32,7 @@  import Data.List (isPrefixOf) import Data.Maybe-import Data.Monoid+import Data.Monoid hiding ((<>)) import qualified Data.Text as T import Options.Applicative import Options.Applicative.Types (readerAsk)
src/Path/Extra.hs view
@@ -22,7 +22,7 @@ import           Path import           Path.IO import           Path.Internal (Path(..))-import           Stack.Prelude+import           RIO import           System.IO.Error (isDoesNotExistError) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as BSL
src/Stack/Build.hs view
@@ -14,7 +14,7 @@  module Stack.Build   (build-  ,withLoadPackage+  ,loadPackage   ,mkBaseConfigOpts   ,queryBuildInfo   ,splitObjsWarning@@ -24,7 +24,7 @@ import           Stack.Prelude import           Data.Aeson (Value (Object, Array), (.=), object) import qualified Data.HashMap.Strict as HM-import           Data.List ((\\))+import           Data.List ((\\), isPrefixOf) import           Data.List.Extra (groupSort) import           Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NE@@ -42,21 +42,23 @@ import           Stack.Build.Installed import           Stack.Build.Source import           Stack.Build.Target-import           Stack.Fetch as Fetch import           Stack.Package import           Stack.PackageLocation (parseSingleCabalFileIndex) import           Stack.Types.Build import           Stack.Types.BuildPlan import           Stack.Types.Config import           Stack.Types.FlagName+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version +import           Stack.Types.Compiler (compilerVersionText #ifdef WINDOWS-import           Stack.Types.Compiler+                                      ,getGhcVersion #endif+                                      ) import           System.FileLock (FileLock, unlockFile)  #ifdef WINDOWS@@ -77,9 +79,8 @@     bopts <- view buildOptsL     let profiling = boptsLibProfile bopts || boptsExeProfile bopts     let symbols = not (boptsLibStrip bopts || boptsExeStrip bopts)-    menv <- getMinimalEnvOverride -    (targets, mbp, locals, extraToBuild, sourceMap) <- loadSourceMapFull NeedTargets boptsCli+    (targets, ls, locals, extraToBuild, sourceMap) <- loadSourceMapFull NeedTargets boptsCli      -- Set local files, necessary for file watching     stackYaml <- view stackYamlL@@ -95,7 +96,7 @@              [lpFiles lp | PSFiles lp _ <- Map.elems sourceMap]      (installedMap, globalDumpPkgs, snapshotDumpPkgs, localDumpPkgs) <--        getInstalled menv+        getInstalled                      GetInstalledOpts                          { getInstalledProfiling = profiling                          , getInstalledHaddock   = shouldHaddockDeps bopts@@ -103,8 +104,7 @@                      sourceMap      baseConfigOpts <- mkBaseConfigOpts boptsCli-    plan <- withLoadPackage $ \loadPackage ->-        constructPlan mbp baseConfigOpts locals extraToBuild localDumpPkgs loadPackage sourceMap installedMap (boptsCLIInitialBuildSteps boptsCli)+    plan <- constructPlan ls baseConfigOpts locals extraToBuild localDumpPkgs loadPackage sourceMap installedMap (boptsCLIInitialBuildSteps boptsCli)      allowLocals <- view $ configL.to configAllowLocals     unless allowLocals $ case justLocals plan of@@ -130,7 +130,7 @@      if boptsCLIDryrun boptsCli         then printPlan plan-        else executePlan menv boptsCli baseConfigOpts locals+        else executePlan boptsCli baseConfigOpts locals                          globalDumpPkgs                          snapshotDumpPkgs                          localDumpPkgs@@ -172,7 +172,7 @@  -- | See https://github.com/commercialhaskell/stack/issues/1198. warnIfExecutablesWithSameNameCouldBeOverwritten-    :: MonadLogger m => [LocalPackage] -> Plan -> m ()+    :: HasLogFunc env => [LocalPackage] -> Plan -> RIO env () warnIfExecutablesWithSameNameCouldBeOverwritten locals plan = do     logDebug "Checking if we are going to build multiple executables with the same name"     forM_ (Map.toList warnings) $ \(exe,(toBuild,otherLocals)) -> do@@ -183,7 +183,7 @@                 T.intercalate                     ", "                     ["'" <> packageNameText p <> ":" <> exe <> "'" | p <- pkgs]-        (logWarn . T.unlines . concat)+        (logWarn . display . T.unlines . concat)             [ [ "Building " <> exe_s <> " " <> exesText toBuild <> "." ]             , [ "Only one of them will be available via 'stack exec' or locally installed."               | length toBuild > 1@@ -239,9 +239,9 @@     collect :: Ord k => [(k,v)] -> Map k (NonEmpty v)     collect = Map.map NE.fromList . Map.fromDistinctAscList . groupSort -warnAboutSplitObjs :: MonadLogger m => BuildOpts -> m ()+warnAboutSplitObjs :: HasLogFunc env => BuildOpts -> RIO env () warnAboutSplitObjs bopts | boptsSplitObjs bopts = do-    logWarn $ "Building with --split-objs is enabled. " <> T.pack splitObjsWarning+    logWarn $ "Building with --split-objs is enabled. " <> fromString splitObjsWarning warnAboutSplitObjs _ = return ()  splitObjsWarning :: String@@ -273,29 +273,25 @@         }  -- | Provide a function for loading package information from the package index-withLoadPackage :: HasEnvConfig env-                => ((PackageLocationIndex FilePath -> Map FlagName Bool -> [Text] -> IO Package) -> RIO env a)-                -> RIO env a-withLoadPackage inner = do-    econfig <- view envConfigL-    root <- view projectRootL-    run <- askRunInIO-    withCabalLoader $ \loadFromIndex ->-        inner $ \loc flags ghcOptions -> run $-            resolvePackage-              (depPackageConfig econfig flags ghcOptions)-              <$> parseSingleCabalFileIndex loadFromIndex root loc-  where-    -- | Package config to be used for dependencies-    depPackageConfig :: EnvConfig -> Map FlagName Bool -> [Text] -> PackageConfig-    depPackageConfig econfig flags ghcOptions = PackageConfig+loadPackage+  :: HasEnvConfig env+  => PackageLocationIndex FilePath+  -> Map FlagName Bool+  -> [Text]+  -> RIO env Package+loadPackage loc flags ghcOptions = do+  compiler <- view actualCompilerVersionL+  platform <- view platformL+  root <- view projectRootL+  let pkgConfig = PackageConfig         { packageConfigEnableTests = False         , packageConfigEnableBenchmarks = False         , packageConfigFlags = flags         , packageConfigGhcOptions = ghcOptions-        , packageConfigCompilerVersion = view actualCompilerVersionL econfig-        , packageConfigPlatform = view platformL econfig+        , packageConfigCompilerVersion = compiler+        , packageConfigPlatform = platform         }+  resolvePackage pkgConfig <$> parseSingleCabalFileIndex root loc  -- | Set the code page for this process as necessary. Only applies to Windows. -- See: https://github.com/commercialhaskell/stack/issues/738@@ -336,11 +332,10 @@          fixInput $ fixOutput inner     expected = 65001 -- UTF-8-    warn typ = logInfo $ T.concat-        [ "Setting"-        , typ-        , " codepage to UTF-8 (65001) to ensure correct output from GHC"-        ]+    warn typ = logInfo $+        "Setting" <>+        typ <>+        " codepage to UTF-8 (65001) to ensure correct output from GHC" #else fixCodePage = id #endif@@ -352,7 +347,7 @@ queryBuildInfo selectors0 =         rawBuildInfo     >>= select id selectors0-    >>= liftIO . TIO.putStrLn . decodeUtf8 . Yaml.encode+    >>= liftIO . TIO.putStrLn . addGlobalHintsComment . decodeUtf8 . Yaml.encode   where     select _ [] value = return value     select front (sel:sels) value =@@ -371,13 +366,35 @@       where         cont = select (front . (sel:)) sels         err msg = throwString $ msg ++ ": " ++ show (front [sel])-+    -- Include comments to indicate that this portion of the "stack+    -- query" API is not necessarily stable.+    addGlobalHintsComment+      | null selectors0 = T.replace globalHintsLine ("\n" <> globalHintsComment <> globalHintsLine)+      -- Append comment instead of pre-pending. The reasoning here is+      -- that something *could* expect that the result of 'stack query+      -- global-hints ghc-boot' is just a string literal. Seems easier+      -- for to expect the first line of the output to be the literal.+      | ["global-hints"] `isPrefixOf` selectors0 = (<> ("\n" <> globalHintsComment))+      | otherwise = id+    globalHintsLine = "\nglobal-hints:\n"+    globalHintsComment = T.concat+      [ "# Note: global-hints is experimental and may be renamed / removed in the future.\n"+      , "# See https://github.com/commercialhaskell/stack/issues/3796"+      ] -- | Get the raw build information object rawBuildInfo :: HasEnvConfig env => RIO env Value rawBuildInfo = do     (locals, _sourceMap) <- loadSourceMap NeedTargets defaultBuildOptsCLI+    wantedCompiler <- view $ wantedCompilerVersionL.to compilerVersionText+    actualCompiler <- view $ actualCompilerVersionL.to compilerVersionText+    globalHints <- view globalHintsL     return $ object         [ "locals" .= Object (HM.fromList $ map localToPair locals)+        , "compiler" .= object+            [ "wanted" .= wantedCompiler+            , "actual" .= actualCompiler+            ]+        , "global-hints" .= globalHints         ]   where     localToPair lp =
src/Stack/Build/Cache.hs view
@@ -57,6 +57,7 @@ import           Stack.Types.Compiler import           Stack.Types.Config import           Stack.Types.GhcPkgId+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.Version@@ -119,29 +120,34 @@     let nonLibComponent prefix name = prefix <> "-" <> T.unpack name     cacheFileName <- parseRelFile $ case component of         CLib -> "lib"+        CInternalLib name -> nonLibComponent "internal-lib" name         CExe name -> nonLibComponent "exe" name         CTest name -> nonLibComponent "test" name         CBench name -> nonLibComponent "bench" name     return $ cachesDir </> cacheFileName  -- | Try to read the dirtiness cache for the given package directory.-tryGetBuildCache :: (MonadUnliftIO m, MonadReader env m, MonadThrow m, MonadLogger m, HasEnvConfig env)-                 => Path Abs Dir -> NamedComponent -> m (Maybe (Map FilePath FileCacheInfo))+tryGetBuildCache :: HasEnvConfig env+                 => Path Abs Dir+                 -> NamedComponent+                 -> RIO env (Maybe (Map FilePath FileCacheInfo)) tryGetBuildCache dir component = liftM (fmap buildCacheTimes) . $(versionedDecodeFile buildCacheVC) =<< buildCacheFile dir component  -- | Try to read the dirtiness cache for the given package directory.-tryGetConfigCache :: (MonadUnliftIO m, MonadReader env m, MonadThrow m, HasEnvConfig env, MonadLogger m)-                  => Path Abs Dir -> m (Maybe ConfigCache)+tryGetConfigCache :: HasEnvConfig env+                  => Path Abs Dir -> RIO env (Maybe ConfigCache) tryGetConfigCache dir = $(versionedDecodeFile configCacheVC) =<< configCacheFile dir  -- | Try to read the mod time of the cabal file from the last build-tryGetCabalMod :: (MonadUnliftIO m, MonadReader env m, MonadThrow m, HasEnvConfig env, MonadLogger m)-               => Path Abs Dir -> m (Maybe ModTime)+tryGetCabalMod :: HasEnvConfig env+               => Path Abs Dir -> RIO env (Maybe ModTime) tryGetCabalMod dir = $(versionedDecodeFile modTimeVC) =<< configCabalMod dir  -- | Write the dirtiness cache for this package's files.-writeBuildCache :: (MonadIO m, MonadReader env m, MonadThrow m, HasEnvConfig env, MonadLogger m)-                => Path Abs Dir -> NamedComponent -> Map FilePath FileCacheInfo -> m ()+writeBuildCache :: HasEnvConfig env+                => Path Abs Dir+                -> NamedComponent+                -> Map FilePath FileCacheInfo -> RIO env () writeBuildCache dir component times = do     fp <- buildCacheFile dir component     $(versionedEncodeFile buildCacheVC) fp BuildCache@@ -149,19 +155,19 @@         }  -- | Write the dirtiness cache for this package's configuration.-writeConfigCache :: (MonadIO m, MonadReader env m, MonadThrow m, HasEnvConfig env, MonadLogger m)+writeConfigCache :: HasEnvConfig env                 => Path Abs Dir                 -> ConfigCache-                -> m ()+                -> RIO env () writeConfigCache dir x = do     fp <- configCacheFile dir     $(versionedEncodeFile configCacheVC) fp x  -- | See 'tryGetCabalMod'-writeCabalMod :: (MonadIO m, MonadReader env m, MonadThrow m, HasEnvConfig env, MonadLogger m)+writeCabalMod :: HasEnvConfig env               => Path Abs Dir               -> ModTime-              -> m ()+              -> RIO env () writeCabalMod dir x = do     fp <- configCabalMod dir     $(versionedEncodeFile modTimeVC) fp x@@ -189,42 +195,42 @@     return $ dir </> rel  -- | Loads the flag cache for the given installed extra-deps-tryGetFlagCache :: (MonadUnliftIO m, MonadThrow m, MonadReader env m, HasEnvConfig env, MonadLogger m)+tryGetFlagCache :: HasEnvConfig env                 => Installed-                -> m (Maybe ConfigCache)+                -> RIO env (Maybe ConfigCache) tryGetFlagCache gid = do     fp <- flagCacheFile gid     $(versionedDecodeFile configCacheVC) fp -writeFlagCache :: (MonadIO m, MonadReader env m, HasEnvConfig env, MonadThrow m, MonadLogger m)+writeFlagCache :: HasEnvConfig env                => Installed                -> ConfigCache-               -> m ()+               -> RIO env () writeFlagCache gid cache = do     file <- flagCacheFile gid     ensureDir (parent file)     $(versionedEncodeFile configCacheVC) file cache  -- | Mark a test suite as having succeeded-setTestSuccess :: (MonadIO m, MonadThrow m, MonadReader env m, HasEnvConfig env, MonadLogger m)+setTestSuccess :: HasEnvConfig env                => Path Abs Dir-               -> m ()+               -> RIO env () setTestSuccess dir = do     fp <- testSuccessFile dir     $(versionedEncodeFile testSuccessVC) fp True  -- | Mark a test suite as not having succeeded-unsetTestSuccess :: (MonadIO m, MonadThrow m, MonadReader env m, HasEnvConfig env, MonadLogger m)+unsetTestSuccess :: HasEnvConfig env                  => Path Abs Dir-                 -> m ()+                 -> RIO env () unsetTestSuccess dir = do     fp <- testSuccessFile dir     $(versionedEncodeFile testSuccessVC) fp False  -- | Check if the test suite already passed-checkTestSuccess :: (MonadUnliftIO m, MonadThrow m, MonadReader env m, HasEnvConfig env, MonadLogger m)+checkTestSuccess :: HasEnvConfig env                  => Path Abs Dir-                 -> m Bool+                 -> RIO env Bool checkTestSuccess dir =     liftM         (fromMaybe False)@@ -247,11 +253,11 @@ -- -- We only pay attention to non-directory options. We don't want to avoid a -- cache hit just because it was installed in a different directory.-precompiledCacheFile :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadLogger m)+precompiledCacheFile :: HasEnvConfig env                      => PackageLocationIndex FilePath                      -> ConfigureOpts                      -> Set GhcPkgId -- ^ dependencies-                     -> m (Maybe (Path Abs File))+                     -> RIO env (Maybe (Path Abs File)) precompiledCacheFile loc copts installedPackageIDs = do   ec <- view envConfigL @@ -312,14 +318,14 @@         return longPath  -- | Write out information about a newly built package-writePrecompiledCache :: (MonadThrow m, MonadReader env m, HasEnvConfig env, MonadIO m, MonadLogger m)+writePrecompiledCache :: HasEnvConfig env                       => BaseConfigOpts                       -> PackageLocationIndex FilePath                       -> ConfigureOpts                       -> Set GhcPkgId -- ^ dependencies                       -> Installed -- ^ library                       -> Set Text -- ^ executables-                      -> m ()+                      -> RIO env () writePrecompiledCache baseConfigOpts loc copts depIDs mghcPkgId exes = do   mfile <- precompiledCacheFile loc copts depIDs   forM_ mfile $ \file -> do
src/Stack/Build/ConstructPlan.hs view
@@ -18,23 +18,22 @@     ( constructPlan     ) where -import           Stack.Prelude-import           Control.Monad.RWS.Strict+import           Stack.Prelude hiding (Display (..))+import           Control.Monad.RWS.Strict hiding ((<>)) import           Control.Monad.State.Strict (execState) import qualified Data.HashSet as HashSet import           Data.List-import           Data.List.Extra (nubOrd) import qualified Data.Map.Strict as M import qualified Data.Map.Strict as Map import qualified Data.Set as Set import qualified Data.Text as T-import           Data.Text.Encoding (decodeUtf8With)+import           Data.Text.Encoding (encodeUtf8, decodeUtf8With) import           Data.Text.Encoding.Error (lenientDecode) import qualified Distribution.Text as Cabal import qualified Distribution.Version as Cabal import           Distribution.Types.BuildType (BuildType (Configure)) import           Generics.Deriving.Monoid (memptydefault, mappenddefault)-import           Lens.Micro (lens)+import qualified RIO import           Stack.Build.Cache import           Stack.Build.Haddock import           Stack.Build.Installed@@ -52,13 +51,14 @@ import           Stack.Types.Config import           Stack.Types.FlagName import           Stack.Types.GhcPkgId+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Runner import           Stack.Types.Version import           System.IO (putStrLn)-import           System.Process.Read (findExecutable)+import           RIO.Process (findExecutable, HasProcessContext (..))  data PackageInfo     =@@ -114,9 +114,11 @@     , wParents :: !ParentMap     -- ^ Which packages a given package depends on, along with the package's version     } deriving Generic+instance Semigroup W where+    (<>) = mappenddefault instance Monoid W where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  type M = RWST -- TODO replace with more efficient WS stack on top of StackT     Ctx@@ -127,7 +129,7 @@ data Ctx = Ctx     { ls             :: !LoadedSnapshot     , baseConfigOpts :: !BaseConfigOpts-    , loadPackage    :: !(PackageLocationIndex FilePath -> Map FlagName Bool -> [Text] -> IO Package)+    , loadPackage    :: !(PackageLocationIndex FilePath -> Map FlagName Bool -> [Text] -> M Package)     , combinedMap    :: !CombinedMap     , toolToPackages :: !(ExeName -> Map PackageName VersionRange)     , ctxEnvConfig   :: !EnvConfig@@ -145,6 +147,10 @@ instance HasRunner Ctx where     runnerL = configL.runnerL instance HasConfig Ctx+instance HasCabalLoader Ctx where+    cabalLoaderL = configL.cabalLoaderL+instance HasProcessContext Ctx where+    processContextL = configL.processContextL instance HasBuildConfig Ctx instance HasEnvConfig Ctx where     envConfigL = lens ctxEnvConfig (\x y -> x { ctxEnvConfig = y })@@ -171,14 +177,13 @@               -> [LocalPackage]               -> Set PackageName -- ^ additional packages that must be built               -> [DumpPackage () () ()] -- ^ locally registered-              -> (PackageLocationIndex FilePath -> Map FlagName Bool -> [Text] -> IO Package) -- ^ load upstream package+              -> (PackageLocationIndex FilePath -> Map FlagName Bool -> [Text] -> RIO EnvConfig Package) -- ^ load upstream package               -> SourceMap               -> InstalledMap               -> Bool               -> RIO env Plan constructPlan ls0 baseConfigOpts0 locals extraToBuild0 localDumpPkgs loadPackage0 sourceMap installedMap initialBuildSteps = do     logDebug "Constructing the build plan"-    u <- askUnliftIO      econfig <- view envConfigL     let onWanted = void . addDep False . packageName . lpPackage@@ -186,10 +191,10 @@             mapM_ onWanted $ filter lpWanted locals             mapM_ (addDep False) $ Set.toList extraToBuild0     lp <- getLocalPackages-    let ctx = mkCtx econfig (unliftIO u . getPackageVersions) lp+    let ctx = mkCtx econfig lp     ((), m, W efinals installExes dirtyReason deps warnings parents) <-         liftIO $ runRWST inner ctx M.empty-    mapM_ logWarn (warnings [])+    mapM_ (logWarn . RIO.display) (warnings [])     let toEither (_, Left e)  = Left e         toEither (k, Right v) = Right (k, v)         (errlibs, adrs) = partitionEithers $ map toEither $ M.toList m@@ -221,10 +226,10 @@             prettyErrorNoIndent $ pprintExceptions errs stackYaml parents (wanted ctx)             throwM $ ConstructPlanFailed "Plan construction failed."   where-    mkCtx econfig getVersions0 lp = Ctx+    mkCtx econfig lp = Ctx         { ls = ls0         , baseConfigOpts = baseConfigOpts0-        , loadPackage = loadPackage0+        , loadPackage = \x y z -> runRIO econfig $ loadPackage0 x y z         , combinedMap = combineMap sourceMap installedMap         , toolToPackages = \name ->           maybe Map.empty (Map.fromSet (const Cabal.anyVersion)) $@@ -232,7 +237,7 @@         , ctxEnvConfig = econfig         , callStack = []         , extraToBuild = extraToBuild0-        , getVersions = getVersions0+        , getVersions = runRIO econfig . getPackageVersions         , wanted = wantedLocalPackages locals <> extraToBuild0         , localNames = Set.fromList $ map (packageName . lpPackage) locals         }@@ -433,7 +438,7 @@ tellExecutablesUpstream pir@(PackageIdentifierRevision (PackageIdentifier name _) _) loc flags = do     ctx <- ask     when (name `Set.member` extraToBuild ctx) $ do-        p <- liftIO $ loadPackage ctx (PLIndex pir) flags []+        p <- loadPackage ctx (PLIndex pir) flags []         tellExecutablesPackage loc p  tellExecutablesPackage :: InstallLocation -> Package -> M ()@@ -470,7 +475,7 @@     case ps of         PSIndex _ flags ghcOptions pkgLoc -> do             planDebug $ "installPackage: Doing all-in-one build for upstream package " ++ show name-            package <- liftIO $ loadPackage ctx (PLIndex pkgLoc) flags ghcOptions -- FIXME be more efficient! Get this from the LoadedPackageInfo!+            package <- loadPackage ctx (PLIndex pkgLoc) flags ghcOptions -- FIXME be more efficient! Get this from the LoadedPackageInfo!             resolveDepsAndInstall True treatAsDep ps package minstalled         PSFiles lp _ ->             case lpTestBench lp of@@ -578,7 +583,7 @@  -- | Is the build type of the package Configure packageBuildTypeConfig :: Package -> Bool-packageBuildTypeConfig pkg = packageBuildType pkg == Just Configure+packageBuildTypeConfig pkg = packageBuildType pkg == Configure  -- Update response in the lib map. If it is an error, and there's -- already an error about cyclic dependencies, prefer the cyclic error.@@ -724,7 +729,7 @@             , configCacheDeps = Set.fromList $ Map.elems present             , configCacheComponents =                 case ps of-                    PSFiles lp _ -> Set.map renderComponent $ lpComponents lp+                    PSFiles lp _ -> Set.map (encodeUtf8 . renderComponent) $ lpComponents lp                     PSIndex{} -> Set.empty             , configCacheHaddock =                 shouldHaddockPackage buildOpts wanted (packageName package) ||@@ -826,13 +831,11 @@ psLocal (PSFiles _ loc) = loc == Local -- FIXME this is probably not the right logic, see configureOptsNoDir. We probably want to check if this appears in packages: psLocal PSIndex{} = False --- | Get all of the dependencies for a given package, including guessed build+-- | Get all of the dependencies for a given package, including build -- tool dependencies. packageDepsWithTools :: Package -> M (Map PackageName (VersionRange, DepType)) packageDepsWithTools p = do     ctx <- ask-    -- TODO: it would be cool to defer these warnings until there's an-    -- actual issue building the package.     let toEither name mp =             case Map.toList mp of                 [] -> Left (ToolWarning name (packageName p) Nothing)@@ -844,12 +847,13 @@              map (\dep -> toEither dep (toolToPackages ctx dep)) (Map.keys (packageTools p))     -- Check whether the tool is on the PATH before warning about it.     warnings <- fmap catMaybes $ forM warnings0 $ \warning@(ToolWarning (ExeName toolName) _ _) -> do+        let settings = minimalEnvSettings { esIncludeLocals = True }         config <- view configL-        menv <- liftIO $ configEnvOverride config minimalEnvSettings { esIncludeLocals = True }-        mfound <- findExecutable menv $ T.unpack toolName+        menv <- liftIO $ configProcessContextSettings config settings+        mfound <- runRIO menv $ findExecutable $ T.unpack toolName         case mfound of-            Nothing -> return (Just warning)-            Just _ -> return Nothing+            Left _ -> return (Just warning)+            Right _ -> return Nothing     tell mempty { wWarnings = (map toolWarningText warnings ++) }     return $ Map.unionsWith                (\(vr1, dt1) (vr2, dt2) ->@@ -878,7 +882,7 @@ toolWarningText (ToolWarning (ExeName toolName) pkgName (Just (option1, option2, options))) =     "Multiple packages found in snapshot which provide a " <>     T.pack (show toolName) <>-    " exeuctable, which is a build-tool dependency of " <>+    " executable, which is a build-tool dependency of " <>     T.pack (show (packageNameString pkgName)) <>     ", so none will be installed.\n" <>     "Here's the list of packages which provide it: " <>@@ -954,29 +958,33 @@       , line <> line       , mconcat (intersperse (line <> line) (mapMaybe pprintException exceptions'))       , line <> line-      , flow "Some potential ways to resolve this:"+      , flow "Some different approaches to resolving this:"       , line <> line       ] +++      (if not onlyHasDependencyMismatches then [] else+         [ "  *" <+> align (flow "Set 'allow-newer: true' to ignore all version constraints and build anyway.")+         , line <> line+         ]+      ) +++      [ "  *" <+> align (flow "Consider trying 'stack solver', which uses the cabal-install solver to attempt to find some working build configuration. This can be convenient when dealing with many complicated constraint errors, but results may be unpredictable.")+      , line <> line+      ] ++       (if Map.null extras then [] else          [ "  *" <+> align-           (flow "Recommended action: try adding the following to your extra-deps in" <+>+           (styleRecommendation (flow "Recommended action:") <+>+            flow "try adding the following to your extra-deps in" <+>             toAnsiDoc (display stackYaml) <> ":")          , line <> line          , vsep (map pprintExtra (Map.toList extras))-         , line <> line+         , line          ]-      ) ++-      [ "  *" <+> align (flow "Set 'allow-newer: true' to ignore all version constraints and build anyway.")-      , line <> line-      , "  *" <+> align (flow "You may also want to try using the 'stack solver' command.")-      , line-      ]+      )   where     exceptions' = nubOrd exceptions      extras = Map.unions $ map getExtras exceptions'-    getExtras (DependencyCycleDetected _) = Map.empty-    getExtras (UnknownPackage _) = Map.empty+    getExtras DependencyCycleDetected{} = Map.empty+    getExtras UnknownPackage{} = Map.empty     getExtras (DependencyPlanFailures _ m) =        Map.unions $ map go $ Map.toList m      where@@ -994,6 +1002,17 @@       map fst $ filter (\(_, (_, _, badDep)) -> badDep == NotInBuildPlan) $ Map.toList pDeps     toNotInBuildPlan _ = [] +    -- This checks if 'allow-newer: true' could resolve all issues.+    onlyHasDependencyMismatches = all go exceptions'+      where+        go DependencyCycleDetected{} = False+        go UnknownPackage{} = False+        go (DependencyPlanFailures _ m) =+          all (\(_, _, depErr) -> isMismatch depErr) (M.elems m)+        isMismatch DependencyMismatch{} = True+        isMismatch Couldn'tResolveItsDependencies{} = True+        isMismatch _ = False+     pprintException (DependencyCycleDetected pNames) = Just $         flow "Dependency cycle detected in packages:" <> line <>         indent 4 (encloseSep "[" "]" "," (map (styleError . display) pNames))@@ -1032,13 +1051,15 @@     pprintDep (name, (range, mlatestApplicable, badDep)) = case badDep of         NotInBuildPlan -> Just $             styleError (display name) <+>-            align (flow "must match" <+> goodRange <> "," <> softline <>-                   flow "but the stack configuration has no specified version" <>+            align ((if range == Cabal.anyVersion+                      then flow "needed"+                      else flow "must match" <+> goodRange) <> "," <> softline <>+                   flow "but the stack configuration has no specified version" <+>                    latestApplicable Nothing)         -- TODO: For local packages, suggest editing constraints         DependencyMismatch version -> Just $             (styleError . display) (PackageIdentifier name version) <+>-            align (flow "from stack configuration does not match" <+> goodRange <>+            align (flow "from stack configuration does not match" <+> goodRange <+>                    latestApplicable (Just version))         -- I think the main useful info is these explain why missing         -- packages are needed. Instead lets give the user the shortest@@ -1051,7 +1072,10 @@         goodRange = styleGood (fromString (Cabal.display range))         latestApplicable mversion =             case mlatestApplicable of-                Nothing -> ""+                Nothing+                    | isNothing mversion ->+                        flow "(no package with that name found, perhaps there is a typo in a package's build-depends or an omission from the stack.yaml packages list?)"+                    | otherwise -> ""                 Just la                     | mlatestApplicable == mversion -> softline <>                         flow "(latest matching version is specified)"@@ -1126,8 +1150,11 @@ newtype MonoidMap k a = MonoidMap (Map k a)     deriving (Eq, Ord, Read, Show, Generic, Functor) -instance (Ord k, Monoid a) => Monoid (MonoidMap k a) where-    mappend (MonoidMap mp1) (MonoidMap mp2) = MonoidMap (M.unionWith mappend mp1 mp2)+instance (Ord k, Semigroup a) => Semigroup (MonoidMap k a) where+    MonoidMap mp1 <> MonoidMap mp2 = MonoidMap (M.unionWith (<>) mp1 mp2)++instance (Ord k, Monoid a, Semigroup a) => Monoid (MonoidMap k a) where+    mappend = (<>)     mempty = MonoidMap mempty  -- Switch this to 'True' to enable some debugging putStrLn in this module
src/Stack/Build/Execute.hs view
@@ -25,16 +25,21 @@  import           Control.Concurrent.Execute import           Control.Concurrent.STM (check)-import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import           Crypto.Hash import           Data.Attoparsec.Text hiding (try) import qualified Data.ByteArray as Mem (convert) import qualified Data.ByteString as S import qualified Data.ByteString.Base64.URL as B64URL import           Data.Char (isSpace)-import           Data.Conduit hiding (runConduitRes)+import           Data.Conduit import qualified Data.Conduit.Binary as CB import qualified Data.Conduit.List as CL+import           Data.Conduit.Process.Typed+                    (ExitCodeException (..), waitExitCode,+                     useHandleOpen, setStdin, setStdout, setStderr, getStdin,+                     createPipe, runProcess_, getStdout,+                     getStderr, createSource) import qualified Data.Conduit.Text as CT import           Data.FileEmbed (embedFile, makeRelativeToProject) import           Data.IORef.RunOnce (runOnce)@@ -42,7 +47,6 @@ import qualified Data.Map.Strict as M import qualified Data.Map.Strict as Map import qualified Data.Set as Set-import           Data.Streaming.Process hiding (callProcess, env) import qualified Data.Text as T import           Data.Text.Encoding (decodeUtf8, encodeUtf8) import           Data.Time.Clock (getCurrentTime)@@ -52,11 +56,11 @@ import           Distribution.System            (OS (Windows),                                                  Platform (Platform)) import qualified Distribution.Text as C-import           Language.Haskell.TH as TH (location) import           Path import           Path.CheckInstall import           Path.Extra (toFilePathNoTrailingSep, rejectMissingFile) import           Path.IO hiding (findExecutable, makeAbsolute, withSystemTempDir)+import qualified RIO import           Stack.Build.Cache import           Stack.Build.Haddock import           Stack.Build.Installed@@ -75,6 +79,7 @@ import           Stack.Types.Compiler import           Stack.Types.Config import           Stack.Types.GhcPkgId+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName@@ -82,17 +87,11 @@ import           Stack.Types.Version import qualified System.Directory as D import           System.Environment (getExecutablePath)-import           System.Exit (ExitCode (ExitSuccess))+import           System.Exit (ExitCode (..)) import qualified System.FilePath as FP-import           System.IO (hPutStr, openBinaryFile)+import           System.IO (hPutStr, stderr, stdout) import           System.PosixCompat.Files (createLink)-import           System.Process.Log (showProcessArgDebug, withProcessTimeLog)-import           System.Process.Read-import           System.Process.Run--#if !MIN_VERSION_process(1,2,1)-import           System.Process.Internals (createProcess_)-#endif+import           RIO.Process  -- | Has an executable been built or not? data ExecutableBuildStatus@@ -105,9 +104,9 @@ preFetch plan     | Set.null idents = logDebug "Nothing to fetch"     | otherwise = do-        logDebug $ T.pack $-            "Prefetching: " ++-            intercalate ", " (map packageIdentifierString $ Set.toList idents)+        logDebug $+            "Prefetching: " <>+            mconcat (intersperse ", " (RIO.display <$> Set.toList idents))         fetchPackages idents   where     idents = Set.unions $ map toIdent $ Map.elems $ planTasks plan@@ -124,16 +123,11 @@         [] -> logInfo "No packages would be unregistered."         xs -> do             logInfo "Would unregister locally:"-            forM_ xs $ \(ident, reason) -> logInfo $ T.concat-                [ T.pack $ packageIdentifierString ident-                , if T.null reason-                    then ""-                    else T.concat-                        [ " ("-                        , reason-                        , ")"-                        ]-                ]+            forM_ xs $ \(ident, reason) -> logInfo $+                RIO.display ident <>+                if T.null reason+                  then ""+                  else " (" <> RIO.display reason <> ")"      logInfo "" @@ -163,37 +157,35 @@         [] -> logInfo "No executables to be installed."         xs -> do             logInfo "Would install executables:"-            forM_ xs $ \(name, loc) -> logInfo $ T.concat-                [ name-                , " from "-                , case loc of-                    Snap -> "snapshot"-                    Local -> "local"-                , " database"-                ]+            forM_ xs $ \(name, loc) -> logInfo $+                RIO.display name <>+                " from " <>+                (case loc of+                   Snap -> "snapshot"+                   Local -> "local") <>+                " database"  -- | For a dry run-displayTask :: Task -> Text-displayTask task = T.pack $ concat-    [ packageIdentifierString $ taskProvides task-    , ": database="-    , case taskLocation task of+displayTask :: Task -> Utf8Builder+displayTask task =+    RIO.display (taskProvides task) <>+    ": database=" <>+    (case taskLocation task of         Snap -> "snapshot"-        Local -> "local"-    , ", source="-    , case taskType task of-        TTFiles lp _ -> toFilePath $ lpDir lp-        TTIndex{} -> "package index"-    , if Set.null missing+        Local -> "local") <>+    ", source=" <>+    (case taskType task of+        TTFiles lp _ -> fromString $ toFilePath $ lpDir lp+        TTIndex{} -> "package index") <>+    (if Set.null missing         then ""-        else ", after: " ++ intercalate "," (map packageIdentifierString $ Set.toList missing)-    ]+        else ", after: " <>+             mconcat (intersperse "," (RIO.display <$> Set.toList missing)))   where     missing = tcoMissing $ taskConfigOpts task  data ExecuteEnv = ExecuteEnv-    { eeEnvOverride    :: !EnvOverride-    , eeConfigureLock  :: !(MVar ())+    { eeConfigureLock  :: !(MVar ())     , eeInstallLock    :: !(MVar ())     , eeBuildOpts      :: !BuildOpts     , eeBuildOptsCLI   :: !BuildOptsCLI@@ -280,7 +272,7 @@         jsExeNameS =             baseNameS ++ ".jsexe"         setupDir =-            configStackRoot config </>+            view stackRootL config </>             $(mkRelDir "setup-exe-cache") </>             platformDir @@ -296,7 +288,6 @@             tmpOutputPath <- fmap (setupDir </>) $ parseRelFile $ "tmp-" ++ outputNameS             tmpJsExePath <- fmap (setupDir </>) $ parseRelDir $ "tmp-" ++ jsExeNameS             ensureDir setupDir-            menv <- getMinimalEnvOverride             let args = buildSetupArgs ++                     [ "-package"                     , "Cabal-" ++ cabalVersionString@@ -306,18 +297,19 @@                     , toFilePath tmpOutputPath                     ] ++                     ["-build-runner" | wc == Ghcjs]-            callProcess' (\cp -> cp { std_out = UseHandle stderr }) (Cmd (Just tmpdir) (compilerExeName wc) menv args)-                `catch` \(ProcessExitedUnsuccessfully _ ec) -> do+            withWorkingDir (toFilePath tmpdir) (proc (compilerExeName wc) args $ \pc0 -> do+              let pc = setStdout (useHandleOpen stderr) pc0+              runProcess_ pc)+                `catch` \ece -> do                     compilerPath <- getCompilerPath wc-                    throwM $ SetupHsBuildFailure ec Nothing compilerPath args Nothing []+                    throwM $ SetupHsBuildFailure (eceExitCode ece) Nothing compilerPath args Nothing []             when (wc == Ghcjs) $ renameDir tmpJsExePath jsExePath             renameFile tmpExePath exePath             return $ Just exePath  -- | Execute a function that takes an 'ExecuteEnv'. withExecuteEnv :: forall env a. HasEnvConfig env-               => EnvOverride-               -> BuildOpts+               => BuildOpts                -> BuildOptsCLI                -> BaseConfigOpts                -> [LocalPackage]@@ -326,8 +318,8 @@                -> [DumpPackage () () ()] -- ^ local packages                -> (ExecuteEnv -> RIO env a)                -> RIO env a-withExecuteEnv menv bopts boptsCli baseConfigOpts locals globalPackages snapshotPackages localPackages inner =-    withSystemTempDir stackProgName $ \tmpdir -> do+withExecuteEnv bopts boptsCli baseConfigOpts locals globalPackages snapshotPackages localPackages inner =+    createTempDirFunction stackProgName $ \tmpdir -> do         configLock <- liftIO $ newMVar ()         installLock <- liftIO $ newMVar ()         idMap <- liftIO $ newTVarIO Map.empty@@ -339,7 +331,7 @@          -- Create files for simple setup and setup shim, if necessary         let setupSrcDir =-                configStackRoot config </>+                view stackRootL config </>                 $(mkRelDir "setup-exe-src")         ensureDir setupSrcDir         setupFileName <- parseRelFile ("setup-" ++ simpleSetupHash ++ ".hs")@@ -353,15 +345,14 @@         setupExe <- getSetupExe setupHs setupShimHs tmpdir          cabalPkgVer <- view cabalVersionL-        globalDB <- getGlobalDB menv =<< view (actualCompilerVersionL.whichCompilerL)+        globalDB <- getGlobalDB =<< view (actualCompilerVersionL.whichCompilerL)         snapshotPackagesTVar <- liftIO $ newTVarIO (toDumpPackagesByGhcPkgId snapshotPackages)         localPackagesTVar <- liftIO $ newTVarIO (toDumpPackagesByGhcPkgId localPackages)         logFilesTChan <- liftIO $ atomically newTChan         let totalWanted = length $ filter lpWanted locals         env <- ask         inner ExecuteEnv-            { eeEnvOverride = menv-            , eeBuildOpts = bopts+            { eeBuildOpts = bopts             , eeBuildOptsCLI = boptsCli              -- Uncertain as to why we cannot run configures in parallel. This appears              -- to be a Cabal library bug. Original issue:@@ -391,6 +382,10 @@   where     toDumpPackagesByGhcPkgId = Map.fromList . map (\dp -> (dpGhcPkgId dp, dp)) +    createTempDirFunction+        | Just True <- boptsKeepTmpFiles bopts = withKeepSystemTempDir+        | otherwise = withSystemTempDir+     dumpLogs :: TChan (Path Abs Dir, Path Abs File) -> Int -> RIO env ()     dumpLogs chan totalWanted = do         allLogs <- fmap reverse $ liftIO $ atomically drainChan@@ -404,13 +399,12 @@                     DumpWarningLogs -> mapM_ dumpLogIfWarning allLogs                     DumpNoLogs                         | totalWanted > 1 ->-                            logInfo $ T.concat-                                [ "Build output has been captured to log files, use "-                                , "--dump-logs to see it on the console"-                                ]+                            logInfo $+                                "Build output has been captured to log files, use " <>+                                "--dump-logs to see it on the console"                         | otherwise -> return ()-                logInfo $ T.pack $ "Log files have been written to: "-                        ++ toFilePath (parent (snd firstLog))+                logInfo $ "Log files have been written to: " <>+                          fromString (toFilePath (parent (snd firstLog)))          -- We only strip the colors /after/ we've dumped logs, so that         -- we get pretty colors in our dump output on the terminal.@@ -428,13 +422,14 @@      dumpLogIfWarning :: (Path Abs Dir, Path Abs File) -> RIO env ()     dumpLogIfWarning (pkgDir, filepath) = do-      firstWarning <- runResourceT-          $ transPipe liftResourceT (CB.sourceFile (toFilePath filepath))-         $$ CT.decodeUtf8Lenient-         =$ CT.lines-         =$ CL.map stripCR-         =$ CL.filter isWarning-         =$ CL.take 1+      firstWarning <- withSourceFile (toFilePath filepath) $ \src ->+            runConduit+          $ src+         .| CT.decodeUtf8Lenient+         .| CT.lines+         .| CL.map stripCR+         .| CL.filter isWarning+         .| CL.take 1       unless (null firstWarning) $ dumpLog " due to warnings" (pkgDir, filepath)      isWarning :: Text -> Bool@@ -443,23 +438,30 @@      dumpLog :: String -> (Path Abs Dir, Path Abs File) -> RIO env ()     dumpLog msgSuffix (pkgDir, filepath) = do-        logInfo $ T.pack $ concat ["\n--  Dumping log file", msgSuffix, ": ", toFilePath filepath, "\n"]+        logInfo $+          "\n--  Dumping log file" <>+          fromString msgSuffix <>+          ": " <>+          fromString (toFilePath filepath) <>+          "\n"         compilerVer <- view actualCompilerVersionL-        runResourceT-            $ transPipe liftResourceT (CB.sourceFile (toFilePath filepath))-           $$ CT.decodeUtf8Lenient-           =$ mungeBuildOutput ExcludeTHLoading ConvertPathsToAbsolute pkgDir compilerVer-           =$ CL.mapM_ logInfo-        logInfo $ T.pack $ "\n--  End of log file: " ++ toFilePath filepath ++ "\n"+        withSourceFile (toFilePath filepath) $ \src ->+              runConduit+            $ src+           .| CT.decodeUtf8Lenient+           .| mungeBuildOutput ExcludeTHLoading ConvertPathsToAbsolute pkgDir compilerVer+           .| CL.mapM_ (logInfo . RIO.display)+        logInfo $ "\n--  End of log file: " <> fromString (toFilePath filepath) <> "\n"      stripColors :: Path Abs File -> IO ()     stripColors fp = do       let colorfp = toFilePath fp ++ "-color"-      runConduitRes $ CB.sourceFile (toFilePath fp) .| CB.sinkFile colorfp-      runConduitRes-        $ CB.sourceFile colorfp-       .| noColors-       .| CB.sinkFile (toFilePath fp)+      withSourceFile (toFilePath fp) $ \src ->+        withSinkFile colorfp $ \sink ->+        runConduit $ src .| sink+      withSourceFile colorfp $ \src ->+        withSinkFile (toFilePath fp) $ \sink ->+        runConduit $ src .| noColors .| sink        where         noColors = do@@ -475,8 +477,7 @@  -- | Perform the actual plan executePlan :: HasEnvConfig env-            => EnvOverride-            -> BuildOptsCLI+            => BuildOptsCLI             -> BaseConfigOpts             -> [LocalPackage]             -> [DumpPackage () () ()] -- ^ global packages@@ -486,24 +487,24 @@             -> Map PackageName Target             -> Plan             -> RIO env ()-executePlan menv boptsCli baseConfigOpts locals globalPackages snapshotPackages localPackages installedMap targets plan = do+executePlan boptsCli baseConfigOpts locals globalPackages snapshotPackages localPackages installedMap targets plan = do     logDebug "Executing the build plan"     bopts <- view buildOptsL-    withExecuteEnv menv bopts boptsCli baseConfigOpts locals globalPackages snapshotPackages localPackages (executePlan' installedMap targets plan)+    withExecuteEnv bopts boptsCli baseConfigOpts locals globalPackages snapshotPackages localPackages (executePlan' installedMap targets plan)      copyExecutables (planInstallExes plan)      config <- view configL-    menv' <- liftIO $ configEnvOverride config EnvSettings+    menv' <- liftIO $ configProcessContextSettings config EnvSettings                     { esIncludeLocals = True                     , esIncludeGhcPackagePath = True                     , esStackExe = True                     , esLocaleUtf8 = False                     , esKeepGhcRts = False                     }-    forM_ (boptsCLIExec boptsCli) $ \(cmd, args) ->-        withProcessTimeLog cmd args $-            callProcess (Cmd Nothing cmd menv' args)+    withProcessContext menv' $+      forM_ (boptsCLIExec boptsCli) $ \(cmd, args) ->+      proc cmd args runProcess_  copyExecutables     :: HasEnvConfig env@@ -538,21 +539,19 @@           >>= rejectMissingFile         case mfp of             Nothing -> do-                logWarn $ T.concat-                    [ "Couldn't find executable "-                    , name-                    , " in directory "-                    , T.pack $ toFilePath bindir-                    ]+                logWarn $+                    "Couldn't find executable " <>+                    RIO.display name <>+                    " in directory " <>+                    fromString (toFilePath bindir)                 return Nothing             Just file -> do                 let destFile = destDir' FP.</> T.unpack name ++ ext-                logInfo $ T.concat-                    [ "Copying from "-                    , T.pack $ toFilePath file-                    , " to "-                    , T.pack destFile-                    ]+                logInfo $+                    "Copying from " <>+                    fromString (toFilePath file) <>+                    " to " <>+                    fromString destFile                  liftIO $ case platform of                     Platform _ Windows | FP.equalFilePath destFile currExe ->@@ -562,11 +561,11 @@      unless (null installed) $ do         logInfo ""-        logInfo $ T.concat-            [ "Copied executables to "-            , T.pack destDir'-            , ":"]-    forM_ installed $ \exe -> logInfo ("- " <> exe)+        logInfo $+            "Copied executables to " <>+            fromString destDir' <>+            ":"+    forM_ installed $ \exe -> logInfo ("- " <> RIO.display exe)     unless compilerSpecific $ warnInstallSearchPathIssues destDir' installed  @@ -597,50 +596,48 @@         ids -> do             localDB <- packageDatabaseLocal             forM_ ids $ \(id', (ident, reason)) -> do-                logInfo $ T.concat-                    [ T.pack $ packageIdentifierString ident-                    , ": unregistering"-                    , if T.null reason+                logInfo $+                    RIO.display ident <>+                    ": unregistering" <>+                    if T.null reason                         then ""-                        else T.concat-                            [ " ("-                            , reason-                            , ")"-                            ]-                    ]-                unregisterGhcPkgId eeEnvOverride wc cv localDB id' ident+                        else " (" <> RIO.display reason <> ")"+                unregisterGhcPkgId wc cv localDB id' ident      liftIO $ atomically $ modifyTVar' eeLocalDumpPkgs $ \initMap ->         foldl' (flip Map.delete) initMap $ Map.keys (planUnregisterLocal plan)      run <- askRunInIO -    let actions = concatMap (toActions installedMap' run ee) $ Map.elems $ Map.mergeWithKey+    -- If running tests concurrently with eachother, then create an MVar+    -- which is empty while each test is being run.+    concurrentTests <- view $ configL.to configConcurrentTests+    mtestLock <- if concurrentTests then return Nothing else Just <$> liftIO (newMVar ())++    let actions = concatMap (toActions installedMap' mtestLock run ee) $ Map.elems $ Map.mergeWithKey             (\_ b f -> Just (Just b, Just f))             (fmap (\b -> (Just b, Nothing)))             (fmap (\f -> (Nothing, Just f)))             (planTasks plan)             (planFinals plan)     threads <- view $ configL.to configJobs-    concurrentTests <- view $ configL.to configConcurrentTests     let keepGoing =-            fromMaybe (boptsTests eeBuildOpts || boptsBenchmarks eeBuildOpts) (boptsKeepGoing eeBuildOpts)-        concurrentFinal =-            -- TODO it probably makes more sense to use a lock for test suites-            -- and just have the execution blocked. Turning off all concurrency-            -- on finals based on the --test option doesn't fit in well.-            if boptsTests eeBuildOpts-                then concurrentTests-                else True+            fromMaybe (not (M.null (planFinals plan))) (boptsKeepGoing eeBuildOpts)     terminal <- view terminalL-    errs <- liftIO $ runActions threads keepGoing concurrentFinal actions $ \doneVar -> do+    errs <- liftIO $ runActions threads keepGoing actions $ \doneVar actionsVar -> do         let total = length actions             loop prev                 | prev == total =-                    run $ logStickyDone ("Completed " <> T.pack (show total) <> " action(s).")+                    run $ logStickyDone ("Completed " <> RIO.display total <> " action(s).")                 | otherwise = do+                    inProgress <- readTVarIO actionsVar+                    let packageNames = map (\(ActionId pkgID _) -> packageIdentifierText pkgID) (toList inProgress)+                        nowBuilding []    = ""+                        nowBuilding names = mconcat $ ": " : intersperse ", " (map RIO.display names)                     when terminal $ run $-                        logSticky ("Progress: " <> T.pack (show prev) <> "/" <> T.pack (show total))+                        logSticky $+                            "Progress " <> RIO.display prev <> "/" <> RIO.display total <>+                                nowBuilding packageNames                     done <- atomically $ do                         done <- readTVar doneVar                         check $ done /= prev@@ -654,9 +651,9 @@     when (boptsHaddock eeBuildOpts) $ do         snapshotDumpPkgs <- liftIO (readTVarIO eeSnapshotDumpPkgs)         localDumpPkgs <- liftIO (readTVarIO eeLocalDumpPkgs)-        generateLocalHaddockIndex eeEnvOverride wc eeBaseConfigOpts localDumpPkgs eeLocals-        generateDepsHaddockIndex eeEnvOverride wc eeBaseConfigOpts eeGlobalDumpPkgs snapshotDumpPkgs localDumpPkgs eeLocals-        generateSnapHaddockIndex eeEnvOverride wc eeBaseConfigOpts eeGlobalDumpPkgs snapshotDumpPkgs+        generateLocalHaddockIndex wc eeBaseConfigOpts localDumpPkgs eeLocals+        generateDepsHaddockIndex wc eeBaseConfigOpts eeGlobalDumpPkgs snapshotDumpPkgs localDumpPkgs eeLocals+        generateSnapHaddockIndex wc eeBaseConfigOpts eeGlobalDumpPkgs snapshotDumpPkgs         when (boptsOpenHaddocks eeBuildOpts) $ do             let planPkgs, localPkgs, installedPkgs, availablePkgs                     :: Map PackageName (PackageIdentifier, InstallLocation)@@ -676,11 +673,12 @@  toActions :: HasEnvConfig env           => InstalledMap+          -> Maybe (MVar ())           -> (RIO env () -> IO ())           -> ExecuteEnv           -> (Maybe Task, Maybe Task) -- build and final           -> [Action]-toActions installedMap runInBase ee (mbuild, mfinal) =+toActions installedMap mtestLock runInBase ee (mbuild, mfinal) =     abuild ++ afinal   where     abuild =@@ -691,41 +689,59 @@                     { actionId = ActionId taskProvides ATBuild                     , actionDeps =                         Set.map (\ident -> ActionId ident ATBuild) (tcoMissing taskConfigOpts)-                    , actionDo = \ac -> runInBase $ singleBuild runInBase ac ee task installedMap False+                    , actionDo = \ac -> runInBase $ singleBuild ac ee task installedMap False+                    , actionConcurrency = ConcurrencyAllowed                     }                 ]     afinal =         case mfinal of             Nothing -> []             Just task@Task {..} ->-                (if taskAllInOne then [] else-                    [Action+                (if taskAllInOne then id else (:)+                    Action                         { actionId = ActionId taskProvides ATBuildFinal                         , actionDeps = addBuild                             (Set.map (\ident -> ActionId ident ATBuild) (tcoMissing taskConfigOpts))-                        , actionDo = \ac -> runInBase $ singleBuild runInBase ac ee task installedMap True-                        }]) ++-                [ Action-                    { actionId = ActionId taskProvides ATFinal-                    , actionDeps =-                        if taskAllInOne-                            then addBuild mempty-                            else Set.singleton (ActionId taskProvides ATBuildFinal)-                    , actionDo = \ac -> runInBase $ do-                        let comps = taskComponents task-                            tests = testComponents comps-                            benches = benchComponents comps-                        unless (Set.null tests) $ do-                            singleTest runInBase topts (Set.toList tests) ac ee task installedMap-                        unless (Set.null benches) $ do-                            singleBench runInBase beopts (Set.toList benches) ac ee task installedMap-                    }-                ]+                        , actionDo = \ac -> runInBase $ singleBuild ac ee task installedMap True+                        , actionConcurrency = ConcurrencyAllowed+                        }) $+                -- These are the "final" actions - running tests and benchmarks.+                (if Set.null tests then id else (:)+                    Action+                        { actionId = ActionId taskProvides ATRunTests+                        , actionDeps = finalDeps+                        , actionDo = \ac -> withLock mtestLock $ runInBase $ do+                            singleTest topts (Set.toList tests) ac ee task installedMap+                        -- Always allow tests tasks to run concurrently with+                        -- other tasks, particularly build tasks. Note that+                        -- 'mtestLock' can optionally make it so that only+                        -- one test is run at a time.+                        , actionConcurrency = ConcurrencyAllowed+                        }) $+                (if Set.null benches then id else (:)+                    Action+                        { actionId = ActionId taskProvides ATRunBenchmarks+                        , actionDeps = finalDeps+                        , actionDo = \ac -> runInBase $ do+                            singleBench beopts (Set.toList benches) ac ee task installedMap+                        -- Never run benchmarks concurrently with any other task, see #3663+                        , actionConcurrency = ConcurrencyDisallowed+                        })+                []               where+                comps = taskComponents task+                tests = testComponents comps+                benches = benchComponents comps+                finalDeps =+                    if taskAllInOne+                        then addBuild mempty+                        else Set.singleton (ActionId taskProvides ATBuildFinal)                 addBuild =                     case mbuild of                         Nothing -> id                         Just _ -> Set.insert $ ActionId taskProvides ATBuild+    withLock Nothing f = f+    withLock (Just lock) f = withMVar lock $ \() -> f     bopts = eeBuildOpts ee     topts = boptsTestOpts bopts     beopts = boptsBenchmarkOpts bopts@@ -774,7 +790,7 @@             , configCacheDeps = allDeps             , configCacheComponents =                 case taskType of-                    TTFiles lp _ -> Set.map renderComponent $ lpComponents lp+                    TTFiles lp _ -> Set.map (encodeUtf8 . renderComponent) $ lpComponents lp                     TTIndex{} -> Set.empty             , configCacheHaddock =                 shouldHaddockPackage eeBuildOpts eeWanted (packageIdentifierName taskProvides)@@ -820,16 +836,15 @@     when needConfig $ withMVar eeConfigureLock $ \_ -> do         deleteCaches pkgDir         announce-        menv <- getMinimalEnvOverride         let programNames =                 if eeCabalPkgVer < $(mkVersion "1.22")                     then ["ghc", "ghc-pkg"]                     else ["ghc", "ghc-pkg", "ghcjs", "ghcjs-pkg"]         exes <- forM programNames $ \name -> do-            mpath <- findExecutable menv name+            mpath <- findExecutable name             return $ case mpath of-                Nothing -> []-                Just x -> return $ concat ["--with-", name, "=", toFilePath x]+                Left _ -> []+                Right x -> return $ concat ["--with-", name, "=", x]         -- Configure cabal with arguments determined by         -- Stack.Types.Build.configureOpts         cabal KeepTHLoading $ "configure" : concat@@ -850,17 +865,15 @@       let fp = pkgDir </> $(mkRelFile "configure")       exists <- doesFileExist fp       unless exists $ do-        logInfo $ "Trying to generate configure with autoreconf in " <> T.pack (toFilePath pkgDir)-        menv <- getMinimalEnvOverride-        readProcessNull (Just pkgDir) menv "autoreconf" ["-i"] `catchAny` \ex ->-          logWarn $ "Unable to run autoreconf: " <> T.pack (show ex)+        logInfo $ "Trying to generate configure with autoreconf in " <> fromString (toFilePath pkgDir)+        withWorkingDir (toFilePath pkgDir) $ readProcessNull "autoreconf" ["-i"] `catchAny` \ex ->+          logWarn $ "Unable to run autoreconf: " <> displayShow ex -announceTask :: MonadLogger m => Task -> Text -> m ()-announceTask task x = logInfo $ T.concat-    [ T.pack $ packageIdentifierString $ taskProvides task-    , ": "-    , x-    ]+announceTask :: HasLogFunc env => Task -> Text -> RIO env ()+announceTask task x = logInfo $+    RIO.display (taskProvides task) <>+    ": " <>+    RIO.display x  -- | This sets up a context for executing build steps which need to run -- Cabal (via a compiled Setup.hs).  In particular it does the following:@@ -874,8 +887,7 @@ -- -- * Provides the user a function with which run the Cabal process. withSingleContext :: forall env a. HasEnvConfig env-                  => (RIO env () -> IO ())-                  -> ActionContext+                  => ActionContext                   -> ExecuteEnv                   -> Task                   -> Maybe (Map PackageIdentifier GhcPkgId)@@ -893,7 +905,7 @@                      -> Maybe (Path Abs File, Handle)          -- Log file                      -> RIO env a)                   -> RIO env a-withSingleContext runInBase ActionContext {..} ExecuteEnv {..} task@Task {..} mdeps msuffix inner0 =+withSingleContext ActionContext {..} ExecuteEnv {..} task@Task {..} mdeps msuffix inner0 =     withPackage $ \package cabalfp pkgDir ->     withLogFile pkgDir package $ \mlogFile ->     withCabal package pkgDir mlogFile $ \cabal ->@@ -906,9 +918,19 @@             TTFiles lp _ -> lpWanted lp             TTIndex{} -> False -    console = wanted-           && all (\(ActionId ident _) -> ident == taskProvides) (Set.toList acRemaining)-           && eeTotalWanted == 1+    -- Output to the console if this is the last task, and the user+    -- asked to build it specifically. When the action is a+    -- 'ConcurrencyDisallowed' action (benchmarks), then we can also be+    -- sure to have excluse access to the console, so output is also+    -- sent to the console in this case.+    --+    -- See the discussion on #426 for thoughts on sending output to the+    -- console from concurrent tasks.+    console =+      (wanted &&+       all (\(ActionId ident _) -> ident == taskProvides) (Set.toList acRemaining) &&+       eeTotalWanted == 1+      ) || (acConcurrency == ConcurrencyDisallowed)      withPackage inner =         case taskType of@@ -935,10 +957,7 @@                     liftIO $ atomically $ writeTChan eeLogFiles (pkgDir, logPath)                 _ -> return () -            bracket-                (liftIO $ openBinaryFile fp WriteMode)-                (liftIO . hClose)-                $ \h -> inner (Just (logPath, h))+            withBinaryFile fp WriteMode $ \h -> inner (Just (logPath, h))      withCabal         :: Package@@ -959,14 +978,14 @@                 , esLocaleUtf8 = True                 , esKeepGhcRts = False                 }-        menv <- liftIO $ configEnvOverride config envSettings+        menv <- liftIO $ configProcessContextSettings config envSettings         distRelativeDir' <- distRelativeDir         esetupexehs <-             -- Avoid broken Setup.hs files causing problems for simple build             -- types, see:             -- https://github.com/commercialhaskell/stack/issues/370             case (packageBuildType package, eeSetupExe) of-                (Just C.Simple, Just setupExe) -> return $ Left setupExe+                (C.Simple, Just setupExe) -> return $ Left setupExe                 _ -> liftIO $ Right <$> getSetupHs pkgDir         inner $ \stripTHLoading args -> do             let cabalPackageArg@@ -991,7 +1010,7 @@                 warnCustomNoDeps :: RIO env ()                 warnCustomNoDeps =                     case (taskType, packageBuildType package) of-                        (TTFiles lp Local, Just C.Custom) | lpWanted lp -> do+                        (TTFiles lp Local, C.Custom) | lpWanted lp -> do                             prettyWarnL                                 [ flow "Package"                                 , display $ packageName package@@ -1026,10 +1045,10 @@                                 case filter (matches . fst) (Map.toList allDeps) of                                     x:xs -> do                                         unless (null xs)-                                            (logWarn (T.pack ("Found multiple installed packages for custom-setup dep: " ++ packageNameString name)))+                                            (logWarn ("Found multiple installed packages for custom-setup dep: " <> RIO.display name))                                         return ("-package-id=" ++ ghcPkgIdString (snd x), Just (toCabalPackageIdentifier (fst x)))                                     [] -> do-                                        logWarn (T.pack ("Could not find custom-setup dep: " ++ packageNameString name))+                                        logWarn ("Could not find custom-setup dep: " <> RIO.display name)                                         return ("-package=" ++ packageNameString name, Nothing)                             let depsArgs = map fst matchedDeps                             -- Generate setup_macros.h and provide it to ghc@@ -1088,19 +1107,20 @@                 runExe :: Path Abs File -> [String] -> RIO env ()                 runExe exeName fullArgs = do                     compilerVer <- view actualCompilerVersionL-                    runAndOutput compilerVer `catch` \(ProcessExitedUnsuccessfully _ ec) -> do+                    runAndOutput compilerVer `catch` \ece -> do                         bss <-                             case mlogFile of                                 Nothing -> return []                                 Just (logFile, h) -> do                                     liftIO $ hClose h-                                    runResourceT-                                        $ transPipe liftResourceT (CB.sourceFile (toFilePath logFile))-                                        =$= CT.decodeUtf8Lenient-                                        $$ mungeBuildOutput stripTHLoading makeAbsolute pkgDir compilerVer-                                        =$ CL.consume+                                    withSourceFile (toFilePath logFile) $ \src ->+                                           runConduit+                                         $ src+                                        .| CT.decodeUtf8Lenient+                                        .| mungeBuildOutput stripTHLoading makeAbsolute pkgDir compilerVer+                                        .| CL.consume                         throwM $ SetupHsBuildFailure-                            ec+                            (eceExitCode ece)                             (Just taskProvides)                             exeName                             fullArgs@@ -1108,22 +1128,27 @@                             bss                   where                     runAndOutput :: CompilerVersion 'CVActual -> RIO env ()-                    runAndOutput compilerVer = case mlogFile of+                    runAndOutput compilerVer = withWorkingDir (toFilePath pkgDir) $ withProcessContext menv $ case mlogFile of                         Just (_, h) ->-                            sinkProcessStderrStdoutHandle (Just pkgDir) menv (toFilePath exeName) fullArgs h h+                            proc (toFilePath exeName) fullArgs+                          $ runProcess_+                          . setStdin (byteStringInput "")+                          . setStdout (useHandleOpen h)+                          . setStderr (useHandleOpen h)                         Nothing ->-                            void $ sinkProcessStderrStdout (Just pkgDir) menv (toFilePath exeName) fullArgs+                            void $ sinkProcessStderrStdout (toFilePath exeName) fullArgs                                 (outputSink KeepTHLoading LevelWarn compilerVer)                                 (outputSink stripTHLoading LevelInfo compilerVer)                     outputSink-                        :: ExcludeTHLoading+                        :: HasCallStack+                        => ExcludeTHLoading                         -> LogLevel                         -> CompilerVersion 'CVActual-                        -> Sink S.ByteString IO ()+                        -> ConduitM S.ByteString Void (RIO env) ()                     outputSink excludeTH level compilerVer =                         CT.decodeUtf8Lenient-                        =$ mungeBuildOutput excludeTH makeAbsolute pkgDir compilerVer-                        =$ CL.mapM_ (runInBase . monadLoggerLog $(TH.location >>= liftLoc) "" level)+                        .| mungeBuildOutput excludeTH makeAbsolute pkgDir compilerVer+                        .| CL.mapM_ (logGeneric "" level . RIO.display)                     -- If users want control, we should add a config option for this                     makeAbsolute :: ConvertPathsToAbsolute                     makeAbsolute = case stripTHLoading of@@ -1185,14 +1210,13 @@ --   with @copy@, and not the copying done by @stack install@ - that is --   handled by 'copyExecutables'. singleBuild :: forall env. (HasEnvConfig env, HasRunner env)-            => (RIO env () -> IO ())-            -> ActionContext+            => ActionContext             -> ExecuteEnv             -> Task             -> InstalledMap             -> Bool             -- ^ Is this a final build?             -> RIO env ()-singleBuild runInBase ac@ActionContext {..} ee@ExecuteEnv {..} task@Task {..} installedMap isFinalBuild = do+singleBuild ac@ActionContext {..} ee@ExecuteEnv {..} task@Task {..} installedMap isFinalBuild = do     (allDepsMap, cache) <- getConfigCache ee task installedMap enableTests enableBenchmarks     mprecompiled <- getPrecompiled cache     minstalled <-@@ -1271,36 +1295,34 @@         wc <- view $ actualCompilerVersionL.whichCompilerL         announceTask task "using precompiled package"         forM_ mlib $ \libpath -> do-            menv <- getMinimalEnvOverride             withMVar eeInstallLock $ \() -> do                 -- We want to ignore the global and user databases.                 -- Unfortunately, ghc-pkg doesn't take such arguments on the                 -- command line. Instead, we'll set GHC_PACKAGE_PATH. See:                 -- https://github.com/commercialhaskell/stack/issues/1146 -                menv' <- modifyEnvOverride menv-                       $ Map.insert-                            (ghcPkgPathEnvVar wc)-                            (T.pack $ toFilePathNoTrailingSep $ bcoSnapDB eeBaseConfigOpts)+                let modifyEnv = Map.insert+                      (ghcPkgPathEnvVar wc)+                      (T.pack $ toFilePathNoTrailingSep $ bcoSnapDB eeBaseConfigOpts) -                -- In case a build of the library with different flags already exists, unregister it-                -- before copying.-                let ghcPkgExe = ghcPkgExeName wc-                catch-                    (readProcessNull Nothing menv' ghcPkgExe-                        [ "unregister"-                        , "--force"-                        , packageIdentifierString taskProvides-                        ])-                    (\ex -> case ex of-                        ProcessFailed{} -> return ()-                        _ -> throwM ex)+                withModifyEnvVars modifyEnv $ do+                  -- In case a build of the library with different flags already exists, unregister it+                  -- before copying.+                  let ghcPkgExe = ghcPkgExeName wc+                  catchAny+                      (readProcessNull ghcPkgExe+                          [ "unregister"+                          , "--force"+                          , packageIdentifierString taskProvides+                          ])+                      (const (return ())) -                readProcessNull Nothing menv' ghcPkgExe-                    [ "register"-                    , "--force"-                    , libpath-                    ]+                  void $ proc ghcPkgExe+                      [ "register"+                      , "--force"+                      , libpath+                      ]+                      readProcess_         liftIO $ forM_ exes $ \exe -> do             D.createDirectoryIfMissing True bindir             let dst = bindir FP.</> FP.takeFileName exe@@ -1315,7 +1337,7 @@         case mlib of             Nothing -> return $ Just $ Executable taskProvides             Just _ -> do-                mpkgid <- loadInstalledPkg eeEnvOverride wc pkgDbs eeSnapshotDumpPkgs pname+                mpkgid <- loadInstalledPkg wc pkgDbs eeSnapshotDumpPkgs pname                  return $ Just $                     case mpkgid of@@ -1324,12 +1346,12 @@       where         bindir = toFilePath $ bcoSnapInstallRoot eeBaseConfigOpts </> bindirSuffix -    realConfigAndBuild cache allDepsMap = withSingleContext runInBase ac ee task (Just allDepsMap) Nothing+    realConfigAndBuild cache allDepsMap = withSingleContext ac ee task (Just allDepsMap) Nothing         $ \package cabalfp pkgDir cabal announce _console _mlogFile -> do             executableBuildStatuses <- getExecutableBuildStatuses package pkgDir             when (not (cabalIsSatisfied executableBuildStatuses) && taskIsTarget task)                  (logInfo-                      ("Building all executables for `" <> packageNameText (packageName package) <>+                      ("Building all executables for `" <> RIO.display (packageName package) <>                        "' once. After a successful build of all of them, only specified executables will be rebuilt."))              _neededConfig <- ensureConfig cache pkgDir ee (announce ("configure" <> annSuffix executableBuildStatuses)) cabal cabalfp task@@ -1390,9 +1412,9 @@                 -- https://github.com/commercialhaskell/stack/issues/2649                 -- is resolved, we will want to partition the warnings                 -- based on variety, and output in different lists.-                let showModuleWarning (UnlistedModulesWarning mcomp modules) =+                let showModuleWarning (UnlistedModulesWarning comp modules) =                       "- In" <+>-                      maybe "the library component" (\c -> fromString c <+> "component") mcomp <>+                      fromString (T.unpack (renderComponent comp)) <>                       ":" <> line <>                       indent 4 (mconcat $ intersperse line $ map (styleGood . fromString . C.display) modules)                 forM_ mlocalWarnings $ \(cabalfp, warnings) -> do@@ -1425,14 +1447,21 @@             announce "haddock"             sourceFlag <- if not (boptsHaddockHyperlinkSource eeBuildOpts) then return [] else do                 -- See #2429 for why the temp dir is used-                hyped <- tryProcessStdout (Just eeTempDir) eeEnvOverride "haddock" ["--hyperlinked-source"]-                case hyped of+                ec+                  <- withWorkingDir (toFilePath eeTempDir)+                   $ proc "haddock" ["--hyperlinked-source"]+                   $ \pc -> withProcess+                     (setStdout createSource $ setStderr createSource pc) $ \p ->+                       runConcurrently+                         $ Concurrently (runConduit $ getStdout p .| CL.sinkNull)+                        *> Concurrently (runConduit $ getStderr p .| CL.sinkNull)+                        *> Concurrently (waitExitCode p)+                case ec of                     -- Fancy crosslinked source-                    Right _ -> do-                        return ["--haddock-option=--hyperlinked-source"]+                    ExitSuccess -> return ["--haddock-option=--hyperlinked-source"]                     -- Older hscolour colouring-                    Left _  -> do-                        hscolourExists <- doesExecutableExist eeEnvOverride "HsColour"+                    ExitFailure _ -> do+                        hscolourExists <- doesExecutableExist "HsColour"                         unless hscolourExists $ logWarn                             ("Warning: haddock not generating hyperlinked sources because 'HsColour' not\n" <>                              "found on PATH (use 'stack install hscolour' to install).")@@ -1455,7 +1484,7 @@             eres <- try $ cabal KeepTHLoading ["copy"]             case eres of                 Left err@CabalExitedUnsuccessfully{} ->-                    throwM $ CabalCopyFailed (packageBuildType package == Just C.Simple) (show err)+                    throwM $ CabalCopyFailed (packageBuildType package == C.Simple) (show err)                 _ -> return ()             when hasLibrary $ cabal KeepTHLoading ["register"] @@ -1470,7 +1499,7 @@         let ident = PackageIdentifier (packageName package) (packageVersion package)         mpkgid <- case packageLibraries package of             HasLibraries _ -> do-                mpkgid <- loadInstalledPkg eeEnvOverride wc [installedPkgDb] installedDumpPkgsTVar (packageName package)+                mpkgid <- loadInstalledPkg wc [installedPkgDb] installedDumpPkgsTVar (packageName package)                 case mpkgid of                     Nothing -> throwM $ Couldn'tFindPkgId $ packageName package                     Just pkgid -> return $ Library ident pkgid Nothing@@ -1499,8 +1528,8 @@          return mpkgid -    loadInstalledPkg menv wc pkgDbs tvar name = do-        dps <- ghcPkgDescribe name menv wc pkgDbs $ conduitDumpPackage =$ CL.consume+    loadInstalledPkg wc pkgDbs tvar name = do+        dps <- ghcPkgDescribe name wc pkgDbs $ conduitDumpPackage .| CL.consume         case dps of             [] -> return Nothing             [dp] -> do@@ -1527,12 +1556,12 @@  -- | Check whether the given executable is defined in the given dist directory. checkExeStatus-    :: (MonadLogger m, MonadIO m, MonadThrow m)+    :: HasLogFunc env     => WhichCompiler     -> Platform     -> Path b Dir     -> Text-    -> m (Text, ExecutableBuildStatus)+    -> RIO env (Text, ExecutableBuildStatus) checkExeStatus compiler platform distDir name = do     exename <- parseRelDir (T.unpack name)     exists <- checkPath (distDir </> $(mkRelDir "build") </> exename)@@ -1587,19 +1616,18 @@ -- | Implements running a package's tests. Also handles producing -- coverage reports if coverage is enabled. singleTest :: HasEnvConfig env-           => (RIO env () -> IO ())-           -> TestOpts+           => TestOpts            -> [Text]            -> ActionContext            -> ExecuteEnv            -> Task            -> InstalledMap            -> RIO env ()-singleTest runInBase topts testsToRun ac ee task installedMap = do+singleTest topts testsToRun ac ee task installedMap = do     -- FIXME: Since this doesn't use cabal, we should be able to avoid using a     -- fullblown 'withSingleContext'.     (allDepsMap, _cache) <- getConfigCache ee task installedMap True False-    withSingleContext runInBase ac ee task (Just allDepsMap) (Just "test") $ \package _cabalfp pkgDir _cabal announce _console mlogFile -> do+    withSingleContext ac ee task (Just allDepsMap) (Just "test") $ \package _cabalfp pkgDir _cabal announce _console mlogFile -> do         config <- view configL         let needHpc = toCoverage topts @@ -1645,20 +1673,20 @@                 tixPath <- liftM (pkgDir </>) $ parseRelFile $ exeName ++ ".tix"                 exePath <- liftM (buildDir </>) $ parseRelFile $ "build/" ++ testName' ++ "/" ++ exeName                 exists <- doesFileExist exePath-                menv <- liftIO $    configEnvOverride config EnvSettings+                menv <- liftIO $ configProcessContextSettings config EnvSettings                     { esIncludeLocals = taskLocation task == Local                     , esIncludeGhcPackagePath = True                     , esStackExe = True                     , esLocaleUtf8 = False                     , esKeepGhcRts = False                     }-                if exists+                withProcessContext menv $ if exists                     then do                         -- We clear out the .tix files before doing a run.                         when needHpc $ do                             tixexists <- doesFileExist tixPath                             when tixexists $-                                logWarn ("Removing HPC file " <> T.pack (toFilePath tixPath))+                                logWarn ("Removing HPC file " <> fromString (toFilePath tixPath))                             liftIO $ ignoringAbsence (removeFile tixPath)                          let args = toAdditionalArgs topts@@ -1674,22 +1702,23 @@                             liftIO $ hFlush stdout                             liftIO $ hFlush stderr -                        let output =+                        let output setter =                                 case mlogFile of-                                    Nothing -> Inherit-                                    Just (_, h) -> UseHandle h+                                    Nothing -> id+                                    Just (_, h) -> setter (useHandleOpen h) -                        -- Use createProcess_ to avoid the log file being closed afterwards-                        (Just inH, Nothing, Nothing, ph) <- createProcess'-                            stestName-                            (\cp -> cp { std_in = CreatePipe, std_out = output, std_err = output })-                            (Cmd (Just pkgDir) (toFilePath exePath) menv args)-                        when isTestTypeLib $ do-                            logPath <- buildLogPath package (Just stestName)-                            ensureDir (parent logPath)-                            liftIO $ hPutStr inH $ show (logPath, testName)-                        liftIO $ hClose inH-                        ec <- liftIO $ waitForProcess ph+                        ec <- withWorkingDir (toFilePath pkgDir) $+                          proc (toFilePath exePath) args $ \pc0 -> do+                            let pc = setStdin createPipe+                                   $ output setStdout+                                   $ output setStderr+                                     pc0+                            withProcess pc $ \p -> do+                              when isTestTypeLib $ do+                                logPath <- buildLogPath package (Just stestName)+                                ensureDir (parent logPath)+                                liftIO $ hPutStr (getStdin p) $ show (logPath, testName)+                              waitExitCode p                         -- Add a trailing newline, incase the test                         -- output didn't finish with a newline.                         when (isNothing mlogFile) (logInfo "")@@ -1707,8 +1736,8 @@                                 announceResult "failed"                                 return $ Map.singleton testName (Just ec)                     else do-                        logError $ T.pack $ show $ TestSuiteExeMissing-                            (packageBuildType package == Just C.Simple)+                        logError $ displayShow $ TestSuiteExeMissing+                            (packageBuildType package == C.Simple)                             exeName                             (packageNameString (packageName package))                             (T.unpack testName)@@ -1739,17 +1768,16 @@  -- | Implements running a package's benchmarks. singleBench :: HasEnvConfig env-            => (RIO env () -> IO ())-            -> BenchmarkOpts+            => BenchmarkOpts             -> [Text]             -> ActionContext             -> ExecuteEnv             -> Task             -> InstalledMap             -> RIO env ()-singleBench runInBase beopts benchesToRun ac ee task installedMap = do+singleBench beopts benchesToRun ac ee task installedMap = do     (allDepsMap, _cache) <- getConfigCache ee task installedMap False True-    withSingleContext runInBase ac ee task (Just allDepsMap) (Just "bench") $ \_package _cabalfp _pkgDir cabal announce _console _mlogFile -> do+    withSingleContext ac ee task (Just allDepsMap) (Just "bench") $ \_package _cabalfp _pkgDir cabal announce _console _mlogFile -> do         let args = map T.unpack benchesToRun <> maybe []                          ((:[]) . ("--benchmark-options=" <>))                          (beoAdditionalArgs beopts)@@ -1778,10 +1806,10 @@                  -> ConduitM Text Text m () mungeBuildOutput excludeTHLoading makeAbsolute pkgDir compilerVer = void $     CT.lines-    =$ CL.map stripCR-    =$ CL.filter (not . isTHLoading)-    =$ filterLinkerWarnings-    =$ toAbsolute+    .| CL.map stripCR+    .| CL.filter (not . isTHLoading)+    .| filterLinkerWarnings+    .| toAbsolute   where     -- | Is this line a Template Haskell "Loading package" line     -- ByteString@@ -1911,7 +1939,7 @@ -- Test-suite and benchmark build components. finalComponentOptions :: LocalPackage -> [String] finalComponentOptions lp =-    map (T.unpack . decodeUtf8 . renderComponent) $+    map (T.unpack . renderComponent) $     Set.toList $     Set.filter (\c -> isCTest c || isCBench c) (lpComponents lp) 
src/Stack/Build/Haddock.hs view
@@ -20,10 +20,8 @@ import           Stack.Prelude import qualified Data.Foldable as F import qualified Data.HashSet as HS-import           Data.List.Extra (nubOrd) import qualified Data.Map.Strict as Map import qualified Data.Set as Set-import qualified Data.Text as T import           Data.Time (UTCTime) import           Path import           Path.Extra@@ -39,7 +37,7 @@ import           Stack.Types.PackageName import           Stack.Types.Runner import qualified System.FilePath as FP-import           System.Process.Read+import           RIO.Process import           Web.Browser (openBrowser)  openHaddocksInBrowser@@ -78,11 +76,11 @@                     else do                         logWarn $                             "Expected to find documentation at " <>-                            T.pack (toFilePath docFile) <>+                            fromString (toFilePath docFile) <>                             ", but that file is missing.  Opening doc index instead."                         getDocIndex             _ -> getDocIndex-    prettyInfo $ "Opening" <+> display docFile <+> "in the browser."+    prettyInfo $ "Opening" <+> Stack.PrettyPrint.display docFile <+> "in the browser."     _ <- liftIO $ openBrowser (toFilePath docFile)     return () @@ -104,14 +102,13 @@  -- | Generate Haddock index and contents for local packages. generateLocalHaddockIndex-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride-    -> WhichCompiler+    :: (HasProcessContext env, HasLogFunc env)+    => WhichCompiler     -> BaseConfigOpts     -> Map GhcPkgId (DumpPackage () () ())  -- ^ Local package dump     -> [LocalPackage]-    -> m ()-generateLocalHaddockIndex envOverride wc bco localDumpPkgs locals = do+    -> RIO env ()+generateLocalHaddockIndex wc bco localDumpPkgs locals = do     let dumpPackages =             mapMaybe                 (\LocalPackage{lpPackage = Package{..}} ->@@ -121,7 +118,6 @@                 locals     generateHaddockIndex         "local packages"-        envOverride         wc         bco         dumpPackages@@ -130,21 +126,19 @@  -- | Generate Haddock index and contents for local packages and their dependencies. generateDepsHaddockIndex-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride-    -> WhichCompiler+    :: (HasProcessContext env, HasLogFunc env)+    => WhichCompiler     -> BaseConfigOpts     -> Map GhcPkgId (DumpPackage () () ())  -- ^ Global dump information     -> Map GhcPkgId (DumpPackage () () ())  -- ^ Snapshot dump information     -> Map GhcPkgId (DumpPackage () () ())  -- ^ Local dump information     -> [LocalPackage]-    -> m ()-generateDepsHaddockIndex envOverride wc bco globalDumpPkgs snapshotDumpPkgs localDumpPkgs locals = do+    -> RIO env ()+generateDepsHaddockIndex wc bco globalDumpPkgs snapshotDumpPkgs localDumpPkgs locals = do     let deps = (mapMaybe (`lookupDumpPackage` allDumpPkgs) . nubOrd . findTransitiveDepends . mapMaybe getGhcPkgId) locals         depDocDir = localDepsDocDir bco     generateHaddockIndex         "local packages and dependencies"-        envOverride         wc         bco         deps@@ -175,17 +169,15 @@  -- | Generate Haddock index and contents for all snapshot packages. generateSnapHaddockIndex-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride-    -> WhichCompiler+    :: (HasProcessContext env, HasLogFunc env)+    => WhichCompiler     -> BaseConfigOpts     -> Map GhcPkgId (DumpPackage () () ())  -- ^ Global package dump     -> Map GhcPkgId (DumpPackage () () ())  -- ^ Snapshot package dump-    -> m ()-generateSnapHaddockIndex envOverride wc bco globalDumpPkgs snapshotDumpPkgs =+    -> RIO env ()+generateSnapHaddockIndex wc bco globalDumpPkgs snapshotDumpPkgs =     generateHaddockIndex         "snapshot packages"-        envOverride         wc         bco         (Map.elems snapshotDumpPkgs ++ Map.elems globalDumpPkgs)@@ -194,16 +186,15 @@  -- | Generate Haddock index and contents for specified packages. generateHaddockIndex-    :: (MonadUnliftIO m, MonadLogger m)+    :: (HasProcessContext env, HasLogFunc env)     => Text-    -> EnvOverride     -> WhichCompiler     -> BaseConfigOpts     -> [DumpPackage () () ()]     -> FilePath     -> Path Abs Dir-    -> m ()-generateHaddockIndex descr envOverride wc bco dumpPackages docRelFP destDir = do+    -> RIO env ()+generateHaddockIndex descr wc bco dumpPackages docRelFP destDir = do     ensureDir destDir     interfaceOpts <- (liftIO . fmap nubOrd . mapMaybeM toInterfaceOpt) dumpPackages     unless (null interfaceOpts) $ do@@ -216,13 +207,13 @@                         or [mt > indexModTime | (_,mt,_,_) <- interfaceOpts]         if needUpdate             then do-                logInfo-                    (T.concat ["Updating Haddock index for ", descr, " in\n",-                               T.pack (toFilePath destIndexFile)])+                logInfo $+                  "Updating Haddock index for " <>+                  Stack.Prelude.display descr <>+                  " in\n" <>+                  fromString (toFilePath destIndexFile)                 liftIO (mapM_ copyPkgDocs interfaceOpts)-                readProcessNull-                    (Just destDir)-                    envOverride+                withWorkingDir (toFilePath destDir) $ readProcessNull                     (haddockExeName wc)                     (map (("--optghc=-package-db=" ++ ) . toFilePathNoTrailingSep)                         [bcoSnapDB bco, bcoLocalDB bco] ++@@ -230,9 +221,11 @@                      ["--gen-contents", "--gen-index"] ++                      [x | (xs,_,_,_) <- interfaceOpts, x <- xs])             else-              logInfo-                    (T.concat ["Haddock index for ", descr, " already up to date at:\n",-                               T.pack (toFilePath destIndexFile)])+              logInfo $+                "Haddock index for " <>+                Stack.Prelude.display descr <>+                " already up to date at:\n" <>+                fromString (toFilePath destIndexFile)   where     toInterfaceOpt :: DumpPackage a b c -> IO (Maybe ([String], UTCTime, Path Abs File, Path Abs File))     toInterfaceOpt DumpPackage {..} =
src/Stack/Build/Installed.hs view
@@ -18,7 +18,6 @@ import           Data.List import qualified Data.Map.Strict as M import qualified Data.Map.Strict as Map-import qualified Data.Text as T import           Path import           Stack.Build.Cache import           Stack.Constants@@ -33,7 +32,6 @@ import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version-import           System.Process.Read (EnvOverride)  -- | Options for 'getInstalled'. data GetInstalledOpts = GetInstalledOpts@@ -47,8 +45,7 @@  -- | Returns the new InstalledMap and all of the locally registered packages. getInstalled :: HasEnvConfig env-             => EnvOverride-             -> GetInstalledOpts+             => GetInstalledOpts              -> Map PackageName PackageSource -- ^ does not contain any installed information              -> RIO env                   ( InstalledMap@@ -56,7 +53,7 @@                   , [DumpPackage () () ()] -- snapshot installed                   , [DumpPackage () () ()] -- locally installed                   )-getInstalled menv opts sourceMap = do+getInstalled opts sourceMap = do     logDebug "Finding out which packages are already installed"     snapDBPath <- packageDatabaseDeps     localDBPath <- packageDatabaseLocal@@ -67,7 +64,7 @@             then configInstalledCache >>= liftM Just . loadInstalledCache             else return Nothing -    let loadDatabase' = loadDatabase menv opts mcache sourceMap+    let loadDatabase' = loadDatabase opts mcache sourceMap      (installedLibs0, globalDumpPkgs) <- loadDatabase' Nothing []     (installedLibs1, _extraInstalled) <-@@ -118,17 +115,16 @@ -- that it has profiling if necessary, and that it matches the version and -- location needed by the SourceMap loadDatabase :: HasEnvConfig env-             => EnvOverride-             -> GetInstalledOpts+             => GetInstalledOpts              -> Maybe InstalledCache -- ^ if Just, profiling or haddock is required              -> Map PackageName PackageSource -- ^ to determine which installed things we should include              -> Maybe (InstalledPackageLocation, Path Abs Dir) -- ^ package database, Nothing for global              -> [LoadHelper] -- ^ from parent databases              -> RIO env ([LoadHelper], [DumpPackage () () ()])-loadDatabase menv opts mcache sourceMap mdb lhs0 = do+loadDatabase opts mcache sourceMap mdb lhs0 = do     wc <- view $ actualCompilerVersionL.to whichCompiler-    (lhs1', dps) <- ghcPkgDump menv wc (fmap snd (maybeToList mdb))-                $ conduitDumpPackage =$ sink+    (lhs1', dps) <- ghcPkgDump wc (fmap snd (maybeToList mdb))+                $ conduitDumpPackage .| sink     let ghcjsHack = wc == Ghcjs && isNothing mdb     lhs1 <- mapMaybeM (processLoadResult mdb ghcjsHack) lhs1'     let lhs = pruneDeps@@ -159,54 +155,50 @@             _ -> CL.map (\dp -> dp { dpSymbols = False })     mloc = fmap fst mdb     sinkDP = conduitProfilingCache-           =$ conduitHaddockCache-           =$ conduitSymbolsCache-           =$ CL.map (isAllowed opts mcache sourceMap mloc &&& toLoadHelper mloc)-           =$ CL.consume+           .| conduitHaddockCache+           .| conduitSymbolsCache+           .| CL.map (isAllowed opts mcache sourceMap mloc &&& toLoadHelper mloc)+           .| CL.consume     sink = getZipSink $ (,)         <$> ZipSink sinkDP         <*> ZipSink CL.consume -processLoadResult :: MonadLogger m+processLoadResult :: HasLogFunc env                   => Maybe (InstalledPackageLocation, Path Abs Dir)                   -> Bool                   -> (Allowed, LoadHelper)-                  -> m (Maybe LoadHelper)+                  -> RIO env (Maybe LoadHelper) processLoadResult _ _ (Allowed, lh) = return (Just lh) processLoadResult _ True (WrongVersion actual wanted, lh)     -- Allow some packages in the ghcjs global DB to have the wrong     -- versions.  Treat them as wired-ins by setting deps to [].     | fst (lhPair lh) `HashSet.member` ghcjsBootPackages = do-        logWarn $ T.concat-            [ "Ignoring that the GHCJS boot package \""-            , packageNameText (fst (lhPair lh))-            , "\" has a different version, "-            , versionText actual-            , ", than the resolver's wanted version, "-            , versionText wanted-            ]+        logWarn $+            "Ignoring that the GHCJS boot package \"" <>+            display (packageNameText (fst (lhPair lh))) <>+            "\" has a different version, " <>+            display (versionText actual) <>+            ", than the resolver's wanted version, " <>+            display (versionText wanted)         return (Just lh) processLoadResult mdb _ (reason, lh) = do-    logDebug $ T.concat $-        [ "Ignoring package "-        , packageNameText (fst (lhPair lh))-        ] ++-        maybe [] (\db -> [", from ", T.pack (show db), ","]) mdb ++-        [ " due to"-        , case reason of+    logDebug $+        "Ignoring package " <>+        display (packageNameText (fst (lhPair lh))) <>+        maybe mempty (\db -> ", from " <> displayShow db <> ",") mdb <>+        " due to" <>+        case reason of             Allowed -> " the impossible?!?!"             NeedsProfiling -> " it needing profiling."             NeedsHaddock -> " it needing haddocks."             NeedsSymbols -> " it needing debugging symbols."             UnknownPkg -> " it being unknown to the resolver / extra-deps."-            WrongLocation mloc loc -> " wrong location: " <> T.pack (show (mloc, loc))-            WrongVersion actual wanted -> T.concat-                [ " wanting version "-                , versionText wanted-                , " instead of "-                , versionText actual-                ]-        ]+            WrongLocation mloc loc -> " wrong location: " <> displayShow (mloc, loc)+            WrongVersion actual wanted ->+                " wanting version " <>+                display (versionText wanted) <>+                " instead of " <>+                display (versionText actual)     return Nothing  data Allowed@@ -238,25 +230,37 @@     | otherwise =         case Map.lookup name sourceMap of             Nothing ->-                case mloc of-                    -- The sourceMap has nothing to say about this global-                    -- package, so we can use it-                    Nothing -> Allowed-                    Just ExtraGlobal -> Allowed-                    -- For non-global packages, don't include unknown packages.-                    -- See:-                    -- https://github.com/commercialhaskell/stack/issues/292-                    Just _ -> UnknownPkg-            Just pii-                | not (checkLocation (piiLocation pii)) -> WrongLocation mloc (piiLocation pii)-                | version /= piiVersion pii -> WrongVersion version (piiVersion pii)-                | otherwise -> Allowed+                -- If the sourceMap has nothing to say about this package,+                -- check if it represents a sublibrary first+                -- See: https://github.com/commercialhaskell/stack/issues/3899+                case dpParentLibIdent dp of+                  Just (PackageIdentifier parentLibName version') ->+                    case Map.lookup parentLibName sourceMap of+                      Nothing -> checkNotFound+                      Just pii+                        | version' == version -> checkFound pii+                        | otherwise -> checkNotFound -- different versions+                  Nothing -> checkNotFound+            Just pii -> checkFound pii   where     PackageIdentifier name version = dpPackageIdent dp     -- Ensure that the installed location matches where the sourceMap says it     -- should be installed     checkLocation Snap = mloc /= Just (InstalledTo Local) -- we can allow either global or snap     checkLocation Local = mloc == Just (InstalledTo Local) || mloc == Just ExtraGlobal -- 'locally' installed snapshot packages can come from extra dbs+    -- Check if a package is allowed if it is found in the sourceMap+    checkFound pii+      | not (checkLocation (piiLocation pii)) = WrongLocation mloc (piiLocation pii)+      | version /= piiVersion pii = WrongVersion version (piiVersion pii)+      | otherwise = Allowed+    -- check if a package is allowed if it is not found in the sourceMap+    checkNotFound = case mloc of+      -- The sourceMap has nothing to say about this global package, so we can use it+      Nothing -> Allowed+      Just ExtraGlobal -> Allowed+      -- For non-global packages, don't include unknown packages.+      -- See: https://github.com/commercialhaskell/stack/issues/292+      Just _ -> UnknownPkg  data LoadHelper = LoadHelper     { lhId   :: !GhcPkgId@@ -278,7 +282,7 @@         if name `HashSet.member` wiredInPackages             then []             else dpDepends dp-    , lhPair = (name, (toPackageLocation mloc, Library ident gid (dpLicense dp)))+    , lhPair = (name, (toPackageLocation mloc, Library ident gid (Right <$> dpLicense dp)))     }   where     gid = dpGhcPkgId dp
src/Stack/Build/Source.hs view
@@ -20,8 +20,7 @@ import              Crypto.Hash.Conduit (sinkHash) import qualified    Data.ByteArray as Mem (convert) import qualified    Data.ByteString as S-import              Data.Conduit (($$), ZipSink (..))-import qualified    Data.Conduit.Binary as CB+import              Data.Conduit (ZipSink (..)) import qualified    Data.Conduit.List as CL import qualified    Data.HashSet as HashSet import              Data.List@@ -38,6 +37,7 @@ import              Stack.Types.BuildPlan import              Stack.Types.Config import              Stack.Types.FlagName+import              Stack.Types.NamedComponent import              Stack.Types.Package import              Stack.Types.PackageName import qualified    System.Directory as D@@ -167,6 +167,7 @@   where     go a b c [] = (Set.fromList $ a [], Set.fromList $ b [], Set.fromList $ c [])     go a b c (CLib:xs) = go a b c xs+    go a b c (CInternalLib x:xs) = go (a . (x:)) b c xs     go a b c (CExe x:xs) = go (a . (x:)) b c xs     go a b c (CTest x:xs) = go a (b . (x:)) c xs     go a b c (CBench x:xs) = go a b (c . (x:)) xs@@ -421,9 +422,7 @@             Nothing -> return Map.empty             Just modTime' ->                 if modTime' < preBuildTime-                    then do-                        newFci <- calcFci modTime' fp-                        return (Map.singleton fp newFci)+                    then Map.singleton fp <$> calcFci modTime' fp                     else return Map.empty  -- | Gets list of Paths for files relevant to a set of components in a package.@@ -436,9 +435,9 @@     -> Set NamedComponent     -> RIO env (Map NamedComponent (Set (Path Abs File)), [PackageWarning]) getPackageFilesForTargets pkg cabalFP nonLibComponents = do-    (_,compFiles,otherFiles,warnings) <-+    (components',compFiles,otherFiles,warnings) <-         getPackageFiles (packageFiles pkg) cabalFP-    let components = Set.insert CLib nonLibComponents+    let components = M.keysSet components' `Set.union` nonLibComponents         componentsFiles =             M.map (\files -> Set.union otherFiles (Set.map dotCabalGetPath files)) $                 M.filterWithKey (\component _ -> component `Set.member` components) compFiles@@ -460,8 +459,8 @@ -- | Create FileCacheInfo for a file. calcFci :: MonadIO m => ModTime -> FilePath -> m FileCacheInfo calcFci modTime' fp = liftIO $-    withBinaryFile fp ReadMode $ \h -> do-        (size, digest) <- CB.sourceHandle h $$ getZipSink+    withSourceFile fp $ \src -> do+        (size, digest) <- runConduit $ src .| getZipSink             ((,)                 <$> ZipSink (CL.fold                     (\x y -> x + fromIntegral (S.length y))
src/Stack/Build/Target.hs view
@@ -79,11 +79,11 @@ import           Path.Extra (rejectMissingDir) import           Path.IO import           Stack.Config (getLocalPackages)-import           Stack.Fetch (withCabalLoader) import           Stack.PackageIndex import           Stack.PackageLocation import           Stack.Snapshot (calculatePackagePromotion) import           Stack.Types.Config+import           Stack.Types.NamedComponent import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version@@ -230,6 +230,7 @@     -- Helper function: check if a 'NamedComponent' matches the given 'ComponentName'     isCompNamed :: ComponentName -> NamedComponent -> Bool     isCompNamed _ CLib = False+    isCompNamed t1 (CInternalLib t2) = t1 == t2     isCompNamed t1 (CExe t2) = t1 == t2     isCompNamed t1 (CTest t2) = t1 == t2     isCompNamed t1 (CBench t2) = t1 == t2@@ -340,9 +341,8 @@               , rrPackageType = Dependency               }       where-        getLatestVersion pn = do-            vs <- getPackageVersions pn-            return (fmap fst (Set.maxView vs))+        getLatestVersion pn =+            fmap fst . Set.maxView <$> getPackageVersions pn      go (RTPackageIdentifier ident@(PackageIdentifier name version))       | Map.member name locals = return $ Left $ T.concat@@ -413,9 +413,9 @@   deriving (Eq, Show)  combineResolveResults-  :: forall m. MonadLogger m+  :: forall env. HasLogFunc env   => [ResolveResult]-  -> m ([Text], Map PackageName Target, Map PackageName (PackageLocationIndex FilePath))+  -> RIO env ([Text], Map PackageName Target, Map PackageName (PackageLocationIndex FilePath)) combineResolveResults results = do     addedDeps <- fmap Map.unions $ forM results $ \result ->       case rrAddedDep result of@@ -509,9 +509,9 @@        drops = Set.empty -- not supported to add drops -  (globals', snapshots, locals') <- withCabalLoader $ \loadFromIndex -> do+  (globals', snapshots, locals') <- do     addedDeps' <- fmap Map.fromList $ forM (Map.toList addedDeps) $ \(name, loc) -> do-      gpd <- parseSingleCabalFileIndex loadFromIndex root loc+      gpd <- parseSingleCabalFileIndex root loc       return (name, (gpd, loc, Nothing))      -- Calculate a list of all of the locals, based on the project@@ -532,7 +532,7 @@           ]      calculatePackagePromotion-      loadFromIndex root ls0 (Map.elems allLocals)+      root ls0 (Map.elems allLocals)       flags hides options drops    let ls = LoadedSnapshot
src/Stack/BuildPlan.hs view
@@ -24,7 +24,7 @@     , showItems     ) where -import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import qualified Data.Foldable as F import qualified Data.HashSet as HashSet import           Data.List (intercalate)@@ -43,11 +43,13 @@ import           Distribution.System (Platform) import           Distribution.Text (display) import qualified Distribution.Version as C+import qualified RIO import           Stack.Constants import           Stack.Package import           Stack.Snapshot import           Stack.Types.BuildPlan import           Stack.Types.FlagName+import           Stack.Types.NamedComponent import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version@@ -428,9 +430,9 @@     -> RIO env (SnapshotDef, BuildPlanCheck) selectBestSnapshot root gpds snaps = do     logInfo $ "Selecting the best among "-               <> T.pack (show (NonEmpty.length snaps))+               <> displayShow (NonEmpty.length snaps)                <> " snapshots...\n"-    F.foldr1 go (NonEmpty.map (getResult <=< loadResolver . ResolverSnapshot) snaps)+    F.foldr1 go (NonEmpty.map (getResult <=< loadResolver . ResolverStackage) snaps)     where         go mold mnew = do             old@(_snap, bpc) <- mold@@ -440,7 +442,7 @@          getResult snap = do             result <- checkSnapBuildPlan root gpds Nothing snap-              -- We know that we're only dealing with ResolverSnapshot+              -- We know that we're only dealing with ResolverStackage               -- here, where we can rely on the global package hints.               -- Therefore, we don't use an actual compiler. For more               -- info, see comments on@@ -454,16 +456,16 @@           | otherwise = (s2, r2)          reportResult BuildPlanCheckOk {} snap = do-            logInfo $ "* Matches " <> sdResolverName snap+            logInfo $ "* Matches " <> RIO.display (sdResolverName snap)             logInfo ""          reportResult r@BuildPlanCheckPartial {} snap = do-            logWarn $ "* Partially matches " <> sdResolverName snap-            logWarn $ indent $ T.pack $ show r+            logWarn $ "* Partially matches " <> RIO.display (sdResolverName snap)+            logWarn $ RIO.display $ indent $ T.pack $ show r          reportResult r@BuildPlanCheckFail {} snap = do-            logWarn $ "* Rejected " <> sdResolverName snap-            logWarn $ indent $ T.pack $ show r+            logWarn $ "* Rejected " <> RIO.display (sdResolverName snap)+            logWarn $ RIO.display $ indent $ T.pack $ show r          indent t = T.unlines $ fmap ("    " <>) (T.lines t) 
src/Stack/Clean.hs view
@@ -14,7 +14,6 @@ import           Stack.Prelude import           Data.List ((\\),intercalate) import qualified Data.Map.Strict as Map-import qualified Data.Text as T import           Path.IO (ignoringAbsence, removeDirRecur) import           Stack.Config (getLocalPackages) import           Stack.Constants.Config (distDirFromDir, workDirFromDir)@@ -32,7 +31,7 @@   where     cleanDir dir =       liftIO (ignoringAbsence (removeDirRecur dir) >> return False) `catchAny` \ex -> do-        logError $ "Exception while recursively deleting " <> T.pack (toFilePath dir) <> "\n" <> T.pack (show ex)+        logError $ "Exception while recursively deleting " <> fromString (toFilePath dir) <> "\n" <> displayShow ex         logError "Perhaps you do not have permission to delete these files or they are in use?"         return True 
src/Stack/Config.hs view
@@ -61,9 +61,10 @@ import qualified Distribution.Text import           Distribution.Version (simplifyVersionRange, mkVersion') import           GHC.Conc (getNumProcessors)-import           Lens.Micro (lens)+import           Lens.Micro (lens, set) import           Network.HTTP.Client (parseUrlThrow)-import           Network.HTTP.Simple (httpJSON, getResponseBody)+import           Network.HTTP.StackClient (httpJSON)+import           Network.HTTP.Simple (getResponseBody) import           Options.Applicative (Parser, strOption, long, help) import           Path import           Path.Extra (toFilePathNoTrailingSep)@@ -75,9 +76,9 @@ import           Stack.Config.Nix import           Stack.Config.Urls import           Stack.Constants-import           Stack.Fetch import qualified Stack.Image as Image import           Stack.PackageLocation+import           Stack.PackageIndex (CabalLoader (..), HasCabalLoader (..)) import           Stack.Snapshot import           Stack.Types.BuildPlan import           Stack.Types.Compiler@@ -94,17 +95,17 @@ import           System.Environment import           System.PosixCompat.Files (fileOwner, getFileStatus) import           System.PosixCompat.User (getEffectiveUserID)-import           System.Process.Read+import           RIO.Process  -- | If deprecated path exists, use it and print a warning. -- Otherwise, return the new path. tryDeprecatedPath-    :: (MonadIO m, MonadLogger m)+    :: HasLogFunc env     => Maybe T.Text -- ^ Description of file for warning (if Nothing, no deprecation warning is displayed)-    -> (Path Abs a -> m Bool) -- ^ Test for existence+    -> (Path Abs a -> RIO env Bool) -- ^ Test for existence     -> Path Abs a -- ^ New path     -> Path Abs a -- ^ Deprecated path-    -> m (Path Abs a, Bool) -- ^ (Path to use, whether it already exists)+    -> RIO env (Path Abs a, Bool) -- ^ (Path to use, whether it already exists) tryDeprecatedPath mWarningDesc exists new old = do     newExists <- exists new     if newExists@@ -116,12 +117,12 @@                     case mWarningDesc of                         Nothing -> return ()                         Just desc ->-                            logWarn $ T.concat-                                [ "Warning: Location of ", desc, " at '"-                                , T.pack (toFilePath old)-                                , "' is deprecated; rename it to '"-                                , T.pack (toFilePath new)-                                , "' instead" ]+                            logWarn $+                                "Warning: Location of " <> display desc <> " at '" <>+                                fromString (toFilePath old) <>+                                "' is deprecated; rename it to '" <>+                                fromString (toFilePath new) <>+                                "' instead"                     return (old, True)                 else return (new, False) @@ -129,8 +130,8 @@ -- If the directory already exists at the deprecated location, its location is returned. -- Otherwise, the new location is returned. getImplicitGlobalProjectDir-    :: (MonadIO m, MonadLogger m)-    => Config -> m (Path Abs Dir)+    :: HasLogFunc env+    => Config -> RIO env (Path Abs Dir) getImplicitGlobalProjectDir config =     --TEST no warning printed     liftM fst $ tryDeprecatedPath@@ -139,7 +140,7 @@         (implicitGlobalProjectDir stackRoot)         (implicitGlobalProjectDirDeprecated stackRoot)   where-    stackRoot = configStackRoot config+    stackRoot = view stackRootL config  -- | This is slightly more expensive than @'asks' ('bcStackYaml' '.' 'getBuildConfig')@ -- and should only be used when no 'BuildConfig' is at hand.@@ -155,7 +156,7 @@ getSnapshots = do     latestUrlText <- askLatestSnapshotUrl     latestUrl <- parseUrlThrow (T.unpack latestUrlText)-    logDebug $ "Downloading snapshot versions file from " <> latestUrlText+    logDebug $ "Downloading snapshot versions file from " <> display latestUrlText     result <- httpJSON latestUrl     logDebug "Done downloading and parsing snapshot versions file"     return $ getResponseBody result@@ -179,17 +180,17 @@                 ProjectAndConfigMonoid project _ <-                     loadConfigYaml (parseProjectAndConfigMonoid (parent fp)) fp                 return $ projectResolver project-            ARLatestNightly -> return $ ResolverSnapshot $ Nightly $ snapshotsNightly snapshots+            ARLatestNightly -> return $ ResolverStackage $ Nightly $ snapshotsNightly snapshots             ARLatestLTSMajor x ->                 case IntMap.lookup x $ snapshotsLts snapshots of                     Nothing -> throwString $ "No LTS release found with major version " ++ show x-                    Just y -> return $ ResolverSnapshot $ LTS x y+                    Just y -> return $ ResolverStackage $ LTS x y             ARLatestLTS                 | IntMap.null $ snapshotsLts snapshots -> throwString "No LTS releases found"                 | otherwise ->                     let (x, y) = IntMap.findMax $ snapshotsLts snapshots-                     in return $ ResolverSnapshot $ LTS x y-    logInfo $ "Selected resolver: " <> resolverRawName r+                     in return $ ResolverStackage $ LTS x y+    logInfo $ "Selected resolver: " <> display (resolverRawName r)     return r  -- | Get the latest snapshot resolver available.@@ -200,16 +201,16 @@             (x,y) <- listToMaybe (reverse (IntMap.toList (snapshotsLts snapshots)))             return (LTS x y)         snap = fromMaybe (Nightly (snapshotsNightly snapshots)) mlts-    return (ResolverSnapshot snap)+    return (ResolverStackage snap)  -- | Create a 'Config' value when we're not using any local -- configuration files (e.g., the script command) configNoLocalConfig-    :: (MonadLogger m, MonadUnliftIO m, MonadThrow m, MonadReader env m, HasRunner env)+    :: HasRunner env     => Path Abs Dir -- ^ stack root     -> Maybe AbstractResolver     -> ConfigMonoid-    -> m Config+    -> RIO env Config configNoLocalConfig _ Nothing _ = throwIO NoResolverWhenUsingNoLocalConfig configNoLocalConfig stackRoot (Just resolver) configMonoid = do     userConfigPath <- liftIO $ getFakeConfigPath stackRoot resolver@@ -223,16 +224,16 @@  -- Interprets ConfigMonoid options. configFromConfigMonoid-    :: (MonadLogger m, MonadUnliftIO m, MonadThrow m, MonadReader env m, HasRunner env)+    :: HasRunner env     => Path Abs Dir -- ^ stack root, e.g. ~/.stack     -> Path Abs File -- ^ user config file path, e.g. ~/.stack/config.yaml     -> Bool -- ^ allow locals?     -> Maybe AbstractResolver     -> Maybe (Project, Path Abs File)     -> ConfigMonoid-    -> m Config+    -> RIO env Config configFromConfigMonoid-    configStackRoot configUserConfigPath configAllowLocals mresolver+    clStackRoot configUserConfigPath configAllowLocals mresolver     mproject ConfigMonoid{..} = do      -- If --stack-work is passed, prefer it. Otherwise, if STACK_WORK      -- is set, use that. If neither, use the default ".stack-work"@@ -245,9 +246,9 @@              logWarn "The latest-snapshot-url field is deprecated in favor of 'urls' configuration"              return (urlsFromMonoid configMonoidUrls) { urlsLatestSnapshot = url }          _ -> return (urlsFromMonoid configMonoidUrls)-     let configConnectionCount = fromFirst 8 configMonoidConnectionCount+     let clConnectionCount = fromFirst 8 configMonoidConnectionCount          configHideTHLoading = fromFirst True configMonoidHideTHLoading-         configPackageIndices = fromFirst+         clIndices = fromFirst             [PackageIndex                 { indexName = IndexName "Hackage"                 , indexLocation = "https://s3.amazonaws.com/hackage.fpcomplete.com/"@@ -280,7 +281,7 @@          configExtraLibDirs = configMonoidExtraLibDirs          configOverrideGccPath = getFirst configMonoidOverrideGccPath          configOverrideHpack = maybe HpackBundled HpackCommand $ getFirst configMonoidOverrideHpack-         +          -- Only place in the codebase where platform is hard-coded. In theory          -- in the future, allow it to be configured.          (Platform defArch defOS) = buildPlatform@@ -296,7 +297,8 @@          configCompilerCheck = fromFirst MatchMinor configMonoidCompilerCheck       case arch of-         OtherArch unk -> logWarn $ "Warning: Unknown value for architecture setting: " <> T.pack (show unk)+         OtherArch "aarch64" -> return ()+         OtherArch unk -> logWarn $ "Warning: Unknown value for architecture setting: " <> displayShow unk          _ -> return ()       configPlatformVariant <- liftIO $@@ -304,7 +306,7 @@       let configBuild = buildOptsFromMonoid configMonoidBuildOpts      configDocker <--         dockerOptsFromMonoid (fmap fst mproject) configStackRoot mresolver configMonoidDockerOpts+         dockerOptsFromMonoid (fmap fst mproject) clStackRoot mresolver configMonoidDockerOpts      configNix <- nixOptsFromMonoid configMonoidNixOpts os       configSystemGHC <-@@ -321,13 +323,14 @@          throwM ManualGHCVariantSettingsAreIncompatibleWithSystemGHC       rawEnv <- liftIO getEnvironment-     pathsEnv <- augmentPathMap configMonoidExtraPath+     pathsEnv <- either throwM return+               $ augmentPathMap (map toFilePath configMonoidExtraPath)                                 (Map.fromList (map (T.pack *** T.pack) rawEnv))-     origEnv <- mkEnvOverride configPlatform pathsEnv-     let configEnvOverride _ = return origEnv+     origEnv <- mkProcessContext pathsEnv+     let configProcessContextSettings _ = return origEnv       configLocalProgramsBase <- case getFirst configMonoidLocalProgramsBase of-       Nothing -> getDefaultLocalProgramsBase configStackRoot configPlatform origEnv+       Nothing -> getDefaultLocalProgramsBase clStackRoot configPlatform origEnv        Just path -> return path      platformOnlyDir <- runReaderT platformOnlyRelDir (configPlatform, configPlatformVariant)      let configLocalPrograms = configLocalProgramsBase </> platformOnlyDir@@ -369,26 +372,30 @@          configDefaultTemplate = getFirst configMonoidDefaultTemplate          configDumpLogs = fromFirst DumpWarningLogs configMonoidDumpLogs          configSaveHackageCreds = fromFirst True configMonoidSaveHackageCreds-         configIgnoreRevisionMismatch = fromFirst False configMonoidIgnoreRevisionMismatch+         clIgnoreRevisionMismatch = fromFirst False configMonoidIgnoreRevisionMismatch       configAllowDifferentUser <-         case getFirst configMonoidAllowDifferentUser of             Just True -> return True             _ -> getInContainer -     configPackageCache <- liftIO $ newIORef Nothing-      let configMaybeProject = mproject -     configRunner <- view runnerL+     configRunner' <- view runnerL +     clCache <- newIORef Nothing+     clUpdateRef <- newMVar True++     let configRunner = set processContextL origEnv configRunner'+         configCabalLoader = CabalLoader {..}+      return Config {..}  -- | Get the default location of the local programs directory. getDefaultLocalProgramsBase :: MonadThrow m                             => Path Abs Dir                             -> Platform-                            -> EnvOverride+                            -> ProcessContext                             -> m (Path Abs Dir) getDefaultLocalProgramsBase configStackRoot configPlatform override =   let@@ -400,7 +407,7 @@       -- mean that Windows users would manually have to move data from the old       -- location to the new one, which is undesirable.       Platform _ Windows ->-        case Map.lookup "LOCALAPPDATA" $ unEnvOverride override of+        case Map.lookup "LOCALAPPDATA" $ view envVarsL override of           Just t ->             case parseAbsDir $ T.unpack t of               Nothing -> throwM $ stringException ("Failed to parse LOCALAPPDATA environment variable (expected absolute directory): " ++ show t)@@ -415,6 +422,10 @@     } instance HasConfig MiniConfig where     configL = lens mcConfig (\x y -> x { mcConfig = y })+instance HasProcessContext MiniConfig where+    processContextL = configL.processContextL+instance HasCabalLoader MiniConfig where+    cabalLoaderL = configL.cabalLoaderL instance HasPlatform MiniConfig instance HasGHCVariant MiniConfig where     ghcVariantL = lens mcGHCVariant (\x y -> x { mcGHCVariant = y })@@ -532,7 +543,7 @@               ARLatestLTS -> "lts"               ARLatestLTSMajor x -> T.pack $ "lts-" ++ show x               ARGlobal -> "global"-      logDebug ("Using resolver: " <> name <> " specified on command line")+      logDebug ("Using resolver: " <> display name <> " specified on command line")        -- In order to resolve custom snapshots, we need a base       -- directory to deal with relative paths. For the case of@@ -550,7 +561,7 @@      (project', stackYamlFP) <- case mproject of       LCSProject (project, fp, _) -> do-          forM_ (projectUserMsg project) (logWarn . T.pack)+          forM_ (projectUserMsg project) (logWarn . fromString)           return (project, fp)       LCSNoConfig _ -> do           p <- assert (isJust mresolver) (getEmptyProject mresolver)@@ -570,12 +581,15 @@                    when (view terminalL config) $                        case maresolver of                            Nothing ->-                               logDebug ("Using resolver: " <> resolverRawName (projectResolver project) <>-                                         " from implicit global project's config file: " <> T.pack dest')+                               logDebug $+                                 "Using resolver: " <>+                                 display (resolverRawName (projectResolver project)) <>+                                 " from implicit global project's config file: " <>+                                 fromString dest'                            Just _ -> return ()                    return (project, dest)                else do-                   logInfo ("Writing implicit global project config file to: " <> T.pack dest')+                   logInfo ("Writing implicit global project config file to: " <> fromString dest')                    logInfo "Note: You can change the snapshot via the resolver field there."                    p <- getEmptyProject mresolver                    liftIO $ do@@ -623,11 +637,11 @@     getEmptyProject mresolver = do       r <- case mresolver of             Just resolver -> do-                logInfo ("Using resolver: " <> resolverRawName resolver <> " specified on command line")+                logInfo ("Using resolver: " <> display (resolverRawName resolver) <> " specified on command line")                 return resolver             Nothing -> do                 r'' <- getLatestResolver-                logInfo ("Using latest snapshot resolver: " <> resolverRawName r'')+                logInfo ("Using latest snapshot resolver: " <> display (resolverRawName r''))                 return r''       return Project         { projectUserMsg = Nothing@@ -640,14 +654,14 @@         }  -- | Get packages from EnvConfig, downloading and cloning as necessary.--- If the packages have already been downloaded, this uses a cached value (+-- If the packages have already been downloaded, this uses a cached value. getLocalPackages :: forall env. HasEnvConfig env => RIO env LocalPackages getLocalPackages = do     cacheRef <- view $ envConfigL.to envConfigPackagesRef     mcached <- liftIO $ readIORef cacheRef     case mcached of         Just cached -> return cached-        Nothing -> withCabalLoader $ \loadFromIndex -> do+        Nothing -> do             root <- view projectRootL             bc <- view buildConfigL @@ -661,8 +675,8 @@                               $ C.package                               $ C.packageDescription gpd                       in (name, (gpd, loc))-            deps <- (map wrapGPD . concat)-                <$> mapM (parseMultiCabalFilesIndex loadFromIndex root) (bcDependencies bc)+            deps <- map wrapGPD . concat+                <$> mapM (parseMultiCabalFilesIndex root) (bcDependencies bc)              checkDuplicateNames $               map (second (PLOther . lpvLoc)) packages ++@@ -759,12 +773,6 @@             fileStatus <- getFileStatus (toFilePath path)             user <- getEffectiveUserID             return (user == fileOwner fileStatus)-  where-#ifdef WINDOWS-    osIsWindows = True-#else-    osIsWindows = False-#endif  -- | 'True' if we are currently running inside a Docker container. getInContainer :: (MonadIO m) => m Bool@@ -777,9 +785,9 @@ -- | Determine the extra config file locations which exist. -- -- Returns most local first-getExtraConfigs :: (MonadIO m, MonadLogger m)+getExtraConfigs :: HasLogFunc env                 => Path Abs File -- ^ use config path-                -> m [Path Abs File]+                -> RIO env [Path Abs File] getExtraConfigs userConfigPath = do   defaultStackGlobalConfigPath <- getDefaultGlobalConfigPath   liftIO $ do@@ -797,8 +805,8 @@ -- | Load and parse YAML from the given config file. Throws -- 'ParseConfigFileException' when there's a decoding error. loadConfigYaml-    :: (MonadIO m, MonadLogger m)-    => (Value -> Yaml.Parser (WithJSONWarnings a)) -> Path Abs File -> m a+    :: HasLogFunc env+    => (Value -> Yaml.Parser (WithJSONWarnings a)) -> Path Abs File -> RIO env a loadConfigYaml parser path = do     eres <- loadYaml parser path     case eres of@@ -807,8 +815,8 @@  -- | Load and parse YAML from the given file. loadYaml-    :: (MonadIO m, MonadLogger m)-    => (Value -> Yaml.Parser (WithJSONWarnings a)) -> Path Abs File -> m (Either Yaml.ParseException a)+    :: HasLogFunc env+    => (Value -> Yaml.Parser (WithJSONWarnings a)) -> Path Abs File -> RIO env (Either Yaml.ParseException a) loadYaml parser path = do     eres <- liftIO $ Yaml.decodeFileEither (toFilePath path)     case eres  of@@ -821,10 +829,10 @@                     return (Right res)  -- | Get the location of the project config file, if it exists.-getProjectConfig :: (MonadIO m, MonadThrow m, MonadLogger m)+getProjectConfig :: HasLogFunc env                  => StackYamlLoc (Path Abs File)                  -- ^ Override stack.yaml-                 -> m (LocalConfigStatus (Path Abs File))+                 -> RIO env (LocalConfigStatus (Path Abs File)) getProjectConfig (SYLOverride stackYaml) = return $ LCSProject stackYaml getProjectConfig SYLDefault = do     env <- liftIO getEnvironment@@ -839,7 +847,7 @@     getStackDotYaml dir = do         let fp = dir </> stackDotYaml             fp' = toFilePath fp-        logDebug $ "Checking for project config at: " <> T.pack fp'+        logDebug $ "Checking for project config at: " <> fromString fp'         exists <- doesFileExist fp         if exists             then return $ Just fp@@ -856,17 +864,17 @@ -- | Find the project config file location, respecting environment variables -- and otherwise traversing parents. If no config is found, we supply a default -- based on current directory.-loadProjectConfig :: (MonadIO m, MonadThrow m, MonadLogger m)+loadProjectConfig :: HasLogFunc env                   => StackYamlLoc (Path Abs File)                   -- ^ Override stack.yaml-                  -> m (LocalConfigStatus (Project, Path Abs File, ConfigMonoid))+                  -> RIO env (LocalConfigStatus (Project, Path Abs File, ConfigMonoid)) loadProjectConfig mstackYaml = do     mfp <- getProjectConfig mstackYaml     case mfp of         LCSProject fp -> do             currDir <- getCurrentDir             logDebug $ "Loading project config file " <>-                        T.pack (maybe (toFilePath fp) toFilePath (stripProperPrefix currDir fp))+                        fromString (maybe (toFilePath fp) toFilePath (stripProperPrefix currDir fp))             LCSProject <$> load fp         LCSNoProject -> do             logDebug "No project config file found, using defaults."@@ -883,8 +891,8 @@ -- If a file already exists at the deprecated location, its location is returned. -- Otherwise, the new location is returned. getDefaultGlobalConfigPath-    :: (MonadIO m, MonadLogger m)-    => m (Maybe (Path Abs File))+    :: HasLogFunc env+    => RIO env (Maybe (Path Abs File)) getDefaultGlobalConfigPath =     case (defaultGlobalConfigPath, defaultGlobalConfigPathDeprecated) of         (Just new,Just old) ->@@ -901,8 +909,8 @@ -- If a file already exists at the deprecated location, its location is returned. -- Otherwise, the new location is returned. getDefaultUserConfigPath-    :: (MonadIO m, MonadLogger m)-    => Path Abs Dir -> m (Path Abs File)+    :: HasLogFunc env+    => Path Abs Dir -> RIO env (Path Abs File) getDefaultUserConfigPath stackRoot = do     (path, exists) <- tryDeprecatedPath         (Just "non-project configuration file")
src/Stack/Config/Build.hs view
@@ -50,6 +50,7 @@           (boptsPreFetch defaultBuildOpts)           buildMonoidPreFetch     , boptsKeepGoing = getFirst buildMonoidKeepGoing+    , boptsKeepTmpFiles = getFirst buildMonoidKeepTmpFiles     , boptsForceDirty = fromFirst           (boptsForceDirty defaultBuildOpts)           buildMonoidForceDirty
src/Stack/Config/Docker.hs view
@@ -41,7 +41,7 @@                         Nothing -> ""                         Just resolver ->                             case resolver of-                                ResolverSnapshot n@(LTS _ _) ->+                                ResolverStackage n@(LTS _ _) ->                                     ":" ++ T.unpack (renderSnapName n)                                 _ ->                                     impureThrow
src/Stack/Config/Nix.hs view
@@ -9,20 +9,25 @@        ) where  import Stack.Prelude+import Control.Monad.Extra (ifM) import qualified Data.Text as T+import qualified Data.Text.IO as TIO import Distribution.System (OS (..))+import Stack.Constants import Stack.Types.Version import Stack.Types.Nix import Stack.Types.Compiler+import Stack.Types.Runner+import System.Directory (doesFileExist)  -- | Interprets NixOptsMonoid options. nixOptsFromMonoid-    :: MonadUnliftIO m+    :: HasRunner env     => NixOptsMonoid     -> OS-    -> m NixOpts+    -> RIO env NixOpts nixOptsFromMonoid NixOptsMonoid{..} os = do-    let nixEnable = fromFirst (getAny nixMonoidDefaultEnable) nixMonoidEnable+    let nixEnable0 = fromFirst False nixMonoidEnable         defaultPure = case os of           OSX -> False           _ -> True@@ -32,6 +37,17 @@         nixShellOptions = fromFirst [] nixMonoidShellOptions                           ++ prefixAll (T.pack "-I") (fromFirst [] nixMonoidPath)         nixAddGCRoots   = fromFirst False nixMonoidAddGCRoots++    osIsNixOS <- isNixOS+    nixEnable <- case () of _+                                | nixEnable0 && osIsWindows -> do+                                      logInfo "Note: Disabling nix integration, since this is being run in Windows"+                                      return False+                                | not nixEnable0 && osIsNixOS -> do+                                      logInfo "Note: Enabling Nix integration, as it is required under NixOS"+                                      return True+                                | otherwise                 -> return nixEnable0+     when (not (null nixPackages) && isJust nixInitFile) $        throwIO NixCannotUseShellFileAndPackagesException     return NixOpts{..}@@ -69,3 +85,10 @@ instance Show StackNixException where   show NixCannotUseShellFileAndPackagesException =     "You cannot have packages and a shell-file filled at the same time in your nix-shell configuration."++isNixOS :: MonadIO m => m Bool+isNixOS = liftIO $ do+    let fp = "/etc/os-release"+    ifM (doesFileExist fp)+        (T.isInfixOf "ID=nixos" <$> TIO.readFile fp)+        (return False)
src/Stack/ConfigCmd.hs view
@@ -70,11 +70,11 @@         config' = HMap.insert cmdKey newValue config     if config' == config         then logInfo-                 (T.pack (toFilePath configFilePath) <>+                 (fromString (toFilePath configFilePath) <>                   " already contained the intended configuration and remains unchanged.")         else do             liftIO (S.writeFile (toFilePath configFilePath) (Yaml.encode config'))-            logInfo (T.pack (toFilePath configFilePath) <> " has been updated.")+            logInfo (fromString (toFilePath configFilePath) <> " has been updated.")  cfgCmdSetValue     :: (HasConfig env, HasGHCVariant env)@@ -85,10 +85,10 @@     -- Check that the snapshot actually exists     void $ loadResolver concreteResolver     return (Yaml.toJSON concreteResolver)-cfgCmdSetValue _ (ConfigCmdSetSystemGhc _ bool) =-    return (Yaml.Bool bool)-cfgCmdSetValue _ (ConfigCmdSetInstallGhc _ bool) =-    return (Yaml.Bool bool)+cfgCmdSetValue _ (ConfigCmdSetSystemGhc _ bool') =+    return (Yaml.Bool bool')+cfgCmdSetValue _ (ConfigCmdSetInstallGhc _ bool') =+    return (Yaml.Bool bool')  cfgCmdSetOptionName :: ConfigCmdSet -> Text cfgCmdSetOptionName (ConfigCmdSetResolver _) = "resolver"
src/Stack/Constants.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}@@ -32,6 +33,7 @@     ,minTerminalWidth     ,maxTerminalWidth     ,defaultTerminalWidth+    ,osIsWindows     )     where @@ -241,3 +243,12 @@ -- automatically detect it and when the user doesn't supply one. defaultTerminalWidth :: Int defaultTerminalWidth = 100++-- | True if using Windows OS.+osIsWindows :: Bool+osIsWindows =+#ifdef WINDOWS+  True+#else+  False+#endif
src/Stack/Constants/Config.hs view
@@ -106,7 +106,7 @@  -- | Directory for project templates. templatesDir :: Config -> Path Abs Dir-templatesDir config = configStackRoot config </> $(mkRelDir "templates")+templatesDir config = view stackRootL config </> $(mkRelDir "templates")  -- | Relative location of build artifacts. distRelativeDir :: (MonadThrow m, MonadReader env m, HasEnvConfig env)
src/Stack/Coverage.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE ScopedTypeVariables   #-} {-# LANGUAGE TemplateHaskell       #-} {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE LambdaCase            #-}@@ -17,12 +18,12 @@     , generateHpcMarkupIndex     ) where -import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy as BL import           Data.List import qualified Data.Map.Strict as Map import qualified Data.Text as T-import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import qualified Data.Text.Lazy as LT import           Path@@ -35,14 +36,15 @@ import           Stack.PrettyPrint import           Stack.Types.Compiler import           Stack.Types.Config+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Runner import           Stack.Types.Version import           System.FilePath (isPathSeparator)-import           System.Process.Read-import           Text.Hastache (htmlEscape)+import qualified RIO+import           RIO.Process import           Trace.Hpc.Tix import           Web.Browser (openBrowser) @@ -65,7 +67,7 @@         -- version that fixes https://ghc.haskell.org/trac/ghc/ticket/1853         mtix <- readTixOrLog tixSrc         case mtix of-            Nothing -> logError $ "Failed to read " <> T.pack (toFilePath tixSrc)+            Nothing -> logError $ "Failed to read " <> fromString (toFilePath tixSrc)             Just tix -> do                 liftIO $ writeTix (toFilePath tixDest) (removeExeModules tix)                 -- TODO: ideally we'd do a file move, but IIRC this can@@ -118,7 +120,7 @@             eincludeName <- findPackageFieldForBuiltPackage pkgDir (packageIdentifier package) hpcNameField             case eincludeName of                 Left err -> do-                    logError err+                    logError $ RIO.display err                     return $ Left err                 Right includeName -> return $ Right $ Just $ T.unpack includeName     forM_ tests $ \testName -> do@@ -126,7 +128,7 @@         let report = "coverage report for " <> pkgName <> "'s test-suite \"" <> testName <> "\""             reportDir = parent tixSrc         case eincludeName of-            Left err -> generateHpcErrorReport reportDir (sanitize (T.unpack err))+            Left err -> generateHpcErrorReport reportDir (RIO.display (sanitize (T.unpack err)))             -- Restrict to just the current library code, if there is a library in the package (see             -- #634 - this will likely be customizable in the future)             Right mincludeName -> do@@ -144,20 +146,18 @@     tixFileExists <- doesFileExist tixSrc     if not tixFileExists         then do-            logError $ T.concat-                 [ "Didn't find .tix for "-                 , report-                 , " - expected to find it at "-                 , T.pack (toFilePath tixSrc)-                 , "."-                 ]+            logError $+                 "Didn't find .tix for " <>+                 RIO.display report <>+                 " - expected to find it at " <>+                 fromString (toFilePath tixSrc) <>+                 "."             return Nothing-        else (`catch` \err -> do-                 let msg = show (err :: ReadProcessException)-                 logError (T.pack msg)-                 generateHpcErrorReport reportDir $ sanitize msg+        else (`catch` \(err :: ProcessException) -> do+                 logError $ displayShow err+                 generateHpcErrorReport reportDir $ RIO.display $ sanitize $ show err                  return Nothing) $-             (`onException` logError ("Error occurred while producing " <> report)) $ do+             (`onException` logError ("Error occurred while producing " <> RIO.display report)) $ do             -- Directories for .mix files.             hpcRelDir <- hpcRelativeDir             -- Compute arguments used for both "hpc markup" and "hpc report".@@ -167,42 +167,42 @@                     concatMap (\x -> ["--srcdir", toFilePathNoTrailingSep x]) pkgDirs ++                     -- Look for index files in the correct dir (relative to each pkgdir).                     ["--hpcdir", toFilePathNoTrailingSep hpcRelDir, "--reset-hpcdirs"]-            menv <- getMinimalEnvOverride-            logInfo $ "Generating " <> report-            outputLines <- liftM (map (S8.filter (/= '\r')) . S8.lines) $-                readProcessStdout Nothing menv "hpc"+            logInfo $ "Generating " <> RIO.display report+            outputLines <- liftM (map (S8.filter (/= '\r')) . S8.lines . BL.toStrict) $+                proc "hpc"                 ( "report"                 : toFilePath tixSrc                 : (args ++ extraReportArgs)                 )+                readProcessStdout_             if all ("(0/0)" `S8.isSuffixOf`) outputLines                 then do-                    let msg html = T.concat-                            [ "Error: The "-                            , report-                            , " did not consider any code. One possible cause of this is"-                            , " if your test-suite builds the library code (see stack "-                            , if html then "<a href='https://github.com/commercialhaskell/stack/issues/1008'>" else ""-                            , "issue #1008"-                            , if html then "</a>" else ""-                            , "). It may also indicate a bug in stack or"-                            , " the hpc program. Please report this issue if you think"-                            , " your coverage report should have meaningful results."-                            ]+                    let msg html =+                            "Error: The " <>+                            RIO.display report <>+                            " did not consider any code. One possible cause of this is" <>+                            " if your test-suite builds the library code (see stack " <>+                            (if html then "<a href='https://github.com/commercialhaskell/stack/issues/1008'>" else "") <>+                            "issue #1008" <>+                            (if html then "</a>" else "") <>+                            "). It may also indicate a bug in stack or" <>+                            " the hpc program. Please report this issue if you think" <>+                            " your coverage report should have meaningful results."                     logError (msg False)                     generateHpcErrorReport reportDir (msg True)                     return Nothing                 else do                     let reportPath = reportDir </> $(mkRelFile "hpc_index.html")                     -- Print output, stripping @\r@ characters because Windows.-                    forM_ outputLines (logInfo . T.decodeUtf8)+                    forM_ outputLines (logInfo . displayBytesUtf8)                     -- Generate the markup.-                    void $ readProcessStdout Nothing menv "hpc"+                    void $ proc "hpc"                         ( "markup"                         : toFilePath tixSrc                         : ("--destdir=" ++ toFilePathNoTrailingSep reportDir)                         : (args ++ extraMarkupArgs)                         )+                        readProcessStdout_                     return (Just reportPath)  data HpcReportOpts = HpcReportOpts@@ -223,7 +223,7 @@          then return []          else do              when (hroptsAll opts && not (null targetNames)) $-                 logWarn $ "Since --all is used, it is redundant to specify these targets: " <> T.pack (show targetNames)+                 logWarn $ "Since --all is used, it is redundant to specify these targets: " <> displayShow targetNames              (_,_,targets) <- parseTargets                  AllowNoTargets                  defaultBuildOptsCLI@@ -287,12 +287,11 @@     let tixFiles = tixFiles0  ++ extraTixFiles         reportDir = outputDir </> $(mkRelDir "combined/all")     if length tixFiles < 2-        then logInfo $ T.concat-            [ if null tixFiles then "No tix files" else "Only one tix file"-            , " found in "-            , T.pack (toFilePath outputDir)-            , ", so not generating a unified coverage report."-            ]+        then logInfo $+            (if null tixFiles then "No tix files" else "Only one tix file") <>+            " found in " <>+            fromString (toFilePath outputDir) <>+            ", so not generating a unified coverage report."         else do             let report = "unified report"             mreportPath <- generateUnionReport report reportDir tixFiles@@ -303,22 +302,24 @@                     -> RIO env (Maybe (Path Abs File)) generateUnionReport report reportDir tixFiles = do     (errs, tix) <- fmap (unionTixes . map removeExeModules) (mapMaybeM readTixOrLog tixFiles)-    logDebug $ "Using the following tix files: " <> T.pack (show tixFiles)-    unless (null errs) $ logWarn $ T.concat $-        "The following modules are left out of the " : report : " due to version mismatches: " :-        intersperse ", " (map T.pack errs)+    logDebug $ "Using the following tix files: " <> fromString (show tixFiles)+    unless (null errs) $ logWarn $+        "The following modules are left out of the " <>+        RIO.display report <>+        " due to version mismatches: " <>+        mconcat (intersperse ", " (map fromString errs))     tixDest <- liftM (reportDir </>) $ parseRelFile (dirnameString reportDir ++ ".tix")     ensureDir (parent tixDest)     liftIO $ writeTix (toFilePath tixDest) tix     generateHpcReportInternal tixDest reportDir report [] [] -readTixOrLog :: (MonadLogger m, MonadUnliftIO m) => Path b File -> m (Maybe Tix)+readTixOrLog :: HasLogFunc env => Path b File -> RIO env (Maybe Tix) readTixOrLog path = do     mtix <- liftIO (readTix (toFilePath path)) `catchAny` \errorCall -> do-        logError $ "Error while reading tix: " <> T.pack (show errorCall)+        logError $ "Error while reading tix: " <> fromString (show errorCall)         return Nothing     when (isNothing mtix) $-        logError $ "Failed to read tix file " <> T.pack (toFilePath path)+        logError $ "Failed to read tix file " <> fromString (toFilePath path)     return mtix  -- | Module names which contain '/' have a package name, and so they weren't built into the@@ -387,23 +388,35 @@         ["</body></html>"]     unless (null rows) $         logInfo $ "\nAn index of the generated HTML coverage reports is available at " <>-            T.pack (toFilePath outputFile)+            fromString (toFilePath outputFile) -generateHpcErrorReport :: MonadIO m => Path Abs Dir -> Text -> m ()+generateHpcErrorReport :: MonadIO m => Path Abs Dir -> Utf8Builder -> m () generateHpcErrorReport dir err = do     ensureDir dir-    liftIO $ T.writeFile (toFilePath (dir </> $(mkRelFile "hpc_index.html"))) $ T.concat-        [ "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body>"-        , "<h1>HPC Report Generation Error</h1>"-        , "<p>"-        , err-        , "</p>"-        , "</body></html>"-        ]+    let fp = toFilePath (dir </> $(mkRelFile "hpc_index.html"))+    writeFileUtf8Builder fp $+        "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body>" <>+        "<h1>HPC Report Generation Error</h1>" <>+        "<p>" <>+        err <>+        "</p>" <>+        "</body></html>"  pathToHtml :: Path b t -> Text pathToHtml = T.dropWhileEnd (=='/') . sanitize . toFilePath +-- | Escape HTML symbols (copied from Text.Hastache)+htmlEscape :: LT.Text -> LT.Text+htmlEscape = LT.concatMap proc_+  where+    proc_ '&'  = "&amp;"+    proc_ '\\' = "&#92;"+    proc_ '"'  = "&quot;"+    proc_ '\'' = "&#39;"+    proc_ '<'  = "&lt;"+    proc_ '>'  = "&gt;"+    proc_ h    = LT.singleton h+ sanitize :: String -> Text sanitize = LT.toStrict . htmlEscape . LT.pack @@ -428,14 +441,14 @@     if cabalVer < $(mkVersion "1.24")         then do             path <- liftM (inplaceDir </>) $ parseRelFile (pkgIdStr ++ "-inplace.conf")-            logDebug $ "Parsing config in Cabal < 1.24 location: " <> T.pack (toFilePath path)+            logDebug $ "Parsing config in Cabal < 1.24 location: " <> fromString (toFilePath path)             exists <- doesFileExist path             if exists then extractField path else notFoundErr         else do             -- With Cabal-1.24, it's in a different location.-            logDebug $ "Scanning " <> T.pack (toFilePath inplaceDir) <> " for files matching " <> T.pack pkgIdStr+            logDebug $ "Scanning " <> fromString (toFilePath inplaceDir) <> " for files matching " <> fromString pkgIdStr             (_, files) <- handleIO (const $ return ([], [])) $ listDir inplaceDir-            logDebug $ T.pack (show files)+            logDebug $ displayShow files             case mapMaybe (\file -> fmap (const file) . (T.stripSuffix ".conf" <=< T.stripPrefix (T.pack (pkgIdStr ++ "-")))                           . T.pack . toFilePath . filename $ file) files of                 [] -> notFoundErr
src/Stack/Docker.hs view
@@ -27,11 +27,13 @@ import           Data.Aeson.Extended (FromJSON(..),(.:),(.:?),(.!=),eitherDecode) import           Data.ByteString.Builder (stringUtf8,charUtf8,toLazyByteString) import qualified Data.ByteString.Char8 as BS+import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Char8 as LBS import           Data.Char (isSpace,toUpper,isAscii,isDigit) import           Data.Conduit.List (sinkNull)+import           Data.Conduit.Process.Typed hiding (proc) import           Data.List (dropWhileEnd,intercalate,isPrefixOf,isInfixOf)-import           Data.List.Extra (trim, nubOrd)+import           Data.List.Extra (trim) import qualified Data.Map.Strict as Map import           Data.Ord (Down(..)) import           Data.Streaming.Process (ProcessExitedUnsuccessfully(..))@@ -40,6 +42,7 @@ import           Data.Time (UTCTime,LocalTime(..),diffDays,utcToLocalTime,getZonedTime,ZonedTime(..)) import           Data.Version (showVersion) import           GHC.Exts (sortWith)+import           Lens.Micro (set) import           Path import           Path.Extra (toFilePathNoTrailingSep) import           Path.IO hiding (canonicalizePath)@@ -48,6 +51,7 @@ import           Stack.Constants import           Stack.Constants.Config import           Stack.Docker.GlobalDB+import           Stack.PackageIndex import           Stack.Types.PackageIndex import           Stack.Types.Runner import           Stack.Types.Version@@ -63,14 +67,11 @@ import           System.IO.Unsafe (unsafePerformIO) import qualified System.PosixCompat.User as User import qualified System.PosixCompat.Files as Files-import           System.Process (CreateProcess(..), StdStream(..), waitForProcess) import           System.Process.PagerEditor (editByteString)-import           System.Process.Read-import           System.Process.Run+import           RIO.Process import           Text.Printf (printf)  #ifndef WINDOWS-import           Control.Concurrent (threadDelay) import           System.Posix.Signals import qualified System.Posix.User as PosixUser #endif@@ -93,7 +94,7 @@ reexecWithOptionalContainer mprojectRoot =     execWithOptionalContainer mprojectRoot getCmdArgs   where-    getCmdArgs docker envOverride imageInfo isRemoteDocker = do+    getCmdArgs docker imageInfo isRemoteDocker = do         config <- view configL         deUser <-             if fromMaybe (not isRemoteDocker) (dockerSetUser docker)@@ -146,8 +147,6 @@                           e <-                               try $                               sinkProcessStderrStdout-                                  Nothing-                                  envOverride                                   "docker"                                   [ "run"                                   , "-v"@@ -237,11 +236,10 @@ runContainerAndExit getCmdArgs                     mprojectRoot                     before-                    after =-  do config <- view configL+                    after = do+     config <- view configL      let docker = configDocker config-     envOverride <- getEnvOverride (configPlatform config)-     checkDockerVersion envOverride docker+     checkDockerVersion docker      (env,isStdinTerminal,isStderrTerminal,homeDir) <- liftIO $        (,,,)        <$> getEnvironment@@ -260,13 +258,13 @@      when (isRemoteDocker &&            maybe False (isInfixOf "boot2docker") dockerCertPath)           (logWarn "Warning: Using boot2docker is NOT supported, and not likely to perform well.")-     maybeImageInfo <- inspect envOverride image+     maybeImageInfo <- inspect image      imageInfo@Inspect{..} <- case maybeImageInfo of        Just ii -> return ii        Nothing          | dockerAutoPull docker ->-             do pullImage envOverride docker image-                mii2 <- inspect envOverride image+             do pullImage docker image+                mii2 <- inspect image                 case mii2 of                   Just ii2 -> return ii2                   Nothing -> throwM (InspectFailedException image)@@ -275,7 +273,7 @@      let ImageConfig {..} = iiConfig          imageEnvVars = map (break (== '=')) icEnv          platformVariant = show $ hashRepoName image-         stackRoot = configStackRoot config+         stackRoot = view stackRootL config          sandboxHomeDir = sandboxDir </> homeDirName          isTerm = not (dockerDetach docker) &&                   isStdinTerminal &&@@ -287,11 +285,12 @@                          -- in place for now, for users who haven't upgraded yet.                          (isTerm || (isNothing bamboo && isNothing jenkins))      hostBinDirPath <- parseAbsDir hostBinDir-     newPathEnv <- augmentPath+     newPathEnv <- either throwM return $ augmentPath+                      ( toFilePath <$>                       [ hostBinDirPath-                      , sandboxHomeDir </> $(mkRelDir ".local/bin")]+                      , sandboxHomeDir </> $(mkRelDir ".local/bin")])                       (T.pack <$> lookupImageEnv "PATH" imageEnvVars)-     (cmnd,args,envVars,extraMount) <- getCmdArgs docker envOverride imageInfo isRemoteDocker+     (cmnd,args,envVars,extraMount) <- getCmdArgs docker imageInfo isRemoteDocker      pwd <- getCurrentDir      liftIO        (do updateDockerImageLastUsed config iiId (toFilePath projectRoot)@@ -309,9 +308,7 @@              (Files.createSymbolicLink                  (toFilePathNoTrailingSep sshDir)                  (toFilePathNoTrailingSep (sandboxHomeDir </> sshRelDir))))-     containerID <- (trim . decodeUtf8) <$> readDockerProcess-       envOverride-       (Just projectRoot)+     containerID <- withWorkingDir (toFilePath projectRoot) $ trim . decodeUtf8 <$> readDockerProcess        (concat          [["create"           ,"--net=host"@@ -356,30 +353,23 @@      run <- askRunInIO      oldHandlers <- forM [sigINT,sigABRT,sigHUP,sigPIPE,sigTERM,sigUSR1,sigUSR2] $ \sig -> do        let sigHandler = run $ do-             readProcessNull Nothing envOverride "docker"-                             ["kill","--signal=" ++ show sig,containerID]+             readProcessNull "docker" ["kill","--signal=" ++ show sig,containerID]              when (sig `elem` [sigTERM,sigABRT]) $ do                -- Give the container 30 seconds to exit gracefully, then send a sigKILL to force it-               liftIO $ threadDelay 30000000-               readProcessNull Nothing envOverride "docker" ["kill",containerID]+               threadDelay 30000000+               readProcessNull "docker" ["kill",containerID]        oldHandler <- liftIO $ installHandler sig (Catch sigHandler) Nothing        return (sig, oldHandler) #endif-     let cmd = Cmd Nothing-                 "docker"-                 envOverride-                 (concat [["start"]-                         ,["-a" | not (dockerDetach docker)]-                         ,["-i" | keepStdinOpen]-                         ,[containerID]])-     e <- finally-         (try $ callProcess'-             (\cp -> cp { delegate_ctlc = False })-             cmd)+     let args' = concat [["start"]+                        ,["-a" | not (dockerDetach docker)]+                        ,["-i" | keepStdinOpen]+                        ,[containerID]]+     e <- try (proc "docker" args' $ runProcess_ . setDelegateCtlc False)+         `finally`          (do unless (dockerPersist docker || dockerDetach docker) $-               catch-                 (readProcessNull Nothing envOverride "docker" ["rm","-f",containerID])-                 (\(_::ReadProcessException) -> return ())+                 readProcessNull "docker" ["rm","-f",containerID]+                 `catch` (\(_::ExitCodeException) -> return ()) #ifndef WINDOWS              forM_ oldHandlers $ \(sig,oldHandler) ->                liftIO $ installHandler sig oldHandler Nothing@@ -404,26 +394,23 @@  -- | Clean-up old docker images and containers. cleanup :: HasConfig env => CleanupOpts -> RIO env ()-cleanup opts =-  do config <- view configL+cleanup opts = do+     config <- view configL      let docker = configDocker config-     envOverride <- getEnvOverride (configPlatform config)-     checkDockerVersion envOverride docker-     let runDocker = readDockerProcess envOverride Nothing-     imagesOut <- runDocker ["images","--no-trunc","-f","dangling=false"]-     danglingImagesOut <- runDocker ["images","--no-trunc","-f","dangling=true"]-     runningContainersOut <- runDocker ["ps","-a","--no-trunc","-f","status=running"]-     restartingContainersOut <- runDocker ["ps","-a","--no-trunc","-f","status=restarting"]-     exitedContainersOut <- runDocker ["ps","-a","--no-trunc","-f","status=exited"]-     pausedContainersOut <- runDocker ["ps","-a","--no-trunc","-f","status=paused"]+     checkDockerVersion docker+     imagesOut <- readDockerProcess ["images","--no-trunc","-f","dangling=false"]+     danglingImagesOut <- readDockerProcess ["images","--no-trunc","-f","dangling=true"]+     runningContainersOut <- readDockerProcess ["ps","-a","--no-trunc","-f","status=running"]+     restartingContainersOut <- readDockerProcess ["ps","-a","--no-trunc","-f","status=restarting"]+     exitedContainersOut <- readDockerProcess ["ps","-a","--no-trunc","-f","status=exited"]+     pausedContainersOut <- readDockerProcess ["ps","-a","--no-trunc","-f","status=paused"]      let imageRepos = parseImagesOut imagesOut          danglingImageHashes = Map.keys (parseImagesOut danglingImagesOut)          runningContainers = parseContainersOut runningContainersOut ++                              parseContainersOut restartingContainersOut          stoppedContainers = parseContainersOut exitedContainersOut ++                              parseContainersOut pausedContainersOut-     inspectMap <- inspects envOverride-                            (Map.keys imageRepos +++     inspectMap <- inspects (Map.keys imageRepos ++                              danglingImageHashes ++                              map fst stoppedContainers ++                              map fst runningContainers)@@ -448,31 +435,40 @@                 CleanupImmediate -> return plan                 CleanupDryRun -> do liftIO (LBS.hPut stdout plan)                                     return LBS.empty-     mapM_ (performPlanLine envOverride)+     mapM_ performPlanLine            (reverse (filter filterPlanLine (lines (LBS.unpack plan'))))-     allImageHashesOut <- runDocker ["images","-aq","--no-trunc"]+     allImageHashesOut <- readDockerProcess ["images","-aq","--no-trunc"]      liftIO (pruneDockerImagesLastUsed config (lines (decodeUtf8 allImageHashesOut)))   where     filterPlanLine line =       case line of         c:_ | isSpace c -> False         _ -> True-    performPlanLine envOverride line =+    performPlanLine line =       case filter (not . null) (words (takeWhile (/= '#') line)) of         [] -> return ()         (c:_):t:v:_ ->           do args <- if | toUpper c == 'R' && t == imageStr ->-                            do logInfo (concatT ["Removing image: '",v,"'"])+                            do logInfo $+                                 "Removing image: '" <>+                                 fromString v <>+                                 "'"                                return ["rmi",v]                         | toUpper c == 'R' && t == containerStr ->-                            do logInfo (concatT ["Removing container: '",v,"'"])+                            do logInfo $+                                 "Removing container: '" <>+                                 fromString v <>+                                 "'"                                return ["rm","-f",v]                         | otherwise -> throwM (InvalidCleanupCommandException line)-             e <- try (readDockerProcess envOverride Nothing args)+             e <- try (readDockerProcess args)              case e of-               Left ex@ProcessFailed{} ->-                 logError (concatT ["Could not remove: '",v,"': ", show ex])-               Left e' -> throwM e'+               Left ex ->+                 logError $+                   "Could not remove: '" <>+                   fromString v <>+                   "': " <>+                   displayShow (ex :: ExitCodeException)                Right _ -> return ()         _ -> throwM (InvalidCleanupCommandException line)     parseImagesOut = Map.fromListWith (++) . map parseImageRepo . drop 1 . lines . decodeUtf8@@ -629,30 +625,29 @@     containerStr = "container"  -- | Inspect Docker image or container.-inspect :: (MonadUnliftIO m,MonadLogger m)-        => EnvOverride -> String -> m (Maybe Inspect)-inspect envOverride image =-  do results <- inspects envOverride [image]+inspect :: (HasProcessContext env, HasLogFunc env)+        => String -> RIO env (Maybe Inspect)+inspect image =+  do results <- inspects [image]      case Map.toList results of        [] -> return Nothing        [(_,i)] -> return (Just i)        _ -> throwIO (InvalidInspectOutputException "expect a single result")  -- | Inspect multiple Docker images and/or containers.-inspects :: (MonadUnliftIO m, MonadLogger m)-         => EnvOverride -> [String] -> m (Map String Inspect)-inspects _ [] = return Map.empty-inspects envOverride images =-  do maybeInspectOut <--       try (readDockerProcess envOverride Nothing ("inspect" : images))+inspects :: (HasProcessContext env, HasLogFunc env)+         => [String] -> RIO env (Map String Inspect)+inspects [] = return Map.empty+inspects images =+  do maybeInspectOut <- try (readDockerProcess ("inspect" : images))      case maybeInspectOut of        Right inspectOut ->          -- filtering with 'isAscii' to workaround @docker inspect@ output containing invalid UTF-8          case eitherDecode (LBS.pack (filter isAscii (decodeUtf8 inspectOut))) of            Left msg -> throwIO (InvalidInspectOutputException msg)            Right results -> return (Map.fromList (map (\r -> (iiId r,r)) results))-       Left (ProcessFailed _ _ _ err)-         |  any (`LBS.isPrefixOf` err) missingImagePrefixes -> return Map.empty+       Left ece+         |  any (`LBS.isPrefixOf` eceStderr ece) missingImagePrefixes -> return Map.empty        Left e -> throwIO e   where missingImagePrefixes = ["Error: No such image", "Error: No such object:"] @@ -661,50 +656,45 @@ pull =   do config <- view configL      let docker = configDocker config-     envOverride <- getEnvOverride (configPlatform config)-     checkDockerVersion envOverride docker-     pullImage envOverride docker (dockerImage docker)+     checkDockerVersion docker+     pullImage docker (dockerImage docker)  -- | Pull Docker image from registry.-pullImage :: (MonadLogger m,MonadIO m,MonadThrow m)-          => EnvOverride -> DockerOpts -> String -> m ()-pullImage envOverride docker image =-  do logInfo (concatT ["Pulling image from registry: '",image,"'"])+pullImage :: (HasProcessContext env, HasLogFunc env)+          => DockerOpts -> String -> RIO env ()+pullImage docker image =+  do logInfo ("Pulling image from registry: '" <> fromString image <> "'")      when (dockerRegistryLogin docker)           (do logInfo "You may need to log in."-              callProcess $ Cmd-                Nothing+              proc                 "docker"-                envOverride                 (concat                    [["login"]                    ,maybe [] (\n -> ["--username=" ++ n]) (dockerRegistryUsername docker)                    ,maybe [] (\p -> ["--password=" ++ p]) (dockerRegistryPassword docker)-                   ,[takeWhile (/= '/') image]]))+                   ,[takeWhile (/= '/') image]])+                runProcess_)      -- We redirect the stdout of the process to stderr so that the output      -- of @docker pull@ will not interfere with the output of other      -- commands when using --auto-docker-pull. See issue #2733.-     let stdoutToStderr cp = cp-           { std_out = UseHandle stderr-           , std_err = UseHandle stderr-           , std_in = CreatePipe-           }-     (Just hin, _, _, ph) <- createProcess' "pullImage" stdoutToStderr $-       Cmd Nothing "docker" envOverride ["pull",image]-     liftIO (hClose hin)-     ec <- liftIO (waitForProcess ph)+     ec <- proc "docker" ["pull", image] $ \pc0 -> do+       let pc = setStdout (useHandleOpen stderr)+              $ setStderr (useHandleOpen stderr)+              $ setStdin closed+                pc0+       runProcess pc      case ec of        ExitSuccess -> return ()        ExitFailure _ -> throwIO (PullFailedException image)  -- | Check docker version (throws exception if incorrect) checkDockerVersion-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride -> DockerOpts -> m ()-checkDockerVersion envOverride docker =-  do dockerExists <- doesExecutableExist envOverride "docker"+    :: (HasProcessContext env, HasLogFunc env)+    => DockerOpts -> RIO env ()+checkDockerVersion docker =+  do dockerExists <- doesExecutableExist "docker"      unless dockerExists (throwIO DockerNotInstalledException)-     dockerVersionOut <- readDockerProcess envOverride Nothing ["--version"]+     dockerVersionOut <- readDockerProcess ["--version"]      case words (decodeUtf8 dockerVersionOut) of        (_:_:v:_) ->          case parseVersionFromString (stripVersion v) of@@ -736,13 +726,13 @@  -- | The Docker container "entrypoint": special actions performed when first entering -- a container, such as switching the UID/GID to the "outside-Docker" user's.-entrypoint :: (MonadUnliftIO m, MonadLogger m, MonadThrow m)-           => Config -> DockerEntrypoint -> m ()+entrypoint :: (HasProcessContext env, HasLogFunc env)+           => Config -> DockerEntrypoint -> RIO env () entrypoint config@Config{..} DockerEntrypoint{..} =   modifyMVar_ entrypointMVar $ \alreadyRan -> do     -- Only run the entrypoint once     unless alreadyRan $ do-      envOverride <- getEnvOverride configPlatform+      envOverride <- view processContextL       homeDir <- liftIO $ parseAbsDir =<< getEnv "HOME"       -- Get the UserEntry for the 'stack' user in the image, if it exists       estackUserEntry0 <- liftIO $ tryJust (guard . isDoesNotExistError) $@@ -751,7 +741,7 @@       case deUser of         Nothing -> return ()         Just (DockerUser 0 _ _ _) -> return ()-        Just du -> updateOrCreateStackUser envOverride estackUserEntry0 homeDir du+        Just du -> withProcessContext envOverride $ updateOrCreateStackUser estackUserEntry0 homeDir du       case estackUserEntry0 of         Left _ -> return ()         Right ue -> do@@ -763,13 +753,13 @@           when buildPlanDirExists $ do             (_, buildPlans) <- listDir (buildPlanDir origStackRoot)             forM_ buildPlans $ \srcBuildPlan -> do-              let destBuildPlan = buildPlanDir configStackRoot </> filename srcBuildPlan+              let destBuildPlan = buildPlanDir (view stackRootL config) </> filename srcBuildPlan               exists <- doesFileExist destBuildPlan               unless exists $ do                 ensureDir (parent destBuildPlan)                 copyFile srcBuildPlan destBuildPlan-          forM_ configPackageIndices $ \pkgIdx -> do-            msrcIndex <- flip runReaderT (config{configStackRoot = origStackRoot}) $ do+          forM_ clIndices $ \pkgIdx -> do+            msrcIndex <- runRIO (set stackRootL origStackRoot config) $ do                srcIndex <- configPackageIndex (indexName pkgIdx)                exists <- doesFileExist srcIndex                return $ if exists@@ -777,8 +767,8 @@                  else Nothing             case msrcIndex of               Nothing -> return ()-              Just srcIndex -> do-                flip runReaderT config $ do+              Just srcIndex ->+                runRIO config $ do                   destIndex <- configPackageIndex (indexName pkgIdx)                   exists <- doesFileExist destIndex                   unless exists $ do@@ -786,15 +776,16 @@                     copyFile srcIndex destIndex     return True   where-    updateOrCreateStackUser envOverride estackUserEntry homeDir DockerUser{..} = do+    CabalLoader {..} = configCabalLoader+    updateOrCreateStackUser estackUserEntry homeDir DockerUser{..} = do       case estackUserEntry of         Left _ -> do           -- If no 'stack' user in image, create one with correct UID/GID and home directory-          readProcessNull Nothing envOverride "groupadd"+          readProcessNull "groupadd"             ["-o"             ,"--gid",show duGid             ,stackUserName]-          readProcessNull Nothing envOverride "useradd"+          readProcessNull "useradd"             ["-oN"             ,"--uid",show duUid             ,"--gid",show duGid@@ -802,17 +793,17 @@             ,stackUserName]         Right _ -> do           -- If there is already a 'stack' user in the image, adjust its UID/GID and home directory-          readProcessNull Nothing envOverride "usermod"+          readProcessNull "usermod"             ["-o"             ,"--uid",show duUid             ,"--home",toFilePathNoTrailingSep homeDir             ,stackUserName]-          readProcessNull Nothing envOverride "groupmod"+          readProcessNull "groupmod"             ["-o"             ,"--gid",show duGid             ,stackUserName]       forM_ duGroups $ \gid -> do-        readProcessNull Nothing envOverride "groupadd"+        readProcessNull "groupadd"           ["-o"           ,"--gid",show gid           ,"group" ++ show gid]@@ -854,9 +845,9 @@ -- process. Throws a 'ReadProcessException' exception if the -- process fails.  Logs process's stderr using @logError@. readDockerProcess-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride -> Maybe (Path Abs Dir) -> [String] -> m BS.ByteString-readDockerProcess envOverride mpwd = readProcessStdout mpwd envOverride "docker"+    :: (HasProcessContext env, HasLogFunc env)+    => [String] -> RIO env BS.ByteString+readDockerProcess args = BL.toStrict <$> proc "docker" args readProcessStdout_ -- FIXME stderr isn't logged with logError, should it be?  -- | Name of home directory within docker sandbox. homeDirName :: Path Rel Dir@@ -870,10 +861,6 @@ decodeUtf8 :: BS.ByteString -> String decodeUtf8 bs = T.unpack (T.decodeUtf8 bs) --- | Convenience function constructing message for @log*@.-concatT :: [String] -> Text-concatT = T.pack . concat- -- | Fail with friendly error if project root not set. fromMaybeProjectRoot :: Maybe (Path Abs Dir) -> Path Abs Dir fromMaybeProjectRoot = fromMaybe (impureThrow CannotDetermineProjectRootException)@@ -933,7 +920,6 @@ -- | Function to get command and arguments to run in Docker container type GetCmdArgs env    = DockerOpts-  -> EnvOverride   -> Inspect   -> Bool   -> RIO env (FilePath,[String],[(String,String)],[Mount])
src/Stack/Docker/GlobalDB.hs view
@@ -16,7 +16,8 @@   ,DockerImageExeId)   where -import           Control.Monad.Logger (NoLoggingT)+import           Control.Monad.Logger (NoLoggingT) -- TODO remove dep when persistent drops monad-logger+import           Control.Monad.Trans.Resource (ResourceT) import           Stack.Prelude import           Data.List (sortBy, isInfixOf, stripPrefix) import           Data.List.Extra (stripSuffix)@@ -58,10 +59,13 @@ -- | Get a list of Docker image hashes and when they were last used. getDockerImagesLastUsed :: Config -> IO [DockerImageLastUsed] getDockerImagesLastUsed config =-  do imageProjects <- withGlobalDB config (selectList [] [Asc DockerImageProjectLastUsedTime])-     return (sortBy (flip sortImage)-                    (Map.toDescList (Map.fromListWith (++)-                                                      (map mapImageProject imageProjects))))+      sortBy (flip sortImage)+    . Map.toDescList+    . Map.fromListWith (++)+    . map mapImageProject+  <$> withGlobalDB+        config+        (selectList [] [Asc DockerImageProjectLastUsedTime])   where     mapImageProject (Entity _ imageProject) =       (dockerImageProjectImageHash imageProject@@ -84,9 +88,9 @@ -- | Get the record of whether an executable is compatible with a Docker image getDockerImageExe :: Config -> String -> FilePath -> UTCTime -> IO (Maybe Bool) getDockerImageExe config imageId exePath exeTimestamp =-    withGlobalDB config $ do-        mentity <- getBy (DockerImageExeUnique imageId exePath exeTimestamp)-        return (fmap (dockerImageExeCompatible . entityVal) mentity)+    withGlobalDB config $+      fmap (dockerImageExeCompatible . entityVal) <$>+      getBy (DockerImageExeUnique imageId exePath exeTimestamp)  -- | Seet the record of whether an executable is compatible with a Docker image setDockerImageExe :: Config -> String -> FilePath -> UTCTime -> Bool -> IO ()
src/Stack/Dot.hs view
@@ -23,8 +23,9 @@ import qualified Data.Text.IO as Text import qualified Data.Traversable as T import           Distribution.Text (display)-import           Distribution.License (License(BSD3))-import           Stack.Build (withLoadPackage)+import qualified Distribution.SPDX.License as SPDX+import           Distribution.License (License(BSD3), licenseFromSPDX)+import           Stack.Build (loadPackage) import           Stack.Build.Installed (getInstalled, GetInstalledOpts(..)) import           Stack.Build.Source import           Stack.Build.Target@@ -32,7 +33,7 @@ import           Stack.Constants import           Stack.Package import           Stack.PackageDump (DumpPackage(..))-import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import           Stack.Types.Build import           Stack.Types.BuildPlan import           Stack.Types.Config@@ -82,7 +83,7 @@ data DotPayload = DotPayload   { payloadVersion :: Maybe Version   -- ^ The package version.-  , payloadLicense :: Maybe License+  , payloadLicense :: Maybe (Either SPDX.License License)   -- ^ The license the package was released under.   } deriving (Eq, Show) @@ -116,23 +117,20 @@       , boptsCLIFlags = dotFlags dotOpts       }   let graph = Map.fromList (localDependencies dotOpts (filter lpWanted locals))-  menv <- getMinimalEnvOverride-  (installedMap, globalDump, _, _) <- getInstalled menv-                                                   (GetInstalledOpts False False False)+  (installedMap, globalDump, _, _) <- getInstalled (GetInstalledOpts False False False)                                                    sourceMap   -- TODO: Can there be multiple entries for wired-in-packages? If so,   -- this will choose one arbitrarily..   let globalDumpMap = Map.fromList $ map (\dp -> (packageIdentifierName (dpPackageIdent dp), dp)) globalDump       globalIdMap = Map.fromList $ map (\dp -> (dpGhcPkgId dp, dpPackageIdent dp)) globalDump-  withLoadPackage (\loader -> do-    let depLoader = createDepLoader sourceMap installedMap globalDumpMap globalIdMap loadPackageDeps-        loadPackageDeps name version loc flags ghcOptions-            -- Skip packages that can't be loaded - see-            -- https://github.com/commercialhaskell/stack/issues/2967-            | name `elem` [$(mkPackageName "rts"), $(mkPackageName "ghc")] =-                return (Set.empty, DotPayload (Just version) (Just BSD3))-            | otherwise = fmap (packageAllDeps &&& makePayload) (loader loc flags ghcOptions)-    liftIO $ resolveDependencies (dotDependencyDepth dotOpts) graph depLoader)+  let depLoader = createDepLoader sourceMap installedMap globalDumpMap globalIdMap loadPackageDeps+      loadPackageDeps name version loc flags ghcOptions+          -- Skip packages that can't be loaded - see+          -- https://github.com/commercialhaskell/stack/issues/2967+          | name `elem` [$(mkPackageName "rts"), $(mkPackageName "ghc")] =+              return (Set.empty, DotPayload (Just version) (Just $ Right BSD3))+          | otherwise = fmap (packageAllDeps &&& makePayload) (loadPackage loc flags ghcOptions)+  resolveDependencies (dotDependencyDepth dotOpts) graph depLoader   where makePayload pkg = DotPayload (Just $ packageVersion pkg) (Just $ packageLicense pkg)  listDependencies :: HasEnvConfig env@@ -145,7 +143,7 @@     where go name payload =             let payloadText =                   if listDepsLicense opts-                      then maybe "<unknown>" (Text.pack . display) (payloadLicense payload)+                      then maybe "<unknown>" (Text.pack . display . either licenseFromSPDX id) (payloadLicense payload)                       else maybe "<unknown>" (Text.pack . show) (payloadVersion payload)                 line = packageNameText name <> listDepsSep opts <> payloadText             in  liftIO $ Text.putStrLn line@@ -236,7 +234,7 @@         case maybePkg of             Just (_, Library _ _ mlicense) -> mlicense             _ -> Nothing-    payloadFromDump dp = DotPayload (Just $ packageIdentifierVersion $ dpPackageIdent dp) (dpLicense dp)+    payloadFromDump dp = DotPayload (Just $ packageIdentifierVersion $ dpPackageIdent dp) (Right <$> dpLicense dp)  -- | Resolve the direct (depth 0) external dependencies of the given local packages localDependencies :: DotOpts -> [LocalPackage] -> [(PackageName, (Set PackageName, DotPayload))]@@ -263,8 +261,8 @@   printLeaves graph   void (Map.traverseWithKey printEdges (fst <$> graph))   liftIO $ Text.putStrLn "}"-  where filteredLocals = Set.filter (\local ->-          packageNameString local `Set.notMember` dotPrune dotOpts) locals+  where filteredLocals = Set.filter (\local' ->+          packageNameString local' `Set.notMember` dotPrune dotOpts) locals  -- | Print the local nodes with a different style depending on options printLocalNodes :: (F.Foldable t, MonadIO m)
− src/Stack/Exec.hs
@@ -1,93 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleContexts #-}--#if __GLASGOW_HASKELL__ >= 800-{-# OPTIONS_GHC -Wno-redundant-constraints #-}-#endif---- | Execute commands within the properly configured Stack--- environment.--module Stack.Exec where--import           Stack.Prelude-import           Stack.Types.Config-import           System.Process.Log--import           Data.Streaming.Process (ProcessExitedUnsuccessfully(..))-import           System.Exit-import           System.Process.Run (callProcess, callProcessObserveStdout, Cmd(..))-#ifdef WINDOWS-import           System.Process.Read (EnvOverride)-#else-import qualified System.Process.PID1 as PID1-import           System.Process.Read (EnvOverride, envHelper, preProcess)-#endif---- | Default @EnvSettings@ which includes locals and GHC_PACKAGE_PATH.------ Note that this also passes through the GHCRTS environment variable.--- See https://github.com/commercialhaskell/stack/issues/3444-defaultEnvSettings :: EnvSettings-defaultEnvSettings = EnvSettings-    { esIncludeLocals = True-    , esIncludeGhcPackagePath = True-    , esStackExe = True-    , esLocaleUtf8 = False-    , esKeepGhcRts = True-    }---- | Environment settings which do not embellish the environment------ Note that this also passes through the GHCRTS environment variable.--- See https://github.com/commercialhaskell/stack/issues/3444-plainEnvSettings :: EnvSettings-plainEnvSettings = EnvSettings-    { esIncludeLocals = False-    , esIncludeGhcPackagePath = False-    , esStackExe = False-    , esLocaleUtf8 = False-    , esKeepGhcRts = True-    }---- | Execute a process within the Stack configured environment.------ Execution will not return, because either:------ 1) On non-windows, execution is taken over by execv of the--- sub-process. This allows signals to be propagated (#527)------ 2) On windows, an 'ExitCode' exception will be thrown.-exec :: (MonadUnliftIO m, MonadLogger m)-     => EnvOverride -> String -> [String] -> m b-#ifdef WINDOWS-exec = execSpawn-#else-exec menv cmd0 args = do-    cmd <- preProcess Nothing menv cmd0-    withProcessTimeLog cmd args $-        liftIO $ PID1.run cmd args (envHelper menv)-#endif---- | Like 'exec', but does not use 'execv' on non-windows. This way, there--- is a sub-process, which is helpful in some cases (#1306)------ This function only exits by throwing 'ExitCode'.-execSpawn :: (MonadUnliftIO m, MonadLogger m)-     => EnvOverride -> String -> [String] -> m b-execSpawn menv cmd0 args = do-    e <- withProcessTimeLog cmd0 args $-        try (callProcess (Cmd Nothing cmd0 menv args))-    liftIO $ case e of-        Left (ProcessExitedUnsuccessfully _ ec) -> exitWith ec-        Right () -> exitSuccess--execObserve :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride -> String -> [String] -> m String-execObserve menv cmd0 args = do-    e <- withProcessTimeLog cmd0 args $-        try (callProcessObserveStdout (Cmd Nothing cmd0 menv args))-    case e of-        Left (ProcessExitedUnsuccessfully _ ec) -> liftIO $ exitWith ec-        Right s -> return s
src/Stack/Fetch.hs view
@@ -13,6 +13,7 @@ {-# LANGUAGE TypeFamilies          #-} {-# LANGUAGE PackageImports        #-} {-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE RecordWildCards       #-}  -- | Functionality for downloading packages securely for cabal's usage. @@ -26,7 +27,7 @@     , resolvePackagesAllowMissing     , ResolvedPackage (..)     , withCabalFiles-    , withCabalLoader+    , loadFromIndex     ) where  import qualified    Codec.Archive.Tar as Tar@@ -36,7 +37,6 @@ import              Stack.Prelude import              Crypto.Hash (SHA256 (..)) import qualified    Data.ByteString as S-import qualified    Data.ByteString.Lazy as L import qualified    Data.Foldable as F import qualified    Data.HashMap.Strict as HashMap import qualified    Data.HashSet as HashSet@@ -48,17 +48,16 @@ import qualified    Data.Text as T import              Data.Text.Encoding (decodeUtf8) import              Data.Text.Metrics+import              Lens.Micro (to) import              Network.HTTP.Download import              Path import              Path.Extra (toFilePathNoTrailingSep) import              Path.IO import              Stack.PackageIndex import              Stack.Types.BuildPlan-import              Stack.Types.Config import              Stack.Types.PackageIdentifier import              Stack.Types.PackageIndex import              Stack.Types.PackageName-import              Stack.Types.Runner import              Stack.Types.Version import qualified    System.FilePath as FP import              System.IO (SeekMode (AbsoluteSeek))@@ -104,7 +103,7 @@         (if uses00Index then "\n\nYou seem to be using a legacy 00-index.tar.gz tarball.\nConsider changing your configuration to use a 01-index.tar.gz file.\nAlternatively, you can set the ignore-revision-mismatch setting to true.\nFor more information, see: https://github.com/commercialhaskell/stack/issues/3520" else "")  -- | Fetch packages into the cache without unpacking-fetchPackages :: HasConfig env => Set PackageIdentifier -> RIO env ()+fetchPackages :: HasCabalLoader env => Set PackageIdentifier -> RIO env () fetchPackages idents' = do     resolved <- resolvePackages Nothing idents Set.empty     ToFetchResult toFetch alreadyUnpacked <- getToFetch Nothing resolved@@ -117,7 +116,7 @@     idents = map (flip PackageIdentifierRevision CFILatest) $ Set.toList idents'  -- | Intended to work for the command line command.-unpackPackages :: HasConfig env+unpackPackages :: HasCabalLoader env                => Maybe SnapshotDef -- ^ when looking up by name, take from this build plan                -> FilePath -- ^ destination                -> [String] -- ^ names or identifiers@@ -132,12 +131,11 @@     unless (Map.null alreadyUnpacked) $         throwM $ UnpackDirectoryAlreadyExists $ Set.fromList $ map toFilePath $ Map.elems alreadyUnpacked     unpacked <- fetchPackages' Nothing toFetch-    F.forM_ (Map.toList unpacked) $ \(ident, dest'') -> logInfo $ T.pack $ concat-        [ "Unpacked "-        , packageIdentifierString ident-        , " to "-        , toFilePath dest''-        ]+    F.forM_ (Map.toList unpacked) $ \(ident, dest'') -> logInfo $+        "Unpacked " <>+        fromString (packageIdentifierString ident) <>+        " to " <>+        fromString (toFilePath dest'')   where     -- Possible future enhancement: parse names as name + version range     parse s =@@ -152,7 +150,7 @@  -- | Same as 'unpackPackageIdents', but for a single package. unpackPackageIdent-    :: HasConfig env+    :: HasCabalLoader env     => Path Abs Dir -- ^ unpack directory     -> Path Rel Dir -- ^ the dist rename directory, see: https://github.com/fpco/stack/issues/157     -> PackageIdentifierRevision@@ -170,7 +168,7 @@ -- | Ensure that all of the given package idents are unpacked into the build -- unpack directory, and return the paths to all of the subdirectories. unpackPackageIdents-    :: HasConfig env+    :: HasCabalLoader env     => Path Abs Dir -- ^ unpack directory     -> Maybe (Path Rel Dir) -- ^ the dist rename directory, see: https://github.com/fpco/stack/issues/157     -> [PackageIdentifierRevision]@@ -190,7 +188,7 @@     deriving Show  -- | Resolve a set of package names and identifiers into @FetchPackage@ values.-resolvePackages :: HasConfig env+resolvePackages :: HasCabalLoader env                 => Maybe SnapshotDef -- ^ when looking up by name, take from this build plan                 -> [PackageIdentifierRevision]                 -> Set PackageName@@ -211,9 +209,9 @@  -- | Does the configuration use a 00-index.tar.gz file for indices? -- See <https://github.com/commercialhaskell/stack/issues/3520>-getUses00Index :: HasConfig env => RIO env Bool+getUses00Index :: HasCabalLoader env => RIO env Bool getUses00Index =-    any is00 <$> view packageIndicesL+    any is00 <$> view (cabalLoaderL.to clIndices)   where     is00 :: PackageIndex -> Bool     is00 index = "00-index.tar.gz" `T.isInfixOf` indexLocation index@@ -226,7 +224,7 @@ -- a warning, that's no longer necessary or desirable since all info -- should be present and checked). resolvePackagesAllowMissing-    :: forall env. HasConfig env+    :: forall env. HasCabalLoader env     => Maybe SnapshotDef -- ^ when looking up by name, take from this build plan     -> [PackageIdentifierRevision]     -> Set PackageName@@ -266,15 +264,19 @@       (missingNames, idents1) = partitionEithers $ map           (\name -> maybe (Left name) Right (getNamed name))           (Set.toList names0)-  config <- view configL+  cl <- view cabalLoaderL   let (missingIdents, resolved) =         partitionEithers-          $ map (\pir -> maybe (Left pir) Right (lookupResolvedPackage config pir cache))+          $ map (\pir -> maybe (Left pir) Right (lookupResolvedPackage cl pir cache))           $ idents0 <> idents1   return (Set.fromList missingNames, HashSet.fromList missingIdents, resolved) -lookupResolvedPackage :: Config -> PackageIdentifierRevision -> PackageCache PackageIndex -> Maybe ResolvedPackage-lookupResolvedPackage config (PackageIdentifierRevision ident@(PackageIdentifier name version) cfi) (PackageCache cache) = do+lookupResolvedPackage+  :: CabalLoader+  -> PackageIdentifierRevision+  -> PackageCache PackageIndex+  -> Maybe ResolvedPackage+lookupResolvedPackage cl (PackageIdentifierRevision ident@(PackageIdentifier name version) cfi) (PackageCache cache) = do   (index, mdownload, files) <- HashMap.lookup name cache >>= HashMap.lookup version   let moffsetSize =         case cfi of@@ -288,7 +290,7 @@     case moffsetSize of       Just x -> Just x       Nothing-        | configIgnoreRevisionMismatch config -> Just $ snd $ NE.last files+        | clIgnoreRevisionMismatch cl -> Just $ snd $ NE.last files         | otherwise -> Nothing   Just ResolvedPackage     { rpIdent = ident@@ -314,11 +316,11 @@  -- | Add the cabal files to a list of idents with their caches. withCabalFiles-    :: (MonadReader env m, MonadUnliftIO m, HasConfig env, MonadThrow m)+    :: HasCabalLoader env     => IndexName     -> [(ResolvedPackage, a)]     -> (PackageIdentifier -> a -> ByteString -> IO b)-    -> m [b]+    -> RIO env [b] withCabalFiles name pkgs f = do     indexPath <- configPackageIndex name     withBinaryFile (toFilePath indexPath) ReadMode@@ -331,71 +333,51 @@             cabalBS <- S.hGet h $ fromIntegral size             f ident tf cabalBS --- | Provide a function which will load up a cabal @ByteString@ from the--- package indices.-withCabalLoader-    :: HasConfig env-    => ((PackageIdentifierRevision -> IO ByteString) -> RIO env a)-    -> RIO env a-withCabalLoader inner = do-    -- Want to try updating the index once during a single run for missing-    -- package identifiers. We also want to ensure we only update once at a-    -- time-    ---    -- TODO: probably makes sense to move this concern into getPackageCaches-    updateRef <- newMVar True--    u <- askUnliftIO--    -- TODO in the future, keep all of the necessary @Handle@s open-    let doLookup :: PackageIdentifierRevision-                 -> IO ByteString-        doLookup ident = do-            bothCaches <- unliftIO u getPackageCaches-            eres <- unliftIO u $ lookupPackageIdentifierExact ident bothCaches-            case eres of-                Just bs -> return bs-                -- Update the cache and try again-                Nothing -> do-                    let fuzzy = fuzzyLookupCandidates ident bothCaches-                        suggestions = case fuzzy of-                            FRNameNotFound Nothing -> ""-                            FRNameNotFound (Just cs) ->-                                  "Perhaps you meant " <> orSeparated cs <> "?"-                            FRVersionNotFound cs -> "Possible candidates: " <>-                              commaSeparated (NE.map packageIdentifierText cs)-                              <> "."-                            FRRevisionNotFound cs ->-                              "The specified revision was not found.\nPossible candidates: " <>-                              commaSeparated (NE.map (T.pack . packageIdentifierRevisionString) cs)-                              <> "."-                    join $ modifyMVar updateRef $ \toUpdate ->-                        if toUpdate then do-                            unliftIO u $ do-                                logInfo $ T.concat-                                    [ "Didn't see "-                                    , T.pack $ packageIdentifierRevisionString ident-                                    , " in your package indices.\n"-                                    , "Updating and trying again."-                                    ]-                                updateAllIndices-                                _ <- getPackageCaches-                                return ()-                            return (False, doLookup ident)-                        else do-                          uses00Index <- unliftIO u getUses00Index-                          return (toUpdate, throwIO $ UnknownPackageIdentifiers-                                       (HashSet.singleton ident) (T.unpack suggestions) uses00Index)-    inner doLookup+loadFromIndex :: HasCabalLoader env => PackageIdentifierRevision -> RIO env ByteString+loadFromIndex ident = do+  -- TODO in the future, keep all of the necessary @Handle@s open+  bothCaches <- getPackageCaches+  mres <- lookupPackageIdentifierExact ident bothCaches+  case mres of+      Just bs -> return bs+      -- Update the cache and try again+      Nothing -> do+          let fuzzy = fuzzyLookupCandidates ident bothCaches+              suggestions = case fuzzy of+                  FRNameNotFound Nothing -> ""+                  FRNameNotFound (Just cs) ->+                        "Perhaps you meant " <> orSeparated cs <> "?"+                  FRVersionNotFound cs -> "Possible candidates: " <>+                    commaSeparated (NE.map packageIdentifierText cs)+                    <> "."+                  FRRevisionNotFound cs ->+                    "The specified revision was not found.\nPossible candidates: " <>+                    commaSeparated (NE.map (T.pack . packageIdentifierRevisionString) cs)+                    <> "."+          cl <- view cabalLoaderL+          join $ modifyMVar (clUpdateRef cl) $ \toUpdate ->+              if toUpdate then do+                  logInfo $+                      "Didn't see " <>+                      fromString (packageIdentifierRevisionString ident) <>+                      " in your package indices.\n" <>+                      "Updating and trying again."+                  updateAllIndices+                  _ <- getPackageCaches+                  return (False, loadFromIndex ident)+              else do+                uses00Index <- getUses00Index+                return (toUpdate, throwIO $ UnknownPackageIdentifiers+                             (HashSet.singleton ident) (T.unpack suggestions) uses00Index)  lookupPackageIdentifierExact-  :: (MonadReader env m, MonadUnliftIO m, HasConfig env, MonadThrow m)+  :: HasCabalLoader env   => PackageIdentifierRevision   -> PackageCache PackageIndex-  -> m (Maybe ByteString)+  -> RIO env (Maybe ByteString) lookupPackageIdentifierExact identRev cache = do-  config <- view configL-  forM (lookupResolvedPackage config identRev cache) $ \rp -> do+  cl <- view cabalLoaderL+  forM (lookupResolvedPackage cl identRev cache) $ \rp -> do     [bs] <- withCabalFiles (indexName (rpIndex rp)) [(rp, ())] $ \_ _ bs -> return bs     return bs @@ -450,7 +432,7 @@     $ cache  -- | Figure out where to fetch from.-getToFetch :: HasConfig env+getToFetch :: HasCabalLoader env            => Maybe (Path Abs Dir) -- ^ directory to unpack into, @Nothing@ means no unpack            -> [ResolvedPackage]            -> RIO env ToFetchResult@@ -509,28 +491,25 @@ -- @ -- -- Since 0.1.0.0-fetchPackages' :: HasConfig env+fetchPackages' :: forall env. HasCabalLoader env                => Maybe (Path Rel Dir) -- ^ the dist rename directory, see: https://github.com/fpco/stack/issues/157                -> Map PackageIdentifier ToFetch                -> RIO env (Map PackageIdentifier (Path Abs Dir)) fetchPackages' mdistDir toFetchAll = do-    connCount <- view $ configL.to configConnectionCount-    outputVar <- liftIO $ newTVarIO Map.empty+    connCount <- view $ cabalLoaderL.to clConnectionCount+    outputVar <- newTVarIO Map.empty -    run <- askRunInIO     parMapM_         connCount-        (go outputVar run)+        (go outputVar)         (Map.toList toFetchAll) -    liftIO $ readTVarIO outputVar+    readTVarIO outputVar   where-    go :: (MonadUnliftIO m,MonadThrow m,MonadLogger m,HasRunner env, MonadReader env m)-       => TVar (Map PackageIdentifier (Path Abs Dir))-       -> (m () -> IO ())+    go :: TVar (Map PackageIdentifier (Path Abs Dir))        -> (PackageIdentifier, ToFetch)-       -> m ()-    go outputVar run (ident, toFetch) = do+       -> RIO env ()+    go outputVar (ident, toFetch) = do         req <- parseUrlThrow $ T.unpack $ tfUrl toFetch         let destpath = tfTarball toFetch @@ -542,7 +521,7 @@                 , drRetryPolicy = drRetryPolicyDefault                 }         let progressSink _ =-                liftIO $ run $ logInfo $ packageIdentifierText ident <> ": download"+                logInfo $ display ident <> ": download"         _ <- verifiedDownload downloadReq destpath progressSink          identStrP <- parseRelDir $ packageIdentifierString ident@@ -579,7 +558,7 @@                 atomically $ modifyTVar outputVar $ Map.insert ident destDir              F.forM_ unexpectedEntries $ \(path, entryType) ->-                logWarn $ "Unexpected entry type " <> entryType <> " for entry " <> T.pack path+                logWarn $ "Unexpected entry type " <> display entryType <> " for entry " <> fromString path  -- | Internal function used to unpack tarball. --@@ -589,16 +568,13 @@ untar :: forall b1 b2. Path b1 File -> Path Rel Dir -> Path b2 Dir -> IO [(FilePath, T.Text)] untar tarPath expectedTarFolder destDirParent = do   ensureDir destDirParent-  withBinaryFile (toFilePath tarPath) ReadMode $ \h -> do-                -- Avoid using L.readFile, which is more likely to leak-                -- resources-                lbs <- L.hGetContents h+  withLazyFile (toFilePath tarPath) $ \lbs -> do                 let rawEntries = fmap (either wrap wrap)                             $ Tar.checkTarbomb (toFilePathNoTrailingSep expectedTarFolder)                             $ Tar.read $ decompress lbs                      filterEntries-                      :: Monoid w => (Tar.Entry -> (Bool, w))+                      :: (Semigroup w, Monoid w) => (Tar.Entry -> (Bool, w))                          -> Tar.Entries b -> (Tar.Entries b, w)                     -- Allow collecting warnings, Writer-monad style.                     filterEntries f =@@ -670,3 +646,12 @@  commaSeparated :: NonEmpty T.Text -> T.Text commaSeparated = F.fold . NE.intersperse ", "++-- | Location of a package tarball+configPackageTarball :: HasCabalLoader env => IndexName -> PackageIdentifier -> RIO env (Path Abs File)+configPackageTarball iname ident = do+    root <- configPackageIndexRoot iname+    name <- parseRelDir $ packageNameString $ packageIdentifierName ident+    ver <- parseRelDir $ versionString $ packageIdentifierVersion ident+    base <- parseRelFile $ packageIdentifierString ident ++ ".tar.gz"+    return (root </> $(mkRelDir "packages") </> name </> ver </> base)
src/Stack/FileWatch.hs view
@@ -4,26 +4,16 @@ module Stack.FileWatch     ( fileWatch     , fileWatchPoll-    , printExceptionStderr     ) where -import Blaze.ByteString.Builder (toLazyByteString, copyByteString)-import Blaze.ByteString.Builder.Char.Utf8 (fromShow) import Control.Concurrent.STM (check) import Stack.Prelude-import qualified Data.ByteString.Lazy as L import qualified Data.Map.Strict as Map import qualified Data.Set as Set import GHC.IO.Exception import Path-import System.Console.ANSI import System.FSNotify-import System.IO (stdout, stderr, hPutStrLn, getLine)---- | Print an exception to stderr-printExceptionStderr :: Exception e => e -> IO ()-printExceptionStderr e =-    L.hPut stderr $ toLazyByteString $ fromShow e <> copyByteString "\n"+import System.IO (hPutStrLn, getLine)  fileWatch :: Handle           -> ((Set (Path Abs File) -> IO ()) -> IO ())@@ -45,14 +35,11 @@               -> IO () fileWatchConf cfg out inner = withManagerConf cfg $ \manager -> do     let putLn = hPutStrLn out-    let withColor color action = do-            outputIsTerminal <- hIsTerminalDevice stdout+    outputIsTerminal <- hIsTerminalDevice out+    let withColor color str = putLn $ do             if outputIsTerminal-            then do-                setSGR [SetColor Foreground Dull color]-                action-                setSGR [Reset]-            else action+            then concat [color, str, reset]+            else str      allFiles <- newTVarIO Set.empty     dirtyVar <- newTVarIO True@@ -139,10 +126,14 @@         case eres of             Left e -> do                 let color = case fromException e of-                        Just ExitSuccess -> Green-                        _ -> Red-                withColor color $ printExceptionStderr e-            _ -> withColor Green $-                putLn "Success! Waiting for next file change."+                        Just ExitSuccess -> green+                        _ -> red+                withColor color $ show e+            _ -> withColor green "Success! Waiting for next file change."          putLn "Type help for available commands. Press enter to force a rebuild."++green, red, reset :: String+green = "\ESC[32m"+red = "\ESC[31m"+reset = "\ESC[0m"
src/Stack/GhcPkg.hs view
@@ -23,6 +23,7 @@  import           Stack.Prelude import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy as BL import           Data.List import qualified Data.Text as T import qualified Data.Text.Encoding as T@@ -37,16 +38,16 @@ import           Stack.Types.PackageName import           Stack.Types.Version import           System.FilePath (searchPathSeparator)-import           System.Process.Read+import           RIO.Process  -- | Get the global package database-getGlobalDB :: (MonadUnliftIO m, MonadLogger m)-            => EnvOverride -> WhichCompiler -> m (Path Abs Dir)-getGlobalDB menv wc = do+getGlobalDB :: (HasProcessContext env, HasLogFunc env)+            => WhichCompiler -> RIO env (Path Abs Dir)+getGlobalDB wc = do     logDebug "Getting global package database location"     -- This seems like a strange way to get the global package database     -- location, but I don't know of a better one-    bs <- ghcPkg menv wc [] ["list", "--global"] >>= either throwIO return+    bs <- ghcPkg wc [] ["list", "--global"] >>= either throwIO return     let fp = S8.unpack $ stripTrailingColon $ firstLine bs     liftIO $ resolveDir' fp   where@@ -57,27 +58,29 @@     firstLine = S8.takeWhile (\c -> c /= '\r' && c /= '\n')  -- | Run the ghc-pkg executable-ghcPkg :: (MonadUnliftIO m, MonadLogger m)-       => EnvOverride-       -> WhichCompiler+ghcPkg :: (HasProcessContext env, HasLogFunc env)+       => WhichCompiler        -> [Path Abs Dir]        -> [String]-       -> m (Either ReadProcessException S8.ByteString)-ghcPkg menv wc pkgDbs args = do+       -> RIO env (Either SomeException S8.ByteString)+ghcPkg wc pkgDbs args = do     eres <- go     case eres of-          Left _ -> do-              mapM_ (createDatabase menv wc) pkgDbs-              go-          Right _ -> return eres+      Left _ -> do+        mapM_ (createDatabase wc) pkgDbs+        go+      Right _ -> return eres   where-    go = tryProcessStdout Nothing menv (ghcPkgExeName wc) args'+    go = fmap (fmap BL.toStrict)+       $ tryAny+       $ proc (ghcPkgExeName wc) args' readProcessStdout_     args' = packageDbFlags pkgDbs ++ args  -- | Create a package database in the given directory, if it doesn't exist.-createDatabase :: (MonadUnliftIO m, MonadLogger m)-               => EnvOverride -> WhichCompiler -> Path Abs Dir -> m ()-createDatabase menv wc db = do+createDatabase+  :: (HasProcessContext env, HasLogFunc env)+  => WhichCompiler -> Path Abs Dir -> RIO env ()+createDatabase wc db = do     exists <- doesFileExist (db </> $(mkRelFile "package.cache"))     unless exists $ do         -- ghc-pkg requires that the database directory does not exist@@ -86,11 +89,10 @@         dirExists <- doesDirExist db         args <- if dirExists             then do-                logWarn $ T.pack $ concat-                    [ "The package database located at "-                    , toFilePath db-                    , " is corrupted (missing its package.cache file)."-                    ]+                logWarn $+                    "The package database located at " <>+                    fromString (toFilePath db) <>+                    " is corrupted (missing its package.cache file)."                 logWarn "Proceeding with a recache"                 return ["--package-db", toFilePath db, "recache"]             else do@@ -99,12 +101,9 @@                 -- finding out it isn't the hard way                 ensureDir (parent db)                 return ["init", toFilePath db]-        eres <- tryProcessStdout Nothing menv (ghcPkgExeName wc) args-        case eres of-            Left e -> do-                logError $ T.pack $ "Unable to create package database at " ++ toFilePath db-                throwIO e-            Right _ -> return ()+        void $ proc (ghcPkgExeName wc) args $ \pc ->+          readProcessStdout_ pc `onException`+          logError ("Unable to create package database at " <> fromString (toFilePath db))  -- | Get the name to use for "ghc-pkg", given the compiler version. ghcPkgExeName :: WhichCompiler -> String@@ -124,51 +123,47 @@  -- | Get the value of a field of the package. findGhcPkgField-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride-    -> WhichCompiler+    :: (HasProcessContext env, HasLogFunc env)+    => WhichCompiler     -> [Path Abs Dir] -- ^ package databases     -> String -- ^ package identifier, or GhcPkgId     -> Text-    -> m (Maybe Text)-findGhcPkgField menv wc pkgDbs name field = do+    -> RIO env (Maybe Text)+findGhcPkgField wc pkgDbs name field = do     result <-         ghcPkg-            menv             wc             pkgDbs             ["field", "--simple-output", name, T.unpack field]     return $         case result of             Left{} -> Nothing-            Right lbs ->-                fmap (stripCR . T.decodeUtf8) $ listToMaybe $ S8.lines lbs+            Right bs ->+                fmap (stripCR . T.decodeUtf8) $ listToMaybe $ S8.lines bs  -- | Get the version of the package-findGhcPkgVersion :: (MonadUnliftIO m, MonadLogger m)-                  => EnvOverride-                  -> WhichCompiler+findGhcPkgVersion :: (HasProcessContext env, HasLogFunc env)+                  => WhichCompiler                   -> [Path Abs Dir] -- ^ package databases                   -> PackageName-                  -> m (Maybe Version)-findGhcPkgVersion menv wc pkgDbs name = do-    mv <- findGhcPkgField menv wc pkgDbs (packageNameString name) "version"+                  -> RIO env (Maybe Version)+findGhcPkgVersion wc pkgDbs name = do+    mv <- findGhcPkgField wc pkgDbs (packageNameString name) "version"     case mv of         Just !v -> return (parseVersion v)         _ -> return Nothing -unregisterGhcPkgId :: (MonadUnliftIO m, MonadLogger m)-                    => EnvOverride-                    -> WhichCompiler+unregisterGhcPkgId :: (HasProcessContext env, HasLogFunc env)+                    => WhichCompiler                     -> CompilerVersion 'CVActual                     -> Path Abs Dir -- ^ package database                     -> GhcPkgId                     -> PackageIdentifier-                    -> m ()-unregisterGhcPkgId menv wc cv pkgDb gid ident = do-    eres <- ghcPkg menv wc [pkgDb] args+                    -> RIO env ()+unregisterGhcPkgId wc cv pkgDb gid ident = do+    eres <- ghcPkg wc [pkgDb] args     case eres of-        Left e -> logWarn $ T.pack $ show e+        Left e -> logWarn $ displayShow e         Right _ -> return ()   where     -- TODO ideally we'd tell ghc-pkg a GhcPkgId instead@@ -179,12 +174,11 @@             _ -> ["--ipid", ghcPkgIdString gid])  -- | Get the version of Cabal from the global package database.-getCabalPkgVer :: (MonadUnliftIO m, MonadLogger m)-               => EnvOverride -> WhichCompiler -> m Version-getCabalPkgVer menv wc = do+getCabalPkgVer :: (HasProcessContext env, HasLogFunc env)+               => WhichCompiler -> RIO env Version+getCabalPkgVer wc = do     logDebug "Getting Cabal package version"     mres <- findGhcPkgVersion-        menv         wc         [] -- global DB         cabalPackageName
src/Stack/Ghci.hs view
@@ -17,26 +17,28 @@     , ghci     ) where -import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import           Control.Monad.State.Strict (State, execState, get, modify) import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy as LBS import           Data.List-import           Data.List.Extra (nubOrd) import qualified Data.Map.Strict as M import qualified Data.Set as S import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TLE import qualified Distribution.PackageDescription as C-import qualified Distribution.Text as C import           Path import           Path.Extra (toFilePathNoTrailingSep) import           Path.IO hiding (withSystemTempDir)+import qualified RIO+import           RIO.Process (HasProcessContext, exec, proc, readProcess_) import           Stack.Build import           Stack.Build.Installed import           Stack.Build.Source import           Stack.Build.Target import           Stack.Config (getLocalPackages) import           Stack.Constants.Config-import           Stack.Exec import           Stack.Ghci.Script import           Stack.Package import           Stack.PrettyPrint@@ -44,11 +46,13 @@ import           Stack.Types.Compiler import           Stack.Types.Config import           Stack.Types.FlagName+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Runner import           System.IO (putStrLn, putStr, getLine)+import           System.IO.Temp (getCanonicalTemporaryDirectory)  #ifndef WINDOWS import qualified System.Posix.Files as Posix@@ -76,14 +80,22 @@     { ghciPkgName :: !PackageName     , ghciPkgOpts :: ![(NamedComponent, BuildInfoOpts)]     , ghciPkgDir :: !(Path Abs Dir)-    , ghciPkgModules :: !(Set ModuleName)-    , ghciPkgModFiles :: !(Set (Path Abs File)) -- ^ Module file paths.+    , ghciPkgModules :: !ModuleMap     , ghciPkgCFiles :: !(Set (Path Abs File)) -- ^ C files.     , ghciPkgMainIs :: !(Map NamedComponent (Set (Path Abs File)))     , ghciPkgTargetFiles :: !(Maybe (Set (Path Abs File)))     , ghciPkgPackage :: !Package     } deriving Show +-- Mapping from a module name to a map with all of the paths that use+-- that name. Each of those paths is associated with a set of components+-- that contain it. Purpose of this complex structure is for use in+-- 'checkForDuplicateModules'.+type ModuleMap = Map ModuleName (Map (Path Abs File) (Set (PackageName, NamedComponent)))++unionModuleMaps :: [ModuleMap] -> ModuleMap+unionModuleMaps = M.unionsWith (M.unionWith S.union)+ data GhciException     = InvalidPackageOption String     | LoadingDuplicateModules@@ -259,19 +271,18 @@     if (ghciSkipIntermediate && not ghciLoadLocalDeps) || null extraLoadDeps         then return directlyWanted         else do-            let extraList = T.intercalate ", " (map (packageNameText . fst) extraLoadDeps)+            let extraList =+                  mconcat $ intersperse ", " (map (RIO.display . fst) extraLoadDeps)             if ghciLoadLocalDeps-                then logInfo $ T.concat-                    [ "The following libraries will also be loaded into GHCi because "-                    , "they are local dependencies of your targets, and you specified --load-local-deps:\n    "-                    , extraList-                    ]-                else logInfo $ T.concat-                    [ "The following libraries will also be loaded into GHCi because "-                    , "they are intermediate dependencies of your targets:\n    "-                    , extraList-                    , "\n(Use --skip-intermediate-deps to omit these)"-                    ]+                then logInfo $+                  "The following libraries will also be loaded into GHCi because " <>+                  "they are local dependencies of your targets, and you specified --load-local-deps:\n    " <>+                  extraList+                else logInfo $+                  "The following libraries will also be loaded into GHCi because " <>+                  "they are intermediate dependencies of your targets:\n    " <>+                  extraList <>+                  "\n(Use --skip-intermediate-deps to omit these)"             return (directlyWanted ++ extraLoadDeps)  getAllNonLocalTargets@@ -323,12 +334,13 @@           fromMaybe (not (null pkgs && null exposePackages)) ghciHidePackages         hidePkgOpts =           if shouldHidePackages-            then "-hide-all-packages" :+            then+              ["-hide-all-packages"] ++               -- This is necessary, because current versions of ghci               -- will entirely fail to start if base isn't visible. This               -- is because it tries to use the interpreter to set               -- buffering options on standard IO.-              "-package" : "base" :+              (if null targets then ["-package", "base"] else []) ++               concatMap (\n -> ["-package", packageNameString n]) exposePackages             else []         oneWordOpts bio@@ -346,17 +358,17 @@     unless (null omittedOpts) $         logWarn             ("The following GHC options are incompatible with GHCi and have not been passed to it: " <>-             T.unwords (map T.pack (nubOrd omittedOpts)))+             mconcat (intersperse " " (fromString <$> nubOrd omittedOpts)))     oiDir <- view objectInterfaceDirL     let odir =             [ "-odir=" <> toFilePathNoTrailingSep oiDir             , "-hidir=" <> toFilePathNoTrailingSep oiDir ]-    logInfo-        ("Configuring GHCi with the following packages: " <>-         T.intercalate ", " (map (packageNameText . ghciPkgName) pkgs))+    logInfo $+      "Configuring GHCi with the following packages: " <>+      mconcat (intersperse ", " (map (RIO.display . ghciPkgName) pkgs))     let execGhci extras = do-            menv <- liftIO $ configEnvOverride config defaultEnvSettings-            execSpawn menv+            menv <- liftIO $ configProcessContextSettings config defaultEnvSettings+            withProcessContext menv $ exec                  (fromMaybe (compilerExeName wc) ghciGhcCommand)                  (("--interactive" : ) $                  -- This initial "-i" resets the include directories to@@ -372,37 +384,68 @@             -- multiple packages.             case pkgs of                 [_] -> do-                    menv <- liftIO $ configEnvOverride config defaultEnvSettings-                    output <- execObserve menv (fromMaybe (compilerExeName wc) ghciGhcCommand) ["--version"]+                    menv <- liftIO $ configProcessContextSettings config defaultEnvSettings+                    output <- withProcessContext menv+                            $ runGrabFirstLine (fromMaybe (compilerExeName wc) ghciGhcCommand) ["--version"]                     return $ "Intero" `isPrefixOf` output                 _ -> return False-    withSystemTempDir "ghci" $ \tmpDirectory -> do-        macrosOptions <- writeMacrosFile tmpDirectory pkgs-        if ghciNoLoadModules-            then execGhci macrosOptions-            else do-                checkForDuplicateModules pkgs-                isIntero <- checkIsIntero-                bopts <- view buildOptsL-                mainFile <- figureOutMainFile bopts mainIsTargets targets pkgs-                scriptPath <- writeGhciScript tmpDirectory (renderScript isIntero pkgs mainFile ghciOnlyMain extraFiles)-                execGhci (macrosOptions ++ ["-ghci-script=" <> toFilePath scriptPath])+    -- Since usage of 'exec' does not return, we cannot do any cleanup+    -- on ghci exit. So, instead leave the generated files. To make this+    -- more efficient and avoid gratuitous generation of garbage, the+    -- file names are determined by hashing. This also has the nice side+    -- effect of making it possible to copy the ghci invocation out of+    -- the log and have it still work.+    tmpDirectory <-+        (</> $(mkRelDir "haskell-stack-ghci")) <$>+        (parseAbsDir =<< liftIO getCanonicalTemporaryDirectory)+    ensureDir tmpDirectory+    macrosOptions <- writeMacrosFile tmpDirectory pkgs+    if ghciNoLoadModules+        then execGhci macrosOptions+        else do+            checkForDuplicateModules pkgs+            isIntero <- checkIsIntero+            bopts <- view buildOptsL+            mainFile <- figureOutMainFile bopts mainIsTargets targets pkgs+            scriptOptions <- writeGhciScript tmpDirectory (renderScript isIntero pkgs mainFile ghciOnlyMain extraFiles)+            execGhci (macrosOptions ++ scriptOptions) -writeMacrosFile :: (MonadIO m) => Path Abs Dir -> [GhciPkgInfo] -> m [String]-writeMacrosFile tmpDirectory packages = do-    preprocessCabalMacros packages macrosFile-  where-    macrosFile = tmpDirectory </> $(mkRelFile "cabal_macros.h")+writeMacrosFile :: HasRunner env => Path Abs Dir -> [GhciPkgInfo] -> RIO env [String]+writeMacrosFile tmpDirectory pkgs = do+    fps <- fmap (nubOrd . catMaybes . concat) $+        forM pkgs $ \pkg -> forM (ghciPkgOpts pkg) $ \(_, bio) -> do+            let cabalMacros = bioCabalMacros bio+            exists <- liftIO $ doesFileExist cabalMacros+            if exists+                then return $ Just cabalMacros+                else do+                    prettyWarnL ["Didn't find expected autogen file:", display cabalMacros]+                    return Nothing+    files <- liftIO $ mapM (S8.readFile . toFilePath) fps+    if null files then return [] else do+        out <- liftIO $ writeHashedFile tmpDirectory $(mkRelFile "cabal_macros.h") $+            S8.concat $ map (<> "\n#undef CURRENT_PACKAGE_KEY\n#undef CURRENT_COMPONENT_ID\n") files+        return ["-optP-include", "-optP" <> toFilePath out] -writeGhciScript :: (MonadIO m) => Path Abs Dir -> GhciScript -> m (Path Abs File)+writeGhciScript :: (MonadIO m) => Path Abs Dir -> GhciScript -> m [String] writeGhciScript tmpDirectory script = do-    liftIO $ scriptToFile scriptPath script+    scriptPath <- liftIO $ writeHashedFile tmpDirectory $(mkRelFile "ghci-script") $+        LBS.toStrict $ scriptToLazyByteString script+    let scriptFilePath = toFilePath scriptPath     setScriptPerms scriptFilePath-    return scriptPath-  where-    scriptPath = tmpDirectory </> $(mkRelFile "ghci-script")-    scriptFilePath = toFilePath scriptPath+    return ["-ghci-script=" <> scriptFilePath] +writeHashedFile :: Path Abs Dir -> Path Rel File -> ByteString -> IO (Path Abs File)+writeHashedFile tmpDirectory relFile contents = do+    relSha <- shaPathForBytes contents+    let outDir = tmpDirectory </> relSha+        outFile = outDir </> relFile+    alreadyExists <- doesFileExist outFile+    unless alreadyExists $ do+        ensureDir outDir+        S8.writeFile (toFilePath outFile) contents+    return outFile+ renderScript :: Bool -> [GhciPkgInfo] -> Maybe (Path Abs File) -> Bool -> [Path Abs File] -> GhciScript renderScript isIntero pkgs mainFile onlyMain extraFiles = do     let cdPhase = case (isIntero, pkgs) of@@ -416,7 +459,7 @@             Just path -> [Right path]             _ -> []         modulePhase = cmdModule $ S.fromList allModules-        allModules = concatMap (S.toList . ghciPkgModules) pkgs+        allModules = nubOrd $ concatMap (M.keys . ghciPkgModules) pkgs     case getFileTargets pkgs <> extraFiles of         [] ->           if onlyMain@@ -442,23 +485,23 @@ figureOutMainFile bopts mainIsTargets targets0 packages = do     case candidates of         [] -> return Nothing-        [c@(_,_,fp)] -> do logInfo ("Using main module: " <> renderCandidate c)+        [c@(_,_,fp)] -> do logInfo ("Using main module: " <> RIO.display (renderCandidate c))                            return (Just fp)         candidate:_ -> do           borderedWarning $ do             logWarn "The main module to load is ambiguous. Candidates are: "-            forM_ (map renderCandidate candidates) logWarn+            forM_ (map renderCandidate candidates) (logWarn . RIO.display)             logWarn                 "You can specify which one to pick by: "             logWarn                 (" * Specifying targets to stack ghci e.g. stack ghci " <>-                 sampleTargetArg candidate)+                RIO.display ( sampleTargetArg candidate))             logWarn                 (" * Specifying what the main is e.g. stack ghci " <>-                 sampleMainIsArg candidate)+                 RIO.display (sampleMainIsArg candidate))             logWarn                 (" * Choosing from the candidate above [1.." <>-                T.pack (show $ length candidates) <> "]")+                RIO.display (length candidates) <> "]")           liftIO userOption   where     targets = fromMaybe (M.fromList $ map (\(k, (_, x)) -> (k, x)) targets0)@@ -509,6 +552,7 @@     renderComp c =         case c of             CLib -> "lib"+            CInternalLib name -> "internal-lib:" <> name             CExe name -> "exe:" <> name             CTest name -> "test:" <> name             CBench name -> "bench:" <> name@@ -526,9 +570,7 @@     -> [(PackageName, (Path Abs File, Target))]     -> RIO env [GhciPkgInfo] getGhciPkgInfos buildOptsCLI sourceMap addPkgs mfileTargets localTargets = do-    menv <- getMinimalEnvOverride     (installedMap, _, _, _) <- getInstalled-        menv         GetInstalledOpts             { getInstalledProfiling = False             , getInstalledHaddock   = False@@ -602,8 +644,9 @@         { ghciPkgName = packageName pkg         , ghciPkgOpts = M.toList filteredOpts         , ghciPkgDir = parent cabalfp-        , ghciPkgModules = mconcat (M.elems (filterWanted mods))-        , ghciPkgModFiles = mconcat (M.elems (filterWanted (M.map (setMapMaybe dotCabalModulePath) files)))+        , ghciPkgModules = unionModuleMaps $+          map (\(comp, mp) -> M.map (\fp -> M.singleton fp (S.singleton (packageName pkg, comp))) mp)+              (M.toList (filterWanted mods))         , ghciPkgMainIs = M.map (setMapMaybe dotCabalMainPath) files         , ghciPkgCFiles = mconcat (M.elems (filterWanted (M.map (setMapMaybe dotCabalCFilePath) files)))         , ghciPkgTargetFiles = mfileTargets >>= M.lookup name@@ -624,13 +667,13 @@     (if boptsBenchmarks bopts then map CBench (S.toList (packageBenchmarks pkg)) else []) wantedPackageComponents _ _ _ = S.empty -checkForIssues :: (MonadThrow m, MonadLogger m) => [GhciPkgInfo] -> m ()+checkForIssues :: HasLogFunc env => [GhciPkgInfo] -> RIO env () checkForIssues pkgs = do     unless (null issues) $ borderedWarning $ do         logWarn "Warning: There are cabal settings for this project which may prevent GHCi from loading your code properly."         logWarn "In some cases it can also load some projects which would otherwise fail to build."         logWarn ""-        mapM_ logWarn $ intercalate [""] issues+        mapM_ (logWarn . RIO.display) $ intercalate [""] issues         logWarn ""         logWarn "To resolve, remove the flag(s) from the cabal file(s) and instead put them at the top of the haskell files."         logWarn ""@@ -687,7 +730,7 @@         , (c, bio) <- ghciPkgOpts pkg         ] -borderedWarning :: MonadLogger m => m a -> m a+borderedWarning :: HasLogFunc env => RIO env a -> RIO env a borderedWarning f = do     logWarn ""     logWarn "* * * * * * * *"@@ -696,20 +739,28 @@     logWarn ""     return x -checkForDuplicateModules :: (MonadThrow m, MonadLogger m) => [GhciPkgInfo] -> m ()+-- TODO: Should this also tell the user the filepaths, not just the+-- module name?+checkForDuplicateModules :: HasRunner env => [GhciPkgInfo] -> RIO env () checkForDuplicateModules pkgs = do     unless (null duplicates) $ do         borderedWarning $ do-            logWarn "The following modules are present in multiple packages:"-            forM_ duplicates $ \(mn, pns) -> do-                logWarn (" * " <> T.pack mn <> " (in " <> T.intercalate ", " (map packageNameText pns) <> ")")+            prettyError $ "Multiple files use the same module name:" <>+              line <> bulletedList (map prettyDuplicate duplicates)         throwM LoadingDuplicateModules   where-    duplicates, allModules :: [(String, [PackageName])]-    duplicates = filter (not . null . tail . snd) allModules-    allModules =-        M.toList $ M.fromListWith (++) $-        concatMap (\pkg -> map ((, [ghciPkgName pkg]) . C.display) (S.toList (ghciPkgModules pkg))) pkgs+    duplicates :: [(ModuleName, Map (Path Abs File) (Set (PackageName, NamedComponent)))]+    duplicates =+      filter (\(_, mp) -> M.size mp > 1) $+      M.toList $+      unionModuleMaps (map ghciPkgModules pkgs)+    prettyDuplicate :: (ModuleName, Map (Path Abs File) (Set (PackageName, NamedComponent))) -> AnsiDoc+    prettyDuplicate (mn, mp) =+      styleError (display mn) <+> "found at the following paths" <> line <>+      bulletedList (map fileDuplicate (M.toList mp))+    fileDuplicate :: (Path Abs File, Set (PackageName, NamedComponent)) -> AnsiDoc+    fileDuplicate (fp, comps) =+      display fp <+> parens (fillSep (punctuate "," (map display (S.toList comps))))  targetWarnings   :: HasRunner env@@ -730,17 +781,19 @@       , flow "It can still be useful to specify these, as they will be passed to ghci via -package flags."       ]   when (null localTargets && isNothing mfileTargets) $-      prettyWarn $ vsep-          [ flow "No local targets specified, so ghci will not use any options from your package.yaml / *.cabal files."+      prettyNote $ vsep+          [ flow "No local targets specified, so a plain ghci will be started with no package hiding or package options."           , ""-          , flow "Potential ways to resolve this:"+          , flow "If you want to use package hiding and options, then you can try one of the following:"+          , ""           , bulletedList               [ fillSep-                  [ flow "If you want to use the package.yaml / *.cabal package in the current directory, use"+                  [ flow "If you want to start a different project configuration than" <+> display stackYaml <> ", then you can use"                   , styleShell "stack init"-                  , flow "to create a new stack.yaml."+                  , flow "to create a new stack.yaml for the packages in the current directory."+                  , line                   ]-              , flow "Add to the 'packages' field of" <+> display stackYaml+              , flow "If you want to use the project configuration at" <+> display stackYaml <> ", then you can add to its 'packages' field."               ]           , ""           ]@@ -788,14 +841,6 @@             (_, Just PSIndex{}) -> return loadAllDeps             (_, _) -> return False -preprocessCabalMacros :: MonadIO m => [GhciPkgInfo] -> Path Abs File -> m [String]-preprocessCabalMacros pkgs out = liftIO $ do-    let fps = nubOrd (concatMap (mapMaybe (bioCabalMacros . snd) . ghciPkgOpts) pkgs)-    files <- mapM (S8.readFile . toFilePath) fps-    if null files then return [] else do-        S8.writeFile (toFilePath out) $ S8.concat $ map (<> "\n#undef CURRENT_PACKAGE_KEY\n#undef CURRENT_COMPONENT_ID\n") files-        return ["-optP-include", "-optP" <> toFilePath out]- setScriptPerms :: MonadIO m => FilePath -> m () #ifdef WINDOWS setScriptPerms _ = do@@ -826,46 +871,16 @@         TargetAll ProjectPackage -> True         _ -> False --{- Copied from Stack.Ide, may be useful in the future---- | Get options and target files for the given package info.-getPackageOptsAndTargetFiles-    :: (MonadThrow m, MonadIO m, MonadReader env m, HasEnvConfig env)-    => Path Abs Dir -> GhciPkgInfo -> m ([FilePath], [FilePath])-getPackageOptsAndTargetFiles pwd pkg = do-    dist <- distDirFromDir (ghciPkgDir pkg)-    let autogen = autogenDir dist-    paths_foo <--        liftM-            (autogen </>)-            (parseRelFile-                 ("Paths_" ++ packageNameString (ghciPkgName pkg) ++ ".hs"))-    paths_foo_exists <- doesFileExist paths_foo-    let ghcOptions bio =-            bioOneWordOpts bio ++-            bioOpts bio ++-            bioPackageFlags bio ++-            maybe [] (\cabalMacros -> ["-optP-include", "-optP" <> toFilePath cabalMacros]) (bioCabalMacros bio)+-- | Run a command and grab the first line of stdout, dropping+-- stderr's contexts completely.+runGrabFirstLine :: (HasProcessContext env, HasLogFunc env) => String -> [String] -> RIO env String+runGrabFirstLine cmd0 args =+  proc cmd0 args $ \pc -> do+    (out, _err) <- readProcess_ pc     return-        ( ("--dist-dir=" <> toFilePathNoTrailingSep dist) :-          -- FIXME: use compilerOptionsCabalFlag-          map ("--ghc-option=" ++) (concatMap (ghcOptions . snd) (ghciPkgOpts pkg))-        , mapMaybe-              (fmap toFilePath . stripProperPrefix pwd)-              (S.toList (ghciPkgCFiles pkg) <> S.toList (ghciPkgModFiles pkg) <>-               [paths_foo | paths_foo_exists]))---- | List load targets for a package target.-targetsCmd :: Text -> GlobalOpts -> IO ()-targetsCmd target go@GlobalOpts{..} =-    withBuildConfig go $-    do let boptsCli = defaultBuildOptsCLI { boptsCLITargets = [target] }-       (_realTargets,_,pkgs) <- ghciSetup (ideGhciOpts boptsCli)-       pwd <- getCurrentDir-       targets <--           fmap-               (concat . snd . unzip)-               (mapM (getPackageOptsAndTargetFiles pwd) pkgs)-       forM_ targets (liftIO . putStrLn)--}+      $ TL.unpack+      $ TL.filter (/= '\r')+      $ TL.concat+      $ take 1+      $ TL.lines+      $ TLE.decodeUtf8With lenientDecode out
src/Stack/Ghci/Script.hs view
@@ -14,22 +14,22 @@   , scriptToFile   ) where -import           Data.ByteString.Lazy (ByteString)-import           Data.ByteString.Builder+import           Data.ByteString.Builder (toLazyByteString) import           Data.List import qualified Data.Set as S-import           Data.Text.Encoding (encodeUtf8Builder) import           Path-import           Stack.Prelude hiding (ByteString)+import           Stack.Prelude import           System.IO (BufferMode (..), hSetBinaryMode)  import           Distribution.ModuleName hiding (toFilePath)  newtype GhciScript = GhciScript { unGhciScript :: [GhciCommand] } +instance Semigroup GhciScript where+  GhciScript xs <> GhciScript ys = GhciScript (ys <> xs) instance Monoid GhciScript where   mempty = GhciScript []-  (GhciScript xs) `mappend` (GhciScript ys) = GhciScript (ys <> xs)+  mappend = (<>)  data GhciCommand   = Add (Set (Either ModuleName (Path Abs File)))@@ -46,7 +46,7 @@ cmdModule :: Set ModuleName -> GhciScript cmdModule = GhciScript . (:[]) . Module -scriptToLazyByteString :: GhciScript -> ByteString+scriptToLazyByteString :: GhciScript -> LByteString scriptToLazyByteString = toLazyByteString . scriptToBuilder  scriptToBuilder :: GhciScript -> Builder@@ -65,30 +65,27 @@  -- Command conversion -fromText :: Text -> Builder-fromText = encodeUtf8Builder- commandToBuilder :: GhciCommand -> Builder  commandToBuilder (Add modules)   | S.null modules = mempty   | otherwise      =-       fromText ":add "-    <> mconcat (intersperse (fromText " ") $-         fmap (stringUtf8 . quoteFileName . either (mconcat . intersperse "." . components) toFilePath)+       ":add "+    <> mconcat (intersperse " " $+         fmap (fromString . quoteFileName . either (mconcat . intersperse "." . components) toFilePath)               (S.toAscList modules))-    <> fromText "\n"+    <> "\n"  commandToBuilder (CdGhc path) =-  fromText ":cd-ghc " <> stringUtf8 (quoteFileName (toFilePath path)) <> fromText "\n"+  ":cd-ghc " <> fromString (quoteFileName (toFilePath path)) <> "\n"  commandToBuilder (Module modules)-  | S.null modules = fromText ":module +\n"+  | S.null modules = ":module +\n"   | otherwise      =-       fromText ":module + "-    <> mconcat (intersperse (fromText " ")-        $ (stringUtf8 . quoteFileName . mconcat . intersperse "." . components) <$> S.toAscList modules)-    <> fromText "\n"+       ":module + "+    <> mconcat (intersperse " "+        $ fromString . quoteFileName . mconcat . intersperse "." . components <$> S.toAscList modules)+    <> "\n"  -- | Make sure that a filename with spaces in it gets the proper quotes. quoteFileName :: String -> String
src/Stack/Hoogle.hs view
@@ -9,12 +9,12 @@     ) where  import           Stack.Prelude-import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy.Char8 as BL8 import           Data.Char (isSpace) import           Data.List (find) import qualified Data.Set as Set import qualified Data.Text as T-import           Lens.Micro+import           Path (parseAbsFile) import           Path.IO hiding (findExecutable) import qualified Stack.Build import           Stack.Fetch@@ -24,16 +24,20 @@ import           Stack.Types.PackageName import           Stack.Types.Version import           System.Exit-import           System.Process.Read (resetExeCache, tryProcessStdout, findExecutable)-import           System.Process.Run+import           RIO.Process  -- | Hoogle command.-hoogleCmd :: ([String],Bool,Bool) -> GlobalOpts -> IO ()-hoogleCmd (args,setup,rebuild) go = withBuildConfig go $ do+hoogleCmd :: ([String],Bool,Bool,Bool) -> GlobalOpts -> IO ()+hoogleCmd (args,setup,rebuild,startServer) go = withBuildConfig go $ do     hooglePath <- ensureHoogleInPath     generateDbIfNeeded hooglePath-    runHoogle hooglePath args+    runHoogle hooglePath args'   where+    args' :: [String]+    args' = if startServer+                 then ["server", "--local", "--port", "8080"]+                 else []+            ++ args     generateDbIfNeeded :: Path Abs File -> RIO EnvConfig ()     generateDbIfNeeded hooglePath = do         databaseExists <- checkDatabaseExists@@ -104,18 +108,18 @@                           | ver >= hoogleMinVersion -> Right ident                         _ -> Left hoogleMinIdent)         case hooglePackageIdentifier of-            Left{} ->-                logInfo-                    ("Minimum " <> packageIdentifierText hoogleMinIdent <>-                     " is not in your index. Installing the minimum version.")-            Right ident ->-                logInfo-                    ("Minimum version is " <> packageIdentifierText hoogleMinIdent <>-                     ". Found acceptable " <>-                     packageIdentifierText ident <>-                     " in your index, installing it.")+            Left{} -> logInfo $+              "Minimum " <>+              display hoogleMinIdent <>+              " is not in your index. Installing the minimum version."+            Right ident -> logInfo $+              "Minimum version is " <>+              display hoogleMinIdent <>+              ". Found acceptable " <>+              display ident <>+              " in your index, installing it."         config <- view configL-        menv <- liftIO $ configEnvOverride config envSettings+        menv <- liftIO $ configProcessContextSettings config envSettings         liftIO             (catch                  (withBuildConfigAndLock@@ -133,22 +137,18 @@                                 }))                  (\(e :: ExitCode) ->                        case e of-                           ExitSuccess -> resetExeCache menv+                           ExitSuccess -> runRIO menv resetExeCache                            _ -> throwIO e))     runHoogle :: Path Abs File -> [String] -> RIO EnvConfig ()     runHoogle hooglePath hoogleArgs = do         config <- view configL-        menv <- liftIO $ configEnvOverride config envSettings+        menv <- liftIO $ configProcessContextSettings config envSettings         dbpath <- hoogleDatabasePath         let databaseArg = ["--database=" ++ toFilePath dbpath]-        runCmd-            Cmd-             { cmdDirectoryToRunIn = Nothing-             , cmdCommandToRun = toFilePath hooglePath-             , cmdEnvOverride = menv-             , cmdCommandLineArguments = hoogleArgs ++ databaseArg-             }-            Nothing+        withProcessContext menv $ proc+          (toFilePath hooglePath)+          (hoogleArgs ++ databaseArg)+          runProcess_     bail :: RIO EnvConfig a     bail = liftIO (exitWith (ExitFailure (-1)))     checkDatabaseExists = do@@ -157,45 +157,47 @@     ensureHoogleInPath :: RIO EnvConfig (Path Abs File)     ensureHoogleInPath = do         config <- view configL-        menv <- liftIO $ configEnvOverride config envSettings-        mhooglePath <- findExecutable menv "hoogle"+        menv <- liftIO $ configProcessContextSettings config envSettings+        mhooglePath <- runRIO menv $ findExecutable "hoogle"         eres <- case mhooglePath of-            Nothing -> return $ Left "Hoogle isn't installed."-            Just hooglePath -> do-                result <- tryProcessStdout Nothing menv (toFilePath hooglePath) ["--numeric-version"]+            Left _ -> return $ Left "Hoogle isn't installed."+            Right hooglePath -> do+                result <- withProcessContext menv+                        $ proc hooglePath ["--numeric-version"]+                        $ tryAny . readProcessStdout_                 let unexpectedResult got = Left $ T.concat                         [ "'"-                        , T.pack (toFilePath hooglePath)+                        , T.pack hooglePath                         , " --numeric-version' did not respond with expected value. Got: "                         , got                         ]                 return $ case result of                     Left err -> unexpectedResult $ T.pack (show err)-                    Right bs -> case parseVersionFromString (takeWhile (not . isSpace) (S8.unpack bs)) of-                        Nothing -> unexpectedResult $ T.pack (S8.unpack bs)+                    Right bs -> case parseVersionFromString (takeWhile (not . isSpace) (BL8.unpack bs)) of+                        Nothing -> unexpectedResult $ T.pack (BL8.unpack bs)                         Just ver                             | ver >= hoogleMinVersion -> Right hooglePath                             | otherwise -> Left $ T.concat                                 [ "Installed Hoogle is too old, "-                                , T.pack (toFilePath hooglePath)+                                , T.pack hooglePath                                 , " is version "                                 , versionText ver                                 , " but >= 5.0 is required."                                 ]         case eres of-            Right hooglePath -> return hooglePath+            Right hooglePath -> parseAbsFile hooglePath             Left err                 | setup -> do-                    logWarn $ err <> " Automatically installing (use --no-setup to disable) ..."+                    logWarn $ display err <> " Automatically installing (use --no-setup to disable) ..."                     installHoogle-                    mhooglePath' <- findExecutable menv "hoogle"+                    mhooglePath' <- runRIO menv $ findExecutable "hoogle"                     case mhooglePath' of-                        Just hooglePath -> return hooglePath-                        Nothing -> do+                        Right hooglePath -> parseAbsFile hooglePath+                        Left _ -> do                             logWarn "Couldn't find hoogle in path after installing.  This shouldn't happen, may be a bug."                             bail                 | otherwise -> do-                    logWarn $ err <> " Not installing it due to --no-setup."+                    logWarn $ display err <> " Not installing it due to --no-setup."                     bail     envSettings =         EnvSettings
src/Stack/IDE.hs view
@@ -17,8 +17,7 @@ import           Stack.Package (readPackageUnresolvedDir, gpdPackageName) import           Stack.Prelude import           Stack.Types.Config-import           Stack.Types.Package-import           Stack.Types.PackageName+import           Stack.Types.NamedComponent  -- | List the packages inside the current project. listPackages :: HasEnvConfig env => RIO env ()@@ -29,13 +28,13 @@     packageDirs <- liftM (map lpvRoot . Map.elems . lpProject) getLocalPackages     forM_ packageDirs $ \dir -> do         (gpd, _) <- readPackageUnresolvedDir dir False-        (logInfo . packageNameText) (gpdPackageName gpd)+        (logInfo . display) (gpdPackageName gpd)  -- | List the targets in the current project. listTargets :: HasEnvConfig env => RIO env () listTargets =     do rawLocals <- lpProject <$> getLocalPackages-       logInfo+       logInfo $ display            (T.intercalate                 "\n"                 (map
src/Stack/Image.hs view
@@ -25,7 +25,7 @@ import           Stack.PrettyPrint import           Stack.Types.Config import           Stack.Types.Image-import           System.Process.Run+import           RIO.Process  -- | Stages the executables & additional content in a staging -- directory under '.stack-work'@@ -130,8 +130,7 @@ createDockerImage     :: HasConfig env     => ImageDockerOpts -> Path Abs Dir -> RIO env ()-createDockerImage dockerConfig dir = do-    menv <- getMinimalEnvOverride+createDockerImage dockerConfig dir =     case imgDockerBase dockerConfig of         Nothing -> throwM StackImageDockerBaseUnspecifiedException         Just base -> do@@ -146,14 +145,13 @@                           (imageName (parent . parent . parent $ dir))                           (imgDockerImageName dockerConfig)                     , toFilePathNoTrailingSep dir]-            callProcess (Cmd Nothing "docker" menv args)+            proc "docker" args runProcess_  -- | Extend the general purpose docker image with entrypoints (if specified). extendDockerImageWithEntrypoint     :: HasConfig env     => ImageDockerOpts -> Path Abs Dir -> RIO env () extendDockerImageWithEntrypoint dockerConfig dir = do-    menv <- getMinimalEnvOverride     let dockerImageName =             fromMaybe                 (imageName (parent . parent . parent $ dir))@@ -174,15 +172,13 @@                                        , "ENTRYPOINT [\"/usr/local/bin/" ++                                          ep ++ "\"]"                                        , "CMD []"]))))-                         callProcess-                             (Cmd-                                  Nothing+                         proc                                   "docker"-                                  menv                                   [ "build"                                   , "-t"                                   , dockerImageName ++ "-" ++ ep-                                  , toFilePathNoTrailingSep dir]))+                                  , toFilePathNoTrailingSep dir]+                                  runProcess_)  -- | Fail with friendly error if project root not set. fromMaybeProjectRoot :: Maybe (Path Abs Dir) -> Path Abs Dir
src/Stack/Init.hs view
@@ -72,7 +72,7 @@         find  = findCabalDirs (includeSubDirs initOpts)         dirs' = if null dirs then [currDir] else dirs     logInfo "Looking for .cabal or package.yaml files to use to init the project."-    cabaldirs <- (Set.toList . Set.unions) <$> mapM find dirs'+    cabaldirs <- Set.toList . Set.unions <$> mapM find dirs'     (bundle, dupPkgs)  <- cabalPackagesCheck cabaldirs noPkgMsg Nothing      (sd, flags, extraDeps, rbundle) <- getDefaultResolver whichCmd dest initOpts@@ -139,31 +139,31 @@         toPkg dir = PLFilePath $ makeRelDir dir         indent t = T.unlines $ fmap ("    " <>) (T.lines t) -    logInfo $ "Initialising configuration using resolver: " <> sdResolverName sd+    logInfo $ "Initialising configuration using resolver: " <> display (sdResolverName sd)     logInfo $ "Total number of user packages considered: "-               <> T.pack (show (Map.size bundle + length dupPkgs))+               <> display (Map.size bundle + length dupPkgs)      when (dupPkgs /= []) $ do         logWarn $ "Warning! Ignoring "-                   <> T.pack (show $ length dupPkgs)+                   <> displayShow (length dupPkgs)                    <> " duplicate packages:"         rels <- mapM makeRel dupPkgs-        logWarn $ indent $ showItems rels+        logWarn $ display $ indent $ showItems rels      when (Map.size ignored > 0) $ do         logWarn $ "Warning! Ignoring "-                   <> T.pack (show $ Map.size ignored)+                   <> displayShow (Map.size ignored)                    <> " packages due to dependency conflicts:"         rels <- mapM makeRel (Map.elems (fmap fst ignored))-        logWarn $ indent $ showItems rels+        logWarn $ display $ indent $ showItems rels      when (Map.size extraDeps > 0) $ do-        logWarn $ "Warning! " <> T.pack (show $ Map.size extraDeps)+        logWarn $ "Warning! " <> displayShow (Map.size extraDeps)                    <> " external dependencies were added."     logInfo $         (if exists then "Overwriting existing configuration file: "          else "Writing configuration to file: ")-        <> T.pack reldest+        <> fromString reldest     liftIO $ L.writeFile (toFilePath dest)            $ B.toLazyByteString            $ renderStackYaml p@@ -239,7 +239,7 @@         [ ("user-message"     , userMsgHelp)         , ("resolver"         , resolverHelp)         , ("packages"         , packageHelp)-        , ("extra-deps"       , "# Dependency packages to be pulled from upstream that are not in the resolver\n# (e.g., acme-missiles-0.3)")+        , ("extra-deps"       , "# Dependency packages to be pulled from upstream that are not in the resolver\n# using the same syntax as the packages field.\n# (e.g., acme-missiles-0.3)")         , ("flags"            , "# Override default flag values for local packages and extra-deps")         , ("extra-package-dbs", "# Extra package databases containing global packages")         ]@@ -262,9 +262,12 @@         , "resolver: nightly-2015-09-21"         , "resolver: ghc-7.10.2"         , "resolver: ghcjs-0.1.0_ghc-7.10.2"-        , "resolver:"-        , " name: custom-snapshot"-        , " location: \"./custom-snapshot.yaml\""+        , ""+        , "The location of a snapshot can be provided as a file or url. Stack assumes"+        , "a snapshot provided as a file might change, whereas a url resource does not."+        , ""+        , "resolver: ./custom-snapshot.yaml"+        , "resolver: https://example.com/snapshots/2018-01-01.yaml"         ]      userMsgHelp = commentHelp@@ -281,14 +284,9 @@         , "   git: https://github.com/commercialhaskell/stack.git"         , "   commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a"         , "- location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a"-        , "  extra-dep: true"         , " subdirs:"         , " - auto-update"         , " - wai"-        , ""-        , "A package marked 'extra-dep: true' will only be built if demanded by a"-        , "non-dependency (i.e. a user package), and its test suites and benchmarks"-        , "will not be run. This is useful for tweaking upstream packages."         ]      footerHelp =@@ -331,7 +329,7 @@         logError ""         logError "    http://docs.haskellstack.org/en/stable/yaml_configuration/"         logError ""-        logError $ "Exception was: " <> T.pack (show e)+        logError $ "Exception was: " <> displayShow e         throwString ""  -- | Get the default resolver value@@ -385,7 +383,7 @@        --   , Extra dependencies        --   , Src packages actually considered) getWorkingResolverPlan whichCmd stackYaml initOpts bundle sd = do-    logInfo $ "Selected resolver: " <> sdResolverName sd+    logInfo $ "Selected resolver: " <> display (sdResolverName sd)     go bundle     where         go info = do@@ -405,13 +403,13 @@                          if length ignored > 1 then do                           logWarn "*** Ignoring packages:"-                          logWarn $ indent $ showItems ignored+                          logWarn $ display $ indent $ showItems ignored                         else                           logWarn $ "*** Ignoring package: "-                                 <> T.pack (packageNameString-                                                (case ignored of-                                                    [] -> error "getWorkingResolverPlan.head"-                                                    x:_ -> x))+                                 <> display+                                      (case ignored of+                                        [] -> error "getWorkingResolverPlan.head"+                                        x:_ -> x)                          go available                     where@@ -454,17 +452,17 @@         BuildPlanCheckFail _ e _             | omitPackages initOpts -> do                 logWarn $ "*** Resolver compiler mismatch: "-                           <> sdResolverName sd-                logWarn $ indent $ T.pack $ show result+                           <> display (sdResolverName sd)+                logWarn $ display $ indent $ T.pack $ show result                 return $ Left $ failedUserPkgs e             | otherwise -> throwM $ ResolverMismatch whichCmd (sdResolverName sd) (show result)     where       resolver = sdResolver sd       indent t  = T.unlines $ fmap ("    " <>) (T.lines t)       warnPartial res = do-          logWarn $ "*** Resolver " <> sdResolverName sd+          logWarn $ "*** Resolver " <> display (sdResolverName sd)                       <> " will need external packages: "-          logWarn $ indent $ T.pack $ show res+          logWarn $ display $ indent $ T.pack $ show res        failedUserPkgs e = Map.keys $ Map.unions (Map.elems (fmap deNeededBy e)) 
+ src/Stack/Ls.hs view
@@ -0,0 +1,267 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Stack.Ls+  ( lsCmd+  , lsParser+  , listDependenciesCmd+  ) where++import Control.Exception (Exception, throw)+import Control.Monad.Catch (MonadThrow)+import Control.Monad.IO.Class (MonadIO, liftIO)+import Control.Monad.Reader (MonadReader)+import Control.Monad (when)+import Data.Aeson+import Stack.Prelude+import Stack.Types.Runner+import qualified Data.Aeson.Types as A+import qualified Data.List as L+import Data.Text hiding (pack, intercalate)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Typeable (Typeable)+import qualified Data.Vector as V+import Network.HTTP.StackClient (httpJSON)+import Network.HTTP.Simple+       (addRequestHeader, getResponseBody, parseRequest,+        setRequestManager)+import Network.HTTP.Types.Header (hAccept)+import qualified Options.Applicative as OA+import Options.Applicative ((<|>))+import Path+import Stack.Runners (withBuildConfig, withBuildConfigDot)+import Stack.Types.Config+import Stack.Dot+import Stack.Options.DotParser (listDepsOptsParser)+import System.Process.PagerEditor (pageText)+import System.Directory (listDirectory)+import System.IO (stderr, hPutStrLn)+import Network.HTTP.Client.TLS (getGlobalManager)++data LsView+    = Local+    | Remote+    deriving (Show, Eq, Ord)++data SnapshotType+    = Lts+    | Nightly+    deriving (Show, Eq, Ord)++data LsCmds+    = LsSnapshot SnapshotOpts+    | LsDependencies ListDepsOpts++data SnapshotOpts = SnapshotOpts+    { soptViewType :: LsView+    , soptLtsSnapView :: Bool+    , soptNightlySnapView :: Bool+    } deriving (Eq, Show, Ord)++newtype LsCmdOpts = LsCmdOpts+    { lsView :: LsCmds+    }++lsParser :: OA.Parser LsCmdOpts+lsParser = LsCmdOpts <$> OA.hsubparser (lsSnapCmd <> lsDepsCmd)++lsCmdOptsParser :: OA.Parser LsCmds+lsCmdOptsParser = LsSnapshot <$> lsViewSnapCmd++lsDepOptsParser :: OA.Parser LsCmds+lsDepOptsParser = LsDependencies <$> listDepsOptsParser++lsViewSnapCmd :: OA.Parser SnapshotOpts+lsViewSnapCmd =+    SnapshotOpts <$>+    (OA.hsubparser (lsViewRemoteCmd <> lsViewLocalCmd) <|> pure Local) <*>+    OA.switch+        (OA.long "lts" <> OA.short 'l' <> OA.help "Only show lts snapshots") <*>+    OA.switch+        (OA.long "nightly" <> OA.short 'n' <>+         OA.help "Only show nightly snapshots")++lsSnapCmd :: OA.Mod OA.CommandFields LsCmds+lsSnapCmd =+    OA.command+        "snapshots"+        (OA.info+             lsCmdOptsParser+             (OA.progDesc "View local snapshot (default option)"))++lsDepsCmd :: OA.Mod OA.CommandFields LsCmds+lsDepsCmd =+    OA.command+        "dependencies"+        (OA.info lsDepOptsParser (OA.progDesc "View the dependencies"))++data Snapshot = Snapshot+    { snapId :: Text+    , snapTitle :: Text+    , snapTime :: Text+    } deriving (Show, Eq, Ord)++data SnapshotData = SnapshotData+    { _snapTotalCounts :: Integer+    , snaps :: [[Snapshot]]+    } deriving (Show, Eq, Ord)++instance FromJSON Snapshot where+    parseJSON o@(Array _) = parseSnapshot o+    parseJSON _ = mempty++instance FromJSON SnapshotData where+    parseJSON (Object s) =+        SnapshotData <$> s .: "totalCount" <*> s .: "snapshots"+    parseJSON _ = mempty++toSnapshot :: [Value] -> Snapshot+toSnapshot [String sid, String stitle, String stime] =+    Snapshot+    { snapId = sid+    , snapTitle = stitle+    , snapTime = stime+    }+toSnapshot val = throw $ ParseFailure val++newtype LsException =+    ParseFailure [Value]+    deriving (Show, Typeable)++instance Exception LsException++parseSnapshot :: Value -> A.Parser Snapshot+parseSnapshot = A.withArray "array of snapshot" (return . toSnapshot . V.toList)++displayTime :: Snapshot -> [Text]+displayTime Snapshot {..} = [snapTime]++displaySnap :: Snapshot -> [Text]+displaySnap Snapshot {..} =+    ["Resolver name: " <> snapId, "\n" <> snapTitle <> "\n\n"]++displaySingleSnap :: [Snapshot] -> Text+displaySingleSnap snapshots =+    case snapshots of+        [] -> mempty+        (x:xs) ->+            let snaps =+                    displayTime x <> ["\n\n"] <> displaySnap x <>+                    L.concatMap displaySnap xs+            in T.concat snaps++renderData :: Bool -> Text -> IO ()+renderData True content = pageText content+renderData False content = T.putStr content++displaySnapshotData :: Bool -> SnapshotData -> IO ()+displaySnapshotData term sdata =+    case L.reverse $ snaps sdata of+        [] -> return ()+        xs ->+            let snaps = T.concat $ L.map displaySingleSnap xs+            in renderData term snaps++filterSnapshotData :: SnapshotData -> SnapshotType -> SnapshotData+filterSnapshotData sdata stype =+    sdata+    { snaps = filterSnapData+    }+  where+    snapdata = snaps sdata+    filterSnapData =+        case stype of+            Lts -> L.map (L.filter (\x -> "lts" `isPrefixOf` snapId x)) snapdata+            Nightly ->+                L.map (L.filter (\x -> "nightly" `isPrefixOf` snapId x)) snapdata++displayLocalSnapshot :: Bool -> [String] -> IO ()+displayLocalSnapshot term xs = renderData term (localSnaptoText xs)++localSnaptoText :: [String] -> Text+localSnaptoText xs = T.intercalate "\n" $ L.map T.pack xs++handleLocal+    :: (MonadIO m, MonadThrow m, MonadReader env m, HasEnvConfig env)+    => LsCmdOpts -> m ()+handleLocal lsOpts = do+    (instRoot :: Path Abs Dir) <- installationRootDeps+    isStdoutTerminal <- view terminalL+    let snapRootDir = parent $ parent instRoot+    snapData' <- liftIO $ listDirectory $ toFilePath snapRootDir+    let snapData = L.sort snapData'+    case lsView lsOpts of+        LsSnapshot SnapshotOpts {..} ->+            case (soptLtsSnapView, soptNightlySnapView) of+                (True, False) ->+                    liftIO $+                    displayLocalSnapshot isStdoutTerminal $+                    L.filter (L.isPrefixOf "lts") snapData+                (False, True) ->+                    liftIO $+                    displayLocalSnapshot isStdoutTerminal $+                    L.filter (L.isPrefixOf "night") snapData+                _ -> liftIO $ displayLocalSnapshot isStdoutTerminal snapData+        LsDependencies _ -> return ()++handleRemote+    :: (MonadIO m, MonadThrow m, MonadReader env m, HasEnvConfig env)+    => LsCmdOpts -> m ()+handleRemote lsOpts = do+    req <- liftIO $ parseRequest urlInfo+    mgr <- liftIO getGlobalManager+    isStdoutTerminal <- view terminalL+    let req' =+            setRequestManager mgr $+            addRequestHeader hAccept "application/json" req+    result <- httpJSON req'+    let snapData = getResponseBody result+    case lsView lsOpts of+        LsSnapshot SnapshotOpts {..} ->+            case (soptLtsSnapView, soptNightlySnapView) of+                (True, False) ->+                    liftIO $+                    displaySnapshotData isStdoutTerminal $+                    filterSnapshotData snapData Lts+                (False, True) ->+                    liftIO $+                    displaySnapshotData isStdoutTerminal $+                    filterSnapshotData snapData Nightly+                _ -> liftIO $ displaySnapshotData isStdoutTerminal snapData+        LsDependencies _ -> return ()+  where+    urlInfo = "https://www.stackage.org/snapshots"++lsCmd :: LsCmdOpts -> GlobalOpts -> IO ()+lsCmd lsOpts go =+    case lsView lsOpts of+        LsSnapshot SnapshotOpts {..} ->+            case soptViewType of+                Local -> withBuildConfig go (handleLocal lsOpts)+                Remote -> withBuildConfig go (handleRemote lsOpts)+        LsDependencies depOpts -> listDependenciesCmd False depOpts go++-- | List the dependencies+listDependenciesCmd :: Bool -> ListDepsOpts -> GlobalOpts -> IO ()+listDependenciesCmd deprecated opts go = do+    when+        deprecated+        (hPutStrLn+             stderr+             "DEPRECATED: Use ls dependencies instead. Will be removed in next major version.")+    withBuildConfigDot (listDepsDotOpts opts) go $ listDependencies opts++lsViewLocalCmd :: OA.Mod OA.CommandFields LsView+lsViewLocalCmd =+    OA.command+        "local"+        (OA.info (pure Local) (OA.progDesc "View local snapshot"))++lsViewRemoteCmd :: OA.Mod OA.CommandFields LsView+lsViewRemoteCmd =+    OA.command+        "remote"+        (OA.info (pure Remote) (OA.progDesc "View remote snapshot"))
src/Stack/New.hs view
@@ -34,12 +34,11 @@ import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding.Error as T (lenientDecode) import qualified Data.Text.IO as T-import qualified Data.Text.Lazy as LT import           Data.Time.Calendar import           Data.Time.Clock import qualified Data.Yaml as Yaml import           Network.HTTP.Download-import           Network.HTTP.Simple+import           Network.HTTP.Simple (Request, HttpException, getResponseStatusCode, getResponseBody) import           Path import           Path.IO import           Stack.Constants@@ -47,9 +46,9 @@ import           Stack.Types.Config import           Stack.Types.PackageName import           Stack.Types.TemplateName-import           System.Process.Run-import           Text.Hastache-import           Text.Hastache.Context+import           RIO.Process+import qualified Text.Mustache as Mustache+import qualified Text.Mustache.Render as Mustache import           Text.Printf import           Text.ProjectTemplate @@ -107,12 +106,12 @@                           RemoteTemp -> "Downloading"          in         logInfo-            (loading <> " template \"" <> templateName template <>+            (loading <> " template \"" <> display (templateName template) <>              "\" to create project \"" <>-             packageNameText project <>+             display (packageNameText project) <>              "\" in " <>              if bare then "the current directory"-                     else T.pack (toFilePath (dirname absDir)) <>+                     else fromString (toFilePath (dirname absDir)) <>              " ...")  data TemplateFrom = LocalTemp | RemoteTemp@@ -145,7 +144,7 @@   where     loadLocalFile :: Path b File -> RIO env Text     loadLocalFile path = do-        logDebug ("Opening local template: \"" <> T.pack (toFilePath path)+        logDebug ("Opening local template: \"" <> fromString (toFilePath path)                                                 <> "\"")         exists <- doesFileExist path         if exists@@ -176,28 +175,28 @@     config <- view configL     currentYear <- do       now <- liftIO getCurrentTime-      (year, _, _) <- return $ toGregorian . utctDay $ now+      let (year, _, _) = toGregorian (utctDay now)       return $ T.pack . show $ year-    let context = M.union (M.union nonceParams extraParams) configParams+    let context = M.unions [nonceParams, nameParams, configParams, yearParam]           where             nameAsVarId = T.replace "-" "_" $ packageNameText project             nameAsModule = T.filter (/= '-') $ T.toTitle $ packageNameText project-            extraParams = M.fromList [ ("name", packageNameText project)-                                     , ("name-as-varid", nameAsVarId)-                                     , ("name-as-module", nameAsModule)-                                     , ("year", currentYear) ]+            nameParams = M.fromList [ ("name", packageNameText project)+                                    , ("name-as-varid", nameAsVarId)+                                    , ("name-as-module", nameAsModule) ]             configParams = configTemplateParams config-    (applied,missingKeys) <--        runWriterT-            (hastacheStr-                 defaultConfig { muEscapeFunc = id }-                 templateText-                 (mkStrContextM (contextFunction context)))+            yearParam = M.singleton "year" currentYear+        etemplateCompiled = Mustache.compileTemplate (T.unpack (templateName template)) templateText+    templateCompiled <- case etemplateCompiled of+      Left e -> throwM $ InvalidTemplate template (show e)+      Right t -> return t+    let (substitutionErrors, applied) = Mustache.checkedSubstitute templateCompiled context+        missingKeys = S.fromList $ concatMap onlyMissingKeys substitutionErrors     unless (S.null missingKeys)-         (logInfo ("\n" <> T.pack (show (MissingParameters project template missingKeys (configUserConfigPath config))) <> "\n"))+         (logInfo ("\n" <> displayShow (MissingParameters project template missingKeys (configUserConfigPath config)) <> "\n"))     files :: Map FilePath LB.ByteString <--        catch (execWriterT $-               yield (T.encodeUtf8 (LT.toStrict applied)) $$+        catch (execWriterT $ runConduit $+               yield (T.encodeUtf8 applied) .|                unpackTemplate receiveMem id               )               (\(e :: ProjectTemplateException) ->@@ -217,20 +216,8 @@                       return (dir </> path, bytes))              (M.toList files))   where-    -- | Does a lookup in the context and returns a moustache value,-    -- on the side, writes out a set of keys that were requested but-    -- not found.-    contextFunction-        :: Monad m-        => Map Text Text-        -> String-        -> WriterT (Set String) m (MuType (WriterT (Set String) m))-    contextFunction context key =-        case M.lookup (T.pack key) context of-            Nothing -> do-                tell (S.singleton key)-                return MuNothing-            Just value -> return (MuVariable value)+    onlyMissingKeys (Mustache.VariableNotFound ks) = map T.unpack ks+    onlyMissingKeys _ = []  -- | Check if we're going to overwrite any existing files. checkForOverwrite :: (MonadIO m, MonadThrow m) => [Path Abs File] -> m ()@@ -252,16 +239,16 @@ -- | Run any initialization functions, such as Git. runTemplateInits     :: HasConfig env-    => Path Abs Dir -> RIO env ()+    => Path Abs Dir+    -> RIO env () runTemplateInits dir = do-    menv <- getMinimalEnvOverride     config <- view configL     case configScmInit config of         Nothing -> return ()         Just Git ->-            catch (callProcess $ Cmd (Just dir) "git" menv ["init"])-                  (\(_ :: ProcessExitedUnsuccessfully) ->-                         logInfo "git init failed to run, ignoring ...")+            withWorkingDir (toFilePath dir) $+            catchAny (proc "git" ["init"] runProcess_)+                  (\_ -> logInfo "git init failed to run, ignoring ...")  -- | Display the set of templates accompanied with description if available. listTemplates :: HasLogFunc env => RIO env ()@@ -295,7 +282,7 @@   resp <- catch (liftM Right $ httpLbs req) (\(ex :: HttpException) -> return . Left $ "Failed to download template info. The HTTP error was: " <> show ex)   case resp >>= is200 of     Left err -> do-      logInfo $ T.pack err+      logInfo $ fromString err       return M.empty     Right resp' ->       case Yaml.decodeEither (LB.toStrict $ getResponseBody resp') :: Either String Object of@@ -421,7 +408,7 @@     show (InvalidTemplate name why) =         "The template \"" <> T.unpack (templateName name) <>         "\" is invalid and could not be used. " <>-        "The error was: \"" <> why <> "\""+        "The error was: " <> why     show (AttemptedOverwrites fps) =         "The template would create the following files, but they already exist:\n" <>         unlines (map (("  " ++) . toFilePath) fps) <>
src/Stack/Nix.hs view
@@ -15,12 +15,12 @@ import           Stack.Prelude import qualified Data.Text as T import           Data.Version (showVersion)+import           Lens.Micro (set) import           Path.IO import qualified Paths_stack as Meta import           Stack.Config (getInNixShell, getInContainer) import           Stack.Config.Nix (nixCompiler) import           Stack.Constants (platformVariantEnvVar,inNixShellEnvVar,inContainerEnvVar)-import           Stack.Exec (exec) import           Stack.Types.Config import           Stack.Types.Docker import           Stack.Types.Nix@@ -28,7 +28,7 @@ import           Stack.Types.Compiler import           System.Environment (getArgs,getExecutablePath,lookupEnv) import qualified System.FilePath  as F-import           System.Process.Read (getEnvOverride)+import           RIO.Process (processContextL, exec)  -- | If Nix is enabled, re-runs the currently running OS command in a Nix container. -- Otherwise, runs the inner action.@@ -63,8 +63,9 @@     -> RIO env (String, [String])     -> RIO env () runShellAndExit mprojectRoot getCompilerVersion getCmdArgs = do-     config <- view configL-     envOverride <- getEnvOverride (configPlatform config)+   config <- view configL+   envOverride <- view processContextL+   local (set processContextL envOverride) $ do      (cmnd,args) <- fmap (escape *** map escape) getCmdArgs      mshellFile <-          traverse (resolveFile (fromMaybeProjectRoot mprojectRoot)) $@@ -73,7 +74,7 @@      inContainer <- getInContainer      ghc <- either throwIO return $ nixCompiler compilerVersion      let pkgsInConfig = nixPackages (configNix config)-         pkgs = pkgsInConfig ++ [ghc, "git", "gcc"]+         pkgs = pkgsInConfig ++ [ghc, "git", "gcc", "gmp"]          pkgsStr = "[" <> T.intercalate " " pkgs <> "]"          pureShell = nixPureShell (configNix config)          addGCRoots = nixAddGCRoots (configNix config)@@ -113,12 +114,12 @@                            -- Using --run instead of --command so we cannot                            -- end up in the nix-shell if stack build is Ctrl-C'd      pathVar <- liftIO $ lookupEnv "PATH"-     logDebug $ "PATH is: " <> T.pack (show pathVar)+     logDebug $ "PATH is: " <> displayShow pathVar      logDebug $        "Using a nix-shell environment " <> (case mshellFile of-            Just path -> "from file: " <> T.pack (toFilePath path)-            Nothing -> "with nix packages: " <> T.intercalate ", " pkgs)-     exec envOverride "nix-shell" fullArgs+            Just path -> "from file: " <> fromString (toFilePath path)+            Nothing -> "with nix packages: " <> display (T.intercalate ", " pkgs))+     exec "nix-shell" fullArgs  -- | Shell-escape quotes inside the string and enclose it in quotes. escape :: String -> String
src/Stack/Options/BuildMonoidParser.hs view
@@ -14,12 +14,12 @@  buildOptsMonoidParser :: GlobalOptsContext -> Parser BuildOptsMonoid buildOptsMonoidParser hide0 =-    BuildOptsMonoid <$> trace <*> profile <*> noStrip <*>+    BuildOptsMonoid <$> trace' <*> profile <*> noStrip <*>     libProfiling <*> exeProfiling <*> libStripping <*>     exeStripping <*> haddock <*> haddockOptsParser hideBool <*>     openHaddocks <*> haddockDeps <*> haddockInternal <*>     haddockHyperlinkSource <*> copyBins <*> copyCompilerTool <*>-    preFetch <*> keepGoing <*> forceDirty <*>+    preFetch <*> keepGoing <*> keepTmpFiles <*> forceDirty <*>     tests <*> testOptsParser hideBool <*> benches <*>     benchOptsParser hideBool <*> reconfigure <*> cabalVerbose <*> splitObjs <*> skipComponents   where@@ -31,7 +31,7 @@      -- These use 'Any' because they are not settable in stack.yaml, so     -- there is no need for options like --no-profile.-    trace = Any <$>+    trace' = Any <$>         flag             False             True@@ -119,6 +119,11 @@         firstBoolFlags             "keep-going"             "continue running after a step fails (default: false for build, true for test/bench)"+            hide+    keepTmpFiles =+        firstBoolFlags+            "keep-tmp-files"+            "keep intermediate files and build directories (default: false)"             hide     preFetch =         firstBoolFlags
src/Stack/Options/Completion.hs view
@@ -12,7 +12,6 @@  import           Data.Char (isSpace) import           Data.List (isPrefixOf)-import           Data.List.Extra (nubOrd) import qualified Data.Map as Map import           Data.Maybe import qualified Data.Set as Set@@ -28,7 +27,7 @@ import           Stack.Setup import           Stack.Types.Config import           Stack.Types.FlagName-import           Stack.Types.Package+import           Stack.Types.NamedComponent import           Stack.Types.PackageName import           System.Process (readProcess) import           Language.Haskell.TH.Syntax (runIO, lift)@@ -66,11 +65,12 @@               runRIO envConfig (inner input)  targetCompleter :: Completer-targetCompleter = buildConfigCompleter $ \input -> do-    lpvs <- fmap lpProject getLocalPackages-    return $-        filter (input `isPrefixOf`) $-        concatMap allComponentNames (Map.toList lpvs)+targetCompleter = buildConfigCompleter $ \input ->+      filter (input `isPrefixOf`)+    . concatMap allComponentNames+    . Map.toList+    . lpProject+  <$> getLocalPackages   where     allComponentNames (name, lpv) =         map (T.unpack . renderPkgComponent . (name,)) (Set.toList (lpvComponents lpv))@@ -103,10 +103,14 @@             _ -> normalFlags  projectExeCompleter :: Completer-projectExeCompleter = buildConfigCompleter $ \input -> do-    lpvs <- fmap lpProject getLocalPackages-    return $-        filter (input `isPrefixOf`) $-        nubOrd $-        concatMap (\(_, lpv) -> map (C.unUnqualComponentName . fst) (C.condExecutables (lpvGPD lpv))) $-        Map.toList lpvs+projectExeCompleter = buildConfigCompleter $ \input ->+      filter (input `isPrefixOf`)+    . nubOrd+    . concatMap+        (\(_, lpv) -> map+          (C.unUnqualComponentName . fst)+          (C.condExecutables (lpvGPD lpv))+        )+    . Map.toList+    . lpProject+  <$> getLocalPackages
src/Stack/Options/ConfigParser.hs view
@@ -63,7 +63,7 @@     <*> nixOptsParser True     <*> firstBoolFlags             "system-ghc"-            "using the system installed GHC (on the PATH) if available and a matching version. Disabled by default."+            "using the system installed GHC (on the PATH) if it is available and its version matches. Disabled by default."             hide     <*> firstBoolFlags             "install-ghc"
src/Stack/Options/DockerParser.hs view
@@ -25,11 +25,11 @@                        "using a Docker container. --docker implies 'system-ghc: true'"                        hide     <*> fmap First-           ((Just . DockerMonoidRepo) <$> option str (long (dockerOptName dockerRepoArgName) <>+           (Just . DockerMonoidRepo <$> option str (long (dockerOptName dockerRepoArgName) <>                                                      hide <>                                                      metavar "NAME" <>                                                      help "Docker repository name") <|>-             (Just . DockerMonoidImage) <$> option str (long (dockerOptName dockerImageArgName) <>+             Just . DockerMonoidImage <$> option str (long (dockerOptName dockerImageArgName) <>                                                       hide <>                                                       metavar "IMAGE" <>                                                       help "Exact Docker image ID (overrides docker-repo)") <|>
src/Stack/Options/NixParser.hs view
@@ -13,8 +13,7 @@ nixOptsParser :: Bool -> Parser NixOptsMonoid nixOptsParser hide0 = overrideActivation <$>   (NixOptsMonoid-  <$> pure (Any False)-  <*> firstBoolFlags nixCmdName+  <$> firstBoolFlags nixCmdName                      "use of a Nix-shell. Implies 'system-ghc: true'"                      hide   <*> firstBoolFlags "nix-pure"
src/Stack/Package.hs view
@@ -33,7 +33,6 @@   ,resolvePackageDescription   ,packageDescTools   ,packageDependencies-  ,autogenDir   ,cabalFilePackageId   ,gpdPackageIdentifier   ,gpdPackageName@@ -42,13 +41,12 @@  import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as C8-import           Data.List (isSuffixOf, partition, isPrefixOf)-import           Data.List.Extra (nubOrd)+import           Data.List (isSuffixOf, isPrefixOf)+import           Data.Maybe (maybe) import qualified Data.Map.Strict as M import qualified Data.Set as S import qualified Data.Text as T-import           Data.Text.Encoding (decodeUtf8, decodeUtf8With)-import           Data.Text.Encoding.Error (lenientDecode)+import           Data.Text.Encoding (decodeUtf8) import           Distribution.Compiler import           Distribution.ModuleName (ModuleName) import qualified Distribution.ModuleName as Cabal@@ -56,9 +54,9 @@ import           Distribution.Package hiding (Package,PackageName,packageName,packageVersion,PackageIdentifier) import qualified Distribution.PackageDescription as D import           Distribution.PackageDescription hiding (FlagName)-import           Distribution.PackageDescription.Parse-import qualified Distribution.PackageDescription.Parse as D-import           Distribution.ParseUtils+import           Distribution.PackageDescription.Parsec+import qualified Distribution.PackageDescription.Parsec as D+import           Distribution.Parsec.Common (PWarning (..), showPos) import           Distribution.Simple.Utils import           Distribution.System (OS (..), Arch, Platform (..)) import qualified Distribution.Text as D@@ -68,7 +66,6 @@ import qualified Distribution.Types.LegacyExeDependency as Cabal import qualified Distribution.Types.UnqualComponentName as Cabal import qualified Distribution.Verbosity as D-import           Distribution.Version (showVersion) import           Lens.Micro (lens) import qualified Hpack import qualified Hpack.Config as Hpack@@ -79,7 +76,9 @@ import           Stack.Build.Installed import           Stack.Constants import           Stack.Constants.Config-import           Stack.Prelude+import           Stack.Fetch (loadFromIndex)+import           Stack.PackageIndex (HasCabalLoader (..))+import           Stack.Prelude hiding (Display (..)) import           Stack.PrettyPrint import           Stack.Types.Build import           Stack.Types.BuildPlan (ExeName (..))@@ -87,6 +86,7 @@ import           Stack.Types.Config import           Stack.Types.FlagName import           Stack.Types.GhcPkgId+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName@@ -96,10 +96,10 @@ import           System.FilePath (splitExtensions, replaceExtension) import qualified System.FilePath as FilePath import           System.IO.Error-import           System.Process.Run (runCmd, Cmd(..))+import           RIO.Process  data Ctx = Ctx { ctxFile :: !(Path Abs File)-               , ctxDir :: !(Path Abs Dir)+               , ctxDistDir :: !(Path Abs Dir)                , ctxEnvConfig :: !EnvConfig                } @@ -110,6 +110,10 @@ instance HasRunner Ctx where     runnerL = configL.runnerL instance HasConfig Ctx+instance HasCabalLoader Ctx where+    cabalLoaderL = configL.cabalLoaderL+instance HasProcessContext Ctx where+    processContextL = configL.processContextL instance HasBuildConfig Ctx instance HasEnvConfig Ctx where     envConfigL = lens ctxEnvConfig (\x y -> x { ctxEnvConfig = y })@@ -122,14 +126,14 @@   -> BS.ByteString   -> m ([PWarning], GenericPackageDescription) rawParseGPD key bs =-    case parseGenericPackageDescription chars of-       ParseFailed e -> throwM $ PackageInvalidCabalFile key e-       ParseOk warnings gpkg -> return (warnings,gpkg)+    case eres of+      Left (mversion, errs) -> throwM $ PackageInvalidCabalFile key+        (fromCabalVersion <$> mversion)+        errs+        warnings+      Right gpkg -> return (warnings, gpkg)   where-    chars = T.unpack (dropBOM (decodeUtf8With lenientDecode bs))--    -- https://github.com/haskell/hackage-server/issues/351-    dropBOM t = fromMaybe t $ T.stripPrefix "\xFEFF" t+    (warnings, eres) = runParseResult $ parseGenericPackageDescription bs  -- | Read the raw, unresolved package information from a file. readPackageUnresolvedDir@@ -154,14 +158,10 @@         ((m1, M.insert dir ret m2), ret)   where     toPretty :: String -> PWarning -> [Doc AnsiAnn]-    toPretty src (PWarning x) =-      [ flow "Cabal file warning in"-      , fromString src <> ":"-      , flow x-      ]-    toPretty src (UTFWarning ln msg) =+    toPretty src (PWarning _type pos msg) =       [ flow "Cabal file warning in"-      , fromString src <> ":" <> fromString (show ln) <> ":"+      , fromString src <> "@"+      , fromString (showPos pos) <> ":"       , flow msg       ] @@ -187,17 +187,16 @@ -- | Read the 'GenericPackageDescription' from the given -- 'PackageIdentifierRevision'. readPackageUnresolvedIndex-  :: forall env. HasRunner env-  => (PackageIdentifierRevision -> IO ByteString) -- ^ load the raw bytes-  -> PackageIdentifierRevision+  :: forall env. HasCabalLoader env+  => PackageIdentifierRevision   -> RIO env GenericPackageDescription-readPackageUnresolvedIndex loadFromIndex pir@(PackageIdentifierRevision pi' _) = do+readPackageUnresolvedIndex pir@(PackageIdentifierRevision pi' _) = do   ref <- view $ runnerL.to runnerParsedCabalFiles   (m, _) <- readIORef ref   case M.lookup pir m of     Just gpd -> return gpd     Nothing -> do-      bs <- liftIO $ loadFromIndex pir+      bs <- loadFromIndex pir       (_warnings, gpd) <- rawParseGPD (Left pir) bs       let foundPI =               fromCabalPackageIdentifier@@ -260,7 +259,7 @@     Package     { packageName = name     , packageVersion = fromCabalVersion (pkgVersion pkgId)-    , packageLicense = license pkg+    , packageLicense = licenseRaw pkg     , packageDeps = deps     , packageFiles = pkgFiles     , packageTools = packageDescTools pkg@@ -335,11 +334,11 @@              distDir <- distDirFromDir pkgDir              env <- view envConfigL              (componentModules,componentFiles,dataFiles',warnings) <--                 runReaderT+                 runRIO+                     (Ctx cabalfp distDir env)                      (packageDescModulesAndFiles pkg)-                     (Ctx cabalfp (buildDir distDir) env)              setupFiles <--                 if buildType pkg `elem` [Nothing, Just Custom]+                 if buildType pkg == Custom                  then do                      let setupHsPath = pkgDir </> $(mkRelFile "Setup.hs")                          setupLhsPath = pkgDir </> $(mkRelFile "Setup.lhs")@@ -386,19 +385,13 @@     -> m (Map NamedComponent BuildInfoOpts) generatePkgDescOpts sourceMap installedMap omitPkgs addPkgs cabalfp pkg componentPaths = do     config <- view configL+    cabalVer <- view cabalVersionL     distDir <- distDirFromDir cabalDir-    let cabalMacros = autogenDir distDir </> $(mkRelFile "cabal_macros.h")-    exists <- doesFileExist cabalMacros-    let mcabalMacros =-            if exists-                then Just cabalMacros-                else Nothing     let generate namedComponent binfo =             ( namedComponent             , generateBuildInfoOpts BioInput                 { biSourceMap = sourceMap                 , biInstalledMap = installedMap-                , biCabalMacros = mcabalMacros                 , biCabalDir = cabalDir                 , biDistDir = distDir                 , biOmitPackages = omitPkgs@@ -408,6 +401,7 @@                 , biConfigLibDirs = configExtraLibDirs config                 , biConfigIncludeDirs = configExtraIncludeDirs config                 , biComponentName = namedComponent+                , biCabalVersion = cabalVer                 }             )     return@@ -442,7 +436,6 @@ data BioInput = BioInput     { biSourceMap :: !SourceMap     , biInstalledMap :: !InstalledMap-    , biCabalMacros :: !(Maybe (Path Abs File))     , biCabalDir :: !(Path Abs Dir)     , biDistDir :: !(Path Abs Dir)     , biOmitPackages :: ![PackageName]@@ -452,6 +445,7 @@     , biConfigLibDirs :: !(Set FilePath)     , biConfigIncludeDirs :: !(Set FilePath)     , biComponentName :: !NamedComponent+    , biCabalVersion :: !Version     }  -- | Generate GHC options for the target. Since Cabal also figures out@@ -471,7 +465,7 @@         , bioOneWordOpts = nubOrd $ concat             [extOpts, srcOpts, includeOpts, libOpts, fworks, cObjectFiles]         , bioPackageFlags = deps-        , bioCabalMacros = biCabalMacros+        , bioCabalMacros = componentAutogen </> $(mkRelFile "cabal_macros.h")         }   where     cObjectFiles =@@ -501,14 +495,19 @@         isGhc _ = False     extOpts = map (("-X" ++) . D.display) (usedExtensions biBuildInfo)     srcOpts =-        map-            (("-i" <>) . toFilePathNoTrailingSep)-            ([biCabalDir | null (hsSourceDirs biBuildInfo)] <>-             mapMaybe toIncludeDir (hsSourceDirs biBuildInfo) <>-             [autogenDir biDistDir,buildDir biDistDir] <>-             [makeGenDir (buildDir biDistDir)-             | Just makeGenDir <- [fileGenDirFromComponentName biComponentName]]) ++-        ["-stubdir=" ++ toFilePathNoTrailingSep (buildDir biDistDir)]+        map (("-i" <>) . toFilePathNoTrailingSep)+            (concat+              [ [ componentBuildDir biCabalVersion biComponentName biDistDir ]+              , [ biCabalDir+                | null (hsSourceDirs biBuildInfo)+                ]+              , mapMaybe toIncludeDir (hsSourceDirs biBuildInfo)+              , [ componentAutogen ]+              , maybeToList (packageAutogenDir biCabalVersion biDistDir)+              , [ componentOutputDir biComponentName biDistDir ]+              ]) +++        [ "-stubdir=" ++ toFilePathNoTrailingSep (buildDir biDistDir) ]+    componentAutogen = componentAutogenDir biCabalVersion biComponentName biDistDir     toIncludeDir "." = Just biCabalDir     toIncludeDir relDir = concatAndColapseAbsDir biCabalDir relDir     includeOpts =@@ -571,35 +570,55 @@     relCFilePath <- stripProperPrefix cabalDir cFilePath     relOFilePath <-         parseRelFile (replaceExtension (toFilePath relCFilePath) "o")-    addComponentPrefix <- fileGenDirFromComponentName namedComponent-    return (addComponentPrefix (buildDir distDir) </> relOFilePath)+    return (componentOutputDir namedComponent distDir </> relOFilePath) +-- | Make the global autogen dir if Cabal version is new enough.+packageAutogenDir :: Version -> Path Abs Dir -> Maybe (Path Abs Dir)+packageAutogenDir cabalVer distDir+    | cabalVer < $(mkVersion "2.0") = Nothing+    | otherwise = Just $ buildDir distDir </> $(mkRelDir "global-autogen")++-- | Make the autogen dir.+componentAutogenDir :: Version -> NamedComponent -> Path Abs Dir -> Path Abs Dir+componentAutogenDir cabalVer component distDir =+    componentBuildDir cabalVer component distDir </> $(mkRelDir "autogen")++-- | See 'Distribution.Simple.LocalBuildInfo.componentBuildDir'+componentBuildDir :: Version -> NamedComponent -> Path Abs Dir -> Path Abs Dir+componentBuildDir cabalVer component distDir+    | cabalVer < $(mkVersion "2.0") = buildDir distDir+    | otherwise =+        case component of+            CLib -> buildDir distDir+            CInternalLib name -> buildDir distDir </> componentNameToDir name+            CExe name -> buildDir distDir </> componentNameToDir name+            CTest name -> buildDir distDir </> componentNameToDir name+            CBench name -> buildDir distDir </> componentNameToDir name+ -- | The directory where generated files are put like .o or .hs (from .x files).-fileGenDirFromComponentName-    :: MonadThrow m-    => NamedComponent -> m (Path b Dir -> Path b Dir)-fileGenDirFromComponentName namedComponent =+componentOutputDir :: NamedComponent -> Path Abs Dir -> Path Abs Dir+componentOutputDir namedComponent distDir =     case namedComponent of-        CLib -> return id+        CLib -> buildDir distDir+        CInternalLib name -> makeTmp name         CExe name -> makeTmp name         CTest name -> makeTmp name         CBench name -> makeTmp name-  where makeTmp name = do-            prefix <- parseRelDir (T.unpack name <> "/" <> T.unpack name <> "-tmp")-            return (</> prefix)---- | Make the autogen dir.-autogenDir :: Path Abs Dir -> Path Abs Dir-autogenDir distDir = buildDir distDir </> $(mkRelDir "autogen")+  where+    makeTmp name =+      buildDir distDir </> componentNameToDir (name <> "/" <> name <> "-tmp") --- | Make the build dir.+-- | Make the build dir. Note that Cabal >= 2.0 uses the+-- 'componentBuildDir' above for some things. buildDir :: Path Abs Dir -> Path Abs Dir buildDir distDir = distDir </> $(mkRelDir "build") --- | Make the component-specific subdirectory of the build directory.-getBuildComponentDir :: Maybe String -> Maybe (Path Rel Dir)-getBuildComponentDir Nothing = Nothing-getBuildComponentDir (Just name) = parseRelDir (name FilePath.</> (name ++ "-tmp"))+-- NOTE: don't export this, only use it for valid paths based on+-- component names.+componentNameToDir :: Text -> Path Rel Dir+componentNameToDir name =+  fromMaybe (error "Invariant violated: component names should always parse as directory names")+            (parseRelDir (T.unpack name))  -- | Get all dependencies of the package (buildable targets only). --@@ -655,26 +674,41 @@     go2 :: Cabal.ExeDependency -> (ExeName, VersionRange)     go2 (Cabal.ExeDependency _pkg name range) = (ExeName $ T.pack $ Cabal.unUnqualComponentName name, range) --- | Variant of 'allBuildInfo' from Cabal that includes foreign--- libraries; see <https://github.com/haskell/cabal/issues/4763>+-- | Variant of 'allBuildInfo' from Cabal that, like versions before+-- 2.2, only includes buildable components. allBuildInfo' :: PackageDescription -> [BuildInfo]-allBuildInfo' pkg = allBuildInfo pkg ++-  [ bi | flib <- foreignLibs pkg-       , let bi = foreignLibBuildInfo flib-       , buildable bi-  ]+allBuildInfo' pkg_descr = [ bi | lib <- allLibraries pkg_descr+                               , let bi = libBuildInfo lib+                               , buildable bi ]+                       ++ [ bi | flib <- foreignLibs pkg_descr+                               , let bi = foreignLibBuildInfo flib+                               , buildable bi ]+                       ++ [ bi | exe <- executables pkg_descr+                               , let bi = buildInfo exe+                               , buildable bi ]+                       ++ [ bi | tst <- testSuites pkg_descr+                               , let bi = testBuildInfo tst+                               , buildable bi ]+                       ++ [ bi | tst <- benchmarks pkg_descr+                               , let bi = benchmarkBuildInfo tst+                               , buildable bi ]  -- | Get all files referenced by the package. packageDescModulesAndFiles-    :: (MonadLogger m, MonadUnliftIO m, MonadReader Ctx m, MonadThrow m)-    => PackageDescription-    -> m (Map NamedComponent (Set ModuleName), Map NamedComponent (Set DotCabalPath), Set (Path Abs File), [PackageWarning])+    :: PackageDescription+    -> RIO Ctx (Map NamedComponent (Map ModuleName (Path Abs File)), Map NamedComponent (Set DotCabalPath), Set (Path Abs File), [PackageWarning]) packageDescModulesAndFiles pkg = do     (libraryMods,libDotCabalFiles,libWarnings) <- -- FIXME add in sub libraries         maybe             (return (M.empty, M.empty, []))             (asModuleAndFileMap libComponent libraryFiles)             (library pkg)+    (subLibrariesMods,subLibDotCabalFiles,subLibWarnings) <-+        liftM+            foldTuples+            (mapM+                 (asModuleAndFileMap internalLibComponent libraryFiles)+                 (subLibraries pkg))     (executableMods,exeDotCabalFiles,exeWarnings) <-         liftM             foldTuples@@ -694,25 +728,25 @@     dfiles <- resolveGlobFiles                     (extraSrcFiles pkg                         ++ map (dataDir pkg FilePath.</>) (dataFiles pkg))-    let modules = libraryMods <> executableMods <> testMods <> benchModules+    let modules = libraryMods <> subLibrariesMods <> executableMods <> testMods <> benchModules         files =-            libDotCabalFiles <> exeDotCabalFiles <> testDotCabalFiles <>+            libDotCabalFiles <> subLibDotCabalFiles <> exeDotCabalFiles <> testDotCabalFiles <>             benchDotCabalPaths-        warnings = libWarnings <> exeWarnings <> testWarnings <> benchWarnings+        warnings = libWarnings <> subLibWarnings <> exeWarnings <> testWarnings <> benchWarnings     return (modules, files, dfiles, warnings)   where     libComponent = const CLib+    internalLibComponent = CInternalLib . T.pack . maybe "" Cabal.unUnqualComponentName . libName     exeComponent = CExe . T.pack . Cabal.unUnqualComponentName . exeName     testComponent = CTest . T.pack . Cabal.unUnqualComponentName . testName     benchComponent = CBench . T.pack . Cabal.unUnqualComponentName . benchmarkName     asModuleAndFileMap label f lib = do-        (a,b,c) <- f lib+        (a,b,c) <- f (label lib) lib         return (M.singleton (label lib) a, M.singleton (label lib) b, c)     foldTuples = foldl' (<>) (M.empty, M.empty, [])  -- | Resolve globbing of files (e.g. data files) to absolute paths.-resolveGlobFiles :: (MonadLogger m,MonadUnliftIO m,MonadReader Ctx m)-                 => [String] -> m (Set (Path Abs File))+resolveGlobFiles :: [String] -> RIO Ctx (Set (Path Abs File)) resolveGlobFiles =     liftM (S.fromList . catMaybes . concat) .     mapM resolve@@ -758,7 +792,7 @@ -- ["test/package-dump/ghc-7.8.txt","test/package-dump/ghc-7.10.txt"] -- @ ---matchDirFileGlob_ :: (MonadLogger m, MonadIO m, HasRunner env, MonadReader env m) => String -> String -> m [String]+matchDirFileGlob_ :: HasRunner env => String -> String -> RIO env [String] matchDirFileGlob_ dir filepath = case parseFileGlob filepath of   Nothing -> liftIO $ throwString $       "invalid file glob '" ++ filepath@@ -787,20 +821,13 @@  -- | Get all files referenced by the benchmark. benchmarkFiles-    :: (MonadLogger m, MonadIO m, MonadReader Ctx m, MonadThrow m)-    => Benchmark -> m (Set ModuleName, Set DotCabalPath, [PackageWarning])-benchmarkFiles bench = do-    dirs <- mapMaybeM resolveDirOrWarn (hsSourceDirs build)-    dir <- asks (parent . ctxFile)-    (modules,files,warnings) <--        resolveFilesAndDeps-            (Just $ Cabal.unUnqualComponentName $ benchmarkName bench)-            (dirs ++ [dir])-            (bnames <> exposed)-            haskellModuleExts-    cfiles <- buildOtherSources build-    return (modules, files <> cfiles, warnings)+    :: NamedComponent+    -> Benchmark+    -> RIO Ctx (Map ModuleName (Path Abs File), Set DotCabalPath, [PackageWarning])+benchmarkFiles component bench = do+    resolveComponentFiles component build names   where+    names = bnames <> exposed     exposed =         case benchmarkInterface bench of             BenchmarkExeV10 _ fp -> [DotCabalMain fp]@@ -810,21 +837,13 @@  -- | Get all files referenced by the test. testFiles-    :: (MonadLogger m, MonadIO m, MonadReader Ctx m, MonadThrow m)-    => TestSuite-    -> m (Set ModuleName, Set DotCabalPath, [PackageWarning])-testFiles test = do-    dirs <- mapMaybeM resolveDirOrWarn (hsSourceDirs build)-    dir <- asks (parent . ctxFile)-    (modules,files,warnings) <--        resolveFilesAndDeps-            (Just $ Cabal.unUnqualComponentName $ testName test)-            (dirs ++ [dir])-            (bnames <> exposed)-            haskellModuleExts-    cfiles <- buildOtherSources build-    return (modules, files <> cfiles, warnings)+    :: NamedComponent+    -> TestSuite+    -> RIO Ctx (Map ModuleName (Path Abs File), Set DotCabalPath, [PackageWarning])+testFiles component test = do+    resolveComponentFiles component build names   where+    names = bnames <> exposed     exposed =         case testInterface test of             TestSuiteExeV10 _ fp -> [DotCabalMain fp]@@ -835,48 +854,50 @@  -- | Get all files referenced by the executable. executableFiles-    :: (MonadLogger m, MonadIO m, MonadReader Ctx m, MonadThrow m)-    => Executable-    -> m (Set ModuleName, Set DotCabalPath, [PackageWarning])-executableFiles exe = do-    dirs <- mapMaybeM resolveDirOrWarn (hsSourceDirs build)-    dir <- asks (parent . ctxFile)-    (modules,files,warnings) <--        resolveFilesAndDeps-            (Just $ Cabal.unUnqualComponentName $ exeName exe)-            (dirs ++ [dir])-            (map DotCabalModule (otherModules build) ++-             [DotCabalMain (modulePath exe)])-            haskellModuleExts-    cfiles <- buildOtherSources build-    return (modules, files <> cfiles, warnings)+    :: NamedComponent+    -> Executable+    -> RIO Ctx (Map ModuleName (Path Abs File), Set DotCabalPath, [PackageWarning])+executableFiles component exe = do+    resolveComponentFiles component build names   where     build = buildInfo exe+    names =+        map DotCabalModule (otherModules build) +++        [DotCabalMain (modulePath exe)]  -- | Get all files referenced by the library. libraryFiles-    :: (MonadLogger m, MonadIO m, MonadReader Ctx m, MonadThrow m)-    => Library -> m (Set ModuleName, Set DotCabalPath, [PackageWarning])-libraryFiles lib = do+    :: NamedComponent+    -> Library+    -> RIO Ctx (Map ModuleName (Path Abs File), Set DotCabalPath, [PackageWarning])+libraryFiles component lib = do+    resolveComponentFiles component build names+  where+    build = libBuildInfo lib+    names = bnames ++ exposed+    exposed = map DotCabalModule (exposedModules lib)+    bnames = map DotCabalModule (otherModules build)++-- | Get all files referenced by the component.+resolveComponentFiles+    :: NamedComponent+    -> BuildInfo+    -> [DotCabalDescriptor]+    -> RIO Ctx (Map ModuleName (Path Abs File), Set DotCabalPath, [PackageWarning])+resolveComponentFiles component build names = do     dirs <- mapMaybeM resolveDirOrWarn (hsSourceDirs build)     dir <- asks (parent . ctxFile)     (modules,files,warnings) <-         resolveFilesAndDeps-            Nothing+            component             (dirs ++ [dir])             names             haskellModuleExts     cfiles <- buildOtherSources build     return (modules, files <> cfiles, warnings)-  where-    names = bnames ++ exposed-    exposed = map DotCabalModule (exposedModules lib)-    bnames = map DotCabalModule (otherModules build)-    build = libBuildInfo lib  -- | Get all C sources and extra source files in a build.-buildOtherSources :: (MonadLogger m,MonadIO m,MonadReader Ctx m)-           => BuildInfo -> m (Set DotCabalPath)+buildOtherSources :: BuildInfo -> RIO Ctx (Set DotCabalPath) buildOtherSources build =     do csources <- liftM                        (S.map DotCabalCFilePath . S.fromList)@@ -1015,7 +1036,7 @@     }  -- | Resolve the condition tree for the library.-resolveConditions :: (Monoid target,Show target)+resolveConditions :: (Semigroup target,Monoid target,Show target)                   => ResolveConditions                   -> (target -> cs -> target)                   -> CondTree ConfVar cs target@@ -1067,24 +1088,22 @@ -- extensions, plus find any of their module and TemplateHaskell -- dependencies. resolveFilesAndDeps-    :: (MonadIO m, MonadLogger m, MonadReader Ctx m, MonadThrow m)-    => Maybe String         -- ^ Package component name+    :: NamedComponent       -- ^ Package component name     -> [Path Abs Dir]       -- ^ Directories to look in.     -> [DotCabalDescriptor] -- ^ Base names.     -> [Text]               -- ^ Extensions.-    -> m (Set ModuleName,Set DotCabalPath,[PackageWarning])+    -> RIO Ctx (Map ModuleName (Path Abs File),Set DotCabalPath,[PackageWarning]) resolveFilesAndDeps component dirs names0 exts = do     (dotCabalPaths, foundModules, missingModules) <- loop names0 S.empty     warnings <- liftM2 (++) (warnUnlisted foundModules) (warnMissing missingModules)     return (foundModules, dotCabalPaths, warnings)   where-    loop [] _ = return (S.empty, S.empty, [])+    loop [] _ = return (S.empty, M.empty, [])     loop names doneModules0 = do         resolved <- resolveFiles dirs names exts         let foundFiles = mapMaybe snd resolved-            (foundModules', missingModules') = partition (isJust . snd) resolved-            foundModules = mapMaybe (dotCabalModule . fst) foundModules'-            missingModules = mapMaybe (dotCabalModule . fst) missingModules'+            foundModules = mapMaybe toResolvedModule resolved+            missingModules = mapMaybe toMissingModule resolved         pairs <- mapM (getDependencies component) foundFiles         let doneModules =                 S.union@@ -1102,20 +1121,20 @@                   (S.fromList                        (foundFiles <> map DotCabalFilePath thDepFiles))                   resolvedFiles-            , S.union-                  (S.fromList foundModules)+            , M.union+                  (M.fromList foundModules)                   resolvedModules             , missingModules)     warnUnlisted foundModules = do         let unlistedModules =-                foundModules `S.difference`-                S.fromList (mapMaybe dotCabalModule names0)+                foundModules `M.difference`+                M.fromList (mapMaybe (fmap (, ()) . dotCabalModule) names0)         return $-            if S.null unlistedModules+            if M.null unlistedModules                 then []                 else [ UnlistedModulesWarning                            component-                           (S.toList unlistedModules)]+                           (map fst (M.toList unlistedModules))]     warnMissing _missingModules = do         return []         -- TODO: bring this back - see@@ -1130,12 +1149,26 @@                            component                            missingModules]         -}-+    -- TODO: In usages of toResolvedModule / toMissingModule, some sort+    -- of map + partition would probably be better.+    toResolvedModule+        :: (DotCabalDescriptor, Maybe DotCabalPath)+        -> Maybe (ModuleName, Path Abs File)+    toResolvedModule (DotCabalModule mn, Just (DotCabalModulePath fp)) =+        Just (mn, fp)+    toResolvedModule _ =+        Nothing+    toMissingModule+        :: (DotCabalDescriptor, Maybe DotCabalPath)+        -> Maybe ModuleName+    toMissingModule (DotCabalModule mn, Nothing) =+        Just mn+    toMissingModule _ =+        Nothing  -- | Get the dependencies of a Haskell module file. getDependencies-    :: (MonadReader Ctx m, MonadIO m, MonadLogger m)-    => Maybe String -> DotCabalPath -> m (Set ModuleName, [Path Abs File])+    :: NamedComponent -> DotCabalPath -> RIO Ctx (Set ModuleName, [Path Abs File]) getDependencies component dotCabalPath =     case dotCabalPath of         DotCabalModulePath resolvedFile -> readResolvedHi resolvedFile@@ -1144,7 +1177,7 @@         DotCabalCFilePath{} -> return (S.empty, [])   where     readResolvedHi resolvedFile = do-        dumpHIDir <- getDumpHIDir+        dumpHIDir <- componentOutputDir component <$> asks ctxDistDir         dir <- asks (parent . ctxFile)         case stripProperPrefix dir resolvedFile of             Nothing -> return (S.empty, [])@@ -1157,14 +1190,10 @@                 if dumpHIExists                     then parseDumpHI dumpHIPath                     else return (S.empty, [])-    getDumpHIDir = do-        bld <- asks ctxDir-        return $ maybe bld (bld </>) (getBuildComponentDir component)  -- | Parse a .dump-hi file into a set of modules and files. parseDumpHI-    :: (MonadReader Ctx m, MonadIO m, MonadLogger m)-    => FilePath -> m (Set ModuleName, [Path Abs File])+    :: FilePath -> RIO Ctx (Set ModuleName, [Path Abs File]) parseDumpHI dumpHIPath = do     dir <- asks (parent . ctxFile)     dumpHI <- liftIO $ fmap C8.lines (C8.readFile dumpHIPath)@@ -1201,22 +1230,20 @@ -- looking for unique instances of base names applied with the given -- extensions. resolveFiles-    :: (MonadIO m, MonadLogger m, MonadThrow m, MonadReader Ctx m)-    => [Path Abs Dir] -- ^ Directories to look in.+    :: [Path Abs Dir] -- ^ Directories to look in.     -> [DotCabalDescriptor] -- ^ Base names.     -> [Text] -- ^ Extensions.-    -> m [(DotCabalDescriptor, Maybe DotCabalPath)]+    -> RIO Ctx [(DotCabalDescriptor, Maybe DotCabalPath)] resolveFiles dirs names exts =     forM names (\name -> liftM (name, ) (findCandidate dirs exts name))  -- | Find a candidate for the given module-or-filename from the list -- of directories and given extensions. findCandidate-    :: (MonadIO m, MonadLogger m, MonadThrow m, MonadReader Ctx m)-    => [Path Abs Dir]+    :: [Path Abs Dir]     -> [Text]     -> DotCabalDescriptor-    -> m (Maybe DotCabalPath)+    -> RIO Ctx (Maybe DotCabalPath) findCandidate dirs exts name = do     pkg <- asks ctxFile >>= parsePackageNameFromFilePath     candidates <- liftIO makeNameCandidates@@ -1267,8 +1294,7 @@ -- | Warn the user that multiple candidates are available for an -- entry, but that we picked one anyway and continued. warnMultiple-    :: (MonadLogger m, HasRunner env, MonadReader env m)-    => DotCabalDescriptor -> Path b t -> [Path b t] -> m ()+    :: DotCabalDescriptor -> Path b t -> [Path b t] -> RIO Ctx () warnMultiple name candidate rest =     -- TODO: figure out how to style 'name' and the dispOne stuff     prettyWarnL@@ -1292,9 +1318,8 @@ -- For example: .erb for a Ruby file might exist in one of the -- directories. logPossibilities-    :: (MonadIO m, MonadThrow m, MonadLogger m, HasRunner env,-        MonadReader env m)-    => [Path Abs Dir] -> ModuleName -> m ()+    :: HasRunner env+    => [Path Abs Dir] -> ModuleName -> RIO env () logPossibilities dirs mn = do     possibilities <- liftM concat (makePossibilities mn)     unless (null possibilities) $ prettyWarnL@@ -1328,18 +1353,17 @@ -- If the directory contains a file named package.yaml, hpack is used to -- generate a .cabal file from it. findOrGenerateCabalFile-    :: forall m env.-          (MonadIO m, MonadUnliftIO m, MonadLogger m, HasRunner env, HasConfig env, MonadReader env m)+    :: forall env. HasConfig env     => Path Abs Dir -- ^ package directory-    -> m (Path Abs File)+    -> RIO env (Path Abs File) findOrGenerateCabalFile pkgDir = do     hpack pkgDir     findCabalFile   where-    findCabalFile :: m (Path Abs File)+    findCabalFile :: RIO env (Path Abs File)     findCabalFile = findCabalFile' >>= either throwIO return -    findCabalFile' :: m (Either PackageException (Path Abs File))+    findCabalFile' :: RIO env (Either PackageException (Path Abs File))     findCabalFile' = do         files <- liftIO $ findFiles             pkgDir@@ -1358,8 +1382,7 @@       where hasExtension fp x = FilePath.takeExtension fp == "." ++ x  -- | Generate .cabal file from package.yaml, if necessary.-hpack :: (MonadIO m, MonadUnliftIO m, MonadLogger m, HasRunner env, HasConfig env, MonadReader env m)-      => Path Abs Dir -> m ()+hpack :: HasConfig env => Path Abs Dir -> RIO env () hpack pkgDir = do     let hpackFile = pkgDir </> $(mkRelFile Hpack.packageConfig)     exists <- liftIO $ doesFileExist hpackFile@@ -1389,16 +1412,17 @@                         , flow "please upgrade and try again."                         ]                     Hpack.ExistingCabalFileWasModifiedManually -> prettyWarnL-                        [ flow "WARNING: "-                        , cabalFile-                        , flow " was modified manually.  Ignoring package.yaml in favor of cabal file."-                        , flow "If you want to use package.yaml instead of the cabal file, "+                        [ cabalFile+                        , flow "was modified manually. Ignoring"+                        , display hpackFile+                        , flow "in favor of the cabal file. If you want to use the"+                        , display . filename $ hpackFile+                        , flow "file instead of the cabal file,"                         , flow "then please delete the cabal file."                         ]-            HpackCommand command -> do-                envOverride <- getMinimalEnvOverride-                let cmd = Cmd (Just pkgDir) command envOverride []-                runCmd cmd Nothing+            HpackCommand command ->+                withWorkingDir (toFilePath pkgDir) $+                proc command [] runProcess_  -- | Path for the package's build log. buildLogPath :: (MonadReader env m, HasBuildConfig env, MonadThrow m)@@ -1412,11 +1436,10 @@   return $ stack </> $(mkRelDir "logs") </> fp  -- Internal helper to define resolveFileOrWarn and resolveDirOrWarn-resolveOrWarn :: (MonadLogger m, MonadIO m, MonadReader Ctx m)-              => Text-              -> (Path Abs Dir -> String -> m (Maybe a))+resolveOrWarn :: Text+              -> (Path Abs Dir -> String -> RIO Ctx (Maybe a))               -> FilePath.FilePath-              -> m (Maybe a)+              -> RIO Ctx (Maybe a) resolveOrWarn subject resolver path =   do cwd <- liftIO getCurrentDir      file <- asks ctxFile@@ -1434,17 +1457,15 @@  -- | Resolve the file, if it can't be resolved, warn for the user -- (purely to be helpful).-resolveFileOrWarn :: (MonadIO m,MonadLogger m,MonadReader Ctx m)-                  => FilePath.FilePath-                  -> m (Maybe (Path Abs File))+resolveFileOrWarn :: FilePath.FilePath+                  -> RIO Ctx (Maybe (Path Abs File)) resolveFileOrWarn = resolveOrWarn "File" f   where f p x = liftIO (forgivingAbsence (resolveFile p x)) >>= rejectMissingFile  -- | Resolve the directory, if it can't be resolved, warn for the user -- (purely to be helpful).-resolveDirOrWarn :: (MonadIO m,MonadLogger m,MonadReader Ctx m)-                 => FilePath.FilePath-                 -> m (Maybe (Path Abs Dir))+resolveDirOrWarn :: FilePath.FilePath+                 -> RIO Ctx (Maybe (Path Abs Dir)) resolveDirOrWarn = resolveOrWarn "Directory" f   where f p x = liftIO (forgivingAbsence (resolveDir p x)) >>= rejectMissingDir @@ -1459,5 +1480,5 @@   where     toStackPI (D.PackageIdentifier (D.unPackageName -> name) ver) = do         name' <- parsePackageNameFromString name-        ver' <- parseVersionFromString (showVersion ver)+        let ver' = fromCabalVersion ver         return (PackageIdentifier name' ver')
src/Stack/PackageDump.hs view
@@ -48,43 +48,41 @@ import           Stack.Types.PackageName import           Stack.Types.Version import           System.Directory (getDirectoryContents, doesFileExist)-import           System.Process.Read+import           System.Process (readProcess) -- FIXME confirm that this is correct+import           RIO.Process hiding (readProcess)  -- | Call ghc-pkg dump with appropriate flags and stream to the given @Sink@, for a single database ghcPkgDump-    :: (MonadUnliftIO m, MonadLogger m)-    => EnvOverride-    -> WhichCompiler+    :: (HasProcessContext env, HasLogFunc env)+    => WhichCompiler     -> [Path Abs Dir] -- ^ if empty, use global-    -> Sink Text IO a-    -> m a+    -> ConduitM Text Void (RIO env) a+    -> RIO env a ghcPkgDump = ghcPkgCmdArgs ["dump"]  -- | Call ghc-pkg describe with appropriate flags and stream to the given @Sink@, for a single database ghcPkgDescribe-    :: (MonadUnliftIO m, MonadLogger m)+    :: (HasProcessContext env, HasLogFunc env)     => PackageName-    -> EnvOverride     -> WhichCompiler     -> [Path Abs Dir] -- ^ if empty, use global-    -> Sink Text IO a-    -> m a+    -> ConduitM Text Void (RIO env) a+    -> RIO env a ghcPkgDescribe pkgName = ghcPkgCmdArgs ["describe", "--simple-output", packageNameString pkgName]  -- | Call ghc-pkg and stream to the given @Sink@, for a single database ghcPkgCmdArgs-    :: (MonadUnliftIO m, MonadLogger m)+    :: (HasProcessContext env, HasLogFunc env)     => [String]-    -> EnvOverride     -> WhichCompiler     -> [Path Abs Dir] -- ^ if empty, use global-    -> Sink Text IO a-    -> m a-ghcPkgCmdArgs cmd menv wc mpkgDbs sink = do+    -> ConduitM Text Void (RIO env) a+    -> RIO env a+ghcPkgCmdArgs cmd wc mpkgDbs sink = do     case reverse mpkgDbs of-        (pkgDb:_) -> createDatabase menv wc pkgDb -- TODO maybe use some retry logic instead?+        (pkgDb:_) -> createDatabase wc pkgDb -- TODO maybe use some retry logic instead?         _ -> return ()-    sinkProcessStdout Nothing menv (ghcPkgExeName wc) args sink'+    sinkProcessStdout (ghcPkgExeName wc) args sink'   where     args = concat         [ case mpkgDbs of@@ -94,7 +92,7 @@         , cmd         , ["--expand-pkgroot"]         ]-    sink' = CT.decodeUtf8 =$= sink+    sink' = CT.decodeUtf8 .| sink  -- | Create a new, empty @InstalledCache@ newInstalledCache :: MonadIO m => m InstalledCache@@ -102,14 +100,13 @@  -- | Load a @InstalledCache@ from disk, swallowing any errors and returning an -- empty cache.-loadInstalledCache :: (MonadLogger m, MonadUnliftIO m)-                   => Path Abs File -> m InstalledCache+loadInstalledCache :: HasLogFunc env => Path Abs File -> RIO env InstalledCache loadInstalledCache path = do     m <- $(versionedDecodeOrLoad installedCacheVC) path (return $ InstalledCacheInner Map.empty)     liftIO $ InstalledCache <$> newIORef m  -- | Save a @InstalledCache@ to disk-saveInstalledCache :: (MonadLogger m, MonadIO m) => Path Abs File -> InstalledCache -> m ()+saveInstalledCache :: HasLogFunc env => Path Abs File -> InstalledCache -> RIO env () saveInstalledCache path (InstalledCache ref) =     liftIO (readIORef ref) >>= $(versionedEncodeFile installedCacheVC) path @@ -160,22 +157,26 @@              -> Bool -- ^ require haddock?              -> Bool -- ^ require debugging symbols?              -> Map PackageName Version -- ^ allowed versions-             -> Consumer (DumpPackage Bool Bool Bool)+             -> ConduitM (DumpPackage Bool Bool Bool) o                          m                          (Map PackageName (DumpPackage Bool Bool Bool))-sinkMatching reqProfiling reqHaddock reqSymbols allowed = do-    dps <- CL.filter (\dp -> isAllowed (dpPackageIdent dp) &&-                             (not reqProfiling || dpProfiling dp) &&-                             (not reqHaddock || dpHaddock dp) &&-                             (not reqSymbols || dpSymbols dp))-       =$= CL.consume-    return $ Map.fromList $ map (packageIdentifierName . dpPackageIdent &&& id) $ Map.elems $ pruneDeps+sinkMatching reqProfiling reqHaddock reqSymbols allowed =+      Map.fromList+    . map (packageIdentifierName . dpPackageIdent &&& id)+    . Map.elems+    . pruneDeps         id         dpGhcPkgId         dpDepends         const -- Could consider a better comparison in the future-        dps+    <$> (CL.filter predicate .| CL.consume)   where+    predicate dp =+      isAllowed (dpPackageIdent dp) &&+      (not reqProfiling || dpProfiling dp) &&+      (not reqHaddock || dpHaddock dp) &&+      (not reqSymbols || dpSymbols dp)+     isAllowed (PackageIdentifier name version) =         case Map.lookup name allowed of             Just version' | version /= version' -> False@@ -184,7 +185,7 @@ -- | Add profiling information to the stream of @DumpPackage@s addProfiling :: MonadIO m              => InstalledCache-             -> Conduit (DumpPackage a b c) m (DumpPackage Bool b c)+             -> ConduitM (DumpPackage a b c) (DumpPackage Bool b c) m () addProfiling (InstalledCache ref) =     CL.mapM go   where@@ -219,7 +220,7 @@ -- | Add haddock information to the stream of @DumpPackage@s addHaddock :: MonadIO m            => InstalledCache-           -> Conduit (DumpPackage a b c) m (DumpPackage a Bool c)+           -> ConduitM (DumpPackage a b c) (DumpPackage a Bool c) m () addHaddock (InstalledCache ref) =     CL.mapM go   where@@ -242,7 +243,7 @@ -- | Add debugging symbol information to the stream of @DumpPackage@s addSymbols :: MonadIO m            => InstalledCache-           -> Conduit (DumpPackage a b c) m (DumpPackage a b Bool)+           -> ConduitM (DumpPackage a b c) (DumpPackage a b Bool) m () addSymbols (InstalledCache ref) =     CL.mapM go   where@@ -281,6 +282,7 @@ data DumpPackage profiling haddock symbols = DumpPackage     { dpGhcPkgId :: !GhcPkgId     , dpPackageIdent :: !PackageIdentifier+    , dpParentLibIdent :: !(Maybe PackageIdentifier)     , dpLicense :: !(Maybe C.License)     , dpLibDirs :: ![FilePath]     , dpLibraries :: ![Text]@@ -313,9 +315,9 @@  -- | Convert a stream of bytes into a stream of @DumpPackage@s conduitDumpPackage :: MonadThrow m-                   => Conduit Text m (DumpPackage () () ())-conduitDumpPackage = (=$= CL.catMaybes) $ eachSection $ do-    pairs <- eachPair (\k -> (k, ) <$> CL.consume) =$= CL.consume+                   => ConduitM Text (DumpPackage () () ()) m ()+conduitDumpPackage = (.| CL.catMaybes) $ eachSection $ do+    pairs <- eachPair (\k -> (k, ) <$> CL.consume) .| CL.consume     let m = Map.fromList pairs     let parseS k =             case Map.lookup k m of@@ -355,6 +357,11 @@                         _ -> Nothing             depends <- mapMaybeM parseDepend $ concatMap T.words $ parseM "depends" +            -- Handle sublibs by recording the name of the parent library+            -- If name of parent library is missing, this is not a sublib.+            let mkParentLib n = PackageIdentifier n version+                parentLib = mkParentLib <$> (parseS "package-name" >>= parsePackageName)+             let parseQuoted key =                     case mapM (P.parseOnly (argsParser NoEscaping)) val of                         Left{} -> throwM (Couldn'tParseField key val)@@ -368,6 +375,7 @@             return $ Just DumpPackage                 { dpGhcPkgId = ghcPkgId                 , dpPackageIdent = PackageIdentifier name version+                , dpParentLibIdent = parentLib                 , dpLicense = license                 , dpLibDirs = libDirPaths                 , dpLibraries = T.words $ T.unwords libraries@@ -397,10 +405,10 @@  -- | Apply the given Sink to each section of output, broken by a single line containing --- eachSection :: Monad m-            => Sink Line m a-            -> Conduit Text m a+            => ConduitM Line Void m a+            -> ConduitM Text a m () eachSection inner =-    CL.map (T.filter (/= '\r')) =$= CT.lines =$= start+    CL.map (T.filter (/= '\r')) .| CT.lines .| start   where      peekText = await >>= maybe (return Nothing) (\bs ->@@ -411,22 +419,22 @@     start = peekText >>= maybe (return ()) (const go)      go = do-        x <- toConsumer $ takeWhileC (/= "---") =$= inner+        x <- toConsumer $ takeWhileC (/= "---") .| inner         yield x         CL.drop 1         start  -- | Grab each key/value pair eachPair :: Monad m-         => (Text -> Sink Line m a)-         -> Conduit Line m a+         => (Text -> ConduitM Line Void m a)+         -> ConduitM Line a m () eachPair inner =     start   where     start = await >>= maybe (return ()) start'      start' bs1 =-        toConsumer (valSrc =$= inner key) >>= yield >> start+        toConsumer (valSrc .| inner key) >>= yield >> start       where         (key, bs2) = T.break (== ':') bs1         (spaces, bs3) = T.span (== ' ') $ T.drop 1 bs2@@ -461,7 +469,7 @@             (spaces, val) = T.splitAt i bs  -- | General purpose utility-takeWhileC :: Monad m => (a -> Bool) -> Conduit a m a+takeWhileC :: Monad m => (a -> Bool) -> ConduitM a a m () takeWhileC f =     loop   where
src/Stack/PackageIndex.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoImplicitPrelude          #-} {-# LANGUAGE BangPatterns               #-}+{-# LANGUAGE CPP                        #-} {-# LANGUAGE ConstraintKinds            #-} {-# LANGUAGE DataKinds                  #-} {-# LANGUAGE DeriveDataTypeable         #-}@@ -24,13 +25,17 @@     , getPackageCaches     , getPackageVersions     , lookupPackageVersions+    , CabalLoader (..)+    , HasCabalLoader (..)+    , configPackageIndex+    , configPackageIndexRoot     ) where  import qualified Codec.Archive.Tar as Tar import           Stack.Prelude import           Data.Aeson.Extended+import qualified Data.ByteString.Char8 as B8 import qualified Data.ByteString.Lazy as L-import           Data.Conduit.Binary (sinkHandle, sourceHandle, sourceFile, sinkFile) import           Data.Conduit.Zlib (ungzip) import qualified Data.List.NonEmpty as NE import qualified Data.HashMap.Strict as HashMap@@ -49,31 +54,30 @@ import           Network.HTTP.Client.TLS (getGlobalManager) import           Network.HTTP.Download import           Network.URI (parseURI)-import           Path (toFilePath, parseAbsFile)+import           Path (toFilePath, parseAbsFile, mkRelDir, mkRelFile, (</>), parseRelDir) import           Path.Extra (tryGetModificationTime) import           Path.IO-import           Stack.Types.Config import           Stack.Types.PackageIdentifier import           Stack.Types.PackageIndex import           Stack.Types.PackageName+import           Stack.Types.Runner (HasRunner) import           Stack.Types.Version import qualified System.Directory as D import           System.FilePath ((<.>))  -- | Populate the package index caches and return them.-populateCache :: HasConfig env => PackageIndex -> RIO env (PackageCache ())+populateCache :: HasCabalLoader env => PackageIndex -> RIO env (PackageCache ()) populateCache index = do     requireIndex index     -- This uses full on lazy I/O instead of ResourceT to provide some     -- protections. Caveat emptor     path <- configPackageIndex (indexName index)-    let loadPIS = withBinaryFile (Path.toFilePath path) ReadMode $ \h -> do+    let loadPIS = withLazyFile (Path.toFilePath path) $ \lbs -> do             logSticky "Populating index cache ..."-            lbs <- liftIO $ L.hGetContents h             loop 0 HashMap.empty (Tar.read lbs)     pis0 <- loadPIS `catch` \e -> do         logWarn $ "Exception encountered when parsing index tarball: "-                <> T.pack (show (e :: Tar.FormatError))+                <> displayShow (e :: Tar.FormatError)         logWarn "Automatically updating index and trying again"         updateIndex index         loadPIS@@ -224,27 +228,28 @@         ]  -- | Require that an index be present, updating if it isn't.-requireIndex :: HasConfig env => PackageIndex -> RIO env ()+requireIndex :: HasCabalLoader env => PackageIndex -> RIO env () requireIndex index = do     tarFile <- configPackageIndex $ indexName index     exists <- doesFileExist tarFile     unless exists $ updateIndex index  -- | Update all of the package indices-updateAllIndices :: HasConfig env => RIO env ()+updateAllIndices :: HasCabalLoader env => RIO env () updateAllIndices = do     clearPackageCaches-    view packageIndicesL >>= mapM_ updateIndex+    cl <- view cabalLoaderL+    mapM_ updateIndex (clIndices cl)  -- | Update the index tarball-updateIndex :: HasConfig env => PackageIndex -> RIO env ()+updateIndex :: HasCabalLoader env => PackageIndex -> RIO env () updateIndex index =   do let name = indexName index          url = indexLocation index      logSticky $ "Updating package index "-               <> indexNameText (indexName index)+               <> display (indexNameText (indexName index))                <> " (mirrored at "-               <> url+               <> display url                <> ") ..."      case indexType index of        ITVanilla -> updateIndexHTTP name url@@ -257,16 +262,18 @@      oldTarFile <- configPackageIndexOld name      oldCacheFile <- configPackageIndexCacheOld name      liftIO $ ignoringAbsence (removeFile oldCacheFile)-     liftIO $ runConduitRes $ sourceFile (toFilePath tarFile) .| sinkFile (toFilePath oldTarFile)+     withSourceFile (toFilePath tarFile) $ \src ->+       withSinkFile (toFilePath oldTarFile) $ \sink ->+       runConduit $ src .| sink  -- | Update the index tarball via HTTP-updateIndexHTTP :: HasConfig env+updateIndexHTTP :: HasCabalLoader env                 => IndexName                 -> Text -- ^ url                 -> RIO env () updateIndexHTTP indexName' url = do     req <- parseRequest $ T.unpack url-    logInfo ("Downloading package index from " <> url)+    logInfo ("Downloading package index from " <> display url)     gz <- configPackageIndexGz indexName'     tar <- configPackageIndex indexName'     wasDownloaded <- redownload req gz@@ -284,16 +291,14 @@             deleteCache indexName'              liftIO $ do-                withBinaryFile (toFilePath gz) ReadMode $ \input ->-                    withBinaryFile tmp WriteMode $ \output -> runConduit-                      $ sourceHandle input-                     .| ungzip-                     .| sinkHandle output+                withSourceFile (toFilePath gz) $ \input ->+                  withSinkFile tmp $ \output -> -- FIXME use withSinkFileCautious+                  runConduit $ input .| ungzip .| output                 renameFile tmpPath tar  -- | Update the index tarball via Hackage Security updateIndexHackageSecurity-    :: HasConfig env+    :: HasCabalLoader env     => IndexName     -> Text -- ^ base URL     -> HackageSecurity@@ -306,7 +311,7 @@     manager <- liftIO getGlobalManager     root <- configPackageIndexRoot indexName'     run <- askRunInIO-    let logTUF = run . logInfo . T.pack . HS.pretty+    let logTUF = run . logInfo . fromString . HS.pretty         withRepo = HS.withRepository             (HS.makeHttpLib manager)             [baseURI]@@ -350,7 +355,7 @@ -- but exited before deleting the cache. -- -- See https://github.com/commercialhaskell/stack/issues/3033-packageIndexNotUpdated :: HasConfig env => IndexName -> RIO env ()+packageIndexNotUpdated :: HasCabalLoader env => IndexName -> RIO env () packageIndexNotUpdated indexName' = do     mindexModTime <- tryGetModificationTime =<< configPackageIndex indexName'     mcacheModTime <- tryGetModificationTime =<< configPackageIndexCache indexName'@@ -364,19 +369,19 @@         _ -> logInfo "No updates to your package index were found"  -- | Delete the package index cache-deleteCache :: HasConfig env => IndexName -> RIO env ()+deleteCache :: HasCabalLoader env => IndexName -> RIO env () deleteCache indexName' = do     fp <- configPackageIndexCache indexName'     eres <- liftIO $ tryIO $ removeFile fp     case eres of-        Left e -> logDebug $ "Could not delete cache: " <> T.pack (show e)-        Right () -> logDebug $ "Deleted index cache at " <> T.pack (toFilePath fp)+        Left e -> logDebug $ "Could not delete cache: " <> displayShow e+        Right () -> logDebug $ "Deleted index cache at " <> fromString (toFilePath fp)  -- | Get the known versions for a given package from the package caches. -- -- See 'getPackageCaches' for performance notes.-getPackageVersions :: HasConfig env => PackageName -> RIO env (Set Version)-getPackageVersions pkgName = fmap (lookupPackageVersions pkgName) getPackageCaches+getPackageVersions :: HasCabalLoader env => PackageName -> RIO env (Set Version)+getPackageVersions pkgName = lookupPackageVersions pkgName <$> getPackageCaches  lookupPackageVersions :: PackageName -> PackageCache index -> Set Version lookupPackageVersions pkgName (PackageCache m) =@@ -386,30 +391,100 @@ -- -- This has two levels of caching: in memory, and the on-disk cache. So, -- feel free to call this function multiple times.-getPackageCaches :: HasConfig env => RIO env (PackageCache PackageIndex)+getPackageCaches :: HasCabalLoader env => RIO env (PackageCache PackageIndex) getPackageCaches = do-    config <- view configL-    mcached <- liftIO $ readIORef (configPackageCache config)+    cl <- view cabalLoaderL+    mcached <- readIORef (clCache cl)     case mcached of         Just cached -> return cached         Nothing -> do-            result <- liftM mconcat $ forM (configPackageIndices config) $ \index -> do+            result <- liftM mconcat $ forM (clIndices cl) $ \index -> do                 fp <- configPackageIndexCache (indexName index)                 PackageCache pis <-+#if MIN_VERSION_template_haskell(2,13,0)+                    $(versionedDecodeOrLoad (storeVersionConfig "pkg-v5" "LLL6OCcimOqRm3r0JmsSlLHcaLE="+#else                     $(versionedDecodeOrLoad (storeVersionConfig "pkg-v5" "A607WaDwhg5VVvZTxNgU9g52DO8="+#endif                                              :: VersionConfig (PackageCache ())))                     fp                     (populateCache index)                 return $ PackageCache ((fmap.fmap) (\((), mpd, files) -> (index, mpd, files)) pis)-            liftIO $ writeIORef (configPackageCache config) (Just result)+            liftIO $ writeIORef (clCache cl) (Just result)             return result  -- | Clear the in-memory hackage index cache. This is needed when the -- hackage index is updated.-clearPackageCaches :: HasConfig env => RIO env ()+clearPackageCaches :: HasCabalLoader env => RIO env () clearPackageCaches = do-    cacheRef <- view $ configL.to configPackageCache-    liftIO $ writeIORef cacheRef Nothing+  cl <- view cabalLoaderL+  writeIORef (clCache cl) Nothing++class HasRunner env => HasCabalLoader env where+  cabalLoaderL :: Lens' env CabalLoader++data CabalLoader = CabalLoader+  { clCache :: !(IORef (Maybe (PackageCache PackageIndex)))+  , clIndices :: ![PackageIndex]+  -- ^ Information on package indices. This is left biased, meaning that+  -- packages in an earlier index will shadow those in a later index.+  --+  -- Warning: if you override packages in an index vs what's available+  -- upstream, you may correct your compiled snapshots, as different+  -- projects may have different definitions of what pkg-ver means! This+  -- feature is primarily intended for adding local packages, not+  -- overriding. Overriding is better accomplished by adding to your+  -- list of packages.+  --+  -- Note that indices specified in a later config file will override+  -- previous indices, /not/ extend them.+  --+  -- Using an assoc list instead of a Map to keep track of priority+  , clStackRoot :: !(Path Abs Dir)+  -- ^ ~/.stack more often than not+  , clUpdateRef :: !(MVar Bool)+  -- ^ Want to try updating the index once during a single run for missing+  -- package identifiers. We also want to ensure we only update once at a+  -- time. Start at @True@.+  --+  -- TODO: probably makes sense to move this concern into getPackageCaches+  , clConnectionCount :: !Int+  -- ^ How many concurrent connections are allowed when downloading+  , clIgnoreRevisionMismatch :: !Bool+  -- ^ Ignore a revision mismatch when loading up cabal files,+  -- and fall back to the latest revision. See:+  -- <https://github.com/commercialhaskell/stack/issues/3520>+  }++-- | Root for a specific package index+configPackageIndexRoot :: HasCabalLoader env => IndexName -> RIO env (Path Abs Dir)+configPackageIndexRoot (IndexName name) = do+    cl <- view cabalLoaderL+    let root = clStackRoot cl+    dir <- parseRelDir $ B8.unpack name+    return (root </> $(mkRelDir "indices") </> dir)++-- | Location of the 01-index.tar file+configPackageIndex :: HasCabalLoader env => IndexName -> RIO env (Path Abs File)+configPackageIndex name = (</> $(mkRelFile "01-index.tar")) <$> configPackageIndexRoot name++-- | Location of the 01-index.cache file+configPackageIndexCache :: HasCabalLoader env => IndexName -> RIO env (Path Abs File)+configPackageIndexCache name = (</> $(mkRelFile "01-index.cache")) <$> configPackageIndexRoot name++-- | Location of the 00-index.cache file+configPackageIndexCacheOld :: HasCabalLoader env => IndexName -> RIO env (Path Abs File)+configPackageIndexCacheOld = liftM (</> $(mkRelFile "00-index.cache")) . configPackageIndexRoot++-- | Location of the 00-index.tar file. This file is just a copy of+-- the 01-index.tar file, provided for tools which still look for the+-- 00-index.tar file.+configPackageIndexOld :: HasCabalLoader env => IndexName -> RIO env (Path Abs File)+configPackageIndexOld = liftM (</> $(mkRelFile "00-index.tar")) . configPackageIndexRoot++-- | Location of the 01-index.tar.gz file+configPackageIndexGz :: HasCabalLoader env => IndexName -> RIO env (Path Abs File)+configPackageIndexGz = liftM (</> $(mkRelFile "01-index.tar.gz")) . configPackageIndexRoot  --------------- Lifted from cabal-install, Distribution.Client.Tar: -- | Return the number of blocks in an entry.
src/Stack/PackageLocation.hs view
@@ -25,7 +25,6 @@ import qualified Data.ByteArray as Mem (convert) import qualified Data.ByteString as S import qualified Data.ByteString.Base64.URL as B64URL-import qualified Data.ByteString.Lazy as L import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8, decodeUtf8) import Distribution.PackageDescription (GenericPackageDescription)@@ -39,8 +38,7 @@ import Stack.Types.Config import Stack.Types.PackageIdentifier import qualified System.Directory as Dir-import System.Process.Read-import System.Process.Run+import RIO.Process  -- | Same as 'resolveMultiPackageLocation', but works on a -- 'SinglePackageLocation'.@@ -109,31 +107,30 @@          let fp = toFilePath file -        withBinaryFile fp ReadMode $ \h -> do+        withLazyFile fp $ \lbs -> do           -- Share a single file read among all of the different           -- parsing attempts. We're not worried about unbounded           -- memory usage, as we will detect almost immediately if           -- this is the wrong type of file.-          lbs <- liftIO $ L.hGetContents h            let tryTargz = do-                logDebug $ "Trying to ungzip/untar " <> T.pack fp+                logDebug $ "Trying to ungzip/untar " <> fromString fp                 let entries = Tar.read $ GZip.decompress lbs                 liftIO $ Tar.unpack (toFilePath dirTmp) entries               tryZip = do-                logDebug $ "Trying to unzip " <> T.pack fp+                logDebug $ "Trying to unzip " <> fromString fp                 let archive = Zip.toArchive lbs                 liftIO $  Zip.extractFilesFromArchive [Zip.OptDestination                                                        (toFilePath dirTmp)] archive               tryTar = do-                logDebug $ "Trying to untar (no ungzip) " <> T.pack fp+                logDebug $ "Trying to untar (no ungzip) " <> fromString fp                 let entries = Tar.read lbs                 liftIO $ Tar.unpack (toFilePath dirTmp) entries               err = throwM $ UnableToExtractArchive url file                catchAnyLog goodpath handler =                   catchAny goodpath $ \e -> do-                      logDebug $ "Got exception: " <> T.pack (show e)+                      logDebug $ "Got exception: " <> displayShow e                       handler            tryTargz `catchAnyLog` tryZip `catchAnyLog` tryTar `catchAnyLog` err@@ -204,31 +201,29 @@     exists <- doesDirExist dir     unless exists $ do         liftIO $ ignoringAbsence (removeDirRecur dir)-        menv <- getMinimalEnvOverride -        let cloneAndExtract commandName cloneArgs resetCommand = do+        let cloneAndExtract commandName cloneArgs resetCommand =+              withWorkingDir (toFilePath root) $ do                 ensureDir root-                logInfo $ "Cloning " <> commit <> " from " <> url-                callProcessInheritStderrStdout Cmd-                    { cmdDirectoryToRunIn = Just root-                    , cmdCommandToRun = commandName-                    , cmdEnvOverride = menv-                    , cmdCommandLineArguments =-                        "clone" :+                logInfo $ "Cloning " <> display commit <> " from " <> display url+                proc commandName+                       ("clone" :                         cloneArgs ++                         [ T.unpack url                         , toFilePathNoTrailingSep dir-                        ]-                    }+                        ]) runProcess_                 created <- doesDirExist dir                 unless created $ throwM $ FailedToCloneRepo commandName-                readProcessNull (Just dir) menv commandName+                withWorkingDir (toFilePath dir) $ readProcessNull commandName                     (resetCommand ++ [T.unpack commit, "--"])-                    `catch` \case-                        ex@ProcessFailed{} -> do-                            logInfo $ "Please ensure that commit " <> commit <> " exists within " <> url+                    `catchAny` \case+                        ex -> do+                            logInfo $+                              "Please ensure that commit " <>+                              display commit <>+                              " exists within " <>+                              display url                             throwM ex-                        ex -> throwM ex          case repoType' of             RepoGit -> cloneAndExtract "git" ["--recursive"] ["--git-dir=.git", "reset", "--hard"]@@ -241,15 +236,14 @@ parseSingleCabalFileIndex   :: forall env.      HasConfig env-  => (PackageIdentifierRevision -> IO ByteString) -- ^ lookup in index-  -> Path Abs Dir -- ^ project root, used for checking out necessary files+  => Path Abs Dir -- ^ project root, used for checking out necessary files   -> PackageLocationIndex FilePath   -> RIO env GenericPackageDescription -- Need special handling of PLIndex for efficiency (just read from the -- index tarball) and correctness (get the cabal file from the index, -- not the package tarball itself, yay Hackage revisions).-parseSingleCabalFileIndex loadFromIndex _ (PLIndex pir) = readPackageUnresolvedIndex loadFromIndex pir-parseSingleCabalFileIndex _ root (PLOther loc) = lpvGPD <$> parseSingleCabalFile root False loc+parseSingleCabalFileIndex _ (PLIndex pir) = readPackageUnresolvedIndex pir+parseSingleCabalFileIndex root (PLOther loc) = lpvGPD <$> parseSingleCabalFile root False loc  parseSingleCabalFile   :: forall env. HasConfig env@@ -286,13 +280,12 @@ -- | 'parseMultiCabalFiles' but supports 'PLIndex' parseMultiCabalFilesIndex   :: forall env. HasConfig env-  => (PackageIdentifierRevision -> IO ByteString)-  -> Path Abs Dir -- ^ project root, used for checking out necessary files+  => Path Abs Dir -- ^ project root, used for checking out necessary files   -> PackageLocationIndex Subdirs   -> RIO env [(GenericPackageDescription, PackageLocationIndex FilePath)]-parseMultiCabalFilesIndex loadFromIndex _root (PLIndex pir) =-  (pure . (, PLIndex pir)) <$>-  readPackageUnresolvedIndex loadFromIndex pir-parseMultiCabalFilesIndex _ root (PLOther loc0) =+parseMultiCabalFilesIndex _root (PLIndex pir) =+  pure . (, PLIndex pir) <$>+  readPackageUnresolvedIndex pir+parseMultiCabalFilesIndex root (PLOther loc0) =   map (\lpv -> (lpvGPD lpv, PLOther $ lpvLoc lpv)) <$>   parseMultiCabalFiles root False loc0
src/Stack/Path.hs view
@@ -20,19 +20,19 @@ import           Stack.Constants import           Stack.Constants.Config import           Stack.GhcPkg as GhcPkg+import           Stack.PackageIndex (HasCabalLoader (..)) import           Stack.Types.Config import           Stack.Types.Runner import qualified System.FilePath as FP import           System.IO (stderr)-import           System.Process.Read (EnvOverride(eoPath))+import           RIO.Process (HasProcessContext (..), exeSearchPathL)  -- | Print out useful path information in a human-readable format (and -- support others later). path-    :: (MonadUnliftIO m, MonadReader env m, HasEnvConfig env, MonadThrow m,-        MonadLogger m)+    :: HasEnvConfig env     => [Text]-    -> m ()+    -> RIO env () path keys =     do -- We must use a BuildConfig from an EnvConfig to ensure that it contains the        -- full environment info including GHC paths etc.@@ -42,12 +42,11 @@        -- global GHC.        -- It was set up in 'withBuildConfigAndLock -> withBuildConfigExt -> setupEnv'.        -- So it's not the *minimal* override path.-       menv <- getMinimalEnvOverride        snap <- packageDatabaseDeps        plocal <- packageDatabaseLocal        extra <- packageDatabaseExtra        whichCompiler <- view $ actualCompilerVersionL.whichCompilerL-       global <- GhcPkg.getGlobalDB menv whichCompiler+       global <- GhcPkg.getGlobalDB whichCompiler        snaproot <- installationRootDeps        localroot <- installationRootLocal        toolsDir <- bindirCompilerTools@@ -78,7 +77,6 @@                       path'                           (PathInfo                                bc-                               menv                                snap                                plocal                                global@@ -103,7 +101,6 @@ -- | Passed to all the path printers as a source of info. data PathInfo = PathInfo     { piBuildConfig  :: BuildConfig-    , piEnvOverride  :: EnvOverride     , piSnapDb       :: Path Abs Dir     , piLocalDb      :: Path Abs Dir     , piGlobalDb     :: Path Abs Dir@@ -122,6 +119,10 @@ instance HasRunner PathInfo where     runnerL = configL.runnerL instance HasConfig PathInfo+instance HasCabalLoader PathInfo where+    cabalLoaderL = configL.cabalLoaderL+instance HasProcessContext PathInfo where+    processContextL = configL.processContextL instance HasBuildConfig PathInfo where     buildConfigL = lens piBuildConfig (\x y -> x { piBuildConfig = y })                  . buildConfigL@@ -148,7 +149,7 @@       , view $ stackYamlL.to toFilePath.to T.pack)     , ( "PATH environment variable"       , "bin-path"-      , T.pack . intercalate [FP.searchPathSeparator] . eoPath . piEnvOverride )+      , T.pack . intercalate [FP.searchPathSeparator] . view exeSearchPathL)     , ( "Install location for GHC and other core tools"       , "programs"       , view $ configL.to configLocalPrograms.to toFilePathNoTrailingSep.to T.pack)
src/Stack/Prelude.hs view
@@ -1,216 +1,153 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE NoImplicitPrelude          #-} {-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE ScopedTypeVariables        #-} module Stack.Prelude-  ( mapLeft-  , ResourceT-  , runConduitRes-  , runResourceT-  , liftResourceT-  , NoLogging (..)+  ( withSourceFile+  , withSinkFile+  , withSinkFileCautious   , withSystemTempDir-  , fromFirst-  , mapMaybeA-  , mapMaybeM-  , forMaybeA-  , forMaybeM+  , withKeepSystemTempDir+  , sinkProcessStderrStdout+  , sinkProcessStdout+  , logProcessStderrStdout+  , readProcessNull+  , withProcessContext   , stripCR-  , logSticky-  , logStickyDone-  , RIO (..)-  , runRIO-  , HasLogFunc (..)   , module X   ) where -import           Control.Applicative  as X (Alternative, Applicative (..),-                                            liftA, liftA2, liftA3, many,-                                            optional, some, (<|>))-import           Control.Arrow        as X (first, second, (&&&), (***))-import           Control.DeepSeq      as X (NFData (..), force, ($!!))-import           Control.Monad        as X (Monad (..), MonadPlus (..), filterM,-                                            foldM, foldM_, forever, guard, join,-                                            liftM, liftM2, replicateM_, unless,-                                            when, zipWithM, zipWithM_, (<$!>),-                                            (<=<), (=<<), (>=>))-import           Control.Monad.Catch  as X (MonadThrow (..))-import           Control.Monad.Logger.CallStack-                                      as X (Loc, LogLevel (..), LogSource,-                                            LogStr, MonadLogger (..),-                                            MonadLoggerIO (..), liftLoc,-                                            logDebug, logError, logInfo,-                                            logOther, logWarn, toLogStr)-import           Control.Monad.Reader as X (MonadReader, MonadTrans (..),-                                            ReaderT (..), ask, asks)-import           Data.Bool            as X (Bool (..), not, otherwise, (&&),-                                            (||))-import           Data.ByteString      as X (ByteString)-import           Data.Char            as X (Char)+import           RIO                  as X import           Data.Conduit         as X (ConduitM, runConduit, (.|))-import           Data.Data            as X (Data (..))-import           Data.Either          as X (Either (..), either, isLeft,-                                            isRight, lefts, partitionEithers,-                                            rights)-import           Data.Eq              as X (Eq (..))-import           Data.Foldable        as X (Foldable, all, and, any, asum,-                                            concat, concatMap, elem, fold,-                                            foldMap, foldl', foldr, forM_, for_,-                                            length, mapM_, msum, notElem, null,-                                            or, product, sequenceA_, sequence_,-                                            sum, toList, traverse_)-import           Data.Function        as X (const, fix, flip, id, on, ($), (&),-                                            (.))-import           Data.Functor         as X (Functor (..), void, ($>), (<$),-                                            (<$>))-import           Data.Hashable        as X (Hashable)-import           Data.HashMap.Strict  as X (HashMap)-import           Data.HashSet         as X (HashSet)-import           Data.Int             as X-import           Data.IntMap.Strict   as X (IntMap)-import           Data.IntSet          as X (IntSet)-import           Data.List            as X (break, drop, dropWhile, filter,-                                            lines, lookup, map, replicate,-                                            reverse, span, take, takeWhile,-                                            unlines, unwords, words, zip, (++))-import           Data.Map.Strict      as X (Map)-import           Data.Maybe           as X (Maybe (..), catMaybes, fromMaybe,-                                            isJust, isNothing, listToMaybe,-                                            mapMaybe, maybe, maybeToList)-import           Data.Monoid          as X (All (..), Any (..), Endo (..),-                                            First (..), Last (..), Monoid (..),-                                            Product (..), Sum (..), (<>))-import           Data.Ord             as X (Ord (..), Ordering (..), comparing)-import           Data.Set             as X (Set)-import           Data.Store           as X (Store)-import           Data.String          as X (IsString (..))-import           Data.Text            as X (Text)-import           Data.Traversable     as X (Traversable (..), for, forM)-import           Data.Vector          as X (Vector)-import           Data.Void            as X (Void, absurd)-import           Data.Word            as X-import           GHC.Generics         as X (Generic)-import           GHC.Stack            as X (HasCallStack)-import           Lens.Micro           as X (Getting)-import           Lens.Micro.Mtl       as X (view) import           Path                 as X (Abs, Dir, File, Path, Rel,                                             toFilePath)-import           Prelude              as X (Bounded (..), Double, Enum,-                                            FilePath, Float, Floating (..),-                                            Fractional (..), IO, Integer,-                                            Integral (..), Num (..), Rational,-                                            Real (..), RealFloat (..),-                                            RealFrac (..), Show, String,-                                            asTypeOf, curry, error, even,-                                            fromIntegral, fst, gcd, lcm, odd,-                                            realToFrac, seq, show, snd,-                                            subtract, uncurry, undefined, ($!),-                                            (^), (^^))-import           Text.Read            as X (Read, readMaybe)-import           UnliftIO             as X -import qualified Data.Text            as T-import qualified Path.IO--import qualified Control.Monad.Trans.Resource as Res (runResourceT, transResourceT)-import           Control.Monad.Trans.Resource.Internal (ResourceT (ResourceT))--mapLeft :: (a1 -> a2) -> Either a1 b -> Either a2 b-mapLeft f (Left a1) = Left (f a1)-mapLeft _ (Right b) = Right b--fromFirst :: a -> First a -> a-fromFirst x = fromMaybe x . getFirst---- | Applicative 'mapMaybe'.-mapMaybeA :: Applicative f => (a -> f (Maybe b)) -> [a] -> f [b]-mapMaybeA f = fmap catMaybes . traverse f---- | @'forMaybeA' '==' 'flip' 'mapMaybeA'@-forMaybeA :: Applicative f => [a] -> (a -> f (Maybe b)) -> f [b]-forMaybeA = flip mapMaybeA+import           Data.Monoid          as X (First (..), Any (..), Sum (..), Endo (..)) --- | Monadic 'mapMaybe'.-mapMaybeM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]-mapMaybeM f = liftM catMaybes . mapM f+import qualified Path.IO --- | @'forMaybeM' '==' 'flip' 'mapMaybeM'@-forMaybeM :: Monad m => [a] -> (a -> m (Maybe b)) -> m [b]-forMaybeM = flip mapMaybeM+import qualified System.IO as IO+import qualified System.Directory as Dir+import qualified System.FilePath as FP+import           System.IO.Error (isDoesNotExistError) --- | Strip trailing carriage return from Text-stripCR :: T.Text -> T.Text-stripCR t = fromMaybe t (T.stripSuffix "\r" t)+import           Data.Conduit.Binary (sourceHandle, sinkHandle)+import qualified Data.Conduit.Binary as CB+import qualified Data.Conduit.List as CL+import           Data.Conduit.Process.Typed (withLoggedProcess_, createSource)+import           RIO.Process (HasProcessContext (..), ProcessContext, setStdin, closed, getStderr, getStdout, proc, withProcess_, setStdout, setStderr, ProcessConfig, readProcessStdout_, workingDirL)+import           Data.Store           as X (Store)+import           Data.Text.Encoding (decodeUtf8With)+import           Data.Text.Encoding.Error (lenientDecode) -runConduitRes :: MonadUnliftIO m => ConduitM () Void (ResourceT m) r -> m r-runConduitRes = runResourceT . runConduit+import qualified RIO.Text as T -runResourceT :: MonadUnliftIO m => ResourceT m a -> m a-runResourceT r = withRunInIO $ \run -> Res.runResourceT (Res.transResourceT run r)+-- | Get a source for a file. Unlike @sourceFile@, doesn't require+-- @ResourceT@. Unlike explicit @withBinaryFile@ and @sourceHandle@+-- usage, you can't accidentally use @WriteMode@ instead of+-- @ReadMode@.+withSourceFile :: MonadUnliftIO m => FilePath -> (ConduitM i ByteString m () -> m a) -> m a+withSourceFile fp inner = withBinaryFile fp ReadMode $ inner . sourceHandle -liftResourceT :: MonadIO m => ResourceT IO a -> ResourceT m a-liftResourceT (ResourceT f) = ResourceT $ liftIO . f+-- | Same idea as 'withSourceFile', see comments there.+withSinkFile :: MonadUnliftIO m => FilePath -> (ConduitM ByteString o m () -> m a) -> m a+withSinkFile fp inner = withBinaryFile fp WriteMode $ inner . sinkHandle --- | Avoid orphan messes-newtype NoLogging a = NoLogging { runNoLogging :: IO a }-  deriving (Functor, Applicative, Monad, MonadIO)-instance MonadUnliftIO NoLogging where-  askUnliftIO = NoLogging $-                withUnliftIO $ \u ->-                return (UnliftIO (unliftIO u . runNoLogging))-instance MonadLogger NoLogging where-  monadLoggerLog _ _ _ _ = return ()+-- | Like 'withSinkFile', but ensures that the file is atomically+-- moved after all contents are written.+withSinkFileCautious+  :: MonadUnliftIO m+  => FilePath+  -> (ConduitM ByteString o m () -> m a)+  -> m a+withSinkFileCautious fp inner =+    withRunInIO $ \run -> bracket acquire cleanup $ \(tmpFP, h) ->+      run (inner $ sinkHandle h) <* (IO.hClose h *> Dir.renameFile tmpFP fp)+  where+    acquire = IO.openBinaryTempFile (FP.takeDirectory fp) (FP.takeFileName fp FP.<.> "tmp")+    cleanup (tmpFP, h) = do+        IO.hClose h+        Dir.removeFile tmpFP `catch` \e ->+            if isDoesNotExistError e+                then return ()+                else throwIO e  -- | Path version withSystemTempDir :: MonadUnliftIO m => String -> (Path Abs Dir -> m a) -> m a withSystemTempDir str inner = withRunInIO $ \run -> Path.IO.withSystemTempDir str $ run . inner --- | Write a "sticky" line to the terminal. Any subsequent lines will--- overwrite this one, and that same line will be repeated below--- again. In other words, the line sticks at the bottom of the output--- forever. Running this function again will replace the sticky line--- with a new sticky line. When you want to get rid of the sticky--- line, run 'logStickyDone'.----logSticky :: MonadLogger m => Text -> m ()-logSticky =-    logOther (LevelOther "sticky")+-- | Like `withSystemTempDir`, but the temporary directory is not deleted.+withKeepSystemTempDir :: MonadUnliftIO m => String -> (Path Abs Dir -> m a) -> m a+withKeepSystemTempDir str inner = withRunInIO $ \run -> do+  path <- Path.IO.getTempDir+  dir <- Path.IO.createTempDir path str+  run $ inner dir --- | This will print out the given message with a newline and disable--- any further stickiness of the line until a new call to 'logSticky'--- happens.+-- | Consume the stdout and stderr of a process feeding strict 'ByteString's to the consumers. ----- It might be better at some point to have a 'runSticky' function--- that encompasses the logSticky->logStickyDone pairing.-logStickyDone :: MonadLogger m => Text -> m ()-logStickyDone =-    logOther (LevelOther "sticky-done")+-- Throws a 'ReadProcessException' if unsuccessful in launching, or 'ProcessExitedUnsuccessfully' if the process itself fails.+sinkProcessStderrStdout+  :: forall e o env. (HasProcessContext env, HasLogFunc env)+  => String -- ^ Command+  -> [String] -- ^ Command line arguments+  -> ConduitM ByteString Void (RIO env) e -- ^ Sink for stderr+  -> ConduitM ByteString Void (RIO env) o -- ^ Sink for stdout+  -> RIO env (e,o)+sinkProcessStderrStdout name args sinkStderr sinkStdout =+  proc name args $ \pc0 -> do+    let pc = setStdout createSource+           $ setStderr createSource+             pc0+    withProcess_ pc $ \p ->+      runConduit (getStderr p .| sinkStderr) `concurrently`+      runConduit (getStdout p .| sinkStdout) --- | The Reader+IO monad. This is different from a 'ReaderT' because:------ * It's not a transformer, it hardcodes IO for simpler usage and--- error messages.+-- | Consume the stdout of a process feeding strict 'ByteString's to a consumer.+-- If the process fails, spits out stdout and stderr as error log+-- level. Should not be used for long-running processes or ones with+-- lots of output; for that use 'sinkProcessStderrStdout'. ----- * Instances of typeclasses like 'MonadLogger' are implemented using--- classes defined on the environment, instead of using an--- underlying monad.-newtype RIO env a = RIO { unRIO :: ReaderT env IO a }-  deriving (Functor,Applicative,Monad,MonadIO,MonadReader env,MonadThrow)--runRIO :: MonadIO m => env -> RIO env a -> m a-runRIO env (RIO (ReaderT f)) = liftIO (f env)+-- Throws a 'ReadProcessException' if unsuccessful.+sinkProcessStdout+    :: (HasProcessContext env, HasLogFunc env)+    => String -- ^ Command+    -> [String] -- ^ Command line arguments+    -> ConduitM ByteString Void (RIO env) a -- ^ Sink for stdout+    -> RIO env a+sinkProcessStdout name args sinkStdout =+  proc name args $ \pc ->+  withLoggedProcess_ (setStdin closed pc) $ \p -> runConcurrently+    $ Concurrently (runConduit $ getStderr p .| CL.sinkNull)+   *> Concurrently (runConduit $ getStdout p .| sinkStdout) -class HasLogFunc env where-  logFuncL :: Getting r env (Loc -> LogSource -> LogLevel -> LogStr -> IO ())+logProcessStderrStdout+    :: (HasCallStack, HasProcessContext env, HasLogFunc env)+    => ProcessConfig stdin stdoutIgnored stderrIgnored+    -> RIO env ()+logProcessStderrStdout pc = withLoggedProcess_ pc $ \p ->+    let logLines = CB.lines .| CL.mapM_ (logInfo . displayBytesUtf8)+     in runConcurrently+            $ Concurrently (runConduit $ getStdout p .| logLines)+           *> Concurrently (runConduit $ getStderr p .| logLines) -instance HasLogFunc env => MonadLogger (RIO env) where-  monadLoggerLog a b c d = do-    f <- view logFuncL-    liftIO $ f a b c $ toLogStr d+-- | Read from the process, ignoring any output.+--+-- Throws a 'ReadProcessException' exception if the process fails.+readProcessNull :: (HasProcessContext env, HasLogFunc env)+                => String -- ^ Command+                -> [String] -- ^ Command line arguments+                -> RIO env ()+readProcessNull name args =+  -- We want the output to appear in any exceptions, so we capture and drop it+  void $ proc name args readProcessStdout_ -instance HasLogFunc env => MonadLoggerIO (RIO env) where-  askLoggerIO = view logFuncL+-- | Use the new 'ProcessContext', but retain the working directory+-- from the parent environment.+withProcessContext :: HasProcessContext env => ProcessContext -> RIO env a -> RIO env a+withProcessContext pcNew inner = do+  pcOld <- view processContextL+  let pcNew' = set workingDirL (view workingDirL pcOld) pcNew+  local (set processContextL pcNew') inner -instance MonadUnliftIO (RIO env) where-    askUnliftIO = RIO $ ReaderT $ \r ->-                  withUnliftIO $ \u ->-                  return (UnliftIO (unliftIO u . flip runReaderT r . unRIO))+-- | Remove a trailing carriage return if present+stripCR :: Text -> Text+stripCR = T.dropSuffix "\r"
src/Stack/PrettyPrint.hs view
@@ -9,15 +9,16 @@       -- * Pretty printing functions       displayPlain, displayWithColor       -- * Logging based on pretty-print typeclass-    , prettyDebug, prettyInfo, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent-    , prettyDebugL, prettyInfoL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL-    , prettyDebugS, prettyInfoS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS+    , prettyDebug, prettyInfo, prettyNote, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent+    , prettyDebugL, prettyInfoL, prettyNoteL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL+    , prettyDebugS, prettyInfoS, prettyNoteS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS       -- * Semantic styling functions       -- | These are preferred to styling or colors directly, so that we can       -- encourage consistency.     , styleWarning, styleError, styleGood     , styleShell, styleFile, styleUrl, styleDir, styleModule     , styleCurrent, styleTarget+    , styleRecommendation     , displayMilliseconds       -- * Formatting utils     , bulletedList@@ -34,42 +35,46 @@     , indentAfterLabel, wordDocs, flow     ) where -import           Stack.Prelude+import qualified RIO+import           Stack.Prelude hiding (Display (..)) import           Data.List (intersperse) import qualified Data.Text as T-import           Stack.Types.Config-import           Stack.Types.Package+import qualified Distribution.ModuleName as C (ModuleName)+import qualified Distribution.Text as C (display)+import           Stack.Types.NamedComponent import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Runner import           Stack.Types.Version-import qualified System.Clock as Clock import           Text.PrettyPrint.Leijen.Extended  displayWithColor     :: (HasRunner env, Display a, HasAnsiAnn (Ann a),-        MonadReader env m, MonadLogger m)+        MonadReader env m, HasLogFunc env, HasCallStack)     => a -> m T.Text displayWithColor x = do-    useAnsi <- liftM logUseColor $ view logOptionsL-    termWidth <- liftM logTermWidth $ view logOptionsL+    useAnsi <- view useColorL+    termWidth <- view $ runnerL.to runnerTermWidth     return $ (if useAnsi then displayAnsi else displayPlain) termWidth x  -- TODO: switch to using implicit callstacks once 7.8 support is dropped  prettyWith :: (HasRunner env, HasCallStack, Display b, HasAnsiAnn (Ann b),-               MonadReader env m, MonadLogger m)+               MonadReader env m, MonadIO m)            => LogLevel -> (a -> b) -> a -> m ()-prettyWith level f = logOther level <=< displayWithColor . f+prettyWith level f = logGeneric "" level . RIO.display <=< displayWithColor . f  -- Note: I think keeping this section aligned helps spot errors, might be -- worth keeping the alignment in place. -prettyDebugWith, prettyInfoWith, prettyWarnWith, prettyErrorWith, prettyWarnNoIndentWith, prettyErrorNoIndentWith-  :: (HasCallStack, HasRunner env, MonadReader env m, MonadLogger m)+prettyDebugWith, prettyInfoWith, prettyNoteWith, prettyWarnWith, prettyErrorWith, prettyWarnNoIndentWith, prettyErrorNoIndentWith+  :: (HasCallStack, HasRunner env, MonadReader env m, MonadIO m)   => (a -> Doc AnsiAnn) -> a -> m () prettyDebugWith = prettyWith LevelDebug prettyInfoWith  = prettyWith LevelInfo+prettyNoteWith f  = prettyWith LevelInfo+                          ((line <>) . (styleGood "Note:" <+>) .+                           indentAfterLabel . f) prettyWarnWith f  = prettyWith LevelWarn                           ((line <>) . (styleWarning "Warning:" <+>) .                            indentAfterLabel . f)@@ -81,31 +86,34 @@ prettyErrorNoIndentWith f = prettyWith LevelWarn                                   ((line <>) . (styleError   "Error:" <+>) . f) -prettyDebug, prettyInfo, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent-  :: (HasCallStack, HasRunner env, MonadReader env m, MonadLogger m)+prettyDebug, prettyInfo, prettyNote, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent+  :: (HasCallStack, HasRunner env, MonadReader env m, MonadIO m)   => Doc AnsiAnn -> m () prettyDebug         = prettyDebugWith         id prettyInfo          = prettyInfoWith          id+prettyNote          = prettyNoteWith          id prettyWarn          = prettyWarnWith          id prettyError         = prettyErrorWith         id prettyWarnNoIndent  = prettyWarnNoIndentWith  id prettyErrorNoIndent = prettyErrorNoIndentWith id -prettyDebugL, prettyInfoL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL-  :: (HasCallStack, HasRunner env, MonadReader env m, MonadLogger m)+prettyDebugL, prettyInfoL, prettyNoteL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL+  :: (HasCallStack, HasRunner env, MonadReader env m, MonadIO m)   => [Doc AnsiAnn] -> m () prettyDebugL         = prettyDebugWith         fillSep prettyInfoL          = prettyInfoWith          fillSep+prettyNoteL          = prettyNoteWith          fillSep prettyWarnL          = prettyWarnWith          fillSep prettyErrorL         = prettyErrorWith         fillSep prettyWarnNoIndentL  = prettyWarnNoIndentWith  fillSep prettyErrorNoIndentL = prettyErrorNoIndentWith fillSep -prettyDebugS, prettyInfoS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS-  :: (HasCallStack, HasRunner env, MonadReader env m, MonadLogger m)+prettyDebugS, prettyInfoS, prettyNoteS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS+  :: (HasCallStack, HasRunner env, MonadReader env m, MonadIO m)   => String -> m () prettyDebugS         = prettyDebugWith         flow prettyInfoS          = prettyInfoWith          flow+prettyNoteS          = prettyNoteWith          flow prettyWarnS          = prettyWarnWith          flow prettyErrorS         = prettyErrorWith         flow prettyWarnNoIndentS  = prettyWarnNoIndentWith  flow@@ -128,21 +136,21 @@ flow :: String -> Doc a flow = fillSep . wordDocs -debugBracket :: (HasCallStack, HasRunner env, MonadReader env m, MonadLogger m,+debugBracket :: (HasCallStack, HasRunner env, MonadReader env m,                  MonadIO m, MonadUnliftIO m) => Doc AnsiAnn -> m a -> m a debugBracket msg f = do-  let output = logDebug <=< displayWithColor+  let output = logDebug . RIO.display <=< displayWithColor   output $ "Start: " <> msg-  start <- liftIO $ Clock.getTime Clock.Monotonic+  start <- getMonotonicTime   x <- f `catch` \ex -> do-      end <- liftIO $ Clock.getTime Clock.Monotonic-      let diff = Clock.diffTimeSpec start end+      end <- getMonotonicTime+      let diff = end - start       output $ "Finished with exception in" <+> displayMilliseconds diff <> ":" <+>           msg <> line <>           "Exception thrown: " <> fromString (show ex)       throwIO (ex :: SomeException)-  end <- liftIO $ Clock.getTime Clock.Monotonic-  let diff = Clock.diffTimeSpec start end+  end <- getMonotonicTime+  let diff = end - start   output $ "Finished in" <+> displayMilliseconds diff <> ":" <+> msg   return x @@ -180,6 +188,10 @@ styleDir :: AnsiDoc -> AnsiDoc styleDir = bold . blue +-- | Style used to highlight part of a recommended course of action.+styleRecommendation :: AnsiDoc -> AnsiDoc+styleRecommendation = bold . green+ -- | Style an 'AnsiDoc' in a way that emphasizes that it is related to --   a current thing. For example, could be used when talking about the --   current package we're processing when outputting the name of it.@@ -212,10 +224,13 @@ instance Display (PackageName, NamedComponent) where     display = cyan . fromString . T.unpack . renderPkgComponent +instance Display C.ModuleName where+    display = fromString . C.display+ -- Display milliseconds.-displayMilliseconds :: Clock.TimeSpec -> AnsiDoc+displayMilliseconds :: Double -> AnsiDoc displayMilliseconds t = green $-    (fromString . show . (`div` 10^(6 :: Int)) . Clock.toNanoSecs) t <> "ms"+    fromString (show (round (t * 1000) :: Int)) <> "ms"  -- | Display a bulleted list of 'AnsiDoc'. bulletedList :: [AnsiDoc] -> AnsiDoc
src/Stack/Runners.hs view
@@ -14,6 +14,7 @@     , withBuildConfigAndLockNoDocker     , withBuildConfig     , withBuildConfigExt+    , withBuildConfigDot     , loadConfigWithOpts     , loadCompilerVersion     , withUserFileLock@@ -33,14 +34,14 @@ import           System.Environment (getEnvironment) import           System.IO import           System.FileLock+import           Stack.Dot  -- FIXME it seems wrong that we call lcLoadBuildConfig multiple times loadCompilerVersion :: GlobalOpts                     -> LoadConfig                     -> IO (CompilerVersion 'CVWanted)-loadCompilerVersion go lc = do-    bconfig <- lcLoadBuildConfig lc (globalCompiler go)-    return $ view wantedCompilerVersionL bconfig+loadCompilerVersion go lc =+    view wantedCompilerVersionL <$> lcLoadBuildConfig lc (globalCompiler go)  -- | Enforce mutual exclusion of every action running via this -- function, on this path, on this users account.@@ -87,7 +88,7 @@     -> RIO Config ()     -> IO () withConfigAndLock go@GlobalOpts{..} inner = loadConfigWithOpts go $ \lc -> do-    withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk ->+    withUserFileLock go (view stackRootL lc) $ \lk ->         runRIO (lcConfig lc) $             Docker.reexecWithOptionalContainer                 (lcProjectRoot lc)@@ -108,7 +109,7 @@             globalConfigMonoid             Nothing             LCSNoProject-    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_lk ->+    withUserFileLock go (view stackRootL lc) $ \_lk ->         runRIO (lcConfig lc) inner  -- For now the non-locking version just unlocks immediately.@@ -155,7 +156,7 @@     -- installed on the host OS.     -> IO () withBuildConfigExt skipDocker go@GlobalOpts{..} mbefore inner mafter = loadConfigWithOpts go $ \lc -> do-    withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk0 -> do+    withUserFileLock go (view stackRootL lc) $ \lk0 -> do       -- A local bit of state for communication between callbacks:       curLk <- newIORef lk0       let inner' lk =@@ -205,9 +206,7 @@         -- If we have been relaunched in a Docker container, perform in-container initialization         -- (switch UID, etc.).  We do this after first loading the configuration since it must         -- happen ASAP but needs a configuration.-        case globalDockerEntrypoint of-            Just de -> Docker.entrypoint (lcConfig lc) de-            Nothing -> return ()+        forM_ globalDockerEntrypoint $ Docker.entrypoint (lcConfig lc)         liftIO $ inner lc  withRunnerGlobal :: GlobalOpts -> (Runner -> IO a) -> IO a@@ -226,7 +225,7 @@ withMiniConfigAndLock go@GlobalOpts{..} inner = withRunnerGlobal go $ \runner -> do     miniConfig <-         runRIO runner $-        (loadMiniConfig . lcConfig) <$>+        loadMiniConfig . lcConfig <$>         loadConfigMaybeProject           globalConfigMonoid           globalResolver@@ -237,3 +236,13 @@ munlockFile :: MonadIO m => Maybe FileLock -> m () munlockFile Nothing = return () munlockFile (Just lk) = liftIO $ unlockFile lk++-- Plumbing for --test and --bench flags+withBuildConfigDot :: DotOpts -> GlobalOpts -> RIO EnvConfig () -> IO ()+withBuildConfigDot opts go f = withBuildConfig go' f+  where+    go' =+        (if dotTestTargets opts then set (globalOptsBuildOptsMonoidL.buildOptsMonoidTestsL) (Just True) else id) $+        (if dotBenchTargets opts then set (globalOptsBuildOptsMonoidL.buildOptsMonoidBenchmarksL) (Just True) else id)+        go+
src/Stack/SDist.hs view
@@ -17,8 +17,8 @@ import qualified Codec.Archive.Tar.Entry as Tar import qualified Codec.Compression.GZip as GZip import           Control.Applicative-import           Control.Concurrent.Execute (ActionContext(..))-import           Stack.Prelude+import           Control.Concurrent.Execute (ActionContext(..), Concurrency(..))+import           Stack.Prelude hiding (Display (..)) import           Control.Monad.Reader.Class (local) import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8@@ -26,7 +26,6 @@ import           Data.Char (toLower) import           Data.Data (cast) import           Data.List-import           Data.List.Extra (nubOrd) import           Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NE import qualified Data.Map.Strict as Map@@ -40,7 +39,7 @@ import           Distribution.Package (Dependency (..)) import qualified Distribution.PackageDescription as Cabal import qualified Distribution.PackageDescription.Check as Check-import qualified Distribution.PackageDescription.Parse as Cabal+import qualified Distribution.PackageDescription.Parsec as Cabal import           Distribution.PackageDescription.PrettyPrint (showGenericPackageDescription) import qualified Distribution.Types.UnqualComponentName as Cabal import qualified Distribution.Text as Cabal@@ -48,6 +47,7 @@ import           Lens.Micro (set) import           Path import           Path.IO hiding (getModificationTime, getPermissions, withSystemTempDir)+import qualified RIO import           Stack.Build (mkBaseConfigOpts, build) import           Stack.Build.Execute import           Stack.Build.Installed@@ -115,9 +115,9 @@         tweakCabal = pvpBounds /= PvpBoundsNone         pkgFp = toFilePath pkgDir     lp <- readLocalPackage pkgDir-    logInfo $ "Getting file list for " <> T.pack pkgFp+    logInfo $ "Getting file list for " <> fromString pkgFp     (fileList, cabalfp) <-  getSDistFileList lp-    logInfo $ "Building sdist tarball for " <> T.pack pkgFp+    logInfo $ "Building sdist tarball for " <> fromString pkgFp     files <- normalizeTarballPaths (map (T.unpack . stripCR . T.pack) (lines fileList))      -- We're going to loop below and eventually find the cabal@@ -173,8 +173,7 @@     unless (cabalfp == cabalfp')       $ error $ "getCabalLbs: cabalfp /= cabalfp': " ++ show (cabalfp, cabalfp')     (_, sourceMap) <- loadSourceMap AllowNoTargets defaultBuildOptsCLI-    menv <- getMinimalEnvOverride-    (installedMap, _, _, _) <- getInstalled menv GetInstalledOpts+    (installedMap, _, _, _) <- getInstalled GetInstalledOpts                                 { getInstalledProfiling = False                                 , getInstalledHaddock = False                                 , getInstalledSymbols = False@@ -210,8 +209,13 @@           <+> display cabalfp           , ""           ]-    case Cabal.parseGenericPackageDescription (showGenericPackageDescription gpd) of-      Cabal.ParseOk _ roundtripped+        (_warnings, eres) = Cabal.runParseResult+                          $ Cabal.parseGenericPackageDescription+                          $ T.encodeUtf8+                          $ T.pack+                          $ showGenericPackageDescription gpd+    case eres of+      Right roundtripped         | roundtripped == gpd -> return ()         | otherwise -> do             prettyWarn $ vsep $ roundtripErrs ++@@ -235,14 +239,14 @@               , flow "If the issue is not fixed, feel free to leave a comment on it indicating that you would like it to be fixed."               , ""               ]-      Cabal.ParseFailed err -> do+      Left (_version, errs) -> do         prettyWarn $ vsep $ roundtripErrs ++           [ flow "In particular, parsing the rendered cabal file is yielding a parse error.  Please check if there are already issues tracking this, and if not, please report new issues to the stack and cabal issue trackers, via"           , bulletedList             [ styleUrl "https://github.com/commercialhaskell/stack/issues/new"             , styleUrl "https://github.com/haskell/cabal/issues/new"             ]-          , flow $ "The parse error is: " ++ show err+          , flow $ "The parse error is: " ++ unlines (map show errs)           , ""           ]     return@@ -319,23 +323,21 @@ getSDistFileList :: HasEnvConfig env => LocalPackage -> RIO env (String, Path Abs File) getSDistFileList lp =     withSystemTempDir (stackProgName <> "-sdist") $ \tmpdir -> do-        menv <- getMinimalEnvOverride         let bopts = defaultBuildOpts         let boptsCli = defaultBuildOptsCLI         baseConfigOpts <- mkBaseConfigOpts boptsCli         (locals, _) <- loadSourceMap NeedTargets boptsCli-        run <- askRunInIO-        withExecuteEnv menv bopts boptsCli baseConfigOpts locals+        withExecuteEnv bopts boptsCli baseConfigOpts locals             [] [] [] -- provide empty list of globals. This is a hack around custom Setup.hs files             $ \ee ->-            withSingleContext run ac ee task Nothing (Just "sdist") $ \_package cabalfp _pkgDir cabal _announce _console _mlogFile -> do+            withSingleContext ac ee task Nothing (Just "sdist") $ \_package cabalfp _pkgDir cabal _announce _console _mlogFile -> do                 let outFile = toFilePath tmpdir FP.</> "source-files-list"                 cabal KeepTHLoading ["sdist", "--list-sources", outFile]                 contents <- liftIO (S.readFile outFile)                 return (T.unpack $ T.decodeUtf8With T.lenientDecode contents, cabalfp)   where     package = lpPackage lp-    ac = ActionContext Set.empty []+    ac = ActionContext Set.empty [] ConcurrencyAllowed     task = Task         { taskProvides = PackageIdentifier (packageName package) (packageVersion package)         , taskType = TTFiles lp Local@@ -355,9 +357,9 @@     -- TODO: consider whether erroring out is better - otherwise the     -- user might upload an incomplete tar?     unless (null outsideDir) $-        logWarn $ T.concat-            [ "Warning: These files are outside of the package directory, and will be omitted from the tarball: "-            , T.pack (show outsideDir)]+        logWarn $+            "Warning: These files are outside of the package directory, and will be omitted from the tarball: " <>+            displayShow outsideDir     return (nubOrd files)   where     (outsideDir, files) = partitionEithers (map pathToEither fps)@@ -405,7 +407,7 @@     config  <- getDefaultPackageConfig     (gdesc, PackageDescriptionPair pkgDesc _) <- readPackageDescriptionDir config pkgDir False     logInfo $-        "Checking package '" <> packageNameText name <> "' for common mistakes"+        "Checking package '" <> RIO.display name <> "' for common mistakes"     let pkgChecks =           -- MSS 2017-12-12: Try out a few different variants of           -- pkgDesc to try and provoke an error or warning. I don't@@ -429,7 +431,7 @@           in partition criticalIssue checks     unless (null warnings) $         logWarn $ "Package check reported the following warnings:\n" <>-                   T.pack (intercalate "\n" . fmap show $ warnings)+                   mconcat (intersperse "\n" . fmap displayShow $ warnings)     case NE.nonEmpty errors of         Nothing -> return ()         Just ne -> throwM $ CheckException ne
src/Stack/Script.hs view
@@ -12,11 +12,10 @@ import           Data.List.Split            (splitWhen) import qualified Data.Map.Strict            as Map import qualified Data.Set                   as Set-import qualified Data.Text                  as T import           Path import           Path.IO import qualified Stack.Build-import           Stack.Exec+import           Stack.Constants            (osIsWindows) import           Stack.GhcPkg               (ghcPkgExeName) import           Stack.Options.ScriptParser import           Stack.Runners@@ -25,7 +24,7 @@ import           Stack.Types.Config import           Stack.Types.PackageName import           System.FilePath            (dropExtension, replaceExtension)-import           System.Process.Read+import           RIO.Process  -- | Run a Stack Script scriptCmd :: ScriptOpts -> GlobalOpts -> IO ()@@ -38,19 +37,21 @@             , globalStackYaml = SYLNoConfig $ parent file             }     withBuildConfigAndLock go $ \lk -> do-        -- Some warnings in case the user somehow tries to set a-        -- stack.yaml location. Note that in this functions we use-        -- logError instead of logWarn because, when using the-        -- interpreter mode, only error messages are shown. See:-        -- https://github.com/commercialhaskell/stack/issues/3007-        case globalStackYaml go' of-          SYLOverride fp -> logError $ T.pack-            $ "Ignoring override stack.yaml file for script command: " ++ fp-          SYLDefault -> return ()-          SYLNoConfig _ -> assert False (return ())+      -- Some warnings in case the user somehow tries to set a+      -- stack.yaml location. Note that in this functions we use+      -- logError instead of logWarn because, when using the+      -- interpreter mode, only error messages are shown. See:+      -- https://github.com/commercialhaskell/stack/issues/3007+      case globalStackYaml go' of+        SYLOverride fp -> logError $+          "Ignoring override stack.yaml file for script command: " <>+          fromString fp+        SYLDefault -> return ()+        SYLNoConfig _ -> assert False (return ()) -        config <- view configL-        menv <- liftIO $ configEnvOverride config defaultEnvSettings+      config <- view configL+      menv <- liftIO $ configProcessContextSettings config defaultEnvSettings+      withProcessContext menv $ do         wc <- view $ actualCompilerVersionL.whichCompilerL         colorFlag <- appropriateGhcColorFlag @@ -71,7 +72,7 @@             -- already. If all needed packages are available, we can             -- skip the (rather expensive) build call below.             bss <- sinkProcessStdout-                Nothing menv (ghcPkgExeName wc)+                (ghcPkgExeName wc)                 ["list", "--simple-output"] CL.consume -- FIXME use the package info from envConfigPackages, or is that crazy?             let installed = Set.fromList                           $ map toPackageName@@ -101,19 +102,20 @@                 ]         munlockFile lk -- Unlock before transferring control away.         case soCompile opts of-          SEInterpret -> exec menv ("run" ++ compilerExeName wc)+          SEInterpret -> exec ("run" ++ compilerExeName wc)                 (ghcArgs ++ toFilePath file : soArgs opts)           _ -> do             let dir = parent file-            -- use sinkProcessStdout to ensure a ProcessFailed-            -- exception is generated for better error messages-            sinkProcessStdout-              (Just dir)-              menv+            -- Use readProcessStdout_ so that (1) if GHC does send any output+            -- to stdout, we capture it and stop it from being sent to our+            -- stdout, which could break scripts, and (2) if there's an+            -- exception, the standard output we did capture will be reported+            -- to the user.+            withWorkingDir (toFilePath dir) $ proc               (compilerExeName wc)               (ghcArgs ++ [toFilePath file])-              CL.sinkNull-            exec menv (toExeName $ toFilePath file) (soArgs opts)+              (void . readProcessStdout_)+            exec (toExeName $ toFilePath file) (soArgs opts)   where     toPackageName = reverse . drop 1 . dropWhile (/= '-') . reverse @@ -121,16 +123,9 @@     wordsComma = splitWhen (\c -> c == ' ' || c == ',')      toExeName fp =-      if isWindows+      if osIsWindows         then replaceExtension fp "exe"         else dropExtension fp--isWindows :: Bool-#ifdef WINDOWS-isWindows = True-#else-isWindows = False-#endif  getPackagesFromModuleInfo   :: ModuleInfo
src/Stack/Setup.hs view
@@ -39,14 +39,16 @@ import "cryptonite" Crypto.Hash (SHA1(..), SHA256(..)) import              Data.Aeson.Extended import qualified    Data.ByteString as S-import qualified    Data.ByteString.Char8 as S8 import qualified    Data.ByteString.Lazy as LBS+import qualified    Data.ByteString.Lazy.Char8 as BL8 import              Data.Char (isSpace)-import              Data.Conduit (Conduit, (=$), await, yield, awaitForever)+import              Data.Conduit (await, yield, awaitForever)+import qualified    Data.Conduit.Binary as CB import              Data.Conduit.Lazy (lazyConsume) import              Data.Conduit.Lift (evalStateC) import qualified    Data.Conduit.List as CL-import              Data.Conduit.Zlib           (ungzip)+import              Data.Conduit.Process.Typed (eceStderr)+import              Data.Conduit.Zlib          (ungzip) import              Data.Foldable (maximumBy) import qualified    Data.HashMap.Strict as HashMap import              Data.IORef.RunOnce (runOnce)@@ -62,21 +64,21 @@ import qualified    Distribution.System as Cabal import              Distribution.Text (simpleParse) import              Lens.Micro (set)-import              Network.HTTP.Simple (getResponseBody, httpLBS, withResponse, getResponseStatusCode)+import              Network.HTTP.Simple (getResponseBody, getResponseStatusCode) import              Network.HTTP.Download import              Path import              Path.CheckInstall (warnInstallSearchPathIssues) import              Path.Extra (toFilePathNoTrailingSep) import              Path.IO hiding (findExecutable, withSystemTempDir) import              Prelude (getLine, putStr, putStrLn, until)+import qualified    RIO import              Stack.Build (build) import              Stack.Config (loadConfig) import              Stack.Constants (stackProgName) import              Stack.Constants.Config (distRelativeDir)-import              Stack.Exec (defaultEnvSettings) import              Stack.Fetch import              Stack.GhcPkg (createDatabase, getCabalPkgVer, getGlobalDB, mkGhcPackagePath, ghcPkgPathEnvVar)-import              Stack.Prelude+import              Stack.Prelude hiding (Display (..)) import              Stack.PrettyPrint import              Stack.Setup.Installed import              Stack.Snapshot (loadSnapshot)@@ -96,10 +98,7 @@ import              System.IO.Error (isPermissionError) import              System.FilePath (searchPathSeparator) import qualified    System.FilePath as FP-import              System.Process (rawSystem)-import              System.Process.Log (withProcessTimeLog)-import              System.Process.Read-import              System.Process.Run (runCmd, Cmd(..))+import              RIO.Process import              Text.Printf (printf)  #if !WINDOWS@@ -145,9 +144,9 @@     deriving Show data SetupException = UnsupportedSetupCombo OS Arch                     | MissingDependencies [String]-                    | UnknownCompilerVersion Text (CompilerVersion 'CVWanted) [CompilerVersion 'CVActual]+                    | UnknownCompilerVersion (Set.Set Text) (CompilerVersion 'CVWanted) (Set.Set (CompilerVersion 'CVActual))                     | UnknownOSKey Text-                    | GHCSanityCheckCompileFailed ReadProcessException (Path Abs File)+                    | GHCSanityCheckCompileFailed SomeException (Path Abs File)                     | WantedMustBeGHC                     | RequireCustomGHCVariant                     | ProblemWhileDecompressing (Path Abs File)@@ -155,6 +154,7 @@                     | GHCJSRequiresStandardVariant                     | GHCJSNotBooted                     | DockerStackExeNotFound Version Text+                    | UnsupportedSetupConfiguration     deriving Typeable instance Exception SetupException instance Show SetupException where@@ -166,11 +166,13 @@     show (MissingDependencies tools) =         "The following executables are missing and must be installed: " ++         intercalate ", " tools-    show (UnknownCompilerVersion oskey wanted known) = concat-        [ "No information found for "+    show (UnknownCompilerVersion oskeys wanted known) = concat+        [ "No setup information found for "         , compilerVersionString wanted-        , ".\nSupported versions for OS key '" ++ T.unpack oskey ++ "': "-        , intercalate ", " (map show known)+        , " on your platform.\nThis probably means a GHC bindist has not yet been added for OS key '"+        , T.unpack (T.intercalate "', '" (sort $ Set.toList oskeys))+        , "'.\nSupported versions: "+        , T.unpack (T.intercalate ", " (map compilerVersionText (sort $ Set.toList known)))         ]     show (UnknownOSKey oskey) =         "Unable to find installation URLs for OS key: " ++@@ -204,6 +206,8 @@         , "\nUse the '"         , T.unpack dockerStackExeArgName         , "' option to specify a location"]+    show UnsupportedSetupConfiguration =+        "I don't know how to install GHC on your system configuration, please install manually"  -- | Modify the environment variables (like PATH) appropriately, possibly doing installation too setupEnv :: (HasBuildConfig env, HasGHCVariant env)@@ -237,15 +241,17 @@      -- Modify the initial environment to include the GHC path, if a local GHC     -- is being used-    menv0 <- getMinimalEnvOverride-    env <- removeHaskellEnvVars-             <$> augmentPathMap (maybe [] edBins mghcBin) (unEnvOverride menv0)-    menv <- mkEnvOverride platform env+    menv0 <- view processContextL+    env <- either throwM (return . removeHaskellEnvVars)+               $ augmentPathMap+                    (map toFilePath $ maybe [] edBins mghcBin)+                    (view envVarsL menv0)+    menv <- mkProcessContext env -    (compilerVer, cabalVer, globaldb) <- runConcurrently $ (,,)-        <$> Concurrently (getCompilerVersion menv wc)-        <*> Concurrently (getCabalPkgVer menv wc)-        <*> Concurrently (getGlobalDB menv wc)+    (compilerVer, cabalVer, globaldb) <- withProcessContext menv $ runConcurrently $ (,,)+        <$> Concurrently (getCompilerVersion wc)+        <*> Concurrently (getCabalPkgVer wc)+        <*> Concurrently (getGlobalDB wc)      logDebug "Resolving package entries"     packagesRef <- liftIO $ newIORef Nothing@@ -255,7 +261,7 @@     -- that GHC can be found on. This is needed for looking up global     -- package information in loadSnapshot.     let bcPath :: BuildConfig-        bcPath = set envOverrideL (const (return menv)) bc+        bcPath = set processContextL menv bc      ls <- runRIO bcPath $ loadSnapshot       (Just compilerVer)@@ -273,13 +279,13 @@     -- extra installation bin directories     mkDirs <- runReaderT extraBinDirs envConfig0     let mpath = Map.lookup "PATH" env-    depsPath <- augmentPath (mkDirs False) mpath-    localsPath <- augmentPath (mkDirs True) mpath+    depsPath <- either throwM return $ augmentPath (toFilePath <$> mkDirs False) mpath+    localsPath <- either throwM return $ augmentPath (toFilePath <$> mkDirs True) mpath      deps <- runReaderT packageDatabaseDeps envConfig0-    createDatabase menv wc deps+    withProcessContext menv $ createDatabase wc deps     localdb <- runReaderT packageDatabaseLocal envConfig0-    createDatabase menv wc localdb+    withProcessContext menv $ createDatabase wc localdb     extras <- runReaderT packageDatabaseExtra envConfig0     let mkGPP locals = mkGhcPackagePath locals localdb deps extras globaldb @@ -287,17 +293,17 @@      executablePath <- liftIO getExecutablePath -    utf8EnvVars <- getUtf8EnvVars menv compilerVer+    utf8EnvVars <- withProcessContext menv $ getUtf8EnvVars compilerVer      mGhcRtsEnvVar <- liftIO $ lookupEnv "GHCRTS"      envRef <- liftIO $ newIORef Map.empty-    let getEnvOverride' es = do+    let getProcessContext' es = do             m <- readIORef envRef             case Map.lookup es m of                 Just eo -> return eo                 Nothing -> do-                    eo <- mkEnvOverride platform+                    eo <- mkProcessContext                         $ Map.insert "PATH" (if esIncludeLocals es then localsPath else depsPath)                         $ (if esIncludeGhcPackagePath es                                 then Map.insert (ghcPkgPathEnvVar wc) (mkGPP (esIncludeLocals es))@@ -342,11 +348,14 @@                         (Map.insert es eo m', ())                     return eo +    envOverride <- liftIO $ getProcessContext' minimalEnvSettings     return EnvConfig         { envConfigBuildConfig = bconfig             { bcConfig = maybe id addIncludeLib mghcBin-                        (view configL bconfig)-                { configEnvOverride = getEnvOverride' }+                       $ set processContextL envOverride+                         (view configL bconfig)+                { configProcessContextSettings = getProcessContext'+                }             }         , envConfigCabalVersion = cabalVer         , envConfigCompilerVersion = compilerVer@@ -373,19 +382,16 @@ ensureCompiler sopts = do     let wc = whichCompiler (soptsWantedCompiler sopts)     when (getGhcVersion (soptsWantedCompiler sopts) < $(mkVersion "7.8")) $ do-        logWarn "stack will almost certainly fail with GHC below version 7.8"+        logWarn "Stack will almost certainly fail with GHC below version 7.8"         logWarn "Valiantly attempting to run anyway, but I know this is doomed"         logWarn "For more information, see: https://github.com/commercialhaskell/stack/issues/648"         logWarn "" -    -- Check the available GHCs-    menv0 <- getMinimalEnvOverride-     msystem <-         if soptsUseSystem sopts             then do                 logDebug "Getting system compiler version"-                getSystemCompiler menv0 wc+                getSystemCompiler wc             else return Nothing      Platform expectedArch _ <- view platformL@@ -435,20 +441,30 @@             let localPrograms = configLocalPrograms config             installed <- listInstalled localPrograms -            (installedCompiler, compilerBuild) <-+            possibleCompilers <-                     case wc of                         Ghc -> do-                            ghcBuild <- getGhcBuild menv0-                            ghcPkgName <- parsePackageNameFromString ("ghc" ++ ghcVariantSuffix ghcVariant ++ compilerBuildSuffix ghcBuild)-                            return (getInstalledTool installed ghcPkgName (isWanted . GhcVersion), ghcBuild)-                        Ghcjs -> return (getInstalledGhcjs installed isWanted, CompilerBuildStandard)-            compilerTool <- case (installedCompiler, soptsForceReinstall sopts) of-                (Just tool, False) -> return tool-                _+                            ghcBuilds <- getGhcBuilds+                            forM ghcBuilds $ \ghcBuild -> do+                                ghcPkgName <- parsePackageNameFromString ("ghc" ++ ghcVariantSuffix ghcVariant ++ compilerBuildSuffix ghcBuild)+                                return (getInstalledTool installed ghcPkgName (isWanted . GhcVersion), ghcBuild)+                        Ghcjs -> return [(getInstalledGhcjs installed isWanted, CompilerBuildStandard)]+            let existingCompilers = concatMap+                    (\(installedCompiler, compilerBuild) ->+                        case (installedCompiler, soptsForceReinstall sopts) of+                            (Just tool, False) -> [(tool, compilerBuild)]+                            _ -> [])+                    possibleCompilers+            logDebug $+              "Found already installed GHC builds: " <>+              mconcat (intersperse ", " (map (fromString . compilerBuildName . snd) existingCompilers))+            (compilerTool, compilerBuild) <- case existingCompilers of+                (tool, build_):_ -> return (tool, build_)+                []                     | soptsInstallIfMissing sopts -> do                         si <- getSetupInfo'-                        downloadAndInstallCompiler-                            compilerBuild+                        downloadAndInstallPossibleCompilers+                            (map snd possibleCompilers)                             si                             (soptsWantedCompiler sopts)                             (soptsCompilerCheck sopts)@@ -458,7 +474,7 @@                             if soptsUseSystem sopts                                 then return False                                 else do-                                    msystemGhc <- getSystemCompiler menv0 wc+                                    msystemGhc <- getSystemCompiler wc                                     return (any (uncurry canUseCompiler) msystemGhc)                         let suggestion = fromMaybe                                 (mconcat@@ -474,7 +490,9 @@                             msystem                             (soptsWantedCompiler sopts, expectedArch)                             ghcVariant-                            compilerBuild+                            (case possibleCompilers of+                                [] -> CompilerBuildStandard+                                (_, compilerBuild):_ -> compilerBuild)                             (soptsCompilerCheck sopts)                             (soptsStackYaml sopts)                             suggestion@@ -497,34 +515,37 @@      menv <-         case mpaths of-            Nothing -> return menv0+            Nothing -> view processContextL             Just ed -> do-                config <- view configL-                m <- augmentPathMap (edBins ed) (unEnvOverride menv0)-                mkEnvOverride (configPlatform config) (removeHaskellEnvVars m)+                menv0 <- view processContextL+                m <- either throwM return+                   $ augmentPathMap (toFilePath <$> edBins ed) (view envVarsL menv0)+                mkProcessContext (removeHaskellEnvVars m)      forM_ (soptsUpgradeCabal sopts) $ \version -> do         unless needLocal $ do             logWarn "Trying to change a Cabal library on a GHC not installed by stack."             logWarn "This may fail, caveat emptor!"-        upgradeCabal menv wc version+        withProcessContext menv $ upgradeCabal wc version      case mtools of-        Just (Just (ToolGhcjs cv), _) -> ensureGhcjsBooted menv cv (soptsInstallIfMissing sopts) (soptsGHCJSBootOpts sopts)+        Just (Just (ToolGhcjs cv), _) ->+            withProcessContext menv+          $ ensureGhcjsBooted cv (soptsInstallIfMissing sopts) (soptsGHCJSBootOpts sopts)         _ -> return () -    when (soptsSanityCheck sopts) $ sanityCheck menv wc+    when (soptsSanityCheck sopts) $ withProcessContext menv $ sanityCheck wc      return (mpaths, compilerBuild, needLocal) --- | Determine which GHC build to use depending on which shared libraries are available+-- | Determine which GHC builds to use depending on which shared libraries are available -- on the system.-getGhcBuild :: HasConfig env => EnvOverride -> RIO env CompilerBuild-getGhcBuild menv = do+getGhcBuilds :: HasConfig env => RIO env [CompilerBuild]+getGhcBuilds = do      config <- view configL     case configGHCBuild config of-        Just ghcBuild -> return ghcBuild+        Just ghcBuild -> return [ghcBuild]         Nothing -> determineGhcBuild   where     determineGhcBuild = do@@ -550,19 +571,22 @@         case platform of             Platform _ Cabal.Linux -> do                 -- Some systems don't have ldconfig in the PATH, so make sure to look in /sbin and /usr/sbin as well-                sbinEnv <- modifyEnvOverride menv $-                    Map.insert "PATH" $-                    "/sbin:/usr/sbin" <>-                    maybe "" (":" <>) (Map.lookup "PATH" (eoTextMap menv))-                eldconfigOut <- tryProcessStdout Nothing sbinEnv "ldconfig" ["-p"]-                egccErrOut <- tryProcessStderrStdout Nothing menv "gcc" ["-v"]+                let sbinEnv m = Map.insert+                      "PATH"+                      ("/sbin:/usr/sbin" <> maybe "" (":" <>) (Map.lookup "PATH" m))+                      m+                eldconfigOut+                  <- withModifyEnvVars sbinEnv+                   $ proc "ldconfig" ["-p"]+                   $ tryAny . readProcessStdout_                 let firstWords = case eldconfigOut of                         Right ldconfigOut -> mapMaybe (listToMaybe . T.words) $-                            T.lines $ T.decodeUtf8With T.lenientDecode ldconfigOut+                            T.lines $ T.decodeUtf8With T.lenientDecode+                                    $ LBS.toStrict ldconfigOut                         Left _ -> []                     checkLib lib                         | libT `elem` firstWords = do-                            logDebug ("Found shared library " <> libT <> " in 'ldconfig -p' output")+                            logDebug ("Found shared library " <> libD <> " in 'ldconfig -p' output")                             return True                         | otherwise = do #ifdef WINDOWS@@ -575,50 +599,40 @@                             -- to scan for shared libs, but this works for our particular case.                             e <- doesFileExist ($(mkAbsDir "/usr/lib") </> lib)                             if e-                                then logDebug ("Found shared library " <> libT <> " in /usr/lib")-                                else logDebug ("Did not find shared library " <> libT)+                                then logDebug ("Found shared library " <> libD <> " in /usr/lib")+                                else logDebug ("Did not find shared library " <> libD)                             return e #endif                       where                         libT = T.pack (toFilePath lib)-                    noPie = case egccErrOut of-                        Right (gccErr,gccOut) ->-                            "--enable-default-pie" `elem` S8.words gccOutput || "Gentoo Hardened" `S8.isInfixOf` gccOutput-                                where gccOutput = gccOut <> gccErr-                        Left _ -> False-                logDebug $ if noPie-                               then "PIE disabled"-                               else "PIE enabled"+                        libD = fromString (toFilePath lib)                 hastinfo5 <- checkLib $(mkRelFile "libtinfo.so.5")                 hastinfo6 <- checkLib $(mkRelFile "libtinfo.so.6")                 hasncurses6 <- checkLib $(mkRelFile "libncursesw.so.6")                 hasgmp5 <- checkLib $(mkRelFile "libgmp.so.10")                 hasgmp4 <- checkLib $(mkRelFile "libgmp.so.3")-                let libComponents =-                        if  | hastinfo6 && hasgmp5 -> ["tinfo6"]-                            | hastinfo5 && hasgmp5 -> []-                            | hasncurses6 && hasgmp5 -> ["ncurses6"]-                            | hasgmp4 && hastinfo5 -> ["gmp4"]-                            | otherwise -> []-                    pieComponents =-                        if noPie-                            then ["nopie"]-                            else []-                case libComponents ++ pieComponents of-                    [] -> useBuild CompilerBuildStandard-                    components -> useBuild (CompilerBuildSpecialized (intercalate "-" components))+                let libComponents = concat+                        [ [["tinfo6"] | hastinfo6 && hasgmp5]+                        , [[] | hastinfo5 && hasgmp5]+                        , [["ncurses6"] | hasncurses6 && hasgmp5 ]+                        , [["gmp4"] | hasgmp4 ]+                        ]+                useBuilds $ map+                    (\c -> case c of+                        [] -> CompilerBuildStandard+                        _ -> CompilerBuildSpecialized (intercalate "-" c))+                    libComponents #if !WINDOWS             Platform _ Cabal.OpenBSD -> do                 releaseStr <- mungeRelease <$> sysRelease-                useBuild (CompilerBuildSpecialized releaseStr)+                useBuilds [CompilerBuildSpecialized releaseStr] #endif-            _ -> useBuild CompilerBuildStandard-    useBuild CompilerBuildStandard = do-        logDebug "Using standard GHC build"-        return CompilerBuildStandard-    useBuild (CompilerBuildSpecialized s) = do-        logDebug ("Using " <> T.pack s <> " GHC build")-        return (CompilerBuildSpecialized s)+            _ -> useBuilds [CompilerBuildStandard]+    useBuilds builds = do+        logDebug $+          "Potential GHC builds: " <>+          mconcat (intersperse ", " (map (fromString . compilerBuildName) builds))+        return builds  #if !WINDOWS -- | Encode an OpenBSD version (like "6.1") into a valid argument for@@ -634,12 +648,10 @@     prefixMaj = prefixFst "maj" prefixMin     prefixMin = prefixFst "min" (map ('r':)) -sysRelease :: (MonadUnliftIO m, MonadLogger m) => m String+sysRelease :: HasLogFunc env => RIO env String sysRelease =   handleIO (\e -> do-               logWarn $ T.concat [ T.pack "Could not query OS version"-                                   , T.pack $ show e-                                   ]+               logWarn $ "Could not query OS version" <> displayShow e                return "") .   liftIO .   alloca $ \ ptr ->@@ -658,7 +670,10 @@     let stackExePath = stackExeDir </> $(mkRelFile "stack")     stackExeExists <- doesFileExist stackExePath     unless stackExeExists $ do-        logInfo $ mconcat ["Downloading Docker-compatible ", T.pack stackProgName, " executable"]+        logInfo $+          "Downloading Docker-compatible " <>+          fromString stackProgName <>+          " executable"         sri <- downloadStackReleaseInfo Nothing Nothing (Just (versionString stackMinorVersion))         platforms <- runReaderT preferredPlatforms (containerPlatform, PlatformVariantNone)         downloadStackExe platforms sri stackExeDir False (const $ return ())@@ -666,56 +681,54 @@  -- | Install the newest version or a specific version of Cabal globally upgradeCabal :: (HasConfig env, HasGHCVariant env)-             => EnvOverride-             -> WhichCompiler+             => WhichCompiler              -> UpgradeTo              -> RIO env ()-upgradeCabal menv wc upgradeTo = do+upgradeCabal wc upgradeTo = do     logInfo "Manipulating the global Cabal is only for debugging purposes"     let name = $(mkPackageName "Cabal")     rmap <- resolvePackages Nothing mempty (Set.singleton name)-    installed <- getCabalPkgVer menv wc+    installed <- getCabalPkgVer wc     case upgradeTo of         Specific wantedVersion -> do             if installed /= wantedVersion then-                doCabalInstall menv wc installed wantedVersion+                doCabalInstall wc installed wantedVersion             else-                logInfo $ T.concat ["No install necessary. Cabal "-                                    , T.pack $ versionString installed-                                    , " is already installed"]+                logInfo $+                  "No install necessary. Cabal " <>+                  RIO.display installed <>+                  " is already installed"         Latest     -> case map rpIdent rmap of             [] -> throwString "No Cabal library found in index, cannot upgrade"             [PackageIdentifier name' latestVersion] | name == name' -> do                 if installed < latestVersion then-                    doCabalInstall menv wc installed latestVersion+                    doCabalInstall wc installed latestVersion                 else-                    logInfo $ T.concat-                        [ "No upgrade necessary: Cabal-"-                        , T.pack $ versionString latestVersion-                        , " is the same or newer than latest hackage version "-                        , T.pack $ versionString installed-                        ]+                    logInfo $+                        "No upgrade necessary: Cabal-" <>+                        RIO.display latestVersion <>+                        " is the same or newer than latest hackage version " <>+                        RIO.display installed             x -> error $ "Unexpected results for resolvePackages: " ++ show x  -- Configure and run the necessary commands for a cabal install doCabalInstall :: (HasConfig env, HasGHCVariant env)-               => EnvOverride-               -> WhichCompiler+               => WhichCompiler                -> Version                -> Version                -> RIO env ()-doCabalInstall menv wc installed wantedVersion = do+doCabalInstall wc installed wantedVersion = do     withSystemTempDir "stack-cabal-upgrade" $ \tmpdir -> do-        logInfo $ T.concat-            [ "Installing Cabal-"-            , T.pack $ versionString wantedVersion-            , " to replace "-            , T.pack $ versionString installed-            ]+        logInfo $+            "Installing Cabal-" <>+            RIO.display wantedVersion <>+            " to replace " <>+            RIO.display installed         let name = $(mkPackageName "Cabal")             ident = PackageIdentifier name wantedVersion         m <- unpackPackageIdents tmpdir Nothing [PackageIdentifierRevision ident CFILatest]-        compilerPath <- join $ findExecutable menv (compilerExeName wc)+        compilerPath <- findExecutable (compilerExeName wc)+                    >>= either throwM parseAbsFile         versionDir <- parseRelDir $ versionString wantedVersion         let installRoot = toFilePath $ parent (parent compilerPath)                                     </> $(mkRelDir "new-cabal")@@ -723,7 +736,7 @@         dir <- case Map.lookup ident m of             Nothing -> error "upgradeCabal: Invariant violated, dir missing"             Just dir -> return dir-        runCmd (Cmd (Just dir) (compilerExeName wc) menv ["Setup.hs"]) Nothing+        withWorkingDir (toFilePath dir) $ proc (compilerExeName wc) ["Setup.hs"] runProcess_         platform <- view platformL         let setupExe = toFilePath $ dir </> case platform of                 Platform _ Cabal.Windows -> $(mkRelFile "Setup.exe")@@ -734,35 +747,35 @@                                        , installRoot FP.</> name'                                        ]             args = "configure" : map dirArgument (words "lib bin data doc")-        runCmd (Cmd (Just dir) setupExe menv args) Nothing-        runCmd (Cmd (Just dir) setupExe menv ["build"]) Nothing-        runCmd (Cmd (Just dir) setupExe menv ["install"]) Nothing+        withWorkingDir (toFilePath dir) $ do+          proc setupExe args runProcess_+          proc setupExe ["build"] runProcess_+          proc setupExe ["install"] runProcess_         logInfo "New Cabal library installed"  -- | Get the version of the system compiler, if available getSystemCompiler-  :: HasLogFunc env-  => EnvOverride-  -> WhichCompiler+  :: (HasProcessContext env, HasLogFunc env)+  => WhichCompiler   -> RIO env (Maybe (CompilerVersion 'CVActual, Arch))-getSystemCompiler menv wc = do+getSystemCompiler wc = do     let exeName = case wc of             Ghc -> "ghc"             Ghcjs -> "ghcjs"-    exists <- doesExecutableExist menv exeName+    exists <- doesExecutableExist exeName     if exists         then do-            eres <- tryProcessStdout Nothing menv exeName ["--info"]+            eres <- proc exeName ["--info"] $ tryAny . readProcessStdout_             let minfo = do-                    Right bs <- Just eres-                    pairs_ <- readMaybe $ S8.unpack bs :: Maybe [(String, String)]+                    Right lbs <- Just eres+                    pairs_ <- readMaybe $ BL8.unpack lbs :: Maybe [(String, String)]                     version <- lookup "Project version" pairs_ >>= parseVersionFromString                     arch <- lookup "Target platform" pairs_ >>= simpleParse . takeWhile (/= '-')                     return (version, arch)             case (wc, minfo) of                 (Ghc, Just (version, arch)) -> return (Just (GhcVersion version, arch))                 (Ghcjs, Just (_, arch)) -> do-                    eversion <- tryAny $ getCompilerVersion menv Ghcjs+                    eversion <- tryAny $ getCompilerVersion Ghcjs                     case eversion of                         Left _ -> return Nothing                         Right version -> return (Just (version, arch))@@ -878,10 +891,10 @@         "Preparing to install GHC" <>         (case ghcVariant of             GHCStandard -> ""-            v -> " (" <> T.pack (ghcVariantName v) <> ")") <>+            v -> " (" <> fromString (ghcVariantName v) <> ")") <>         (case ghcBuild of             CompilerBuildStandard -> ""-            b -> " (" <> T.pack (compilerBuildName b) <> ")") <>+            b -> " (" <> fromString (compilerBuildName b) <> ")") <>         " to an isolated location."     logInfo "This will not interfere with any system-level installation."     ghcPkgName <- parsePackageNameFromString ("ghc" ++ ghcVariantSuffix ghcVariant ++ compilerBuildSuffix ghcBuild)@@ -911,13 +924,56 @@ getWantedCompilerInfo key versionCheck wanted toCV pairs_ =     case mpair of         Just pair -> return pair-        Nothing -> throwM $ UnknownCompilerVersion key wanted (map toCV (Map.keys pairs_))+        Nothing -> throwM $ UnknownCompilerVersion (Set.singleton key) wanted (Set.fromList $ map toCV (Map.keys pairs_))   where     mpair =         listToMaybe $         sortBy (flip (comparing fst)) $         filter (isWantedCompiler versionCheck wanted . toCV . fst) (Map.toList pairs_) +-- | Download and install the first available compiler build.+downloadAndInstallPossibleCompilers+    :: (HasGHCVariant env, HasConfig env)+    => [CompilerBuild]+    -> SetupInfo+    -> CompilerVersion 'CVWanted+    -> VersionCheck+    -> Maybe String+    -> RIO env (Tool, CompilerBuild)+downloadAndInstallPossibleCompilers possibleCompilers si wanted versionCheck mbindistURL =+    go possibleCompilers Nothing+  where+    -- This will stop as soon as one of the builds doesn't throw an @UnknownOSKey@ or+    -- @UnknownCompilerVersion@ exception (so it will only try subsequent builds if one is non-existent,+    -- not if the download or install fails for some other reason).+    -- The @Unknown*@ exceptions thrown by each attempt are combined into a single exception+    -- (if only @UnknownOSKey@ is thrown, then the first of those is rethrown, but if any+    -- @UnknownCompilerVersion@s are thrown then the attempted OS keys and available versions+    -- are unioned).+    go [] Nothing = throwM UnsupportedSetupConfiguration+    go [] (Just e) = throwM e+    go (b:bs) e = do+        logDebug $ "Trying to setup GHC build: " <> fromString (compilerBuildName b)+        er <- try $ downloadAndInstallCompiler b si wanted versionCheck mbindistURL+        case er of+            Left e'@(UnknownCompilerVersion ks' w' vs') ->+                case e of+                    Nothing -> go bs (Just e')+                    Just (UnknownOSKey k) ->+                        go bs $ Just $ UnknownCompilerVersion (Set.insert k ks') w' vs'+                    Just (UnknownCompilerVersion ks _ vs) ->+                        go bs $ Just $ UnknownCompilerVersion (Set.union ks' ks) w' (Set.union vs' vs)+                    Just x -> throwM x+            Left e'@(UnknownOSKey k') ->+                case e of+                    Nothing -> go bs (Just e')+                    Just (UnknownOSKey _) -> go bs e+                    Just (UnknownCompilerVersion ks w vs) ->+                        go bs $ Just $ UnknownCompilerVersion (Set.insert k' ks) w vs+                    Just x -> throwM x+            Left e' -> throwM e'+            Right r -> return (r, b)+ getGhcKey :: (MonadReader env m, HasPlatform env, HasGHCVariant env, MonadThrow m)           => CompilerBuild -> m Text getGhcKey ghcBuild = do@@ -930,17 +986,18 @@          => Platform -> m Text getOSKey platform =     case platform of-        Platform I386   Cabal.Linux   -> return "linux32"-        Platform X86_64 Cabal.Linux   -> return "linux64"-        Platform I386   Cabal.OSX     -> return "macosx"-        Platform X86_64 Cabal.OSX     -> return "macosx"-        Platform I386   Cabal.FreeBSD -> return "freebsd32"-        Platform X86_64 Cabal.FreeBSD -> return "freebsd64"-        Platform I386   Cabal.OpenBSD -> return "openbsd32"-        Platform X86_64 Cabal.OpenBSD -> return "openbsd64"-        Platform I386   Cabal.Windows -> return "windows32"-        Platform X86_64 Cabal.Windows -> return "windows64"-        Platform Arm    Cabal.Linux   -> return "linux-armv7"+        Platform I386                  Cabal.Linux   -> return "linux32"+        Platform X86_64                Cabal.Linux   -> return "linux64"+        Platform I386                  Cabal.OSX     -> return "macosx"+        Platform X86_64                Cabal.OSX     -> return "macosx"+        Platform I386                  Cabal.FreeBSD -> return "freebsd32"+        Platform X86_64                Cabal.FreeBSD -> return "freebsd64"+        Platform I386                  Cabal.OpenBSD -> return "openbsd32"+        Platform X86_64                Cabal.OpenBSD -> return "openbsd64"+        Platform I386                  Cabal.Windows -> return "windows32"+        Platform X86_64                Cabal.Windows -> return "windows64"+        Platform Arm                   Cabal.Linux   -> return "linux-armv7"+        Platform (OtherArch "aarch64") Cabal.Linux   -> return "linux-aarch64"         Platform arch os -> throwM $ UnsupportedSetupCombo os arch  downloadFromInfo@@ -1005,9 +1062,9 @@                 -> RIO env () installGHCPosix version downloadInfo _ archiveFile archiveType tempDir destDir = do     platform <- view platformL-    menv0 <- getMinimalEnvOverride-    menv <- mkEnvOverride platform (removeHaskellEnvVars (unEnvOverride menv0))-    logDebug $ "menv = " <> T.pack (show (unEnvOverride menv))+    menv0 <- view processContextL+    menv <- mkProcessContext (removeHaskellEnvVars (view envVarsL menv0))+    logDebug $ "menv = " <> displayShow (view envVarsL menv)     (zipTool', compOpt) <-         case archiveType of             TarXz -> return ("xz", 'J')@@ -1025,9 +1082,9 @@         <*> (checkDependency "gmake" <|> checkDependency "make")         <*> tarDep -    logDebug $ "ziptool: " <> T.pack zipTool-    logDebug $ "make: " <> T.pack makeTool-    logDebug $ "tar: " <> T.pack tarTool+    logDebug $ "ziptool: " <> fromString zipTool+    logDebug $ "make: " <> fromString makeTool+    logDebug $ "tar: " <> fromString tarTool      dir <-         liftM (tempDir </>) $@@ -1035,12 +1092,18 @@         "ghc-" ++ versionString version      let runStep step wd env cmd args = do-            menv' <- modifyEnvOverride menv (Map.union env)-            result <- try (readProcessNull (Just wd) menv' cmd args)+            menv' <- modifyEnvVars menv (Map.union env)+            result <- do+                let logLines = CB.lines .| CL.mapM_ (logDebug . displayBytesUtf8)+                withWorkingDir (toFilePath wd)+                  $ withProcessContext menv'+                  $ try+                  $ sinkProcessStderrStdout cmd args logLines logLines+             case result of-                Right _ -> return ()+                Right ((), ()) -> return ()                 Left ex -> do-                    logError (T.pack (show (ex :: ReadProcessException)))+                    logError (displayShow (ex :: ProcessException))                     prettyError $                         hang 2                           ("Error encountered while" <+> step <+> "GHC with" <> line <>@@ -1053,8 +1116,11 @@                         "  -" <+> display destDir <> line                     liftIO exitFailure -    logSticky $ T.concat ["Unpacking GHC into ", T.pack . toFilePath $ tempDir, " ..."]-    logDebug $ "Unpacking " <> T.pack (toFilePath archiveFile)+    logSticky $+      "Unpacking GHC into " <>+      fromString (toFilePath tempDir) <>+      " ..."+    logDebug $ "Unpacking " <> fromString (toFilePath archiveFile)     runStep "unpacking" tempDir mempty tarTool [compOpt : "xf", toFilePath archiveFile]      logSticky "Configuring GHC ..."@@ -1067,7 +1133,7 @@     runStep "installing" dir mempty makeTool ["install"]      logStickyDone $ "Installed GHC."-    logDebug $ "GHC installed to " <> T.pack (toFilePath destDir)+    logDebug $ "GHC installed to " <> fromString (toFilePath destDir)  installGHCJS :: HasConfig env              => SetupInfo@@ -1078,12 +1144,12 @@              -> RIO env () installGHCJS si archiveFile archiveType _tempDir destDir = do     platform <- view platformL-    menv0 <- getMinimalEnvOverride+    menv0 <- view processContextL     -- This ensures that locking is disabled for the invocations of     -- stack below.     let removeLockVar = Map.delete "STACK_LOCK"-    menv <- mkEnvOverride platform (removeLockVar (removeHaskellEnvVars (unEnvOverride menv0)))-    logDebug $ "menv = " <> T.pack (show (unEnvOverride menv))+    menv <- mkProcessContext (removeLockVar (removeHaskellEnvVars (view envVarsL menv0)))+    logDebug $ "menv = " <> displayShow (view envVarsL menv)      -- NOTE: this is a bit of a hack - instead of using the temp     -- directory, leave the unpacked source tarball in the destination@@ -1110,17 +1176,20 @@             (zipTool, tarTool) <- checkDependencies $ (,)                 <$> checkDependency zipTool'                 <*> checkDependency "tar"-            logDebug $ "ziptool: " <> T.pack zipTool-            logDebug $ "tar: " <> T.pack tarTool+            logDebug $ "ziptool: " <> fromString zipTool+            logDebug $ "tar: " <> fromString tarTool             return $ do                 liftIO $ ignoringAbsence (removeDirRecur destDir)                 liftIO $ ignoringAbsence (removeDirRecur unpackDir)-                readProcessNull (Just destDir) menv tarTool ["xf", toFilePath archiveFile]+                withProcessContext menv $ withWorkingDir (toFilePath destDir) $ readProcessNull tarTool ["xf", toFilePath archiveFile]                 innerDir <- expectSingleUnpackedDir archiveFile destDir                 renameDir innerDir unpackDir -    logSticky $ T.concat ["Unpacking GHCJS into ", T.pack . toFilePath $ unpackDir, " ..."]-    logDebug $ "Unpacking " <> T.pack (toFilePath archiveFile)+    logSticky $+      "Unpacking GHCJS into " <>+      fromString (toFilePath unpackDir) <>+      " ..."+    logDebug $ "Unpacking " <> fromString (toFilePath archiveFile)     runUnpack      logSticky "Setting up GHCJS build environment"@@ -1149,15 +1218,15 @@     logStickyDone "Installed GHCJS."  ensureGhcjsBooted :: HasConfig env-                  => EnvOverride -> CompilerVersion 'CVActual -> Bool -> [String]+                  => CompilerVersion 'CVActual -> Bool -> [String]                   -> RIO env ()-ensureGhcjsBooted menv cv shouldBoot bootOpts = do-    eres <- try $ sinkProcessStdout Nothing menv "ghcjs" [] (return ())+ensureGhcjsBooted cv shouldBoot bootOpts = do+    eres <- try $ sinkProcessStdout "ghcjs" [] (return ())     case eres of         Right () -> return ()-        Left (ProcessFailed _ _ _ err) | "no input files" `S.isInfixOf` LBS.toStrict err ->+        Left ece | "no input files" `S.isInfixOf` LBS.toStrict (eceStderr ece) ->             return ()-        Left (ProcessFailed _ _ _ err) | "ghcjs_boot.completed" `S.isInfixOf` LBS.toStrict err ->+        Left ece | "ghcjs_boot.completed" `S.isInfixOf` LBS.toStrict (eceStderr ece) ->             if not shouldBoot then throwM GHCJSNotBooted else do                 config <- view configL                 destDir <- installDir (configLocalPrograms config) (ToolGhcjs cv)@@ -1182,15 +1251,15 @@                 unless actualStackYamlExists $                     throwString "Error: Couldn't find GHCJS stack.yaml in old or new location."                 bootGhcjs ghcjsVersion actualStackYaml destDir bootOpts-        Left err -> throwM err+        Left ece -> throwIO ece -bootGhcjs :: HasRunner env+bootGhcjs :: (HasRunner env, HasProcessContext env)           => Version -> Path Abs File -> Path Abs Dir -> [String] -> RIO env () bootGhcjs ghcjsVersion stackYaml destDir bootOpts = do     envConfig <- loadGhcjsEnvConfig stackYaml (destDir </> $(mkRelDir "bin"))-    menv <- liftIO $ configEnvOverride (view configL envConfig) defaultEnvSettings+    menv <- liftIO $ configProcessContextSettings (view configL envConfig) defaultEnvSettings     -- Install cabal-install if missing, or if the installed one is old.-    mcabal <- getCabalInstallVersion menv+    mcabal <- withProcessContext menv getCabalInstallVersion     shouldInstallCabal <- case mcabal of         Nothing -> do             logInfo "No cabal-install binary found for use with GHCJS."@@ -1199,20 +1268,20 @@             | v < $(mkVersion "1.22.4") -> do                 logInfo $                     "The cabal-install found on PATH is too old to be used for booting GHCJS (version " <>-                    versionText v <>+                    RIO.display v <>                     ")."                 return True             | v >= $(mkVersion "1.23") -> do                 logWarn $                     "The cabal-install found on PATH is a version stack doesn't know about, version " <>-                    versionText v <>+                    RIO.display v <>                     ". This may or may not work.\n" <>                     "See this issue: https://github.com/ghcjs/ghcjs/issues/470"                 return False             | ghcjsVersion >= $(mkVersion "0.2.0.20160413") && v >= $(mkVersion "1.22.8") -> do                 logWarn $                     "The cabal-install found on PATH, version " <>-                    versionText v <>+                    RIO.display v <>                     ", is >= 1.22.8.\n" <>                     "That version has a bug preventing ghcjs < 0.2.0.20160413 from booting.\n" <>                     "See this issue: https://github.com/ghcjs/ghcjs/issues/470"@@ -1225,21 +1294,21 @@           , esLocaleUtf8 = True           , esKeepGhcRts = False           }-    menv' <- liftIO $ configEnvOverride (view configL envConfig) envSettings-    shouldInstallAlex <- not <$> doesExecutableExist menv "alex"-    shouldInstallHappy <- not <$> doesExecutableExist menv "happy"+    menv' <- liftIO $ configProcessContextSettings (view configL envConfig) envSettings+    shouldInstallAlex <- runRIO menv $ not <$> doesExecutableExist "alex"+    shouldInstallHappy <- runRIO menv $ not <$> doesExecutableExist "happy"     let bootDepsToInstall =           [ "cabal-install" | shouldInstallCabal ] ++           [ "alex" | shouldInstallAlex ] ++           [ "happy" | shouldInstallHappy ]     when (not (null bootDepsToInstall)) $ do-        logInfo $ "Building tools from source, needed for ghcjs-boot: " <> T.pack (show bootDepsToInstall)+        logInfo $ "Building tools from source, needed for ghcjs-boot: " <> displayShow bootDepsToInstall         buildInGhcjsEnv envConfig $ defaultBuildOptsCLI { boptsCLITargets = bootDepsToInstall }         let failedToFindErr = do                 logError "This shouldn't happen, because it gets built to the snapshot bin directory, which should be treated as being on the PATH."                 liftIO exitFailure         when shouldInstallCabal $ do-            mcabal' <- getCabalInstallVersion menv'+            mcabal' <- withProcessContext menv' getCabalInstallVersion             case mcabal' of                 Nothing -> do                     logError "Failed to get cabal-install version after installing it."@@ -1251,17 +1320,17 @@                         "This version is specified by the stack.yaml file included in the ghcjs tarball.\n"                 _ -> return ()         when shouldInstallAlex $ do-            alexInstalled <- doesExecutableExist menv "alex"+            alexInstalled <- runRIO menv $ doesExecutableExist "alex"             when (not alexInstalled) $ do                 logError "Failed to find 'alex' executable after installing it."                 failedToFindErr         when shouldInstallHappy $ do-            happyInstalled <- doesExecutableExist menv "happy"+            happyInstalled <- runRIO menv $ doesExecutableExist "happy"             when (not happyInstalled) $ do                 logError "Failed to find 'happy' executable after installing it."                 failedToFindErr     logSticky "Booting GHCJS (this will take a long time) ..."-    logProcessStderrStdout Nothing "ghcjs-boot" menv' bootOpts+    withProcessContext menv' $ proc "ghcjs-boot" bootOpts logProcessStderrStdout     logStickyDone "GHCJS booted."  loadGhcjsEnvConfig :: HasRunner env@@ -1283,45 +1352,42 @@             set (buildOptsL.buildOptsHaddockL) False envConfig) $         build (\_ -> return ()) Nothing boptsCli -getCabalInstallVersion :: HasLogFunc env => EnvOverride -> RIO env (Maybe Version)-getCabalInstallVersion menv = do-    ebs <- tryProcessStdout Nothing menv "cabal" ["--numeric-version"]-    liftIO $ case ebs of+getCabalInstallVersion :: (HasProcessContext env, HasLogFunc env) => RIO env (Maybe Version)+getCabalInstallVersion = do+    ebs <- proc "cabal" ["--numeric-version"] $ tryAny . readProcessStdout_+    case ebs of         Left _ -> return Nothing-        Right bs -> Just <$> parseVersion (T.dropWhileEnd isSpace (T.decodeUtf8 bs))+        Right bs -> Just <$> parseVersion (T.dropWhileEnd isSpace (T.decodeUtf8 (LBS.toStrict bs)))  -- | Check if given processes appear to be present, throwing an exception if -- missing.-checkDependencies :: (MonadIO m, MonadThrow m, MonadReader env m, HasConfig env)-                  => CheckDependency a -> m a-checkDependencies (CheckDependency f) = do-    menv <- getMinimalEnvOverride-    liftIO (f menv) >>= either (throwM . MissingDependencies) return+checkDependencies :: CheckDependency env a -> RIO env a+checkDependencies (CheckDependency f) = f >>= either (throwIO . MissingDependencies) return -checkDependency :: String -> CheckDependency String-checkDependency tool = CheckDependency $ \menv -> do-    exists <- doesExecutableExist menv tool+checkDependency :: HasProcessContext env => String -> CheckDependency env String+checkDependency tool = CheckDependency $ do+    exists <- doesExecutableExist tool     return $ if exists then Right tool else Left [tool] -newtype CheckDependency a = CheckDependency (EnvOverride -> IO (Either [String] a))+newtype CheckDependency env a = CheckDependency (RIO env (Either [String] a))     deriving Functor-instance Applicative CheckDependency where-    pure x = CheckDependency $ \_ -> return (Right x)-    CheckDependency f <*> CheckDependency x = CheckDependency $ \menv -> do-        f' <- f menv-        x' <- x menv+instance Applicative (CheckDependency env) where+    pure x = CheckDependency $ return (Right x)+    CheckDependency f <*> CheckDependency x = CheckDependency $ do+        f' <- f+        x' <- x         return $             case (f', x') of                 (Left e1, Left e2) -> Left $ e1 ++ e2                 (Left e, Right _) -> Left e                 (Right _, Left e) -> Left e                 (Right f'', Right x'') -> Right $ f'' x''-instance Alternative CheckDependency where-    empty = CheckDependency $ \_ -> return $ Left []-    CheckDependency x <|> CheckDependency y = CheckDependency $ \menv -> do-        res1 <- x menv+instance Alternative (CheckDependency env) where+    empty = CheckDependency $ return $ Left []+    CheckDependency x <|> CheckDependency y = CheckDependency $ do+        res1 <- x         case res1 of-            Left _ -> y menv+            Left _ -> y             Right x' -> return $ Right x'  installGHCWindows :: HasConfig env@@ -1335,7 +1401,7 @@ installGHCWindows version si archiveFile archiveType _tempDir destDir = do     tarComponent <- parseRelDir $ "ghc-" ++ versionString version     withUnpackedTarball7z "GHC" si archiveFile archiveType (Just tarComponent) destDir-    logInfo $ "GHC installed to " <> T.pack (toFilePath destDir)+    logInfo $ "GHC installed to " <> fromString (toFilePath destDir)  installMsys2Windows :: HasConfig env                   => Text -- ^ OS Key@@ -1348,9 +1414,9 @@ installMsys2Windows osKey si archiveFile archiveType _tempDir destDir = do     exists <- liftIO $ D.doesDirectoryExist $ toFilePath destDir     when exists $ liftIO (D.removeDirectoryRecursive $ toFilePath destDir) `catchIO` \e -> do-        logError $ T.pack $-            "Could not delete existing msys directory: " ++-            toFilePath destDir+        logError $+            "Could not delete existing msys directory: " <>+            fromString (toFilePath destDir)         throwM e      msys <- parseRelDir $ "msys" ++ T.unpack (fromMaybe "32" $ T.stripPrefix "windows" osKey)@@ -1360,13 +1426,14 @@     -- I couldn't find this officially documented anywhere, but you need to run     -- the MSYS shell once in order to initialize some pacman stuff. Once that     -- run happens, you can just run commands as usual.-    platform <- view platformL-    menv0 <- getMinimalEnvOverride-    newEnv0 <- modifyEnvOverride menv0 $ Map.insert "MSYSTEM" "MSYS"-    newEnv <- augmentPathMap [destDir </> $(mkRelDir "usr") </> $(mkRelDir "bin")]-                             (unEnvOverride newEnv0)-    menv <- mkEnvOverride platform newEnv-    runCmd (Cmd (Just destDir) "sh" menv ["--login", "-c", "true"]) Nothing+    menv0 <- view processContextL+    newEnv0 <- modifyEnvVars menv0 $ Map.insert "MSYSTEM" "MSYS"+    newEnv <- either throwM return $ augmentPathMap+                  [toFilePath $ destDir </> $(mkRelDir "usr") </> $(mkRelDir "bin")]+                  (view envVarsL newEnv0)+    menv <- mkProcessContext newEnv+    withWorkingDir (toFilePath destDir) $ withProcessContext menv+      $ proc "sh" ["--login", "-c", "true"] runProcess_      -- No longer installing git, it's unreliable     -- (https://github.com/commercialhaskell/stack/issues/1046) and the@@ -1412,7 +1479,7 @@ expectSingleUnpackedDir archiveFile destDir = do     contents <- listDir destDir     case contents of-        ([dir], []) -> return dir+        ([dir], _ ) -> return dir         _ -> throwString $ "Expected a single directory within unpacked " ++ toFilePath archiveFile  -- | Download 7z as necessary, and get a function for unpacking things.@@ -1438,8 +1505,7 @@                         , "-y"                         , toFilePath archive                         ]-                ec <- withProcessTimeLog cmd args $-                    liftIO $ rawSystem cmd args+                ec <- proc cmd args runProcess                 when (ec /= ExitSuccess)                     $ liftIO $ throwM (ProblemWhileDecompressing archive)         _ -> throwM SetupInfoMissingSevenz@@ -1452,18 +1518,16 @@ chattyDownload label downloadInfo path = do     let url = downloadInfoUrl downloadInfo     req <- parseUrlThrow $ T.unpack url-    logSticky $ T.concat-      [ "Preparing to download "-      , label-      , " ..."-      ]-    logDebug $ T.concat-      [ "Downloading from "-      , url-      , " to "-      , T.pack $ toFilePath path-      , " ..."-      ]+    logSticky $+      "Preparing to download " <>+      RIO.display label <>+      " ..."+    logDebug $+      "Downloading from " <>+      RIO.display url <>+      " to " <>+      fromString (toFilePath path) <>+      " ..."     hashChecks <- fmap catMaybes $ forM       [ ("sha1",   HashCheck SHA1,   downloadInfoSha1)       , ("sha256", HashCheck SHA256, downloadInfoSha256)@@ -1471,42 +1535,38 @@       $ \(name, constr, getter) ->         case getter downloadInfo of           Just bs -> do-            logDebug $ T.concat-                [ "Will check against "-                , name-                , " hash: "-                , T.decodeUtf8With T.lenientDecode bs-                ]+            logDebug $+                "Will check against " <>+                name <>+                " hash: " <>+                displayBytesUtf8 bs             return $ Just $ constr $ CheckHexDigestByteString bs           Nothing -> return Nothing-    when (null hashChecks) $ logWarn $ T.concat-        [ "No sha1 or sha256 found in metadata,"-        , " download hash won't be checked."-        ]+    when (null hashChecks) $ logWarn $+        "No sha1 or sha256 found in metadata," <>+        " download hash won't be checked."     let dReq = DownloadRequest             { drRequest = req             , drHashChecks = hashChecks             , drLengthCheck = mtotalSize             , drRetryPolicy = drRetryPolicyDefault             }-    run <- askRunInIO-    x <- verifiedDownload dReq path (chattyDownloadProgress run)+    x <- verifiedDownload dReq path chattyDownloadProgress     if x-        then logStickyDone ("Downloaded " <> label <> ".")+        then logStickyDone ("Downloaded " <> RIO.display label <> ".")         else logStickyDone "Already downloaded."   where     mtotalSize = downloadInfoContentLength downloadInfo-    chattyDownloadProgress runInBase _ = do-        _ <- liftIO $ runInBase $ logSticky $-          label <> ": download has begun"+    chattyDownloadProgress _ = do+        _ <- logSticky $ RIO.display label <> ": download has begun"         CL.map (Sum . S.length)-          =$ chunksOverTime 1-          =$ go+          .| chunksOverTime 1+          .| go       where         go = evalStateC 0 $ awaitForever $ \(Sum size) -> do             modify (+ size)             totalSoFar <- get-            liftIO $ runInBase $ logSticky $ T.pack $+            logSticky $ fromString $                 case mtotalSize of                     Nothing -> chattyProgressNoTotal totalSoFar                     Just 0 -> chattyProgressNoTotal totalSoFar@@ -1550,7 +1610,7 @@ -- The final yield may come sooner, and may be a superfluous mempty. -- Note that Integer and Float literals can be turned into NominalDiffTime -- (these literals are interpreted as "seconds")-chunksOverTime :: (Monoid a, MonadIO m) => NominalDiffTime -> Conduit a m a+chunksOverTime :: (Monoid a, Semigroup a, MonadIO m) => NominalDiffTime -> ConduitM a a m () chunksOverTime diff = do     currentTime <- liftIO getCurrentTime     evalStateC (currentTime, mempty) go@@ -1572,23 +1632,22 @@         go  -- | Perform a basic sanity check of GHC-sanityCheck :: HasLogFunc env-            => EnvOverride-            -> WhichCompiler+sanityCheck :: (HasProcessContext env, HasLogFunc env)+            => WhichCompiler             -> RIO env ()-sanityCheck menv wc = withSystemTempDir "stack-sanity-check" $ \dir -> do+sanityCheck wc = withSystemTempDir "stack-sanity-check" $ \dir -> do     let fp = toFilePath $ dir </> $(mkRelFile "Main.hs")     liftIO $ S.writeFile fp $ T.encodeUtf8 $ T.pack $ unlines         [ "import Distribution.Simple" -- ensure Cabal library is present         , "main = putStrLn \"Hello World\""         ]     let exeName = compilerExeName wc-    ghc <- liftIO $ join $ findExecutable menv exeName-    logDebug $ "Performing a sanity check on: " <> T.pack (toFilePath ghc)-    eres <- tryProcessStdout (Just dir) menv exeName+    ghc <- findExecutable exeName >>= either throwM parseAbsFile+    logDebug $ "Performing a sanity check on: " <> fromString (toFilePath ghc)+    eres <- withWorkingDir (toFilePath dir) $ proc exeName         [ fp         , "-no-user-package-db"-        ]+        ] $ try . readProcessStdout_     case eres of         Left e -> throwIO $ GHCSanityCheckCompileFailed e ghc         Right _ -> return () -- TODO check that the output of running the command is correct@@ -1608,17 +1667,17 @@  -- | Get map of environment variables to set to change the GHC's encoding to UTF-8 getUtf8EnvVars-    :: (HasLogFunc env, HasPlatform env)-    => EnvOverride-    -> CompilerVersion 'CVActual+    :: (HasProcessContext env, HasPlatform env, HasLogFunc env)+    => CompilerVersion 'CVActual     -> RIO env (Map Text Text)-getUtf8EnvVars menv compilerVer =+getUtf8EnvVars compilerVer =     if getGhcVersion compilerVer >= $(mkVersion "7.10.3")         -- GHC_CHARENC supported by GHC >=7.10.3         then return $ Map.singleton "GHC_CHARENC" "UTF-8"         else legacyLocale   where     legacyLocale = do+        menv <- view processContextL         Platform _ os <- view platformL         if os == Cabal.Windows             then@@ -1627,7 +1686,7 @@                  return                      Map.empty             else do-                let checkedVars = map checkVar (Map.toList $ eoTextMap menv)+                let checkedVars = map checkVar (Map.toList $ view envVarsL menv)                     -- List of environment variables that will need to be updated to set UTF-8 (because                     -- they currently do not specify UTF-8).                     needChangeVars = concatMap fst checkedVars@@ -1644,7 +1703,7 @@                              Map.empty                     else do                         -- Get a list of known locales by running @locale -a@.-                        elocales <- tryProcessStdout Nothing menv "locale" ["-a"]+                        elocales <- tryAny $ proc "locale" ["-a"] readProcessStdout_                         let                             -- Filter the list to only include locales with UTF-8 encoding.                             utf8Locales =@@ -1655,8 +1714,8 @@                                             isUtf8Locale                                             (T.lines $                                              T.decodeUtf8With-                                                 T.lenientDecode-                                                 locales)+                                                 T.lenientDecode $+                                                 LBS.toStrict locales)                             mfallback = getFallbackLocale utf8Locales                         when                             (isNothing mfallback)@@ -1667,7 +1726,7 @@                             changes =                                 Map.unions $                                 map-                                    (adjustedVarValue utf8Locales mfallback)+                                    (adjustedVarValue menv utf8Locales mfallback)                                     needChangeVars                             -- Get the values of variables to add.                             adds@@ -1697,9 +1756,9 @@     -- same language /and/ territory, then with same language, and finally the first UTF-8 locale     -- returned by @locale -a@.     adjustedVarValue-        :: [Text] -> Maybe Text -> Text -> Map Text Text-    adjustedVarValue utf8Locales mfallback k =-        case Map.lookup k (eoTextMap menv) of+        :: ProcessContext -> [Text] -> Maybe Text -> Text -> Map Text Text+    adjustedVarValue menv utf8Locales mfallback k =+        case Map.lookup k (view envVarsL menv) of             Nothing -> Map.empty             Just v ->                 case concatMap@@ -1802,7 +1861,7 @@                                 ++ unwords (map snd platforms0)           loop ((isWindows, p'):ps) = do             let p = T.pack p'-            logInfo $ "Querying for archive location for platform: " <> p+            logInfo $ "Querying for archive location for platform: " <> fromString p'             case findArchive archiveInfo p of               Just x -> return (isWindows, x)               Nothing -> loop ps@@ -1818,7 +1877,7 @@                 , destDir </> $(mkRelFile "stack.tmp")                 ) -    logInfo $ "Downloading from: " <> archiveURL+    logInfo $ "Downloading from: " <> RIO.display archiveURL      liftIO $ do       case () of@@ -1849,10 +1908,10 @@     destDir' <- liftIO . D.canonicalizePath . toFilePath $ destDir     warnInstallSearchPathIssues destDir' ["stack"] -    logInfo $ T.pack $ "New stack executable available at " ++ toFilePath destFile+    logInfo $ "New stack executable available at " <> fromString (toFilePath destFile)      when checkPath $ performPathChecking destFile-      `catchAny` \e -> logError (T.pack (show e))+      `catchAny` (logError . displayShow)   where      findArchive (StackReleaseInfo val) pattern = do@@ -1915,7 +1974,7 @@   executablePath <- liftIO getExecutablePath   executablePath' <- parseAbsFile executablePath   unless (toFilePath newFile == executablePath) $ do-    logInfo $ T.pack $ "Also copying stack executable to " ++ executablePath+    logInfo $ "Also copying stack executable to " <> fromString executablePath     tmpFile <- parseAbsFile $ executablePath ++ ".tmp"     eres <- tryIO $ do       liftIO $ copyFile newFile tmpFile@@ -1928,13 +1987,12 @@       Right () -> return ()       Left e         | isPermissionError e -> do-            logWarn $ T.pack $ "Permission error when trying to copy: " ++ show e+            logWarn $ "Permission error when trying to copy: " <> displayShow e             logWarn "Should I try to perform the file copy using sudo? This may fail"             toSudo <- prompt "Try using sudo? (y/n) "             when toSudo $ do               let run cmd args = do-                    ec <- withProcessTimeLog cmd args $-                        liftIO $ rawSystem cmd args+                    ec <- proc cmd args runProcess                     when (ec /= ExitSuccess) $ error $ concat                           [ "Process exited with "                           , show ec@@ -1956,7 +2014,7 @@               logInfo "Going to run the following commands:"               logInfo ""               forM_ commands $ \(cmd, args) ->-                logInfo $ "-  " `T.append` T.unwords (map T.pack (cmd:args))+                logInfo $ "-  " <> mconcat (intersperse " " (fromString <$> (cmd:args)))               mapM_ (uncurry run) commands               logInfo ""               logInfo "sudo file copy worked!"
src/Stack/Setup/Installed.hs view
@@ -26,6 +26,7 @@ import           Stack.Prelude import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as S8+import qualified Data.ByteString.Lazy as BL import           Data.List hiding (concat, elem, maximumBy) import qualified Data.Text as T import qualified Data.Text.Encoding as T@@ -39,7 +40,7 @@ import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version-import           System.Process.Read+import           RIO.Process  data Tool     = Tool PackageIdentifier -- ^ e.g. ghc-7.8.4, msys2-20150512@@ -88,26 +89,25 @@         parseToolText x  getCompilerVersion-  :: HasLogFunc env-  => EnvOverride-  -> WhichCompiler+  :: (HasProcessContext env, HasLogFunc env)+  => WhichCompiler   -> RIO env (CompilerVersion 'CVActual)-getCompilerVersion menv wc =+getCompilerVersion wc =     case wc of         Ghc -> do             logDebug "Asking GHC for its version"-            bs <- readProcessStdout Nothing menv "ghc" ["--numeric-version"]-            let (_, ghcVersion) = versionFromEnd bs+            bs <- proc "ghc" ["--numeric-version"] readProcessStdout_+            let (_, ghcVersion) = versionFromEnd $ BL.toStrict bs             x <- GhcVersion <$> parseVersion (T.decodeUtf8 ghcVersion)-            logDebug $ "GHC version is: " <> compilerVersionText x+            logDebug $ "GHC version is: " <> display x             return x         Ghcjs -> do             logDebug "Asking GHCJS for its version"             -- Output looks like             --             -- The Glorious Glasgow Haskell Compilation System for JavaScript, version 0.1.0 (GHC 7.10.2)-            bs <- readProcessStdout Nothing menv "ghcjs" ["--version"]-            let (rest, ghcVersion) = T.decodeUtf8 <$> versionFromEnd bs+            bs <- proc "ghcjs" ["--version"] readProcessStdout_+            let (rest, ghcVersion) = T.decodeUtf8 <$> versionFromEnd (BL.toStrict bs)                 (_, ghcjsVersion) = T.decodeUtf8 <$> versionFromEnd rest             GhcjsVersion <$> parseVersion ghcjsVersion <*> parseVersion ghcVersion   where@@ -165,7 +165,7 @@                 ]             }         (Platform _ x, toolName) -> do-            logWarn $ "binDirs: unexpected OS/tool combo: " <> T.pack (show (x, toolName))+            logWarn $ "binDirs: unexpected OS/tool combo: " <> displayShow (x, toolName)             return mempty   where     isGHC n = "ghc" == n || "ghc-" `isPrefixOf` n@@ -176,9 +176,11 @@     , edInclude :: ![Path Abs Dir]     , edLib :: ![Path Abs Dir]     } deriving (Show, Generic)+instance Semigroup ExtraDirs where+    (<>) = mappenddefault instance Monoid ExtraDirs where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  installDir :: (MonadReader env m, MonadThrow m)            => Path Abs Dir
src/Stack/Sig.hs view
@@ -2,7 +2,7 @@ {-| Module      : Stack.Sig Description : GPG Signatures for Stack-Copyright   : (c) FPComplete.com, 2015+Copyright   : (c) 2015-2018, Stack contributors License     : BSD3 Maintainer  : Tim Dysinger <tim@fpcomplete.com> Stability   : experimental
src/Stack/Sig/GPG.hs view
@@ -5,7 +5,7 @@ {-| Module      : Stack.Sig.GPG Description : GPG Functions-Copyright   : (c) FPComplete.com, 2015+Copyright   : (c) 2015-2018, Stack contributors License     : BSD3 Maintainer  : Tim Dysinger <tim@fpcomplete.com> Stability   : experimental@@ -29,8 +29,8 @@  -- | Sign a file path with GPG, returning the @Signature@. gpgSign-    :: (MonadIO m, MonadLogger m, MonadThrow m)-    => Path Abs File -> m Signature+    :: HasLogFunc env+    => Path Abs File -> RIO env Signature gpgSign path = do     gpgWarnTTY     (_hIn,hOut,hErr,process) <-@@ -97,7 +97,7 @@ -- | `man gpg-agent` shows that you need GPG_TTY environment variable set to -- properly deal with interactions with gpg-agent. (Doesn't apply to Windows -- though)-gpgWarnTTY :: (MonadIO m, MonadLogger m) => m ()+gpgWarnTTY :: HasLogFunc env => RIO env () gpgWarnTTY =     unless         ("ming" `isPrefixOf` os)
src/Stack/Sig/Sign.hs view
@@ -7,7 +7,7 @@ {-| Module      : Stack.Sig.Sign Description : Signing Packages-Copyright   : (c) FPComplete.com, 2015+Copyright   : (c) 2015-2018, Stack contributors License     : BSD3 Maintainer  : Tim Dysinger <tim@fpcomplete.com> Stability   : experimental@@ -21,10 +21,9 @@ import           Stack.Prelude import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Lazy as L-import qualified Data.Text as T import           Network.HTTP.Client (RequestBody (RequestBodyBS)) import           Network.HTTP.Download-import           Network.HTTP.Simple+import           Network.HTTP.Simple (setRequestMethod, setRequestBody, getResponseStatusCode) import           Network.HTTP.Types (methodPut) import           Path import           Stack.Package@@ -36,12 +35,8 @@ -- | Sign a haskell package with the given url of the signature -- service and a path to a tarball. sign-#if __GLASGOW_HASKELL__ < 710-    :: (Applicative m, MonadUnliftIO m, MonadLogger m, MonadThrow m)-#else-    :: (MonadUnliftIO m, MonadLogger m, MonadThrow m)-#endif-    => String -> Path Abs File -> m Signature+    :: HasLogFunc env+    => String -> Path Abs File -> RIO env Signature sign url filePath =     withRunInIO $ \run ->     withSystemTempDir@@ -82,12 +77,8 @@ -- function will write the bytes to the path in a temp dir and sign -- the tarball with GPG. signTarBytes-#if __GLASGOW_HASKELL__ < 710-    :: (Applicative m, MonadUnliftIO m, MonadLogger m, MonadThrow m)-#else-    :: (MonadUnliftIO m, MonadLogger m, MonadThrow m)-#endif-    => String -> Path Rel File -> L.ByteString -> m Signature+    :: HasLogFunc env+    => String -> Path Rel File -> L.ByteString -> RIO env Signature signTarBytes url tarPath bs =     withSystemTempDir         "stack"@@ -99,8 +90,8 @@ -- | Sign a haskell package given the url to the signature service, a -- @PackageIdentifier@ and a file path to the package on disk. signPackage-    :: (MonadIO m, MonadLogger m, MonadThrow m)-    => String -> PackageIdentifier -> Path Abs File -> m Signature+    :: HasLogFunc env+    => String -> PackageIdentifier -> Path Abs File -> RIO env Signature signPackage url pkg filePath = do     sig@(Signature signature) <- gpgSign filePath     let (PackageIdentifier name version) = pkg@@ -116,5 +107,5 @@     when         (getResponseStatusCode res /= 200)         (throwM (GPGSignException "unable to sign & upload package"))-    logInfo ("Signature uploaded to " <> T.pack fullUrl)+    logInfo ("Signature uploaded to " <> fromString fullUrl)     return sig
src/Stack/Snapshot.hs view
@@ -21,7 +21,7 @@   , calculatePackagePromotion   ) where -import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import           Control.Monad.State.Strict      (get, put, StateT, execStateT) import           Crypto.Hash.Conduit (hashFile) import           Data.Aeson (withObject, (.!=), (.:), (.:?), Value (Object))@@ -32,6 +32,7 @@ import qualified Data.HashMap.Strict as HashMap import qualified Data.Map as Map import qualified Data.Set as Set+import           Data.Time (toGregorian) import qualified Data.Text as T import           Data.Text.Encoding (encodeUtf8) import           Data.Yaml (decodeFileEither, ParseException (AesonException))@@ -44,10 +45,11 @@ import qualified Distribution.Version as C import           Network.HTTP.Client (Request) import           Network.HTTP.Download+import qualified RIO+import           Network.URI (isURI) import           Path import           Path.IO import           Stack.Constants-import           Stack.Fetch import           Stack.Package import           Stack.PackageDump import           Stack.PackageLocation@@ -63,6 +65,7 @@ import           Stack.Types.Compiler import           Stack.Types.Resolver import qualified System.Directory as Dir+import qualified System.FilePath as FilePath  type SinglePackageLocation = PackageLocationIndex FilePath @@ -74,6 +77,7 @@   | NeedResolverOrCompiler !Text   | MissingPackages !(Set PackageName)   | CustomResolverException !Text !(Either Request FilePath) !ParseException+  | InvalidStackageException !SnapName !String   deriving Typeable instance Exception SnapshotException instance Show SnapshotException where@@ -123,18 +127,28 @@   show (CustomResolverException url loc e) = concat     [ "Unable to load custom resolver "     , T.unpack url-    , " from location\n"-    , show loc+    , " from "+    , case loc of+        Left _req -> "HTTP request"+        Right fp -> "local file:\n  " ++ fp     , "\nException: "-    , show e+    , case e of+        AesonException s -> s+        _ -> show e     ]+  show (InvalidStackageException snapName e) = concat+    [ "Unable to parse Stackage snapshot "+    , T.unpack (renderSnapName snapName)+    , ": "+    , e+    ]  -- | Convert a 'Resolver' into a 'SnapshotDef' loadResolver   :: forall env. HasConfig env   => Resolver   -> RIO env SnapshotDef-loadResolver (ResolverSnapshot name) = do+loadResolver (ResolverStackage name) = do     stackage <- view stackRootL     file' <- parseRelFile $ T.unpack file     cachePath <- (buildPlanCacheDir stackage </>) <$> parseRelFile (T.unpack (renderSnapName name <> ".cache"))@@ -145,23 +159,25 @@             Left e -> throwIO e             Right value ->               case parseEither parseStackageSnapshot value of-                Left s -> throwIO $ AesonException s+                Left s -> throwIO $ InvalidStackageException name s                 Right x -> return x-    logDebug $ "Decoding build plan from: " <> T.pack (toFilePath fp)+    logDebug $ "Decoding build plan from: " <> fromString (toFilePath fp)     eres <- tryDecode     case eres of         Right sd -> return sd         Left e -> do-            logDebug $ "Decoding Stackage snapshot definition from file failed: " <> T.pack (show e)+            logDebug $+              "Decoding Stackage snapshot definition from file failed: " <>+              displayShow e             ensureDir (parent fp)             url <- buildBuildPlanUrl name file             req <- parseRequest $ T.unpack url-            logSticky $ "Downloading " <> renderSnapName name <> " build plan ..."-            logDebug $ "Downloading build plan from: " <> url+            logSticky $ "Downloading " <> RIO.display name <> " build plan ..."+            logDebug $ "Downloading build plan from: " <> RIO.display url             wasDownloaded <- redownload req fp             if wasDownloaded-              then logStickyDone $ "Downloaded " <> renderSnapName name <> " build plan."-              else logStickyDone $ "Skipped download of " <> renderSnapName name <> " because its the stored entity tag matches the server version"+              then logStickyDone $ "Downloaded " <> RIO.display name <> " build plan."+              else logStickyDone $ "Skipped download of " <> RIO.display name <> " because its the stored entity tag matches the server version"             tryDecode >>= either throwM return    where@@ -197,7 +213,7 @@         -- Not dropping any packages in a Stackage snapshot         let sdDropPackages = Set.empty -        let sdResolver = ResolverSnapshot name+        let sdResolver = ResolverStackage name             sdResolverName = renderSnapName name          return SnapshotDef {..}@@ -240,7 +256,7 @@     , sdGlobalHints = Map.empty     } loadResolver (ResolverCustom url loc) = do-  logDebug $ "Loading " <> url <> " build plan from " <> T.pack (show loc)+  logDebug $ "Loading " <> RIO.display url <> " build plan from " <> displayShow loc   case loc of     Left req -> download' req >>= load . toFilePath     Right fp -> load fp@@ -260,24 +276,36 @@      load :: FilePath -> RIO env SnapshotDef     load fp = do+      let resolveLocalArchives sd = sd {+            sdLocations = resolveLocalArchive <$> sdLocations sd+          }+          resolveLocalArchive (PLOther (PLArchive archive)) = +            PLOther $ PLArchive $ archive {+              archiveUrl = T.pack $ resolveLocalFilePath (T.unpack $ archiveUrl archive)+            }+          resolveLocalArchive pl = pl+          resolveLocalFilePath path =+            if isURI path || FilePath.isAbsolute path+              then path+              else FilePath.dropFileName fp FilePath.</> FilePath.normalise path+       WithJSONWarnings (sd0, mparentResolver, mcompiler) warnings <-         liftIO (decodeFileEither fp) >>= either           (throwM . CustomResolverException url loc)-          (either (throwM . AesonException) return . parseEither parseCustom)+          (either (throwM . CustomResolverException url loc . AesonException) return . parseEither parseCustom)       logJSONWarnings (T.unpack url) warnings-       forM_ (sdLocations sd0) $ \loc' ->         case loc' of           PLOther (PLFilePath _) -> throwM $ FilepathInCustomSnapshot url           _ -> return ()-+      let sd0' = resolveLocalArchives sd0       -- The fp above may just be the download location for a URL,       -- which we don't want to use. Instead, look back at loc from       -- above.       mdir <-         case loc of           Left _ -> return Nothing-          Right fp' -> (Just . parent) <$> liftIO (Dir.canonicalizePath fp' >>= parseAbsFile)+          Right fp' -> Just . parent <$> liftIO (Dir.canonicalizePath fp' >>= parseAbsFile)        -- Deal with the dual nature of the compiler key, which either       -- means "use this compiler" or "override the compiler in the@@ -306,11 +334,11 @@             let hash' :: SnapshotHash                 hash' = combineHash rawHash $                   case sdResolver parent' of-                    ResolverSnapshot snapName -> snapNameToHash snapName+                    ResolverStackage snapName -> snapNameToHash snapName                     ResolverCustom _ parentHash -> parentHash-                    ResolverCompiler _ -> error "loadResolver: Receieved ResolverCompiler in impossible location"+                    ResolverCompiler _ -> error "loadResolver: Received ResolverCompiler in impossible location"             return (Right parent', hash')-      return $ overrideCompiler sd0+      return $ overrideCompiler sd0'         { sdParent = parent'         , sdResolver = ResolverCustom url hash'         }@@ -321,7 +349,7 @@     parseCustom :: Value                 -> Parser (WithJSONWarnings (SnapshotDef, Maybe (ResolverWith ()), Maybe (CompilerVersion 'CVWanted)))     parseCustom = withObjectWarnings "CustomSnapshot" $ \o -> (,,)-        <$> (SnapshotDef (Left (error "loadResolver")) (ResolverSnapshot (LTS 0 0))+        <$> (SnapshotDef (Left (error "loadResolver")) (ResolverStackage (LTS 0 0))             <$> (o ..: "name")             <*> jsonSubWarningsT (o ..:? "packages" ..!= [])             <*> o ..:? "drop-packages" ..!= Set.empty@@ -346,18 +374,7 @@   -> Path Abs Dir -- ^ project root, used for checking out necessary files   -> SnapshotDef   -> RIO env LoadedSnapshot-loadSnapshot mcompiler root sd = withCabalLoader $ \loader -> loadSnapshot' loader mcompiler root sd---- | Fully load up a 'SnapshotDef' into a 'LoadedSnapshot'-loadSnapshot'-  :: forall env.-     (HasConfig env, HasGHCVariant env)-  => (PackageIdentifierRevision -> IO ByteString) -- ^ load a cabal file's contents from the index-  -> Maybe (CompilerVersion 'CVActual) -- ^ installed GHC we should query; if none provided, use the global hints-  -> Path Abs Dir -- ^ project root, used for checking out necessary files-  -> SnapshotDef-  -> RIO env LoadedSnapshot-loadSnapshot' loadFromIndex mcompiler root =+loadSnapshot mcompiler root =     start   where     start (snapshotDefFixes -> sd) = do@@ -381,18 +398,18 @@           Right sd' -> start sd'        gpds <--        (concat <$> mapM (parseMultiCabalFilesIndex loadFromIndex root) (sdLocations sd))+        (concat <$> mapM (parseMultiCabalFilesIndex root) (sdLocations sd))         `onException` do           logError "Unable to load cabal files for snapshot"           case sdResolver sd of-            ResolverSnapshot name -> do+            ResolverStackage name -> do               stackRoot <- view stackRootL               file <- parseRelFile $ T.unpack $ renderSnapName name <> ".yaml"               let fp = buildPlanDir stackRoot </> file               liftIO $ ignoringAbsence $ removeFile fp               logError ""               logError "----"-              logError $ "Deleting cached snapshot file: " <> T.pack (toFilePath fp)+              logError $ "Deleting cached snapshot file: " <> fromString (toFilePath fp)               logError "Recommendation: try running again. If this fails again, open an upstream issue at:"               logError $                 case name of@@ -403,7 +420,7 @@             _ -> return ()        (globals, snapshot, locals) <--        calculatePackagePromotion loadFromIndex root ls0+        calculatePackagePromotion root ls0         (map (\(x, y) -> (x, y, ())) gpds)         (sdFlags sd) (sdHidden sd) (sdGhcOptions sd) (sdDropPackages sd) @@ -424,8 +441,7 @@ calculatePackagePromotion   :: forall env localLocation.      (HasConfig env, HasGHCVariant env)-  => (PackageIdentifierRevision -> IO ByteString) -- ^ load from index-  -> Path Abs Dir -- ^ project root+  => Path Abs Dir -- ^ project root   -> LoadedSnapshot   -> [(GenericPackageDescription, SinglePackageLocation, localLocation)] -- ^ packages we want to add on top of this snapshot   -> Map PackageName (Map FlagName Bool) -- ^ flags@@ -438,7 +454,7 @@        , Map PackageName (LoadedPackageInfo (SinglePackageLocation, Maybe localLocation)) -- new locals        ) calculatePackagePromotion-  loadFromIndex root (LoadedSnapshot compilerVersion globals0 parentPackages0)+  root (LoadedSnapshot compilerVersion globals0 parentPackages0)   gpds flags0 hides0 options0 drops0 = do        platform <- view platformL@@ -500,7 +516,7 @@        -- ... so recalculate based on new values       upgraded <- fmap Map.fromList-                $ mapM (recalculate loadFromIndex root compilerVersion flags hide ghcOptions)+                $ mapM (recalculate root compilerVersion flags hide ghcOptions)                 $ Map.toList allToUpgrade        -- Could be nice to check snapshot early... but disabling@@ -526,22 +542,21 @@ -- hide values, and GHC options. recalculate :: forall env.                (HasConfig env, HasGHCVariant env)-            => (PackageIdentifierRevision -> IO ByteString)-            -> Path Abs Dir -- ^ root+            => Path Abs Dir -- ^ root             -> CompilerVersion 'CVActual             -> Map PackageName (Map FlagName Bool)             -> Map PackageName Bool -- ^ hide?             -> Map PackageName [Text] -- ^ GHC options             -> (PackageName, LoadedPackageInfo SinglePackageLocation)             -> RIO env (PackageName, LoadedPackageInfo SinglePackageLocation)-recalculate loadFromIndex root compilerVersion allFlags allHide allOptions (name, lpi0) = do+recalculate root compilerVersion allFlags allHide allOptions (name, lpi0) = do   let hide = fromMaybe (lpiHide lpi0) (Map.lookup name allHide)       options = fromMaybe (lpiGhcOptions lpi0) (Map.lookup name allOptions)   case Map.lookup name allFlags of     Nothing -> return (name, lpi0 { lpiHide = hide, lpiGhcOptions = options }) -- optimization     Just flags -> do       let loc = lpiLocation lpi0-      gpd <- parseSingleCabalFileIndex loadFromIndex root loc+      gpd <- parseSingleCabalFileIndex root loc       platform <- view platformL       let res@(name', lpi) = calculate gpd platform compilerVersion loc flags hide options       unless (name == name' && lpiVersion lpi0 == lpiVersion lpi) $ error "recalculate invariant violated"@@ -606,8 +621,7 @@              => CompilerVersion 'CVActual              -> RIO env LoadedSnapshot loadCompiler cv = do-  menv <- getMinimalEnvOverride-  m <- ghcPkgDump menv (whichCompiler cv) []+  m <- ghcPkgDump (whichCompiler cv) []     (conduitDumpPackage .| CL.foldMap (\dp -> Map.singleton (dpGhcPkgId dp) dp))   return LoadedSnapshot     { lsCompilerVersion = cv@@ -686,10 +700,9 @@   where     PackageIdentifier name _version = fromCabalPackageIdentifier $ C.package $ C.packageDescription gpd --- | Some hard-coded fixes for build plans, hopefully to be irrelevant over--- time.+-- | Some hard-coded fixes for build plans, only for hysterical raisins. snapshotDefFixes :: SnapshotDef -> SnapshotDef-snapshotDefFixes sd | isStackage (sdResolver sd) = sd+snapshotDefFixes sd | isOldStackage (sdResolver sd) = sd     { sdFlags = Map.unionWith Map.union overrides $ sdFlags sd     }   where@@ -698,8 +711,12 @@       , ($(mkPackageName "yaml"), Map.singleton $(mkFlagName "system-libyaml") False)       ] -    isStackage (ResolverSnapshot _) = True-    isStackage _ = False+    -- Only apply this hack to older Stackage snapshots. In+    -- particular, nightly-2018-03-13 did not contain these two+    -- packages.+    isOldStackage (ResolverStackage (LTS major _)) = major < 11+    isOldStackage (ResolverStackage (Nightly (toGregorian -> (year, _, _)))) = year < 2018+    isOldStackage _ = False snapshotDefFixes sd = sd  -- | Convert a global 'LoadedPackageInfo' to a snapshot one by@@ -709,9 +726,16 @@     { lpiLocation = PLIndex (PackageIdentifierRevision (PackageIdentifier name (lpiVersion lpi)) CFILatest)     } --- | Split the globals into those which have their dependencies met,--- and those that don't. This deals with promotion of globals to--- snapshot when another global has been upgraded already.+-- | Split the packages into those which have their dependencies met,+-- and those that don't. The first argument is packages that are known+-- to be available for use as a dependency. The second argument is the+-- packages to check.+--+-- This works by repeatedly iterating through the list of input+-- packages, adding any that have their dependencies satisfied to a map+-- (eventually this set is the fst of the result tuple). Once an+-- iteration completes without adding anything to this set, it knows it+-- has found everything that has its dependencies met, and exits. splitUnmetDeps :: Map PackageName Version -- ^ extra dependencies available                -> Map PackageName (LoadedPackageInfo loc)                -> ( Map PackageName (LoadedPackageInfo loc)
src/Stack/Solver.hs view
@@ -19,36 +19,37 @@     , parseCabalOutputLine     ) where -import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import           Data.Aeson.Extended         (object, (.=), toJSON) import qualified Data.ByteString as S+import qualified Data.ByteString.Lazy as BL import           Data.Char (isSpace)+import           Data.Conduit.Process.Typed (eceStderr) import qualified Data.HashMap.Strict as HashMap import qualified Data.HashSet as HashSet-import           Data.List                   ( (\\), isSuffixOf, intercalate-                                             , minimumBy, isPrefixOf)+import           Data.List                   ( (\\), isSuffixOf+                                             , minimumBy, isPrefixOf+                                             , intersperse) import           Data.List.Extra (groupSortOn) import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Text as T import           Data.Text.Encoding (decodeUtf8, encodeUtf8)-import           Data.Text.Encoding.Error (lenientDecode)-import qualified Data.Text.Lazy as LT-import           Data.Text.Lazy.Encoding (decodeUtf8With) import           Data.Tuple (swap) import qualified Data.Yaml as Yaml import qualified Distribution.Package as C import qualified Distribution.PackageDescription as C import qualified Distribution.Text as C-import           Lens.Micro (set) import           Path import           Path.Find (findFiles) import           Path.IO hiding (findExecutable, findFiles, withSystemTempDir)+import qualified RIO import           Stack.Build.Target (gpdVersion) import           Stack.BuildPlan import           Stack.Config (getLocalPackages, loadConfigYaml) import           Stack.Constants (stackDotYaml, wiredInPackages) import           Stack.Package               (readPackageUnresolvedDir, gpdPackageName)+import           Stack.PackageIndex import           Stack.PrettyPrint import           Stack.Setup import           Stack.Setup.Installed@@ -61,11 +62,10 @@ import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Resolver-import           Stack.Types.Runner import           Stack.Types.Version import qualified System.Directory as D import qualified System.FilePath as FP-import           System.Process.Read+import           RIO.Process import           Text.Regex.Applicative.Text (match, sym, psym, anySym, few)  import qualified Data.Text.Normalize as T ( normalize , NormalizationMode(NFC) )@@ -111,12 +111,12 @@                toConstraintArgs (flagConstraints constraintType) ++                fmap toFilePath cabalfps -    menv <- getMinimalEnvOverride-    catch (liftM Right (readProcessStdout (Just tmpdir) menv "cabal" args))-          (\ex -> case ex of-              ProcessFailed _ _ _ err -> return $ Left err-              _ -> throwM ex)-    >>= either parseCabalErrors parseCabalOutput+    try ( withWorkingDir (toFilePath tmpdir)+        $ proc "cabal" args readProcessStdout_+        )+        >>= either+          (parseCabalErrors . eceStderr)+          (parseCabalOutput . BL.toStrict)    where     errCheck = T.isInfixOf "Could not resolve dependencies"@@ -129,11 +129,11 @@     parseCabalErrors err = do         let errExit e = error $ "Could not parse cabal-install errors:\n\n"                               ++ cabalBuildErrMsg (T.unpack e)-            msg = LT.toStrict $ decodeUtf8With lenientDecode err+            msg = decodeUtf8With lenientDecode $ toStrictBytes err          if errCheck msg then do             logInfo "Attempt failed.\n"-            logInfo $ cabalBuildErrMsg msg+            logInfo $ RIO.display $ cabalBuildErrMsg msg             let pkgs = parseConflictingPkgs msg                 mPkgNames = map (C.simpleParse . T.unpack) pkgs                 pkgNames  = map (fromCabalPackageName . C.pkgName)@@ -141,7 +141,7 @@              when (any isNothing mPkgNames) $ do                   logInfo $ "*** Only some package names could be parsed: " <>-                      T.pack (intercalate ", " (map show pkgNames))+                      mconcat (intersperse ", " (map displayShow pkgNames))                   error $ T.unpack $                        "*** User packages involved in cabal failure: "                        <> T.intercalate ", " (parseConflictingPkgs msg)@@ -166,7 +166,7 @@         let ls = drop 1                $ dropWhile (not . T.isPrefixOf "In order, ")                $ linesNoCR-               $ decodeUtf8 bs+               $ decodeUtf8With lenientDecode bs             (errs, pairs) = partitionEithers $ map parseCabalOutputLine ls         if null errs           then return $ Right (Map.fromList pairs)@@ -226,7 +226,7 @@                -> Map PackageName Version -- ^ constraints                -> RIO env [Text] getCabalConfig dir constraintType constraints = do-    indices <- view $ configL.to configPackageIndices+    indices <- view $ cabalLoaderL.to clIndices     remotes <- mapM goIndex indices     let cache = T.pack $ "remote-repo-cache: " ++ dir     return $ cache : remotes ++ map goConstraint (Map.toList constraints)@@ -300,15 +300,14 @@     -> (CompilerVersion 'CVActual -> RIO env a)     -> RIO env a setupCabalEnv compiler inner = do-    mpaths <- setupCompiler compiler-    menv0 <- getMinimalEnvOverride-    envMap <- removeHaskellEnvVars-              <$> augmentPathMap (maybe [] edBins mpaths)-                                 (unEnvOverride menv0)-    platform <- view platformL-    menv <- mkEnvOverride platform envMap--    mcabal <- getCabalInstallVersion menv+  mpaths <- setupCompiler compiler+  menv0 <- view processContextL+  envMap <- either throwM (return . removeHaskellEnvVars)+              $ augmentPathMap (toFilePath <$> maybe [] edBins mpaths)+                               (view envVarsL menv0)+  menv <- mkProcessContext envMap+  withProcessContext menv $ do+    mcabal <- getCabalInstallVersion     case mcabal of         Nothing -> throwM SolverMissingCabalInstall         Just version@@ -323,16 +322,15 @@                 ") is newer than stack has been tested with.  If you run into difficulties, consider downgrading." <> line             | otherwise -> return () -    mver <- getSystemCompiler menv (whichCompiler compiler)+    mver <- getSystemCompiler (whichCompiler compiler)     version <- case mver of         Just (version, _) -> do-            logInfo $ "Using compiler: " <> compilerVersionText version+            logInfo $ "Using compiler: " <> RIO.display version             return version         Nothing -> error "Failed to determine compiler version. \                          \This is most likely a bug." -    env <- set envOverrideL (const (return menv)) <$> ask-    runRIO env (inner version)+    inner version  -- | Merge two separate maps, one defining constraints on package versions and -- the other defining package flagmap, into a single map of version and flagmap@@ -378,7 +376,7 @@  solveResolverSpec stackYaml cabalDirs                   (sd, srcConstraints, extraConstraints) = do-  logInfo $ "Using resolver: " <> sdResolverName sd+  logInfo $ "Using resolver: " <> RIO.display (sdResolverName sd)   let wantedCompilerVersion = sdWantedCompilerVersion sd   setupCabalEnv wantedCompilerVersion $ \compilerVersion -> do     (compilerVer, snapConstraints) <- getResolverConstraints (Just compilerVersion) stackYaml sd@@ -403,12 +401,12 @@      logInfo "Asking cabal to calculate a build plan..."     unless (Map.null depOnlyConstraints)-        (logInfo $ "Trying with " <> srcNames <> " as hard constraints...")+        (logInfo $ "Trying with " <> RIO.display srcNames <> " as hard constraints...")      eresult <- solver Constraint     eresult' <- case eresult of         Left _ | not (Map.null depOnlyConstraints) -> do-            logInfo $ "Retrying with " <> srcNames <> " as preferences..."+            logInfo $ "Retrying with " <> RIO.display srcNames <> " as preferences..."             solver Preference         _ -> return eresult @@ -455,7 +453,7 @@                         <> showItems (map show (Map.toList bothVers))              logInfo $ "Successfully determined a build plan with "-                     <> T.pack (show $ Map.size external)+                     <> displayShow (Map.size external)                      <> " external dependencies."              return $ Right (srcs, external)@@ -501,10 +499,10 @@ -- package.yaml.  Subdirectories can be included depending on the -- @recurse@ parameter. findCabalDirs-  :: (MonadIO m, MonadUnliftIO m, MonadLogger m, HasRunner env, MonadReader env m, HasConfig env)-  => Bool -> Path Abs Dir -> m (Set (Path Abs Dir))+  :: HasConfig env+  => Bool -> Path Abs Dir -> RIO env (Set (Path Abs Dir)) findCabalDirs recurse dir =-    (Set.fromList . map parent)+    Set.fromList . map parent     <$> liftIO (findFiles dir isHpackOrCabal subdirFilter)   where     subdirFilter subdir = recurse && not (isIgnored subdir)@@ -543,7 +541,7 @@      relpaths <- mapM prettyPath cabaldirs     logInfo "Using cabal packages:"-    logInfo $ T.pack (formatGroup relpaths)+    logInfo $ formatGroup relpaths      packages <- map (\(x, y) -> (y, x)) <$>                 mapM (flip readPackageUnresolvedDir True)@@ -566,7 +564,7 @@         error $ "Package name as defined in the .cabal file must match the \                 \.cabal file name.\n\                 \Please fix the following packages and try again:\n"-                <> formatGroup rels+                <> T.unpack (utf8BuilderToText (formatGroup rels))      let dupGroups = filter ((> 1) . length)                             . groupSortOn (gpdPackageName . snd)@@ -581,11 +579,11 @@      when (dupIgnored /= []) $ do         dups <- mapM (mapM (prettyPath. fst)) (dupGroups packages)-        logWarn $ T.pack $-            "Following packages have duplicate package names:\n"-            <> intercalate "\n" (map formatGroup dups)+        logWarn $+            "Following packages have duplicate package names:\n" <>+            mconcat (intersperse "\n" (map formatGroup dups))         case dupErrMsg of-          Nothing -> logWarn $ T.pack $+          Nothing -> logWarn $                  "Packages with duplicate names will be ignored.\n"               <> "Packages in upper level directories will be preferred.\n"           Just msg -> error msg@@ -594,15 +592,14 @@             $ map (\(file, gpd) -> (gpdPackageName gpd,(file, gpd))) unique            , map fst dupIgnored) -formatGroup :: [String] -> String-formatGroup = concatMap (\path -> "- " <> path <> "\n")+formatGroup :: [String] -> Utf8Builder+formatGroup = foldMap (\path -> "- " <> fromString path <> "\n")  reportMissingCabalFiles-  :: (MonadIO m, MonadUnliftIO m, MonadThrow m, MonadLogger m,-      HasRunner env, MonadReader env m, HasConfig env)+  :: HasConfig env   => [Path Abs File]   -- ^ Directories to scan   -> Bool              -- ^ Whether to scan sub-directories-  -> m ()+  -> RIO env () reportMissingCabalFiles cabalfps includeSubdirs = do     allCabalDirs <- findCabalDirs includeSubdirs =<< getCurrentDir @@ -611,7 +608,7 @@               $ allCabalDirs `Set.difference` Set.fromList (map parent cabalfps)     unless (null relpaths) $ do         logWarn "The following packages are missing from the config:"-        logWarn $ T.pack (formatGroup relpaths)+        logWarn $ formatGroup relpaths  -- TODO Currently solver uses a stack.yaml in the parent chain when there is -- no stack.yaml in the current directory. It should instead look for a@@ -632,7 +629,7 @@     let stackYaml = bcStackYaml bconfig     relStackYaml <- prettyPath stackYaml -    logInfo $ "Using configuration file: " <> T.pack relStackYaml+    logInfo $ "Using configuration file: " <> fromString relStackYaml     lp <- getLocalPackages     let packages = lpProject lp     let noPkgMsg = "No cabal packages found in " <> relStackYaml <>@@ -665,12 +662,12 @@     resultSpecs <- case resolverResult of         BuildPlanCheckOk flags ->             return $ Just (mergeConstraints oldSrcs flags, Map.empty)-        BuildPlanCheckPartial {} -> do-            eres <- solveResolverSpec stackYaml cabalDirs+        BuildPlanCheckPartial {} ->+            either (const Nothing) Just <$>+            solveResolverSpec stackYaml cabalDirs                               (sd, srcConstraints, extraConstraints)             -- TODO Solver should also use the init code to ignore incompatible             -- packages-            return $ either (const Nothing) Just eres         BuildPlanCheckFail {} ->             throwM $ ResolverMismatch IsSolverCmd (sdResolverName sd) (show resolverResult) @@ -701,7 +698,7 @@     if changed then do         logInfo ""         logInfo $ "The following changes will be made to "-                   <> T.pack relStackYaml <> ":"+                   <> fromString relStackYaml <> ":"          printResolver (fmap void mOldResolver) (void resolver) @@ -714,12 +711,12 @@         -- TODO backup the old config file         if modStackYaml then do             writeStackYaml stackYaml resolver versions flags-            logInfo $ "Updated " <> T.pack relStackYaml+            logInfo $ "Updated " <> fromString relStackYaml         else do-            logInfo $ "To automatically update " <> T.pack relStackYaml+            logInfo $ "To automatically update " <> fromString relStackYaml                        <> ", rerun with '--update-config'"      else-        logInfo $ "No changes needed to " <> T.pack relStackYaml+        logInfo $ "No changes needed to " <> fromString relStackYaml      where         indentLines t = T.unlines $ fmap ("    " <>) (T.lines t)@@ -727,23 +724,22 @@         printResolver mOldRes res = do             forM_ mOldRes $ \oldRes ->                 when (res /= oldRes) $ do-                    logInfo $ T.concat-                        [ "* Resolver changes from "-                        , resolverRawName oldRes-                        , " to "-                        , resolverRawName res-                        ]+                    logInfo $+                        "* Resolver changes from " <>+                        RIO.display (resolverRawName oldRes) <>+                        " to " <>+                        RIO.display (resolverRawName res)          printFlags fl msg = do             unless (Map.null fl) $ do-                logInfo $ T.pack msg-                logInfo $ indentLines $ decodeUtf8 $ Yaml.encode+                logInfo $ fromString msg+                logInfo $ RIO.display $ indentLines $ decodeUtf8 $ Yaml.encode                                        $ object ["flags" .= fl]          printDeps deps msg = do             unless (Map.null deps) $ do-                logInfo $ T.pack msg-                logInfo $ indentLines $ decodeUtf8 $ Yaml.encode $ object+                logInfo $ fromString msg+                logInfo $ RIO.display $ indentLines $ decodeUtf8 $ Yaml.encode $ object                         ["extra-deps" .= map fromTuple (Map.toList deps)]          writeStackYaml path res deps fl = do@@ -786,7 +782,7 @@     let forNonSnapshot inner = setupCabalEnv (sdWantedCompilerVersion sd) (inner . Just)         runner =           case sdResolver sd of-            ResolverSnapshot _ -> ($ Nothing)+            ResolverStackage _ -> ($ Nothing)             ResolverCompiler _ -> forNonSnapshot             ResolverCustom _ _ -> forNonSnapshot 
src/Stack/StaticBytes.hs view
@@ -114,9 +114,8 @@   lengthD = VP.length   fromWordsD len words0 = unsafePerformIO $ do     ba <- BA.newByteArray len-    let loop _ [] = do-          ba' <- BA.unsafeFreezeByteArray ba-          return $ VP.Vector 0 len ba'+    let loop _ [] =+          VP.Vector 0 len <$> BA.unsafeFreezeByteArray ba         loop i (w:ws) = do           BA.writeByteArray ba i w           loop (i + 1) ws
src/Stack/Types/Build.hs view
@@ -74,13 +74,14 @@ import           Stack.Types.Config import           Stack.Types.FlagName import           Stack.Types.GhcPkgId+import           Stack.Types.NamedComponent import           Stack.Types.Package import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version import           System.Exit                     (ExitCode (ExitFailure)) import           System.FilePath                 (pathSeparator)-import           System.Process.Log              (showProcessArgDebug)+import           RIO.Process                     (showProcessArgDebug)  ---------------------------------------------- -- Exceptions@@ -604,7 +605,6 @@     , map ("--extra-include-dirs=" ++) (Set.toList (configExtraIncludeDirs config))     , map ("--extra-lib-dirs=" ++) (Set.toList (configExtraLibDirs config))     , maybe [] (\customGcc -> ["--with-gcc=" ++ toFilePath customGcc]) (configOverrideGccPath config)-    , hpackOptions (configOverrideHpack config)     , ["--ghcjs" | wc == Ghcjs]     , ["--exact-configuration" | useExactConf]     ]@@ -628,9 +628,6 @@     depOptions = map (uncurry toDepOption) $ Map.toList deps       where         toDepOption = if newerCabal then toDepOption1_22 else toDepOption1_18--    hpackOptions HpackBundled = []-    hpackOptions (HpackCommand cmd) = ["--with-hpack=" ++ cmd]      toDepOption1_22 ident gid = concat         [ "--dependency="
src/Stack/Types/BuildPlan.hs view
@@ -102,7 +102,7 @@ instance NFData SnapshotDef  snapshotDefVC :: VersionConfig SnapshotDef-snapshotDefVC = storeVersionConfig "sd-v1" "tnwWSSLerZ2XeR6XpVwj5Uh0eF4="+snapshotDefVC = storeVersionConfig "sd-v1" "CKo7nln8EXkw07Gq-4ATxszNZiE="  -- | A relative file path including a unique string for the given -- snapshot.@@ -110,7 +110,7 @@ sdRawPathName sd =     T.unpack $ go $ sdResolver sd   where-    go (ResolverSnapshot name) = renderSnapName name+    go (ResolverStackage name) = renderSnapName name     go (ResolverCompiler version) = compilerVersionText version     go (ResolverCustom _ hash) = "custom-" <> sdResolverName sd <> "-" <> trimmedSnapshotHash hash @@ -229,7 +229,7 @@  instance subdirs ~ Subdirs => FromJSON (WithJSONWarnings (PackageLocationIndex subdirs)) where     parseJSON v-        = ((noJSONWarnings . PLIndex) <$> parseJSON v)+        = (noJSONWarnings . PLIndex <$> parseJSON v)       <|> (fmap PLOther <$> parseJSON v)  instance subdirs ~ Subdirs => FromJSON (WithJSONWarnings (PackageLocation subdirs)) where@@ -237,6 +237,7 @@         = (noJSONWarnings <$> withText "PackageLocation" (\t -> http t <|> file t) v)         <|> repo v         <|> archiveObject v+        <|> github v       where         file t = pure $ PLFilePath $ T.unpack t         http t =@@ -269,6 +270,26 @@             , archiveHash = msha'             } +        github = withObjectWarnings "PLArchive:github" $ \o -> do+          GitHubRepo ghRepo <- o ..: "github"+          commit <- o ..: "commit"+          subdirs <- o ..:? "subdirs" ..!= DefaultSubdirs+          return $ PLArchive Archive+            { archiveUrl = "https://github.com/" <> ghRepo <> "/archive/" <> commit <> ".tar.gz"+            , archiveSubdirs = subdirs+            , archiveHash = Nothing+            }++-- An unexported newtype wrapper to hang a 'FromJSON' instance off of. Contains+-- a GitHub user and repo name separated by a forward slash, e.g. "foo/bar".+newtype GitHubRepo = GitHubRepo Text++instance FromJSON GitHubRepo where+    parseJSON = withText "GitHubRepo" $ \s -> do+        case T.split (== '/') s of+            [x, y] | not (T.null x || T.null y) -> return (GitHubRepo s)+            _ -> fail "expecting \"user/repo\""+ -- | Name of an executable. newtype ExeName = ExeName { unExeName :: Text }     deriving (Show, Eq, Ord, Hashable, IsString, Generic, Store, NFData, Data, Typeable)@@ -342,12 +363,15 @@ instance Store DepInfo instance NFData DepInfo -instance Monoid DepInfo where-    mempty = DepInfo mempty (fromVersionRange C.anyVersion)-    DepInfo a x `mappend` DepInfo b y = DepInfo+instance Semigroup DepInfo where+    DepInfo a x <> DepInfo b y = DepInfo         (mappend a b)         (intersectVersionIntervals x y) +instance Monoid DepInfo where+    mempty = DepInfo mempty (fromVersionRange C.anyVersion)+    mappend = (<>)+ data Component = CompLibrary                | CompExecutable                | CompTestSuite@@ -369,10 +393,13 @@ instance Store ModuleInfo instance NFData ModuleInfo +instance Semigroup ModuleInfo where+  ModuleInfo x <> ModuleInfo y =+    ModuleInfo (Map.unionWith Set.union x y)+ instance Monoid ModuleInfo where   mempty = ModuleInfo mempty-  mappend (ModuleInfo x) (ModuleInfo y) =-    ModuleInfo (Map.unionWith Set.union x y)+  mappend = (<>)  moduleInfoVC :: VersionConfig ModuleInfo moduleInfoVC = storeVersionConfig "mi-v2" "8ImAfrwMVmqoSoEpt85pLvFeV3s="
src/Stack/Types/Compiler.hs view
@@ -31,10 +31,6 @@ -- -- Note that despite having this datatype, stack isn't in a hurry to -- support compilers other than GHC.------ NOTE: updating this will change its binary serialization. The--- version number in the 'BinarySchema' instance for 'MiniBuildPlan'--- should be updated. data CompilerVersion (cvType :: CVType)     = GhcVersion {-# UNPACK #-} !Version     | GhcjsVersion@@ -43,6 +39,8 @@     deriving (Generic, Show, Eq, Ord, Data, Typeable) instance Store (CompilerVersion a) instance NFData (CompilerVersion a)+instance Display (CompilerVersion a) where+    display = display . compilerVersionText instance ToJSON (CompilerVersion a) where     toJSON = toJSON . compilerVersionText instance FromJSON (CompilerVersion a) where
src/Stack/Types/Config.hs view
@@ -35,7 +35,6 @@   ,HasConfig(..)   ,askLatestSnapshotUrl   ,explicitSetupDeps-  ,getMinimalEnvOverride   -- ** BuildConfig & HasBuildConfig   ,BuildConfig(..)   ,LocalPackages(..)@@ -44,7 +43,6 @@   ,lpvName   ,lpvVersion   ,lpvComponents-  ,NamedComponent(..)   ,stackYamlL   ,projectRootL   ,HasBuildConfig(..)@@ -77,6 +75,8 @@   -- ** EnvSettings   ,EnvSettings(..)   ,minimalEnvSettings+  ,defaultEnvSettings+  ,plainEnvSettings   -- ** GlobalOpts & GlobalOptsMonoid   ,GlobalOpts(..)   ,GlobalOptsMonoid(..)@@ -90,14 +90,6 @@   ,PackageIndex(..)   ,IndexName(..)   ,indexNameText-  -- Config fields-  ,configPackageIndex-  ,configPackageIndexOld-  ,configPackageIndexCache-  ,configPackageIndexCacheOld-  ,configPackageIndexGz-  ,configPackageIndexRoot-  ,configPackageTarball   -- ** Project & ProjectAndConfigMonoid   ,Project(..)   ,ProjectAndConfigMonoid(..)@@ -133,6 +125,7 @@   ,platformGhcVerOnlyRelDir   ,useShaPathOnWindows   ,shaPath+  ,shaPathForBytes   ,workDirL   -- * Command-specific types   -- ** Eval@@ -163,13 +156,13 @@   ,buildOptsMonoidInstallExesL   ,buildOptsHaddockL   ,globalOptsBuildOptsMonoidL-  ,packageIndicesL   ,stackRootL   ,configUrlsL   ,cabalVersionL   ,whichCompilerL-  ,envOverrideL+  ,envOverrideSettingsL   ,loadedSnapshotL+  ,globalHintsL   ,shouldForceGhcColorFlag   ,appropriateGhcColorFlag   -- * Lens reexport@@ -213,12 +206,14 @@ import           Path import qualified Paths_stack as Meta import           Stack.Constants+import           Stack.PackageIndex (HasCabalLoader (..), CabalLoader (clStackRoot)) import           Stack.Types.BuildPlan import           Stack.Types.Compiler import           Stack.Types.CompilerBuild import           Stack.Types.Docker import           Stack.Types.FlagName import           Stack.Types.Image+import           Stack.Types.NamedComponent import           Stack.Types.Nix import           Stack.Types.PackageIdentifier import           Stack.Types.PackageIndex@@ -230,16 +225,14 @@ import           Stack.Types.Version import qualified System.FilePath as FilePath import           System.PosixCompat.Types (UserID, GroupID, FileMode)-import           System.Process.Read (EnvOverride, findExecutable)+import           RIO.Process (ProcessContext, HasProcessContext (..), findExecutable)  -- Re-exports import           Stack.Types.Config.Build as X  -- | The top-level Stackage configuration. data Config =-  Config {configStackRoot           :: !(Path Abs Dir)-         -- ^ ~/.stack more often than not-         ,configWorkDir             :: !(Path Rel Dir)+  Config {configWorkDir             :: !(Path Rel Dir)          -- ^ this allows to override .stack-work directory          ,configUserConfigPath      :: !(Path Abs File)          -- ^ Path to user configuration file (usually ~/.stack/config.yaml)@@ -249,14 +242,12 @@          -- ^ Docker configuration          ,configNix                 :: !NixOpts          -- ^ Execution environment (e.g nix-shell) configuration-         ,configEnvOverride         :: !(EnvSettings -> IO EnvOverride)+         ,configProcessContextSettings :: !(EnvSettings -> IO ProcessContext)          -- ^ Environment variables to be passed to external tools          ,configLocalProgramsBase   :: !(Path Abs Dir)          -- ^ Non-platform-specific path containing local installations          ,configLocalPrograms       :: !(Path Abs Dir)          -- ^ Path containing local installations (mainly GHC)-         ,configConnectionCount     :: !Int-         -- ^ How many concurrent connections are allowed when downloading          ,configHideTHLoading       :: !Bool          -- ^ Hide the Template Haskell "Loading package ..." messages from the          -- console@@ -276,21 +267,6 @@          -- e.g. The latest snapshot file.          -- A build plan name (e.g. lts5.9.yaml) is appended when downloading          -- the build plan actually.-         ,configPackageIndices      :: ![PackageIndex]-         -- ^ Information on package indices. This is left biased, meaning that-         -- packages in an earlier index will shadow those in a later index.-         ---         -- Warning: if you override packages in an index vs what's available-         -- upstream, you may correct your compiled snapshots, as different-         -- projects may have different definitions of what pkg-ver means! This-         -- feature is primarily intended for adding local packages, not-         -- overriding. Overriding is better accomplished by adding to your-         -- list of packages.-         ---         -- Note that indices specified in a later config file will override-         -- previous indices, /not/ extend them.-         ---         -- Using an assoc list instead of a Map to keep track of priority          ,configSystemGHC           :: !Bool          -- ^ Should we use the system-installed GHC (on the PATH) if          -- available? Can be overridden by command line options.@@ -349,8 +325,6 @@          ,configAllowDifferentUser  :: !Bool          -- ^ Allow users other than the stack root owner to use the stack          -- installation.-         ,configPackageCache        :: !(IORef (Maybe (PackageCache PackageIndex)))-         -- ^ In memory cache of hackage index.          ,configDumpLogs            :: !DumpLogs          -- ^ Dump logs of local non-dependencies when doing a build.          ,configMaybeProject        :: !(Maybe (Project, Path Abs File))@@ -362,10 +336,7 @@          ,configSaveHackageCreds    :: !Bool          -- ^ Should we save Hackage credentials to a file?          ,configRunner              :: !Runner-         ,configIgnoreRevisionMismatch :: !Bool-         -- ^ Ignore a revision mismatch when loading up cabal files,-         -- and fall back to the latest revision. See:-         -- <https://github.com/commercialhaskell/stack/issues/3520>+         ,configCabalLoader         :: !CabalLoader          }  data HpackExecutable@@ -489,9 +460,12 @@     , globalMonoidStackYaml    :: !(First FilePath) -- ^ Override project stack.yaml     } deriving (Show, Generic) +instance Semigroup GlobalOptsMonoid where+    (<>) = mappenddefault+ instance Monoid GlobalOptsMonoid where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  -- | Default logging level should be something useful but not crazy. defaultLogLevel :: LogLevel@@ -620,14 +594,6 @@        $ lpvGPD lpv    in version --- | A single, fully resolved component of a package-data NamedComponent-    = CLib-    | CExe !Text-    | CTest !Text-    | CBench !Text-    deriving (Show, Eq, Ord)- -- | Value returned by 'Stack.Config.loadConfig'. data LoadConfig = LoadConfig     { lcConfig          :: !Config@@ -715,7 +681,7 @@ data ConfigMonoid =   ConfigMonoid     { configMonoidStackRoot          :: !(First (Path Abs Dir))-    -- ^ See: 'configStackRoot'+    -- ^ See: 'clStackRoot'     , configMonoidWorkDir            :: !(First (Path Rel Dir))     -- ^ See: 'configWorkDir'.     , configMonoidBuildOpts          :: !BuildOptsMonoid@@ -733,7 +699,7 @@     , configMonoidUrls               :: !UrlsMonoid     -- ^ See: 'configUrls     , configMonoidPackageIndices     :: !(First [PackageIndex])-    -- ^ See: 'configPackageIndices'+    -- ^ See: @picIndices@     , configMonoidSystemGHC          :: !(First Bool)     -- ^ See: 'configSystemGHC'     ,configMonoidInstallGHC          :: !(First Bool)@@ -809,9 +775,12 @@     }   deriving (Show, Generic) +instance Semigroup ConfigMonoid where+    (<>) = mappenddefault+ instance Monoid ConfigMonoid where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  parseConfigMonoid :: Path Abs Dir -> Value -> Yaml.Parser (WithJSONWarnings ConfigMonoid) parseConfigMonoid = withObjectWarnings "ConfigMonoid" . parseConfigMonoidObject@@ -1095,7 +1064,7 @@                )         ]     show (UnableToExtractArchive url file) = concat-        [ "Archive extraction failed. We support tarballs and zip, couldn't handle the following URL, "+        [ "Archive extraction failed. Tarballs and zip archives are supported, couldn't handle the following URL, "         , T.unpack url, " downloaded to the file ", toFilePath $ filename file         ]     show (BadStackVersionException requiredRange) = concat@@ -1211,44 +1180,6 @@ askLatestSnapshotUrl :: (MonadReader env m, HasConfig env) => m Text askLatestSnapshotUrl = view $ configL.to configUrls.to urlsLatestSnapshot --- | Root for a specific package index-configPackageIndexRoot :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> m (Path Abs Dir)-configPackageIndexRoot (IndexName name) = do-    root <- view stackRootL-    dir <- parseRelDir $ S8.unpack name-    return (root </> $(mkRelDir "indices") </> dir)---- | Location of the 01-index.cache file-configPackageIndexCache :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> m (Path Abs File)-configPackageIndexCache = liftM (</> $(mkRelFile "01-index.cache")) . configPackageIndexRoot---- | Location of the 00-index.cache file-configPackageIndexCacheOld :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> m (Path Abs File)-configPackageIndexCacheOld = liftM (</> $(mkRelFile "00-index.cache")) . configPackageIndexRoot---- | Location of the 01-index.tar file-configPackageIndex :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> m (Path Abs File)-configPackageIndex = liftM (</> $(mkRelFile "01-index.tar")) . configPackageIndexRoot---- | Location of the 00-index.tar file. This file is just a copy of--- the 01-index.tar file, provided for tools which still look for the--- 00-index.tar file.-configPackageIndexOld :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> m (Path Abs File)-configPackageIndexOld = liftM (</> $(mkRelFile "00-index.tar")) . configPackageIndexRoot---- | Location of the 01-index.tar.gz file-configPackageIndexGz :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> m (Path Abs File)-configPackageIndexGz = liftM (</> $(mkRelFile "01-index.tar.gz")) . configPackageIndexRoot---- | Location of a package tarball-configPackageTarball :: (MonadReader env m, HasConfig env, MonadThrow m) => IndexName -> PackageIdentifier -> m (Path Abs File)-configPackageTarball iname ident = do-    root <- configPackageIndexRoot iname-    name <- parseRelDir $ packageNameString $ packageIdentifierName ident-    ver <- parseRelDir $ versionString $ packageIdentifierVersion ident-    base <- parseRelFile $ packageIdentifierString ident ++ ".tar.gz"-    return (root </> $(mkRelDir "packages") </> name </> ver </> base)- -- | @".stack-work"@ workDirL :: HasConfig env => Lens' env (Path Rel Dir) workDirL = configL.lens configWorkDir (\x y -> x { configWorkDir = y })@@ -1303,7 +1234,7 @@     compilerVersion <- envConfigCompilerVersion <$> view envConfigL     compiler <- parseRelDir $ compilerVersionString compilerVersion     return $-        configStackRoot config </>+        view stackRootL config </>         $(mkRelDir "compiler-tools") </>         platform </>         compiler </>@@ -1377,10 +1308,12 @@ #endif  shaPath :: (IsPath Rel t, MonadThrow m) => Path Rel t -> m (Path Rel t)-shaPath+shaPath = shaPathForBytes . encodeUtf8 . T.pack . toFilePath++shaPathForBytes :: (IsPath Rel t, MonadThrow m) => ByteString -> m (Path Rel t)+shaPathForBytes     = parsePath . S8.unpack . S8.take 8     . Mem.convertToBase Mem.Base16 . hashWith SHA1-    . encodeUtf8 . T.pack . toFilePath  -- TODO: Move something like this into the path package. Consider -- subsuming path-io's 'AnyPath'?@@ -1468,19 +1401,12 @@              => m (Bool -> [Path Abs Dir]) extraBinDirs = do     deps <- installationRootDeps-    local <- installationRootLocal+    local' <- installationRootLocal     tools <- bindirCompilerTools     return $ \locals -> if locals-        then [local </> bindirSuffix, deps </> bindirSuffix, tools]+        then [local' </> bindirSuffix, deps </> bindirSuffix, tools]         else [deps </> bindirSuffix, tools] --- | Get the minimal environment override, useful for just calling external--- processes like git or ghc-getMinimalEnvOverride :: (MonadReader env m, HasConfig env, MonadIO m) => m EnvOverride-getMinimalEnvOverride = do-    config' <- view configL-    liftIO $ configEnvOverride config' minimalEnvSettings- minimalEnvSettings :: EnvSettings minimalEnvSettings =     EnvSettings@@ -1491,6 +1417,32 @@     , esKeepGhcRts = False     } +-- | Default @EnvSettings@ which includes locals and GHC_PACKAGE_PATH.+--+-- Note that this also passes through the GHCRTS environment variable.+-- See https://github.com/commercialhaskell/stack/issues/3444+defaultEnvSettings :: EnvSettings+defaultEnvSettings = EnvSettings+    { esIncludeLocals = True+    , esIncludeGhcPackagePath = True+    , esStackExe = True+    , esLocaleUtf8 = False+    , esKeepGhcRts = True+    }++-- | Environment settings which do not embellish the environment+--+-- Note that this also passes through the GHCRTS environment variable.+-- See https://github.com/commercialhaskell/stack/issues/3444+plainEnvSettings :: EnvSettings+plainEnvSettings = EnvSettings+    { esIncludeLocals = False+    , esIncludeGhcPackagePath = False+    , esStackExe = False+    , esLocaleUtf8 = False+    , esKeepGhcRts = True+    }+ -- | Get the path for the given compiler ignoring any local binaries. -- -- https://github.com/commercialhaskell/stack/issues/1052@@ -1501,8 +1453,11 @@ getCompilerPath wc = do     config' <- view configL     eoWithoutLocals <- liftIO $-        configEnvOverride config' minimalEnvSettings { esLocaleUtf8 = True }-    join (findExecutable eoWithoutLocals (compilerExeName wc))+        configProcessContextSettings config' minimalEnvSettings { esLocaleUtf8 = True }+    eres <- runRIO eoWithoutLocals $ findExecutable $ compilerExeName wc+    case eres of+      Left e -> throwM e+      Right x -> parseAbsFile x  data ProjectAndConfigMonoid   = ProjectAndConfigMonoid !Project !ConfigMonoid@@ -1730,6 +1685,16 @@  -- | For @siGHCs@ and @siGHCJSs@ fields maps are deeply merged. -- For all fields the values from the last @SetupInfo@ win.+instance Semigroup SetupInfo where+    l <> r =+        SetupInfo+        { siSevenzExe = siSevenzExe r <|> siSevenzExe l+        , siSevenzDll = siSevenzDll r <|> siSevenzDll l+        , siMsys2 = siMsys2 r <> siMsys2 l+        , siGHCs = Map.unionWith (<>) (siGHCs r) (siGHCs l)+        , siGHCJSs = Map.unionWith (<>) (siGHCJSs r) (siGHCJSs l)+        , siStack = Map.unionWith (<>) (siStack l) (siStack r) }+ instance Monoid SetupInfo where     mempty =         SetupInfo@@ -1740,14 +1705,7 @@         , siGHCJSs = Map.empty         , siStack = Map.empty         }-    mappend l r =-        SetupInfo-        { siSevenzExe = siSevenzExe r <|> siSevenzExe l-        , siSevenzDll = siSevenzDll r <|> siSevenzDll l-        , siMsys2 = siMsys2 r <> siMsys2 l-        , siGHCs = Map.unionWith (<>) (siGHCs r) (siGHCs l)-        , siGHCJSs = Map.unionWith (<>) (siGHCJSs r) (siGHCJSs l)-        , siStack = Map.unionWith (<>) (siStack l) (siStack r) }+    mappend = (<>)  -- | Remote or inline 'SetupInfo' data SetupInfoLocation@@ -1887,7 +1845,7 @@     {-# INLINE ghcVariantL #-}  -- | Class for environment values that can provide a 'Config'.-class (HasPlatform env, HasRunner env) => HasConfig env where+class (HasPlatform env, HasProcessContext env, HasCabalLoader env) => HasConfig env where     configL :: Lens' env Config     default configL :: HasBuildConfig env => Lens' env Config     configL = buildConfigL.lens bcConfig (\x y -> x { bcConfig = y })@@ -1924,6 +1882,24 @@     ghcVariantL = lens bcGHCVariant (\x y -> x { bcGHCVariant = y }) instance HasGHCVariant EnvConfig +instance HasProcessContext Config where+    processContextL = runnerL.processContextL+instance HasProcessContext LoadConfig where+    processContextL = configL.processContextL+instance HasProcessContext BuildConfig where+    processContextL = configL.processContextL+instance HasProcessContext EnvConfig where+    processContextL = configL.processContextL++instance HasCabalLoader Config where+    cabalLoaderL = lens configCabalLoader (\x y -> x { configCabalLoader = y })+instance HasCabalLoader LoadConfig where+    cabalLoaderL = configL.cabalLoaderL+instance HasCabalLoader BuildConfig where+    cabalLoaderL = configL.cabalLoaderL+instance HasCabalLoader EnvConfig where+    cabalLoaderL = configL.cabalLoaderL+ instance HasConfig Config where     configL = id     {-# INLINE configL #-}@@ -1964,16 +1940,16 @@ -- Helper lenses ----------------------------------- -stackRootL :: HasConfig s => Lens' s (Path Abs Dir)-stackRootL = configL.lens configStackRoot (\x y -> x { configStackRoot = y })+stackRootL :: HasCabalLoader s => Lens' s (Path Abs Dir)+stackRootL = cabalLoaderL.lens clStackRoot (\x y -> x { clStackRoot = y }) --- | The compiler specified by the @MiniBuildPlan@. This may be+-- | The compiler specified by the @SnapshotDef@. This may be -- different from the actual compiler used! wantedCompilerVersionL :: HasBuildConfig s => Getting r s (CompilerVersion 'CVWanted) wantedCompilerVersionL = snapshotDefL.to sdWantedCompilerVersion  -- | The version of the compiler which will actually be used. May be--- different than that specified in the 'MiniBuildPlan' and returned+-- different than that specified in the 'SnapshotDef' and returned -- by 'wantedCompilerVersionL'. actualCompilerVersionL :: HasEnvConfig s => Lens' s (CompilerVersion 'CVActual) actualCompilerVersionL = envConfigL.lens@@ -1985,11 +1961,6 @@     bcSnapshotDef     (\x y -> x { bcSnapshotDef = y }) -packageIndicesL :: HasConfig s => Lens' s [PackageIndex]-packageIndicesL = configL.lens-    configPackageIndices-    (\x y -> x { configPackageIndices = y })- buildOptsL :: HasConfig s => Lens' s BuildOpts buildOptsL = configL.lens     configBuild@@ -2046,17 +2017,20 @@ whichCompilerL :: Getting r (CompilerVersion a) WhichCompiler whichCompilerL = to whichCompiler -envOverrideL :: HasConfig env => Lens' env (EnvSettings -> IO EnvOverride)-envOverrideL = configL.lens-    configEnvOverride-    (\x y -> x { configEnvOverride = y })+envOverrideSettingsL :: HasConfig env => Lens' env (EnvSettings -> IO ProcessContext)+envOverrideSettingsL = configL.lens+    configProcessContextSettings+    (\x y -> x { configProcessContextSettings = y }) +globalHintsL :: HasBuildConfig s => Getting r s (Map PackageName (Maybe Version))+globalHintsL = snapshotDefL.to sdGlobalHints+ shouldForceGhcColorFlag :: (HasRunner env, HasEnvConfig env)                         => RIO env Bool shouldForceGhcColorFlag = do     canDoColor <- (>= $(mkVersion "8.2.1")) . getGhcVersion               <$> view actualCompilerVersionL-    shouldDoColor <- logUseColor <$> view logOptionsL+    shouldDoColor <- view useColorL     return $ canDoColor && shouldDoColor  appropriateGhcColorFlag :: (HasRunner env, HasEnvConfig env)
src/Stack/Types/Config/Build.hs view
@@ -64,6 +64,8 @@             -- ^ Watch files for changes and automatically rebuild             ,boptsKeepGoing :: !(Maybe Bool)             -- ^ Keep building/running after failure+            ,boptsKeepTmpFiles :: !(Maybe Bool)+            -- ^ Keep intermediate files and build directories             ,boptsForceDirty :: !Bool             -- ^ Force treating all local packages as having dirty files @@ -105,6 +107,7 @@     , boptsInstallCompilerTool = False     , boptsPreFetch = False     , boptsKeepGoing = Nothing+    , boptsKeepTmpFiles = Nothing     , boptsForceDirty = False     , boptsTests = False     , boptsTestOpts = defaultTestOpts@@ -172,6 +175,7 @@     , buildMonoidInstallCompilerTool :: !(First Bool)     , buildMonoidPreFetch :: !(First Bool)     , buildMonoidKeepGoing :: !(First Bool)+    , buildMonoidKeepTmpFiles :: !(First Bool)     , buildMonoidForceDirty :: !(First Bool)     , buildMonoidTests :: !(First Bool)     , buildMonoidTestOpts :: !TestOptsMonoid@@ -202,6 +206,7 @@               buildMonoidInstallCompilerTool <- First <$> o ..:? buildMonoidInstallCompilerToolArgName               buildMonoidPreFetch <- First <$> o ..:? buildMonoidPreFetchArgName               buildMonoidKeepGoing <- First <$> o ..:? buildMonoidKeepGoingArgName+              buildMonoidKeepTmpFiles <- First <$> o ..:? buildMonoidKeepTmpFilesArgName               buildMonoidForceDirty <- First <$> o ..:? buildMonoidForceDirtyArgName               buildMonoidTests <- First <$> o ..:? buildMonoidTestsArgName               buildMonoidTestOpts <- jsonSubWarnings (o ..:? buildMonoidTestOptsArgName ..!= mempty)@@ -255,6 +260,9 @@ buildMonoidKeepGoingArgName :: Text buildMonoidKeepGoingArgName = "keep-going" +buildMonoidKeepTmpFilesArgName :: Text+buildMonoidKeepTmpFilesArgName = "keep-tmp-files"+ buildMonoidForceDirtyArgName :: Text buildMonoidForceDirtyArgName = "force-dirty" @@ -282,9 +290,12 @@ buildMonoidSkipComponentsName :: Text buildMonoidSkipComponentsName = "skip-components" +instance Semigroup BuildOptsMonoid where+    (<>) = mappenddefault+ instance Monoid BuildOptsMonoid where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  -- | Which subset of packages to build data BuildSubset@@ -339,9 +350,12 @@ toMonoidDisableRunArgName :: Text toMonoidDisableRunArgName = "no-run-tests" +instance Semigroup TestOptsMonoid where+  (<>) = mappenddefault+ instance Monoid TestOptsMonoid where   mempty = memptydefault-  mappend = mappenddefault+  mappend = (<>)   @@ -362,9 +376,12 @@     (\o -> do hoMonoidAdditionalArgs <- o ..:? hoMonoidAdditionalArgsName ..!= []               return HaddockOptsMonoid{..}) +instance Semigroup HaddockOptsMonoid where+  (<>) = mappenddefault+ instance Monoid HaddockOptsMonoid where   mempty = memptydefault-  mappend = mappenddefault+  mappend = (<>)  hoMonoidAdditionalArgsName :: Text hoMonoidAdditionalArgsName = "haddock-args"@@ -401,9 +418,12 @@ beoMonoidDisableRunArgName :: Text beoMonoidDisableRunArgName = "no-run-benchmarks" +instance Semigroup BenchmarkOptsMonoid where+  (<>) = mappenddefault+ instance Monoid BenchmarkOptsMonoid where   mempty = memptydefault-  mappend = mappenddefault+  mappend = (<>)  data FileWatchOpts   = NoFileWatch
src/Stack/Types/Docker.hs view
@@ -9,7 +9,7 @@  module Stack.Types.Docker where -import Stack.Prelude+import Stack.Prelude hiding (Display (..)) import Data.Aeson.Extended import Data.List (intercalate) import qualified Data.Text as T@@ -106,11 +106,11 @@ -- | Decode uninterpreted docker options from JSON/YAML. instance FromJSON (WithJSONWarnings DockerOptsMonoid) where   parseJSON = withObjectWarnings "DockerOptsMonoid"-    (\o -> do dockerMonoidDefaultEnable    <- pure (Any True)+    (\o -> do let dockerMonoidDefaultEnable = Any True               dockerMonoidEnable           <- First <$> o ..:? dockerEnableArgName               dockerMonoidRepoOrImage      <- First <$>-                                              (((Just . DockerMonoidImage) <$> o ..: dockerImageArgName) <|>-                                              ((Just . DockerMonoidRepo) <$> o ..: dockerRepoArgName) <|>+                                              ((Just . DockerMonoidImage <$> o ..: dockerImageArgName) <|>+                                              (Just . DockerMonoidRepo <$> o ..: dockerRepoArgName) <|>                                               pure Nothing)               dockerMonoidRegistryLogin    <- First <$> o ..:? dockerRegistryLoginArgName               dockerMonoidRegistryUsername <- First <$> o ..:? dockerRegistryUsernameArgName@@ -132,9 +132,13 @@               return DockerOptsMonoid{..})  -- | Left-biased combine Docker options+instance Semigroup DockerOptsMonoid where+  (<>) = mappenddefault++-- | Left-biased combine Docker options instance Monoid DockerOptsMonoid where   mempty = memptydefault-  mappend = mappenddefault+  mappend = (<>)  -- | Where to get the `stack` executable to run in Docker containers data DockerStackExe
src/Stack/Types/Image.hs view
@@ -51,9 +51,12 @@                          { ..                          }) +instance Semigroup ImageOptsMonoid where+    (<>) = mappenddefault+ instance Monoid ImageOptsMonoid where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)  instance FromJSON (WithJSONWarnings ImageDockerOpts) where     parseJSON = withObjectWarnings
+ src/Stack/Types/NamedComponent.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+module Stack.Types.NamedComponent+  ( NamedComponent (..)+  , renderComponent+  , renderPkgComponents+  , renderPkgComponent+  , exeComponents+  , testComponents+  , benchComponents+  , isCLib+  , isCExe+  , isCTest+  , isCBench+  ) where++import Stack.Prelude+import Stack.Types.PackageName+import qualified Data.Set as Set+import qualified Data.Text as T++-- | A single, fully resolved component of a package+data NamedComponent+    = CLib+    | CInternalLib !Text+    | CExe !Text+    | CTest !Text+    | CBench !Text+    deriving (Show, Eq, Ord)++renderComponent :: NamedComponent -> Text+renderComponent CLib = "lib"+renderComponent (CInternalLib x) = "internal-lib:" <> x+renderComponent (CExe x) = "exe:" <> x+renderComponent (CTest x) = "test:" <> x+renderComponent (CBench x) = "bench:" <> x++renderPkgComponents :: [(PackageName, NamedComponent)] -> Text+renderPkgComponents = T.intercalate " " . map renderPkgComponent++renderPkgComponent :: (PackageName, NamedComponent) -> Text+renderPkgComponent (pkg, comp) = packageNameText pkg <> ":" <> renderComponent comp++exeComponents :: Set NamedComponent -> Set Text+exeComponents = Set.fromList . mapMaybe mExeName . Set.toList+  where+    mExeName (CExe name) = Just name+    mExeName _ = Nothing++testComponents :: Set NamedComponent -> Set Text+testComponents = Set.fromList . mapMaybe mTestName . Set.toList+  where+    mTestName (CTest name) = Just name+    mTestName _ = Nothing++benchComponents :: Set NamedComponent -> Set Text+benchComponents = Set.fromList . mapMaybe mBenchName . Set.toList+  where+    mBenchName (CBench name) = Just name+    mBenchName _ = Nothing++isCLib :: NamedComponent -> Bool+isCLib CLib{} = True+isCLib _ = False++isCExe :: NamedComponent -> Bool+isCExe CExe{} = True+isCExe _ = False++isCTest :: NamedComponent -> Bool+isCTest CTest{} = True+isCTest _ = False++isCBench :: NamedComponent -> Bool+isCBench CBench{} = True+isCBench _ = False
src/Stack/Types/Nix.hs view
@@ -31,9 +31,7 @@ -- | An uninterpreted representation of nix options. -- Configurations may be "cascaded" using mappend (left-biased). data NixOptsMonoid = NixOptsMonoid-  {nixMonoidDefaultEnable :: !Any-    -- ^ Should nix-shell be defaulted to enabled (does @nix:@ section exist in the config)?-  ,nixMonoidEnable :: !(First Bool)+  {nixMonoidEnable :: !(First Bool)     -- ^ Is using nix-shell enabled?   ,nixMonoidPureShell :: !(First Bool)     -- ^ Should the nix-shell be pure@@ -53,8 +51,7 @@ -- | Decode uninterpreted nix options from JSON/YAML. instance FromJSON (WithJSONWarnings NixOptsMonoid) where   parseJSON = withObjectWarnings "NixOptsMonoid"-    (\o -> do nixMonoidDefaultEnable <- pure (Any False)-              nixMonoidEnable        <- First <$> o ..:? nixEnableArgName+    (\o -> do nixMonoidEnable        <- First <$> o ..:? nixEnableArgName               nixMonoidPureShell     <- First <$> o ..:? nixPureShellArgName               nixMonoidPackages      <- First <$> o ..:? nixPackagesArgName               nixMonoidInitFile      <- First <$> o ..:? nixInitFileArgName@@ -64,9 +61,13 @@               return NixOptsMonoid{..})  -- | Left-biased combine Nix options+instance Semigroup NixOptsMonoid where+  (<>) = mappenddefault++-- | Left-biased combine Nix options instance Monoid NixOptsMonoid where   mempty = memptydefault-  mappend = mappenddefault+  mappend = (<>)  -- | Nix enable argument name. nixEnableArgName :: Text
src/Stack/Types/Package.hs view
@@ -16,9 +16,8 @@ import qualified Data.Set as Set import           Data.Store.Version (VersionConfig) import           Data.Store.VersionTagged (storeVersionConfig)-import qualified Data.Text as T-import           Data.Text.Encoding (encodeUtf8, decodeUtf8)-import           Distribution.InstalledPackageInfo (PError)+import           Distribution.Parsec.Common (PError (..), PWarning (..), showPos)+import qualified Distribution.SPDX.License as SPDX import           Distribution.License (License) import           Distribution.ModuleName (ModuleName) import           Distribution.PackageDescription (TestSuiteInterface, BuildType)@@ -29,13 +28,18 @@ import           Stack.Types.Config import           Stack.Types.FlagName import           Stack.Types.GhcPkgId+import           Stack.Types.NamedComponent import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version  -- | All exceptions thrown by the library. data PackageException-  = PackageInvalidCabalFile (Either PackageIdentifierRevision (Path Abs File)) PError+  = PackageInvalidCabalFile+      !(Either PackageIdentifierRevision (Path Abs File))+      !(Maybe Version)+      ![PError]+      ![PWarning]   | PackageNoCabalFileFound (Path Abs Dir)   | PackageMultipleCabalFilesFound (Path Abs Dir) [Path Abs File]   | MismatchedCabalName (Path Abs File) PackageName@@ -43,19 +47,45 @@   deriving Typeable instance Exception PackageException instance Show PackageException where-    show (PackageInvalidCabalFile loc err) = concat+    show (PackageInvalidCabalFile loc _mversion errs warnings) = concat         [ "Unable to parse cabal file "         , case loc of             Left pir -> "for " ++ packageIdentifierRevisionString pir             Right fp -> toFilePath fp-        , ": "-        , show err+        {-++         Not actually needed, the errors will indicate if a newer version exists.+         Also, it seems that this is set to Just the version even if we support it.++        , case mversion of+            Nothing -> ""+            Just version -> "\nRequires newer Cabal file parser version: " +++                            versionString version+        -}+        , "\n\n"+        , unlines $ map+            (\(PError pos msg) -> concat+                [ "- "+                , showPos pos+                , ": "+                , msg+                ])+            errs+        , unlines $ map+            (\(PWarning _ pos msg) -> concat+                [ "- "+                , showPos pos+                , ": "+                , msg+                ])+            warnings         ]     show (PackageNoCabalFileFound dir) = concat         [ "Stack looks for packages in the directories configured in"-        , " the 'packages' variable defined in your stack.yaml\n"-        , "The current entry points to " ++ toFilePath dir ++-          " but no .cabal file could be found there."+        , " the 'packages' and 'extra-deps' fields defined in your stack.yaml\n"+        , "The current entry points to "+        , toFilePath dir+        , " but no .cabal or package.yaml file could be found there."         ]     show (PackageMultipleCabalFilesFound dir files) =         "Multiple .cabal files found in directory " ++@@ -90,7 +120,7 @@ data Package =   Package {packageName :: !PackageName                    -- ^ Name of the package.           ,packageVersion :: !Version                     -- ^ Version of the package-          ,packageLicense :: !License                     -- ^ The license the package was released under.+          ,packageLicense :: !(Either SPDX.License License) -- ^ The license the package was released under.           ,packageFiles :: !GetPackageFiles               -- ^ Get all files of the package.           ,packageDeps :: !(Map PackageName VersionRange) -- ^ Packages that the package depends on.           ,packageTools :: !(Map ExeName VersionRange)    -- ^ A build tool name.@@ -104,7 +134,7 @@           ,packageExes :: !(Set Text)                     -- ^ names of executables           ,packageOpts :: !GetPackageOpts                 -- ^ Args to pass to GHC.           ,packageHasExposedModules :: !Bool              -- ^ Does the package have exposed modules?-          ,packageBuildType :: !(Maybe BuildType)         -- ^ Package build-type.+          ,packageBuildType :: !BuildType                 -- ^ Package build-type.           ,packageSetupDeps :: !(Maybe (Map PackageName VersionRange))                                                           -- ^ If present: custom-setup dependencies           }@@ -127,7 +157,7 @@                      -> [PackageName]                      -> Path Abs File                      -> RIO env-                          (Map NamedComponent (Set ModuleName)+                          (Map NamedComponent (Map ModuleName (Path Abs File))                           ,Map NamedComponent (Set DotCabalPath)                           ,Map NamedComponent BuildInfoOpts)     }@@ -142,7 +172,7 @@     -- ^ These options can safely have 'nubOrd' applied to them, as     -- there are no multi-word options (see     -- https://github.com/commercialhaskell/stack/issues/1255)-    , bioCabalMacros :: Maybe (Path Abs File)+    , bioCabalMacros :: Path Abs File     } deriving Show  -- | Files to get for a cabal package.@@ -156,7 +186,7 @@     { getPackageFiles :: forall env. HasEnvConfig env                       => Path Abs File                       -> RIO env-                           (Map NamedComponent (Set ModuleName)+                           (Map NamedComponent (Map ModuleName (Path Abs File))                            ,Map NamedComponent (Set DotCabalPath)                            ,Set (Path Abs File)                            ,[PackageWarning])@@ -166,7 +196,7 @@  -- | Warning generated when reading a package data PackageWarning-    = UnlistedModulesWarning (Maybe String) [ModuleName]+    = UnlistedModulesWarning NamedComponent [ModuleName]       -- ^ Modules found that are not listed in cabal file      -- TODO: bring this back - see@@ -257,63 +287,19 @@     }     deriving Show -renderComponent :: NamedComponent -> S.ByteString-renderComponent CLib = "lib"-renderComponent (CExe x) = "exe:" <> encodeUtf8 x-renderComponent (CTest x) = "test:" <> encodeUtf8 x-renderComponent (CBench x) = "bench:" <> encodeUtf8 x--renderPkgComponents :: [(PackageName, NamedComponent)] -> Text-renderPkgComponents = T.intercalate " " . map renderPkgComponent--renderPkgComponent :: (PackageName, NamedComponent) -> Text-renderPkgComponent (pkg, comp) = packageNameText pkg <> ":" <> decodeUtf8 (renderComponent comp)--exeComponents :: Set NamedComponent -> Set Text-exeComponents = Set.fromList . mapMaybe mExeName . Set.toList-  where-    mExeName (CExe name) = Just name-    mExeName _ = Nothing--testComponents :: Set NamedComponent -> Set Text-testComponents = Set.fromList . mapMaybe mTestName . Set.toList-  where-    mTestName (CTest name) = Just name-    mTestName _ = Nothing--benchComponents :: Set NamedComponent -> Set Text-benchComponents = Set.fromList . mapMaybe mBenchName . Set.toList-  where-    mBenchName (CBench name) = Just name-    mBenchName _ = Nothing--isCLib :: NamedComponent -> Bool-isCLib CLib{} = True-isCLib _ = False--isCExe :: NamedComponent -> Bool-isCExe CExe{} = True-isCExe _ = False--isCTest :: NamedComponent -> Bool-isCTest CTest{} = True-isCTest _ = False--isCBench :: NamedComponent -> Bool-isCBench CBench{} = True-isCBench _ = False- lpFiles :: LocalPackage -> Set.Set (Path Abs File) lpFiles = Set.unions . M.elems . lpComponentFiles  -- | A location to install a package into, either snapshot or local data InstallLocation = Snap | Local     deriving (Show, Eq)+instance Semigroup InstallLocation where+    Local <> _ = Local+    _ <> Local = Local+    Snap <> Snap = Snap instance Monoid InstallLocation where     mempty = Snap-    mappend Local _ = Local-    mappend _ Local = Local-    mappend Snap Snap = Snap+    mappend = (<>)  data InstalledPackageLocation = InstalledTo InstallLocation | ExtraGlobal     deriving (Show, Eq)@@ -397,7 +383,7 @@ type InstalledMap = Map PackageName (InstallLocation, Installed)  data Installed-    = Library PackageIdentifier GhcPkgId (Maybe License)+    = Library PackageIdentifier GhcPkgId (Maybe (Either SPDX.License License))     | Executable PackageIdentifier     deriving (Show, Eq) 
src/Stack/Types/PackageIdentifier.hs view
@@ -80,6 +80,8 @@  instance Show PackageIdentifier where   show = show . packageIdentifierString+instance Display PackageIdentifier where+  display = fromString . packageIdentifierString  instance ToJSON PackageIdentifier where   toJSON = toJSON . packageIdentifierString
src/Stack/Types/PackageIndex.hs view
@@ -50,9 +50,12 @@    (index, Maybe PackageDownload, NonEmpty ([CabalHash], OffsetSize))))   deriving (Generic, Eq, Show, Data, Typeable, Store, NFData) +instance Semigroup (PackageCache index) where+  PackageCache x <> PackageCache y = PackageCache (HashMap.unionWith HashMap.union x y)+ instance Monoid (PackageCache index) where   mempty = PackageCache HashMap.empty-  mappend (PackageCache x) (PackageCache y) = PackageCache (HashMap.unionWith HashMap.union x y)+  mappend = (<>)  -- | offset in bytes into the 01-index.tar file for the .cabal file -- contents, and size in bytes of the .cabal file
src/Stack/Types/PackageName.hs view
@@ -60,6 +60,8 @@  instance Show PackageName where   show (PackageName n) = T.unpack n+instance Display PackageName where+  display (PackageName n) = display n  instance FromJSON PackageName where   parseJSON j =
src/Stack/Types/Resolver.hs view
@@ -68,7 +68,7 @@  -- | How we resolve which dependencies to install given a set of packages. data ResolverWith customContents-    = ResolverSnapshot !SnapName -- FIXME rename to ResolverStackage+    = ResolverStackage !SnapName     -- ^ Use an official snapshot from the Stackage project, either an     -- LTS Haskell or Stackage Nightly. @@ -92,7 +92,7 @@  instance ToJSON (ResolverWith a) where     toJSON x = case x of-        ResolverSnapshot name -> toJSON $ renderSnapName name+        ResolverStackage name -> toJSON $ renderSnapName name         ResolverCompiler version -> toJSON $ compilerVersionText version         ResolverCustom loc _ -> toJSON loc instance a ~ () => FromJSON (ResolverWith a) where@@ -102,7 +102,7 @@ -- presentation. When possible, you should prefer @sdResolverName@, as -- it will handle the human-friendly name inside a custom snapshot. resolverRawName :: ResolverWith a -> Text-resolverRawName (ResolverSnapshot name) = renderSnapName name+resolverRawName (ResolverStackage name) = renderSnapName name resolverRawName (ResolverCompiler v) = compilerVersionText v resolverRawName (ResolverCustom loc _ ) = "custom: " <> loc @@ -124,13 +124,13 @@             $ T.stripPrefix "file://" t <|> T.stripPrefix "file:" t       return $ toFilePath dir FP.</> rel     Just req -> return $ Left req-parseCustomLocation _ (ResolverSnapshot name) = return $ ResolverSnapshot name+parseCustomLocation _ (ResolverStackage name) = return $ ResolverStackage name parseCustomLocation _ (ResolverCompiler cv) = return $ ResolverCompiler cv  -- | Parse a @Resolver@ from a @Text@ parseResolverText :: Text -> ResolverWith () parseResolverText t-    | Right x <- parseSnapName t = ResolverSnapshot x+    | Right x <- parseSnapName t = ResolverStackage x     | Just v <- parseCompilerVersion t = ResolverCompiler v     | otherwise = ResolverCustom t () @@ -162,6 +162,8 @@     deriving (Generic, Typeable, Show, Data, Eq) instance Store SnapName instance NFData SnapName+instance Display SnapName where+  display = display . renderSnapName  data BuildPlanTypesException     = ParseSnapNameException !Text
src/Stack/Types/Runner.hs view
@@ -3,13 +3,8 @@ {-# LANGUAGE DeriveGeneric              #-} {-# LANGUAGE FlexibleContexts           #-} {-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE NoImplicitPrelude          #-}-{-# LANGUAGE OverloadedStrings          #-}-{-# LANGUAGE RecordWildCards            #-}-{-# LANGUAGE StandaloneDeriving         #-}-{-# LANGUAGE TemplateHaskell            #-} {-# LANGUAGE TypeFamilies               #-} {-# LANGUAGE UndecidableInstances       #-} @@ -19,43 +14,29 @@     ( Runner (..)     , HasRunner (..)     , terminalL+    , useColorL     , reExecL-    , stickyL-    , logOptionsL-    , Sticky (..)-    , LogOptions (..)     , ColorWhen (..)     , withRunner     ) where -import qualified Data.ByteString.Char8      as S8-import           Data.Char-import           Data.List                  (stripPrefix)-import qualified Data.Text                  as T-import qualified Data.Text.Encoding         as T-import qualified Data.Text.Encoding.Error   as T-import qualified Data.Text.IO               as T-import           Data.Time import           Distribution.PackageDescription (GenericPackageDescription)-import           GHC.Foreign                (peekCString, withCString)-import           Language.Haskell.TH-import           Language.Haskell.TH.Syntax (lift) import           Lens.Micro import           Stack.Prelude              hiding (lift) import           Stack.Constants import           Stack.Types.PackageIdentifier (PackageIdentifierRevision) import           System.Console.ANSI-import           System.FilePath-import           System.IO                  (localeEncoding)-import           System.Log.FastLogger+import           RIO.Process (HasProcessContext (..), ProcessContext, mkDefaultProcessContext) import           System.Terminal  -- | Monadic environment. data Runner = Runner   { runnerReExec     :: !Bool-  , runnerLogOptions :: !LogOptions   , runnerTerminal   :: !Bool-  , runnerSticky     :: !Sticky+  , runnerUseColor   :: !Bool+  , runnerLogFunc    :: !LogFunc+  , runnerTermWidth  :: !Int+  , runnerProcessContext :: !ProcessContext   , runnerParsedCabalFiles :: !(IORef       ( Map PackageIdentifierRevision GenericPackageDescription       , Map (Path Abs Dir)            (GenericPackageDescription, Path Abs File)@@ -70,192 +51,30 @@   -- <https://github.com/commercialhaskell/stack/issues/3591>.   } -class HasLogFunc env => HasRunner env where+class (HasProcessContext env, HasLogFunc env) => HasRunner env where   runnerL :: Lens' env Runner+instance HasProcessContext Runner where+  processContextL = lens runnerProcessContext (\x y -> x { runnerProcessContext = y }) instance HasRunner Runner where   runnerL = id  terminalL :: HasRunner env => Lens' env Bool terminalL = runnerL.lens runnerTerminal (\x y -> x { runnerTerminal = y }) +useColorL :: HasRunner env => Lens' env Bool+useColorL = runnerL.lens runnerUseColor (\x y -> x { runnerUseColor = y })+ reExecL :: HasRunner env => Lens' env Bool reExecL = runnerL.lens runnerReExec (\x y -> x { runnerReExec = y }) -stickyL :: HasRunner env => Lens' env Sticky-stickyL = runnerL.lens runnerSticky (\x y -> x { runnerSticky = y })--logOptionsL :: HasRunner env => Lens' env LogOptions-logOptionsL = runnerL.lens runnerLogOptions (\x y -> x { runnerLogOptions = y })--newtype Sticky = Sticky-  { unSticky :: Maybe (MVar (Maybe Text))-  }--data LogOptions = LogOptions-  { logUseColor      :: Bool-  , logTermWidth     :: Int-  , logUseUnicode    :: Bool-  , logUseTime       :: Bool-  , logMinLevel      :: LogLevel-  , logVerboseFormat :: Bool-  }- -------------------------------------------------------------------------------- -- Logging functionality  instance HasLogFunc Runner where-  logFuncL = to $ \env -> stickyLoggerFuncImpl (view stickyL env) (view logOptionsL env)--stickyLoggerFuncImpl-    :: ToLogStr msg-    => Sticky -> LogOptions-    -> (Loc -> LogSource -> LogLevel -> msg -> IO ())-stickyLoggerFuncImpl (Sticky mref) lo loc src level msg =-    case mref of-        Nothing ->-            loggerFunc-                lo-                out-                loc-                src-                (case level of-                     LevelOther "sticky-done" -> LevelInfo-                     LevelOther "sticky" -> LevelInfo-                     _ -> level)-                msg-        Just ref -> modifyMVar_ ref $ \sticky -> do-            let backSpaceChar = '\8'-                repeating = S8.replicate (maybe 0 T.length sticky)-                clear = S8.hPutStr out-                    (repeating backSpaceChar <>-                     repeating ' ' <>-                     repeating backSpaceChar)--            -- Convert some GHC-generated Unicode characters as necessary-            let msgText-                    | logUseUnicode lo = msgTextRaw-                    | otherwise = T.map replaceUnicode msgTextRaw--            case level of-                LevelOther "sticky-done" -> do-                    clear-                    T.hPutStrLn out msgText-                    hFlush out-                    return Nothing-                LevelOther "sticky" -> do-                    clear-                    T.hPutStr out msgText-                    hFlush out-                    return (Just msgText)-                _-                    | level >= logMinLevel lo -> do-                        clear-                        loggerFunc lo out loc src level $ toLogStr msgText-                        case sticky of-                            Nothing ->-                                return Nothing-                            Just line -> do-                                T.hPutStr out line >> hFlush out-                                return sticky-                    | otherwise ->-                        return sticky-  where-    out = stderr-    msgTextRaw = T.decodeUtf8With T.lenientDecode msgBytes-    msgBytes = fromLogStr (toLogStr msg)---- | Replace Unicode characters with non-Unicode equivalents-replaceUnicode :: Char -> Char-replaceUnicode '\x2018' = '`'-replaceUnicode '\x2019' = '\''-replaceUnicode c = c---- | Logging function takes the log level into account.-loggerFunc :: ToLogStr msg-           => LogOptions -> Handle -> Loc -> Text -> LogLevel -> msg -> IO ()-loggerFunc lo outputChannel loc _src level msg =-   when (level >= logMinLevel lo)-        (liftIO (do out <- getOutput-                    T.hPutStrLn outputChannel out))-  where-    getOutput = do-      timestamp <- getTimestamp-      l <- getLevel-      lc <- getLoc-      return $ T.concat-        [ T.pack timestamp-        , T.pack l-        , T.pack (ansi [Reset])-        , T.decodeUtf8 (fromLogStr (toLogStr msg))-        , T.pack lc-        , T.pack (ansi [Reset])-        ]-     where-       ansi xs | logUseColor lo = setSGRCode xs-               | otherwise = ""-       getTimestamp-         | logVerboseFormat lo && logUseTime lo =-           do now <- getZonedTime-              return $-                  ansi [SetColor Foreground Vivid Black]-                  ++ formatTime' now ++ ": "-         | otherwise = return ""-         where-           formatTime' =-               take timestampLength . formatTime defaultTimeLocale "%F %T.%q"-       getLevel-         | logVerboseFormat lo =-           return ((case level of-                      LevelDebug -> ansi [SetColor Foreground Dull Green]-                      LevelInfo -> ansi [SetColor Foreground Dull Blue]-                      LevelWarn -> ansi [SetColor Foreground Dull Yellow]-                      LevelError -> ansi [SetColor Foreground Dull Red]-                      LevelOther _ -> ansi [SetColor Foreground Dull Magenta]) ++-                   "[" ++-                   map toLower (drop 5 (show level)) ++-                   "] ")-         | otherwise = return ""-       getLoc-         | logVerboseFormat lo =-           return $-               ansi [SetColor Foreground Vivid Black] ++-               "\n@(" ++ fileLocStr ++ ")"-         | otherwise = return ""-       fileLocStr =-         fromMaybe file (stripPrefix dirRoot file) ++-         ':' :-         line loc ++-         ':' :-         char loc-         where-           file = loc_filename loc-           line = show . fst . loc_start-           char = show . snd . loc_start-       dirRoot = $(lift . T.unpack . fromMaybe undefined . T.stripSuffix (T.pack $ "Stack" </> "Types" </> "Runner.hs") . T.pack . loc_filename =<< location)---- | The length of a timestamp in the format "YYYY-MM-DD hh:mm:ss.μμμμμμ".--- This definition is top-level in order to avoid multiple reevaluation at runtime.-timestampLength :: Int-timestampLength =-  length (formatTime defaultTimeLocale "%F %T.000000" (UTCTime (ModifiedJulianDay 0) 0))---- | With a sticky state, do the thing.-withSticky :: (MonadIO m)-           => Bool -> (Sticky -> m b) -> m b-withSticky terminal m =-    if terminal-       then do state <- liftIO (newMVar Nothing)-               originalMode <- liftIO (hGetBuffering stdout)-               liftIO (hSetBuffering stdout NoBuffering)-               a <- m (Sticky (Just state))-               state' <- liftIO (takeMVar state)-               liftIO (when (isJust state') (S8.putStr "\n"))-               liftIO (hSetBuffering stdout originalMode)-               return a-       else m (Sticky Nothing)+  logFuncL = lens runnerLogFunc (\x y -> x { runnerLogFunc = y })  -- | With a 'Runner', do the thing-withRunner :: MonadIO m+withRunner :: MonadUnliftIO m            => LogLevel            -> Bool -- ^ use time?            -> Bool -- ^ terminal?@@ -272,36 +91,29 @@   termWidth <- clipWidth <$> maybe (fromMaybe defaultTerminalWidth                                     <$> liftIO getTerminalWidth)                                    pure widthOverride-  canUseUnicode <- liftIO getCanUseUnicode   ref <- newIORef mempty-  withSticky terminal $ \sticky -> inner Runner+  menv <- mkDefaultProcessContext+  logOptions0 <- logOptionsHandle stderr False+  let logOptions+        = setLogUseColor useColor+        $ setLogUseTime useTime+        $ setLogMinLevel logLevel+        $ setLogVerboseFormat (logLevel <= LevelDebug)+        $ setLogTerminal terminal+          logOptions0+  withLogFunc logOptions $ \logFunc -> inner Runner     { runnerReExec = reExec-    , runnerLogOptions = LogOptions-        { logUseColor = useColor-        , logTermWidth = termWidth-        , logUseUnicode = canUseUnicode-        , logUseTime = useTime-        , logMinLevel = logLevel-        , logVerboseFormat = logLevel <= LevelDebug-        }     , runnerTerminal = terminal-    , runnerSticky = sticky+    , runnerUseColor = useColor+    , runnerLogFunc = logFunc+    , runnerTermWidth = termWidth     , runnerParsedCabalFiles = ref+    , runnerProcessContext = menv     }   where clipWidth w           | w < minTerminalWidth = minTerminalWidth           | w > maxTerminalWidth = maxTerminalWidth           | otherwise = w---- | Taken from GHC: determine if we should use Unicode syntax-getCanUseUnicode :: IO Bool-getCanUseUnicode = do-    let enc = localeEncoding-        str = "\x2018\x2019"-        test = withCString enc str $ \cstr -> do-            str' <- peekCString enc cstr-            return (str == str')-    test `catchIO` \_ -> return False  data ColorWhen = ColorNever | ColorAlways | ColorAuto     deriving (Show, Generic)
src/Stack/Types/Sig.hs view
@@ -6,7 +6,7 @@ {-| Module      : Stack.Types.Sig Description : Signature Types-Copyright   : (c) FPComplete.com, 2015+Copyright   : (c) 2015-2018, Stack contributors License     : BSD3 Maintainer  : Tim Dysinger <tim@fpcomplete.com> Stability   : experimental
src/Stack/Types/Urls.hs view
@@ -38,6 +38,9 @@             <*> o ..: "lts-build-plans"             <*> o ..: "nightly-build-plans" +instance Semigroup UrlsMonoid where+    (<>) = mappenddefault+ instance Monoid UrlsMonoid where     mempty = memptydefault-    mappend = mappenddefault+    mappend = (<>)
src/Stack/Types/Version.hs view
@@ -81,6 +81,8 @@   show (Version v) =     intercalate "."                 (map show (V.toList v))+instance Display Version where+  display = display . versionText  instance ToJSON Version where   toJSON = toJSON . versionText@@ -99,10 +101,13 @@     IntersectingVersionRange { getIntersectingVersionRange :: Cabal.VersionRange }     deriving Show +instance Semigroup IntersectingVersionRange where+    IntersectingVersionRange l <> IntersectingVersionRange r =+        IntersectingVersionRange (l `Cabal.intersectVersionRanges` r)+ instance Monoid IntersectingVersionRange where     mempty = IntersectingVersionRange Cabal.anyVersion-    mappend (IntersectingVersionRange l) (IntersectingVersionRange r) =-        IntersectingVersionRange (l `Cabal.intersectVersionRanges` r)+    mappend = (<>)  -- | Attoparsec parser for a package version. versionParser :: Parser Version
src/Stack/Types/VersionIntervals.hs view
@@ -53,9 +53,8 @@     (toCabal y)  toCabal :: VersionIntervals -> C.VersionIntervals-toCabal (VersionIntervals vi) = fromMaybe-  (error "Stack.Types.VersionIntervals.toCabal: invariant violated")-  (C.mkVersionIntervals $ map go vi)+toCabal (VersionIntervals vi) =+  C.mkVersionIntervals $ map go vi   where     go (VersionInterval lowerV lowerB mupper) =         ( C.LowerBound (toCabalVersion lowerV) (toCabalBound lowerB)
src/Stack/Upgrade.hs view
@@ -12,7 +12,7 @@     , upgradeOpts     ) where -import           Stack.Prelude               hiding (force)+import           Stack.Prelude               hiding (force, Display (..)) import qualified Data.HashMap.Strict         as HashMap import qualified Data.List import qualified Data.Map                    as Map@@ -36,7 +36,7 @@ import           Stack.Types.Resolver import           System.Exit                 (ExitCode (ExitSuccess)) import           System.Process              (rawSystem, readProcess)-import           System.Process.Run+import           RIO.Process  upgradeOpts :: Parser UpgradeOpts upgradeOpts = UpgradeOpts@@ -187,10 +187,9 @@   -> RIO env () sourceUpgrade gConfigMonoid mresolver builtHash (SourceOpts gitRepo) =   withSystemTempDir "stack-upgrade" $ \tmp -> do-    menv <- getMinimalEnvOverride     mdir <- case gitRepo of       Just (repo, branch) -> do-        remote <- liftIO $ readProcess "git" ["ls-remote", repo, branch] []+        remote <- liftIO $ System.Process.readProcess "git" ["ls-remote", repo, branch] []         latestCommit <-           case words remote of             [] -> throwString $ "No commits found for branch " ++ branch ++ " on repo " ++ repo@@ -212,7 +211,7 @@                 -- the stack repo until we're comfortable with "stack upgrade                 -- --git" not working for earlier versions.                 let args = [ "clone", repo , "stack", "--depth", "1", "--recursive", "--branch", branch]-                runCmd (Cmd (Just tmp) "git" menv args) Nothing+                withWorkingDir (toFilePath tmp) $ proc "git" args runProcess_                 return $ Just $ tmp </> $(mkRelDir "stack")       Nothing -> do         updateAllIndices
src/Stack/Upload.hs view
@@ -29,12 +29,11 @@ import           Network.HTTP.Client                   (Response,                                                         RequestBody(RequestBodyLBS),                                                         Request)-import           Network.HTTP.Simple                   (withResponse,-                                                        getResponseStatusCode,+import           Network.HTTP.StackClient              (withResponse, httpNoBody)+import           Network.HTTP.Simple                   (getResponseStatusCode,                                                         getResponseBody,                                                         setRequestHeader,-                                                        parseRequest,-                                                        httpNoBody)+                                                        parseRequest) import           Network.HTTP.Client.MultipartFormData (formDataBody, partFileRequestBody,                                                         partBS, partLBS) import           Network.HTTP.Client.TLS               (getGlobalManager,@@ -125,7 +124,7 @@  credsFile :: Config -> IO FilePath credsFile config = do-    let dir = toFilePath (configStackRoot config) </> "upload"+    let dir = toFilePath (view stackRootL config) </> "upload"     createDirectoryIfMissing True dir     return $ dir </> "credentials.json" 
− src/System/Process/Log.hs
@@ -1,64 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}---- | Separate module because TH.--module System.Process.Log-    (logCreateProcess-    ,withProcessTimeLog-    ,showProcessArgDebug)-    where--import qualified Data.Text as T-import           Stack.Prelude-import qualified System.Clock as Clock-import           System.Process (CreateProcess(..), CmdSpec(..))---- | Log running a process with its arguments, for debugging (-v).-logCreateProcess :: MonadLogger m => CreateProcess -> m ()-logCreateProcess CreateProcess { cmdspec = ShellCommand shellCmd } =-  logDebug ("Creating shell process: " <> T.pack shellCmd)-logCreateProcess CreateProcess { cmdspec = RawCommand name args } =-  logDebug-      ("Creating process: " <> T.pack name <> " " <>-       T.intercalate-           " "-           (map showProcessArgDebug args))---- | Log running a process with its arguments, for debugging (-v).------ This logs one message before running the process and one message after.-withProcessTimeLog :: (MonadIO m, MonadLogger m) => String -> [String] -> m a -> m a-withProcessTimeLog name args proc = do-  let cmdText =-          T.intercalate-              " "-              (T.pack name : map showProcessArgDebug args)-  logDebug ("Run process: " <> cmdText)-  start <- liftIO $ Clock.getTime Clock.Monotonic-  x <- proc-  end <- liftIO $ Clock.getTime Clock.Monotonic-  let diff = Clock.diffTimeSpec start end-  -- useAnsi <- asks getAnsiTerminal-  let useAnsi = True-  logDebug-      ("Process finished in " <>-      (if useAnsi then "\ESC[92m" else "") <> -- green-      timeSpecMilliSecondText diff <>-      (if useAnsi then "\ESC[0m" else "") <> -- reset-       ": " <> cmdText)-  return x--timeSpecMilliSecondText :: Clock.TimeSpec -> Text-timeSpecMilliSecondText t =-    (T.pack . show . (`div` 10^(6 :: Int)) . Clock.toNanoSecs) t <> "ms"---- | Show a process arg including speechmarks when necessary. Just for--- debugging purposes, not functionally important.-showProcessArgDebug :: String -> Text-showProcessArgDebug x-    | any special x || null x = T.pack (show x)-    | otherwise = T.pack x-  where special '"' = True-        special ' ' = True-        special _ = False
src/System/Process/PagerEditor.hs view
@@ -7,6 +7,7 @@   (-- * Pager    pageWriter   ,pageByteString+  ,pageText   ,pageBuilder   ,pageFile   ,pageString@@ -19,9 +20,9 @@   ,EditorException(..))   where -import Stack.Prelude hiding (ByteString)-import Data.ByteString.Lazy (ByteString,hPut,readFile)-import Data.ByteString.Builder (Builder,stringUtf8,hPutBuilder)+import qualified Data.ByteString.Lazy (readFile)+import Data.ByteString.Lazy (hPut)+import Stack.Prelude import System.Directory (findExecutable) import System.Environment (lookupEnv) import System.Exit (ExitCode(..))@@ -29,6 +30,7 @@ import System.Process (createProcess,shell,proc,waitForProcess,StdStream (CreatePipe)                       ,CreateProcess(std_in, close_fds, delegate_ctlc)) import System.IO (hPutStr,readFile,stdout)+import qualified Data.Text.IO as T  -- | Run pager, providing a function that writes to the pager's input. pageWriter :: (Handle -> IO ()) -> IO ()@@ -52,9 +54,13 @@        Nothing -> writer stdout  -- | Run pager to display a lazy ByteString.-pageByteString :: ByteString -> IO ()+pageByteString :: LByteString -> IO () pageByteString = pageWriter . flip hPut +-- | Run pager to display a 'Text'+pageText :: Text -> IO ()+pageText = pageWriter . flip T.hPutStr+ -- | Run pager to display a ByteString-Builder. pageBuilder :: Builder -> IO () pageBuilder = pageWriter . flip hPutBuilder@@ -65,7 +71,7 @@  -- | Run pager to display a string. pageString :: String -> IO ()-pageString = pageBuilder . stringUtf8+pageString = pageBuilder . fromString  -- | Run editor to edit a file. editFile :: FilePath -> IO ()@@ -95,7 +101,7 @@                                     reader p')  -- | Run editor on a ByteString.-editByteString :: String -> ByteString -> IO ByteString+editByteString :: String -> LByteString -> IO LByteString editByteString f s = editReaderWriter f (`hPut` s) Data.ByteString.Lazy.readFile  -- | Run editor on a String.
− src/System/Process/Read.hs
@@ -1,436 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings #-}---- | Reading from external processes.--module System.Process.Read-  (readProcessStdout-  ,readProcessStderrStdout-  ,tryProcessStdout-  ,tryProcessStderrStdout-  ,sinkProcessStdout-  ,sinkProcessStderrStdout-  ,sinkProcessStderrStdoutHandle-  ,logProcessStderrStdout-  ,readProcess-  ,EnvOverride(..)-  ,unEnvOverride-  ,mkEnvOverride-  ,modifyEnvOverride-  ,envHelper-  ,doesExecutableExist-  ,findExecutable-  ,getEnvOverride-  ,envSearchPath-  ,preProcess-  ,readProcessNull-  ,ReadProcessException (..)-  ,augmentPath-  ,augmentPathMap-  ,resetExeCache-  )-  where--import           Stack.Prelude-import qualified Data.ByteString as S-import           Data.ByteString.Builder-import qualified Data.ByteString.Lazy as L-import           Data.Conduit-import qualified Data.Conduit.Binary as CB-import qualified Data.Conduit.List as CL-import           Data.Conduit.Process hiding (callProcess)-import qualified Data.Map as Map-import qualified Data.Text as T-import           Data.Text.Encoding (decodeUtf8With)-import           Data.Text.Encoding.Error (lenientDecode)-import qualified Data.Text.Lazy as LT-import qualified Data.Text.Lazy.Encoding as LT-import           Distribution.System (OS (Windows), Platform (Platform))-import           Path-import           Path.Extra-import           Path.IO hiding (findExecutable)-import qualified System.Directory as D-import           System.Environment (getEnvironment)-import           System.Exit-import qualified System.FilePath as FP-import           System.Process.Log---- | Override the environment received by a child process.-data EnvOverride = EnvOverride-    { eoTextMap :: Map Text Text -- ^ Environment variables as map-    , eoStringList :: [(String, String)] -- ^ Environment variables as association list-    , eoPath :: [FilePath] -- ^ List of directories searched for executables (@PATH@)-    , eoExeCache :: IORef (Map FilePath (Either ReadProcessException (Path Abs File)))-    , eoExeExtensions :: [String] -- ^ @[""]@ on non-Windows systems, @["", ".exe", ".bat"]@ on Windows-    , eoPlatform :: Platform-    }---- | Get the environment variables from an 'EnvOverride'.-unEnvOverride :: EnvOverride -> Map Text Text-unEnvOverride = eoTextMap---- | Get the list of directories searched (@PATH@).-envSearchPath :: EnvOverride -> [FilePath]-envSearchPath = eoPath---- | Modify the environment variables of an 'EnvOverride'.-modifyEnvOverride :: MonadIO m-                  => EnvOverride-                  -> (Map Text Text -> Map Text Text)-                  -> m EnvOverride-modifyEnvOverride eo f = mkEnvOverride-    (eoPlatform eo)-    (f $ eoTextMap eo)---- | Create a new 'EnvOverride'.-mkEnvOverride :: MonadIO m-              => Platform-              -> Map Text Text-              -> m EnvOverride-mkEnvOverride platform tm' = do-    ref <- liftIO $ newIORef Map.empty-    return EnvOverride-        { eoTextMap = tm-        , eoStringList = map (T.unpack *** T.unpack) $ Map.toList tm-        , eoPath =-             (if isWindows then (".":) else id)-             (maybe [] (FP.splitSearchPath . T.unpack) (Map.lookup "PATH" tm))-        , eoExeCache = ref-        , eoExeExtensions =-            if isWindows-                then let pathext = fromMaybe-                           ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC"-                           (Map.lookup "PATHEXT" tm)-                      in map T.unpack $ "" : T.splitOn ";" pathext-                else [""]-        , eoPlatform = platform-        }-  where-    -- Fix case insensitivity of the PATH environment variable on Windows.-    tm-        | isWindows = Map.fromList $ map (first T.toUpper) $ Map.toList tm'-        | otherwise = tm'--    -- Don't use CPP so that the Windows code path is at least type checked-    -- regularly-    isWindows =-        case platform of-            Platform _ Windows -> True-            _ -> False---- | Helper conversion function.-envHelper :: EnvOverride -> Maybe [(String, String)]-envHelper = Just . eoStringList---- | Read from the process, ignoring any output.------ Throws a 'ReadProcessException' exception if the process fails.-readProcessNull :: (MonadUnliftIO m, MonadLogger m)-                => Maybe (Path Abs Dir) -- ^ Optional working directory-                -> EnvOverride-                -> String -- ^ Command-                -> [String] -- ^ Command line arguments-                -> m ()-readProcessNull wd menv name args =-    sinkProcessStdout wd menv name args CL.sinkNull---- | Try to produce a strict 'S.ByteString' from the stdout of a--- process.-tryProcessStdout :: (MonadUnliftIO m, MonadLogger m)-                 => Maybe (Path Abs Dir) -- ^ Optional directory to run in-                 -> EnvOverride-                 -> String -- ^ Command-                 -> [String] -- ^ Command line arguments-                 -> m (Either ReadProcessException S.ByteString)-tryProcessStdout wd menv name args =-    try (readProcessStdout wd menv name args)---- | Try to produce strict 'S.ByteString's from the stderr and stdout of a--- process.-tryProcessStderrStdout :: (MonadUnliftIO m, MonadLogger m)-                       => Maybe (Path Abs Dir) -- ^ Optional directory to run in-                       -> EnvOverride-                       -> String -- ^ Command-                       -> [String] -- ^ Command line arguments-                       -> m (Either ReadProcessException (S.ByteString, S.ByteString))-tryProcessStderrStdout wd menv name args =-    try (readProcessStderrStdout wd menv name args)---- | Produce a strict 'S.ByteString' from the stdout of a process.------ Throws a 'ReadProcessException' exception if the process fails.-readProcessStdout :: (MonadUnliftIO m, MonadLogger m)-                  => Maybe (Path Abs Dir) -- ^ Optional directory to run in-                  -> EnvOverride-                  -> String -- ^ Command-                  -> [String] -- ^ Command line arguments-                  -> m S.ByteString-readProcessStdout wd menv name args =-  sinkProcessStdout wd menv name args CL.consume >>=-  liftIO . evaluate . S.concat---- | Produce strict 'S.ByteString's from the stderr and stdout of a process.------ Throws a 'ReadProcessException' exception if the process fails.-readProcessStderrStdout :: (MonadUnliftIO m, MonadLogger m)-                        => Maybe (Path Abs Dir) -- ^ Optional directory to run in-                        -> EnvOverride-                        -> String -- ^ Command-                        -> [String] -- ^ Command line arguments-                        -> m (S.ByteString, S.ByteString)-readProcessStderrStdout wd menv name args = do-  (e, o) <- sinkProcessStderrStdout wd menv name args CL.consume CL.consume-  liftIO $ (,) <$> evaluate (S.concat e) <*> evaluate (S.concat o)---- | An exception while trying to read from process.-data ReadProcessException-    = ProcessFailed CreateProcess ExitCode L.ByteString L.ByteString-    -- ^ @'ProcessFailed' createProcess exitCode stdout stderr@-    | NoPathFound-    | ExecutableNotFound String [FilePath]-    | ExecutableNotFoundAt FilePath-    deriving Typeable-instance Show ReadProcessException where-    show (ProcessFailed cp ec out err) = concat $-        [ "Running "-        , showSpec $ cmdspec cp] ++-        maybe [] (\x -> [" in directory ", x]) (cwd cp) ++-        [ " exited with "-        , show ec-        , "\n\n"-        , toStr out-        , "\n"-        , toStr err-        ]-      where-        toStr = LT.unpack . LT.decodeUtf8With lenientDecode--        showSpec (ShellCommand str) = str-        showSpec (RawCommand cmd args) =-            unwords $ cmd : map (T.unpack . showProcessArgDebug) args-    show NoPathFound = "PATH not found in EnvOverride"-    show (ExecutableNotFound name path) = concat-        [ "Executable named "-        , name-        , " not found on path: "-        , show path-        ]-    show (ExecutableNotFoundAt name) =-        "Did not find executable at specified path: " ++ name-instance Exception ReadProcessException---- | Consume the stdout of a process feeding strict 'S.ByteString's to a consumer.--- If the process fails, spits out stdout and stderr as error log--- level. Should not be used for long-running processes or ones with--- lots of output; for that use 'sinkProcessStdoutLogStderr'.------ Throws a 'ReadProcessException' if unsuccessful.-sinkProcessStdout-    :: (MonadUnliftIO m, MonadLogger m)-    => Maybe (Path Abs Dir) -- ^ Optional directory to run in-    -> EnvOverride-    -> String -- ^ Command-    -> [String] -- ^ Command line arguments-    -> Sink S.ByteString IO a -- ^ Sink for stdout-    -> m a-sinkProcessStdout wd menv name args sinkStdout = do-  stderrBuffer <- liftIO (newIORef mempty)-  stdoutBuffer <- liftIO (newIORef mempty)-  (_,sinkRet) <--      catch-          (sinkProcessStderrStdout-               wd-               menv-               name-               args-               (CL.mapM_ (\bytes -> liftIO (modifyIORef' stderrBuffer (<> byteString bytes))))-               (CL.iterM (\bytes -> liftIO (modifyIORef' stdoutBuffer (<> byteString bytes))) $=-                sinkStdout))-          (\(ProcessExitedUnsuccessfully cp ec) ->-               do stderrBuilder <- liftIO (readIORef stderrBuffer)-                  stdoutBuilder <- liftIO (readIORef stdoutBuffer)-                  liftIO $ throwM $ ProcessFailed-                    cp-                    ec-                    (toLazyByteString stdoutBuilder)-                    (toLazyByteString stderrBuilder))-  return sinkRet--logProcessStderrStdout-    :: (HasCallStack, MonadUnliftIO m, MonadLogger m)-    => Maybe (Path Abs Dir)-    -> String-    -> EnvOverride-    -> [String]-    -> m ()-logProcessStderrStdout mdir name menv args = withUnliftIO $ \u -> do-    let logLines = CB.lines =$ CL.mapM_ (unliftIO u . logInfo . decodeUtf8With lenientDecode)-    ((), ()) <- unliftIO u $ sinkProcessStderrStdout mdir menv name args logLines logLines-    return ()---- | Consume the stdout and stderr of a process feeding strict 'S.ByteString's to the consumers.------ Throws a 'ReadProcessException' if unsuccessful in launching, or 'ProcessExitedUnsuccessfully' if the process itself fails.-sinkProcessStderrStdout :: forall m e o. (MonadIO m, MonadLogger m)-                        => Maybe (Path Abs Dir) -- ^ Optional directory to run in-                        -> EnvOverride-                        -> String -- ^ Command-                        -> [String] -- ^ Command line arguments-                        -> Sink S.ByteString IO e -- ^ Sink for stderr-                        -> Sink S.ByteString IO o -- ^ Sink for stdout-                        -> m (e,o)-sinkProcessStderrStdout wd menv name args sinkStderr sinkStdout = do-  name' <- preProcess wd menv name-  withProcessTimeLog name' args $-      liftIO $ withCheckedProcess-          (proc name' args) { env = envHelper menv, cwd = fmap toFilePath wd }-          (\ClosedStream out err -> f err out)-  where--    -- There is a bug in streaming-commons or conduit-extra which-    -- leads to a file descriptor leak. Ideally, we should be able to-    -- simply use the following code. Instead, we're using the code-    -- below it, which is explicit in closing Handles. When the-    -- upstream bug is fixed, we can consider moving back to the-    -- simpler code, though there's really no downside to the more-    -- complex version used here.-    ---    -- f :: Source IO S.ByteString -> Source IO S.ByteString -> IO (e, o)-    -- f err out = (err $$ sinkStderr) `concurrently` (out $$ sinkStdout)--    f :: Handle -> Handle -> IO (e, o)-    f err out = ((CB.sourceHandle err $$ sinkStderr) `concurrently` (CB.sourceHandle out $$ sinkStdout))-        `finally` hClose err `finally` hClose out---- | Like sinkProcessStderrStdout, but receives Handles for stderr and stdout instead of 'Sink's.------ Throws a 'ReadProcessException' if unsuccessful in launching, or 'ProcessExitedUnsuccessfully' if the process itself fails.-sinkProcessStderrStdoutHandle :: (MonadIO m, MonadLogger m)-                              => Maybe (Path Abs Dir) -- ^ Optional directory to run in-                              -> EnvOverride-                              -> String -- ^ Command-                              -> [String] -- ^ Command line arguments-                              -> Handle-                              -> Handle-                              -> m ()-sinkProcessStderrStdoutHandle wd menv name args err out = do-  name' <- preProcess wd menv name-  withProcessTimeLog name' args $-      liftIO $ withCheckedProcess-          (proc name' args)-              { env = envHelper menv-              , cwd = fmap toFilePath wd-              , std_err = UseHandle err-              , std_out = UseHandle out-              }-          (\ClosedStream UseProvidedHandle UseProvidedHandle -> return ())---- | Perform pre-call-process tasks.  Ensure the working directory exists and find the--- executable path.------ Throws a 'ReadProcessException' if unsuccessful.-preProcess :: (MonadIO m)-  => Maybe (Path Abs Dir) -- ^ Optional directory to create if necessary-  -> EnvOverride       -- ^ How to override environment-  -> String            -- ^ Command name-  -> m FilePath-preProcess wd menv name = do-  name' <- liftIO $ liftM toFilePath $ join $ findExecutable menv name-  maybe (return ()) ensureDir wd-  return name'---- | Check if the given executable exists on the given PATH.-doesExecutableExist :: (MonadIO m)-  => EnvOverride       -- ^ How to override environment-  -> String            -- ^ Name of executable-  -> m Bool-doesExecutableExist menv name = liftM isJust $ findExecutable menv name---- | Find the complete path for the executable.------ Throws a 'ReadProcessException' if unsuccessful.-findExecutable :: (MonadIO m, MonadThrow n)-  => EnvOverride       -- ^ How to override environment-  -> String            -- ^ Name of executable-  -> m (n (Path Abs File)) -- ^ Full path to that executable on success-findExecutable eo name0 | any FP.isPathSeparator name0 = do-    let names0 = map (name0 ++) (eoExeExtensions eo)-        testNames [] = return $ throwM $ ExecutableNotFoundAt name0-        testNames (name:names) = do-            exists <- liftIO $ D.doesFileExist name-            if exists-                then do-                    path <- liftIO $ resolveFile' name-                    return $ return path-                else testNames names-    testNames names0-findExecutable eo name = liftIO $ do-    m <- readIORef $ eoExeCache eo-    epath <- case Map.lookup name m of-        Just epath -> return epath-        Nothing -> do-            let loop [] = return $ Left $ ExecutableNotFound name (eoPath eo)-                loop (dir:dirs) = do-                    let fp0 = dir FP.</> name-                        fps0 = map (fp0 ++) (eoExeExtensions eo)-                        testFPs [] = loop dirs-                        testFPs (fp:fps) = do-                            exists <- D.doesFileExist fp-                            existsExec <- if exists then liftM D.executable $ D.getPermissions fp else return False-                            if existsExec-                                then do-                                    fp' <- D.makeAbsolute fp >>= parseAbsFile-                                    return $ return fp'-                                else testFPs fps-                    testFPs fps0-            epath <- loop $ eoPath eo-            () <- atomicModifyIORef (eoExeCache eo) $ \m' ->-                (Map.insert name epath m', ())-            return epath-    return $ either throwM return epath---- | Reset the executable cache.-resetExeCache :: MonadIO m => EnvOverride -> m ()-resetExeCache eo = liftIO (atomicModifyIORef (eoExeCache eo) (const mempty))---- | Load up an 'EnvOverride' from the standard environment.-getEnvOverride :: MonadIO m => Platform -> m EnvOverride-getEnvOverride platform =-    liftIO $-    getEnvironment >>=-          mkEnvOverride platform-        . Map.fromList . map (T.pack *** T.pack)--newtype InvalidPathException = PathsInvalidInPath [FilePath]-    deriving Typeable--instance Exception InvalidPathException-instance Show InvalidPathException where-    show (PathsInvalidInPath paths) = unlines $-        [ "Would need to add some paths to the PATH environment variable \-          \to continue, but they would be invalid because they contain a "-          ++ show FP.searchPathSeparator ++ "."-        , "Please fix the following paths and try again:"-        ] ++ paths---- | Augment the PATH environment variable with the given extra paths.-augmentPath :: MonadThrow m => [Path Abs Dir] -> Maybe Text -> m Text-augmentPath dirs mpath =-  do let illegal = filter (FP.searchPathSeparator `elem`) (map toFilePath dirs)-     unless (null illegal) (throwM $ PathsInvalidInPath illegal)-     return $ T.intercalate (T.singleton FP.searchPathSeparator)-            $ map (T.pack . toFilePathNoTrailingSep) dirs-            ++ maybeToList mpath---- | Apply 'augmentPath' on the PATH value in the given Map.-augmentPathMap :: MonadThrow m => [Path Abs Dir] -> Map Text Text-                               -> m (Map Text Text)-augmentPathMap dirs origEnv =-  do path <- augmentPath dirs mpath-     return $ Map.insert "PATH" path origEnv-  where-    mpath = Map.lookup "PATH" origEnv
− src/System/Process/Run.hs
@@ -1,138 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RecordWildCards #-}--- | Run sub-processes.--module System.Process.Run-    (runCmd-    ,runCmd'-    ,callProcess-    ,callProcess'-    ,callProcessInheritStderrStdout-    ,callProcessObserveStdout-    ,createProcess'-    ,ProcessExitedUnsuccessfully-    ,Cmd(..)-    )-    where--import           Stack.Prelude-import           Data.Conduit.Process hiding (callProcess)-import qualified Data.Text as T-import           System.Exit (exitWith, ExitCode (..))-import           System.IO (hGetLine)-import qualified System.Process-import           System.Process.Log-import           System.Process.Read---- | Cmd holds common infos needed to running a process in most cases-data Cmd = Cmd-  { cmdDirectoryToRunIn :: Maybe (Path Abs Dir) -- ^ directory to run in-  , cmdCommandToRun :: FilePath -- ^ command to run-  , cmdEnvOverride :: EnvOverride-  , cmdCommandLineArguments :: [String] -- ^ command line arguments-  }---- | Run the given command in the given directory, inheriting stdout and stderr.------ If it exits with anything but success, prints an error--- and then calls 'exitWith' to exit the program.-runCmd :: forall (m :: * -> *).-         (MonadLogger m, MonadUnliftIO m)-      => Cmd-      -> Maybe Text  -- ^ optional additional error message-      -> m ()-runCmd = runCmd' id--runCmd' :: forall (m :: * -> *).-         (MonadLogger m, MonadUnliftIO m)-      => (CreateProcess -> CreateProcess)-      -> Cmd-      -> Maybe Text  -- ^ optional additional error message-      -> m ()-runCmd' modCP cmd@Cmd{..} mbErrMsg = do-    result <- try (callProcess' modCP cmd)-    case result of-        Left (ProcessExitedUnsuccessfully _ ec) -> do-            logError $-                T.pack $-                concat $-                    [ "Exit code "-                    , show ec-                    , " while running "-                    , show (cmdCommandToRun : cmdCommandLineArguments)-                    ] ++ (case cmdDirectoryToRunIn of-                            Nothing -> []-                            Just mbDir -> [" in ", toFilePath mbDir]-                            )-            forM_ mbErrMsg logError-            liftIO (exitWith ec)-        Right () -> return ()---- | Like 'System.Process.callProcess', but takes an optional working directory and--- environment override, and throws 'ProcessExitedUnsuccessfully' if the--- process exits unsuccessfully and a 'ReadProcessException' if the executable is not found.------ Inherits stdout and stderr.-callProcess :: (MonadIO m, MonadLogger m) => Cmd -> m ()-callProcess = callProcess' id---- | Like 'System.Process.callProcess', but takes an optional working directory and--- environment override, and throws 'ProcessExitedUnsuccessfully' if the--- process exits unsuccessfully and a 'ReadProcessException' if the executable is not found.------ Inherits stdout and stderr.-callProcess' :: (MonadIO m, MonadLogger m)-             => (CreateProcess -> CreateProcess) -> Cmd -> m ()-callProcess' modCP cmd = do-    c <- liftM modCP (cmdToCreateProcess cmd)-    logCreateProcess c-    liftIO $ do-        (_, _, _, p) <- System.Process.createProcess c-        exit_code <- waitForProcess p-        case exit_code of-            ExitSuccess   -> return ()-            ExitFailure _ -> throwM (ProcessExitedUnsuccessfully c exit_code)--callProcessInheritStderrStdout :: (MonadIO m, MonadLogger m) => Cmd -> m ()-callProcessInheritStderrStdout cmd = do-    let inheritOutput cp = cp { std_in = CreatePipe, std_out = Inherit, std_err = Inherit }-    callProcess' inheritOutput cmd--callProcessObserveStdout :: (MonadIO m, MonadLogger m) => Cmd -> m String-callProcessObserveStdout cmd = do-    c <- liftM modCP (cmdToCreateProcess cmd)-    logCreateProcess c-    liftIO $ do-        (_, Just hStdout, _, p) <- System.Process.createProcess c-        hSetBuffering hStdout NoBuffering-        exit_code <- waitForProcess p-        case exit_code of-            ExitSuccess   -> hGetLine hStdout-            ExitFailure _ -> throwM (ProcessExitedUnsuccessfully c exit_code)-  where-    modCP c = c { std_in = CreatePipe, std_out = CreatePipe, std_err = Inherit }---- | Like 'System.Process.Internal.createProcess_', but taking a 'Cmd'.--- Note that the 'Handle's provided by 'UseHandle' are not closed--- automatically.-createProcess' :: (MonadIO m, MonadLogger m)-               => String-               -> (CreateProcess -> CreateProcess)-               -> Cmd-               -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)-createProcess' tag modCP cmd = do-    c <- liftM modCP (cmdToCreateProcess cmd)-    logCreateProcess c-    liftIO $ System.Process.createProcess_ tag c---- Throws a 'ReadProcessException' if process is not found.-cmdToCreateProcess :: MonadIO m => Cmd -> m CreateProcess-cmdToCreateProcess (Cmd wd cmd0 menv args) = do-    cmd <- preProcess wd menv cmd0-    return $ (proc cmd args) { delegate_ctlc = True-                             , cwd = fmap toFilePath wd-                             , env = envHelper menv }
src/Text/PrettyPrint/Leijen/Extended.hs view
@@ -124,7 +124,7 @@ import qualified Data.Text.IO as T import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Builder as LTB-import Stack.Prelude+import Stack.Prelude hiding (Display (..)) import System.Console.ANSI (Color(..), ColorIntensity(..), ConsoleLayer(..), ConsoleIntensity(..), SGR(..), setSGRCode, hSupportsANSI) import qualified Text.PrettyPrint.Annotated.Leijen as P import Text.PrettyPrint.Annotated.Leijen hiding ((<>), display)@@ -137,8 +137,10 @@ -- Perhaps it can still have native string support, by adding a type -- parameter to Doc? +instance Semigroup (Doc a) where+    (<>) = (P.<>) instance Monoid (Doc a) where-    mappend = (P.<>)+    mappend = (<>)     mempty = empty  --------------------------------------------------------------------------------@@ -162,7 +164,7 @@ type AnsiDoc = Doc AnsiAnn  newtype AnsiAnn = AnsiAnn [SGR]-    deriving (Eq, Show, Monoid)+    deriving (Eq, Show, Semigroup, Monoid)  class HasAnsiAnn a where     getAnsiAnn :: a -> AnsiAnn
src/main/Main.hs view
@@ -18,7 +18,7 @@ #ifndef HIDE_DEP_VERSIONS import qualified Build_stack #endif-import           Stack.Prelude+import           Stack.Prelude hiding (Display (..)) import           Control.Monad.Reader (local) import           Control.Monad.Trans.Except (ExceptT) import           Control.Monad.Writer.Lazy (Writer)@@ -30,15 +30,14 @@ import qualified Data.Map.Strict as Map import qualified Data.Text as T import           Data.Version (showVersion)-import           System.Process.Read+import           RIO.Process #ifdef USE_GIT_INFO import           Development.GitRev (gitCommitCount, gitHash) #endif-import           Distribution.System (buildArch, buildPlatform)+import           Distribution.System (buildArch) import qualified Distribution.Text as Cabal (display) import           Distribution.Version (mkVersion') import           GHC.IO.Encoding (mkTextEncoding, textEncodingName)-import           Lens.Micro import           Options.Applicative import           Options.Applicative.Help (errorHelp, stringChunk, vcatChunks) import           Options.Applicative.Builder.Extra@@ -59,13 +58,13 @@ import           Stack.Coverage import qualified Stack.Docker as Docker import           Stack.Dot-import           Stack.Exec import           Stack.GhcPkg (findGhcPkgField) import qualified Stack.Nix as Nix import           Stack.Fetch import           Stack.FileWatch import           Stack.Ghci import           Stack.Hoogle+import           Stack.Ls import qualified Stack.IDE as IDE import qualified Stack.Image as Image import           Stack.Init@@ -105,7 +104,7 @@ import           System.Environment (getProgName, getArgs, withArgs) import           System.Exit import           System.FilePath (isValid, pathSeparator)-import           System.IO (stderr, stdin, stdout, BufferMode(..), hPutStrLn, hGetEncoding, hSetEncoding)+import           System.IO (stderr, stdin, stdout, BufferMode(..), hPutStrLn, hPrint, hGetEncoding, hSetEncoding)  -- | Change the character encoding of the given Handle to transliterate -- on unsupported characters instead of throwing an exception@@ -150,10 +149,10 @@ #else     warningString = unlines       [ ""-      , "Warning: this is an unsupported build that may have been built with different"-      , "versions of dependencies and GHC than the officially release binaries, and"-      , "therefore may not behave identically.  If you encounter problems, please try"-      , "the latest official build by running 'stack upgrade --force-download'."+      , "Warning: this is an unsupported build that may use different versions of"+      , "dependencies and GHC than the officially released binaries, and therefore may"+      , "not behave identically.  If you encounter problems, please try the latest"+      , "official build by running 'stack upgrade --force-download'."       ] #endif @@ -198,7 +197,7 @@           case fromException e of               Just ec -> exitWith ec               Nothing -> do-                  printExceptionStderr e+                  hPrint stderr e                   exitFailure  -- Vertically combine only the error component of the first argument with the@@ -299,10 +298,16 @@                     "Print out handy path information"                     pathCmd                     Stack.Path.pathParser+        addCommand' "ls"+                    "List command. (Supports snapshots and dependencies)"+                    lsCmd+                    lsParser         addCommand' "unpack"                     "Unpack one or more packages locally"                     unpackCmd-                    (some $ strArgument $ metavar "PACKAGE")+                    ((,) <$> some (strArgument $ metavar "PACKAGE")+                         <*> optional (textOption $ long "to" <>+                                         help "Optional path to unpack the package into (will unpack into subdirectory)"))         addCommand' "update"                     "Update the package index"                     updateCmd@@ -333,7 +338,7 @@                     ("Run hoogle, the Haskell API search engine. Use 'stack exec' syntax " ++                      "to pass Hoogle arguments, e.g. stack hoogle -- --count=20")                     hoogleCmd-                    ((,,) <$> many (strArgument (metavar "ARG"))+                    ((,,,) <$> many (strArgument (metavar "ARG"))                           <*> boolFlags                                   True                                   "setup"@@ -341,7 +346,10 @@                                   idm                           <*> switch                                   (long "rebuild" <>-                                   help "Rebuild the hoogle database"))+                                   help "Rebuild the hoogle database")+                          <*> switch+                                  (long "server" <>+                                   help "Start local Hoogle server"))         )        -- These are the only commands allowed in interpreter mode as well@@ -381,7 +389,7 @@                     cleanOptsParser         addCommand' "list-dependencies"                     "List the dependencies"-                    listDependenciesCmd+                    (listDependenciesCmd True)                     listDepsOptsParser         addCommand' "query"                     "Query general build information (experimental)"@@ -502,12 +510,11 @@     else do       mExternalExec <- D.findExecutable cmd       case mExternalExec of-        Just ex -> do-          menv <- getEnvOverride buildPlatform+        Just ex -> withProcessContextNoLogging $ do           -- TODO show the command in verbose mode           -- hPutStrLn stderr $ unwords $           --   ["Running", "[" ++ ex, unwords (tail args) ++ "]"]-          _ <- runNoLogging (exec menv ex (tail args))+          _ <- exec ex (tail args)           return f         Nothing -> return $ fmap (vcatErrorHelp (noSuchCmd cmd)) f   where@@ -563,8 +570,12 @@       progName <- getProgName       iargs <- getInterpreterArgs path       let parseCmdLine = commandLineHandler currentDir progName True-          separator = if "--" `elem` iargs then [] else ["--"]-          cmdArgs = stackArgs ++ iargs ++ separator ++ path : fileArgs+          -- Implicit file arguments are put before other arguments that+          -- occur after "--". See #3658+          cmdArgs = stackArgs ++ case break (== "--") iargs of+            (beforeSep, []) -> beforeSep ++ ["--"] ++ [path] ++ fileArgs+            (beforeSep, optSep : afterSep) ->+              beforeSep ++ [optSep] ++ [path] ++ fileArgs ++ afterSep        -- TODO show the command in verbose mode        -- hPutStrLn stderr $ unwords $        --   ["Running", "[" ++ progName, unwords cmdArgs ++ "]"]@@ -578,7 +589,7 @@ setupCmd sco@SetupCmdOpts{..} go@GlobalOpts{..} = loadConfigWithOpts go $ \lc -> do   when (isJust scoUpgradeCabal && nixEnable (configNix (lcConfig lc))) $ do     throwIO UpgradeCabalUnusable-  withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk -> do+  withUserFileLock go (view stackRootL lc) $ \lk -> do     let getCompilerVersion = loadCompilerVersion go lc     runRIO (lcConfig lc) $       Docker.reexecWithOptionalContainer@@ -605,8 +616,8 @@   -- See issues #2010 and #3468 for why "stack clean --full" is not used   -- within docker.   case opts of-    CleanFull{} -> withBuildConfigAndLock go (const (clean opts))-    CleanShallow{} -> withBuildConfigAndLockNoDocker go (const (clean opts))+    CleanFull{} -> withBuildConfigAndLockNoDocker go (const (clean opts))+    CleanShallow{} -> withBuildConfigAndLock go (const (clean opts))  -- | Helper for build and install commands buildCmd :: BuildOptsCLI -> GlobalOpts -> IO ()@@ -641,10 +652,11 @@       ]  -- | Unpack packages to the filesystem-unpackCmd :: [String] -> GlobalOpts -> IO ()-unpackCmd names go = withConfigAndLock go $ do+unpackCmd :: ([String], Maybe Text) -> GlobalOpts -> IO ()+unpackCmd (names, Nothing) go = unpackCmd (names, Just ".") go+unpackCmd (names, Just dstPath) go = withConfigAndLock go $ do     mSnapshotDef <- mapM (makeConcreteResolver Nothing >=> loadResolver) (globalResolver go)-    Stack.Fetch.unpackPackages mSnapshotDef "." names+    Stack.Fetch.unpackPackages mSnapshotDef (T.unpack dstPath) names  -- | Update the package index updateCmd :: () -> GlobalOpts -> IO ()@@ -766,7 +778,7 @@                 (ExecGhc, args) -> return ("ghc", args)                 (ExecRunGhc, args) -> return ("runghc", args)           loadConfigWithOpts go $ \lc ->-            withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk -> do+            withUserFileLock go (view stackRootL lc) $ \lk -> do               let getCompilerVersion = loadCompilerVersion go lc               runRIO (lcConfig lc) $                 Docker.reexecWithOptionalContainer@@ -775,42 +787,43 @@                     (Just $ munlockFile lk)                     (runRIO (lcConfig lc) $ do                         config <- view configL-                        menv <- liftIO $ configEnvOverride config plainEnvSettings-                        Nix.reexecWithOptionalShell+                        menv <- liftIO $ configProcessContextSettings config plainEnvSettings+                        withProcessContext menv $ Nix.reexecWithOptionalShell                             (lcProjectRoot lc)                             getCompilerVersion                             (runRIO (lcConfig lc) $-                                exec menv cmd args))+                                exec cmd args))                     Nothing                     Nothing -- Unlocked already above.         ExecOptsEmbellished {..} ->             withBuildConfigAndLock go $ \lk -> do-                let targets = concatMap words eoPackages-                unless (null targets) $-                    Stack.Build.build (const $ return ()) lk defaultBuildOptsCLI-                        { boptsCLITargets = map T.pack targets-                        }+              let targets = concatMap words eoPackages+              unless (null targets) $+                  Stack.Build.build (const $ return ()) lk defaultBuildOptsCLI+                      { boptsCLITargets = map T.pack targets+                      } -                config <- view configL-                menv <- liftIO $ configEnvOverride config eoEnvSettings+              config <- view configL+              menv <- liftIO $ configProcessContextSettings config eoEnvSettings+              withProcessContext menv $ do                 -- Add RTS options to arguments                 let argsWithRts args = if null eoRtsOptions                             then args :: [String]                             else args ++ ["+RTS"] ++ eoRtsOptions ++ ["-RTS"]                 (cmd, args) <- case (eoCmd, argsWithRts eoArgs) of                     (ExecCmd cmd, args) -> return (cmd, args)-                    (ExecGhc, args) -> getGhcCmd "" menv eoPackages args+                    (ExecGhc, args) -> getGhcCmd "" eoPackages args                     -- NOTE: this won't currently work for GHCJS, because it doesn't have                     -- a runghcjs binary. It probably will someday, though.                     (ExecRunGhc, args) ->-                        getGhcCmd "run" menv eoPackages args+                        getGhcCmd "run" eoPackages args                 munlockFile lk -- Unlock before transferring control away. -                runWithPath eoCwd $ exec menv cmd args+                runWithPath eoCwd $ exec cmd args   where       -- return the package-id of the first package in GHC_PACKAGE_PATH-      getPkgId menv wc name = do-          mId <- findGhcPkgField menv wc [] name "id"+      getPkgId wc name = do+          mId <- findGhcPkgField wc [] name "id"           case mId of               Just i -> return (head $ words (T.unpack i))               -- should never happen as we have already installed the packages@@ -818,13 +831,12 @@                   hPutStrLn stderr ("Could not find package id of package " ++ name)                   exitFailure -      getPkgOpts menv wc pkgs = do-          ids <- mapM (getPkgId menv wc) pkgs-          return $ map ("-package-id=" ++) ids+      getPkgOpts wc pkgs =+          map ("-package-id=" ++) <$> mapM (getPkgId wc) pkgs -      getGhcCmd prefix menv pkgs args = do+      getGhcCmd prefix pkgs args = do           wc <- view $ actualCompilerVersionL.whichCompilerL-          pkgopts <- getPkgOpts menv wc pkgs+          pkgopts <- getPkgOpts wc pkgs           return (prefix ++ compilerExeName wc, pkgopts ++ args)        runWithPath :: Maybe FilePath -> RIO EnvConfig () -> RIO EnvConfig ()@@ -872,7 +884,7 @@ dockerPullCmd _ go@GlobalOpts{..} =     loadConfigWithOpts go $ \lc ->     -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/?-    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->+    withUserFileLock go (view stackRootL lc) $ \_ ->      runRIO (lcConfig lc) $        Docker.preventInContainer Docker.pull @@ -881,7 +893,7 @@ dockerResetCmd keepHome go@GlobalOpts{..} =     loadConfigWithOpts go $ \lc ->     -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/?-    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->+    withUserFileLock go (view stackRootL lc) $ \_ ->       runRIO (lcConfig lc) $         Docker.preventInContainer $ Docker.reset (lcProjectRoot lc) keepHome @@ -890,7 +902,7 @@ dockerCleanupCmd cleanupOpts go@GlobalOpts{..} =     loadConfigWithOpts go $ \lc ->     -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/?-    withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->+    withUserFileLock go (view stackRootL lc) $ \_ ->      runRIO (lcConfig lc) $         Docker.preventInContainer $             Docker.cleanup cleanupOpts@@ -928,7 +940,9 @@ newCmd (newOpts,initOpts) go@GlobalOpts{..} =     withMiniConfigAndLock go $ do         dir <- new newOpts (forceOverwrite initOpts)-        initProject IsNewCmd dir initOpts globalResolver+        exists <- doesFileExist $ dir </> stackDotYaml+        when (forceOverwrite initOpts || not exists) $+            initProject IsNewCmd dir initOpts globalResolver  -- | List the available templates. templatesCmd :: () -> GlobalOpts -> IO ()@@ -944,19 +958,6 @@ -- | Visualize dependencies dotCmd :: DotOpts -> GlobalOpts -> IO () dotCmd dotOpts go = withBuildConfigDot dotOpts go $ dot dotOpts---- | List the dependencies-listDependenciesCmd :: ListDepsOpts -> GlobalOpts -> IO ()-listDependenciesCmd opts go = withBuildConfigDot (listDepsDotOpts opts) go $ listDependencies opts---- Plumbing for --test and --bench flags-withBuildConfigDot :: DotOpts -> GlobalOpts -> RIO EnvConfig () -> IO ()-withBuildConfigDot opts go f = withBuildConfig go' f-  where-    go' =-        (if dotTestTargets opts then set (globalOptsBuildOptsMonoidL.buildOptsMonoidTestsL) (Just True) else id) $-        (if dotBenchTargets opts then set (globalOptsBuildOptsMonoidL.buildOptsMonoidBenchmarksL) (Just True) else id)-        go  -- | Query build information queryCmd :: [String] -> GlobalOpts -> IO ()
src/test/Network/HTTP/Download/VerifiedSpec.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE NoImplicitPrelude #-} module Network.HTTP.Download.VerifiedSpec where -import           Control.Monad.Logger           (runStdoutLoggingT) import           Control.Retry                  (limitRetries) import           Crypto.Hash import           Network.HTTP.Client.Conduit@@ -67,8 +66,7 @@   let exampleProgressHook _ = return ()    describe "verifiedDownload" $ do-    let run func = runStdoutLoggingT-                 $ withRunner LevelError True True ColorNever Nothing False+    let run func = withRunner LevelError True True ColorNever Nothing False                  $ \runner -> runRIO runner func     -- Preconditions:     -- * the exampleReq server is running
src/test/Stack/Build/TargetSpec.hs view
@@ -6,7 +6,7 @@ import qualified Data.Text           as T import           Stack.Build.Target import           Stack.Prelude-import           Stack.Types.Config+import           Stack.Types.NamedComponent import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version
src/test/Stack/ConfigSpec.hs view
@@ -35,6 +35,7 @@   "  prefetch: true\n" ++   "  force-dirty: true\n" ++   "  keep-going: true\n" +++  "  keep-tmp-files: true\n" ++   "  test: true\n" ++   "  test-arguments:\n" ++   "    rerun-tests: true\n" ++@@ -117,6 +118,7 @@       boptsInstallExes `shouldBe` True       boptsPreFetch `shouldBe` True       boptsKeepGoing `shouldBe` Just True+      boptsKeepTmpFiles `shouldBe` Just True       boptsForceDirty `shouldBe` True       boptsTests `shouldBe` True       boptsTestOpts `shouldBe` TestOpts {toRerunTests = True
src/test/Stack/DotSpec.hs view
@@ -20,7 +20,7 @@ import           Stack.Dot  dummyPayload :: DotPayload-dummyPayload = DotPayload (parseVersionFromString "0.0.0.0") (Just BSD3)+dummyPayload = DotPayload (parseVersionFromString "0.0.0.0") (Just (Right BSD3))  spec :: Spec spec = do
src/test/Stack/Ghci/ScriptSpec.hs view
@@ -6,7 +6,6 @@ -- | Test suite for the GhciScript DSL module Stack.Ghci.ScriptSpec where -import           Data.Monoid import qualified Data.Set as S import           Distribution.ModuleName import           Test.Hspec
src/test/Stack/NixSpec.hs view
@@ -1,14 +1,16 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RecordWildCards  #-}-{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings #-} module Stack.NixSpec where +import Data.Maybe (fromJust) import Options.Applicative import Path+import Prelude (writeFile) import Stack.Config-import Stack.Options.NixParser import Stack.Config.Nix+import Stack.Constants+import Stack.Options.NixParser import Stack.Prelude import Stack.Types.Compiler import Stack.Types.Config@@ -18,8 +20,6 @@ import System.Directory import System.Environment import Test.Hspec-import Prelude (writeFile)-import Data.Maybe (fromJust)  sampleConfigNixEnabled :: String sampleConfigNixEnabled =@@ -37,9 +37,6 @@   "nix:\n" ++   "   enable: False" -stackDotYaml :: Path Rel File-stackDotYaml = $(mkRelFile "stack.yaml")- setup :: IO () setup = unsetEnv "STACK_YAML" @@ -62,6 +59,7 @@         (info (nixOptsParser False) mempty)         cmdLineOpts       parseOpts cmdLineOpts = mempty { configMonoidNixOpts = parseNixOpts cmdLineOpts }+  let trueOnNonWindows = not osIsWindows   describe "nix disabled in config file" $     around_ (withStackDotYaml sampleConfigNixDisabled) $ do       it "sees that the nix shell is not enabled" $ do@@ -70,11 +68,11 @@       describe "--nix given on command line" $         it "sees that the nix shell is enabled" $ do           lc <- loadConfig' (parseOpts ["--nix"])-          nixEnable (configNix $ lcConfig lc) `shouldBe` True+          nixEnable (configNix $ lcConfig lc) `shouldBe` trueOnNonWindows       describe "--nix-pure given on command line" $         it "sees that the nix shell is enabled" $ do           lc <- loadConfig' (parseOpts ["--nix-pure"])-          nixEnable (configNix $ lcConfig lc) `shouldBe` True+          nixEnable (configNix $ lcConfig lc) `shouldBe` trueOnNonWindows       describe "--no-nix given on command line" $         it "sees that the nix shell is not enabled" $ do           lc <- loadConfig' (parseOpts ["--no-nix"])@@ -87,7 +85,7 @@     around_ (withStackDotYaml sampleConfigNixEnabled) $ do       it "sees that the nix shell is enabled" $ do         lc <- loadConfig' mempty-        nixEnable (configNix $ lcConfig lc) `shouldBe` True+        nixEnable (configNix $ lcConfig lc) `shouldBe` trueOnNonWindows       describe "--no-nix given on command line" $         it "sees that the nix shell is not enabled" $ do           lc <- loadConfig' (parseOpts ["--no-nix"])@@ -95,11 +93,11 @@       describe "--nix-pure given on command line" $         it "sees that the nix shell is enabled" $ do           lc <- loadConfig' (parseOpts ["--nix-pure"])-          nixEnable (configNix $ lcConfig lc) `shouldBe` True+          nixEnable (configNix $ lcConfig lc) `shouldBe` trueOnNonWindows       describe "--no-nix-pure given on command line" $         it "sees that the nix shell is enabled" $ do           lc <- loadConfig' (parseOpts ["--no-nix-pure"])-          nixEnable (configNix $ lcConfig lc) `shouldBe` True+          nixEnable (configNix $ lcConfig lc) `shouldBe` trueOnNonWindows       it "sees that the only package asked for is glpk and asks for the correct GHC derivation" $ do         lc <- loadConfig' mempty         nixPackages (configNix $ lcConfig lc) `shouldBe` ["glpk"]
src/test/Stack/PackageDumpSpec.hs view
@@ -5,12 +5,10 @@ module Stack.PackageDumpSpec where  import           Data.Conduit-import qualified Data.Conduit.Binary           as CB import qualified Data.Conduit.List             as CL import           Data.Conduit.Text             (decodeUtf8) import qualified Data.Map                      as Map import qualified Data.Set                      as Set-import           Distribution.System           (buildPlatform) import           Distribution.License          (License(..)) import           Stack.PackageDump import           Stack.Prelude@@ -19,7 +17,7 @@ import           Stack.Types.PackageIdentifier import           Stack.Types.PackageName import           Stack.Types.Version-import           System.Process.Read+import           RIO.Process import           Test.Hspec import           Test.Hspec.QuickCheck @@ -30,7 +28,7 @@ spec = do     describe "eachSection" $ do         let test name content expected = it name $ do-                actual <- yield content $$ eachSection CL.consume =$ CL.consume+                actual <- runConduit $ yield content .| eachSection CL.consume .| CL.consume                 actual `shouldBe` expected         test             "unix line endings"@@ -56,7 +54,7 @@                 , "   val4b"                 ]             sink k = fmap (k, ) CL.consume-        actual <- mapM_ yield bss $$ eachPair sink =$ CL.consume+        actual <- runConduit $ mapM_ yield bss .| eachPair sink .| CL.consume         actual `shouldBe`             [ ("key1", ["val1"])             , ("key2", ["val2a", "val2b"])@@ -66,11 +64,13 @@      describe "conduitDumpPackage" $ do         it "ghc 7.8" $ do-            haskell2010:_ <- runResourceT-                $ CB.sourceFile "test/package-dump/ghc-7.8.txt"-              =$= decodeUtf8-               $$ conduitDumpPackage-               =$ CL.consume+            haskell2010:_ <-+                  withSourceFile "test/package-dump/ghc-7.8.txt" $ \src ->+                  runConduit+                $ src+               .| decodeUtf8+               .| conduitDumpPackage+               .| CL.consume             ghcPkgId <- parseGhcPkgId "haskell2010-1.1.2.0-05c8dd51009e08c6371c82972d40f55a"             packageIdent <- parsePackageIdentifier "haskell2010-1.1.2.0"             depends <- mapM parseGhcPkgId@@ -81,6 +81,7 @@             haskell2010 { dpExposedModules = [] } `shouldBe` DumpPackage                 { dpGhcPkgId = ghcPkgId                 , dpPackageIdent = packageIdent+                , dpParentLibIdent = Nothing                 , dpLicense = Just BSD3                 , dpLibDirs = ["/opt/ghc/7.8.4/lib/ghc-7.8.4/haskell2010-1.1.2.0"]                 , dpDepends = depends@@ -96,11 +97,13 @@                 }          it "ghc 7.10" $ do-            haskell2010:_ <- runResourceT-                $ CB.sourceFile "test/package-dump/ghc-7.10.txt"-              =$= decodeUtf8-               $$ conduitDumpPackage-               =$ CL.consume+            haskell2010:_ <-+                  withSourceFile "test/package-dump/ghc-7.10.txt" $ \src ->+                  runConduit+                $ src+               .| decodeUtf8+               .| conduitDumpPackage+               .| CL.consume             ghcPkgId <- parseGhcPkgId "ghc-7.10.1-325809317787a897b7a97d646ceaa3a3"             pkgIdent <- parsePackageIdentifier "ghc-7.10.1"             depends <- mapM parseGhcPkgId@@ -122,6 +125,7 @@             haskell2010 { dpExposedModules = [] } `shouldBe` DumpPackage                 { dpGhcPkgId = ghcPkgId                 , dpPackageIdent = pkgIdent+                , dpParentLibIdent = Nothing                 , dpLicense = Just BSD3                 , dpLibDirs = ["/opt/ghc/7.10.1/lib/ghc-7.10.1/ghc_EMlWrQ42XY0BNVbSrKixqY"]                 , dpHaddockInterfaces = ["/opt/ghc/7.10.1/share/doc/ghc/html/libraries/ghc-7.10.1/ghc.haddock"]@@ -136,11 +140,13 @@                 , dpExposedModules = []                 }         it "ghc 7.8.4 (osx)" $ do-            hmatrix:_ <- runResourceT-                $ CB.sourceFile "test/package-dump/ghc-7.8.4-osx.txt"-              =$= decodeUtf8-               $$ conduitDumpPackage-               =$ CL.consume+            hmatrix:_ <-+                  withSourceFile "test/package-dump/ghc-7.8.4-osx.txt" $ \src ->+                  runConduit+                $ src+               .| decodeUtf8+               .| conduitDumpPackage+               .| CL.consume             ghcPkgId <- parseGhcPkgId "hmatrix-0.16.1.5-12d5d21f26aa98774cdd8edbc343fbfe"             pkgId <- parsePackageIdentifier "hmatrix-0.16.1.5"             depends <- mapM parseGhcPkgId@@ -156,6 +162,7 @@             hmatrix `shouldBe` DumpPackage                 { dpGhcPkgId = ghcPkgId                 , dpPackageIdent = pkgId+                , dpParentLibIdent = Nothing                 , dpLicense = Just BSD3                 , dpLibDirs =                       [ "/Users/alexbiehl/.stack/snapshots/x86_64-osx/lts-2.13/7.8.4/lib/x86_64-osx-ghc-7.8.4/hmatrix-0.16.1.5"@@ -174,11 +181,13 @@                 , dpExposedModules = ["Data.Packed","Data.Packed.Vector","Data.Packed.Matrix","Data.Packed.Foreign","Data.Packed.ST","Data.Packed.Development","Numeric.LinearAlgebra","Numeric.LinearAlgebra.LAPACK","Numeric.LinearAlgebra.Algorithms","Numeric.Container","Numeric.LinearAlgebra.Util","Numeric.LinearAlgebra.Devel","Numeric.LinearAlgebra.Data","Numeric.LinearAlgebra.HMatrix","Numeric.LinearAlgebra.Static"]                 }         it "ghc HEAD" $ do-          ghcBoot:_ <- runResourceT-              $ CB.sourceFile "test/package-dump/ghc-head.txt"-            =$= decodeUtf8-             $$ conduitDumpPackage-             =$ CL.consume+          ghcBoot:_ <-+                withSourceFile "test/package-dump/ghc-head.txt" $ \src ->+                runConduit+              $ src+             .| decodeUtf8+             .| conduitDumpPackage+             .| CL.consume           ghcPkgId <- parseGhcPkgId "ghc-boot-0.0.0.0"           pkgId <- parsePackageIdentifier "ghc-boot-0.0.0.0"           depends <- mapM parseGhcPkgId@@ -191,6 +200,7 @@           ghcBoot `shouldBe` DumpPackage             { dpGhcPkgId = ghcPkgId             , dpPackageIdent = pkgId+            , dpParentLibIdent = Nothing             , dpLicense = Just BSD3             , dpLibDirs =                   ["/opt/ghc/head/lib/ghc-7.11.20151213/ghc-boot-0.0.0.0"]@@ -207,32 +217,29 @@             }  -    it "ghcPkgDump + addProfiling + addHaddock" $ (id :: IO () -> IO ()) $ runNoLogging $ do-        menv' <- getEnvOverride buildPlatform-        menv <- mkEnvOverride buildPlatform $ Map.delete "GHC_PACKAGE_PATH" $ unEnvOverride menv'+    it "ghcPkgDump + addProfiling + addHaddock" $ runEnvNoLogging $ do         icache <- newInstalledCache-        ghcPkgDump menv Ghc []+        ghcPkgDump Ghc []             $  conduitDumpPackage-            =$ addProfiling icache-            =$ addHaddock icache-            =$ fakeAddSymbols-            =$ CL.sinkNull+            .| addProfiling icache+            .| addHaddock icache+            .| fakeAddSymbols+            .| CL.sinkNull -    it "sinkMatching" $ do-        menv' <- getEnvOverride buildPlatform-        menv <- mkEnvOverride buildPlatform $ Map.delete "GHC_PACKAGE_PATH" $ unEnvOverride menv'+    it "sinkMatching" $ runEnvNoLogging $ do         icache <- newInstalledCache-        m <- runNoLogging $ ghcPkgDump menv Ghc []+        m <- ghcPkgDump Ghc []             $  conduitDumpPackage-            =$ addProfiling icache-            =$ addHaddock icache-            =$ fakeAddSymbols-            =$ sinkMatching False False False (Map.singleton $(mkPackageName "transformers") $(mkVersion "0.0.0.0.0.0.1"))+            .| addProfiling icache+            .| addHaddock icache+            .| fakeAddSymbols+            .| sinkMatching False False False (Map.singleton $(mkPackageName "transformers") $(mkVersion "0.0.0.0.0.0.1"))         case Map.lookup $(mkPackageName "base") m of             Nothing -> error "base not present"             Just _ -> return ()-        Map.lookup $(mkPackageName "transformers") m `shouldBe` Nothing-        Map.lookup $(mkPackageName "ghc") m `shouldBe` Nothing+        liftIO $ do+          Map.lookup $(mkPackageName "transformers") m `shouldBe` Nothing+          Map.lookup $(mkPackageName "ghc") m `shouldBe` Nothing      describe "pruneDeps" $ do         it "sanity check" $ do@@ -276,5 +283,11 @@             Just deps -> Set.null $ Set.difference (Set.fromList deps) allIds  -- addSymbols can't be reasonably tested like this-fakeAddSymbols :: Monad m => Conduit (DumpPackage a b c) m (DumpPackage a b Bool)+fakeAddSymbols :: Monad m => ConduitM (DumpPackage a b c) (DumpPackage a b Bool) m () fakeAddSymbols = CL.map (\dp -> dp { dpSymbols = False })++runEnvNoLogging :: RIO LoggedProcessContext a -> IO a+runEnvNoLogging inner = do+  envVars <- view envVarsL <$> mkDefaultProcessContext+  menv <- mkProcessContext $ Map.delete "GHC_PACKAGE_PATH" envVars+  runRIO (LoggedProcessContext menv mempty) inner
+ src/test/Stack/Types/BuildPlanSpec.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE OverloadedStrings #-}++module Stack.Types.BuildPlanSpec where++import           Data.Aeson.Extended (WithJSONWarnings(..))+import           Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as S8+import           Data.Yaml (decode)+import           Stack.Types.BuildPlan+import           Test.Hspec++spec :: Spec+spec =+  describe "PackageLocation" $ do+    describe "Archive" $ do+      describe "github" $ do+        let decode' :: ByteString -> Maybe (WithJSONWarnings (PackageLocation Subdirs))+            decode' = decode++        it "'github' and 'commit' keys" $ do+          let contents :: ByteString+              contents =+                S8.pack+                  (unlines+                    [ "github: oink/town"+                    , "commit: abc123"+                    ])+          let expected :: PackageLocation Subdirs+              expected =+                PLArchive Archive+                  { archiveUrl = "https://github.com/oink/town/archive/abc123.tar.gz"+                  , archiveSubdirs = DefaultSubdirs+                  , archiveHash = Nothing+                  }+          decode' contents `shouldBe` Just (WithJSONWarnings expected [])++        it "'github', 'commit', and 'subdirs' keys" $ do+          let contents :: ByteString+              contents =+                S8.pack+                  (unlines+                    [ "github: oink/town"+                    , "commit: abc123"+                    , "subdirs:"+                    , "  - foo"+                    ])+          let expected :: PackageLocation Subdirs+              expected =+                PLArchive Archive+                  { archiveUrl = "https://github.com/oink/town/archive/abc123.tar.gz"+                  , archiveSubdirs = ExplicitSubdirs ["foo"]+                  , archiveHash = Nothing+                  }+          decode' contents `shouldBe` Just (WithJSONWarnings expected [])++        it "does not parse GitHub repo with no slash" $ do+          let contents :: ByteString+              contents =+                S8.pack+                  (unlines+                    [ "github: oink"+                    , "commit: abc123"+                    ])+          decode' contents `shouldBe` Nothing++        it "does not parse GitHub repo with leading slash" $ do+          let contents :: ByteString+              contents =+                S8.pack+                  (unlines+                    [ "github: /oink"+                    , "commit: abc123"+                    ])+          decode' contents `shouldBe` Nothing++        it "does not parse GitHub repo with trailing slash" $ do+          let contents :: ByteString+              contents =+                S8.pack+                  (unlines+                    [ "github: oink/"+                    , "commit: abc123"+                    ])+          decode' contents `shouldBe` Nothing++        it "does not parse GitHub repo with more than one slash" $ do+          let contents :: ByteString+              contents =+                S8.pack+                  (unlines+                    [ "github: oink/town/here"+                    , "commit: abc123"+                    ])+          decode' contents `shouldBe` Nothing
stack.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: fb527fd6f73c61ffd0b8055991e9f777b12c9a6790e5939a1e46edc260201513+-- hash: 5b3e8d70c3e492d9cc4473a5919b80ee0fc2f59d6eb81b898d2bb507a83159e1  name:           stack-version:        1.6.5+version:        1.7.1 synopsis:       The Haskell Tool Stack description:    Please see the README.md for usage information, and the wiki on Github for more details.  Also, note that the API for the library is not currently stable, and may change significantly, even between minor releases. It is currently only intended for use by the executable. category:       Development@@ -16,8 +16,7 @@ license:        BSD3 license-file:   LICENSE build-type:     Custom-cabal-version:  >= 1.10-+cabal-version:  >= 1.24 extra-source-files:     ChangeLog.md     CONTRIBUTING.md@@ -43,7 +42,6 @@     doc/stack_yaml_vs_cabal_package_file.md     doc/travis_ci.md     doc/yaml_configuration.md-    package.yaml     README.md     src/setup-shim/StackSetupShim.hs     stack.yaml@@ -58,7 +56,7 @@ custom-setup   setup-depends:       Cabal-    , base+    , base >=4.10 && <5     , filepath  flag disable-git-info@@ -87,109 +85,6 @@   default: False  library-  hs-source-dirs:-      src/-  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-identities-  build-depends:-      Cabal-    , aeson-    , annotated-wl-pprint-    , ansi-terminal-    , async-    , attoparsec-    , base >=4.9 && <5-    , base64-bytestring-    , blaze-builder-    , bytestring-    , clock-    , conduit-    , conduit-extra-    , containers-    , cryptonite-    , cryptonite-conduit-    , deepseq-    , directory-    , echo-    , exceptions-    , extra-    , fast-logger-    , file-embed-    , filelock-    , filepath-    , fsnotify-    , generic-deriving-    , hackage-security-    , hashable-    , hastache-    , hpack-    , hpc-    , http-client-    , http-client-tls-    , http-conduit-    , http-types-    , memory-    , microlens-    , microlens-mtl-    , mintty-    , monad-logger-    , mono-traversable-    , mtl-    , neat-interpolation-    , network-uri-    , open-browser-    , optparse-applicative-    , path-    , path-io-    , persistent-    , persistent-sqlite-    , persistent-template-    , pretty-    , primitive-    , process-    , project-template-    , regex-applicative-text-    , resourcet-    , retry-    , semigroups-    , split-    , stm-    , store-    , store-core-    , streaming-commons-    , tar-    , template-haskell-    , temporary-    , text-    , text-metrics-    , th-reify-many-    , time-    , tls-    , transformers-    , unicode-transforms-    , unix-compat-    , unliftio-    , unordered-containers-    , vector-    , yaml-    , zip-archive-    , zlib-  if os(windows)-    cpp-options: -DWINDOWS-    build-depends:-        Win32-  else-    build-depends:-        bindings-uname-      , pid1-      , unix-    build-tools:-        hsc2hs-  if os(windows)-    hs-source-dirs:-        src/windows/-  else-    hs-source-dirs:-        src/unix/   exposed-modules:       Control.Concurrent.Execute       Data.Aeson.Extended@@ -200,6 +95,7 @@       Data.Store.VersionTagged       Network.HTTP.Download       Network.HTTP.Download.Verified+      Network.HTTP.StackClient       Options.Applicative.Args       Options.Applicative.Builder.Extra       Options.Applicative.Complicated@@ -229,7 +125,6 @@       Stack.Docker       Stack.Docker.GlobalDB       Stack.Dot-      Stack.Exec       Stack.Fetch       Stack.FileWatch       Stack.GhcPkg@@ -239,6 +134,7 @@       Stack.IDE       Stack.Image       Stack.Init+      Stack.Ls       Stack.New       Stack.Nix       Stack.Options.BenchParser@@ -296,6 +192,7 @@       Stack.Types.FlagName       Stack.Types.GhcPkgId       Stack.Types.Image+      Stack.Types.NamedComponent       Stack.Types.Nix       Stack.Types.Package       Stack.Types.PackageDump@@ -311,20 +208,121 @@       Stack.Upgrade       Stack.Upload       Text.PrettyPrint.Leijen.Extended-      System.Process.Log       System.Process.PagerEditor-      System.Process.Read-      System.Process.Run       System.Terminal   other-modules:       Hackage.Security.Client.Repository.HttpLib.HttpClient+  hs-source-dirs:+      src/+  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-identities+  build-depends:+      Cabal+    , aeson+    , annotated-wl-pprint+    , ansi-terminal+    , async+    , attoparsec+    , base >=4.10 && <5+    , base64-bytestring+    , bytestring+    , conduit+    , conduit-extra >=1.2.3.1+    , containers+    , cryptonite+    , cryptonite-conduit+    , deepseq+    , directory+    , echo+    , exceptions+    , extra+    , file-embed+    , filelock+    , filepath+    , fsnotify+    , generic-deriving+    , hackage-security+    , hashable+    , hpack+    , hpc+    , http-client+    , http-client-tls+    , http-conduit+    , http-types+    , memory+    , microlens+    , mintty+    , monad-logger+    , mono-traversable+    , mtl+    , mustache+    , neat-interpolation+    , network-uri+    , open-browser+    , optparse-applicative+    , path+    , path-io+    , persistent+    , persistent-sqlite+    , persistent-template+    , pretty+    , primitive+    , process+    , project-template+    , regex-applicative-text+    , resourcet+    , retry+    , rio+    , semigroups+    , split+    , stm+    , store+    , store-core+    , streaming-commons+    , tar+    , template-haskell+    , temporary+    , text+    , text-metrics+    , th-reify-many+    , time+    , tls+    , transformers+    , typed-process >=0.2.1.0+    , unicode-transforms+    , unix-compat+    , unliftio >=0.2.4.0+    , unordered-containers+    , vector+    , yaml+    , zip-archive+    , zlib+  if os(windows)+    cpp-options: -DWINDOWS+    build-depends:+        Win32+  else+    build-depends:+        bindings-uname+      , unix+    build-tools:+        hsc2hs+  if os(windows)+    hs-source-dirs:+        src/windows/+  else+    hs-source-dirs:+        src/unix/   default-language: Haskell2010+  autogen-modules: Paths_stack  executable stack   main-is: Main.hs+  other-modules:+      Build_stack+      Paths_stack   hs-source-dirs:       src/main-  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -threaded+  ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -threaded -rtsopts   build-depends:       Cabal     , aeson@@ -332,13 +330,11 @@     , ansi-terminal     , async     , attoparsec-    , base >=4.9 && <5+    , base >=4.10 && <5     , base64-bytestring-    , blaze-builder     , bytestring-    , clock     , conduit-    , conduit-extra+    , conduit-extra >=1.2.3.1     , containers     , cryptonite     , cryptonite-conduit@@ -347,7 +343,6 @@     , echo     , exceptions     , extra-    , fast-logger     , file-embed     , filelock     , filepath@@ -355,7 +350,6 @@     , generic-deriving     , hackage-security     , hashable-    , hastache     , hpack     , hpc     , http-client@@ -364,11 +358,11 @@     , http-types     , memory     , microlens-    , microlens-mtl     , mintty     , monad-logger     , mono-traversable     , mtl+    , mustache     , neat-interpolation     , network-uri     , open-browser@@ -385,6 +379,7 @@     , regex-applicative-text     , resourcet     , retry+    , rio     , semigroups     , split     , stack@@ -401,9 +396,10 @@     , time     , tls     , transformers+    , typed-process >=0.2.1.0     , unicode-transforms     , unix-compat-    , unliftio+    , unliftio >=0.2.4.0     , unordered-containers     , vector     , yaml@@ -416,7 +412,6 @@   else     build-depends:         bindings-uname-      , pid1       , unix     build-tools:         hsc2hs@@ -431,13 +426,17 @@     cpp-options: -DHIDE_DEP_VERSIONS   if flag(supported-build)     cpp-options: -DSUPPORTED_BUILD-  other-modules:-      Paths_stack   default-language: Haskell2010+  autogen-modules:+      Build_stack,+      Paths_stack  test-suite stack-integration-test   type: exitcode-stdio-1.0   main-is: IntegrationSpec.hs+  other-modules:+      StackTest+      Paths_stack   hs-source-dirs:       test/integration       test/integration/lib@@ -449,13 +448,11 @@     , ansi-terminal     , async     , attoparsec-    , base >=4.9 && <5+    , base >=4.10 && <5     , base64-bytestring-    , blaze-builder     , bytestring-    , clock     , conduit-    , conduit-extra+    , conduit-extra >=1.2.3.1     , containers     , cryptonite     , cryptonite-conduit@@ -464,7 +461,6 @@     , echo     , exceptions     , extra-    , fast-logger     , file-embed     , filelock     , filepath@@ -472,7 +468,6 @@     , generic-deriving     , hackage-security     , hashable-    , hastache     , hpack     , hpc     , hspec@@ -482,11 +477,11 @@     , http-types     , memory     , microlens-    , microlens-mtl     , mintty     , monad-logger     , mono-traversable     , mtl+    , mustache     , neat-interpolation     , network-uri     , open-browser@@ -503,6 +498,7 @@     , regex-applicative-text     , resourcet     , retry+    , rio     , semigroups     , split     , stm@@ -518,9 +514,10 @@     , time     , tls     , transformers+    , typed-process >=0.2.1.0     , unicode-transforms     , unix-compat-    , unliftio+    , unliftio >=0.2.4.0     , unordered-containers     , vector     , yaml@@ -533,20 +530,35 @@   else     build-depends:         bindings-uname-      , pid1       , unix     build-tools:         hsc2hs   if !(flag(integration-tests))     buildable: False-  other-modules:-      StackTest-      Paths_stack   default-language: Haskell2010  test-suite stack-test   type: exitcode-stdio-1.0   main-is: Test.hs+  other-modules:+      Network.HTTP.Download.VerifiedSpec+      Spec+      Stack.ArgsSpec+      Stack.Build.ExecuteSpec+      Stack.Build.TargetSpec+      Stack.ConfigSpec+      Stack.DotSpec+      Stack.Ghci.PortableFakePaths+      Stack.Ghci.ScriptSpec+      Stack.GhciSpec+      Stack.NixSpec+      Stack.PackageDumpSpec+      Stack.SolverSpec+      Stack.StaticBytesSpec+      Stack.StoreSpec+      Stack.Types.BuildPlanSpec+      Stack.Untar.UntarSpec+      Paths_stack   hs-source-dirs:       src/test   ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -threaded@@ -558,13 +570,11 @@     , ansi-terminal     , async     , attoparsec-    , base >=4.9 && <5+    , base >=4.10 && <5     , base64-bytestring-    , blaze-builder     , bytestring-    , clock     , conduit-    , conduit-extra+    , conduit-extra >=1.2.3.1     , containers     , cryptonite     , cryptonite-conduit@@ -573,7 +583,6 @@     , echo     , exceptions     , extra-    , fast-logger     , file-embed     , filelock     , filepath@@ -581,7 +590,6 @@     , generic-deriving     , hackage-security     , hashable-    , hastache     , hpack     , hpc     , hspec@@ -591,11 +599,11 @@     , http-types     , memory     , microlens-    , microlens-mtl     , mintty     , monad-logger     , mono-traversable     , mtl+    , mustache     , neat-interpolation     , network-uri     , open-browser@@ -612,6 +620,7 @@     , regex-applicative-text     , resourcet     , retry+    , rio     , semigroups     , smallcheck     , split@@ -629,9 +638,10 @@     , time     , tls     , transformers+    , typed-process >=0.2.1.0     , unicode-transforms     , unix-compat-    , unliftio+    , unliftio >=0.2.4.0     , unordered-containers     , vector     , yaml@@ -644,26 +654,7 @@   else     build-depends:         bindings-uname-      , pid1       , unix     build-tools:         hsc2hs-  other-modules:-      Network.HTTP.Download.VerifiedSpec-      Spec-      Stack.ArgsSpec-      Stack.Build.ExecuteSpec-      Stack.Build.TargetSpec-      Stack.ConfigSpec-      Stack.DotSpec-      Stack.Ghci.PortableFakePaths-      Stack.Ghci.ScriptSpec-      Stack.GhciSpec-      Stack.NixSpec-      Stack.PackageDumpSpec-      Stack.SolverSpec-      Stack.StaticBytesSpec-      Stack.StoreSpec-      Stack.Untar.UntarSpec-      Paths_stack   default-language: Haskell2010
stack.yaml view
@@ -1,4 +1,5 @@-resolver: lts-9.14+resolver: lts-11.6+ # docker: #   enable: true #   repo: fpco/stack-full@@ -11,25 +12,22 @@   enable: false   packages:     - zlib+    - unzip flags:   stack:     hide-dependency-versions: true     supported-build: true-  mintty:-    win32-2-5: false extra-deps:-- Cabal-2.0.1.0-- mintty-0.1.1-- bindings-uname-0.1-- path-0.6.1-- path-io-1.3.3-- extra-1.6-- hsc2hs-0.68.2-- hpack-0.20.0-- unliftio-0.2.1.0-- ansi-terminal-0.7.1.1-- ansi-wl-pprint-0.6.8.1-- smallcheck-1.1.3-- archive: https://github.com/haskell/hackage-security/archive/3297b0f3f4285cb30321baaa7b54e3d22e1f6bd7.tar.gz-  subdirs:-  - hackage-security+- rio-0.1.1.0@rev:0+- Cabal-2.2.0.1@rev:0+- hpack-0.28.2+- http-api-data-0.3.8.1@rev:0++# Avoid https://github.com/commercialhaskell/stack/issues/3922+# (triggered because later versions of persistent transitively depends+# on haskell-src-exts, which needs the 'happy' build tool)+- persistent-2.7.1@rev:0+- persistent-sqlite-2.6.4@rev:0+- resourcet-1.1.11@rev:0+- conduit-1.2.13@rev:0+- conduit-extra-1.2.3.2@rev:0
test/integration/IntegrationSpec.hs view
@@ -79,7 +79,7 @@     when newHomeExists (removeDirectoryRecursive newHome)     createDirectoryIfMissing True newStackRoot     copyTree toCopyRoot origStackRoot newStackRoot-    writeFile (newStackRoot </> "config.yaml") "system-ghc: true"+    writeFile (newStackRoot </> "config.yaml") "system-ghc: true\ninstall-ghc: false\n"     let testDir = currDir </> "tests" </> name         mainFile = testDir </> "Main.hs"         libDir = currDir </> "lib"
test/integration/lib/StackTest.hs view
@@ -205,11 +205,10 @@ -- | To avoid problems with GHC version mismatch when a new LTS major -- version is released, pass this argument to @stack@ when running in -- a global context. The LTS major version here should match that of--- the main @stack.yaml@ (and ordinarily be the `.0` minor version).+-- the main @stack.yaml@. ----- NOTE: currently using lts-8.22 instead of lts-8.0 because the `cyclic-test-deps` integration test is broken with lts-8.0 because a hackage metadata revision invalidated the snapshot (snapshot has `test-framework-quickcheck2-0.3.0.3` and `QuickCheck-2.9.2`, which used to be fine, but now test-framework-quickcheck2 was revised to have a `QuickCheck < 2.8` constraint). defaultResolverArg :: String-defaultResolverArg = "--resolver=lts-8.22"+defaultResolverArg = "--resolver=lts-11.6"  -- | Remove a file and ignore any warnings about missing files. removeFileIgnore :: FilePath -> IO ()