stack 1.7.1 → 1.9.1
raw patch · 85 files changed
+1903/−1366 lines, 85 filesdep +githashdep −gitrevdep ~Cabaldep ~Win32dep ~aeson
Dependencies added: githash
Dependencies removed: gitrev
Dependency ranges changed: Cabal, Win32, aeson, ansi-terminal, conduit, conduit-extra, containers, deepseq, directory, exceptions, extra, file-embed, filepath, fsnotify, generic-deriving, hpack, hspec, http-client, http-conduit, http-types, memory, mintty, monad-logger, mono-traversable, neat-interpolation, optparse-applicative, path-io, persistent, persistent-sqlite, primitive, resourcet, retry, rio, semigroups, smallcheck, stm, store, store-core, streaming-commons, template-haskell, temporary, text, typed-process, unix-compat, unliftio, yaml, zip-archive
Files
- ChangeLog.md +151/−0
- README.md +5/−0
- doc/ChangeLog.md +151/−0
- doc/GUIDE.md +100/−40
- doc/MAINTAINER_GUIDE.md +0/−439
- doc/README.md +9/−2
- doc/architecture.md +1/−1
- doc/build_command.md +7/−1
- doc/ghci.md +7/−0
- doc/ghcjs.md +11/−4
- doc/install_and_upgrade.md +5/−5
- doc/nix_integration.md +5/−4
- doc/yaml_configuration.md +56/−2
- src/Data/Monoid/Map.hs +18/−0
- src/Hackage/Security/Client/Repository/HttpLib/HttpClient.hs +30/−49
- src/Network/HTTP/Download.hs +10/−8
- src/Network/HTTP/Download/Verified.hs +16/−7
- src/Network/HTTP/StackClient.hs +55/−2
- src/Stack/Build/Cache.hs +13/−8
- src/Stack/Build/ConstructPlan.hs +66/−94
- src/Stack/Build/Execute.hs +128/−67
- src/Stack/Build/Installed.hs +1/−2
- src/Stack/Build/Source.hs +7/−4
- src/Stack/Build/Target.hs +2/−1
- src/Stack/BuildPlan.hs +1/−46
- src/Stack/Config.hs +8/−5
- src/Stack/Config/Build.hs +3/−0
- src/Stack/Config/Nix.hs +26/−22
- src/Stack/Constants/Config.hs +9/−1
- src/Stack/Coverage.hs +43/−17
- src/Stack/Docker.hs +2/−2
- src/Stack/Fetch.hs +7/−3
- src/Stack/FileWatch.hs +1/−1
- src/Stack/GhcPkg.hs +4/−4
- src/Stack/Ghci.hs +97/−48
- src/Stack/Hoogle.hs +1/−1
- src/Stack/Init.hs +1/−1
- src/Stack/Ls.hs +2/−6
- src/Stack/New.hs +100/−130
- src/Stack/Options/BenchParser.hs +1/−1
- src/Stack/Options/BuildMonoidParser.hs +7/−1
- src/Stack/Options/Completion.hs +3/−1
- src/Stack/Options/ExecParser.hs +1/−0
- src/Stack/Options/GlobalParser.hs +7/−4
- src/Stack/Options/NewParser.hs +6/−3
- src/Stack/Options/SDistParser.hs +3/−2
- src/Stack/Options/TestParser.hs +2/−2
- src/Stack/Package.hs +134/−88
- src/Stack/PackageIndex.hs +12/−6
- src/Stack/PackageLocation.hs +1/−1
- src/Stack/Prelude.hs +67/−5
- src/Stack/PrettyPrint.hs +6/−4
- src/Stack/SDist.hs +4/−2
- src/Stack/Script.hs +2/−1
- src/Stack/Setup.hs +15/−24
- src/Stack/Setup/Installed.hs +14/−3
- src/Stack/SetupCmd.hs +1/−1
- src/Stack/Sig/Sign.hs +1/−3
- src/Stack/Snapshot.hs +1/−12
- src/Stack/Solver.hs +4/−3
- src/Stack/Types/Build.hs +9/−2
- src/Stack/Types/BuildPlan.hs +12/−8
- src/Stack/Types/Config.hs +22/−6
- src/Stack/Types/Config/Build.hs +9/−0
- src/Stack/Types/NamedComponent.hs +12/−0
- src/Stack/Types/Package.hs +24/−2
- src/Stack/Types/PackageIdentifier.hs +1/−2
- src/Stack/Types/PackageIndex.hs +11/−0
- src/Stack/Types/Resolver.hs +1/−1
- src/Stack/Types/Runner.hs +1/−1
- src/Stack/Types/TemplateName.hs +60/−16
- src/Stack/Upgrade.hs +12/−1
- src/Stack/Upload.hs +27/−54
- src/main/Main.hs +61/−25
- src/test/Network/HTTP/Download/VerifiedSpec.hs +1/−1
- src/test/Stack/ConfigSpec.hs +2/−1
- src/test/Stack/StoreSpec.hs +0/−6
- src/test/Stack/Types/BuildPlanSpec.hs +2/−2
- src/test/Stack/Types/TemplateNameSpec.hs +51/−0
- src/unix/Stack/DefaultColorWhen.hs +11/−0
- src/windows/Stack/DefaultColorWhen.hs +65/−0
- stack.cabal +35/−32
- stack.yaml +19/−8
- test/integration/IntegrationSpec.hs +3/−3
- test/integration/lib/StackTest.hs +1/−1
ChangeLog.md view
@@ -1,6 +1,157 @@ # Changelog +## v1.9.1++Release notes:++* Statically linked Linux bindists are back again, thanks to [@nh2](https://github.com/nh2).+* We will be deleting the Ubuntu, Debian, CentOS, Fedora, and Arch package repos from `download.fpcomplete.com` soon. These have been deprecated for over a year and have not received new releases, but were left in place for compatibility with older scripts.++Major changes:++* Upgrade to Cabal 2.4+ * Note that, in this process, the behavior of file globbing has+ been modified to match that of Cabal. In particular, this means+ that for Cabal spec versions less than 2.4, `*.txt` will+ match `foo.txt`, but not `foo.2.txt`.+* `GHCJS` support is being downgraded to 'experimental'. A warning notifying the user of the experimental status of `GHCJS` will be displayed.++Behavior changes:++* `ghc-options` from `stack.yaml` are now appended to `ghc-options` from+ `config.yaml`, whereas before they would be replaced.+* `stack build` will now announce when sublibraries of a package are being+ build, in the same way executables, tests, benchmarks and libraries are+ announced+* `stack sdist` will now announce the destination of the generated tarball,+ regardless of whether or not it passed the sanity checks+* The `--upgrade-cabal` option to `stack setup` has been+ deprecated. This feature no longer works with GHC 8.2 and+ later. Furthermore, the reason for this flag originally being+ implemented was drastically lessened once Stack started using the+ snapshot's `Cabal` library for custom setups. See:+ [#4070](https://github.com/commercialhaskell/stack/issues/4070).+* With the new namespaced template feature, `stack templates` is no+ longer able to meaningfully display a list of all templates+ available. Instead, the command will download and display a+ [help file](https://github.com/commercialhaskell/stack-templates/blob/master/STACK_HELP.md)+ with more information on how to discover templates. See:+ [#4039](https://github.com/commercialhaskell/stack/issues/4039)+* Build tools are now handled in a similar way to `cabal-install`. In+ particular, for legacy `build-tools` fields, we use a hard-coded+ list of build tools in place of looking up build tool packages in a+ tool map. This both brings Stack's behavior closer into line with+ `cabal-install`, avoids some bugs, and opens up some possible+ optimizations/laziness. See:+ [#4125](https://github.com/commercialhaskell/stack/issues/4125).+* Mustache templating is not applied to large files (over 50kb) to+ avoid performance degredation. See:+ [#4133](https://github.com/commercialhaskell/stack/issues/4133).+* `stack upload` signs the package by default, as documented. `--no-signature`+ turns the signing off.+ [#3739](https://github.com/commercialhaskell/stack/issues/3739)+* In case there is a network connectivity issue while trying to+ download a template, stack will check whether that template had+ been downloaded before. In that case, the cached version will be+ used. See [#3850](https://github.com/commercialhaskell/stack/issues/3739).++Other enhancements:++* On Windows before Windows 10, --color=never is the default on terminals that+ can support ANSI color codes in output only by emulation+* On Windows, recognise a 'mintty' (false) terminal as a terminal, by default+* `stack build` issues a warning when `base` is explicitly listed in+ `extra-deps` of `stack.yaml`+* `stack build` suggests trying another GHC version should the build+ plan end up requiring unattainable `base` version.+* A new sub command `run` has been introduced to build and run a specified executable+ similar to `cabal run`. If no executable is provided as the first argument, it+ defaults to the first available executable in the project.+* `stack build` missing dependency suggestions (on failure to construct a valid+ build plan because of missing deps) are now printed with their latest+ cabal file revision hash. See+ [#4068](https://github.com/commercialhaskell/stack/pull/4068).+* Added new `--tar-dir` option to `stack sdist`, that allows to copy+ the resulting tarball to the specified directory.+* Introduced the `--interleaved-output` command line option and+ `build.interleaved-output` config value which causes multiple concurrent+ builds to dump to stderr at the same time with a `packagename> ` prefix. See+ [#3225](https://github.com/commercialhaskell/stack/issues/3225).+* The default retry strategy has changed to exponential backoff.+ This should help with+ [#3510](https://github.com/commercialhaskell/stack/issues/3510).+* `stack new` now allows template names of the form `username/foo` to+ download from a user other than `commercialstack` on Github, and can be prefixed+ with the service `github:`, `gitlab:`, or `bitbucket:`. [#4039](https://github.com/commercialhaskell/stack/issues/4039)+* Switch to `githash` to include some unmerged bugfixes in `gitrev`+ Suggestion to add `'allow-newer': true` now shows path to user config+ file where this flag should be put into [#3685](https://github.com/commercialhaskell/stack/issues/3685)+* `stack ghci` now asks which main target to load before doing the build,+ rather than after+* Bump to hpack 0.29.0+* With GHC 8.4 and later, Haddock is given the `--quickjump` flag.+* It is possible to specify the Hackage base URL to upload packages to, instead+ of the default of `https://hackage.haskell.org/`, by using `hackage-base-url`+ configuration option.+* When using Nix, if a specific minor version of GHC is not requested, the+ latest minor version in the given major branch will be used automatically.++Bug fixes:++* `stack ghci` now does not invalidate `.o` files on repeated runs,+ meaning any modules compiled with `-fobject-code` will be cached+ between ghci runs. See+ [#4038](https://github.com/commercialhaskell/stack/pull/4038).+* `~/.stack/config.yaml` and `stack.yaml` terminating by newline+* The previous released caused a regression where some `stderr` from the+ `ghc-pkg` command showed up in the terminal. This output is now silenced.+* A regression in recompilation checking introduced in v1.7.1 has been fixed.+ See [#4001](https://github.com/commercialhaskell/stack/issues/4001)+* `stack ghci` on a package with internal libraries was erroneously looking+ for a wrong package corresponding to the internal library and failing to+ load any module. This has been fixed now and changes to the code in the+ library and the sublibrary are properly tracked. See+ [#3926](https://github.com/commercialhaskell/stack/issues/3926).+* For packages with internal libraries not depended upon, `stack build` used+ to fail the build process since the internal library was not built but it+ was tried to be registered. This is now fixed by always building internal+ libraries. See+ [#3996](https://github.com/commercialhaskell/stack/issues/3996).+* `--no-nix` was not respected under NixOS+* Fix a regression which might use a lot of RAM. See+ [#4027](https://github.com/commercialhaskell/stack/issues/4027).+* Order of commandline arguments does not matter anymore.+ See [#3959](https://github.com/commercialhaskell/stack/issues/3959)+* When prompting users about saving their Hackage credentials on upload,+ flush to stdout before waiting for the response so the prompt actually+ displays. Also fixes a similar issue with ghci target selection prompt.+* If `cabal` is not on PATH, running `stack solver` now prompts the user+ to run `stack install cabal-install`+* `stack build` now succeeds in building packages which contain sublibraries+ which are dependencies of executables, tests or benchmarks but not of the+ main library. See+ [#3787](https://github.com/commercialhaskell/stack/issues/3959).+* Sublibraries are now properly considered for coverage reports when the test+ suite depends on the internal library. Before, stack was erroring when+ trying to generate the coverage report, see+ [#4105](https://github.com/commercialhaskell/stack/issues/4105).+* Sublibraries are now added to the precompiled cache and recovered from there+ when the snapshot gets updated. Previously, updating the snapshot when there+ was a package with a sublibrary in the snapshot resulted in broken builds.+ This is now fixed, see+ [#4071](https://github.com/commercialhaskell/stack/issues/4071).+* [#4114] Stack pretty prints error messages with proper `error` logging+ level instead of `warning` now. This also fixes self-executing scripts+ not piping plan construction errors from runhaskell to terminal (issue+ #3942).+* Fix invalid "While building Setup.hs" when Cabal calls fail. See:+ [#3934](https://github.com/commercialhaskell/stack/issues/3934)+* `stack upload` signs the package by default, as documented. `--no-signature`+ turns the signing off.+ [#3739](https://github.com/commercialhaskell/stack/issues/3739)++ ## v1.7.1 Release notes:
README.md view
@@ -3,8 +3,13 @@ [](https://travis-ci.org/commercialhaskell/stack) [](https://ci.appveyor.com/project/snoyberg/stack) [](https://github.com/commercialhaskell/stack/releases)+[](https://gitter.im/commercialhaskell/stack?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 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](./doc) directory for more information.++### Subsystem maintainers++* GHCJS - [Matchwood](https://github.com/matchwood)
doc/ChangeLog.md view
@@ -1,6 +1,157 @@ # Changelog +## v1.9.1++Release notes:++* Statically linked Linux bindists are back again, thanks to [@nh2](https://github.com/nh2).+* We will be deleting the Ubuntu, Debian, CentOS, Fedora, and Arch package repos from `download.fpcomplete.com` soon. These have been deprecated for over a year and have not received new releases, but were left in place for compatibility with older scripts.++Major changes:++* Upgrade to Cabal 2.4+ * Note that, in this process, the behavior of file globbing has+ been modified to match that of Cabal. In particular, this means+ that for Cabal spec versions less than 2.4, `*.txt` will+ match `foo.txt`, but not `foo.2.txt`.+* `GHCJS` support is being downgraded to 'experimental'. A warning notifying the user of the experimental status of `GHCJS` will be displayed.++Behavior changes:++* `ghc-options` from `stack.yaml` are now appended to `ghc-options` from+ `config.yaml`, whereas before they would be replaced.+* `stack build` will now announce when sublibraries of a package are being+ build, in the same way executables, tests, benchmarks and libraries are+ announced+* `stack sdist` will now announce the destination of the generated tarball,+ regardless of whether or not it passed the sanity checks+* The `--upgrade-cabal` option to `stack setup` has been+ deprecated. This feature no longer works with GHC 8.2 and+ later. Furthermore, the reason for this flag originally being+ implemented was drastically lessened once Stack started using the+ snapshot's `Cabal` library for custom setups. See:+ [#4070](https://github.com/commercialhaskell/stack/issues/4070).+* With the new namespaced template feature, `stack templates` is no+ longer able to meaningfully display a list of all templates+ available. Instead, the command will download and display a+ [help file](https://github.com/commercialhaskell/stack-templates/blob/master/STACK_HELP.md)+ with more information on how to discover templates. See:+ [#4039](https://github.com/commercialhaskell/stack/issues/4039)+* Build tools are now handled in a similar way to `cabal-install`. In+ particular, for legacy `build-tools` fields, we use a hard-coded+ list of build tools in place of looking up build tool packages in a+ tool map. This both brings Stack's behavior closer into line with+ `cabal-install`, avoids some bugs, and opens up some possible+ optimizations/laziness. See:+ [#4125](https://github.com/commercialhaskell/stack/issues/4125).+* Mustache templating is not applied to large files (over 50kb) to+ avoid performance degredation. See:+ [#4133](https://github.com/commercialhaskell/stack/issues/4133).+* `stack upload` signs the package by default, as documented. `--no-signature`+ turns the signing off.+ [#3739](https://github.com/commercialhaskell/stack/issues/3739)+* In case there is a network connectivity issue while trying to+ download a template, stack will check whether that template had+ been downloaded before. In that case, the cached version will be+ used. See [#3850](https://github.com/commercialhaskell/stack/issues/3739).++Other enhancements:++* On Windows before Windows 10, --color=never is the default on terminals that+ can support ANSI color codes in output only by emulation+* On Windows, recognise a 'mintty' (false) terminal as a terminal, by default+* `stack build` issues a warning when `base` is explicitly listed in+ `extra-deps` of `stack.yaml`+* `stack build` suggests trying another GHC version should the build+ plan end up requiring unattainable `base` version.+* A new sub command `run` has been introduced to build and run a specified executable+ similar to `cabal run`. If no executable is provided as the first argument, it+ defaults to the first available executable in the project.+* `stack build` missing dependency suggestions (on failure to construct a valid+ build plan because of missing deps) are now printed with their latest+ cabal file revision hash. See+ [#4068](https://github.com/commercialhaskell/stack/pull/4068).+* Added new `--tar-dir` option to `stack sdist`, that allows to copy+ the resulting tarball to the specified directory.+* Introduced the `--interleaved-output` command line option and+ `build.interleaved-output` config value which causes multiple concurrent+ builds to dump to stderr at the same time with a `packagename> ` prefix. See+ [#3225](https://github.com/commercialhaskell/stack/issues/3225).+* The default retry strategy has changed to exponential backoff.+ This should help with+ [#3510](https://github.com/commercialhaskell/stack/issues/3510).+* `stack new` now allows template names of the form `username/foo` to+ download from a user other than `commercialstack` on Github, and can be prefixed+ with the service `github:`, `gitlab:`, or `bitbucket:`. [#4039](https://github.com/commercialhaskell/stack/issues/4039)+* Switch to `githash` to include some unmerged bugfixes in `gitrev`+ Suggestion to add `'allow-newer': true` now shows path to user config+ file where this flag should be put into [#3685](https://github.com/commercialhaskell/stack/issues/3685)+* `stack ghci` now asks which main target to load before doing the build,+ rather than after+* Bump to hpack 0.29.0+* With GHC 8.4 and later, Haddock is given the `--quickjump` flag.+* It is possible to specify the Hackage base URL to upload packages to, instead+ of the default of `https://hackage.haskell.org/`, by using `hackage-base-url`+ configuration option.+* When using Nix, if a specific minor version of GHC is not requested, the+ latest minor version in the given major branch will be used automatically.++Bug fixes:++* `stack ghci` now does not invalidate `.o` files on repeated runs,+ meaning any modules compiled with `-fobject-code` will be cached+ between ghci runs. See+ [#4038](https://github.com/commercialhaskell/stack/pull/4038).+* `~/.stack/config.yaml` and `stack.yaml` terminating by newline+* The previous released caused a regression where some `stderr` from the+ `ghc-pkg` command showed up in the terminal. This output is now silenced.+* A regression in recompilation checking introduced in v1.7.1 has been fixed.+ See [#4001](https://github.com/commercialhaskell/stack/issues/4001)+* `stack ghci` on a package with internal libraries was erroneously looking+ for a wrong package corresponding to the internal library and failing to+ load any module. This has been fixed now and changes to the code in the+ library and the sublibrary are properly tracked. See+ [#3926](https://github.com/commercialhaskell/stack/issues/3926).+* For packages with internal libraries not depended upon, `stack build` used+ to fail the build process since the internal library was not built but it+ was tried to be registered. This is now fixed by always building internal+ libraries. See+ [#3996](https://github.com/commercialhaskell/stack/issues/3996).+* `--no-nix` was not respected under NixOS+* Fix a regression which might use a lot of RAM. See+ [#4027](https://github.com/commercialhaskell/stack/issues/4027).+* Order of commandline arguments does not matter anymore.+ See [#3959](https://github.com/commercialhaskell/stack/issues/3959)+* When prompting users about saving their Hackage credentials on upload,+ flush to stdout before waiting for the response so the prompt actually+ displays. Also fixes a similar issue with ghci target selection prompt.+* If `cabal` is not on PATH, running `stack solver` now prompts the user+ to run `stack install cabal-install`+* `stack build` now succeeds in building packages which contain sublibraries+ which are dependencies of executables, tests or benchmarks but not of the+ main library. See+ [#3787](https://github.com/commercialhaskell/stack/issues/3959).+* Sublibraries are now properly considered for coverage reports when the test+ suite depends on the internal library. Before, stack was erroring when+ trying to generate the coverage report, see+ [#4105](https://github.com/commercialhaskell/stack/issues/4105).+* Sublibraries are now added to the precompiled cache and recovered from there+ when the snapshot gets updated. Previously, updating the snapshot when there+ was a package with a sublibrary in the snapshot resulted in broken builds.+ This is now fixed, see+ [#4071](https://github.com/commercialhaskell/stack/issues/4071).+* [#4114] Stack pretty prints error messages with proper `error` logging+ level instead of `warning` now. This also fixes self-executing scripts+ not piping plan construction errors from runhaskell to terminal (issue+ #3942).+* Fix invalid "While building Setup.hs" when Cabal calls fail. See:+ [#3934](https://github.com/commercialhaskell/stack/issues/3934)+* `stack upload` signs the package by default, as documented. `--no-signature`+ turns the signing off.+ [#3739](https://github.com/commercialhaskell/stack/issues/3739)++ ## v1.7.1 Release notes:
doc/GUIDE.md view
@@ -359,10 +359,10 @@ # build output ... ``` -Finally, to find out which versions of these libraries stack installed, we can ask stack to `list-dependencies`:+Finally, to find out which versions of these libraries stack installed, we can ask stack to `ls dependencies`: ```-michael@d30748af6d3d:~/helloworld$ stack list-dependencies+michael@d30748af6d3d:~/helloworld$ stack ls dependencies # dependency output ... ``` @@ -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-11.6`, as is currently the latest LTS)+* The appropriate resolver value (`resolver: lts-11.19`, 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,15 +444,15 @@ ## Resolvers and changing your compiler version -Let's explore package sets a bit further. Instead of lts-11.6, let's change our+Let's explore package sets a bit further. Instead of lts-11.19, 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.+this is currently 2018-07-25 - please see the resolve from the link above to get the latest. Then, Rerunning `stack build` will produce: ``` michael@d30748af6d3d:~/helloworld$ stack build-Downloaded nightly-2017-12-19 build plan.+Downloaded nightly-2018-07-31 build plan. # build output ... ``` @@ -460,8 +460,8 @@ Continuous Integration (CI) setting, like on Travis. For example: ```-michael@d30748af6d3d:~/helloworld$ stack --resolver lts-11.6 build-Downloaded lts-11.6 build plan.+michael@d30748af6d3d:~/helloworld$ stack --resolver lts-11.19 build+Downloaded lts-11.19 build plan. # build output ... ``` @@ -1203,7 +1203,7 @@ ## exec -We've already used `stack exec` used multiple times in this guide. As you've+We've already used `stack exec` multiple times in this guide. As you've likely already guessed, it allows you to run executables, but with a slightly modified environment. In particular: `stack exec` looks for executables on stack's bin paths, and sets a few additional environment variables (like adding@@ -1548,18 +1548,37 @@ ``` michael@d30748af6d3d:~$ stack templates-chrisdone-hakyll-template-new-template-simple-yesod-minimal-yesod-mongo-yesod-mysql-yesod-postgres-yesod-postgres-fay-yesod-simple-yesod-sqlite-michael@d30748af6d3d:~$ stack new my-yesod-project yesod-simple+# Stack Templates++The `stack new` command will create a new project based on a project template.+Templates can be located on the local filesystem, on Github, or arbitrary URLs.+For more information, please see the user guide:++https://docs.haskellstack.org/en/stable/GUIDE/#templates++There are many templates available, some simple examples:++ stack new myproj # uses the default template+ stack new myproj2 rio # uses the rio template+ stack new website yesodweb/sqlite # Yesod server with SQLite DB++For more information and other templates, please see the `stack-templates`+Wiki:++https://github.com/commercialhaskell/stack-templates/wiki++Please feel free to add your own templates to the Wiki for discoverability.++Want to improve this text? Send us a PR!++https://github.com/commercialhaskell/stack-templates/edit/master/STACK_HELP.md+```++You can specify one of these templates following your project name+in the `stack new` command:++```+michael@d30748af6d3d:~$ stack new my-yesod-project yesodweb/simple Downloading template "yesod-simple" to create project "my-yesod-project" in my-yesod-project/ ... Using the following authorship configuration: author-email: example@example.com@@ -1574,13 +1593,42 @@ Wrote project config to: /home/michael/my-yesod-project/stack.yaml ``` -Alternatively you can use your own templates by specifying the path:+The default `stack-templates` repository is on [Github](https://github.com/commercialhaskell/stack-templates),+under the user account `commercialstack`. You can download templates from a+different Github user by prefixing the username and a slash: ```+stack new my-yesod-project yesodweb/simple+```++Then it would be downloaded from Github, user account `yesodweb`,+repo `stack-templates`, and file `yesod-simple.hsfiles`.++You can even download templates from a service other that Github, such as+[Gitlab](https://gitlab.com) or [Bitbucket](https://bitbucket.com):++```+stack new my-project gitlab:user29/foo+```++That template would be downloaded from Gitlab, user account `user29`,+repo `stack-templates`, and file `foo.hsfiles`.++If you need more flexibility, you can specify the full URL of the template:++```+stack new my-project https://my-site.com/content/template9.hsfiles+```++(The `.hsfiles` extension is optional; it will be added if it's not specified.)++Alternatively you can use a local template by specifying the path:++``` stack new project ~/location/of/your/template.hsfiles ``` -As a starting point you can use [the "simple" template](https://github.com/commercialhaskell/stack-templates/blob/master/simple.hsfiles).+As a starting point for creating your own templates, you can use [the "simple" template](https://github.com/commercialhaskell/stack-templates/blob/master/simple.hsfiles). An introduction into template-writing and a place for submitting official templates, you will find at [the stack-templates repository](https://github.com/commercialhaskell/stack-templates#readme). @@ -1613,21 +1661,19 @@ ### Docker -stack provides two built-in Docker integrations. Firstly, you can build your-code inside a Docker image, which means:+stack provides two built-in Docker integrations. The first way is to+build your code inside a Docker image, which means: * even more reproducibility to your builds, since you and the rest of your team will always have the same system libraries * the Docker images ship with entire precompiled snapshots. That means you have a large initial download, but much faster builds -For more information, see-[the Docker-integration documentation](docker_integration.md).--stack can also generate Docker images for you containing your built executables.-This feature is great for automating deployments from CI. This feature is not-yet well-documented, but the basics are to add a section like the following-to stack.yaml:+The second way is to generate Docker images for you containing your+built executables (the executable is built in your local machine and+copied into the image) . This feature is great for automating+deployments from CI. This feature is not yet well-documented, but the+basics are to add a section like the following to stack.yaml: ```yaml image:@@ -1663,9 +1709,10 @@ Note that the executable will be built in the development environment and copied to the container, so the dev OS must match that of the-container OS. This is easily accomplished using [Docker integration](docker_integration.md),-under which the exe emitted by `stack build` will be built on the-Docker container, not the local OS.+container OS. Note that you can use the `--docker` option to build+your code inside the Docker container in case you have a different+development environment or if you specifically want to build on the+container. The executable will be stored under `/usr/local/bin/<your-project>-exe` in the running container.@@ -1678,6 +1725,23 @@ - <your-project>-exe ``` +The difference between the first and second integration methods is+that in the first one your Haskell code is actually built in the+container whereas in the second one the executable built in your host+machine is copied to the container. The presence of the following+configuration in `stack.yaml` informs stack to switch to the first+integration method:++```yaml+docker:+ enable: true+```++Alternatively, instead of the above configuration, you can use the+`--docker` option to achieve the same. You can find more details+about the first integration method [in the Docker integration+documentation](./docker_integration.md).+ ### Nix stack provides an integration with [Nix](http://nixos.org/nix),@@ -1736,10 +1800,6 @@ * `stack upgrade` will build a new version of stack from source. * `--git` is a convenient way to get the most recent version from master for those testing and living on the bleeding edge.-* `stack setup --upgrade-cabal` can install a newer version of the Cabal- 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 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@@ -1817,7 +1877,7 @@ * `--verbose` (or `-v`) — much more info about internal operations (useful for bug reports) * The [home page](http://haskellstack.org) * The [stack mailing list](https://groups.google.com/d/forum/haskell-stack)-* The [the FAQ](faq.md)+* The [FAQ](faq.md) * The [stack wiki](https://github.com/commercialhaskell/stack/wiki) * The [haskell-stack tag on Stack Overflow](http://stackoverflow.com/questions/tagged/haskell-stack) * [Another getting started with stack tutorial](http://seanhess.github.io/2015/08/04/practical-haskell-getting-started.html)
− doc/MAINTAINER_GUIDE.md
@@ -1,439 +0,0 @@-<div class="hidden-warning"><a href="https://docs.haskellstack.org/"><img src="https://rawgit.com/commercialhaskell/stack/master/doc/img/hidden-warning.svg"></a></div>--# Maintainer guide--## Next release:--* Create release candidate process (maybe switch to GHC-style versioning)-* Maybe drop 32-bit CentOS 6 bindists, since GHC 8.2.1 seems to have dropped them.-* Replace non-static Linux bindists with static (but keep old links active so- links don't break and 'stack upgrade' in old versions still work)--## Pre-release steps--* Check for any P0 and P1 issues.-* Ensure `release` and `stable` branches merged to `master`-* Check compatibility with latest Stackage snapshots- * stack-*.yaml (where `*` is not `nightly`): bump to use latest LTS minor- version (be sure any extra-deps that exist only for custom flags have- versions matching the snapshot)- * Check for any redundant extra-deps- * Run `stack --stack-yaml=stack-*.yaml test --pedantic` (replace `*` with- the actual file)-* Check compatibility with latest nightly stackage snapshot:- * Update `stack-nightly.yaml` with latest nightly and remove extra-deps (be- sure any extra-deps that exist only for custom flags have versions- matching the snapshot)- * Run `stack --stack-yaml=stack-nightly.yaml test --pedantic`-* Check pvp-bounds compatibility with Stackage snapshots:- * Create an sdist using `stack sdist --pvp-bounds=both`- * Temporarily replace `stack.cabal` with the `stack.cabal` in that sdist- * Run `stack --stack-yaml=stack-*.yaml test --pedantic` for each- `stack-*.yaml` and adjust upper bounds in original `stack.cabal` until it- works with pvp-bounds.-* Ensure integration tests pass on a Windows, macOS, and Linux (Linux- integration tests are run- by- [Gitlab](http://gitlab.fpcomplete.com/fpco-mirrors/stack/pipelines)):- `stack install --pedantic && stack test --pedantic --flag- stack:integration-tests`. The actual release script will perform a more- thorough test for every platform/variant prior to uploading, so this is just a- pre-check-* In master branch:- * stack.cabal: bump the version number to release (even third- component)- * ChangeLog: rename the "Unreleased changes" section to the new version-* Cut a release candidate branch `rc/vX.Y.Z` from master-* In master branch:- * stack.cabal: bump version number to unstable (odd third component)- * Changelog: add new "unreleased changes" section-* In RC branch:- * Update the ChangeLog:- * Check for any important changes that missed getting an entry in- Changelog (`git log origin/stable...HEAD`)- * Check for any entries that snuck into the previous version's changes- due to merges (`git diff origin/stable HEAD ChangeLog.md`)- * Review documentation for any changes that need to be made- * Search for old Stack version, unstable stack version, and the next- "obvious" version in sequence (if doing a non-obvious jump), and- `UNRELEASED` and replace with new version- * Look for any links to "latest" documentation, replace with version tag- * Ensure all documentation pages listed in `mkdocs.yaml`- * Update `.github/ISSUE_TEMPLATE.md` to point at the new version.- * Check for new [FreeBSD release](https://www.freebsd.org/releases/).- * Check that no new entries need to be added to- [releases.yaml](https://github.com/fpco/stackage-content/blob/master/stack/releases.yaml),- [install_and_upgrade.md](https://github.com/commercialhaskell/stack/blob/master/doc/install_and_upgrade.md),- and- `README.md`- * Remove unsupported/obsolete distribution versions from the release process.- * [Ubuntu](https://wiki.ubuntu.com/Releases)- * 14.04 EOL 2019-APR- * 16.04 EOL 2021-APR- * [CentOS](https://wiki.centos.org/Download) - * 6 EOL 2020-NOV-30- * 7 EOL 2024-JUN-30--## Release process--See-[stack-release-script's README](https://github.com/commercialhaskell/stack/blob/master/etc/scripts/README.md#prerequisites)-for requirements to perform the release, and more details about the tool.--A note about the `etc/scripts/*-releases.sh` scripts: if you run them from a-different working tree than the scripts themselves (e.g. if you have `stack1`-and `stack2` trees, and run `cd stack1; ../stack2/etc/scripts/vagrant-release.sh`)-the scripts and Vagrantfiles from the-tree containing the script will be used to build the stack code in the current-directory. That allows you to iterate on the release process while building a-consistent and clean stack version.--* Create a- [new draft Github release](https://github.com/commercialhaskell/stack/releases/new)- with tag and name `vX.Y.Z` (where X.Y.Z is the stack package's version), targeting the- RC branch--* On each machine you'll be releasing from, set environment variables:- `GITHUB_AUTHORIZATION_TOKEN`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`,- `AWS_DEFAULT_REGION`.-- Note: since one of the tools (rpm-s3 on CentOS) doesn't support AWS- temporary credentials, you can't use MFA with the AWS credentials- (`AWS_SECURITY_TOKEN` is ignored).--* On a machine with Vagrant installed:- * Run `etc/scripts/vagrant-releases.sh`--* On macOS:- * Run `etc/scripts/osx-release.sh`--* On Windows:- * Ensure your working tree is in `C:\stack` (or a similarly short path)- * Run `etc\scripts\windows-releases.bat`- * Release Windows installers. See- [stack-installer README](https://github.com/borsboom/stack-installer#readme)--* On Linux ARMv7:- * Run `etc/scripts/linux-armv7-release.sh`--* Build sdist using `stack sdist . --pvp-bounds=both`, and upload it to the- Github release with a name like `stack-X.Y.Z-sdist-0.tar.gz`.--* Publish Github release. Use e.g. `git shortlog -s release..HEAD|sed $'s/^[0-9 \t]*/* /'|sort -f`- to get the list of contributors.--* Upload package to Hackage: `stack upload . --pvp-bounds=both`--* Push signed Git tag, matching Github release tag name, e.g.: `git tag -d vX.Y.Z; git tag -u 0x575159689BEFB442 -m vX.Y.Z vX.Y.Z && git push -f origin vX.Y.Z`--* Reset the `release` branch to the released commit, e.g.: `git checkout release && git merge --ff-only vX.Y.Z && git push origin release`--* Update the `stable` branch similarly--* Delete the RC branch and any RC tags (locally and on origin)--* Activate version for new release tag on- [readthedocs.org](https://readthedocs.org/dashboard/stack/versions/), and- ensure that stable documentation has updated--* Merge any changes made in the RC/release/stable branches to master.--* On a machine with Vagrant installed:- * Make sure you are on the same commit as when `vagrant-release.sh` was run.- * Run `etc/scripts/vagrant-distros.sh`--* Upload haddocks to Hackage: `etc/scripts/upload-haddocks.sh` (if they weren't auto-built)--* Announce to haskell-cafe@haskell.org, haskell-stack@googlegroups.com,- commercialhaskell@googlegroups.com mailing lists--* Keep an eye on the- [Hackage matrix builder](http://matrix.hackage.haskell.org/package/stack)--## Setting up a Windows VM for releases--These instructions are a bit rough, but has the steps to get the Windows machine-set up.-- 1. Download VM image:- https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/mac/-- 2. Launch the VM using Virtualbox and the image downloaded-- 3. Adjust settings:- * Number of CPUs: match the host- * Memory: at least 3 GB- * Video RAM: the minimum recommended by Virtualbox- * Enable 3D and 2D accelerated mode- * Enabled shared clipboard (both directions)-- 4. Install the VMware guest additions, and reboot-- 5. In **Settings**->**Update & Security**->**Windows Update**->**Advanced options**:- * Change **Choose how updates are installed** to **Notify to schedule restart**- * Check **Defer upgrades**-- 6. Configure a shared folder for your home directory on the host, and mount it on Z:-- 7. Install Windows SDK (for signtool):- http://microsoft.com/en-us/download/confirmation.aspx?id=8279-- 8. Install msysgit: https://msysgit.github.io/-- 9. Install nsis-2.46.5-Unicode-setup.exe from http://www.scratchpaper.com/--10: Install Stack using the Windows 64-bit installer--11. Visit https://hackage.haskell.org/ in Edge to ensure system has correct CA- certificates--12. Get the object code certificate from- [password-store](https://github.com/fpco/password-store), in- `certificates/code_signing/fpcomplete_corporation_startssl_2015-09-22.pfx`.- Double click it in explorer and import it--13. Run in command prompt:-- md C:\p- md C:\p\tmp- cd \p- md c:\tmp--14. Create `C:\p\env.bat`:-- SET STACK_ROOT=C:\p\.sr- SET TEMP=C:\p\tmp- SET TMP=C:\p\tmp- SET PATH=C:\Users\IEUser\AppData\Roaming\local\bin;"c:\Program Files\Git\usr\bin";"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin";%PATH%--15. Run `C:\p\env.bat` (do this every time you open a new command prompt)--16. Import the `dev@fpcomplete.com` (0x575159689BEFB442) GPG secret key--17. Run in command prompt (adjust the `user.email` and `user.name` settings):-- stack setup- stack install cabal-install- md %HOMEPATH%\.ssh- copy z:\.ssh\id_rsa %HOMEPATH%\.ssh- git config --global user.email manny@fpcomplete.com- git config --global user.name "Emanuel Borsboom"- git config --global push.default simple- git config --global core.autocrlf true- git clone git@github.com:commercialhaskell/stack.git- git clone git@github.com:borsboom/stack-installer.git--## Setting up an ARM VM for releases--These instructions assume the host system is running macOS. Some steps will vary-with a different host OS.--### Install qemu on host-- brew install qemu--### Install fuse-ext2-- brew install e2fsprogs m4 automake autoconf libtool && \- git clone https://github.com/alperakcan/fuse-ext2.git && \- cd fuse-ext2 && \--Add `m4_ifdef([AM_PROG_AR], [AM_PROG_AR])` to the `configure.ac` after-`m4_ifdef([AC_PROG_LIB],[AC_PROG_LIB],[m4_warn(portability,[Missing AC_PROJ_LIB])])`-line.-- PKG_CONFIG_PATH="$(brew --prefix e2fsprogs)/lib/pkgconfig" \- CFLAGS="-idirafter/$(brew --prefix e2fsprogs)/include -idirafter/usr/local/include/osxfuse" \- LDFLAGS="-L$(brew --prefix e2fsprogs)/lib" \- ./configure--### Create VM and install Debian in it-- wget http://ftp.de.debian.org/debian/dists/jessie/main/installer-armhf/current/images/netboot/initrd.gz && \- wget http://ftp.de.debian.org/debian/dists/jessie/main/installer-armhf/current/images/netboot/vmlinuz && \- wget http://ftp.de.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca9.dtb && \- qemu-img create -f raw armdisk.raw 15G && \- qemu-system-arm -M vexpress-a9 -cpu cortex-a9 -kernel vmlinuz -initrd initrd.gz -sd armdisk.raw -append "root=/dev/mmcblk0p2" -m 1024M -redir tcp:2223::22 -dtb vexpress-v2p-ca9.dtb -append "console=ttyAMA0,115200" -serial stdio--Now the Debian installer will run. Don't use LVM for partitioning (it won't-boot), and add at least 4 GB swap during installation.--### Get boot files after install--Adjust the disk number `/dev/disk3` below to match the output from `hdiutil attach`.-- hdiutil attach -imagekey diskimage-class=CRawDiskImage -nomount armdisk.raw && \- sudo mkdir -p /Volumes/debarm && \- sudo fuse-ext2 /dev/disk3s1 /Volumes/debarm/ && \- sleep 5 && \- cp /Volumes/debarm/vmlinuz-3.16.0-4-armmp . && \- cp /Volumes/debarm/initrd.img-3.16.0-4-armmp . && \- sudo umount /Volumes/debarm && \- hdiutil detach /dev/disk3--### Boot VM--Adjust `/dev/mmcblk0p3` below to the root partition you created during installation.-- qemu-system-arm -M vexpress-a9 -cpu cortex-a9 -kernel vmlinuz-3.16.0-4-armmp -initrd initrd.img-3.16.0-4-armmp -sd armdisk.raw -m 1024M -dtb vexpress-v2p-ca9.dtb -append "root=/dev/mmcblk0p3 console=ttyAMA0,115200" -serial stdio -redir tcp:2223::22--### Setup rest of system--Log onto the VM as root, then (replace `<<<USERNAME>>>` with the user you set up-during Debian installation):-- apt-get update && \- apt-get install -y sudo && \- adduser <<<USERNAME>>> sudo--Now you can SSH to the VM using `ssh -p 2223 <<<USERNAME>>>@localhost` and use `sudo` in-the shell.--### Install build tools and dependencies packages-- sudo apt-get install -y g++ gcc libc6-dev libffi-dev libgmp-dev make xz-utils zlib1g-dev git gnupg--### Install clang+llvm--NOTE: the Debian jessie `llvm` package does not work (executables built with it-just exit with "schedule: re-entered unsafely.").--The version of LLVM needed depends on the version of GHC you need.--#### GHC 8.0.2 (the standard for building Stack)-- wget http://llvm.org/releases/3.7.1/clang+llvm-3.7.1-armv7a-linux-gnueabihf.tar.xz && \- sudo tar xvf clang+llvm-3.7.1-armv7a-linux-gnueabihf.tar.xz -C /opt--Run this now and add it to the `.profile`:-- export PATH="$HOME/.local/bin:/opt/clang+llvm-3.7.1-armv7a-linux-gnueabihf/bin:$PATH"--#### GHC 7.10.3-- wget http://llvm.org/releases/3.5.2/clang+llvm-3.5.2-armv7a-linux-gnueabihf.tar.xz && \- sudo tar xvf clang+llvm-3.5.2-armv7a-linux-gnueabihf.tar.xz -C /opt--Run this now and add it to the `.profile`:-- export PATH="$HOME/.local/bin:/opt/clang+llvm-3.5.2-armv7a-linux-gnueabihf/bin:$PATH"--### Install Stack--#### Binary--Get an [existing `stack` binary](https://github.com/commercialhaskell/stack/releases)-and put it in `~/.local/bin`.--#### From source (using cabal-install):-- wget http://downloads.haskell.org/~ghc/7.10.3/ghc-7.10.3-armv7-deb8-linux.tar.xz && \- tar xvf ghc-7.10.3-armv7-deb8-linux.tar.xz && \- cd ghc-7.10.3 && \- ./configure --prefix=/opt/ghc-7.10.3 && \- sudo make install && \- cd ..- export PATH="/opt/ghc-7.10.3/bin:$PATH"- wget https://www.haskell.org/cabal/release/cabal-install-1.24.0.0/cabal-install-1.24.0.0.tar.gz &&&&& \- tar xvf cabal-install-1.24.0.0.tar.gz && \- cd cabal-install-1.24.0.0 && \- EXTRA_CONFIGURE_OPTS="" ./bootstrap.sh && \- cd .. && \- export PATH="$HOME/.cabal/bin:$PATH" && \- cabal update--Edit `~/.cabal/config`, and set `executable-stripping: False` and-`library-stripping: False`.-- cabal unpack stack && \- cd stack-* && \- cabal install && \- mv ~/.cabal/bin/stack ~/.local/bin--### Import GPG private key--Import the `dev@fpcomplete.com` (0x575159689BEFB442) GPG secret key--### Resources-- - http://mashu.github.io/2015/08/12/QEMU-Debian-armhf.html- - https://www.aurel32.net/info/debian_arm_qemu.php- - http://linuxdeveloper.blogspot.ca/2011/08/how-to-install-arm-debian-on-ubuntu.html- - http://www.macworld.com/article/2855038/how-to-mount-and-manage-non-native-file-systems-in-os-x-with-fuse.html- - https://github.com/alperakcan/fuse-ext2#mac-os- - https://github.com/alperakcan/fuse-ext2/issues/31#issuecomment-214713801- - https://github.com/alperakcan/fuse-ext2/issues/33#issuecomment-216758378- - https://github.com/alperakcan/fuse-ext2/issues/32#issuecomment-216758019- - http://osxdaily.com/2007/03/23/create-a-ram-disk-in-mac-os-x/--## Adding a new GHC version-- * Push new tag to our fork:-- git clone git@github.com:commercialhaskell/ghc.git- cd ghc- git remote add upstream git@github.com:ghc/ghc.git- git fetch upstream- git push origin ghc-X.Y.Z-release-- * [Publish a new Github release](https://github.com/commercialhaskell/ghc/releases/new)- with tag `ghc-X.Y.Z-release` and same name.-- * Down all the relevant GHC bindists from https://www.haskell.org/ghc/download_ghc_X_Y_Z and upload them to the just-created Github release (see- [stack-setup-2.yaml](https://github.com/fpco/stackage-content/blob/master/stack/stack-setup-2.yaml)- for the ones we used in the last GHC release).-- In the case of macOS, repackage the `.xz` bindist as a `.bz2`, since macOS does- not include `xz` by default or provide an easy way to install it.-- The script at `etc/scripts/mirror-ghc-bindists-to-github.sh` will help with- this. See the comments within the script.-- * Build any additional required bindists (see below for instructions)-- * tinfo6 (`etc/vagrant/fedora24-x86_64`)- * ncurses6 (`etc/vagrant/arch-x86_64`)-- * [Edit stack-setup-2.yaml](https://github.com/fpco/stackage-content/edit/master/stack/stack-setup-2.yaml)- and add the new bindists, pointing to the Github release version. Be sure to- update the `content-length` and `sha1` values.--### Building GHC--On systems with a small `/tmp`, you should set TMP and TEMP to an alternate-location.--For GHC >= 7.10.2, set the `GHC_VERSION` environment variable to the version to build:-- * `export GHC_VERSION=8.0.2`- * `export GHC_VERSION=8.0.1`- * `export GHC_VERSION=7.10.3a`- * `export GHC_VERSION=7.10.2`--then, run (from [here](https://ghc.haskell.org/trac/ghc/wiki/Newcomers)):-- git config --global url."git://github.com/ghc/packages-".insteadOf git://github.com/ghc/packages/ && \- git clone -b ghc-${GHC_VERSION}-release --recursive git://github.com/ghc/ghc ghc-${GHC_VERSION} && \- cd ghc-${GHC_VERSION}/ && \- cp mk/build.mk.sample mk/build.mk && \- sed -i 's/^#BuildFlavour *= *perf$/BuildFlavour = perf/' mk/build.mk && \- ./boot && \- ./configure --enable-tarballs-autodownload && \- sed -i 's/^TAR_COMP *= *bzip2$/TAR_COMP = xz/' mk/config.mk && \- make -j$(cat /proc/cpuinfo|grep processor|wc -l) && \- make binary-dist--GHC 7.8.4 is slightly different:-- export GHC_VERSION=7.8.4 && \- git config --global url."git://github.com/ghc/packages-".insteadOf git://github.com/ghc/packages/ && \- git clone -b ghc-${GHC_VERSION}-release --recursive git://github.com/ghc/ghc ghc-${GHC_VERSION} && \- cd ghc-${GHC_VERSION}/ && \- ./sync-all --extra --nofib -r git://git.haskell.org get -b ghc-7.8 && \- cp mk/build.mk.sample mk/build.mk && \- sed -i 's/^#BuildFlavour *= *perf$/BuildFlavour = perf/' mk/build.mk && \- perl boot && \- ./configure && \- sed -i 's/^TAR_COMP *= *bzip2$/TAR_COMP = xz/' mk/config.mk && \- make -j$(cat /proc/cpuinfo|grep processor|wc -l) && \- make binary-dist
doc/README.md view
@@ -95,9 +95,12 @@ 2. If you need to include another library (for example the package [`text`](https://hackage.haskell.org/package/text)): - - Add the package `text` to the file `my-project.cabal`- in the section `build-depends: ...`.+ - Add the package `text` to the file `package.yaml`+ in the section `dependencies: ...`. - Run `stack build` another time.+ - `stack build` will update my-project.cabal for you.+ If desired you can update the .cabal file manually+ and stack will use .cabal instead of package.yaml. 3. If you get an error that tells you your package isn't in the LTS. Just try to add a new version in the `stack.yaml` file in the `extra-deps` section.@@ -191,3 +194,7 @@ If you'd like to get involved with Stack, check out the [newcomer friendly](https://github.com/commercialhaskell/stack/issues?q=is%3Aopen+is%3Aissue+label%3a%22newcomer+friendly%22) label on the Github issue tracker.++#### How to uninstall+Removing ``~/.stack`` and ``/usr/local/bin/stack`` should be sufficient. You may want to delete ``.stack-work`` folders in any Haskell projects that you have built.+
doc/architecture.md view
@@ -96,7 +96,7 @@ When running a build, we know which packages we want installed (inventively called "wanteds"), which packages are available to install, and which are-already installed. In plan construction, we put them information together to+already installed. In plan construction, we put this information together to decide which packages must be built. The code in Stack.Build.ConstructPlan is authoritative on this and should be consulted. The basic idea though is:
doc/build_command.md view
@@ -161,7 +161,7 @@ * `--exec "cmd [args]"` will run a command after a successful build To come back to the composable approach described above, consider this final-example (which uses the [wai repository](https://github.com/yesodweb/wai/):+example (which uses the [wai repository](https://github.com/yesodweb/wai/)): ``` stack build --file-watch --test --copy-bins --haddock wai-extra :warp warp:doctest --exec 'echo Yay, it worked!'@@ -194,3 +194,9 @@ warnings, to avoid problems of interleaved output and decrease console noise. If you would like to see this content instead, you can use the `--dump-logs` command line option, or add `dump-logs: all` to your `stack.yaml` file.++Alternatively, starting with Stack 1.8, you can pass `--interleaved-output` to+see output of all packages being built scroll by in a streaming fashion. The+output from each package built will be prefixed by the package name, e.g. `mtl>+Building ...`. Note that, unlike the default output, this will include the+output from dependencies being built, not just targets.
doc/ghci.md view
@@ -75,3 +75,10 @@ it may be useful to run ghci plainly like `stack exec ghci`. This will run a plain `ghci` in an environment which includes `GHC_PACKAGE_PATH`, and so will have access to your databases.++*Note*: Running `stack ghci` on a pristine copy of the code doesn't currently+build libraries+([#2790](https://github.com/commercialhaskell/stack/issues/2790)) or internal+libraries ([#4148](https://github.com/commercialhaskell/stack/issues/4148)).+It is recommended to always run a `stack build` before running `stack ghci`,+until these two issues are closed.
doc/ghcjs.md view
@@ -1,8 +1,8 @@ <div class="hidden-warning"><a href="https://docs.haskellstack.org/"><img src="https://rawgit.com/commercialhaskell/stack/master/doc/img/hidden-warning.svg"></a></div> -# GHCJS+# GHCJS (experimental) -To use GHCJS with stack, place a GHCJS version in the [`compiler`](yaml_configuration.md#compiler) field of `stack.yaml`. After this, all stack commands should work with GHCJS! In particular:+To use GHCJS with stack, place a GHCJS version in the [`compiler`](yaml_configuration.md#compiler) field of `stack.yaml`. After this, some stack commands should work with GHCJS. In particular: * `stack setup` will install GHCJS from source and boot it, which takes a long time. @@ -21,8 +21,14 @@ ## Example Configurations -### Recent versions of GHCJS, repacked for stack+### GHCJS repacked for snapsnots lts-8 and lts-9 +Please see the [ghcjs-stack-dist repository](https://github.com/matchwood/ghcjs-stack-dist) for `lts-8` and `lts-9` configurations and refer to the [README](https://github.com/matchwood/ghcjs-stack-dist/blob/master/README.md) for common issues.++Support for `> lts-9` snapshots (`GHC 8.2` and above) is currently [work in progress](https://github.com/matchwood/ghcjs-stack-dist/issues/10).++### GHCJS repacked for snapsnots < lts-8+ These versions of GHCJS were created by [Marcin Tolysz](https://github.com/tolysz), and were particularly crafted to include package versions which match those expected by particular stackage@@ -55,7 +61,7 @@ url: http://ghcjs.tolysz.org/ghc-8.0-2017-02-05-lts-7.19-9007019.tar.gz sha1: d2cfc25f9cda32a25a87d9af68891b2186ee52f9 ```-The later can be generated via: https://github.com/tolysz/prepare-ghcjs+The latter can be generated via: https://github.com/tolysz/prepare-ghcjs the former is a bit more manual. Those bundles are only tested against the latest `node-7.4.0`. In order to correctly boot and use ghcjs, one might need to install `alex` `happy` `hscolour` `hsc2hs` with the normal ghc.@@ -64,6 +70,7 @@ |resolver|ghcjs|url|sha1| |---|---|---|---|+| lts-7.19 |0.2.1| http://ghcjs.tolysz.org/ghc-8.0-2017-02-05-lts-7.19-9007019.tar.gz | d2cfc25f9cda32a25a87d9af68891b2186ee52f9 | | lts-7.15 |0.2.1| http://ghcjs.tolysz.org/ghc-8.0-2017-01-11-lts-7.15-9007015.tar.gz | 30d34e9d704bdb799066387dfa1ba98b8884d932 | | lts-7.14 |0.2.1| http://ghcjs.tolysz.org/ghc-8.0-2016-12-25-lts-7.14-9007014.tar.gz | 530c4ee5e19e2874e128431c7ad421e336df0303 | | lts-7.13 |0.2.1| http://ghcjs.tolysz.org/ghc-8.0-2016-12-18-lts-7.13-9007013.tar.gz | 0d2ebe0931b29adca7cb9d9b9f77d60095bfb864 |
doc/install_and_upgrade.md view
@@ -73,7 +73,7 @@ If you have the popular [brew](https://brew.sh/) tool installed, you can just do: - brew install haskell-stack+ brew install stack * The Homebrew formula and bottles are **unofficial** and lag slightly behind new Stack releases, but tend to be updated within a day or two.@@ -104,8 +104,8 @@ There is also a [Ubuntu package](http://packages.ubuntu.com/search?keywords=haskell-stack&searchon=names&suite=all§ion=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` may work too. The+recommend running `stack upgrade --binary-only` after installing it. For older stack+versions which do not support `--binary-only`, 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).@@ -117,8 +117,8 @@ There is also a [Debian package](https://packages.debian.org/search?keywords=haskell-stack&searchon=names&suite=all§ion=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` may work too.+`stack upgrade --binary-only` is recommended after installing it. For older stack+versions which do not support `--binary-only`, just `stack upgrade` may work too. ## <a name="centos"></a>CentOS / Red Hat / Amazon Linux
doc/nix_integration.md view
@@ -54,7 +54,7 @@ support means packages will always be built using a GHC available inside the shell, rather than your globally installed one if any. -Note that in this mode `stack` can use only GHC versions than have+Note that in this mode `stack` can use only GHC versions that have already been mirrored into the Nix package repository. The [Nixpkgs master branch](https://github.com/NixOS/nixpkgs/tree/master/pkgs/development/haskell-modules) usually picks up new versions quickly, but it takes two or three@@ -186,9 +186,10 @@ ```yaml nix: - # false by default. Must be present and set to `true` to enable Nix.- # You can set set it in your `$HOME/.stack/config.yaml` to enable- # Nix for all your projects without having to repeat it+ # false by default. Must be present and set to `true` to enable Nix, except on+ # NixOS where it is enabled by default (see #3938). You can set set it in your+ # `$HOME/.stack/config.yaml` to enable Nix for all your projects without having+ # to repeat it # enable: true # true by default. Tells Nix whether to run in a pure shell or not.
doc/yaml_configuration.md view
@@ -199,6 +199,8 @@ extra-deps: - git: git@github.com:commercialhaskell/stack.git commit: 6a86ee32e5b869a877151f74064572225e1a0398+- git: git@github.com:snoyberg/http-client.git+ commit: "a5f4f3" - hg: https://example.com/hg/repo commit: da39a3ee5e6b4b0d3255bfef95601890afd80709 ```@@ -226,6 +228,14 @@ - wai ``` +Since v1.7.1, you can specify packages from GitHub repository name using `github`:++```yaml+extra-deps:+- github: snoyberg/http-client+ commit: a5f4f30f01366738f913968163d856366d7e0342+```+ 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@@ -548,7 +558,7 @@ command line parameters. NOTE: Prior to version 1.6.0, the `$locals`, `$targets`, and-`$everything` keys were not support. Instead, you could use `"*"` for+`$everything` keys were not supported. Instead, you could use `"*"` for the behavior represented now by `$everything`. It is highly recommended to switch to the new, more expressive, keys. @@ -777,6 +787,9 @@ reconfigure: false cabal-verbose: false split-objs: false++ # Since 1.8+ interleaved-output: false ``` The meanings of these settings correspond directly with the CLI flags of the@@ -865,6 +878,17 @@ Since 1.5.0 +### hackage-base-url++Sets the address of the Hackage server to upload the package to. Default is+`https://hackage.haskell.org/`.++```yaml+hackage-base-url: https://hackage.example.com/+```++Since 1.9.1+ ### ignore-revision-mismatch Cabal files in packages can be specified via exact revisions to deal@@ -956,7 +980,7 @@ variable. These will be used when resolving the location of executables, and will also be visible in the `PATH` variable of processes run by stack. -For example, to prepend `/path-to-some-dep/bin` to your PATh:+For example, to prepend `/path-to-some-dep/bin` to your PATH: ```yaml extra-path:@@ -986,3 +1010,33 @@ This option specifies which template to use with `stack new`, when none is specified. The default is called `new-template`. The other templates are listed in [the stack-templates repo](https://github.com/commercialhaskell/stack-templates/).++### stack-colors++Stack uses styles to format some of its output. The default styles do not work+well with every terminal theme. This option specifies stack's output styles,+allowing new styles to replace the defaults. The option is used as+`stack-colors: <STYLES>`, where `<STYLES>` is a colon-delimited sequence of+key=value, 'key' is a style name and 'value' is a semicolon-delimited list of+'ANSI' SGR (Select Graphic Rendition) control codes (in decimal). Use the+command `stack ls stack-colors --basic` to see the current sequence.++The 'ANSI' standards refer to (1) standard ECMA-48 'Control Functions for Coded+Character Sets' (5th edition, 1991); (2) extensions in ITU-T Recommendation+(previously CCITT Recommendation) T.416 (03/93) 'Information Technology – Open+Document Architecture (ODA) and Interchange Format: Character Content+Architectures' (also published as ISO/IEC International Standard 8613-6); and+(3) further extensions used by 'XTerm', a terminal emulator for the X Window+System. The 'ANSI' SGR codes are described in a+[Wikipedia article](http://en.wikipedia.org/wiki/ANSI_escape_code)+and those codes supported on current versions of Windows in+[Microsoft's documentation](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).++For example, users of the popular+[Solarized Dark](https://ethanschoonover.com/solarized/)+terminal theme might wish to set the styles as follows:++```yaml+stack-colors: error=31:good=32:shell=35:dir=34:recommendation=32:target=95:module=35:package-component=95+```+The styles can also be set at the command line using the equivalent `--stack-colors=<STYLES>` global option. Styles set at the command line take precedence over those set in a yaml configuration file.
+ src/Data/Monoid/Map.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Data.Monoid.Map where++import qualified Data.Map as M+import Stack.Prelude++-- | Utility newtype wrapper to make make Map's Monoid also use the+-- element's Monoid.+newtype MonoidMap k a = MonoidMap (Map k a)+ deriving (Eq, Ord, Read, Show, Generic, Functor)++instance (Ord k, Semigroup a) => Semigroup (MonoidMap k a) where+ MonoidMap mp1 <> MonoidMap mp2 = MonoidMap (M.unionWith (<>) mp1 mp2)++instance (Ord k, Semigroup a) => Monoid (MonoidMap k a) where+ mappend = (<>)+ mempty = MonoidMap mempty
src/Hackage/Security/Client/Repository/HttpLib/HttpClient.hs view
@@ -7,8 +7,7 @@ -- https://github.com/well-typed/hackage-security/tree/master/hackage-security-http-client -- to avoid extra dependencies module Hackage.Security.Client.Repository.HttpLib.HttpClient (- withClient- , makeHttpLib+ makeHttpLib -- ** Re-exports , Manager -- opaque ) where@@ -17,13 +16,10 @@ import Control.Monad (void) import Data.ByteString (ByteString) import Network.URI-import Network.HTTP.Client (Manager) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BS.C8-import qualified Network.HTTP.Client as HttpClient-import qualified Network.HTTP.Client.Internal as HttpClient+import Network.HTTP.StackClient (Manager) import qualified Network.HTTP.StackClient as StackClient-import qualified Network.HTTP.Types as HttpClient import Hackage.Security.Client hiding (Header) import Hackage.Security.Client.Repository.HttpLib@@ -34,21 +30,6 @@ Top-level API -------------------------------------------------------------------------------} --- | Initialization------ The proxy must be specified at initialization because @http-client@ does not--- allow to change the proxy once the 'Manager' is created.-withClient :: ProxyConfig HttpClient.Proxy -> (Manager -> HttpLib -> IO a) -> IO a-withClient proxyConfig callback = do- manager <- HttpClient.newManager (setProxy HttpClient.defaultManagerSettings)- callback manager $ makeHttpLib manager- where- setProxy = HttpClient.managerSetProxy $- case proxyConfig of- ProxyConfigNone -> HttpClient.noProxy- ProxyConfigUse p -> HttpClient.useProxy p- ProxyConfigAuto -> HttpClient.proxyEnvironment Nothing- -- | Create an 'HttpLib' value from a preexisting 'Manager'. makeHttpLib :: Manager -> HttpLib makeHttpLib manager = HttpLib@@ -68,10 +49,10 @@ get manager reqHeaders uri callback = wrapCustomEx $ do -- TODO: setUri fails under certain circumstances; in particular, when -- the URI contains URL auth. Not sure if this is a concern.- request' <- HttpClient.setUri HttpClient.defaultRequest uri+ request' <- StackClient.setUri StackClient.defaultRequest uri let request = setRequestHeaders reqHeaders request' checkHttpException $ StackClient.withResponseByManager request manager $ \response -> do- let br = wrapCustomEx $ HttpClient.responseBody response+ let br = wrapCustomEx $ StackClient.responseBody response callback (getResponseHeaders response) br getRange :: Throws SomeRemoteError@@ -80,49 +61,49 @@ -> (HttpStatus -> [HttpResponseHeader] -> BodyReader -> IO a) -> IO a getRange manager reqHeaders uri (from, to) callback = wrapCustomEx $ do- request' <- HttpClient.setUri HttpClient.defaultRequest uri+ request' <- StackClient.setUri StackClient.defaultRequest uri let request = setRange from to $ setRequestHeaders reqHeaders request' checkHttpException $ StackClient.withResponseByManager request manager $ \response -> do- let br = wrapCustomEx $ HttpClient.responseBody response+ let br = wrapCustomEx $ StackClient.responseBody response case () of- () | HttpClient.responseStatus response == HttpClient.partialContent206 ->+ () | StackClient.responseStatus response == StackClient.partialContent206 -> callback HttpStatus206PartialContent (getResponseHeaders response) br- () | HttpClient.responseStatus response == HttpClient.ok200 ->+ () | StackClient.responseStatus response == StackClient.ok200 -> callback HttpStatus200OK (getResponseHeaders response) br _otherwise ->- throwChecked $ HttpClient.HttpExceptionRequest request- $ HttpClient.StatusCodeException (void response) ""+ throwChecked $ StackClient.HttpExceptionRequest request+ $ StackClient.StatusCodeException (void response) "" -- | Wrap custom exceptions -- -- NOTE: The only other exception defined in @http-client@ is @TimeoutTriggered@ -- but it is currently disabled <https://github.com/snoyberg/http-client/issues/116>-wrapCustomEx :: (Throws HttpClient.HttpException => IO a)+wrapCustomEx :: (Throws StackClient.HttpException => IO a) -> (Throws SomeRemoteError => IO a)-wrapCustomEx act = handleChecked (\(ex :: HttpClient.HttpException) -> go ex) act+wrapCustomEx act = handleChecked (\(ex :: StackClient.HttpException) -> go ex) act where go ex = throwChecked (SomeRemoteError ex) -checkHttpException :: Throws HttpClient.HttpException => IO a -> IO a-checkHttpException = handle $ \(ex :: HttpClient.HttpException) ->+checkHttpException :: Throws StackClient.HttpException => IO a -> IO a+checkHttpException = handle $ \(ex :: StackClient.HttpException) -> throwChecked ex {------------------------------------------------------------------------------- http-client auxiliary -------------------------------------------------------------------------------} -hAcceptRanges :: HttpClient.HeaderName+hAcceptRanges :: StackClient.HeaderName hAcceptRanges = "Accept-Ranges" -hAcceptEncoding :: HttpClient.HeaderName+hAcceptEncoding :: StackClient.HeaderName hAcceptEncoding = "Accept-Encoding" setRange :: Int -> Int- -> HttpClient.Request -> HttpClient.Request+ -> StackClient.Request -> StackClient.Request setRange from to req = req {- HttpClient.requestHeaders = (HttpClient.hRange, rangeHeader)- : HttpClient.requestHeaders req+ StackClient.requestHeaders = (StackClient.hRange, rangeHeader)+ : StackClient.requestHeaders req } where -- Content-Range header uses inclusive rather than exclusive bounds@@ -131,42 +112,42 @@ -- | Set request headers setRequestHeaders :: [HttpRequestHeader]- -> HttpClient.Request -> HttpClient.Request+ -> StackClient.Request -> StackClient.Request setRequestHeaders opts req = req {- HttpClient.requestHeaders = trOpt disallowCompressionByDefault opts+ StackClient.requestHeaders = trOpt disallowCompressionByDefault opts } where- trOpt :: [(HttpClient.HeaderName, [ByteString])]+ trOpt :: [(StackClient.HeaderName, [ByteString])] -> [HttpRequestHeader]- -> [HttpClient.Header]+ -> [StackClient.Header] trOpt acc [] = concatMap finalizeHeader acc trOpt acc (HttpRequestMaxAge0:os) =- trOpt (insert HttpClient.hCacheControl ["max-age=0"] acc) os+ trOpt (insert StackClient.hCacheControl ["max-age=0"] acc) os trOpt acc (HttpRequestNoTransform:os) =- trOpt (insert HttpClient.hCacheControl ["no-transform"] acc) os+ trOpt (insert StackClient.hCacheControl ["no-transform"] acc) os -- disable content compression (potential security issue)- disallowCompressionByDefault :: [(HttpClient.HeaderName, [ByteString])]+ disallowCompressionByDefault :: [(StackClient.HeaderName, [ByteString])] disallowCompressionByDefault = [(hAcceptEncoding, [])] -- Some headers are comma-separated, others need multiple headers for -- multiple options. -- -- TODO: Right we we just comma-separate all of them.- finalizeHeader :: (HttpClient.HeaderName, [ByteString])- -> [HttpClient.Header]+ finalizeHeader :: (StackClient.HeaderName, [ByteString])+ -> [StackClient.Header] finalizeHeader (name, strs) = [(name, BS.intercalate ", " (reverse strs))] insert :: Eq a => a -> [b] -> [(a, [b])] -> [(a, [b])] insert x y = Lens.modify (Lens.lookupM x) (++ y) -- | Extract the response headers-getResponseHeaders :: HttpClient.Response a -> [HttpResponseHeader]+getResponseHeaders :: StackClient.Response a -> [HttpResponseHeader] getResponseHeaders response = concat [ [ HttpResponseAcceptRangesBytes | (hAcceptRanges, "bytes") `elem` headers ] ] where- headers = HttpClient.responseHeaders response+ headers = StackClient.responseHeaders response
src/Network/HTTP/Download.hs view
@@ -30,12 +30,8 @@ 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.StackClient (httpJSON, httpLbs, httpLBS, withResponse)-import Network.HTTP.Simple (getResponseBody, getResponseHeaders, getResponseStatusCode,- setRequestHeader)+import Network.HTTP.StackClient (Request, Response, HttpException, httpJSON, httpLbs, httpLBS, withResponse, path, checkResponse, parseUrlThrow, parseRequest, setRequestHeader, getResponseHeaders, requestHeaders, getResponseBody, getResponseStatusCode) import Path.IO (doesFileExist) import System.Directory (createDirectoryIfMissing, removeFile)@@ -89,7 +85,7 @@ [("If-None-Match", L.toStrict etag)] } req2 = req1 { checkResponse = \_ _ -> return () }- recoveringHttp drRetryPolicyDefault $ liftIO $+ recoveringHttp drRetryPolicyDefault $ catchingHttpExceptions $ liftIO $ withResponse req2 $ \res -> case getResponseStatusCode res of 200 -> do createDirectoryIfMissing True $ takeDirectory destFilePath@@ -108,9 +104,15 @@ return True 304 -> return False- _ -> throwM $ RedownloadFailed req2 dest $ void res+ _ -> throwM $ RedownloadInvalidResponse req2 dest $ void res -data DownloadException = RedownloadFailed Request (Path Abs File) (Response ())+ where+ catchingHttpExceptions :: RIO env a -> RIO env a+ catchingHttpExceptions action = catch action (throwM . RedownloadHttpError)++data DownloadException = RedownloadInvalidResponse Request (Path Abs File) (Response ())+ | RedownloadHttpError HttpException+ deriving (Show, Typeable) instance Exception DownloadException
src/Network/HTTP/Download/Verified.hs view
@@ -30,7 +30,7 @@ import Control.Monad import Control.Monad.Catch (Handler (..)) -- would be nice if retry exported this itself import Stack.Prelude hiding (Handler (..))-import Control.Retry (recovering,limitRetries,RetryPolicy,constantDelay,RetryStatus(..))+import Control.Retry (recovering,limitRetries,RetryPolicy,exponentialBackoff,RetryStatus(..)) import Crypto.Hash import Crypto.Hash.Conduit (sinkHash) import Data.ByteArray as Mem (convert)@@ -41,10 +41,7 @@ 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.StackClient (httpSink)-import Network.HTTP.Simple (Request, HttpException, getResponseHeaders)-import Network.HTTP.Types.Header (hContentLength, hContentMD5)+import Network.HTTP.StackClient (Request, HttpException, httpSink, getUri, path, getResponseHeaders, hContentLength, hContentMD5) import Path import Stack.Types.Runner import Stack.PrettyPrint@@ -59,9 +56,20 @@ , drRetryPolicy :: RetryPolicy } --- | Default to retrying thrice with a short constant delay.+-- | Default to retrying seven times with exponential backoff starting from+-- one hundred milliseconds.+--+-- This means the tries will occur after these delays if necessary:+--+-- * 0.1s+-- * 0.2s+-- * 0.4s+-- * 0.8s+-- * 1.6s+-- * 3.2s+-- * 6.4s drRetryPolicyDefault :: RetryPolicy-drRetryPolicyDefault = limitRetries 3 <> constantDelay onehundredMilliseconds+drRetryPolicyDefault = limitRetries 7 <> exponentialBackoff onehundredMilliseconds where onehundredMilliseconds = 100000 data HashCheck = forall a. (Show a, HashAlgorithm a) => HashCheck@@ -210,6 +218,7 @@ [ "If you see this warning and stack fails to download," , "but running the command again solves the problem," , "please report here: https://github.com/commercialhaskell/stack/issues/3510"+ , "Make sure to paste the output of 'stack --version'" ] ] return True
src/Network/HTTP/StackClient.hs view
@@ -13,6 +13,54 @@ , setUserAgent , withResponse , withResponseByManager+ , setRequestMethod+ , setRequestHeader+ , addRequestHeader+ , setRequestBody+ , setRequestManager+ , getResponseHeaders+ , getResponseBody+ , getResponseStatusCode+ , Network.HTTP.Client.responseHeaders+ , Network.HTTP.Client.responseStatus+ , Network.HTTP.Client.responseBody+ , parseRequest+ , parseRequest_+ , defaultRequest+ , setUri+ , getUri+ , path+ , checkResponse+ , parseUrlThrow+ , requestHeaders+ , getGlobalManager+ , applyDigestAuth+ , displayDigestAuthException+ , Request+ , RequestBody(RequestBodyBS, RequestBodyLBS)+ , Response+ , Manager+ , Header+ , HeaderName+ , HttpException(HttpExceptionRequest)+ , HttpExceptionContent(StatusCodeException)+ , hAccept+ , hContentLength+ , hContentMD5+ , hCacheControl+ , hRange+ , methodPut+ , ok200+ , partialContent206+ , Proxy+ , useProxy+ , noProxy+ , proxyEnvironment+ , managerSetProxy+ , formDataBody+ , partFileRequestBody+ , partBS+ , partLBS ) where import Data.Aeson (FromJSON)@@ -21,9 +69,14 @@ 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 Network.HTTP.Client (BodyReader, Manager, Request, RequestBody(..), Response, Manager, HttpExceptionContent(..), parseRequest, parseRequest_, defaultRequest, getUri, path, checkResponse, parseUrlThrow, responseStatus, responseBody, useProxy, noProxy, proxyEnvironment, managerSetProxy, Proxy)+import Network.HTTP.Client.Internal (setUri)+import Network.HTTP.Simple (setRequestMethod, setRequestBody, setRequestHeader, addRequestHeader, setRequestManager, HttpException(..), getResponseBody, getResponseStatusCode, getResponseHeaders)+import Network.HTTP.Types (hAccept, hContentLength, hContentMD5, hCacheControl, hRange, methodPut, Header, HeaderName, ok200, partialContent206)+import Network.HTTP.Conduit (requestHeaders)+import Network.HTTP.Client.TLS (getGlobalManager, applyDigestAuth, displayDigestAuthException) import qualified Network.HTTP.Simple+import Network.HTTP.Client.MultipartFormData (formDataBody, partFileRequestBody, partBS, partLBS) import UnliftIO (MonadIO, MonadUnliftIO, withRunInIO, withUnliftIO, unliftIO)
src/Stack/Build/Cache.hs view
@@ -324,29 +324,33 @@ -> ConfigureOpts -> Set GhcPkgId -- ^ dependencies -> Installed -- ^ library+ -> [GhcPkgId] -- ^ sublibraries, in the GhcPkgId format -> Set Text -- ^ executables -> RIO env ()-writePrecompiledCache baseConfigOpts loc copts depIDs mghcPkgId exes = do+writePrecompiledCache baseConfigOpts loc copts depIDs mghcPkgId sublibs exes = do mfile <- precompiledCacheFile loc copts depIDs forM_ mfile $ \file -> do ensureDir (parent file) ec <- view envConfigL let stackRootRelative = makeRelative (view stackRootL ec)- mlibpath <-- case mghcPkgId of- Executable _ -> return Nothing- Library _ ipid _ -> liftM Just $ do- ipid' <- parseRelFile $ ghcPkgIdString ipid ++ ".conf"- relPath <- stackRootRelative $ bcoSnapDB baseConfigOpts </> ipid'- return $ toFilePath relPath+ mlibpath <- case mghcPkgId of+ Executable _ -> return Nothing+ Library _ ipid _ -> liftM Just $ pathFromPkgId stackRootRelative ipid+ sublibpaths <- mapM (pathFromPkgId stackRootRelative) sublibs exes' <- forM (Set.toList exes) $ \exe -> do name <- parseRelFile $ T.unpack exe relPath <- stackRootRelative $ bcoSnapInstallRoot baseConfigOpts </> bindirSuffix </> name return $ toFilePath relPath $(versionedEncodeFile precompiledCacheVC) file PrecompiledCache { pcLibrary = mlibpath+ , pcSubLibs = sublibpaths , pcExes = exes' }+ where+ pathFromPkgId stackRootRelative ipid = do+ ipid' <- parseRelFile $ ghcPkgIdString ipid ++ ".conf"+ relPath <- stackRootRelative $ bcoSnapDB baseConfigOpts </> ipid'+ return $ toFilePath relPath -- | Check the cache for a precompiled package matching the given -- configuration.@@ -372,6 +376,7 @@ let mkAbs' = (toFilePath stackRoot FP.</>) return PrecompiledCache { pcLibrary = mkAbs' <$> pcLibrary pc0+ , pcSubLibs = mkAbs' <$> pcSubLibs pc0 , pcExes = mkAbs' <$> pcExes pc0 }
src/Stack/Build/ConstructPlan.hs view
@@ -22,9 +22,11 @@ import Control.Monad.RWS.Strict hiding ((<>)) import Control.Monad.State.Strict (execState) import qualified Data.HashSet as HashSet+import qualified Data.HashMap.Strict as HashMap import Data.List import qualified Data.Map.Strict as M import qualified Data.Map.Strict as Map+import Data.Monoid.Map (MonoidMap(..)) import qualified Data.Set as Set import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8, decodeUtf8With)@@ -38,8 +40,6 @@ import Stack.Build.Haddock import Stack.Build.Installed import Stack.Build.Source-import Stack.BuildPlan-import Stack.Config (getLocalPackages) import Stack.Constants import Stack.Package import Stack.PackageDump@@ -131,11 +131,10 @@ , baseConfigOpts :: !BaseConfigOpts , loadPackage :: !(PackageLocationIndex FilePath -> Map FlagName Bool -> [Text] -> M Package) , combinedMap :: !CombinedMap- , toolToPackages :: !(ExeName -> Map PackageName VersionRange) , ctxEnvConfig :: !EnvConfig , callStack :: ![PackageName] , extraToBuild :: !(Set PackageName)- , getVersions :: !(PackageName -> IO (Set Version))+ , getVersions :: !(PackageName -> IO (HashMap Version (Maybe CabalHash))) , wanted :: !(Set PackageName) , localNames :: !(Set PackageName) }@@ -185,13 +184,16 @@ constructPlan ls0 baseConfigOpts0 locals extraToBuild0 localDumpPkgs loadPackage0 sourceMap installedMap initialBuildSteps = do logDebug "Constructing the build plan" + bconfig <- view buildConfigL+ when (hasBaseInDeps bconfig) $+ prettyWarn $ flow "You are trying to upgrade/downgrade base, which is almost certainly not what you really want. Please, consider using another GHC version if you need a certain version of base, or removing base from extra-deps. See more at https://github.com/commercialhaskell/stack/issues/3940." <> line+ econfig <- view envConfigL let onWanted = void . addDep False . packageName . lpPackage let inner = do mapM_ onWanted $ filter lpWanted locals mapM_ (addDep False) $ Set.toList extraToBuild0- lp <- getLocalPackages- let ctx = mkCtx econfig lp+ let ctx = mkCtx econfig ((), m, W efinals installExes dirtyReason deps warnings parents) <- liftIO $ runRWST inner ctx M.empty mapM_ (logWarn . RIO.display) (warnings [])@@ -223,17 +225,19 @@ else do planDebug $ show errs stackYaml <- view stackYamlL- prettyErrorNoIndent $ pprintExceptions errs stackYaml parents (wanted ctx)+ stackRoot <- view stackRootL+ prettyErrorNoIndent $ pprintExceptions errs stackYaml stackRoot parents (wanted ctx) throwM $ ConstructPlanFailed "Plan construction failed." where- mkCtx econfig lp = Ctx+ hasBaseInDeps bconfig =+ elem $(mkPackageName "base")+ $ map (packageIdentifierName . pirIdent) [i | (PLIndex i) <- bcDependencies bconfig]++ mkCtx econfig = Ctx { ls = ls0 , baseConfigOpts = baseConfigOpts0 , loadPackage = \x y z -> runRIO econfig $ loadPackage0 x y z , combinedMap = combineMap sourceMap installedMap- , toolToPackages = \name ->- maybe Map.empty (Map.fromSet (const Cabal.anyVersion)) $- Map.lookup name toolMap , ctxEnvConfig = econfig , callStack = [] , extraToBuild = extraToBuild0@@ -241,8 +245,6 @@ , wanted = wantedLocalPackages locals <> extraToBuild0 , localNames = Set.fromList $ map (packageName . lpPackage) locals }- where- toolMap = getToolMap ls0 lp -- | State to be maintained during the calculation of local packages -- to unregister.@@ -365,13 +367,6 @@ } tell mempty { wFinals = Map.singleton (packageName package) res } --- | Is this package being used as a library, or just as a build tool?--- If the former, we need to ensure that a library actually--- exists. See--- <https://github.com/commercialhaskell/stack/issues/2195>-data DepType = AsLibrary | AsBuildTool- deriving (Show, Eq)- -- | Given a 'PackageName', adds all of the build tasks to build the -- package, if needed. --@@ -613,11 +608,16 @@ addPackageDeps treatAsDep package = do ctx <- ask deps' <- packageDepsWithTools package- deps <- forM (Map.toList deps') $ \(depname, (range, depType)) -> do+ deps <- forM (Map.toList deps') $ \(depname, DepValue range depType) -> do eres <- addDep treatAsDep depname- let getLatestApplicable = do- vs <- liftIO $ getVersions ctx depname- return (latestApplicableVersion range vs)+ let getLatestApplicableVersionAndRev = do+ vsAndRevs <- liftIO $ getVersions ctx depname+ let vs = Set.fromList (HashMap.keys vsAndRevs)+ case latestApplicableVersion range vs of+ Nothing -> pure Nothing+ Just lappVer -> do+ let mlappRev = join (HashMap.lookup lappVer vsAndRevs)+ pure $ (lappVer,) <$> mlappRev case eres of Left e -> do addParent depname range Nothing@@ -625,7 +625,7 @@ case e of UnknownPackage name -> assert (name == depname) NotInBuildPlan _ -> Couldn'tResolveItsDependencies (packageVersion package)- mlatestApplicable <- getLatestApplicable+ mlatestApplicable <- getLatestApplicableVersionAndRev return $ Left (depname, (range, mlatestApplicable, bd)) Right adr | depType == AsLibrary && not (adrHasLibrary adr) -> return $ Left (depname, (range, Nothing, HasNoLibrary))@@ -669,7 +669,7 @@ ADRFound loc (Library ident gid _) -> return $ Right (Set.empty, Map.singleton ident gid, loc) else do- mlatestApplicable <- getLatestApplicable+ mlatestApplicable <- getLatestApplicableVersionAndRev return $ Left (depname, (range, mlatestApplicable, DependencyMismatch $ adrVersion adr)) case partitionEithers deps of -- Note that the Monoid for 'InstallLocation' means that if any@@ -701,8 +701,10 @@ TTFiles lp _ -> packageHasLibrary $ lpPackage lp TTIndex p _ _ -> packageHasLibrary p + -- make sure we consider internal libraries as libraries too packageHasLibrary :: Package -> Bool packageHasLibrary p =+ not (Set.null (packageInternalLibraries p)) || case packageLibraries p of HasLibraries _ -> True NoLibraries -> False@@ -833,61 +835,32 @@ -- | Get all of the dependencies for a given package, including build -- tool dependencies.-packageDepsWithTools :: Package -> M (Map PackageName (VersionRange, DepType))+packageDepsWithTools :: Package -> M (Map PackageName DepValue) packageDepsWithTools p = do- ctx <- ask- let toEither name mp =- case Map.toList mp of- [] -> Left (ToolWarning name (packageName p) Nothing)- [_] -> Right mp- ((x, _):(y, _):zs) ->- Left (ToolWarning name (packageName p) (Just (x, y, map fst zs)))- (warnings0, toolDeps) =- partitionEithers $- 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+ warnings <- fmap catMaybes $ forM (Set.toList $ packageUnknownTools p) $+ \name@(ExeName toolName) -> do let settings = minimalEnvSettings { esIncludeLocals = True } config <- view configL menv <- liftIO $ configProcessContextSettings config settings mfound <- runRIO menv $ findExecutable $ T.unpack toolName case mfound of- Left _ -> return (Just warning)+ Left _ -> return $ Just $ ToolWarning name (packageName p) Right _ -> return Nothing tell mempty { wWarnings = (map toolWarningText warnings ++) }- return $ Map.unionsWith- (\(vr1, dt1) (vr2, dt2) ->- ( intersectVersionRanges vr1 vr2- , case dt1 of- AsLibrary -> AsLibrary- AsBuildTool -> dt2- )- )- $ ((, AsLibrary) <$> packageDeps p)- : (Map.map (, AsBuildTool) <$> toolDeps)+ return $ packageDeps p -- | Warn about tools in the snapshot definition. States the tool name--- expected, the package name using it, and found packages. If the--- last value is Nothing, it means the tool was not found--- anywhere. For a Just value, it was found in at least two packages.-data ToolWarning = ToolWarning ExeName PackageName (Maybe (PackageName, PackageName, [PackageName]))+-- expected and the package name using it.+data ToolWarning = ToolWarning ExeName PackageName deriving Show toolWarningText :: ToolWarning -> Text-toolWarningText (ToolWarning (ExeName toolName) pkgName Nothing) =+toolWarningText (ToolWarning (ExeName toolName) pkgName) = "No packages found in snapshot which provide a " <> T.pack (show toolName) <> " executable, which is a build-tool dependency of " <> T.pack (show (packageNameString pkgName))-toolWarningText (ToolWarning (ExeName toolName) pkgName (Just (option1, option2, options))) =- "Multiple packages found in snapshot which provide a " <>- T.pack (show toolName) <>- " 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: " <>- T.intercalate ", " (map packageNameText (option1:option2:options)) <>- "\nSince there's no good way to choose, you may need to install it manually." -- | Strip out anything from the @Plan@ intended for the local database stripLocals :: Plan -> Plan@@ -931,8 +904,9 @@ deriving instance Ord VersionRange --- | For display purposes only, Nothing if package not found-type LatestApplicableVersion = Maybe Version+-- | The latest applicable version and it's latest cabal file revision.+-- For display purposes only, Nothing if package not found+type LatestApplicableVersion = Maybe (Version, CabalHash) -- | Reason why a dependency was not used data BadDependency@@ -949,10 +923,11 @@ pprintExceptions :: [ConstructPlanException] -> Path Abs File+ -> Path Abs Dir -> ParentMap -> Set PackageName -> AnsiDoc-pprintExceptions exceptions stackYaml parentMap wanted =+pprintExceptions exceptions stackYaml stackRoot parentMap wanted = mconcat $ [ flow "While constructing the build plan, the following exceptions were encountered:" , line <> line@@ -962,14 +937,24 @@ , line <> line ] ++ (if not onlyHasDependencyMismatches then [] else- [ " *" <+> align (flow "Set 'allow-newer: true' to ignore all version constraints and build anyway.")+ [ " *" <+> align (flow "Set 'allow-newer: true' in " <+> toAnsiDoc (display (defaultUserConfigPath stackRoot)) <+> "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+ ] ++ addExtraDepsRecommendations++ where+ exceptions' = nubOrd exceptions++ addExtraDepsRecommendations+ | Map.null extras = []+ | (Just _) <- Map.lookup $(mkPackageName "base") extras =+ [ " *" <+> align (flow "Build requires unattainable version of base. Since base is a part of GHC, you most likely need to use a different GHC version with the matching base.")+ , line+ ]+ | otherwise = [ " *" <+> align (styleRecommendation (flow "Recommended action:") <+> flow "try adding the following to your extra-deps in" <+>@@ -978,9 +963,6 @@ , vsep (map pprintExtra (Map.toList extras)) , line ]- )- where- exceptions' = nubOrd exceptions extras = Map.unions $ map getExtras exceptions' getExtras DependencyCycleDetected{} = Map.empty@@ -989,13 +971,16 @@ Map.unions $ map go $ Map.toList m where -- TODO: Likely a good idea to distinguish these to the user. In particular, for DependencyMismatch- go (name, (_range, Just version, NotInBuildPlan)) =- Map.singleton name version- go (name, (_range, Just version, DependencyMismatch{})) =- Map.singleton name version+ go (name, (_range, Just (version,cabalHash), NotInBuildPlan)) =+ Map.singleton name (version,cabalHash)+ go (name, (_range, Just (version,cabalHash), DependencyMismatch{})) =+ Map.singleton name (version, cabalHash) go _ = Map.empty- pprintExtra (name, version) =- fromString (concat ["- ", packageNameString name, "-", versionString version])+ pprintExtra (name, (version, cabalHash)) =+ let cfInfo = CFIHash Nothing cabalHash+ packageId = PackageIdentifier name version+ packageIdRev = PackageIdentifierRevision packageId cfInfo+ in fromString $ packageIdentifierRevisionString packageIdRev allNotInBuildPlan = Set.fromList $ concatMap toNotInBuildPlan exceptions' toNotInBuildPlan (DependencyPlanFailures _ pDeps) =@@ -1076,11 +1061,11 @@ | 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 <>+ Just (laVer, _)+ | Just laVer == mversion -> softline <> flow "(latest matching version is specified)" | otherwise -> softline <>- flow "(latest matching version is" <+> styleGood (display la) <> ")"+ flow "(latest matching version is" <+> styleGood (display laVer) <> ")" -- | Get the shortest reason for the package to be in the build plan. In -- other words, trace the parent dependencies back to a 'wanted'@@ -1143,19 +1128,6 @@ , dpNameLength = dpNameLength dp + T.length (packageNameText (packageIdentifierName ident)) , dpPath = [ident] }---- Utility newtype wrapper to make make Map's Monoid also use the--- element's Monoid.--newtype MonoidMap k a = MonoidMap (Map k a)- deriving (Eq, Ord, Read, Show, Generic, Functor)--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 planDebug :: MonadIO m => String -> m ()
src/Stack/Build/Execute.hs view
@@ -11,6 +11,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TupleSections #-} -- | Perform a build module Stack.Build.Execute ( printPlan@@ -875,6 +876,12 @@ ": " <> RIO.display x +-- | How we deal with output from GHC, either dumping to a log file or the+-- console (with some prefix).+data OutputType+ = OTLogFile !(Path Abs File) !Handle+ | OTConsole !Utf8Builder+ -- | 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: --@@ -901,15 +908,14 @@ -> (ExcludeTHLoading -> [String] -> RIO env ()) -- Function to run Cabal with args -> (Text -> RIO env ()) -- An 'announce' function, for different build phases- -> Bool -- Whether output should be directed to the console- -> Maybe (Path Abs File, Handle) -- Log file+ -> OutputType -> RIO env a) -> RIO env a withSingleContext ActionContext {..} ExecuteEnv {..} task@Task {..} mdeps msuffix inner0 = withPackage $ \package cabalfp pkgDir ->- withLogFile pkgDir package $ \mlogFile ->- withCabal package pkgDir mlogFile $ \cabal ->- inner0 package cabalfp pkgDir cabal announce console mlogFile+ withOutputType pkgDir package $ \outputType ->+ withCabal package pkgDir outputType $ \cabal ->+ inner0 package cabalfp pkgDir cabal announce outputType where announce = announceTask task @@ -944,8 +950,16 @@ let cabalfp = dir </> cabalfpRel inner package cabalfp dir - withLogFile pkgDir package inner- | console = inner Nothing+ withOutputType pkgDir package inner+ -- If the user requested interleaved output, dump to the console with a+ -- prefix.+ | boptsInterleavedOutput eeBuildOpts = inner $ OTConsole $ RIO.display (packageName package) <> "> "++ -- Not in interleaved mode. When building a single wanted package, dump+ -- to the console with no prefix.+ | console = inner $ OTConsole mempty++ -- Neither condition applies, dump to a file. | otherwise = do logPath <- buildLogPath package msuffix ensureDir (parent logPath)@@ -957,15 +971,15 @@ liftIO $ atomically $ writeTChan eeLogFiles (pkgDir, logPath) _ -> return () - withBinaryFile fp WriteMode $ \h -> inner (Just (logPath, h))+ withBinaryFile fp WriteMode $ \h -> inner $ OTLogFile logPath h withCabal :: Package -> Path Abs Dir- -> Maybe (Path Abs File, Handle)+ -> OutputType -> ((ExcludeTHLoading -> [String] -> RIO env ()) -> RIO env a) -> RIO env a- withCabal package pkgDir mlogFile inner = do+ withCabal package pkgDir outputType inner = do config <- view configL unless (configAllowDifferentUser config) $@@ -1108,47 +1122,48 @@ runExe exeName fullArgs = do compilerVer <- view actualCompilerVersionL runAndOutput compilerVer `catch` \ece -> do- bss <-- case mlogFile of- Nothing -> return []- Just (logFile, h) -> do+ (mlogFile, bss) <-+ case outputType of+ OTConsole _ -> return (Nothing, [])+ OTLogFile logFile h -> do liftIO $ hClose h- withSourceFile (toFilePath logFile) $ \src ->+ fmap (Just logFile,) $ withSourceFile (toFilePath logFile) $ \src -> runConduit $ src .| CT.decodeUtf8Lenient .| mungeBuildOutput stripTHLoading makeAbsolute pkgDir compilerVer .| CL.consume- throwM $ SetupHsBuildFailure+ throwM $ CabalExitedUnsuccessfully (eceExitCode ece)- (Just taskProvides)+ taskProvides exeName fullArgs- (fmap fst mlogFile)+ mlogFile bss where runAndOutput :: CompilerVersion 'CVActual -> RIO env ()- runAndOutput compilerVer = withWorkingDir (toFilePath pkgDir) $ withProcessContext menv $ case mlogFile of- Just (_, h) ->+ runAndOutput compilerVer = withWorkingDir (toFilePath pkgDir) $ withProcessContext menv $ case outputType of+ OTLogFile _ h -> proc (toFilePath exeName) fullArgs $ runProcess_ . setStdin (byteStringInput "") . setStdout (useHandleOpen h) . setStderr (useHandleOpen h)- Nothing ->+ OTConsole prefix -> void $ sinkProcessStderrStdout (toFilePath exeName) fullArgs- (outputSink KeepTHLoading LevelWarn compilerVer)- (outputSink stripTHLoading LevelInfo compilerVer)+ (outputSink KeepTHLoading LevelWarn compilerVer prefix)+ (outputSink stripTHLoading LevelInfo compilerVer prefix) outputSink :: HasCallStack => ExcludeTHLoading -> LogLevel -> CompilerVersion 'CVActual+ -> Utf8Builder -> ConduitM S.ByteString Void (RIO env) ()- outputSink excludeTH level compilerVer =+ outputSink excludeTH level compilerVer prefix = CT.decodeUtf8Lenient .| mungeBuildOutput excludeTH makeAbsolute pkgDir compilerVer- .| CL.mapM_ (logGeneric "" level . RIO.display)+ .| CL.mapM_ (logGeneric "" level . (prefix <>) . RIO.display) -- If users want control, we should add a config option for this makeAbsolute :: ConvertPathsToAbsolute makeAbsolute = case stripTHLoading of@@ -1245,20 +1260,24 @@ where result = T.intercalate " + " $ concat [ ["lib" | taskAllInOne && hasLib]+ , ["internal-lib" | taskAllInOne && hasSubLib] , ["exe" | taskAllInOne && hasExe] , ["test" | enableTests] , ["bench" | enableBenchmarks] ]- (hasLib, hasExe) = case taskType of+ (hasLib, hasSubLib, hasExe) = case taskType of TTFiles lp Local ->- let hasLibrary =- case packageLibraries (lpPackage lp) of+ let package = lpPackage lp+ hasLibrary =+ case packageLibraries package of NoLibraries -> False HasLibraries _ -> True- in (hasLibrary, not (Set.null (exesToBuild executableBuildStatuses lp)))+ hasSubLibrary = not . Set.null $ packageInternalLibraries package+ hasExecutables = not . Set.null $ exesToBuild executableBuildStatuses lp+ in (hasLibrary, hasSubLibrary, hasExecutables) -- This isn't true, but we don't want to have this info for -- upstream deps.- _ -> (False, False)+ _ -> (False, False, False) getPrecompiled cache = case taskLocation task of@@ -1291,10 +1310,27 @@ return $ if b then Just pc else Nothing _ -> return Nothing - copyPreCompiled (PrecompiledCache mlib exes) = do+ copyPreCompiled (PrecompiledCache mlib sublibs exes) = do wc <- view $ actualCompilerVersionL.whichCompilerL announceTask task "using precompiled package"- forM_ mlib $ \libpath -> do++ -- We need to copy .conf files for the main library and all sublibraries which exist in the cache,+ -- from their old snapshot to the new one. However, we must unregister any such library in the new+ -- snapshot, in case it was built with different flags.+ let+ subLibNames = map T.unpack . Set.toList $ case taskType of+ TTFiles lp _ -> packageInternalLibraries $ lpPackage lp+ TTIndex p _ _ -> packageInternalLibraries p+ (name, version) = toTuple taskProvides+ mainLibName = packageNameString name+ mainLibVersion = versionString version+ pkgName = mainLibName ++ "-" ++ mainLibVersion+ -- z-package-z-internal for internal lib internal of package package+ toCabalInternalLibName n = concat ["z-", mainLibName, "-z-", n, "-", mainLibVersion]+ allToUnregister = map (const pkgName) (maybeToList mlib) ++ map toCabalInternalLibName subLibNames+ allToRegister = maybeToList mlib ++ sublibs++ unless (null allToRegister) $ do withMVar eeInstallLock $ \() -> do -- We want to ignore the global and user databases. -- Unfortunately, ghc-pkg doesn't take such arguments on the@@ -1306,23 +1342,17 @@ (T.pack $ toFilePathNoTrailingSep $ bcoSnapDB eeBaseConfigOpts) 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- ])++ -- first unregister everything that needs to be unregistered+ forM_ allToUnregister $ \packageName -> catchAny+ (readProcessNull ghcPkgExe [ "unregister", "--force", packageName]) (const (return ())) - void $ proc ghcPkgExe- [ "register"- , "--force"- , libpath- ]- readProcess_+ -- now, register the cached conf files+ forM_ allToRegister $ \libpath ->+ proc ghcPkgExe [ "register", "--force", libpath] readProcess_+ liftIO $ forM_ exes $ \exe -> do D.createDirectoryIfMissing True bindir let dst = bindir FP.</> FP.takeFileName exe@@ -1347,7 +1377,7 @@ bindir = toFilePath $ bcoSnapInstallRoot eeBaseConfigOpts </> bindirSuffix realConfigAndBuild cache allDepsMap = withSingleContext ac ee task (Just allDepsMap) Nothing- $ \package cabalfp pkgDir cabal announce _console _mlogFile -> do+ $ \package cabalfp pkgDir cabal announce _outputType -> do executableBuildStatuses <- getExecutableBuildStatuses package pkgDir when (not (cabalIsSatisfied executableBuildStatuses) && taskIsTarget task) (logInfo@@ -1421,7 +1451,7 @@ unless (null warnings) $ prettyWarn $ "The following modules should be added to exposed-modules or other-modules in" <+> display cabalfp <> ":" <> line <>- indent 4 (mconcat $ map showModuleWarning warnings) <>+ indent 4 (mconcat $ intersperse line $ map showModuleWarning warnings) <> line <> line <> "Missing modules in the cabal file are likely to cause undefined reference errors from the linker, along with other problems." @@ -1466,19 +1496,32 @@ ("Warning: haddock not generating hyperlinked sources because 'HsColour' not\n" <> "found on PATH (use 'stack install hscolour' to install).") return ["--hyperlink-source" | hscolourExists]++ -- For GHC 8.4 and later, provide the --quickjump option.+ actualCompiler <- view actualCompilerVersionL+ let quickjump =+ case actualCompiler of+ GhcVersion ghcVer+ | ghcVer >= $(mkVersion "8.4") -> ["--haddock-option=--quickjump"]+ _ -> []+ cabal KeepTHLoading $ concat [ ["haddock", "--html", "--hoogle", "--html-location=../$pkg-$version/"] , sourceFlag , ["--internal" | boptsHaddockInternal eeBuildOpts] , [ "--haddock-option=" <> opt | opt <- hoAdditionalArgs (boptsHaddockOpts eeBuildOpts) ]+ , quickjump ] let hasLibrary = case packageLibraries package of NoLibraries -> False HasLibraries _ -> True- shouldCopy = not isFinalBuild && (hasLibrary || not (Set.null (packageExes package)))+ packageHasComponentSet f = not $ Set.null $ f package+ hasInternalLibrary = packageHasComponentSet packageInternalLibraries+ hasExecutables = packageHasComponentSet packageExes+ shouldCopy = not isFinalBuild && (hasLibrary || hasInternalLibrary || hasExecutables) when shouldCopy $ withMVar eeInstallLock $ \() -> do announce "copy/register" eres <- try $ cabal KeepTHLoading ["copy"]@@ -1497,15 +1540,24 @@ ( bcoLocalDB eeBaseConfigOpts , eeLocalDumpPkgs ) let ident = PackageIdentifier (packageName package) (packageVersion package)- mpkgid <- case packageLibraries package of+ -- only return the sublibs to cache them if we also cache the main lib (that is, if it exists)+ (mpkgid, sublibsPkgIds) <- case packageLibraries package of HasLibraries _ -> do+ sublibsPkgIds <- fmap catMaybes $+ forM (Set.toList $ packageInternalLibraries package) $ \sublib -> do+ -- z-haddock-library-z-attoparsec for internal lib attoparsec of haddock-library+ let sublibName = T.concat ["z-", packageNameText $ packageName package, "-z-", sublib]+ case parsePackageName sublibName of+ Nothing -> return Nothing -- invalid lib, ignored+ Just subLibName -> loadInstalledPkg wc [installedPkgDb] installedDumpPkgsTVar subLibName+ mpkgid <- loadInstalledPkg wc [installedPkgDb] installedDumpPkgsTVar (packageName package) case mpkgid of Nothing -> throwM $ Couldn'tFindPkgId $ packageName package- Just pkgid -> return $ Library ident pkgid Nothing+ Just pkgid -> return (Library ident pkgid Nothing, sublibsPkgIds) NoLibraries -> do markExeInstalled (taskLocation task) taskProvides -- TODO unify somehow with writeFlagCache?- return $ Executable ident+ return (Executable ident, []) -- don't return sublibs in this case case taskLocation task of Snap ->@@ -1514,7 +1566,7 @@ (ttPackageLocation taskType) (configCacheOpts cache) (configCacheDeps cache)- mpkgid (packageExes package)+ mpkgid sublibsPkgIds (packageExes package) _ -> return () case taskType of@@ -1627,7 +1679,7 @@ -- 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 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 outputType -> do config <- view configL let needHpc = toCoverage topts @@ -1697,15 +1749,17 @@ -- Clear "Progress: ..." message before -- redirecting output.- when (isNothing mlogFile) $ do+ case outputType of+ OTConsole _ -> do logStickyDone "" liftIO $ hFlush stdout liftIO $ hFlush stderr+ OTLogFile _ _ -> pure () let output setter =- case mlogFile of- Nothing -> id- Just (_, h) -> setter (useHandleOpen h)+ case outputType of+ OTConsole _ -> id+ OTLogFile _ h -> setter (useHandleOpen h) ec <- withWorkingDir (toFilePath pkgDir) $ proc (toFilePath exePath) args $ \pc0 -> do@@ -1721,7 +1775,9 @@ waitExitCode p -- Add a trailing newline, incase the test -- output didn't finish with a newline.- when (isNothing mlogFile) (logInfo "")+ case outputType of+ OTConsole _ -> logInfo ""+ OTLogFile _ _ -> pure () -- Move the .tix file out of the package -- directory into the hpc work dir, for -- tidiness.@@ -1752,16 +1808,18 @@ generateHpcReport pkgDir package testsToRun' bs <- liftIO $- case mlogFile of- Nothing -> return ""- Just (logFile, h) -> do+ case outputType of+ OTConsole _ -> return ""+ OTLogFile logFile h -> do hClose h S.readFile $ toFilePath logFile unless (Map.null errs) $ throwM $ TestSuiteFailure (taskProvides task) errs- (fmap fst mlogFile)+ (case outputType of+ OTLogFile fp _ -> Just fp+ OTConsole _ -> Nothing) bs setTestSuccess pkgDir@@ -1777,7 +1835,7 @@ -> RIO env () singleBench beopts benchesToRun ac ee task installedMap = do (allDepsMap, _cache) <- getConfigCache ee task installedMap False True- withSingleContext 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 _outputType -> do let args = map T.unpack benchesToRun <> maybe [] ((:[]) . ("--benchmark-options=" <>)) (beoAdditionalArgs beopts)@@ -1899,19 +1957,22 @@ else return [optsFlag, baseOpts] --- Library and executable build components.+-- Library, internal and foreign libraries and executable build components. primaryComponentOptions :: Map Text ExecutableBuildStatus -> LocalPackage -> [String] primaryComponentOptions executableBuildStatuses lp = -- TODO: get this information from target parsing instead, -- which will allow users to turn off library building if -- desired- (case packageLibraries (lpPackage lp) of+ (case packageLibraries package of NoLibraries -> [] HasLibraries names -> map T.unpack- $ T.append "lib:" (packageNameText (packageName (lpPackage lp)))+ $ T.append "lib:" (packageNameText (packageName package)) : map (T.append "flib:") (Set.toList names)) +++ map (T.unpack . T.append "lib:") (Set.toList $ packageInternalLibraries package) ++ map (T.unpack . T.append "exe:") (Set.toList $ exesToBuild executableBuildStatuses lp)+ where+ package = lpPackage lp -- | History of this function: --
src/Stack/Build/Installed.hs view
@@ -16,7 +16,6 @@ import qualified Data.Foldable as F import qualified Data.HashSet as HashSet import Data.List-import qualified Data.Map.Strict as M import qualified Data.Map.Strict as Map import Path import Stack.Build.Cache@@ -75,7 +74,7 @@ loadDatabase' (Just (InstalledTo Snap, snapDBPath)) installedLibs1 (installedLibs3, localDumpPkgs) <- loadDatabase' (Just (InstalledTo Local, localDBPath)) installedLibs2- let installedLibs = M.fromList $ map lhPair installedLibs3+ let installedLibs = Map.fromList $ map lhPair installedLibs3 F.forM_ mcache $ \cache -> do icache <- configInstalledCache
src/Stack/Build/Source.hs view
@@ -214,7 +214,9 @@ case packageLibraries pkg of NoLibraries -> False HasLibraries _ -> True- in hasLibrary || not (Set.null nonLibComponents)+ in hasLibrary+ || not (Set.null nonLibComponents)+ || not (Set.null $ packageInternalLibraries pkg) filterSkippedComponents = Set.filter (not . (`elem` boptsSkipComponents bopts)) @@ -284,8 +286,8 @@ return LocalPackage { lpPackage = pkg- , lpTestDeps = packageDeps testpkg- , lpBenchDeps = packageDeps benchpkg+ , lpTestDeps = dvVersionRange <$> packageDeps testpkg+ , lpBenchDeps = dvVersionRange <$> packageDeps benchpkg , lpTestBench = btpkg , lpComponentFiles = componentFiles , lpForceDirty = boptsForceDirty bopts@@ -437,7 +439,8 @@ getPackageFilesForTargets pkg cabalFP nonLibComponents = do (components',compFiles,otherFiles,warnings) <- getPackageFiles (packageFiles pkg) cabalFP- let components = M.keysSet components' `Set.union` nonLibComponents+ let necessaryComponents = Set.insert CLib $ Set.filter isCInternalLib (M.keysSet components')+ components = necessaryComponents `Set.union` nonLibComponents componentsFiles = M.map (\files -> Set.union otherFiles (Set.map dotCabalGetPath files)) $ M.filterWithKey (\component _ -> component `Set.member` components) compFiles
src/Stack/Build/Target.hs view
@@ -71,6 +71,7 @@ ) where import Stack.Prelude+import qualified Data.HashMap.Strict as HashMap import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.Text as T@@ -342,7 +343,7 @@ } where getLatestVersion pn =- fmap fst . Set.maxView <$> getPackageVersions pn+ fmap fst . Set.maxView . Set.fromList . HashMap.keys <$> getPackageVersions pn go (RTPackageIdentifier ident@(PackageIdentifier name version)) | Map.member name locals = return $ Left $ T.concat
src/Stack/BuildPlan.hs view
@@ -20,7 +20,6 @@ , gpdPackages , removeSrcPkgDefaultFlags , selectBestSnapshot- , getToolMap , showItems ) where @@ -36,10 +35,8 @@ import qualified Distribution.Package as C import Distribution.PackageDescription (GenericPackageDescription, flagDefault, flagManual,- flagName, genPackageFlags,- condExecutables)+ flagName, genPackageFlags) import qualified Distribution.PackageDescription as C-import qualified Distribution.Types.UnqualComponentName as C import Distribution.System (Platform) import Distribution.Text (display) import qualified Distribution.Version as C@@ -49,7 +46,6 @@ 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@@ -144,47 +140,6 @@ "Failed to load custom snapshot at " ++ T.unpack url ++ ", because no 'compiler' or 'resolver' is specified."---- | Map from tool name to package providing it. This accounts for--- both snapshot and local packages (deps and project packages).-getToolMap :: LoadedSnapshot- -> LocalPackages- -> Map ExeName (Set PackageName)-getToolMap ls locals =-- {- We no longer do this, following discussion at:-- https://github.com/commercialhaskell/stack/issues/308#issuecomment-112076704-- -- First grab all of the package names, for times where a build tool is- -- identified by package name- $ Map.fromList (map (packageNameByteString &&& Set.singleton) (Map.keys ps))- -}-- Map.unionsWith Set.union $ concat- [ concatMap goSnap $ Map.toList $ lsPackages ls- , concatMap goLocalProj $ Map.toList $ lpProject locals- , concatMap goLocalDep $ Map.toList $ lpDependencies locals- ]- where- goSnap (pname, lpi) =- map (flip Map.singleton (Set.singleton pname))- $ Set.toList- $ lpiProvidedExes lpi-- goLocalProj (pname, lpv) =- map (flip Map.singleton (Set.singleton pname))- [ExeName t | CExe t <- Set.toList (lpvComponents lpv)]-- goLocalDep (pname, (gpd, _loc)) =- map (flip Map.singleton (Set.singleton pname))- $ gpdExes gpd-- -- TODO consider doing buildable checking. Not a big deal though:- -- worse case scenario is we build an extra package that wasn't- -- strictly needed.- gpdExes :: GenericPackageDescription -> [ExeName]- gpdExes = map (ExeName . T.pack . C.unUnqualComponentName . fst) . condExecutables gpdPackages :: [GenericPackageDescription] -> Map PackageName Version gpdPackages gpds = Map.fromList $
src/Stack/Config.hs view
@@ -51,8 +51,11 @@ import Stack.Prelude import Data.Aeson.Extended import qualified Data.ByteString as S+import Data.Coerce (coerce) import qualified Data.IntMap as IntMap import qualified Data.Map as Map+import qualified Data.Monoid+import Data.Monoid.Map (MonoidMap(..)) import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8) import qualified Data.Yaml as Yaml@@ -62,9 +65,7 @@ import Distribution.Version (simplifyVersionRange, mkVersion') import GHC.Conc (getNumProcessors) import Lens.Micro (lens, set)-import Network.HTTP.Client (parseUrlThrow)-import Network.HTTP.StackClient (httpJSON)-import Network.HTTP.Simple (getResponseBody)+import Network.HTTP.StackClient (httpJSON, parseUrlThrow, getResponseBody) import Options.Applicative (Parser, strOption, long, help) import Path import Path.Extra (toFilePathNoTrailingSep)@@ -360,8 +361,8 @@ let configTemplateParams = configMonoidTemplateParameters configScmInit = getFirst configMonoidScmInit- configGhcOptionsByName = configMonoidGhcOptionsByName- configGhcOptionsByCat = configMonoidGhcOptionsByCat+ configGhcOptionsByName = coerce configMonoidGhcOptionsByName+ configGhcOptionsByCat = coerce configMonoidGhcOptionsByCat configSetupInfoLocations = configMonoidSetupInfoLocations configPvpBounds = fromFirst (PvpBounds PvpBoundsNone False) configMonoidPvpBounds configModifyCodePage = fromFirst True configMonoidModifyCodePage@@ -372,6 +373,7 @@ configDefaultTemplate = getFirst configMonoidDefaultTemplate configDumpLogs = fromFirst DumpWarningLogs configMonoidDumpLogs configSaveHackageCreds = fromFirst True configMonoidSaveHackageCreds+ configHackageBaseUrl = fromFirst "https://hackage.haskell.org/" configMonoidHackageBaseUrl clIgnoreRevisionMismatch = fromFirst False configMonoidIgnoreRevisionMismatch configAllowDifferentUser <-@@ -964,4 +966,5 @@ , "# author-email:" , "# copyright:" , "# github-username:"+ , "" ]
src/Stack/Config/Build.hs view
@@ -72,6 +72,9 @@ (boptsSplitObjs defaultBuildOpts) buildMonoidSplitObjs , boptsSkipComponents = buildMonoidSkipComponents+ , boptsInterleavedOutput = fromFirst+ (boptsInterleavedOutput defaultBuildOpts)+ buildMonoidInterleavedOutput } where -- These options are not directly used in bopts, instead they
src/Stack/Config/Nix.hs view
@@ -27,8 +27,7 @@ -> OS -> RIO env NixOpts nixOptsFromMonoid NixOptsMonoid{..} os = do- let nixEnable0 = fromFirst False nixMonoidEnable- defaultPure = case os of+ let defaultPure = case os of OSX -> False _ -> True nixPureShell = fromFirst defaultPure nixMonoidPureShell@@ -38,14 +37,14 @@ ++ prefixAll (T.pack "-I") (fromFirst [] nixMonoidPath) nixAddGCRoots = fromFirst False nixMonoidAddGCRoots + -- Enable Nix-mode by default on NixOS, unless Docker-mode was specified osIsNixOS <- isNixOS+ let nixEnable0 = fromFirst osIsNixOS nixMonoidEnable+ 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) $@@ -56,23 +55,28 @@ nixCompiler :: CompilerVersion a -> Either StringException T.Text nixCompiler compilerVersion =- let -- These are the latest minor versions for each respective major version available in nixpkgs- fixMinor "8.2" = "8.2.1"- fixMinor "8.0" = "8.0.2"- fixMinor "7.10" = "7.10.3"- fixMinor "7.8" = "7.8.4"- fixMinor "7.6" = "7.6.3"- fixMinor "7.4" = "7.4.2"- fixMinor "7.2" = "7.2.2"- fixMinor "6.12" = "6.12.3"- fixMinor "6.10" = "6.10.4"- fixMinor v = v- nixCompilerFromVersion v = T.append (T.pack "haskell.compiler.ghc")- (T.filter (/= '.')- (fixMinor (versionText v)))- in case compilerVersion of- GhcVersion v -> Right $ nixCompilerFromVersion v- _ -> Left $ stringException "Only GHC is supported by stack --nix"+ case compilerVersion of+ GhcVersion version ->+ case T.split (== '.') (versionText version) of+ x : y : minor ->+ Right $+ case minor of+ [] ->+ -- The minor version is not specified. Select the latest minor+ -- version in Nixpkgs corresponding to the requested major+ -- version.+ let major = T.concat [x, y] in+ "(let compilers = builtins.filter \+ \(name: builtins.match \+ \\"ghc" <> major <> "[[:digit:]]*\" name != null) \+ \(lib.attrNames haskell.compiler); in \+ \if compilers == [] \+ \then abort \"No compiler found for GHC "+ <> versionText version <> "\"\+ \else haskell.compiler.${builtins.head compilers})"+ _ -> "haskell.compiler.ghc" <> T.concat (x : y : minor)+ _ -> Left $ stringException "GHC major version not specified"+ _ -> Left $ stringException "Only GHC is supported by stack --nix" -- Exceptions thown specifically by Stack.Nix data StackNixException
src/Stack/Constants/Config.hs view
@@ -15,6 +15,7 @@ , hpcRelativeDir , hpcDirFromDir , objectInterfaceDirL+ , ghciDirL , templatesDir ) where @@ -32,11 +33,18 @@ root = view projectRootL env in root </> workDir </> $(mkRelDir "odir/") +-- | GHCi files directory.+ghciDirL :: HasBuildConfig env => Getting r env (Path Abs Dir)+ghciDirL = to $ \env -> -- FIXME is this idomatic lens code?+ let workDir = view workDirL env+ root = view projectRootL env+ in root </> workDir </> $(mkRelDir "ghci/")+ -- | The directory containing the files used for dirtiness check of source files. buildCachesDir :: (MonadThrow m, MonadReader env m, HasEnvConfig env) => Path Abs Dir -- ^ Package directory. -> m (Path Abs Dir)-buildCachesDir dir = +buildCachesDir dir = liftM (</> $(mkRelDir "stack-build-caches")) (distDirFromDir dir)
src/Stack/Coverage.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -7,6 +7,8 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TupleSections #-}+ -- | Generate HPC (Haskell Program Coverage) reports module Stack.Coverage ( deleteHpcReports@@ -23,6 +25,7 @@ import qualified Data.ByteString.Lazy as BL import Data.List import qualified Data.Map.Strict as Map+import qualified Data.Set as Set import qualified Data.Text as T import qualified Data.Text.IO as T import qualified Data.Text.Lazy as LT@@ -106,23 +109,24 @@ case packageLibraries package of NoLibraries -> False HasLibraries _ -> True+ internalLibs = packageInternalLibraries package eincludeName <- -- Pre-7.8 uses plain PKG-version in tix files.- if ghcVersion < $(mkVersion "7.10") then return $ Right $ Just pkgId+ if ghcVersion < $(mkVersion "7.10") then return $ Right $ Just [pkgId] -- We don't expect to find a package key if there is no library.- else if not hasLibrary then return $ Right Nothing+ else if not hasLibrary && Set.null internalLibs then return $ Right Nothing -- Look in the inplace DB for the package key. -- See https://github.com/commercialhaskell/stack/issues/1181#issuecomment-148968986 else do -- GHC 8.0 uses package id instead of package key. -- See https://github.com/commercialhaskell/stack/issues/2424 let hpcNameField = if ghcVersion >= $(mkVersion "8.0") then "id" else "key"- eincludeName <- findPackageFieldForBuiltPackage pkgDir (packageIdentifier package) hpcNameField+ eincludeName <- findPackageFieldForBuiltPackage pkgDir (packageIdentifier package) internalLibs hpcNameField case eincludeName of Left err -> do logError $ RIO.display err return $ Left err- Right includeName -> return $ Right $ Just $ T.unpack includeName+ Right includeNames -> return $ Right $ Just $ map T.unpack includeNames forM_ tests $ \testName -> do tixSrc <- tixFilePath (packageName package) (T.unpack testName) let report = "coverage report for " <> pkgName <> "'s test-suite \"" <> testName <> "\""@@ -133,7 +137,7 @@ -- #634 - this will likely be customizable in the future) Right mincludeName -> do let extraArgs = case mincludeName of- Just includeName -> ["--include", includeName ++ ":"]+ Just includeNames -> "--include" : intersperse "--include" (map (\n -> n ++ ":") includeNames) Nothing -> [] mreportPath <- generateHpcReportInternal tixSrc reportDir report extraArgs extraArgs forM_ mreportPath (displayReportPath report . display)@@ -168,13 +172,13 @@ -- Look for index files in the correct dir (relative to each pkgdir). ["--hpcdir", toFilePathNoTrailingSep hpcRelDir, "--reset-hpcdirs"] logInfo $ "Generating " <> RIO.display report- outputLines <- liftM (map (S8.filter (/= '\r')) . S8.lines . BL.toStrict) $+ outputLines <- liftM (map (S8.filter (/= '\r')) . S8.lines . BL.toStrict . fst) $ proc "hpc" ( "report" : toFilePath tixSrc : (args ++ extraReportArgs) )- readProcessStdout_+ readProcess_ if all ("(0/0)" `S8.isSuffixOf`) outputLines then do let msg html =@@ -202,7 +206,7 @@ : ("--destdir=" ++ toFilePathNoTrailingSep reportDir) : (args ++ extraMarkupArgs) )- readProcessStdout_+ readProcess_ return (Just reportPath) data HpcReportOpts = HpcReportOpts@@ -425,9 +429,9 @@ findPackageFieldForBuiltPackage :: HasEnvConfig env- => Path Abs Dir -> PackageIdentifier -> Text- -> RIO env (Either Text Text)-findPackageFieldForBuiltPackage pkgDir pkgId field = do+ => Path Abs Dir -> PackageIdentifier -> Set.Set Text -> Text+ -> RIO env (Either Text [Text])+findPackageFieldForBuiltPackage pkgDir pkgId internalLibs field = do distDir <- distDirFromDir pkgDir let inplaceDir = distDir </> $(mkRelDir "package.conf.inplace") pkgIdStr = packageIdentifierString pkgId@@ -440,20 +444,42 @@ cabalVer <- view cabalVersionL if cabalVer < $(mkVersion "1.24") then do+ -- here we don't need to handle internal libs path <- liftM (inplaceDir </>) $ parseRelFile (pkgIdStr ++ "-inplace.conf") logDebug $ "Parsing config in Cabal < 1.24 location: " <> fromString (toFilePath path) exists <- doesFileExist path- if exists then extractField path else notFoundErr+ if exists then fmap (:[]) <$> extractField path else notFoundErr else do -- With Cabal-1.24, it's in a different location. logDebug $ "Scanning " <> fromString (toFilePath inplaceDir) <> " for files matching " <> fromString pkgIdStr (_, files) <- handleIO (const $ return ([], [])) $ listDir inplaceDir logDebug $ displayShow files- case mapMaybe (\file -> fmap (const file) . (T.stripSuffix ".conf" <=< T.stripPrefix (T.pack (pkgIdStr ++ "-")))- . T.pack . toFilePath . filename $ file) files of+ -- From all the files obtained from the scanning process above, we+ -- need to identify which are .conf files and then ensure that+ -- there is at most one .conf file for each library and internal+ -- library (some might be missing if that component has not been+ -- built yet). We should error if there are more than one .conf+ -- file for a component or if there are no .conf files at all in+ -- the searched location.+ let toFilename = T.pack . toFilePath . filename+ -- strip known prefix and suffix from the found files to determine only the conf files+ stripKnown = T.stripSuffix ".conf" <=< T.stripPrefix (T.pack (pkgIdStr ++ "-"))+ stripped = mapMaybe (\file -> fmap (,file) . stripKnown . toFilename $ file) files+ -- which component could have generated each of these conf files+ stripHash n = let z = T.dropWhile (/= '-') n in if T.null z then "" else T.tail z+ matchedComponents = map (\(n, f) -> (stripHash n, [f])) stripped+ byComponents = Map.restrictKeys (Map.fromListWith (++) matchedComponents) $ Set.insert "" internalLibs+ logDebug $ displayShow byComponents+ if Map.null $ Map.filter (\fs -> length fs > 1) byComponents+ then case concat $ Map.elems byComponents of [] -> notFoundErr- [path] -> extractField path- _ -> return $ Left $ "Multiple files matching " <> T.pack (pkgIdStr ++ "-*.conf") <> " found in " <>+ -- for each of these files, we need to extract the requested field+ paths -> do+ (errors, keys) <- partitionEithers <$> traverse extractField paths+ case errors of+ (a:_) -> return $ Left a -- the first error only, since they're repeated anyway+ [] -> return $ Right keys+ else return $ Left $ "Multiple files matching " <> T.pack (pkgIdStr ++ "-*.conf") <> " found in " <> T.pack (toFilePath inplaceDir) <> ". Maybe try 'stack clean' on this package?" displayReportPath :: (HasRunner env)
src/Stack/Docker.hs view
@@ -243,8 +243,8 @@ (env,isStdinTerminal,isStderrTerminal,homeDir) <- liftIO $ (,,,) <$> getEnvironment- <*> hIsTerminalDevice stdin- <*> hIsTerminalDevice stderr+ <*> hIsTerminalDeviceOrMinTTY stdin+ <*> hIsTerminalDeviceOrMinTTY stderr <*> (parseAbsDir =<< getHomeDirectory) isStdoutTerminal <- view terminalL let dockerHost = lookup "DOCKER_HOST" env
src/Stack/Fetch.hs view
@@ -377,9 +377,13 @@ -> RIO env (Maybe ByteString) lookupPackageIdentifierExact identRev cache = do cl <- view cabalLoaderL- forM (lookupResolvedPackage cl identRev cache) $ \rp -> do- [bs] <- withCabalFiles (indexName (rpIndex rp)) [(rp, ())] $ \_ _ bs -> return bs- return bs+ case lookupResolvedPackage cl identRev cache of+ Nothing -> return Nothing+ Just rp -> do+ bss <- withCabalFiles (indexName (rpIndex rp)) [(rp, ())] $ \_ _ bs -> return bs+ case bss of+ [bs] -> return (Just bs)+ _ -> return Nothing data FuzzyResults = FRNameNotFound !(Maybe (NonEmpty T.Text))
src/Stack/FileWatch.hs view
@@ -35,7 +35,7 @@ -> IO () fileWatchConf cfg out inner = withManagerConf cfg $ \manager -> do let putLn = hPutStrLn out- outputIsTerminal <- hIsTerminalDevice out+ outputIsTerminal <- hIsTerminalDeviceOrMinTTY out let withColor color str = putLn $ do if outputIsTerminal then concat [color, str, reset]
src/Stack/GhcPkg.hs view
@@ -71,9 +71,9 @@ go Right _ -> return eres where- go = fmap (fmap BL.toStrict)- $ tryAny- $ proc (ghcPkgExeName wc) args' readProcessStdout_+ go = tryAny+ $ BL.toStrict . fst+ <$> proc (ghcPkgExeName wc) args' readProcess_ args' = packageDbFlags pkgDbs ++ args -- | Create a package database in the given directory, if it doesn't exist.@@ -102,7 +102,7 @@ ensureDir (parent db) return ["init", toFilePath db] void $ proc (ghcPkgExeName wc) args $ \pc ->- readProcessStdout_ pc `onException`+ readProcess_ pc `onException` logError ("Unable to create package database at " <> fromString (toFilePath db)) -- | Get the name to use for "ghc-pkg", given the compiler version.
src/Stack/Ghci.hs view
@@ -51,7 +51,7 @@ import Stack.Types.PackageIdentifier import Stack.Types.PackageName import Stack.Types.Runner-import System.IO (putStrLn, putStr, getLine)+import System.IO (putStrLn) import System.IO.Temp (getCanonicalTemporaryDirectory) #ifndef WINDOWS@@ -87,6 +87,13 @@ , ghciPkgPackage :: !Package } deriving Show +-- | Loaded package description and related info.+data GhciPkgDesc = GhciPkgDesc+ { ghciDescPkg :: !Package+ , ghciDescCabalFp :: !(Path Abs File)+ , ghciDescTarget :: !Target+ }+ -- 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@@ -154,15 +161,31 @@ nonLocalTargets <- getAllNonLocalTargets inputTargets -- Check if additional package arguments are sensible. addPkgs <- checkAdditionalPackages ghciAdditionalPackages+ -- Load package descriptions.+ pkgDescs <- loadGhciPkgDescs buildOptsCLI localTargets+ -- If necessary, ask user about which main module to load.+ bopts <- view buildOptsL+ mainFile <-+ if ghciNoLoadModules+ then return Nothing+ else do+ -- Figure out package files, in order to ask the user+ -- about which main module to load. See the note below for+ -- why this is done again after the build. This could+ -- potentially be done more efficiently, because all we+ -- need is the location of main modules, not the rest.+ pkgs0 <- getGhciPkgInfos sourceMap addPkgs (fmap fst mfileTargets) pkgDescs+ figureOutMainFile bopts mainIsTargets localTargets pkgs0 -- Build required dependencies and setup local packages. stackYaml <- view stackYamlL buildDepsAndInitialSteps opts (map (packageNameText . fst) localTargets) targetWarnings stackYaml localTargets nonLocalTargets mfileTargets- -- Load the list of modules _after_ building, to catch changes in unlisted dependencies (#1180)- pkgs <- getGhciPkgInfos buildOptsCLI sourceMap addPkgs (fmap fst mfileTargets) localTargets+ -- Load the list of modules _after_ building, to catch changes in+ -- unlisted dependencies (#1180)+ pkgs <- getGhciPkgInfos sourceMap addPkgs (fmap fst mfileTargets) pkgDescs checkForIssues pkgs -- Finally, do the invocation of ghci- runGhci opts localTargets mainIsTargets pkgs (maybe [] snd mfileTargets) (nonLocalTargets ++ addPkgs)+ runGhci opts localTargets mainFile pkgs (maybe [] snd mfileTargets) (nonLocalTargets ++ addPkgs) preprocessTargets :: HasEnvConfig env => BuildOptsCLI -> [Text] -> RIO env (Either [Path Abs File] (Map PackageName Target)) preprocessTargets buildOptsCLI rawTargets = do@@ -321,12 +344,12 @@ :: HasEnvConfig env => GhciOpts -> [(PackageName, (Path Abs File, Target))]- -> Maybe (Map PackageName Target)+ -> Maybe (Path Abs File) -> [GhciPkgInfo] -> [Path Abs File] -> [PackageName] -> RIO env ()-runGhci GhciOpts{..} targets mainIsTargets pkgs extraFiles exposePackages = do+runGhci GhciOpts{..} targets mainFile pkgs extraFiles exposePackages = do config <- view configL wc <- view $ actualCompilerVersionL.whichCompilerL let pkgopts = hidePkgOpts ++ genOpts ++ ghcOpts@@ -398,20 +421,20 @@ tmpDirectory <- (</> $(mkRelDir "haskell-stack-ghci")) <$> (parseAbsDir =<< liftIO getCanonicalTemporaryDirectory)+ ghciDir <- view ghciDirL+ ensureDir ghciDir ensureDir tmpDirectory- macrosOptions <- writeMacrosFile tmpDirectory pkgs+ macrosOptions <- writeMacrosFile ghciDir 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 :: HasRunner env => Path Abs Dir -> [GhciPkgInfo] -> RIO env [String]-writeMacrosFile tmpDirectory pkgs = do+writeMacrosFile outputDirectory pkgs = do fps <- fmap (nubOrd . catMaybes . concat) $ forM pkgs $ \pkg -> forM (ghciPkgOpts pkg) $ \(_, bio) -> do let cabalMacros = bioCabalMacros bio@@ -423,22 +446,22 @@ return Nothing files <- liftIO $ mapM (S8.readFile . toFilePath) fps if null files then return [] else do- out <- liftIO $ writeHashedFile tmpDirectory $(mkRelFile "cabal_macros.h") $+ out <- liftIO $ writeHashedFile outputDirectory $(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 [String]-writeGhciScript tmpDirectory script = do- scriptPath <- liftIO $ writeHashedFile tmpDirectory $(mkRelFile "ghci-script") $+writeGhciScript outputDirectory script = do+ scriptPath <- liftIO $ writeHashedFile outputDirectory $(mkRelFile "ghci-script") $ LBS.toStrict $ scriptToLazyByteString script let scriptFilePath = toFilePath scriptPath setScriptPerms scriptFilePath return ["-ghci-script=" <> scriptFilePath] writeHashedFile :: Path Abs Dir -> Path Rel File -> ByteString -> IO (Path Abs File)-writeHashedFile tmpDirectory relFile contents = do+writeHashedFile outputDirectory relFile contents = do relSha <- shaPathForBytes contents- let outDir = tmpDirectory </> relSha+ let outDir = outputDirectory </> relSha outFile = outDir </> relFile alreadyExists <- doesFileExist outFile unless alreadyExists $ do@@ -472,9 +495,8 @@ getFileTargets :: [GhciPkgInfo] -> [Path Abs File] getFileTargets = concatMap (concatMap S.toList . maybeToList . ghciPkgTargetFiles) --- | Figure out the main-is file to load based on the targets. Sometimes there--- is none, sometimes it's unambiguous, sometimes it's--- ambiguous. Warns and returns nothing if it's ambiguous.+-- | Figure out the main-is file to load based on the targets. Asks the+-- user for input if there is more than one candidate main-is file. figureOutMainFile :: HasRunner env => BuildOpts@@ -530,11 +552,10 @@ T.pack (toFilePath mainIs) candidateIndices = take (length candidates) [1 :: Int ..] userOption = do- putStr "Specify main module to use (press enter to load none): "- option <- getLine+ option <- prompt "Specify main module to use (press enter to load none): " let selected = fromMaybe ((+1) $ length candidateIndices)- (readMaybe option :: Maybe Int)+ (readMaybe (T.unpack option) :: Maybe Int) case elemIndex selected candidateIndices of Nothing -> do putStrLn@@ -561,41 +582,24 @@ sampleMainIsArg (pkg,comp,_) = "--main-is " <> packageNameText pkg <> ":" <> renderComp comp -getGhciPkgInfos+loadGhciPkgDescs :: HasEnvConfig env => BuildOptsCLI- -> SourceMap- -> [PackageName]- -> Maybe (Map PackageName (Set (Path Abs File))) -> [(PackageName, (Path Abs File, Target))]- -> RIO env [GhciPkgInfo]-getGhciPkgInfos buildOptsCLI sourceMap addPkgs mfileTargets localTargets = do- (installedMap, _, _, _) <- getInstalled- GetInstalledOpts- { getInstalledProfiling = False- , getInstalledHaddock = False- , getInstalledSymbols = False- }- sourceMap- let localLibs = [name | (name, (_, target)) <- localTargets, hasLocalComp isCLib target]+ -> RIO env [GhciPkgDesc]+loadGhciPkgDescs buildOptsCLI localTargets = forM localTargets $ \(name, (cabalfp, target)) ->- makeGhciPkgInfo buildOptsCLI sourceMap installedMap localLibs addPkgs mfileTargets name cabalfp target+ loadGhciPkgDesc buildOptsCLI name cabalfp target --- | Make information necessary to load the given package in GHCi.-makeGhciPkgInfo+-- | Load package description information for a ghci target.+loadGhciPkgDesc :: HasEnvConfig env => BuildOptsCLI- -> SourceMap- -> InstalledMap- -> [PackageName]- -> [PackageName]- -> Maybe (Map PackageName (Set (Path Abs File))) -> PackageName -> Path Abs File -> Target- -> RIO env GhciPkgInfo-makeGhciPkgInfo buildOptsCLI sourceMap installedMap locals addPkgs mfileTargets name cabalfp target = do- bopts <- view buildOptsL+ -> RIO env GhciPkgDesc+loadGhciPkgDesc buildOptsCLI name cabalfp target = do econfig <- view envConfigL bconfig <- view buildConfigL compilerVersion <- view actualCompilerVersionL@@ -633,7 +637,51 @@ (C.updatePackageDescription bi x) (C.updatePackageDescription bi y)) mbuildinfo+ return GhciPkgDesc+ { ghciDescPkg = pkg+ , ghciDescCabalFp = cabalfp+ , ghciDescTarget = target+ } +getGhciPkgInfos+ :: HasEnvConfig env+ => SourceMap+ -> [PackageName]+ -> Maybe (Map PackageName (Set (Path Abs File)))+ -> [GhciPkgDesc]+ -> RIO env [GhciPkgInfo]+getGhciPkgInfos sourceMap addPkgs mfileTargets localTargets = do+ (installedMap, _, _, _) <- getInstalled+ GetInstalledOpts+ { getInstalledProfiling = False+ , getInstalledHaddock = False+ , getInstalledSymbols = False+ }+ sourceMap+ let localLibs =+ [ packageName (ghciDescPkg desc)+ | desc <- localTargets+ , hasLocalComp isCLib (ghciDescTarget desc)+ ]+ forM localTargets $ \pkgDesc ->+ makeGhciPkgInfo sourceMap installedMap localLibs addPkgs mfileTargets pkgDesc++-- | Make information necessary to load the given package in GHCi.+makeGhciPkgInfo+ :: HasEnvConfig env+ => SourceMap+ -> InstalledMap+ -> [PackageName]+ -> [PackageName]+ -> Maybe (Map PackageName (Set (Path Abs File)))+ -> GhciPkgDesc+ -> RIO env GhciPkgInfo+makeGhciPkgInfo sourceMap installedMap locals addPkgs mfileTargets pkgDesc = do+ bopts <- view buildOptsL+ let pkg = ghciDescPkg pkgDesc+ cabalfp = ghciDescCabalFp pkgDesc+ target = ghciDescTarget pkgDesc+ name = packageName pkg (mods,files,opts) <- getPackageOpts (packageOpts pkg) sourceMap installedMap locals addPkgs cabalfp let filteredOpts = filterWanted opts filterWanted = M.filterWithKey (\k _ -> k `S.member` allWanted)@@ -641,7 +689,7 @@ setMapMaybe f = S.fromList . mapMaybe f . S.toList return GhciPkgInfo- { ghciPkgName = packageName pkg+ { ghciPkgName = name , ghciPkgOpts = M.toList filteredOpts , ghciPkgDir = parent cabalfp , ghciPkgModules = unionModuleMaps $@@ -661,8 +709,9 @@ wantedPackageComponents bopts (TargetAll ProjectPackage) pkg = S.fromList $ (case packageLibraries pkg of NoLibraries -> []- HasLibraries _names -> [CLib]) ++ -- FIXME. This ignores sub libraries and foreign libraries. Is that OK?+ HasLibraries names -> CLib : map CInternalLib (S.toList names)) ++ map CExe (S.toList (packageExes pkg)) <>+ map CInternalLib (S.toList $ packageInternalLibraries pkg) <> (if boptsTests bopts then map CTest (M.keys (packageTests pkg)) else []) <> (if boptsBenchmarks bopts then map CBench (S.toList (packageBenchmarks pkg)) else []) wantedPackageComponents _ _ _ = S.empty
src/Stack/Hoogle.hs view
@@ -164,7 +164,7 @@ Right hooglePath -> do result <- withProcessContext menv $ proc hooglePath ["--numeric-version"]- $ tryAny . readProcessStdout_+ $ tryAny . fmap fst . readProcess_ let unexpectedResult got = Left $ T.concat [ "'" , T.pack hooglePath
src/Stack/Init.hs view
@@ -185,6 +185,7 @@ <> F.foldMap (goComment o) comments <> goOthers (o `HM.difference` HM.fromList comments) <> B.byteString footerHelp+ <> "\n" goComment o (name, comment) = case (convert <$> HM.lookup name o) <|> nonPresentValue name of@@ -261,7 +262,6 @@ , "resolver: lts-3.5" , "resolver: nightly-2015-09-21" , "resolver: ghc-7.10.2"- , "resolver: ghcjs-0.1.0_ghc-7.10.2" , "" , "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."
src/Stack/Ls.hs view
@@ -24,11 +24,8 @@ 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 Network.HTTP.StackClient (httpJSON, getGlobalManager, addRequestHeader, getResponseBody, parseRequest,+ setRequestManager, hAccept) import qualified Options.Applicative as OA import Options.Applicative ((<|>)) import Path@@ -39,7 +36,6 @@ import System.Process.PagerEditor (pageText) import System.Directory (listDirectory) import System.IO (stderr, hPutStrLn)-import Network.HTTP.Client.TLS (getGlobalManager) data LsView = Local
src/Stack/New.hs view
@@ -12,33 +12,26 @@ module Stack.New ( new , NewOpts(..)- , defaultTemplateName- , templateNameArgument- , getTemplates , TemplateName- , listTemplates)- where+ , templatesHelp+ ) where import Stack.Prelude import Control.Monad.Trans.Writer.Strict-import Data.Aeson-import Data.Aeson.Types-import qualified Data.ByteString as SB+import Control.Monad (void) import qualified Data.ByteString.Lazy as LB import Data.Conduit-import qualified Data.HashMap.Strict as HM import Data.List 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.Encoding as T-import qualified Data.Text.Encoding.Error as T (lenientDecode)-import qualified Data.Text.IO as T+import qualified Data.Text.Lazy.Encoding as TLE import Data.Time.Calendar import Data.Time.Clock-import qualified Data.Yaml as Yaml import Network.HTTP.Download-import Network.HTTP.Simple (Request, HttpException, getResponseStatusCode, getResponseBody)+import Network.HTTP.StackClient (Request, HttpException, getResponseStatusCode, getResponseBody) import Path import Path.IO import Stack.Constants@@ -49,7 +42,6 @@ import RIO.Process import qualified Text.Mustache as Mustache import qualified Text.Mustache.Render as Mustache-import Text.Printf import Text.ProjectTemplate --------------------------------------------------------------------------------@@ -126,10 +118,7 @@ templateDir <- view $ configL.to templatesDir case templatePath name of AbsPath absFile -> logIt LocalTemp >> loadLocalFile absFile- UrlPath s -> do- req <- parseRequest s- let rel = fromMaybe backupUrlRelPath (parseRelFile s)- downloadTemplate req (templateDir </> rel)+ UrlPath s -> downloadFromUrl s templateDir RelPath relFile -> catch (do f <- loadLocalFile relFile@@ -141,6 +130,10 @@ (templateDir </> relFile) Nothing -> throwM e )+ RepoPath rtp -> do+ let url = urlFromRepoTemplatePath rtp+ downloadFromUrl (T.unpack url) templateDir+ where loadLocalFile :: Path b File -> RIO env Text loadLocalFile path = do@@ -148,20 +141,46 @@ <> "\"") exists <- doesFileExist path if exists- then liftIO (fmap (T.decodeUtf8With T.lenientDecode) (SB.readFile (toFilePath path)))+ then readFileUtf8 (toFilePath path) else throwM (FailedToLoadTemplate name (toFilePath path))- relRequest :: MonadThrow n => Path Rel File -> n Request- relRequest rel = parseRequest (defaultTemplateUrl <> "/" <> toFilePath rel)+ relRequest :: Path Rel File -> Maybe Request+ relRequest rel = do+ rtp <- parseRepoPathWithService defaultRepoService (T.pack (toFilePath rel))+ let url = urlFromRepoTemplatePath rtp+ parseRequest (T.unpack url)+ downloadFromUrl :: String -> Path Abs Dir -> RIO env Text+ downloadFromUrl s templateDir = do+ req <- parseRequest s+ let rel = fromMaybe backupUrlRelPath (parseRelFile s)+ downloadTemplate req (templateDir </> rel) downloadTemplate :: Request -> Path Abs File -> RIO env Text downloadTemplate req path = do logIt RemoteTemp- _ <-- catch- (redownload req path)- (throwM . FailedToDownloadTemplate name)+ catch+ (void $ redownload req path)+ (useCachedVersionOrThrow path)+ loadLocalFile path+ useCachedVersionOrThrow :: Path Abs File -> DownloadException -> RIO env ()+ useCachedVersionOrThrow path exception = do+ exists <- doesFileExist path++ if exists+ then do logWarn "Tried to download the template but an error was found."+ logWarn "Using cached local version. It may not be the most recent version though."+ else throwM (FailedToDownloadTemplate name exception)+ backupUrlRelPath = $(mkRelFile "downloaded.template.file.hsfiles") +-- | Construct a URL for downloading from a repo.+urlFromRepoTemplatePath :: RepoTemplatePath -> Text+urlFromRepoTemplatePath (RepoTemplatePath Github user name) =+ T.concat ["https://raw.githubusercontent.com", "/", user, "/stack-templates/master/", name]+urlFromRepoTemplatePath (RepoTemplatePath Gitlab user name) =+ T.concat ["https://gitlab.com", "/", user, "/stack-templates/raw/master/", name]+urlFromRepoTemplatePath (RepoTemplatePath Bitbucket user name) =+ T.concat ["https://bitbucket.org", "/", user, "/stack-templates/raw/master/", name]+ -- | Apply and unpack a template into a directory. applyTemplate :: HasConfig env@@ -186,17 +205,9 @@ , ("name-as-module", nameAsModule) ] configParams = configTemplateParams config 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" <> displayShow (MissingParameters project template missingKeys (configUserConfigPath config)) <> "\n")) files :: Map FilePath LB.ByteString <- catch (execWriterT $ runConduit $- yield (T.encodeUtf8 applied) .|+ yield (T.encodeUtf8 templateText) .| unpackTemplate receiveMem id ) (\(e :: ProjectTemplateException) ->@@ -208,12 +219,36 @@ unless (any isPkgSpec . M.keys $ files) $ throwM (InvalidTemplate template "Template does not contain a .cabal \ \or package.yaml file")++ -- Apply Mustache templating to a single file within the project+ -- template.+ let applyMustache bytes+ -- Workaround for performance problems with mustache and+ -- large files, applies to Yesod templates with large+ -- bootstrap CSS files. See+ -- https://github.com/commercialhaskell/stack/issues/4133.+ | LB.length bytes < 50000+ , Right text <- TLE.decodeUtf8' bytes = do+ let etemplateCompiled = Mustache.compileTemplate (T.unpack (templateName template)) $ TL.toStrict text+ 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" <> displayShow (MissingParameters project template missingKeys (configUserConfigPath config)) <> "\n"))+ pure $ LB.fromStrict $ encodeUtf8 applied++ -- Too large or too binary+ | otherwise = pure bytes+ liftM M.fromList (mapM (\(fp,bytes) -> do path <- parseRelFile fp- return (dir </> path, bytes))+ bytes' <- applyMustache bytes+ return (dir </> path, bytes')) (M.toList files)) where onlyMissingKeys (Mustache.VariableNotFound ks) = map T.unpack ks@@ -250,71 +285,15 @@ 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 ()-listTemplates = do- templates <- getTemplates- templateInfo <- getTemplateInfo- if not . M.null $ templateInfo then do- let keySizes = map (T.length . templateName) $ S.toList templates- padWidth = show $ maximum keySizes- outputfmt = "%-" <> padWidth <> "s %s\n"- headerfmt = "%-" <> padWidth <> "s %s\n"- liftIO $ printf headerfmt ("Template"::String) ("Description"::String)- forM_ (S.toList templates) (\x -> do- let name = templateName x- desc = fromMaybe "" $ liftM (mappend "- ") (M.lookup name templateInfo >>= description)- liftIO $ printf outputfmt (T.unpack name) (T.unpack desc))- else mapM_ (liftIO . T.putStrLn . templateName) (S.toList templates)---- | Get the set of templates.-getTemplates :: HasLogFunc env => RIO env (Set TemplateName)-getTemplates = do- req <- liftM setGithubHeaders (parseUrlThrow defaultTemplatesList)- resp <- catch (httpJSON req) (throwM . FailedToDownloadTemplates)- case getResponseStatusCode resp of- 200 -> return $ unTemplateSet $ getResponseBody resp- code -> throwM (BadTemplatesResponse code)--getTemplateInfo :: HasLogFunc env => RIO env (Map Text TemplateInfo)-getTemplateInfo = do- req <- liftM setGithubHeaders (parseUrlThrow defaultTemplateInfoUrl)- 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 $ fromString err- return M.empty- Right resp' ->- case Yaml.decodeEither (LB.toStrict $ getResponseBody resp') :: Either String Object of- Left err ->- throwM $ BadTemplateInfo err- Right o ->- return (M.mapMaybe (Yaml.parseMaybe Yaml.parseJSON) (M.fromList . HM.toList $ o) :: Map Text TemplateInfo)- where- is200 resp =- case getResponseStatusCode resp of- 200 -> return resp- code -> Left $ "Unexpected status code while retrieving templates info: " <> show code--newtype TemplateSet = TemplateSet { unTemplateSet :: Set TemplateName }-instance FromJSON TemplateSet where- parseJSON = fmap TemplateSet . parseTemplateSet---- | Parser the set of templates from the JSON.-parseTemplateSet :: Value -> Parser (Set TemplateName)-parseTemplateSet a = do- xs <- parseJSON a- fmap S.fromList (mapMaybeM parseTemplate xs)- where- parseTemplate v = do- o <- parseJSON v- name <- o .: "name"- if ".hsfiles" `isSuffixOf` name- then case parseTemplateNameFromString name of- Left{} ->- fail ("Unable to parse template name from " <> name)- Right template -> return (Just template)- else return Nothing+-- | Display help for the templates command.+templatesHelp :: HasLogFunc env => RIO env ()+templatesHelp = do+ let url = defaultTemplatesHelpUrl+ req <- liftM setGithubHeaders (parseUrlThrow url)+ resp <- httpLbs req `catch` (throwM . FailedToDownloadTemplatesHelp)+ case decodeUtf8' $ LB.toStrict $ getResponseBody resp of+ Left err -> throwM $ BadTemplatesHelpEncoding url err+ Right txt -> logInfo $ display txt -------------------------------------------------------------------------------- -- Defaults@@ -323,20 +302,14 @@ defaultTemplateName :: TemplateName defaultTemplateName = $(mkTemplateName "new-template") --- | Default web root URL to download from.-defaultTemplateUrl :: String-defaultTemplateUrl =- "https://raw.githubusercontent.com/commercialhaskell/stack-templates/master"---- | Default web URL to get a yaml file containing template metadata.-defaultTemplateInfoUrl :: String-defaultTemplateInfoUrl =- "https://raw.githubusercontent.com/commercialhaskell/stack-templates/master/template-info.yaml"+-- | The default service to use to download templates.+defaultRepoService :: RepoService+defaultRepoService = Github --- | Default web URL to list the repo contents.-defaultTemplatesList :: String-defaultTemplatesList =- "https://api.github.com/repos/commercialhaskell/stack-templates/contents/"+-- | Default web URL to get the `stack templates` help output.+defaultTemplatesHelpUrl :: String+defaultTemplatesHelpUrl =+ "https://raw.githubusercontent.com/commercialhaskell/stack-templates/master/STACK_HELP.md" -------------------------------------------------------------------------------- -- Exceptions@@ -347,15 +320,14 @@ !FilePath | FailedToDownloadTemplate !TemplateName !DownloadException- | FailedToDownloadTemplates !HttpException- | BadTemplatesResponse !Int | AlreadyExists !(Path Abs Dir) | MissingParameters !PackageName !TemplateName !(Set String) !(Path Abs File) | InvalidTemplate !TemplateName !String | AttemptedOverwrites [Path Abs File]- | FailedToDownloadTemplateInfo !HttpException- | BadTemplateInfo !String- | BadTemplateInfoResponse !Int+ | FailedToDownloadTemplatesHelp !HttpException+ | BadTemplatesHelpEncoding+ !String -- URL it's downloaded from+ !UnicodeException | Can'tUseWiredInName !PackageName deriving (Typeable) @@ -366,20 +338,20 @@ "Failed to load download template " <> T.unpack (templateName name) <> " from " <> path- show (FailedToDownloadTemplate name (RedownloadFailed _ _ resp)) =+ show (FailedToDownloadTemplate name (RedownloadInvalidResponse _ _ resp)) = case getResponseStatusCode resp of 404 ->- "That template doesn't exist. Run `stack templates' to see a list of available templates."+ "That template doesn't exist. Run `stack templates' to discover available templates." code -> "Failed to download template " <> T.unpack (templateName name) <> ": unknown reason, status code was: " <> show code++ show (FailedToDownloadTemplate name (RedownloadHttpError httpError)) =+ "There was an unexpected HTTP error while downloading template " <>+ T.unpack (templateName name) <> ": " <> show httpError show (AlreadyExists path) = "Directory " <> toFilePath path <> " already exists. Aborting."- show (FailedToDownloadTemplates ex) =- "Failed to download templates. The HTTP error was: " <> show ex- show (BadTemplatesResponse code) =- "Unexpected status code while retrieving templates list: " <> show code show (MissingParameters name template missingKeys userConfigPath) = intercalate "\n"@@ -413,11 +385,9 @@ "The template would create the following files, but they already exist:\n" <> unlines (map ((" " ++) . toFilePath) fps) <> "Use --force to ignore this, and overwite these files."- show (FailedToDownloadTemplateInfo ex) =- "Failed to download templates info. The HTTP error was: " <> show ex- show (BadTemplateInfo err) =- "Template info couldn't be parsed: " <> err- show (BadTemplateInfoResponse code) =- "Unexpected status code while retrieving templates info: " <> show code+ show (FailedToDownloadTemplatesHelp ex) =+ "Failed to download `stack templates` help. The HTTP error was: " <> show ex+ show (BadTemplatesHelpEncoding url err) =+ "UTF-8 decoding error on template info from\n " <> url <> "\n\n" <> show err show (Can'tUseWiredInName name) = "The name \"" <> packageNameString name <> "\" is used by GHC wired-in packages, and so shouldn't be used as a package name"
src/Stack/Options/BenchParser.hs view
@@ -19,7 +19,7 @@ help ("Forward BENCH_ARGS to the benchmark suite. " <> "Supports templates from `cabal bench`") <> hide))- <*> optionalFirst (switch (long "no-run-benchmarks" <>+ <*> optionalFirst (flag' True (long "no-run-benchmarks" <> help "Disable running of benchmarks. (Benchmarks will still be built.)" <> hide)) where hide = hideMods hide0
src/Stack/Options/BuildMonoidParser.hs view
@@ -21,7 +21,8 @@ haddockHyperlinkSource <*> copyBins <*> copyCompilerTool <*> preFetch <*> keepGoing <*> keepTmpFiles <*> forceDirty <*> tests <*> testOptsParser hideBool <*> benches <*>- benchOptsParser hideBool <*> reconfigure <*> cabalVerbose <*> splitObjs <*> skipComponents+ benchOptsParser hideBool <*> reconfigure <*> cabalVerbose <*> splitObjs <*> skipComponents <*>+ interleavedOutput where hideBool = hide0 /= BuildCmdGlobalOpts hide =@@ -167,3 +168,8 @@ (long "skip" <> help "Skip given component, can be specified multiple times" <> hide)))+ interleavedOutput =+ firstBoolFlags+ "interleaved-output"+ "Print concurrent GHC output to the console with a prefix for the package name"+ hide
src/Stack/Options/Completion.hs view
@@ -21,6 +21,7 @@ import Options.Applicative import Options.Applicative.Builder.Extra import Stack.Config (getLocalPackages)+import Stack.DefaultColorWhen (defaultColorWhen) import Stack.Options.GlobalParser (globalOptsFromMonoid) import Stack.Runners (loadConfigWithOpts) import Stack.Prelude hiding (lift)@@ -57,7 +58,8 @@ -- If it looks like a flag, skip this more costly completion. ('-': _) -> return [] _ -> do- let go = (globalOptsFromMonoid False mempty)+ defColorWhen <- liftIO defaultColorWhen+ let go = (globalOptsFromMonoid False defColorWhen mempty) { globalLogLevel = LevelOther "silent" } loadConfigWithOpts go $ \lc -> do bconfig <- liftIO $ lcLoadBuildConfig lc (globalCompiler go)
src/Stack/Options/ExecParser.hs view
@@ -22,6 +22,7 @@ txt = case mcmd of Nothing -> normalTxt Just ExecCmd{} -> normalTxt+ Just ExecRun -> "-- ARGS (e.g. stack run -- file.txt)" Just ExecGhc -> "-- ARGS (e.g. stack runghc -- X.hs -o x)" Just ExecRunGhc -> "-- ARGS (e.g. stack runghc -- X.hs)" normalTxt = "-- ARGS (e.g. stack exec -- ghc-pkg describe base)"
src/Stack/Options/GlobalParser.hs view
@@ -38,7 +38,10 @@ (long "color" <> metavar "WHEN" <> completeWith ["always", "never", "auto"] <>- help "Specify when to use color in output; WHEN is 'always', 'never', or 'auto'" <>+ help "Specify when to use color in output; WHEN is 'always', 'never', \+ \or 'auto'. On Windows versions before Windows 10, for terminals \+ \that do not support color codes, the default is 'never'; color \+ \may work on terminals that support color codes" <> hide)) <*> optionalFirst (option auto (long "terminal-width" <>@@ -58,8 +61,8 @@ hide0 = kind /= OuterGlobalOpts -- | Create GlobalOpts from GlobalOptsMonoid.-globalOptsFromMonoid :: Bool -> GlobalOptsMonoid -> GlobalOpts-globalOptsFromMonoid defaultTerminal GlobalOptsMonoid{..} = GlobalOpts+globalOptsFromMonoid :: Bool -> ColorWhen -> GlobalOptsMonoid -> GlobalOpts+globalOptsFromMonoid defaultTerminal defaultColorWhen GlobalOptsMonoid{..} = GlobalOpts { globalReExecVersion = getFirst globalMonoidReExecVersion , globalDockerEntrypoint = getFirst globalMonoidDockerEntrypoint , globalLogLevel = fromFirst defaultLogLevel globalMonoidLogLevel@@ -68,7 +71,7 @@ , globalResolver = getFirst globalMonoidResolver , globalCompiler = getFirst globalMonoidCompiler , globalTerminal = fromFirst defaultTerminal globalMonoidTerminal- , globalColorWhen = fromFirst ColorAuto globalMonoidColorWhen+ , globalColorWhen = fromFirst defaultColorWhen globalMonoidColorWhen , globalTermWidth = getFirst globalMonoidTermWidth , globalStackYaml = maybe SYLDefault SYLOverride $ getFirst globalMonoidStackYaml }
src/Stack/Options/NewParser.hs view
@@ -23,9 +23,12 @@ help "Do not create a subdirectory for the project") <*> optional (templateNameArgument (metavar "TEMPLATE_NAME" <>- help "Name of a template or a local template in a file or a URL.\- \ For example: foo or foo.hsfiles or ~/foo or\- \ https://example.com/foo.hsfiles")) <*>+ help "Name of a template - can take the form\+ \ [[service:]username/]template with optional service name\+ \ (github, gitlab, or bitbucket) \+ \ and username for the service; or, a local filename such as\+ \ foo.hsfiles or ~/foo; or, a full URL such as\+ \ https://example.com/foo.hsfiles.")) <*> fmap M.fromList (many
src/Stack/Options/SDistParser.hs view
@@ -15,13 +15,14 @@ optional pvpBoundsOption <*> ignoreCheckSwitch <*> (if signDefault- then switch (long "no-signature" <> help "Do not sign & upload signatures")+ then not <$> switch (long "no-signature" <> help "Do not sign & upload signatures") else switch (long "sign" <> help "Sign & upload signatures")) <*> strOption (long "sig-server" <> metavar "URL" <> showDefault <> value "https://sig.commercialhaskell.org" <> help "URL") <*>- buildPackageOption+ buildPackageOption <*>+ optional (strOption (long "tar-dir" <> help "If specified, copy all the tar to this dir")) where ignoreCheckSwitch = switch (long "ignore-check"
src/Stack/Options/TestParser.hs view
@@ -27,12 +27,12 @@ help "Arguments passed in to the test suite program" <> hide))) <*> optionalFirst- (switch+ (flag' True (long "coverage" <> help "Generate a code coverage report" <> hide)) <*> optionalFirst- (switch+ (flag' True (long "no-run-tests" <> help "Disable running of tests. (Tests will still be built.)" <> hide))
src/Stack/Package.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -31,7 +30,6 @@ ,buildLogPath ,PackageException (..) ,resolvePackageDescription- ,packageDescTools ,packageDependencies ,cabalFilePackageId ,gpdPackageIdentifier@@ -40,13 +38,14 @@ where import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as C8-import Data.List (isSuffixOf, isPrefixOf)+import qualified Data.ByteString.Lazy.Char8 as CL8+import Data.List (isPrefixOf, unzip) 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)+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TLE import Distribution.Compiler import Distribution.ModuleName (ModuleName) import qualified Distribution.ModuleName as Cabal@@ -57,14 +56,16 @@ import Distribution.PackageDescription.Parsec import qualified Distribution.PackageDescription.Parsec as D import Distribution.Parsec.Common (PWarning (..), showPos)-import Distribution.Simple.Utils+import Distribution.Simple.Glob (matchDirFileGlob) import Distribution.System (OS (..), Arch, Platform (..)) import qualified Distribution.Text as D import qualified Distribution.Types.CondTree as Cabal import qualified Distribution.Types.ExeDependency as Cabal import Distribution.Types.ForeignLib import qualified Distribution.Types.LegacyExeDependency as Cabal+import Distribution.Types.MungedPackageName import qualified Distribution.Types.UnqualComponentName as Cabal+import qualified Distribution.Types.Version as Cabal import qualified Distribution.Verbosity as D import Lens.Micro (lens) import qualified Hpack@@ -93,7 +94,7 @@ import Stack.Types.Runner import Stack.Types.Version import qualified System.Directory as D-import System.FilePath (splitExtensions, replaceExtension)+import System.FilePath (replaceExtension) import qualified System.FilePath as FilePath import System.IO.Error import RIO.Process@@ -262,7 +263,7 @@ , packageLicense = licenseRaw pkg , packageDeps = deps , packageFiles = pkgFiles- , packageTools = packageDescTools pkg+ , packageUnknownTools = unknownTools , packageGhcOptions = packageConfigGhcOptions packageConfig , packageFlags = packageConfigFlags packageConfig , packageDefaultFlags = M.fromList@@ -275,10 +276,9 @@ Just lib in case mlib of- Nothing- | null extraLibNames -> NoLibraries- | otherwise -> error "Package has buildable sublibraries but no buildable libraries, I'm giving up"+ Nothing -> NoLibraries Just _ -> HasLibraries foreignLibNames+ , packageInternalLibraries = subLibNames , packageTests = M.fromList [(T.pack (Cabal.unUnqualComponentName $ testName t), testInterface t) | t <- testSuites pkgNoMod@@ -299,8 +299,13 @@ , packageOpts = GetPackageOpts $ \sourceMap installedMap omitPkgs addPkgs cabalfp -> do (componentsModules,componentFiles,_,_) <- getPackageFiles pkgFiles cabalfp+ let internals = S.toList $ internalLibComponents $ M.keysSet componentsModules+ excludedInternals <- mapM parsePackageName internals+ mungedInternals <- mapM (parsePackageName . toInternalPackageMungedName) internals componentsOpts <-- generatePkgDescOpts sourceMap installedMap omitPkgs addPkgs cabalfp pkg componentFiles+ generatePkgDescOpts sourceMap installedMap+ (excludedInternals ++ omitPkgs) (mungedInternals ++ addPkgs)+ cabalfp pkg componentFiles return (componentsModules,componentFiles,componentsOpts) , packageHasExposedModules = maybe False@@ -325,6 +330,10 @@ $ filter (buildable . foreignLibBuildInfo) $ foreignLibs pkg + toInternalPackageMungedName+ = T.pack . unMungedPackageName . computeCompatPackageName (pkgName pkgId)+ . Just . Cabal.mkUnqualComponentName . T.unpack+ -- Gets all of the modules, files, build files, and data files that -- constitute the package. This is primarily used for dirtiness -- checking during build, as well as use by "stack ghci"@@ -354,18 +363,28 @@ return (componentModules, componentFiles, buildFiles <> dataFiles', warnings) pkgId = package pkg name = fromCabalPackageName (pkgName pkgId)- deps = M.filterWithKey (const . not . isMe) (M.union- (packageDependencies packageConfig pkg)++ (unknownTools, knownTools) = packageDescTools pkg++ deps = M.filterWithKey (const . not . isMe) (M.unionsWith (<>)+ [ asLibrary <$> packageDependencies packageConfig pkg -- We include all custom-setup deps - if present - in the -- package deps themselves. Stack always works with the -- invariant that there will be a single installed package -- relating to a package name, and this applies at the setup -- dependency level as well.- (fromMaybe M.empty msetupDeps))+ , asLibrary <$> fromMaybe M.empty msetupDeps+ , knownTools+ ]) msetupDeps = fmap (M.fromList . map (depName &&& depRange) . setupDepends) (setupBuildInfo pkg) + asLibrary range = DepValue+ { dvVersionRange = range+ , dvType = AsLibrary+ }+ -- Is the package dependency mentioned here me: either the package -- name itself, or the name of one of the sub libraries isMe name' = name' == name || packageNameText name' `S.member` extraLibNames@@ -411,6 +430,12 @@ [] (return . generate CLib . libBuildInfo) (library pkg)+ , mapMaybe+ (\sublib -> do+ let maybeLib = CInternalLib . T.pack . Cabal.unUnqualComponentName <$> libName sublib+ flip generate (libBuildInfo sublib) <$> maybeLib+ )+ (subLibraries pkg) , fmap (\exe -> generate@@ -662,18 +687,68 @@ -- -- This uses both the new 'buildToolDepends' and old 'buildTools' -- information.-packageDescTools :: PackageDescription -> Map ExeName VersionRange-packageDescTools =- M.fromList . concatMap tools . allBuildInfo'+packageDescTools+ :: PackageDescription+ -> (Set ExeName, Map PackageName DepValue)+packageDescTools pd =+ (S.fromList $ concat unknowns, M.fromListWith (<>) $ concat knowns) where- tools bi = map go1 (buildTools bi) ++ map go2 (buildToolDepends bi)+ (unknowns, knowns) = unzip $ map perBI $ allBuildInfo' pd - go1 :: Cabal.LegacyExeDependency -> (ExeName, VersionRange)- go1 (Cabal.LegacyExeDependency name range) = (ExeName $ T.pack name, range)+ perBI :: BuildInfo -> ([ExeName], [(PackageName, DepValue)])+ perBI bi =+ (unknownTools, tools)+ where+ (unknownTools, knownTools) = partitionEithers $ map go1 (buildTools bi) - go2 :: Cabal.ExeDependency -> (ExeName, VersionRange)- go2 (Cabal.ExeDependency _pkg name range) = (ExeName $ T.pack $ Cabal.unUnqualComponentName name, range)+ tools = mapMaybe go2 (knownTools ++ buildToolDepends bi) + -- This is similar to desugarBuildTool from Cabal, however it+ -- uses our own hard-coded map which drops tools shipped with+ -- GHC (like hsc2hs), and includes some tools from Stackage.+ go1 :: Cabal.LegacyExeDependency -> Either ExeName Cabal.ExeDependency+ go1 (Cabal.LegacyExeDependency name range) =+ case M.lookup name hardCodedMap of+ Just pkgName -> Right $ Cabal.ExeDependency pkgName (Cabal.mkUnqualComponentName name) range+ Nothing -> Left $ ExeName $ T.pack name++ go2 :: Cabal.ExeDependency -> Maybe (PackageName, DepValue)+ go2 (Cabal.ExeDependency pkg _name range)+ | pkg `S.member` preInstalledPackages = Nothing+ | otherwise = Just+ ( fromCabalPackageName pkg+ , DepValue+ { dvVersionRange = range+ , dvType = AsBuildTool+ }+ )++-- | A hard-coded map for tool dependencies+hardCodedMap :: Map String D.PackageName+hardCodedMap = M.fromList+ [ ("alex", Distribution.Package.mkPackageName "alex")+ , ("happy", Distribution.Package.mkPackageName "happy")+ , ("cpphs", Distribution.Package.mkPackageName "cpphs")+ , ("greencard", Distribution.Package.mkPackageName "greencard")+ , ("c2hs", Distribution.Package.mkPackageName "c2hs")+ , ("hscolour", Distribution.Package.mkPackageName "hscolour")+ , ("hspec-discover", Distribution.Package.mkPackageName "hspec-discover")+ , ("hsx2hs", Distribution.Package.mkPackageName "hsx2hs")+ , ("gtk2hsC2hs", Distribution.Package.mkPackageName "gtk2hs-buildtools")+ , ("gtk2hsHookGenerator", Distribution.Package.mkPackageName "gtk2hs-buildtools")+ , ("gtk2hsTypeGen", Distribution.Package.mkPackageName "gtk2hs-buildtools")+ ]++-- | Executable-only packages which come pre-installed with GHC and do+-- not need to be built. Without this exception, we would either end+-- up unnecessarily rebuilding these packages, or failing because the+-- packages do not appear in the Stackage snapshot.+preInstalledPackages :: Set D.PackageName+preInstalledPackages = S.fromList+ [ D.mkPackageName "hsc2hs"+ , D.mkPackageName "haddock"+ ]+ -- | Variant of 'allBuildInfo' from Cabal that, like versions before -- 2.2, only includes buildable components. allBuildInfo' :: PackageDescription -> [BuildInfo]@@ -698,7 +773,7 @@ :: 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+ (libraryMods,libDotCabalFiles,libWarnings) <- maybe (return (M.empty, M.empty, [])) (asModuleAndFileMap libComponent libraryFiles)@@ -725,7 +800,7 @@ (mapM (asModuleAndFileMap benchComponent benchmarkFiles) (benchmarks pkg))- dfiles <- resolveGlobFiles+ dfiles <- resolveGlobFiles (specVersion pkg) (extraSrcFiles pkg ++ map (dataDir pkg FilePath.</>) (dataFiles pkg)) let modules = libraryMods <> subLibrariesMods <> executableMods <> testMods <> benchModules@@ -746,8 +821,11 @@ foldTuples = foldl' (<>) (M.empty, M.empty, []) -- | Resolve globbing of files (e.g. data files) to absolute paths.-resolveGlobFiles :: [String] -> RIO Ctx (Set (Path Abs File))-resolveGlobFiles =+resolveGlobFiles+ :: Cabal.Version -- ^ cabal file version+ -> [String]+ -> RIO Ctx (Set (Path Abs File))+resolveGlobFiles cabalFileVersion = liftM (S.fromList . catMaybes . concat) . mapM resolve where@@ -764,7 +842,7 @@ mapM resolveFileOrWarn names matchDirFileGlob' dir glob = catch- (matchDirFileGlob_ dir glob)+ (liftIO (matchDirFileGlob minBound cabalFileVersion dir glob)) (\(e :: IOException) -> if isUserError e then do@@ -777,48 +855,6 @@ return [] else throwIO e) --- | This is a copy/paste of the Cabal library function, but with------ @ext == ext'@------ Changed to------ @isSuffixOf ext ext'@------ So that this will work:------ @--- λ> matchDirFileGlob_ "." "test/package-dump/*.txt"--- ["test/package-dump/ghc-7.8.txt","test/package-dump/ghc-7.10.txt"]--- @----matchDirFileGlob_ :: HasRunner env => String -> String -> RIO env [String]-matchDirFileGlob_ dir filepath = case parseFileGlob filepath of- Nothing -> liftIO $ throwString $- "invalid file glob '" ++ filepath- ++ "'. Wildcards '*' are only allowed in place of the file"- ++ " name, not in the directory name or file extension."- ++ " If a wildcard is used it must be with an file extension."- Just (NoGlob filepath') -> return [filepath']- Just (FileGlob dir' ext) -> do- efiles <- liftIO $ try $ D.getDirectoryContents (dir FilePath.</> dir')- let matches =- case efiles of- Left (_ :: IOException) -> []- Right files ->- [ dir' FilePath.</> file- | file <- files- , let (name, ext') = splitExtensions file- , not (null name) && isSuffixOf ext ext'- ]- when (null matches) $- prettyWarnL- [ flow "filepath wildcard"- , "'" <> styleFile (fromString filepath) <> "'"- , flow "does not match any files."- ]- return matches- -- | Get all files referenced by the benchmark. benchmarkFiles :: NamedComponent@@ -1196,24 +1232,24 @@ :: FilePath -> RIO Ctx (Set ModuleName, [Path Abs File]) parseDumpHI dumpHIPath = do dir <- asks (parent . ctxFile)- dumpHI <- liftIO $ fmap C8.lines (C8.readFile dumpHIPath)+ dumpHI <- liftIO $ filterDumpHi <$> fmap CL8.lines (CL8.readFile dumpHIPath) let startModuleDeps =- dropWhile (not . ("module dependencies:" `C8.isPrefixOf`)) dumpHI+ dropWhile (not . ("module dependencies:" `CL8.isPrefixOf`)) dumpHI moduleDeps = S.fromList $- mapMaybe (D.simpleParse . T.unpack . decodeUtf8) $- C8.words $- C8.concat $- C8.dropWhile (/= ' ') (fromMaybe "" $ listToMaybe startModuleDeps) :- takeWhile (" " `C8.isPrefixOf`) (drop 1 startModuleDeps)+ mapMaybe (D.simpleParse . TL.unpack . TLE.decodeUtf8) $+ CL8.words $+ CL8.concat $+ CL8.dropWhile (/= ' ') (fromMaybe "" $ listToMaybe startModuleDeps) :+ takeWhile (" " `CL8.isPrefixOf`) (drop 1 startModuleDeps) thDeps = -- The dependent file path is surrounded by quotes but is not escaped. -- It can be an absolute or relative path. mapMaybe- (fmap T.unpack .- (T.stripSuffix "\"" <=< T.stripPrefix "\"") .- T.dropWhileEnd (== '\r') . decodeUtf8 . C8.dropWhile (/= '"')) $- filter ("addDependentFile \"" `C8.isPrefixOf`) dumpHI+ (fmap TL.unpack .+ (TL.stripSuffix "\"" <=< TL.stripPrefix "\"") .+ TL.dropWhileEnd (== '\r') . TLE.decodeUtf8 . CL8.dropWhile (/= '"')) $+ filter ("addDependentFile \"" `CL8.isPrefixOf`) dumpHI thDepsResolved <- liftM catMaybes $ forM thDeps $ \x -> do mresolved <- liftIO (forgivingAbsence (resolveFile dir x)) >>= rejectMissingFile when (isNothing mresolved) $@@ -1225,7 +1261,23 @@ ] return mresolved return (moduleDeps, thDepsResolved)+ where+ -- | Filtering step fixing RAM usage upon a big dump-hi file. See+ -- https://github.com/commercialhaskell/stack/issues/4027 It is+ -- an optional step from a functionality stand-point.+ filterDumpHi dumpHI =+ let dl x xs = x ++ xs+ isLineInteresting (acc, moduleDepsStarted) l+ | moduleDepsStarted && " " `CL8.isPrefixOf` l =+ (acc . dl [l], True)+ | "module dependencies:" `CL8.isPrefixOf` l =+ (acc . dl [l], True)+ | "addDependentFile \"" `CL8.isPrefixOf` l =+ (acc . dl [l], False)+ | otherwise = (acc, False)+ in fst (foldl' isLineInteresting (dl [], False) dumpHI) [] + -- | Try to resolve the list of base names in the given directory by -- looking for unique instances of base names applied with the given -- extensions.@@ -1392,13 +1444,7 @@ config <- view configL case configOverrideHpack config of HpackBundled -> do-#if MIN_VERSION_hpack(0,26,0)- r <- liftIO $ Hpack.hpackResult $ Hpack.setTarget (toFilePath hpackFile) Hpack.defaultOptions-#elif MIN_VERSION_hpack(0,23,0)- r <- liftIO $ Hpack.hpackResult Hpack.defaultRunOptions {Hpack.runOptionsConfigDir = Just (toFilePath pkgDir)} Hpack.NoForce-#else- r <- liftIO $ Hpack.hpackResult (Just $ toFilePath pkgDir) Hpack.NoForce-#endif+ r <- liftIO $ Hpack.hpackResult $ Hpack.setProgramName "stack" $ Hpack.setTarget (toFilePath hpackFile) Hpack.defaultOptions forM_ (Hpack.resultWarnings r) prettyWarnS let cabalFile = styleFile . fromString . Hpack.resultCabalFile $ r case Hpack.resultStatus r of
src/Stack/PackageIndex.hs view
@@ -39,7 +39,6 @@ import Data.Conduit.Zlib (ungzip) import qualified Data.List.NonEmpty as NE import qualified Data.HashMap.Strict as HashMap-import qualified Data.Set as Set import Data.Store.Version import Data.Store.VersionTagged import qualified Data.Text as T@@ -51,7 +50,7 @@ import qualified Hackage.Security.Client.Repository.HttpLib.HttpClient as HS import qualified Hackage.Security.Util.Path as HS import qualified Hackage.Security.Util.Pretty as HS-import Network.HTTP.Client.TLS (getGlobalManager)+import Network.HTTP.StackClient (getGlobalManager) import Network.HTTP.Download import Network.URI (parseURI) import Path (toFilePath, parseAbsFile, mkRelDir, mkRelFile, (</>), parseRelDir)@@ -380,12 +379,17 @@ -- | Get the known versions for a given package from the package caches. -- -- See 'getPackageCaches' for performance notes.-getPackageVersions :: HasCabalLoader env => PackageName -> RIO env (Set Version)+getPackageVersions :: HasCabalLoader env => PackageName -> RIO env (HashMap Version (Maybe CabalHash)) getPackageVersions pkgName = lookupPackageVersions pkgName <$> getPackageCaches -lookupPackageVersions :: PackageName -> PackageCache index -> Set Version+lookupPackageVersions :: PackageName -> PackageCache index -> HashMap Version (Maybe CabalHash) lookupPackageVersions pkgName (PackageCache m) =- maybe Set.empty (Set.fromList . HashMap.keys) $ HashMap.lookup pkgName m+ maybe HashMap.empty (HashMap.map extractOrigRevHash) $ HashMap.lookup pkgName m+ where+ -- Extract the original cabal file hash (the first element of the one or two+ -- element list currently representing the cabal file hashes).+ extractOrigRevHash (_,_, neRevHashesAndOffsets) =+ listToMaybe $ fst (NE.last neRevHashesAndOffsets) -- | Load the package caches, or create the caches if necessary. --@@ -401,7 +405,9 @@ result <- liftM mconcat $ forM (clIndices cl) $ \index -> do fp <- configPackageIndexCache (indexName index) PackageCache pis <--#if MIN_VERSION_template_haskell(2,13,0)+#if MIN_VERSION_template_haskell(2,14,0)+ $(versionedDecodeOrLoad (storeVersionConfig "pkg-v5" "35_zXZ4b4CIWfrLXtjWteR4nb6o="+#elif MIN_VERSION_template_haskell(2,13,0) $(versionedDecodeOrLoad (storeVersionConfig "pkg-v5" "LLL6OCcimOqRm3r0JmsSlLHcaLE=" #else $(versionedDecodeOrLoad (storeVersionConfig "pkg-v5" "A607WaDwhg5VVvZTxNgU9g52DO8="
src/Stack/PackageLocation.hs view
@@ -28,7 +28,7 @@ import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8, decodeUtf8) import Distribution.PackageDescription (GenericPackageDescription)-import Network.HTTP.Client (parseUrlThrow)+import Network.HTTP.StackClient (parseUrlThrow) import Network.HTTP.Download.Verified import Path import Path.Extra
src/Stack/Prelude.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -13,6 +14,10 @@ , readProcessNull , withProcessContext , stripCR+ , hIsTerminalDeviceOrMinTTY+ , prompt+ , promptPassword+ , promptBool , module X ) where @@ -28,17 +33,23 @@ import qualified System.IO as IO import qualified System.Directory as Dir import qualified System.FilePath as FP+import System.IO.Echo (withoutInputEcho) import System.IO.Error (isDoesNotExistError) +#ifdef WINDOWS+import System.Win32 (isMinTTYHandle, withHandleToHANDLE)+#endif+ 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 RIO.Process (HasProcessContext (..), ProcessContext, setStdin, closed, getStderr, getStdout, proc, withProcess_, setStdout, setStderr, ProcessConfig, readProcess_, workingDirL) import Data.Store as X (Store) import Data.Text.Encoding (decodeUtf8With) import Data.Text.Encoding.Error (lenientDecode) +import qualified Data.Text.IO as T import qualified RIO.Text as T -- | Get a source for a file. Unlike @sourceFile@, doesn't require@@ -86,7 +97,7 @@ -- -- Throws a 'ReadProcessException' if unsuccessful in launching, or 'ProcessExitedUnsuccessfully' if the process itself fails. sinkProcessStderrStdout- :: forall e o env. (HasProcessContext env, HasLogFunc env)+ :: forall e o env. (HasProcessContext env, HasLogFunc env, HasCallStack) => String -- ^ Command -> [String] -- ^ Command line arguments -> ConduitM ByteString Void (RIO env) e -- ^ Sink for stderr@@ -108,7 +119,7 @@ -- -- Throws a 'ReadProcessException' if unsuccessful. sinkProcessStdout- :: (HasProcessContext env, HasLogFunc env)+ :: (HasProcessContext env, HasLogFunc env, HasCallStack) => String -- ^ Command -> [String] -- ^ Command line arguments -> ConduitM ByteString Void (RIO env) a -- ^ Sink for stdout@@ -132,13 +143,13 @@ -- | Read from the process, ignoring any output. -- -- Throws a 'ReadProcessException' exception if the process fails.-readProcessNull :: (HasProcessContext env, HasLogFunc env)+readProcessNull :: (HasProcessContext env, HasLogFunc env, HasCallStack) => 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_+ void $ proc name args readProcess_ -- | Use the new 'ProcessContext', but retain the working directory -- from the parent environment.@@ -151,3 +162,54 @@ -- | Remove a trailing carriage return if present stripCR :: Text -> Text stripCR = T.dropSuffix "\r"++-- | hIsTerminaDevice does not recognise handles to mintty terminals as terminal+-- devices, but isMinTTYHandle does.+hIsTerminalDeviceOrMinTTY :: MonadIO m => Handle -> m Bool+#ifdef WINDOWS+hIsTerminalDeviceOrMinTTY h = do+ isTD <- hIsTerminalDevice h+ if isTD+ then return True+ else liftIO $ withHandleToHANDLE h isMinTTYHandle+#else+hIsTerminalDeviceOrMinTTY = hIsTerminalDevice+#endif++-- | Prompt the user by sending text to stdout, and taking a line of+-- input from stdin.+prompt :: MonadIO m => Text -> m Text+prompt txt = liftIO $ do+ T.putStr txt+ hFlush stdout+ T.getLine++-- | Prompt the user by sending text to stdout, and collecting a line+-- of input from stdin. While taking input from stdin, input echoing is+-- disabled, to hide passwords.+--+-- Based on code from cabal-install, Distribution.Client.Upload+promptPassword :: MonadIO m => Text -> m Text+promptPassword txt = liftIO $ do+ T.putStr txt+ hFlush stdout+ -- Save/restore the terminal echoing status (no echoing for entering+ -- the password).+ password <- withoutInputEcho T.getLine+ -- Since the user's newline is not echoed, one needs to be inserted.+ T.putStrLn ""+ return password++-- | Prompt the user by sending text to stdout, and collecting a line of+-- input from stdin. If something other than "y" or "n" is entered, then+-- print a message indicating that "y" or "n" is expected, and ask+-- again.+promptBool :: MonadIO m => Text -> m Bool+promptBool txt = liftIO $ do+ input <- prompt txt+ case input of+ "y" -> return True+ "n" -> return False+ _ -> do+ T.putStrLn "Please press either 'y' or 'n', and then enter."+ promptBool txt
src/Stack/PrettyPrint.hs view
@@ -83,7 +83,7 @@ indentAfterLabel . f) prettyWarnNoIndentWith f = prettyWith LevelWarn ((line <>) . (styleWarning "Warning:" <+>) . f)-prettyErrorNoIndentWith f = prettyWith LevelWarn+prettyErrorNoIndentWith f = prettyWith LevelError ((line <>) . (styleError "Error:" <+>) . f) prettyDebug, prettyInfo, prettyNote, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent@@ -154,6 +154,8 @@ output $ "Finished in" <+> displayMilliseconds diff <> ":" <+> msg return x +-- The following syles do not affect the colour of the background.+ -- | Style an 'AnsiDoc' as an error. Should be used sparingly, not to style -- entire long messages. For example, it's used to style the "Error:" -- label for an error message, not the entire message.@@ -164,7 +166,7 @@ -- entire long messages. For example, it's used to style the "Warning:" -- label for an error message, not the entire message. styleWarning :: AnsiDoc -> AnsiDoc-styleWarning = yellow+styleWarning = dullyellow -- | Style an 'AnsiDoc' in a way to emphasize that it is a particularly good -- thing.@@ -178,7 +180,7 @@ -- | Style an 'AnsiDoc' as a filename. See 'styleDir' for directories. styleFile :: AnsiDoc -> AnsiDoc-styleFile = bold . white+styleFile = dullcyan -- | Style an 'AsciDoc' as a URL. For now using the same style as files. styleUrl :: AnsiDoc -> AnsiDoc@@ -196,7 +198,7 @@ -- a current thing. For example, could be used when talking about the -- current package we're processing when outputting the name of it. styleCurrent :: AnsiDoc -> AnsiDoc-styleCurrent = yellow+styleCurrent = dullyellow -- TODO: figure out how to describe this styleTarget :: AnsiDoc -> AnsiDoc
src/Stack/SDist.hs view
@@ -84,6 +84,8 @@ -- ^ The URL of the signature server , sdoptsBuildTarball :: Bool -- ^ Whether to build the tarball+ , sdoptsTarPath :: Maybe FilePath+ -- ^ Where to copy the tarball } newtype CheckException@@ -330,7 +332,7 @@ withExecuteEnv bopts boptsCli baseConfigOpts locals [] [] [] -- provide empty list of globals. This is a hack around custom Setup.hs files $ \ee ->- withSingleContext 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 _outputType -> do let outFile = toFilePath tmpdir FP.</> "source-files-list" cabal KeepTHLoading ["sdist", "--list-sources", outFile] contents <- liftIO (S.readFile outFile)@@ -422,7 +424,7 @@ case Check.checkPackage gdesc Nothing of [] -> Check.checkPackage gdesc (Just pkgDesc) x -> x- fileChecks <- liftIO $ Check.checkPackageFiles pkgDesc (toFilePath pkgDir)+ fileChecks <- liftIO $ Check.checkPackageFiles minBound pkgDesc (toFilePath pkgDir) let checks = pkgChecks ++ fileChecks (errors, warnings) = let criticalIssue (Check.PackageBuildImpossible _) = True
src/Stack/Script.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections #-} module Stack.Script ( scriptCmd ) where@@ -211,7 +212,7 @@ $ map (\(pn, lpi) -> ModuleInfo $ Map.fromList- $ map (\mn -> (mn, Set.singleton pn))+ $ map (, Set.singleton pn) $ Set.toList $ lpiExposedModules lpi) $ filter (\(pn, lpi) ->
src/Stack/Setup.hs view
@@ -64,13 +64,13 @@ import qualified Distribution.System as Cabal import Distribution.Text (simpleParse) import Lens.Micro (set)-import Network.HTTP.Simple (getResponseBody, getResponseStatusCode)+import Network.HTTP.StackClient (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 Prelude (until) import qualified RIO import Stack.Build (build) import Stack.Config (loadConfig)@@ -94,7 +94,6 @@ import qualified System.Directory as D import System.Environment (getExecutablePath, lookupEnv) import System.Exit (ExitCode (..), exitFailure)-import System.IO (stdout) import System.IO.Error (isPermissionError) import System.FilePath (searchPathSeparator) import qualified System.FilePath as FP@@ -578,7 +577,7 @@ eldconfigOut <- withModifyEnvVars sbinEnv $ proc "ldconfig" ["-p"]- $ tryAny . readProcessStdout_+ $ tryAny . fmap fst . readProcess_ let firstWords = case eldconfigOut of Right ldconfigOut -> mapMaybe (listToMaybe . T.words) $ T.lines $ T.decodeUtf8With T.lenientDecode@@ -685,7 +684,8 @@ -> UpgradeTo -> RIO env () upgradeCabal wc upgradeTo = do- logInfo "Manipulating the global Cabal is only for debugging purposes"+ logWarn "Using deprecated --upgrade-cabal feature, this is not recommended"+ logWarn "Manipulating the global Cabal is only for debugging purposes" let name = $(mkPackageName "Cabal") rmap <- resolvePackages Nothing mempty (Set.singleton name) installed <- getCabalPkgVer wc@@ -718,6 +718,10 @@ -> Version -> RIO env () doCabalInstall wc installed wantedVersion = do+ when (wantedVersion >= $(mkVersion "2.2")) $ do+ logWarn "--upgrade-cabal will almost certainly fail for Cabal 2.2 or later"+ logWarn "See: https://github.com/commercialhaskell/stack/issues/4070"+ logWarn "Valiantly attempting to build it anyway, but I know this is doomed" withSystemTempDir "stack-cabal-upgrade" $ \tmpdir -> do logInfo $ "Installing Cabal-" <>@@ -765,7 +769,7 @@ exists <- doesExecutableExist exeName if exists then do- eres <- proc exeName ["--info"] $ tryAny . readProcessStdout_+ eres <- proc exeName ["--info"] $ tryAny . fmap fst . readProcess_ let minfo = do Right lbs <- Just eres pairs_ <- readMaybe $ BL8.unpack lbs :: Maybe [(String, String)]@@ -1354,10 +1358,10 @@ getCabalInstallVersion :: (HasProcessContext env, HasLogFunc env) => RIO env (Maybe Version) getCabalInstallVersion = do- ebs <- proc "cabal" ["--numeric-version"] $ tryAny . readProcessStdout_+ ebs <- tryAny $ proc "cabal" ["--numeric-version"] readProcess_ case ebs of Left _ -> return Nothing- Right bs -> Just <$> parseVersion (T.dropWhileEnd isSpace (T.decodeUtf8 (LBS.toStrict 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.@@ -1647,7 +1651,7 @@ eres <- withWorkingDir (toFilePath dir) $ proc exeName [ fp , "-no-user-package-db"- ] $ try . readProcessStdout_+ ] $ try . readProcess_ case eres of Left e -> throwIO $ GHCSanityCheckCompileFailed e ghc Right _ -> return () -- TODO check that the output of running the command is correct@@ -1703,7 +1707,7 @@ Map.empty else do -- Get a list of known locales by running @locale -a@.- elocales <- tryAny $ proc "locale" ["-a"] readProcessStdout_+ elocales <- tryAny $ fmap fst $ proc "locale" ["-a"] readProcess_ let -- Filter the list to only include locales with UTF-8 encoding. utf8Locales =@@ -1989,7 +1993,7 @@ | isPermissionError e -> do 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) "+ toSudo <- promptBool "Try using sudo? (y/n) " when toSudo $ do let run cmd args = do ec <- proc cmd args runProcess@@ -2019,19 +2023,6 @@ logInfo "" logInfo "sudo file copy worked!" | otherwise -> throwM e--prompt :: MonadIO m => String -> m Bool-prompt str =- liftIO go- where- go = do- putStr str- hFlush stdout- l <- getLine- case l of- 'y':_ -> return True- 'n':_ -> return False- _ -> putStrLn "Invalid entry, try again" >> go getDownloadVersion :: StackReleaseInfo -> Maybe Version getDownloadVersion (StackReleaseInfo val) = do
src/Stack/Setup/Installed.hs view
@@ -55,7 +55,7 @@ toolNameString ToolGhcjs{} = "ghcjs" parseToolText :: Text -> Maybe Tool-parseToolText (parseCompilerVersion -> Just (cv@GhcjsVersion{})) = Just (ToolGhcjs cv)+parseToolText (parseCompilerVersion -> Just cv@GhcjsVersion{}) = Just (ToolGhcjs cv) parseToolText (parsePackageIdentifierFromString . T.unpack -> Just pkgId) = Just (Tool pkgId) parseToolText _ = Nothing @@ -88,6 +88,16 @@ x <- T.stripSuffix ".installed" $ T.pack $ toFilePath $ filename fp parseToolText x +-- | See https://github.com/commercialhaskell/stack/issues/4086.+warnAboutGHCJS :: HasLogFunc env => RIO env ()+warnAboutGHCJS =+ logWarn $ "Building a GHCJS project. " <> fromString ghcjsWarning++ghcjsWarning :: String+ghcjsWarning = unwords+ [ "Note that GHCJS support in Stack is EXPERIMENTAL"+ ]+ getCompilerVersion :: (HasProcessContext env, HasLogFunc env) => WhichCompiler@@ -96,17 +106,18 @@ case wc of Ghc -> do logDebug "Asking GHC for its version"- bs <- proc "ghc" ["--numeric-version"] readProcessStdout_+ bs <- fst <$> proc "ghc" ["--numeric-version"] readProcess_ let (_, ghcVersion) = versionFromEnd $ BL.toStrict bs x <- GhcVersion <$> parseVersion (T.decodeUtf8 ghcVersion) logDebug $ "GHC version is: " <> display x return x Ghcjs -> do+ warnAboutGHCJS 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 <- proc "ghcjs" ["--version"] readProcessStdout_+ bs <- fst <$> proc "ghcjs" ["--version"] readProcess_ let (rest, ghcVersion) = T.decodeUtf8 <$> versionFromEnd (BL.toStrict bs) (_, ghcjsVersion) = T.decodeUtf8 <$> versionFromEnd rest GhcjsVersion <$> parseVersion ghcjsVersion <*> parseVersion ghcVersion
src/Stack/SetupCmd.hs view
@@ -63,7 +63,7 @@ <> OA.help "Install a specific version of Cabal" ) latestParser = OA.flag' Latest ( OA.long "upgrade-cabal"- <> OA.help "Install latest version of Cabal globally" )+ <> OA.help "DEPRECATED Install latest version of Cabal globally" ) setupParser :: OA.Parser SetupCmdOpts setupParser = SetupCmdOpts
src/Stack/Sig/Sign.hs view
@@ -21,10 +21,8 @@ import Stack.Prelude import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Lazy as L-import Network.HTTP.Client (RequestBody (RequestBodyBS)) import Network.HTTP.Download-import Network.HTTP.Simple (setRequestMethod, setRequestBody, getResponseStatusCode)-import Network.HTTP.Types (methodPut)+import Network.HTTP.StackClient (RequestBody (RequestBodyBS), setRequestMethod, setRequestBody, getResponseStatusCode, methodPut) import Path import Stack.Package import Stack.Sig.GPG
src/Stack/Snapshot.hs view
@@ -39,11 +39,10 @@ import Distribution.InstalledPackageInfo (PError) import Distribution.PackageDescription (GenericPackageDescription) import qualified Distribution.PackageDescription as C-import qualified Distribution.Types.UnqualComponentName as C import Distribution.System (Platform) import Distribution.Text (display) import qualified Distribution.Version as C-import Network.HTTP.Client (Request)+import Network.HTTP.StackClient (Request) import Network.HTTP.Download import qualified RIO import Network.URI (isURI)@@ -579,8 +578,6 @@ , lpiFlags = Map.empty , lpiGhcOptions = [] , lpiPackageDeps = Map.empty- , lpiProvidedExes = Set.empty- , lpiNeededExes = Map.empty , lpiExposedModules = Set.empty , lpiHide = False }@@ -654,8 +651,6 @@ , lpiFlags = Map.empty , lpiGhcOptions = [] , lpiPackageDeps = Map.unions $ map goDep $ dpDepends dp- , lpiProvidedExes = Set.empty- , lpiNeededExes = Map.empty , lpiExposedModules = Set.fromList $ map (ModuleName . encodeUtf8) $ dpExposedModules dp , lpiHide = not $ dpIsExposed dp }@@ -819,12 +814,6 @@ , lpiPackageDeps = Map.map fromVersionRange $ Map.filterWithKey (const . (/= name)) $ packageDependencies pconfig pd- , lpiProvidedExes =- Set.fromList- $ map (ExeName . T.pack . C.unUnqualComponentName . C.exeName)- $ C.executables pd- , lpiNeededExes = Map.map fromVersionRange- $ packageDescTools pd , lpiExposedModules = maybe Set.empty (Set.fromList . map fromCabalModuleName . C.exposedModules)
src/Stack/Solver.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} module Stack.Solver ( cabalPackagesCheck@@ -112,11 +113,11 @@ fmap toFilePath cabalfps try ( withWorkingDir (toFilePath tmpdir)- $ proc "cabal" args readProcessStdout_+ $ proc "cabal" args readProcess_ ) >>= either (parseCabalErrors . eceStderr)- (parseCabalOutput . BL.toStrict)+ (parseCabalOutput . BL.toStrict . fst) where errCheck = T.isInfixOf "Could not resolve dependencies"@@ -343,7 +344,7 @@ -- combine entry in both maps (\_ v f -> Just (v, f)) -- convert entry in first map only- (fmap (flip (,) Map.empty))+ (fmap (, Map.empty)) -- convert entry in second map only (\m -> if Map.null m then Map.empty else error "Bug: An entry in flag map must have a corresponding \
src/Stack/Types/Build.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-}@@ -671,11 +672,13 @@ instance NFData ConfigureOpts -- | Information on a compiled package: the library conf file (if relevant),--- and all of the executable paths.+-- the sublibraries (if present) and all of the executable paths. data PrecompiledCache = PrecompiledCache -- Use FilePath instead of Path Abs File for Binary instances { pcLibrary :: !(Maybe FilePath) -- ^ .conf file inside the package database+ , pcSubLibs :: ![FilePath]+ -- ^ .conf file inside the package database, for each of the sublibraries , pcExes :: ![FilePath] -- ^ Full paths to executables }@@ -684,4 +687,8 @@ instance NFData PrecompiledCache precompiledCacheVC :: VersionConfig PrecompiledCache-precompiledCacheVC = storeVersionConfig "precompiled-v1" "eMzSOwaHJMamA5iNKs1A025frlQ="+#if MIN_VERSION_template_haskell(2,14,0)+precompiledCacheVC = storeVersionConfig "precompiled-v2" "1Q08F5_iKDGDMPCuBG0-Av9nEKk="+#else+precompiledCacheVC = storeVersionConfig "precompiled-v2" "55vMMtbIlS4UukKnSmjs1SrI01o="+#endif
src/Stack/Types/BuildPlan.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-}@@ -43,7 +44,7 @@ import Data.Text.Encoding (encodeUtf8) import qualified Distribution.ModuleName as C import qualified Distribution.Version as C-import Network.HTTP.Client (parseRequest)+import Network.HTTP.StackClient (parseRequest) import Stack.Prelude import Stack.Types.Compiler import Stack.Types.FlagName@@ -102,7 +103,11 @@ instance NFData SnapshotDef snapshotDefVC :: VersionConfig SnapshotDef+#if MIN_VERSION_template_haskell(2,14,0)+snapshotDefVC = storeVersionConfig "sd-v1" "u-V-7pmU0YA-nXZFI0UBIST3JdY="+#else snapshotDefVC = storeVersionConfig "sd-v1" "CKo7nln8EXkw07Gq-4ATxszNZiE="+#endif -- | A relative file path including a unique string for the given -- snapshot.@@ -310,7 +315,11 @@ instance NFData LoadedSnapshot loadedSnapshotVC :: VersionConfig LoadedSnapshot-loadedSnapshotVC = storeVersionConfig "ls-v4" "a_ljrJRo8hA_-gcIDP9c6NXJ2pE="+#if MIN_VERSION_template_haskell(2,14,0)+loadedSnapshotVC = storeVersionConfig "ls-v5" "Rl-3KjZ1LqhIyGy-o0HCC-I6cRc="+#else+loadedSnapshotVC = storeVersionConfig "ls-v5" "CeSRWh1VU8v0__kwA__msbe6WlU="+#endif -- | Information on a single package for the 'LoadedSnapshot' which -- can be installed.@@ -340,11 +349,6 @@ , lpiPackageDeps :: !(Map PackageName VersionIntervals) -- ^ All packages which must be built/copied/registered before -- this package.- , lpiProvidedExes :: !(Set ExeName)- -- ^ The names of executables provided by this package, for- -- performing build tool lookups.- , lpiNeededExes :: !(Map ExeName VersionIntervals)- -- ^ Executables needed by this package. , lpiExposedModules :: !(Set ModuleName) -- ^ Modules exposed by this package's library , lpiHide :: !Bool
src/Stack/Types/Config.hs view
@@ -182,11 +182,14 @@ import Data.Attoparsec.Args (parseArgs, EscapingMode (Escaping)) import qualified Data.ByteArray.Encoding as Mem (convertToBase, Base(Base16)) import qualified Data.ByteString.Char8 as S8+import Data.Coerce (coerce) import Data.List (stripPrefix) import Data.List.NonEmpty (NonEmpty) import qualified Data.List.NonEmpty as NonEmpty import qualified Data.Map as Map import qualified Data.Map.Strict as M+import qualified Data.Monoid as Monoid+import Data.Monoid.Map (MonoidMap(..)) import qualified Data.Set as Set import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8)@@ -335,6 +338,8 @@ -- command disallows this. ,configSaveHackageCreds :: !Bool -- ^ Should we save Hackage credentials to a file?+ ,configHackageBaseUrl :: !Text+ -- ^ Hackage base URL used when uploading packages ,configRunner :: !Runner ,configCabalLoader :: !CabalLoader }@@ -401,6 +406,7 @@ data SpecialExecCmd = ExecCmd String+ | ExecRun | ExecGhc | ExecRunGhc deriving (Show, Eq)@@ -738,10 +744,14 @@ -- ^ Template parameters. ,configMonoidScmInit :: !(First SCM) -- ^ Initialize SCM (e.g. git init) when making new projects?- ,configMonoidGhcOptionsByName :: !(Map PackageName [Text])- -- ^ See 'configGhcOptionsByName'- ,configMonoidGhcOptionsByCat :: !(Map ApplyGhcOptions [Text])- -- ^ See 'configGhcOptionsAll'+ ,configMonoidGhcOptionsByName :: !(MonoidMap PackageName (Monoid.Dual [Text]))+ -- ^ See 'configGhcOptionsByName'. Uses 'Monoid.Dual' so that+ -- options from the configs on the right come first, so that they+ -- can be overridden.+ ,configMonoidGhcOptionsByCat :: !(MonoidMap ApplyGhcOptions (Monoid.Dual [Text]))+ -- ^ See 'configGhcOptionsAll'. Uses 'Monoid.Dual' so that options+ -- from the configs on the right come first, so that they can be+ -- overridden. ,configMonoidExtraPath :: ![Path Abs Dir] -- ^ Additional paths to search for executables in ,configMonoidSetupInfoLocations :: ![SetupInfoLocation]@@ -770,6 +780,8 @@ -- ^ See 'configDumpLogs' , configMonoidSaveHackageCreds :: !(First Bool) -- ^ See 'configSaveHackageCreds'+ , configMonoidHackageBaseUrl :: !(First Text)+ -- ^ See 'configHackageBaseUrl' , configMonoidIgnoreRevisionMismatch :: !(First Bool) -- ^ See 'configIgnoreRevisionMismatch' }@@ -842,13 +854,13 @@ return x (Nothing, Nothing) -> return [] - let configMonoidGhcOptionsByCat = Map.fromList+ let configMonoidGhcOptionsByCat = coerce $ Map.fromList [ (AGOEverything, optionsEverything) , (AGOLocals, Map.findWithDefault [] GOKLocals options) , (AGOTargets, Map.findWithDefault [] GOKTargets options) ] - configMonoidGhcOptionsByName = Map.fromList+ configMonoidGhcOptionsByName = coerce $ Map.fromList [(name, opts) | (GOKPackage name, opts) <- Map.toList options] configMonoidExtraPath <- obj ..:? configMonoidExtraPathName ..!= []@@ -867,6 +879,7 @@ configMonoidAllowDifferentUser <- First <$> obj ..:? configMonoidAllowDifferentUserName configMonoidDumpLogs <- First <$> obj ..:? configMonoidDumpLogsName configMonoidSaveHackageCreds <- First <$> obj ..:? configMonoidSaveHackageCredsName+ configMonoidHackageBaseUrl <- First <$> obj ..:? configMonoidHackageBaseUrlName configMonoidIgnoreRevisionMismatch <- First <$> obj ..:? configMonoidIgnoreRevisionMismatchName return ConfigMonoid {..}@@ -1006,6 +1019,9 @@ configMonoidSaveHackageCredsName :: Text configMonoidSaveHackageCredsName = "save-hackage-creds"++configMonoidHackageBaseUrlName :: Text+configMonoidHackageBaseUrlName = "hackage-base-url" configMonoidIgnoreRevisionMismatchName :: Text configMonoidIgnoreRevisionMismatchName = "ignore-revision-mismatch"
src/Stack/Types/Config/Build.hs view
@@ -88,6 +88,9 @@ -- ^ Whether to enable split-objs. ,boptsSkipComponents :: ![Text] -- ^ Which components to skip when building+ ,boptsInterleavedOutput :: !Bool+ -- ^ Should we use the interleaved GHC output when building+ -- multiple packages? } deriving (Show) @@ -117,6 +120,7 @@ , boptsCabalVerbose = False , boptsSplitObjs = False , boptsSkipComponents = []+ , boptsInterleavedOutput = False } defaultBuildOptsCLI ::BuildOptsCLI@@ -185,6 +189,7 @@ , buildMonoidCabalVerbose :: !(First Bool) , buildMonoidSplitObjs :: !(First Bool) , buildMonoidSkipComponents :: ![Text]+ , buildMonoidInterleavedOutput :: !(First Bool) } deriving (Show, Generic) instance FromJSON (WithJSONWarnings BuildOptsMonoid) where@@ -216,6 +221,7 @@ buildMonoidCabalVerbose <- First <$> o ..:? buildMonoidCabalVerboseArgName buildMonoidSplitObjs <- First <$> o ..:? buildMonoidSplitObjsName buildMonoidSkipComponents <- o ..:? buildMonoidSkipComponentsName ..!= mempty+ buildMonoidInterleavedOutput <- First <$> o ..:? buildMonoidInterleavedOutputName return BuildOptsMonoid{..}) buildMonoidLibProfileArgName :: Text@@ -289,6 +295,9 @@ buildMonoidSkipComponentsName :: Text buildMonoidSkipComponentsName = "skip-components"++buildMonoidInterleavedOutputName :: Text+buildMonoidInterleavedOutputName = "interleaved-output" instance Semigroup BuildOptsMonoid where (<>) = mappenddefault
src/Stack/Types/NamedComponent.hs view
@@ -8,7 +8,9 @@ , exeComponents , testComponents , benchComponents+ , internalLibComponents , isCLib+ , isCInternalLib , isCExe , isCTest , isCBench@@ -59,9 +61,19 @@ mBenchName (CBench name) = Just name mBenchName _ = Nothing +internalLibComponents :: Set NamedComponent -> Set Text+internalLibComponents = Set.fromList . mapMaybe mInternalName . Set.toList+ where+ mInternalName (CInternalLib name) = Just name+ mInternalName _ = Nothing+ isCLib :: NamedComponent -> Bool isCLib CLib{} = True isCLib _ = False++isCInternalLib :: NamedComponent -> Bool+isCInternalLib CInternalLib{} = True+isCInternalLib _ = False isCExe :: NamedComponent -> Bool isCExe CExe{} = True
src/Stack/Types/Package.hs view
@@ -122,13 +122,14 @@ ,packageVersion :: !Version -- ^ Version of the package ,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.+ ,packageDeps :: !(Map PackageName DepValue) -- ^ Packages that the package depends on, both as libraries and build tools.+ ,packageUnknownTools :: !(Set ExeName) -- ^ Build tools specified in the legacy manner (build-tools:) that failed the hard-coded lookup. ,packageAllDeps :: !(Set PackageName) -- ^ Original dependencies (not sieved). ,packageGhcOptions :: ![Text] -- ^ Ghc options used on package. ,packageFlags :: !(Map FlagName Bool) -- ^ Flags used on package. ,packageDefaultFlags :: !(Map FlagName Bool) -- ^ Defaults for unspecified flags. ,packageLibraries :: !PackageLibraries -- ^ does the package have a buildable library stanza?+ ,packageInternalLibraries :: !(Set Text) -- ^ names of internal libraries ,packageTests :: !(Map Text TestSuiteInterface) -- ^ names and interfaces of test suites ,packageBenchmarks :: !(Set Text) -- ^ names of benchmarks ,packageExes :: !(Set Text) -- ^ names of executables@@ -139,6 +140,27 @@ -- ^ If present: custom-setup dependencies } deriving (Show,Typeable)++-- | The value for a map from dependency name. This contains both the+-- version range and the type of dependency, and provides a semigroup+-- instance.+data DepValue = DepValue+ { dvVersionRange :: !VersionRange+ , dvType :: !DepType+ }+ deriving (Show,Typeable)+instance Semigroup DepValue where+ DepValue a x <> DepValue b y = DepValue (intersectVersionRanges a b) (x <> y)++-- | Is this package being used as a library, or just as a build tool?+-- If the former, we need to ensure that a library actually+-- exists. See+-- <https://github.com/commercialhaskell/stack/issues/2195>+data DepType = AsLibrary | AsBuildTool+ deriving (Show, Eq)+instance Semigroup DepType where+ AsLibrary <> _ = AsLibrary+ AsBuildTool <> x = x packageIdentifier :: Package -> PackageIdentifier packageIdentifier pkg =
src/Stack/Types/PackageIdentifier.hs view
@@ -209,8 +209,7 @@ packageIdentifierParser = do name <- packageNameParser char '-'- version <- versionParser- return (PackageIdentifier name version)+ PackageIdentifier name <$> versionParser -- | Convenient way to parse a package identifier from a 'Text'. parsePackageIdentifier :: MonadThrow m => Text -> m PackageIdentifier
src/Stack/Types/PackageIndex.hs view
@@ -42,6 +42,17 @@ -- file revision indicates the hash of the contents of the cabal file, -- and the offset into the index tarball. --+-- The reason for each 'Version' mapping to a two element list of+-- 'CabalHash'es is because some older Stackage snapshots have CRs in+-- their cabal files. For compatibility with these older snapshots,+-- both hashes are stored: the first element of the two element list+-- being the original hash, and the (potential) second element with+-- the CRs stripped. [Note: This is was initially stored as a two+-- element list, and cannot be easily packed into more explict ADT or+-- newtype because of some template-haskell that would need to be+-- modified as well: the 'versionedDecodeOrLoad' function call found+-- in the 'getPackageCaches' function in 'Stack.PackageIndex'.]+-- -- It's assumed that cabal files appear in the index tarball in the -- correct revision order. newtype PackageCache index = PackageCache
src/Stack/Types/Resolver.hs view
@@ -49,7 +49,7 @@ import Data.Text.Encoding (decodeUtf8) import Data.Text.Read (decimal) import Data.Time (Day)-import Network.HTTP.Client (Request, parseUrlThrow)+import Network.HTTP.StackClient (Request, parseUrlThrow) import Options.Applicative (ReadM) import qualified Options.Applicative.Types as OA import Path
src/Stack/Types/Runner.hs view
@@ -116,4 +116,4 @@ | otherwise = w data ColorWhen = ColorNever | ColorAlways | ColorAuto- deriving (Show, Generic)+ deriving (Eq, Show, Generic)
src/Stack/Types/TemplateName.hs view
@@ -6,14 +6,24 @@ -- | Template name handling. -module Stack.Types.TemplateName where+module Stack.Types.TemplateName+ ( TemplateName+ , RepoTemplatePath (..)+ , RepoService (..)+ , TemplatePath (..)+ , mkTemplateName+ , templateName+ , templatePath+ , parseTemplateNameFromString+ , parseRepoPathWithService+ , templateNameArgument+ , templateParamArgument+ ) where -import Data.Aeson.Extended (FromJSON, withText, parseJSON)-import Data.Aeson.Types (typeMismatch)+import Data.Aeson (FromJSON (..), withText) import qualified Data.Text as T-import Data.Yaml (Value(Object), (.:?)) import Language.Haskell.TH-import Network.HTTP.Client (parseRequest)+import Network.HTTP.StackClient (parseRequest) import qualified Options.Applicative as O import Path import Path.Internal@@ -30,21 +40,25 @@ -- the template repository | UrlPath String -- ^ a full URL+ | RepoPath RepoTemplatePath deriving (Eq, Ord, Show) +-- | Details for how to access a template from a remote repo.+data RepoTemplatePath = RepoTemplatePath+ { rtpService :: RepoService+ , rtpUser :: Text+ , rtpTemplate :: Text+ }+ deriving (Eq, Ord, Show)++-- | Services from which templates can be retrieved from a repository.+data RepoService = Github | Gitlab | Bitbucket+ deriving (Eq, Ord, Show)+ instance FromJSON TemplateName where parseJSON = withText "TemplateName" $ either fail return . parseTemplateNameFromString . T.unpack -data TemplateInfo = TemplateInfo- { author :: Maybe Text- , description :: Maybe Text }- deriving (Eq, Ord, Show)--instance FromJSON TemplateInfo where- parseJSON (Object v) = TemplateInfo <$> v .:? "author" <*> v .:? "description"- parseJSON invalid = typeMismatch "Template Info" invalid- -- | An argument which accepts a template name of the format -- @foo.hsfiles@ or @foo@, ultimately normalized to @foo@. templateNameArgument :: O.Mod O.ArgumentFields TemplateName@@ -79,12 +93,13 @@ $ asum (validParses prefix hsf orig) validParses prefix hsf orig = -- NOTE: order is important- [ TemplateName (T.pack orig) . UrlPath <$> (parseRequest orig *> Just orig)+ [ TemplateName prefix . RepoPath <$> parseRepoPath hsf+ , TemplateName (T.pack orig) . UrlPath <$> (parseRequest orig *> Just orig) , TemplateName prefix . AbsPath <$> parseAbsFile hsf , TemplateName prefix . RelPath <$> parseRelFile hsf ] expected = "Expected a template like: foo or foo.hsfiles or\- \ https://example.com/foo.hsfiles"+ \ https://example.com/foo.hsfiles or github:user/foo" -- | Make a template name. mkTemplateName :: String -> Q Exp@@ -98,6 +113,11 @@ AbsPath (Path fp) -> [|AbsPath (Path fp)|] RelPath (Path fp) -> [|RelPath (Path fp)|] UrlPath fp -> [|UrlPath fp|]+ RepoPath (RepoTemplatePath sv u t) ->+ case sv of+ Github -> [|RepoPath $ RepoTemplatePath Github u t|]+ Gitlab -> [|RepoPath $ RepoTemplatePath Gitlab u t|]+ Bitbucket -> [|RepoPath $ RepoTemplatePath Bitbucket u t|] -- | Get a text representation of the template name. templateName :: TemplateName -> Text@@ -106,3 +126,27 @@ -- | Get the path of the template. templatePath :: TemplateName -> TemplatePath templatePath (TemplateName _ fp) = fp++defaultRepoUserForService :: RepoService -> Maybe Text+defaultRepoUserForService Github = Just "commercialhaskell"+defaultRepoUserForService _ = Nothing++-- | Parses a template path of the form @github:user/template@.+parseRepoPath :: String -> Maybe RepoTemplatePath+parseRepoPath s =+ case T.splitOn ":" (T.pack s) of+ ["github" , rest] -> parseRepoPathWithService Github rest+ ["gitlab" , rest] -> parseRepoPathWithService Gitlab rest+ ["bitbucket" , rest] -> parseRepoPathWithService Bitbucket rest+ _ -> Nothing++-- | Parses a template path of the form @user/template@, given a service+parseRepoPathWithService :: RepoService -> Text -> Maybe RepoTemplatePath+parseRepoPathWithService service path =+ case T.splitOn "/" path of+ [user, name] -> Just $ RepoTemplatePath service user name+ [name] -> do+ repoUser <- defaultRepoUserForService service+ Just $ RepoTemplatePath service repoUser name+ _ -> Nothing+
src/Stack/Upgrade.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}@@ -24,6 +24,10 @@ import qualified Paths_stack as Paths import Stack.Build import Stack.Config+-- Following import is redundant on non-Windows operating systems+#ifdef WINDOWS+import Stack.DefaultColorWhen (defaultColorWhen)+#endif import Stack.Fetch import Stack.PackageIndex import Stack.PrettyPrint@@ -212,6 +216,13 @@ -- --git" not working for earlier versions. let args = [ "clone", repo , "stack", "--depth", "1", "--recursive", "--branch", branch] withWorkingDir (toFilePath tmp) $ proc "git" args runProcess_+#ifdef WINDOWS+ -- On Windows 10, an upstream issue with the `git clone` command+ -- means that command clears, but does not then restore, the+ -- ENABLE_VIRTUAL_TERMINAL_PROCESSING flag for native terminals.+ -- The folowing hack re-enables the lost ANSI-capability.+ _ <- liftIO defaultColorWhen+#endif return $ Just $ tmp </> $(mkRelDir "stack") Nothing -> do updateAllIndices
src/Stack/Upload.hs view
@@ -25,18 +25,12 @@ import qualified Data.Conduit.Binary as CB import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8)-import qualified Data.Text.IO as TIO-import Network.HTTP.Client (Response,- RequestBody(RequestBodyLBS),- Request)-import Network.HTTP.StackClient (withResponse, httpNoBody)-import Network.HTTP.Simple (getResponseStatusCode,+import Network.HTTP.StackClient (Request, RequestBody(RequestBodyLBS), Response, withResponse, httpNoBody, getGlobalManager, getResponseStatusCode, getResponseBody, setRequestHeader,- parseRequest)-import Network.HTTP.Client.MultipartFormData (formDataBody, partFileRequestBody,- partBS, partLBS)-import Network.HTTP.Client.TLS (getGlobalManager,+ parseRequest,+ formDataBody, partFileRequestBody,+ partBS, partLBS, applyDigestAuth, displayDigestAuthException) import Stack.Types.Config@@ -46,8 +40,7 @@ import System.Directory (createDirectoryIfMissing, removeFile) import System.FilePath ((</>), takeFileName)-import System.IO (stdout, putStrLn, putStr, getLine, print) -- TODO remove putStrLn, use logInfo-import System.IO.Echo (withoutInputEcho)+import System.IO (stdout, putStrLn, putStr, print) -- TODO remove putStrLn, use logInfo -- | Username and password to log into Hackage. --@@ -87,10 +80,8 @@ return $ mkCreds fp where fromPrompt fp = do- putStr "Hackage username: "- hFlush stdout- username <- TIO.getLine- password <- promptPassword+ username <- prompt "Hackage username: "+ password <- promptPassword "Hackage password: " let hc = HackageCreds { hcUsername = username , hcPassword = password@@ -98,46 +89,22 @@ } when (configSaveHackageCreds config) $ do- let prompt = "Save hackage credentials to file at " ++ fp ++ " [y/n]? "- putStr prompt- input <- loopPrompt prompt+ shouldSave <- promptBool $ T.pack $+ "Save hackage credentials to file at " ++ fp ++ " [y/n]? " putStrLn "NOTE: Avoid this prompt in the future by using: save-hackage-creds: false"- hFlush stdout- case input of- "y" -> do- L.writeFile fp (encode hc)- putStrLn "Saved!"- hFlush stdout- _ -> return ()+ when shouldSave $ do+ L.writeFile fp (encode hc)+ putStrLn "Saved!"+ hFlush stdout return hc - loopPrompt :: String -> IO String- loopPrompt p = do- input <- TIO.getLine- case input of- "y" -> return "y"- "n" -> return "n"- _ -> do- putStr p- loopPrompt p- credsFile :: Config -> IO FilePath credsFile config = do let dir = toFilePath (view stackRootL config) </> "upload" createDirectoryIfMissing True dir return $ dir </> "credentials.json" --- | Lifted from cabal-install, Distribution.Client.Upload-promptPassword :: IO Text-promptPassword = do- putStr "Hackage password: "- hFlush stdout- -- save/restore the terminal echoing status (no echoing for entering the password)- passwd <- withoutInputEcho $ fmap T.pack getLine- putStrLn ""- return passwd- applyCreds :: HackageCreds -> Request -> IO Request applyCreds creds req0 = do manager <- getGlobalManager@@ -159,13 +126,14 @@ -- sending a file like 'upload', this sends a lazy bytestring. -- -- Since 0.1.2.1-uploadBytes :: HackageCreds+uploadBytes :: String -- ^ Hackage base URL+ -> HackageCreds -> String -- ^ tar file name -> L.ByteString -- ^ tar file contents -> IO ()-uploadBytes creds tarName bytes = do+uploadBytes baseUrl creds tarName bytes = do let req1 = setRequestHeader "Accept" ["text/plain"]- "https://hackage.haskell.org/packages/"+ (fromString $ baseUrl <> "packages/") formData = [partFileRequestBody "package" tarName (RequestBodyLBS bytes)] req2 <- formDataBody formData req1 req3 <- applyCreds creds req2@@ -199,16 +167,21 @@ -- | Upload a single tarball with the given @Uploader@. -- -- Since 0.1.0.0-upload :: HackageCreds -> FilePath -> IO ()-upload creds fp = uploadBytes creds (takeFileName fp) =<< L.readFile fp+upload :: String -- ^ Hackage base URL+ -> HackageCreds+ -> FilePath+ -> IO ()+upload baseUrl creds fp = uploadBytes baseUrl creds (takeFileName fp) =<< L.readFile fp -uploadRevision :: HackageCreds+uploadRevision :: String -- ^ Hackage base URL+ -> HackageCreds -> PackageIdentifier -> L.ByteString -> IO ()-uploadRevision creds ident cabalFile = do+uploadRevision baseUrl creds ident cabalFile = do req0 <- parseRequest $ concat- [ "https://hackage.haskell.org/package/"+ [ baseUrl+ , "package/" , packageIdentifierString ident , "/" , packageNameString $ packageIdentifierName ident
src/main/Main.hs view
@@ -28,11 +28,12 @@ import Data.IORef.RunOnce (runOnce) import Data.List import qualified Data.Map.Strict as Map+import qualified Data.Set as Set import qualified Data.Text as T import Data.Version (showVersion) import RIO.Process #ifdef USE_GIT_INFO-import Development.GitRev (gitCommitCount, gitHash)+import GitHash (giCommitCount, giHash, tGitInfoCwd) #endif import Distribution.System (buildArch) import qualified Distribution.Text as Cabal (display)@@ -56,6 +57,7 @@ import Stack.Constants import Stack.Constants.Config import Stack.Coverage+import Stack.DefaultColorWhen (defaultColorWhen) import qualified Stack.Docker as Docker import Stack.Dot import Stack.GhcPkg (findGhcPkgField)@@ -97,6 +99,7 @@ import Stack.Types.Version import Stack.Types.Config import Stack.Types.Compiler+import Stack.Types.NamedComponent import Stack.Types.Nix import Stack.Upgrade import qualified Stack.Upload as Upload@@ -104,6 +107,7 @@ import System.Environment (getProgName, getArgs, withArgs) import System.Exit import System.FilePath (isValid, pathSeparator)+import qualified System.FilePath as FP import System.IO (stderr, stdin, stdout, BufferMode(..), hPutStrLn, hPrint, hGetEncoding, hSetEncoding) -- | Change the character encoding of the given Handle to transliterate@@ -124,13 +128,12 @@ [ [$(simpleVersion Meta.version)] -- Leave out number of commits for --depth=1 clone -- See https://github.com/commercialhaskell/stack/issues/792- , [" (" ++ commitCount ++ " commits)" | commitCount /= ("1"::String) &&- commitCount /= ("UNKNOWN" :: String)]+ , [" (" ++ show commitCount ++ " commits)" | commitCount /= 1] , [" ", Cabal.display buildArch] , [depsString, warningString] ] where- commitCount = $gitCommitCount+ commitCount = giCommitCount $$tGitInfoCwd #else versionString' = showVersion Meta.version@@ -167,7 +170,11 @@ hSetTranslit stderr args <- getArgs progName <- getProgName- isTerminal <- hIsTerminalDevice stdout+ isTerminal <- hIsTerminalDeviceOrMinTTY stdout+ -- On Windows, where applicable, defaultColorWhen has the side effect of+ -- enabling ANSI for ANSI-capable native (ConHost) terminals, if not already+ -- ANSI-enabled.+ defColorWhen <- defaultColorWhen execExtraHelp args Docker.dockerHelpOptName (dockerOptsParser False)@@ -183,7 +190,7 @@ Left (exitCode :: ExitCode) -> throwIO exitCode Right (globalMonoid,run) -> do- let global = globalOptsFromMonoid isTerminal globalMonoid+ let global = globalOptsFromMonoid isTerminal defColorWhen globalMonoid when (globalLogLevel global == LevelDebug) $ hPutStrLn stderr versionString' case globalReExecVersion global of Just expectVersion -> do@@ -357,6 +364,10 @@ "Execute a command" execCmd (execOptsParser Nothing)+ addCommand' "run"+ "Build and run an executable. Defaults to the first available executable if none is provided as the first argument."+ execCmd+ (execOptsParser $ Just ExecRun) addGhciCommand' "ghci" "Run ghci in the context of package(s) (experimental)" ghciCmd@@ -667,7 +678,7 @@ upgrade (globalConfigMonoid go) (globalResolver go) #ifdef USE_GIT_INFO- (find (/= "UNKNOWN") [$gitHash])+ (Just (giHash $$tGitInfoCwd)) #else Nothing #endif@@ -675,7 +686,7 @@ -- | Upload to Hackage uploadCmd :: SDistOpts -> GlobalOpts -> IO ()-uploadCmd (SDistOpts [] _ _ _ _ _) go =+uploadCmd (SDistOpts [] _ _ _ _ _ _) go = withConfigAndLock go . prettyErrorL $ [ flow "To upload the current package, please run" , styleShell "stack upload ."@@ -706,6 +717,7 @@ ] liftIO exitFailure config <- view configL+ let hackageUrl = T.unpack $ configHackageBaseUrl config getCreds <- liftIO (runOnce (Upload.loadCreds config)) mapM_ (resolveFile' >=> checkSDistTarball sdistOpts) files forM_@@ -714,7 +726,7 @@ do tarFile <- resolveFile' file liftIO $ do creds <- getCreds- Upload.upload creds (toFilePath tarFile)+ Upload.upload hackageUrl creds (toFilePath tarFile) when (sdoptsSign sdistOpts) (void $@@ -728,8 +740,8 @@ checkSDistTarball' sdistOpts tarName tarBytes liftIO $ do creds <- getCreds- Upload.uploadBytes creds tarName tarBytes- forM_ mcabalRevision $ uncurry $ Upload.uploadRevision creds+ Upload.uploadBytes hackageUrl creds tarName tarBytes+ forM_ mcabalRevision $ uncurry $ Upload.uploadRevision hackageUrl creds tarPath <- parseRelFile tarName when (sdoptsSign sdistOpts)@@ -764,19 +776,21 @@ tarPath <- (distDir </>) <$> parseRelFile tarName ensureDir (parent tarPath) liftIO $ L.writeFile (toFilePath tarPath) tarBytes- checkSDistTarball sdistOpts tarPath prettyInfoL [flow "Wrote sdist tarball to", display tarPath]+ checkSDistTarball sdistOpts tarPath+ forM_ (sdoptsTarPath sdistOpts) $ copyTarToTarPath tarPath tarName when (sdoptsSign sdistOpts) (void $ Sig.sign (sdoptsSignServerUrl sdistOpts) tarPath)+ where+ copyTarToTarPath tarPath tarName targetDir = liftIO $ do+ let targetTarPath = targetDir FP.</> tarName+ D.createDirectoryIfMissing True $ FP.takeDirectory targetTarPath+ D.copyFile (toFilePath tarPath) targetTarPath -- | Execute a command. execCmd :: ExecOpts -> GlobalOpts -> IO () execCmd ExecOpts {..} go@GlobalOpts{..} = case eoExtra of ExecOptsPlain -> do- (cmd, args) <- case (eoCmd, eoArgs) of- (ExecCmd cmd, args) -> return (cmd, args)- (ExecGhc, args) -> return ("ghc", args)- (ExecRunGhc, args) -> return ("runghc", args) loadConfigWithOpts go $ \lc -> withUserFileLock go (view stackRootL lc) $ \lk -> do let getCompilerVersion = loadCompilerVersion go lc@@ -785,14 +799,17 @@ (lcProjectRoot lc) -- Unlock before transferring control away, whether using docker or not: (Just $ munlockFile lk)- (runRIO (lcConfig lc) $ do+ (withBuildConfigAndLock go $ \buildLock -> do config <- view configL menv <- liftIO $ configProcessContextSettings config plainEnvSettings- withProcessContext menv $ Nix.reexecWithOptionalShell- (lcProjectRoot lc)- getCompilerVersion- (runRIO (lcConfig lc) $- exec cmd args))+ withProcessContext menv $ do+ (cmd, args) <- case (eoCmd, eoArgs) of+ (ExecCmd cmd, args) -> return (cmd, args)+ (ExecRun, args) -> getRunCmd args+ (ExecGhc, args) -> return ("ghc", args)+ (ExecRunGhc, args) -> return ("runghc", args)+ munlockFile buildLock+ Nix.reexecWithOptionalShell (lcProjectRoot lc) getCompilerVersion (runRIO (lcConfig lc) $ exec cmd args)) Nothing Nothing -- Unlocked already above. ExecOptsEmbellished {..} ->@@ -812,9 +829,10 @@ else args ++ ["+RTS"] ++ eoRtsOptions ++ ["-RTS"] (cmd, args) <- case (eoCmd, argsWithRts eoArgs) of (ExecCmd cmd, args) -> return (cmd, args)+ (ExecRun, args) -> getRunCmd 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.+ -- NOTE: This doesn't work for GHCJS, because it doesn't have+ -- a runghcjs binary. (ExecRunGhc, args) -> getGhcCmd "run" eoPackages args munlockFile lk -- Unlock before transferring control away.@@ -834,6 +852,24 @@ getPkgOpts wc pkgs = map ("-package-id=" ++) <$> mapM (getPkgId wc) pkgs + getRunCmd args = do+ pkgComponents <- liftM (map lpvComponents . Map.elems . lpProject) getLocalPackages+ let executables = filter isCExe $ concatMap Set.toList pkgComponents+ let (exe, args') = case args of+ [] -> (firstExe, args)+ x:xs -> case find (\y -> y == (CExe $ T.pack x)) executables of+ Nothing -> (firstExe, args)+ argExe -> (argExe, xs)+ where+ firstExe = listToMaybe executables+ case exe of+ Just (CExe exe') -> do+ Stack.Build.build (const (return ())) Nothing defaultBuildOptsCLI{boptsCLITargets = [T.cons ':' exe']}+ return (T.unpack exe', args')+ _ -> do+ logError "No executables found."+ liftIO exitFailure+ getGhcCmd prefix pkgs args = do wc <- view $ actualCompilerVersionL.whichCompilerL pkgopts <- getPkgOpts wc pkgs@@ -946,7 +982,7 @@ -- | List the available templates. templatesCmd :: () -> GlobalOpts -> IO ()-templatesCmd _ go@GlobalOpts{..} = withConfigAndLock go listTemplates+templatesCmd _ go@GlobalOpts{..} = withConfigAndLock go templatesHelp -- | Fix up extra-deps for a project solverCmd :: Bool -- ^ modify stack.yaml automatically?
src/test/Network/HTTP/Download/VerifiedSpec.hs view
@@ -3,7 +3,7 @@ import Control.Retry (limitRetries) import Crypto.Hash-import Network.HTTP.Client.Conduit+import Network.HTTP.StackClient import Network.HTTP.Download.Verified import Path import Path.IO hiding (withSystemTempDir)
src/test/Stack/ConfigSpec.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE TemplateHaskell #-} module Stack.ConfigSpec where +import Control.Arrow import Data.Aeson.Extended import Data.Yaml import Path@@ -165,7 +166,7 @@ it "is parseable" $ \_ -> do curDir <- getCurrentDir let parsed :: Either String (Either String (WithJSONWarnings ConfigMonoid))- parsed = parseEither (parseConfigMonoid curDir) <$> decodeEither defaultConfigYaml+ parsed = parseEither (parseConfigMonoid curDir) <$> left show (decodeEither' defaultConfigYaml) case parsed of Right (Right _) -> return () :: IO () _ -> fail "Failed to parse default config yaml"
src/test/Stack/StoreSpec.hs view
@@ -51,12 +51,6 @@ (if (minBound :: a) `notElem` xs then [minBound] else []) ++ (if (maxBound :: a) `notElem` xs && (maxBound :: a) /= minBound then maxBound : xs else xs) -$(do let ns = [ ''Int64, ''Word64, ''Word8- ]- f n = [d| instance Monad m => Serial m $(conT n) where- series = generate (\_ -> addMinAndMaxBounds [0, 1]) |]- concat <$> mapM f ns)- $(do let tys = [ ''InstalledCacheInner -- FIXME , ''PackageCache -- FIXME , ''LoadedSnapshot
src/test/Stack/Types/BuildPlanSpec.hs view
@@ -5,7 +5,7 @@ import Data.Aeson.Extended (WithJSONWarnings(..)) import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as S8-import Data.Yaml (decode)+import Data.Yaml (decodeThrow) import Stack.Types.BuildPlan import Test.Hspec @@ -15,7 +15,7 @@ describe "Archive" $ do describe "github" $ do let decode' :: ByteString -> Maybe (WithJSONWarnings (PackageLocation Subdirs))- decode' = decode+ decode' = decodeThrow it "'github' and 'commit' keys" $ do let contents :: ByteString
+ src/test/Stack/Types/TemplateNameSpec.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE OverloadedStrings #-}++module Stack.Types.TemplateNameSpec where++import Stack.Types.TemplateName+import Path.Internal+import System.Info (os)+import Test.Hspec++spec :: Spec+spec =+ describe "TemplateName" $ do+ describe "parseTemplateNameFromString" $ do+ let pathOf s = either error templatePath (parseTemplateNameFromString s)++ it "parses out the TemplatePath" $ do+ pathOf "github:user/name" `shouldBe` (RepoPath $ RepoTemplatePath Github "user" "name.hsfiles")+ pathOf "bitbucket:user/name" `shouldBe` (RepoPath $ RepoTemplatePath Bitbucket "user" "name.hsfiles")+ pathOf "gitlab:user/name" `shouldBe` (RepoPath $ RepoTemplatePath Gitlab "user" "name.hsfiles")++ pathOf "http://www.com/file" `shouldBe` UrlPath "http://www.com/file"+ pathOf "https://www.com/file" `shouldBe` UrlPath "https://www.com/file"++ pathOf "name" `shouldBe` (RelPath $ Path "name.hsfiles")+ pathOf "name.hsfile" `shouldBe` (RelPath $ Path "name.hsfile.hsfiles")+ pathOf "name.hsfiles" `shouldBe` (RelPath $ Path "name.hsfiles")+ pathOf "" `shouldBe` (RelPath $ Path ".hsfiles")++ if os == "mingw32"+ then do+ pathOf "//home/file" `shouldBe` (AbsPath $ Path "\\\\home\\file.hsfiles")+ pathOf "/home/file" `shouldBe` (RelPath $ Path "\\home\\file.hsfiles")+ pathOf "/home/file.hsfiles" `shouldBe` (RelPath $ Path "\\home\\file.hsfiles")++ pathOf "c:\\home\\file" `shouldBe` (AbsPath $ Path "C:\\home\\file.hsfiles")+ pathOf "with/slash" `shouldBe` (RelPath $ Path "with\\slash.hsfiles")++ let colonAction =+ do+ return $! pathOf "with:colon"+ colonAction `shouldThrow` anyErrorCall++ else do+ pathOf "//home/file" `shouldBe` (AbsPath $ Path "/home/file.hsfiles")+ pathOf "/home/file" `shouldBe` (AbsPath $ Path "/home/file.hsfiles")+ pathOf "/home/file.hsfiles" `shouldBe` (AbsPath $ Path "/home/file.hsfiles")++ pathOf "c:\\home\\file" `shouldBe` (RelPath $ Path "c:\\home\\file.hsfiles")+ pathOf "with/slash" `shouldBe` (RelPath $ Path "with/slash.hsfiles")+ pathOf "with:colon" `shouldBe` (RelPath $ Path "with:colon.hsfiles")+
+ src/unix/Stack/DefaultColorWhen.hs view
@@ -0,0 +1,11 @@+{- | This version of the module is only for non-Windows (eg unix-like)+operating systems.+-}+module Stack.DefaultColorWhen+ ( defaultColorWhen+ ) where++import Stack.Types.Runner (ColorWhen (ColorAuto))++defaultColorWhen :: IO ColorWhen+defaultColorWhen = return ColorAuto
+ src/windows/Stack/DefaultColorWhen.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE CPP #-}++{- | This version of the module is only for Windows operating systems.+-}+module Stack.DefaultColorWhen+ ( defaultColorWhen+ ) where++-- The Win32 package provides CPP macro WINDOWS_CCONV.+#include "windows_cconv.h"++import Stack.Prelude (stdout)+import Stack.Types.Runner (ColorWhen (ColorAuto, ColorNever))++import Data.Bits ((.|.), (.&.))+import Foreign.Marshal (alloca)+import Foreign.Ptr (Ptr)+import Foreign.Storable (peek)+import System.Win32.Types (BOOL, DWORD, HANDLE, iNVALID_HANDLE_VALUE,+ nullHANDLE, withHandleToHANDLE)++defaultColorWhen :: IO ColorWhen+defaultColorWhen = withHandleToHANDLE stdout aNSISupport++-- The following is based on extracts from the modules+-- System.Console.ANSI.Windows.Foreign and System.Console.ANSI.Windows.Detect+-- from the ansi-terminal package, simplified.++-- | This function first checks if the Windows handle is valid and yields+-- 'never' if it is not. It then tries to get a ConHost console mode for that+-- handle. If it can not, it assumes that the handle is ANSI-enabled. If virtual+-- termimal (VT) processing is already enabled, the handle supports 'auto'.+-- Otherwise, it trys to enable processing. If it can, the handle supports+-- 'auto'. If it can not, the function yields 'never'.+aNSISupport :: HANDLE -> IO ColorWhen+aNSISupport h =+ if h == iNVALID_HANDLE_VALUE || h == nullHANDLE+ then return ColorNever -- Invalid handle or no handle+ else do+ tryMode <- getConsoleMode h+ case tryMode of+ Nothing -> return ColorAuto -- No ConHost mode+ Just mode -> if mode .&. eNABLE_VIRTUAL_TERMINAL_PROCESSING /= 0+ then return ColorAuto -- VT processing already enabled+ else do+ let mode' = mode .|. eNABLE_VIRTUAL_TERMINAL_PROCESSING+ succeeded <- cSetConsoleMode h mode'+ if succeeded+ then return ColorAuto -- VT processing enabled+ else return ColorNever -- Can't enable VT processing+ where+ eNABLE_VIRTUAL_TERMINAL_PROCESSING = 4++foreign import WINDOWS_CCONV unsafe "windows.h GetConsoleMode"+ cGetConsoleMode :: HANDLE -> Ptr DWORD -> IO BOOL++foreign import WINDOWS_CCONV unsafe "windows.h SetConsoleMode"+ cSetConsoleMode :: HANDLE -> DWORD -> IO BOOL++getConsoleMode :: HANDLE -> IO (Maybe DWORD)+getConsoleMode handle = alloca $ \ptr_mode -> do+ succeeded <- cGetConsoleMode handle ptr_mode+ if succeeded+ then Just <$> peek ptr_mode+ else pure Nothing
stack.cabal view
@@ -1,11 +1,13 @@--- This file has been generated from package.yaml by hpack version 0.28.2.+cabal-version: 1.24++-- This file has been generated from package.yaml by hpack version 0.31.0. -- -- see: https://github.com/sol/hpack ----- hash: 5b3e8d70c3e492d9cc4473a5919b80ee0fc2f59d6eb81b898d2bb507a83159e1+-- hash: c1123498f6d6ebc3a0fc03b968146f349da538acc9bfa189e0f65c5cd447aca6 name: stack-version: 1.7.1+version: 1.9.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,10 +18,10 @@ license: BSD3 license-file: LICENSE build-type: Custom-cabal-version: >= 1.24 extra-source-files:- ChangeLog.md CONTRIBUTING.md+ ChangeLog.md+ README.md doc/architecture.md doc/build_command.md doc/ChangeLog.md@@ -33,7 +35,6 @@ doc/ghcjs.md doc/GUIDE.md doc/install_and_upgrade.md- doc/MAINTAINER_GUIDE.md doc/nix_integration.md doc/nonstandard_project_init.md doc/README.md@@ -42,7 +43,6 @@ doc/stack_yaml_vs_cabal_package_file.md doc/travis_ci.md doc/yaml_configuration.md- README.md src/setup-shim/StackSetupShim.hs stack.yaml test/package-dump/ghc-7.10.txt@@ -92,6 +92,7 @@ Data.Attoparsec.Combinators Data.Attoparsec.Interpreter Data.IORef.RunOnce+ Data.Monoid.Map Data.Store.VersionTagged Network.HTTP.Download Network.HTTP.Download.Verified@@ -122,6 +123,7 @@ Stack.Constants Stack.Constants.Config Stack.Coverage+ Stack.DefaultColorWhen Stack.Docker Stack.Docker.GlobalDB Stack.Dot@@ -214,7 +216,7 @@ 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+ ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -fwarn-identities build-depends: Cabal , aeson@@ -226,7 +228,7 @@ , base64-bytestring , bytestring , conduit- , conduit-extra >=1.2.3.1+ , conduit-extra , containers , cryptonite , cryptonite-conduit@@ -287,10 +289,10 @@ , time , tls , transformers- , typed-process >=0.2.1.0+ , typed-process , unicode-transforms , unix-compat- , unliftio >=0.2.4.0+ , unliftio , unordered-containers , vector , yaml@@ -301,11 +303,11 @@ build-depends: Win32 else+ build-tools:+ hsc2hs build-depends: bindings-uname , unix- build-tools:- hsc2hs if os(windows) hs-source-dirs: src/windows/@@ -322,7 +324,7 @@ Paths_stack hs-source-dirs: src/main- ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -threaded -rtsopts+ ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -threaded -rtsopts build-depends: Cabal , aeson@@ -334,7 +336,7 @@ , base64-bytestring , bytestring , conduit- , conduit-extra >=1.2.3.1+ , conduit-extra , containers , cryptonite , cryptonite-conduit@@ -396,10 +398,10 @@ , time , tls , transformers- , typed-process >=0.2.1.0+ , typed-process , unicode-transforms , unix-compat- , unliftio >=0.2.4.0+ , unliftio , unordered-containers , vector , yaml@@ -410,17 +412,17 @@ build-depends: Win32 else+ build-tools:+ hsc2hs build-depends: bindings-uname , unix- build-tools:- hsc2hs if flag(static) ld-options: -static -pthread if !(flag(disable-git-info)) cpp-options: -DUSE_GIT_INFO build-depends:- gitrev+ githash , optparse-simple if flag(hide-dependency-versions) cpp-options: -DHIDE_DEP_VERSIONS@@ -440,7 +442,7 @@ hs-source-dirs: test/integration test/integration/lib- ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -Wall -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -optP-Wno-nonportable-include-path -threaded -rtsopts -with-rtsopts=-N build-depends: Cabal , aeson@@ -452,7 +454,7 @@ , base64-bytestring , bytestring , conduit- , conduit-extra >=1.2.3.1+ , conduit-extra , containers , cryptonite , cryptonite-conduit@@ -514,10 +516,10 @@ , time , tls , transformers- , typed-process >=0.2.1.0+ , typed-process , unicode-transforms , unix-compat- , unliftio >=0.2.4.0+ , unliftio , unordered-containers , vector , yaml@@ -528,11 +530,11 @@ build-depends: Win32 else+ build-tools:+ hsc2hs build-depends: bindings-uname , unix- build-tools:- hsc2hs if !(flag(integration-tests)) buildable: False default-language: Haskell2010@@ -557,11 +559,12 @@ Stack.StaticBytesSpec Stack.StoreSpec Stack.Types.BuildPlanSpec+ Stack.Types.TemplateNameSpec Stack.Untar.UntarSpec Paths_stack hs-source-dirs: src/test- 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 -optP-Wno-nonportable-include-path -threaded build-depends: Cabal , QuickCheck@@ -574,7 +577,7 @@ , base64-bytestring , bytestring , conduit- , conduit-extra >=1.2.3.1+ , conduit-extra , containers , cryptonite , cryptonite-conduit@@ -638,10 +641,10 @@ , time , tls , transformers- , typed-process >=0.2.1.0+ , typed-process , unicode-transforms , unix-compat- , unliftio >=0.2.4.0+ , unliftio , unordered-containers , vector , yaml@@ -652,9 +655,9 @@ build-depends: Win32 else+ build-tools:+ hsc2hs build-depends: bindings-uname , unix- build-tools:- hsc2hs default-language: Haskell2010
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-11.6+resolver: lts-11.22 # docker: # enable: true@@ -9,7 +9,6 @@ # name: "fpco/stack-test" nix: # --nix on the command-line to enable.- enable: false packages: - zlib - unzip@@ -18,16 +17,28 @@ hide-dependency-versions: true supported-build: true extra-deps:-- 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+- Cabal-2.4.0.1@rev:0+- cabal-install-2.4.0.0@rev:1+- resolv-0.1.1.1@rev:0+- infer-license-0.2.0@rev:0 #for hpack-0.31+- hpack-0.31.0@rev:0+- http-api-data-0.3.8.1@rev:1+- githash-0.1.1.0@rev:0+- yaml-0.10.4.0@rev:0 #for hpack-0.31+- windns-0.1.0.0@rev:0+- hackage-security-0.5.3.0@rev:2+- cabal-doctest-1.0.6@rev:2 -# Avoid https://github.com/commercialhaskell/stack/issues/3922+# Avoid https://github.com/commercialhaskell/stack/issues/4125 # (triggered because later versions of persistent transitively depends # on haskell-src-exts, which needs the 'happy' build tool)+# THIS IS FIXED AS OF STACK 1.8, but keep these here until next major+# version to maintain the ability to build stack with older versions. - 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-1.2.13.1@rev:0 - conduit-extra-1.2.3.2@rev:0++ghc-options:+ "$locals": -fhide-source-paths
test/integration/IntegrationSpec.hs view
@@ -97,8 +97,8 @@ (ClosedStream, outSrc, errSrc, sph) <- streamingProcess cp (out, err, ec) <- runConcurrently $ (,,)- <$> Concurrently (outSrc $$ sinkLbs)- <*> Concurrently (errSrc $$ sinkLbs)+ <$> Concurrently (outSrc `connect` sinkLbs)+ <*> Concurrently (errSrc `connect` sinkLbs) <*> Concurrently (waitForStreamingProcess sph) when (ec /= ExitSuccess) $ throwIO $ TestFailure out err ec where@@ -120,7 +120,7 @@ copyTree :: (FilePath -> Bool) -> FilePath -> FilePath -> IO () copyTree toCopy src dst =- runResourceT (sourceDirectoryDeep False src $$ CL.mapM_ go)+ runResourceT (sourceDirectoryDeep False src `connect` CL.mapM_ go) `catch` \(_ :: IOException) -> return () where go srcfp = when (toCopy srcfp) $ liftIO $ do
test/integration/lib/StackTest.hs view
@@ -208,7 +208,7 @@ -- the main @stack.yaml@. -- defaultResolverArg :: String-defaultResolverArg = "--resolver=lts-11.6"+defaultResolverArg = "--resolver=lts-11.19" -- | Remove a file and ignore any warnings about missing files. removeFileIgnore :: FilePath -> IO ()