stack 0.1.8.0 → 0.1.10.0
raw patch · 63 files changed
+1983/−4590 lines, 63 filesdep +email-validatedep +uuiddep ~basedep ~conduitdep ~monad-logger
Dependencies added: email-validate, uuid
Dependency ranges changed: base, conduit, monad-logger, stack
Files
- CONTRIBUTING.md +9/−1
- ChangeLog.md +73/−3
- README.md +4/−197
- doc/GUIDE.md +0/−1736
- doc/MAINTAINER_GUIDE.md +0/−135
- doc/SIGNING_KEY.md +0/−34
- doc/architecture.md +0/−131
- doc/build_command.md +0/−114
- doc/dependency_visualization.md +0/−41
- doc/docker_integration.md +0/−477
- doc/faq.md +0/−281
- doc/install_and_upgrade.md +0/−251
- doc/nonstandard_project_init.md +0/−101
- doc/shell_autocompletion.md +0/−35
- doc/stack_and_ghcjs.md +0/−75
- doc/yaml_configuration.md +0/−407
- src/Network/HTTP/Download/Verified.hs +2/−1
- src/Options/Applicative/Complicated.hs +6/−1
- src/Stack/Build.hs +80/−1
- src/Stack/Build/ConstructPlan.hs +22/−18
- src/Stack/Build/Execute.hs +69/−44
- src/Stack/Build/Source.hs +23/−14
- src/Stack/Config.hs +65/−51
- src/Stack/Config/Docker.hs +22/−8
- src/Stack/Config/Nix.hs +45/−0
- src/Stack/Constants.hs +31/−7
- src/Stack/Coverage.hs +38/−18
- src/Stack/Docker.hs +66/−67
- src/Stack/Exec.hs +6/−7
- src/Stack/Fetch.hs +2/−1
- src/Stack/Ghci.hs +112/−33
- src/Stack/Ide.hs +8/−4
- src/Stack/Image.hs +14/−18
- src/Stack/Init.hs +1/−1
- src/Stack/New.hs +1/−1
- src/Stack/Nix.hs +129/−0
- src/Stack/Options.hs +40/−17
- src/Stack/Package.hs +48/−30
- src/Stack/SDist.hs +89/−23
- src/Stack/Setup.hs +20/−21
- src/Stack/Sig.hs +65/−0
- src/Stack/Sig/GPG.hs +102/−0
- src/Stack/Sig/Sign.hs +138/−0
- src/Stack/Types.hs +2/−0
- src/Stack/Types/Build.hs +22/−19
- src/Stack/Types/Config.hs +84/−24
- src/Stack/Types/Internal.hs +1/−0
- src/Stack/Types/Nix.hs +83/−0
- src/Stack/Types/Package.hs +8/−6
- src/Stack/Types/Sig.hs +99/−0
- src/Stack/Types/StackT.hs +9/−9
- src/Stack/Types/Version.hs +9/−0
- src/Stack/Upgrade.hs +20/−15
- src/Stack/Upload.hs +7/−1
- src/System/Process/Read.hs +1/−1
- src/System/Process/Run.hs +40/−32
- src/main/Main.hs +144/−38
- src/test/Stack/BuildPlanSpec.hs +2/−2
- src/test/Stack/ConfigSpec.hs +4/−4
- src/test/Stack/NixSpec.hs +67/−0
- stack.cabal +38/−32
- stack.yaml +1/−2
- test/integration/lib/StackTest.hs +12/−0
CONTRIBUTING.md view
@@ -1,3 +1,5 @@+# Contributors Guide+ ## Bug Reports When reporting a bug, please write in the following format:@@ -19,7 +21,7 @@ > _What actually happened._ >-> Here is the `stack ---version` output:+> Here is the `stack --version` output: > > ``` > $ stack --version@@ -40,7 +42,13 @@ ## Documentation+ If you would like to help with documentation, please note that for most cases the Wiki has been deprecated in favor of markdown files placed in a new `/doc` subdirectory of the repository itself. Please submit a [pull request](https://help.github.com/articles/using-pull-requests/) with your changes/additions.++The documentation is rendered on [haskellstack.org](http://haskellstack.org) by+readthedocs.org using Sphinx and CommonMark. Since links and formatting vary+from GFM, please check the documentation there before submitting a PR to fix+those. If your changes move or rename files, or subsume Wiki content, please continue to leave a file/page in the old location temporarily, in addition to the new location. This will allow users time to update any shared links to the old location. Please also update any links in other files, or on the Wiki, to point to the new file location.
ChangeLog.md view
@@ -1,10 +1,80 @@+# Changelog++## 0.1.10.0++Release notes:++* The Stack home page is now at [haskellstack.org](http://haskellstack.org),+ which shows the documentation rendered by readthedocs.org. Note: this+ has necessitated some changes to the links in the documentation's markdown+ source code, so please check the links on the website before submitting a PR+ to fix them.+* The locations of the+ [Ubuntu](http://docs.haskellstack.org/en/stable/install_and_upgrade.html#ubuntu)+ and+ [Debian](http://docs.haskellstack.org/en/stable/install_and_upgrade.html#debian)+ package repositories have changed to have correct URL semantics according to+ Debian's guidelines+ [#1378](https://github.com/commercialhaskell/stack/issues/1378). The old+ locations will continue to work for some months, but we suggest that you+ adjust your `/etc/apt/sources.list.d/fpco.list` to the new location to avoid+ future disruption.+* [openSUSE and SUSE Linux Enterprise](http://docs.haskellstack.org/en/stable/install_and_upgrade.html#opensuse-suse-linux-enterprise)+ packages are now available, thanks to [@mimi1vx](https://github.com/mimi1vx).+ Note: there will be some lag before these pick up new versions, as they are+ based on Stackage LTS.++Major changes:++* Support for building inside a Nix-shell providing system dependencies+ [#1285](https://github.com/commercialhaskell/stack/pull/1285)+* Add optional GPG signing on `stack upload --sign` or with+ `stack sig sign ...`++Other enhancements:++* Print latest applicable version of packages on conflicts+ [#508](https://github.com/commercialhaskell/stack/issues/508)+* Support for packages located in Mercurial repositories+ [#1397](https://github.com/commercialhaskell/stack/issues/1397)+* Only run benchmarks specified as build targets+ [#1412](https://github.com/commercialhaskell/stack/issues/1412)+* Support git-style executable fall-through (`stack something` executes+ `stack-something` if present)+ [#1433](https://github.com/commercialhaskell/stack/issues/1433)+* GHCi now loads intermediate dependencies+ [#584](https://github.com/commercialhaskell/stack/issues/584)+* `--work-dir` option for overriding `.stack-work`+ [#1178](https://github.com/commercialhaskell/stack/issues/1178)+* Support `detailed-0.9` tests+ [#1429](https://github.com/commercialhaskell/stack/issues/1429)+* Docker: improved POSIX signal proxying to containers+ [#547](https://github.com/commercialhaskell/stack/issues/547)++Bug fixes:++* Show absolute paths in error messages in multi-package builds+ [#1348](https://github.com/commercialhaskell/stack/issues/1348)+* Docker-built binaries and libraries in different path+ [#911](https://github.com/commercialhaskell/stack/issues/911)+ [#1367](https://github.com/commercialhaskell/stack/issues/1367)+* Docker: `--resolver` argument didn't effect selected image tag+* GHCi: Spaces in filepaths caused module loading issues+ [#1401](https://github.com/commercialhaskell/stack/issues/1401)+* GHCi: cpp-options in cabal files weren't used+ [#1419](https://github.com/commercialhaskell/stack/issues/1419)+* Benchmarks couldn't be run independently of eachother+ [#1412](https://github.com/commercialhaskell/stack/issues/1412)+* Send output of building setup to stderr+ [#1410](https://github.com/commercialhaskell/stack/issues/1410)+ ## 0.1.8.0 Major changes: * GHCJS can now be used with stackage snapshots via the new `compiler` field. * Windows installers are now available:- [download them here](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#windows)+ [download them here](http://docs.haskellstack.org/en/stable/install_and_upgrade.html#windows) [#613](https://github.com/commercialhaskell/stack/issues/613) * Docker integration works with non-FPComplete generated images [#531](https://github.com/commercialhaskell/stack/issues/531)@@ -73,7 +143,7 @@ * Fix: unlisted files in tests and benchmarks trigger extraneous second build [#838](https://github.com/commercialhaskell/stack/issues/838) -## v0.1.6.0+## 0.1.6.0 Major changes: @@ -218,7 +288,7 @@ * Respect TemplateHaskell addDependentFile dependency changes ([#105](https://github.com/commercialhaskell/stack/issues/105)) * TH dependent files are taken into account when determining whether a package needs to be built. * Overhauled target parsing, added `--test` and `--bench` options [#651](https://github.com/commercialhaskell/stack/issues/651)- * For details, see [Build commands documentation](doc/build_command.md)+ * For details, see [Build commands documentation](http://docs.haskellstack.org/en/stable/build_command.html) Other enhancements:
README.md view
@@ -4,201 +4,8 @@ [](https://ci.appveyor.com/project/snoyberg/stack) [](https://github.com/commercialhaskell/stack/releases) -`stack` is a cross-platform program for developing Haskell-projects. It is aimed at Haskellers both new and experienced.--<img src="http://i.imgur.com/WW69oTj.gif" width="50%" align="right">--It features:--* Installing GHC automatically, in an isolated location.-* Installing packages needed for your project.-* Building your project.-* Testing your project.-* Benchmarking your project.--#### How to install--Downloads are available by operating system:--* [Windows](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#windows)-* [Mac OS X](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#mac-os-x)-* [Ubuntu](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#ubuntu)-* [Debian](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#debian)-* [CentOS / Red Hat / Amazon Linux](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#centos--red-hat--amazon-linux)-* [Fedora](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#fedora)-* [Arch Linux](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#arch-linux)-* [NixOS](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#nixos)-* [Linux (general)](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#linux)--[Upgrade instructions](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md#upgrade)--Note: if you are using cabal-install to install stack, you may need to pass a-constraint to work around a-[Cabal issue](https://github.com/haskell/cabal/issues/2759): `cabal install---constraint 'mono-traversable >= 0.9' stack`.--#### Quick Start Guide--First you need to [install it (see previous section)](#how-to-install).--##### Start your new project:--~~~ {.bash}-stack new my-project-cd my-project-stack setup-stack build-stack exec my-project-exe-~~~--- The `stack new` command will create a new directory containing all-the needed files to start a project correctly.-- The `stack setup` will download the compiler if necessary in an isolated- location (default `~/.stack`) that won't interfere with any system-level- installations. (For information on installation paths, please use the `stack- path` command.).-- The `stack build` command will build the minimal project.-- `stack exec my-project-exe` will execute the command.-- If you just want to install an executable using stack, then all you have to do-is`stack install <package-name>`.--If you want to launch a REPL:--~~~ {.bash}-stack ghci-~~~---Run `stack` for a complete list of commands.--##### Workflow--The `stack new` command should have created the following files:--~~~-.-├── LICENSE-├── Setup.hs-├── app-│ └── Main.hs-├── my-project.cabal-├── src-│ └── Lib.hs-├── stack.yaml-└── test- └── Spec.hs-- 3 directories, 7 files-~~~--So to manage your library:--1. Edit files in the `src/` directory.--The `app` directory should preferably contains only files related to-executables.--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: ...`.- - run `stack build` another time--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.--It was a really fast introduction on how to start to code in Haskell using `stack`.-If you want to go further, we highly recommend you to read the [`stack` guide](https://github.com/commercialhaskell/stack/blob/master/doc/GUIDE.md).--#### How to contribute--This assumes that you have already installed a version of stack, and have `git`-installed.--1. Clone `stack` from git with- `git clone https://github.com/commercialhaskell/stack.git`.-2. Enter into the stack folder with `cd stack`.-3. Build `stack` using a pre-existing `stack` install with- `stack setup && stack build`.-4. Once `stack` finishes building, check the stack version with- `stack --version`. Make sure the version is the latest.-5. Look for issues tagged with- [`newcomer` and `awaiting-pr` labels](https://github.com/commercialhaskell/stack/issues?q=is%3Aopen+is%3Aissue+label%3Anewcomer+label%3A%22awaiting+pr%22)--Build from source as a one-liner:--```bash-git clone https://github.com/commercialhaskell/stack.git && \-cd stack && \-stack setup && \-stack build-```--#### Complete guide to stack--This repository also contains a complete [user guide to using stack-](https://github.com/commercialhaskell/stack/blob/release/doc/GUIDE.md), covering all of the most common use cases.---#### Questions, Feedback, Discussion--* For frequently asked questions about detailed or specific use-cases, please- see [the FAQ](https://github.com/commercialhaskell/stack/blob/release/doc/faq.md).-* For general questions, comments, feedback and support please write- to [the stack mailing list](https://groups.google.com/d/forum/haskell-stack).-* For bugs, issues, or requests please- [open an issue](https://github.com/commercialhaskell/stack/issues/new).-* When using Stack Overflow, please use [the haskell-stack- tag](http://stackoverflow.com/questions/tagged/haskell-stack).--#### Why stack?--stack is a project of the [Commercial Haskell](http://commercialhaskell.com/)-group, spearheaded by [FP Complete](https://www.fpcomplete.com/). It is-designed to answer the needs of commercial Haskell users, hobbyist Haskellers,-and individuals and companies thinking about starting to use Haskell. It is-intended to be easy to use for newcomers, while providing the customizability-and power experienced developers need.--While stack itself has been around since June of 2015, it is based on codebases-used by FP Complete for its corporate customers and internally for years prior.-stack is a refresh of that codebase combined with other open source efforts-like [stackage-cli](https://github.com/fpco/stackage-cli) to meet the needs of-users everywhere.--A large impetus for the work on stack was a [large survey of people interested-in-Haskell](https://www.fpcomplete.com/blog/2015/05/thousand-user-haskell-survey),-which rated build issues as a major concern. The stack team hopes that stack-can address these concerns.--<hr>--## Documentation Table Of Contents+`stack` is a cross-platform program for developing Haskell projects. It is aimed+at Haskellers both new and experienced. -* Project Documentation- * [Maintainer Guide](https://github.com/commercialhaskell/stack/blob/release/doc/MAINTAINER_GUIDE.md): includes releasing information- * [Signing Key](https://github.com/commercialhaskell/stack/blob/release/doc/SIGNING_KEY.md): downloadable stack binaries are signed- with this key-* Tool Documentation- * [Build Command](https://github.com/commercialhaskell/stack/blob/release/doc/build_command.md): reference for the syntax of the- build command and the command line targets- * [Dependency Visualization](https://github.com/commercialhaskell/stack/blob/release/doc/dependency_visualization.md): uses Graphviz- * [Docker Integration](https://github.com/commercialhaskell/stack/blob/release/doc/docker_integration.md)- * [FAQ](https://github.com/commercialhaskell/stack/blob/release/doc/faq.md): frequently asked questions about detailed or specific- use-cases- * [Install/Upgrade](https://github.com/commercialhaskell/stack/blob/release/doc/install_and_upgrade.md): a list of downloads- available by operating system, installation instructions, and upgrade- instructions- * [Nonstandard Project Initialization](https://github.com/commercialhaskell/stack/blob/release/doc/nonstandard_project_init.md)- * [Shell Autocompletion](https://github.com/commercialhaskell/stack/blob/release/doc/shell_autocompletion.md)- * [User Guide](https://github.com/commercialhaskell/stack/blob/release/doc/GUIDE.md): in-depth tutorial covering the most common use- cases and all major stack features (requires no prior Haskell tooling- experience)- * [YAML Configuration](https://github.com/commercialhaskell/stack/blob/release/doc/yaml_configuration.md): reference for writing- `stack.yaml` files-* Advanced Documentation- * [Architecture](https://github.com/commercialhaskell/stack/blob/release/doc/architecture.md): reference for people curious about- stack internals, wanting to get involved deeply in the codebase, or- wanting to use stack in unusual ways+See [haskellstack.org](http://haskellstack.org) or the `doc` directory for more+information.
− doc/GUIDE.md
@@ -1,1736 +0,0 @@-stack is a modern, cross-platform build tool for Haskell code.--This guide takes a new stack user through the typical workflows. This guide-will not teach Haskell or involve much code, and it requires no prior experience-with the Haskell packaging system or other build tools.--## Stack's functions--stack handles the management of your toolchain (including GHC — the Glasgow-Haskell Compiler — and, for Windows users, MSYS), building and registering-libraries, building build tool dependencies, and more. While it can use existing-tools on your system, stack has the capacity to be your one-stop shop for all-Haskell tooling you need. This guide will follow that stack-centric approach.--### What makes stack special?--The primary stack design point is __reproducible builds__. If you run `stack-build` today, you should get the same result running `stack build` tomorrow.-There are some cases that can break that rule (changes in your operating system-configuration, for example), but, overall, stack follows this design philosophy-closely. To make this a simple process, stack uses curated package sets-called __snapshots__.--stack has also been designed from the ground up to be user friendly, with an-intuitive, discoverable command line interface. For many users, simply-downloading stack and reading `stack --help` will be enough to get up and-running. This guide provides a more gradual tour for users who prefer that-learning style.--To build your project, stack uses a `stack.yaml` file in the root directory of-your project as a sort of blueprint. That file contains a reference, called a-__resolver__, to the snapshot which your package will be built against.--Finally, stack is __isolated__: it will not make changes outside of specific-stack directories. stack-built files generally go in either the stack root-directory (default `~/.stack`) or `./.stack-work` directories local to each-project. The stack root directory holds packages belonging to snapshots and any-stack-installed versions of GHC. Stack will not tamper with any system version-of GHC or interfere with packages installed by `cabal` or any other build tools.--_NOTE_ In this guide, we'll use commands as run on a GNU/Linux system-(specifically Ubuntu 14.04, 64-bit) and share output from that. Output on other-systems — or with different versions of stack — will be slightly different, but-all commands work cross-platform, unless explicitly stated otherwise.--## Downloading and Installation--The [documentation dedicated to downloading-stack](install_and_upgrade.md) has the most-up-to-date information for a variety of operating systems, including multiple-GNU/Linux flavors. Instead of repeating that content here, please go check out-that page and come back here when you can successfully run `stack --version`.-The rest of this session will demonstrate the installation procedure on a-vanilla Ubuntu 14.04 machine.--```-# Starting with a *really* bare machine-michael@d30748af6d3d:~$ sudo apt-get install wget-# Demonstrate that stack really isn't available-michael@d30748af6d3d:~$ stack--bash: stack: command not found-# Get the signing key for the package repo-michael@d30748af6d3d:~$ wget -q -O- https://s3.amazonaws.com/download.fpcomplete.com/ubuntu/fpco.key | sudo apt-key add --OK-michael@d30748af6d3d:~$ echo 'deb http://download.fpcomplete.com/ubuntu/trusty stable main'|sudo tee /etc/apt/sources.list.d/fpco.list-deb http://download.fpcomplete.com/ubuntu/trusty stable main-michael@d30748af6d3d:~$ sudo apt-get update && sudo apt-get install stack -y-# downloading...-michael@d30748af6d3d:~$ stack --version-Version 0.1.3.1, Git revision 908b04205e6f436d4a5f420b1c6c646ed2b804d7-```--With stack now up and running, you're good to go. Though not required, we-recommend setting your PATH environment variable to include `$HOME/.local/bin`:--```-michael@d30748af6d3d:~$ echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc-```--## Hello World Example--With stack installed, let's create a new project from a template and walk-through the most common stack commands.--### stack new--We'll start off with the `stack new` command to create a new-*project*. We'll call our project `helloworld`, and we'll use the-`new-template` project template:--```-michael@d30748af6d3d:~$ stack new helloworld new-template-```--For this first stack command, there's quite a bit of initial setup it needs to-do (such as downloading the list of packages available upstream), so you'll see-a lot of output. Though your exact results may vary, below is an example of the-sort of output you will see. Over the course of this guide a lot of the content-will begin to make more sense:--```-Downloading template "new-template" to create project "helloworld" in helloworld/ ...-Using the following authorship configuration:-author-email: example@example.com-author-name: Example Author Name-Copy these to /home/michael/.stack/config.yaml and edit to use different values.-Writing default config file to: /home/michael/helloworld/stack.yaml-Basing on cabal files:-- /home/michael/helloworld/helloworld.cabal--Downloaded lts-3.2 build plan.-Caching build plan-Fetched package index.-Populated index cache.-Checking against build plan lts-3.2-Selected resolver: lts-3.2-Wrote project config to: /home/michael/helloworld/stack.yaml-```-We now have a project in the `helloworld` directory!--### stack setup--Instead of assuming you want stack to download and install-GHC for you, it asks you to do this as a separate command:-`setup`. If we don't run `stack setup` now, we'll later see a-message that we are missing the right GHC version.--Let's run stack setup:--```-michael@d30748af6d3d:~/helloworld$ stack setup-Downloaded ghc-7.10.2.-Installed GHC.-stack will use a locally installed GHC-For more information on paths, see 'stack path' and 'stack exec env'-To use this GHC and packages outside of a project, consider using:-stack ghc, stack ghci, stack runghc, or stack exec-```--It doesn't come through in the output here, but you'll get intermediate-download percentage statistics while the download is occurring. This command-may take some time, depending on download speeds.--__NOTE__: GHC will be installed to your global stack root directory, so-calling `ghc` on the command line won't work. See the `stack exec`,-`stack ghc`, and `stack runghc` commands below for more information.--### stack build--Next, we'll run the most important stack command: `stack build`.--__NOTE__: If you forgot to run `stack setup` in the previous step you'll get an-error:--```-michael@d30748af6d3d:~$ cd helloworld/-michael@d30748af6d3d:~/helloworld$ stack build-No GHC found, expected version 7.10.2 (x86_64) (based on resolver setting in /home/michael/helloworld/stack.yaml).-Try running stack setup-```--stack needs GHC in order to build your project, and `stack setup` must be run to-check whether GHC is available (and install it if not).--Having run `stack setup` successfully, `stack build` should build our project:--```-michael@d30748af6d3d:~/helloworld$ stack build-helloworld-0.1.0.0: configure-Configuring helloworld-0.1.0.0...-helloworld-0.1.0.0: build-Preprocessing library helloworld-0.1.0.0...-[1 of 1] Compiling Lib ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )-In-place registering helloworld-0.1.0.0...-Preprocessing executable 'helloworld-exe' for helloworld-0.1.0.0...-[1 of 1] Compiling Main ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe-tmp/Main.o )-Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe ...-helloworld-0.1.0.0: install-Installing library in-/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/lib/x86_64-linux-ghc-7.10.2/helloworld-0.1.0.0-6urpPe0MO7OHasGCFSyIAT-Installing executable(s) in-/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/bin-Registering helloworld-0.1.0.0...-```--### stack exec--Looking closely at the output of the previous command, you can see that it built-both a library called "helloworld" and an executable called "helloworld-exe".-We'll explain more in the next section, but, for now, just notice that the-executables are installed in our project's `./stack-work` directory.--Now, Let's use `stack exec` to run our executable (which just outputs the string-"someFunc"):--```-michael@d30748af6d3d:~/helloworld$ stack exec helloworld-exe-someFunc-```--`stack exec` works by providing the same reproducible environment that was used-to build your project to the command that you are running. Thus, it knew where-to find `helloworld-exe` even though it is hidden in the `./stack-work`-directory.--### stack test--Finally, like all good software, helloworld actually has a test suite.-Let's run it with `stack test`:--```-michael@d30748af6d3d:~/helloworld$ stack test-NOTE: the test command is functionally equivalent to 'build --test'-helloworld-0.1.0.0: configure (test)-Configuring helloworld-0.1.0.0...-helloworld-0.1.0.0: build (test)-Preprocessing library helloworld-0.1.0.0...-In-place registering helloworld-0.1.0.0...-Preprocessing test suite 'helloworld-test' for helloworld-0.1.0.0...-[1 of 1] Compiling Main ( test/Spec.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test-tmp/Main.o )-Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test ...-helloworld-0.1.0.0: test (suite: helloworld-test)-Test suite not yet implemented-```--Reading the output, you'll see that stack first builds the test suite and then-automatically runs it for us. For both the `build` and `test` command, already-built components are not built again. You can see this by running `stack build`-and `stack test` a second time:--```-michael@d30748af6d3d:~/helloworld$ stack build-michael@d30748af6d3d:~/helloworld$ stack test-NOTE: the test command is functionally equivalent to 'build --test'-helloworld-0.1.0.0: test (suite: helloworld-test)-Test suite not yet implemented-```--## Inner Workings of stack--In this subsection, we'll dissect the helloworld example in more detail.--### Files in helloworld--Before studying stack more, let's understand our project a bit better.--```-michael@d30748af6d3d:~/helloworld$ find * -type f-LICENSE-Setup.hs-app/Main.hs-helloworld.cabal-src/Lib.hs-stack.yaml-test/Spec.hs-```--The `app/Main.hs`, `src/Lib.hs`, and `test/Spec.hs` files are all Haskell source-files that compose the actual functionality of our project (we won't dwell on-them here). The LICENSE file has no impact on the build, but is there for-informational/legal purposes only. The files of interest here are Setup.hs,-helloworld.cabal, and stack.yaml.--The Setup.hs file is a component of the Cabal build system which stack uses.-It's technically not needed by stack, but it is still considered good practice-in the Haskell world to include it. The file we're using is straight-boilerplate:--```haskell-import Distribution.Simple-main = defaultMain-```--Next, let's look at our stack.yaml file, which gives our project-level settings:--```yaml-flags: {}-packages:-- '.'-extra-deps: []-resolver: lts-3.2-```--If you're familiar with YAML, you may recognize that the `flags` and-`extra-deps` keys have empty values. We'll see more interesting usages for these-fields later. Let's focus on the other two fields. `packages` tells stack which-local packages to build. In our simple example, we have only a single package in-our project, located in the same directory, so `'.'` suffices. However, stack-has powerful support for multi-package projects, which we'll elaborate on as-this guide progresses.--The final field is resolver. This tells stack *how* to build your package:-which GHC version to use, versions of package dependencies, and so on. Our-value here says to use [LTS Haskell version-3.2](https://www.stackage.org/lts-3.2), which implies GHC 7.10.2 (which is why-`stack setup` installs that version of GHC). There are a number of values you-can use for resolver, which we'll cover later.--The final file of import is helloworld.cabal. stack is built on top of the-Cabal build system. In Cabal, we have individual *packages*, each of which-contains a single .cabal file. The .cabal file can define 1 or more-*components*: a library, executables, test suites, and benchmarks. It also-specifies additional information such as library dependencies, default language-pragmas, and so on.--In this guide, we'll discuss the bare minimum necessary to understand how to-modify a .cabal file. Haskell.org has the definitive [reference for the .cabal-file format](https://www.haskell.org/cabal/users-guide/developing-packages.html).--### The setup command--As we saw above, the `setup` command installed GHC for us. Just for kicks,-let's run `setup` a second time:--```-michael@d30748af6d3d:~/helloworld$ stack setup-stack will use a locally installed GHC-For more information on paths, see 'stack path' and 'stack exec env'-To use this GHC and packages outside of a project, consider using:-stack ghc, stack ghci, stack runghc, or stack exec-```--Thankfully, the command is smart enough to know not to perform an installation-twice. `setup` will either use the first GHC it finds on your PATH, or a locally-installed version. As the command output above indicates, you can use `stack-path` for quite a bit of path information (which we'll play with more later).-For now, we'll just look at where GHC is installed:--```-michael@d30748af6d3d:~/helloworld$ stack exec which ghc-/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/bin/ghc-```--As you can see from that path (and as emphasized earlier), the installation is-placed to not interfere with any other GHC installation, whether system-wide or-even different GHC versions installed by stack.--### The build command--The build command is the heart and soul of stack. It is the engine that powers-building your code, testing it, getting dependencies, and more. Quite a bit of-the remainder of this guide will cover more advanced `build` functions and-features, such as building test and Haddocks at the same time, or constantly-rebuilding blocking on file changes.--*On a philosophical note:* Running the build command twice with the same-options and arguments should generally be a no-op (besides things like-rerunning test suites), and should, in general, produce a reproducible result-between different runs.--## Adding dependencies--Let's say we decide to modify our helloworld source a bit to use a new library,-perhaps the ubiquitous text package. For example:--```haskell-{-# LANGUAGE OverloadedStrings #-}-module Lib- ( someFunc- ) where--import qualified Data.Text.IO as T--someFunc :: IO ()-someFunc = T.putStrLn "someFunc"-```--When we try to build this, things don't go as expected:--```haskell-michael@d30748af6d3d:~/helloworld$ stack build-helloworld-0.1.0.0-c91e853ce4bfbf6d394f54b135573db8: unregistering (local file changes)-helloworld-0.1.0.0: configure-Configuring helloworld-0.1.0.0...-helloworld-0.1.0.0: build-Preprocessing library helloworld-0.1.0.0...--/home/michael/helloworld/src/Lib.hs:6:18:- Could not find module `Data.Text.IO'- Use -v to see a list of the files searched for.---- While building package helloworld-0.1.0.0 using:- /home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/bin/runhaskell -package=Cabal-1.22.4.0 -clear-package-db -global-package-db -package-db=/home/michael/.stack/snapshots/x86_64-linux/lts-3.2/7.10.2/pkgdb/ /tmp/stack5846/Setup.hs --builddir=.stack-work/dist/x86_64-linux/Cabal-1.22.4.0/ build exe:helloworld-exe --ghc-options -hpcdir .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/hpc/.hpc/ -ddump-hi -ddump-to-file- Process exited with code: ExitFailure 1-```--Notice that it says "Could not find module." This means that the package-containing the module in question is not available. To tell stack to use text,-you need to add it to your .cabal file — specifically in your build-depends-section, like this:--```cabal-library- hs-source-dirs: src- exposed-modules: Lib- build-depends: base >= 4.7 && < 5- -- This next line is the new one- , text- default-language: Haskell2010-```--Now if we rerun `stack build`, we should get a successful result:--```-michael@d30748af6d3d:~/helloworld$ stack build-text-1.2.1.3: download-text-1.2.1.3: configure-text-1.2.1.3: build-text-1.2.1.3: install-helloworld-0.1.0.0: configure-Configuring helloworld-0.1.0.0...-helloworld-0.1.0.0: build-Preprocessing library helloworld-0.1.0.0...-[1 of 1] Compiling Lib ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )-In-place registering helloworld-0.1.0.0...-Preprocessing executable 'helloworld-exe' for helloworld-0.1.0.0...-[1 of 1] Compiling Main ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe-tmp/Main.o ) [Lib changed]-Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe ...-helloworld-0.1.0.0: install-Installing library in-/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/lib/x86_64-linux-ghc-7.10.2/helloworld-0.1.0.0-HI1deOtDlWiAIDtsSJiOtw-Installing executable(s) in-/home/michael/helloworld/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/bin-Registering helloworld-0.1.0.0...-Completed all 2 actions.-```--This output means that the text package was downloaded, configured, built, and-locally installed. Once that was done, we moved on to building our local package-(helloworld). At no point did we need to ask stack to build dependencies — it-does so automatically.--### extra-deps--Let's try a more off-the-beaten-track package: the joke-[acme-missiles](http://www.stackage.org/package/acme-missiles) package. Our-source code is simple:--```haskell-module Lib- ( someFunc- ) where--import Acme.Missiles--someFunc :: IO ()-someFunc = launchMissiles-```--In this case, we can add acme-missiles to the .cabal file, but we get a new type-of error message from `stack build`:--```-michael@d30748af6d3d:~/helloworld$ stack build-While constructing the BuildPlan the following exceptions were encountered:---- While attempting to add dependency,- Could not find package acme-missiles in known packages---- Failure when adding dependencies:- acme-missiles: needed (-any), latest is 0.3, but not present in build plan- needed for package: helloworld-0.1.0.0--Recommended action: try adding the following to your extra-deps in /home/michael/helloworld/stack.yaml-- acme-missiles-0.3--You may also want to try the 'stack solver' command-```--It says acme-missiles is "not present in build plan." This brings us to the next-major topic in using stack.--## Curated package sets--Remember above when `stack new` selected the lts-3.2 resolver for us? That-defined our build plan and available packages. When we tried using the-text package, it just worked, because it was part of the lts-3.2 *package set*.-But acme-missiles is not part of that package set, so building failed.--To add this new dependency, we'll use the `extra-deps` field in stack.yaml to-define extra dependencies not present in the resolver. With that change, our-stack.yaml looks like:--```yaml-flags: {}-packages:-- '.'-extra-deps:-- acme-missiles-0.3 # not in lts-3.2-resolver: lts-3.2-```--Now `stack build` will succeed.--With that out of the way, let's dig a little bit more into these package sets,-also known as *snapshots*. We mentioned lts-3.2, and you can get quite a bit of-information about it at-[https://www.stackage.org/lts-3.2](https://www.stackage.org/lts-3.2), including:--* The appropriate resolver value (`resolver: lts-3.2`, as we used above)-* 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-* A [list of all modules](https://www.stackage.org/lts-3.2/docs) in a snapshot,- which an be useful when trying to determine which package to add to your- .cabal file--You can also see a [list of all available-snapshots](https://www.stackage.org/snapshots). You'll notice two flavors: LTS-(for "Long Term Support") and Nightly. You can read more about them on the-[LTS Haskell Github page](https://github.com/fpco/lts-haskell#readme). If you're-not sure which to use, start with LTS Haskell (which stack will lean towards by-default as well).--## Resolvers and changing your compiler version--Let's explore package sets a bit further. Instead of lts-3.2, let's change our-stack.yaml file to use-[nightly-2015-08-26](https://www.stackage.org/nightly-2015-08-26). Rerunning-`stack build` will produce:--```-michael@d30748af6d3d:~/helloworld$ stack build-Downloaded nightly-2015-08-26 build plan.-Caching build plan-stm-2.4.4: configure-stm-2.4.4: build-stm-2.4.4: install-acme-missiles-0.3: configure-acme-missiles-0.3: build-acme-missiles-0.3: install-helloworld-0.1.0.0: configure-Configuring helloworld-0.1.0.0...-helloworld-0.1.0.0: build-Preprocessing library helloworld-0.1.0.0...-In-place registering helloworld-0.1.0.0...-Preprocessing executable 'helloworld-exe' for helloworld-0.1.0.0...-Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-exe/helloworld-exe ...-helloworld-0.1.0.0: install-Installing library in-/home/michael/helloworld/.stack-work/install/x86_64-linux/nightly-2015-08-26/7.10.2/lib/x86_64-linux-ghc-7.10.2/helloworld-0.1.0.0-6cKaFKQBPsi7wB4XdqRv8w-Installing executable(s) in-/home/michael/helloworld/.stack-work/install/x86_64-linux/nightly-2015-08-26/7.10.2/bin-Registering helloworld-0.1.0.0...-Completed all 3 actions.-```--We can also change resolvers on the command line, which can be useful in a-Continuous Integration (CI) setting, like on Travis. For example:--```-michael@d30748af6d3d:~/helloworld$ stack --resolver lts-3.1 build-Downloaded lts-3.1 build plan.-Caching build plan-stm-2.4.4: configure-# Rest is the same, no point copying it-```--When passed on the command line, you also get some additional "short-cut"-versions of resolvers: `--resolver nightly` will use the newest Nightly resolver-available, `--resolver lts` will use the newest LTS, and `--resolver lts-2` will-use the newest LTS in the 2.X series. The reason these are only available on the-command line and not in your stack.yaml file is that using them:--1. Will slow down your build (since stack then needs to download information on- the latest available LTS each time it builds)-2. Produces unreliable results (since a build run today may proceed differently- tomorrow because of changes outside of your control)--### Changing GHC versions--Finally, let's try using an older LTS snapshot. We'll use the newest 2.X-snapshot:--```-michael@d30748af6d3d:~/helloworld$ stack --resolver lts-2 build-Selected resolver: lts-2.22-Downloaded lts-2.22 build plan.-Caching build plan-No GHC found, expected version 7.8.4 (x86_64) (based on resolver setting in /home/michael/helloworld/stack.yaml). Try running stack setup-```--This fails, because GHC 7.8.4 (which lts-2.22 uses) is not available on our-system. So, we see that different LTS versions (2 vs 3 in this case) use-different GHC versions. Now, how do we get the right GHC version after changing-the LTS version? One answer is to use `stack setup` like we did above, this-time with the `--resolver lts-2` option. However, there's another method worth-mentioning: the `--install-ghc` flag.--```-michael@d30748af6d3d:~/helloworld$ stack --resolver lts-2 --install-ghc build-Selected resolver: lts-2.22-Downloaded ghc-7.8.4.-Installed GHC.-stm-2.4.4: configure-# Mostly same as before, nothing interesting to see-```--What's nice about `--install-ghc` is:--1. You don't need to have an extra step in your build script-2. It only requires downloading the information on latest snapshots once--As mentioned above, the default behavior of stack is to *not* install new-versions of GHC automatically. We want to avoid surprising users with large-downloads/installs. The `--install-ghc` flag simply changes that default-behavior.--### Other resolver values--We've mentioned `nightly-YYYY-MM-DD` and `lts-X.Y` values for the resolver.-There are actually other options available, and the list will grow over time.-At the time of writing:--* `ghc-X.Y.Z`, for requiring a specific GHC version but no additional packages-* Experimental GHCJS support-* Experimental custom snapshot support--The most up-to-date information can always be found in the-[stack.yaml documentation](yaml_configuration.md#resolver).--## Existing projects--Alright, enough playing around with simple projects. Let's take an open source-package and try to build it. We'll be ambitious and use-[yackage](https://www.stackage.org/package/yackage), a local package server-using [Yesod](http://www.yesodweb.com/). To get the code, we'll use the `stack-unpack` command:--```-michael@d30748af6d3d:~$ stack unpack yackage-0.8.0-yackage-0.8.0: download-Unpacked yackage-0.8.0 to /home/michael/yackage-0.8.0/-michael@d30748af6d3d:~$ cd yackage-0.8.0/-```--This new directory does not have a stack.yaml file, so we need to make one-first. We could do it by hand, but let's be lazy instead with the `stack init`-command:--```-michael@d30748af6d3d:~/yackage-0.8.0$ stack init-Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml-Basing on cabal files:-- /home/michael/yackage-0.8.0/yackage.cabal--Checking against build plan lts-3.2-Selected resolver: lts-3.2-Wrote project config to: /home/michael/yackage-0.8.0/stack.yaml-michael@d30748af6d3d:~/yackage-0.8.0$ cat stack.yaml-flags:- yackage:- upload: true-packages:-- '.'-extra-deps: []-resolver: lts-3.2-```--stack init does quite a few things for you behind the scenes:--* Creates a list of snapshots that would be good candidates.- * The basic algorithm here is to prefer options in this order:- * Snapshots for which you've already built some packages (to- increase sharing of binary package databases, as we'll discuss later)- * Recent snapshots- * LTS- * These preferences can be tweaked with command line flags (see `stack init- --help`).-* Finds all of the .cabal files in your current directory and subdirectories- (unless you use `--ignore-subdirs`) and determines the packages and versions- they require-* Finds a combination of snapshot and package flags that allows everything to- compile--Assuming it finds a match, it will write your stack.yaml file, and everything-will work. Given that LTS Haskell and Stackage Nightly have ~1400 of the most-common Haskell packages, this will often be enough. However, let's simulate a-failure by adding acme-missiles to our build-depends and re-initing:--```-michael@d30748af6d3d:~/yackage-0.8.0$ stack init --force-Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml-Basing on cabal files:-- /home/michael/yackage-0.8.0/yackage.cabal--Checking against build plan lts-3.2--* Build plan did not match your requirements:- acme-missiles not found- - yackage requires -any--Checking against build plan lts-3.1--* Build plan did not match your requirements:- acme-missiles not found- - yackage requires -any---Checking against build plan nightly-2015-08-26--* Build plan did not match your requirements:- acme-missiles not found- - yackage requires -any---Checking against build plan lts-2.22--* Build plan did not match your requirements:- acme-missiles not found- - yackage requires -any-- warp version 3.0.13.1 found- - yackage requires >=3.1---There was no snapshot found that matched the package bounds in your .cabal files.-Please choose one of the following commands to get started.-- stack init --resolver lts-3.2- stack init --resolver lts-3.1- stack init --resolver nightly-2015-08-26- stack init --resolver lts-2.22--You'll then need to add some extra-deps. See the-[stack.yaml documentation](yaml_configuration.md#extra-deps).--You can also try falling back to a dependency solver with:-- stack init --solver-```--stack has tested four different snapshots, and in every case discovered that-acme-missiles is not available. Also, when testing lts-2.22, it found that the-warp version provided was too old for yackage. So, what do we do?--The recommended approach is: pick a resolver, and fix the problem. Again,-following the advice mentioned above, default to LTS if you don't have a-preference. In this case, the newest LTS listed is lts-3.2. Let's pick that.-stack has told us the correct command to do this. We'll just remove our old-stack.yaml first and then run it:--```-michael@d30748af6d3d:~/yackage-0.8.0$ rm stack.yaml-michael@d30748af6d3d:~/yackage-0.8.0$ stack init --resolver lts-3.2-Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml-Basing on cabal files:-- /home/michael/yackage-0.8.0/yackage.cabal--Checking against build plan lts-3.2--* Build plan did not match your requirements:- acme-missiles not found- - yackage requires -any---Selected resolver: lts-3.2-Wrote project config to: /home/michael/yackage-0.8.0/stack.yaml-```--As you may guess, `stack build` will now fail due to the missing acme-missiles.-Toward the end of the error message, it says the familiar:--```-Recommended action: try adding the following to your extra-deps in /home/michael/yackage-0.8.0/stack.yaml-- acme-missiles-0.3-```--If you're following along at home, try making the necessary stack.yaml-modification to get things building.--### Alternative solution: dependency solving--There's another solution to consider for missing dependencies. At the end-of the previous error message, it said:--```-You may also want to try the 'stack solver' command-```--This approach uses a full-blown dependency solver to look at all upstream-package versions available and compare them to your snapshot selection and-version ranges in your .cabal file. In order to use this feature, you'll need-the cabal executable available. Let's build that with:--```-michael@d30748af6d3d:~/yackage-0.8.0$ stack build cabal-install-random-1.1: download-mtl-2.2.1: download-network-2.6.2.1: download-old-locale-1.0.0.7: download-random-1.1: configure-random-1.1: build-# ...-cabal-install-1.22.6.0: download-cabal-install-1.22.6.0: configure-cabal-install-1.22.6.0: build-cabal-install-1.22.6.0: install-Completed all 10 actions.-```--Now we can use `stack solver`:--```-michael@d30748af6d3d:~/yackage-0.8.0$ stack solver-This command is not guaranteed to give you a perfect build plan-It's possible that even with the changes generated below, you will still need to do some manual tweaking-Asking cabal to calculate a build plan, please wait-extra-deps:-- acme-missiles-0.3-```--And if we're exceptionally lazy, we can ask stack to modify our stack.yaml file-for us:--```-michael@d30748af6d3d:~/yackage-0.8.0$ stack solver --modify-stack-yaml-This command is not guaranteed to give you a perfect build plan-It's possible that even with the changes generated below, you will still need to do some manual tweaking-Asking cabal to calculate a build plan, please wait-extra-deps:-- acme-missiles-0.3-Updated /home/michael/yackage-0.8.0/stack.yaml-```--With that change, `stack build` will now run.--NOTE: You should probably back up your stack.yaml before doing this, such as-committing to Git/Mercurial/Darcs.--There's one final approach to mention: skipping the snapshot entirely and just-using dependency solving. You can do this with the `--solver` flag to `init`.-This is not a commonly used workflow with stack, as you end up with a large-number of extra-deps and no guarantee that the packages will compile together.-For those interested, however, the option is available. You need to make sure-you have both the ghc and cabal commands on your PATH. An easy way to do this-is to use the `stack exec` command:--```-michael@d30748af6d3d:~/yackage-0.8.0$ stack exec -- stack init --solver --force-Writing default config file to: /home/michael/yackage-0.8.0/stack.yaml-Basing on cabal files:-- /home/michael/yackage-0.8.0/yackage.cabal--Asking cabal to calculate a build plan, please wait-Selected resolver: ghc-7.10-Wrote project config to: /home/michael/yackage-0.8.0/stack.yaml-```--## Different databases--Time to take a short break from hands-on examples and discuss a little-architecture. stack has the concept of multiple *databases*. A database-consists of a GHC package database (which contains the compiled version of a-library), executables, and a few other things as well. To give you an idea:--```-michael@d30748af6d3d:~/helloworld$ ls .stack-work/install/x86_64-linux/lts-3.2/7.10.2/-bin doc flag-cache lib pkgdb-```--Databases in stack are *layered*. For example, the database listing we just gave-is called a *local* database. That is layered on top of a *snapshot* database,-which contains the libraries and executables specified in the snapshot itself.-Finally, GHC itself ships with a number of libraries and executables, which-forms the *global* database. To get a quick idea of this, we can look at the-output of the `stack exec ghc-pkg list` command in our helloworld project:--```-/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/lib/ghc-7.10.2/package.conf.d- Cabal-1.22.4.0- array-0.5.1.0- base-4.8.1.0- bin-package-db-0.0.0.0- binary-0.7.5.0- bytestring-0.10.6.0- containers-0.5.6.2- deepseq-1.4.1.1- directory-1.2.2.0- filepath-1.4.0.0- ghc-7.10.2- ghc-prim-0.4.0.0- haskeline-0.7.2.1- hoopl-3.10.0.2- hpc-0.6.0.2- integer-gmp-1.0.0.0- pretty-1.1.2.0- process-1.2.3.0- rts-1.0- template-haskell-2.10.0.0- terminfo-0.4.0.1- time-1.5.0.1- transformers-0.4.2.0- unix-2.7.1.0- xhtml-3000.2.1-/home/michael/.stack/snapshots/x86_64-linux/nightly-2015-08-26/7.10.2/pkgdb- stm-2.4.4-/home/michael/helloworld/.stack-work/install/x86_64-linux/nightly-2015-08-26/7.10.2/pkgdb- acme-missiles-0.3- helloworld-0.1.0.0-```--Notice that acme-missiles ends up in the *local* database. Anything which is-not installed from a snapshot ends up in the local database. This includes:-your own code, extra-deps, and in some cases even snapshot packages, if you-modify them in some way. The reason we have this structure is that:--* it lets multiple projects reuse the same binary builds of many snapshot- packages,-* but doesn't allow different projects to "contaminate" each other by putting- non-standard content into the shared snapshot database--Typically, the process by which a snapshot package is marked as modified is-referred to as "promoting to an extra-dep," meaning we treat it just like a-package in the extra-deps section. This happens for a variety of reasons,-including:--* changing the version of the snapshot package-* changing build flags-* one of the packages that the package depends on has been promoted to an- extra-dep--As you probably guessed, there are multiple snapshot databases available, e.g.:--```-michael@d30748af6d3d:~/helloworld$ ls ~/.stack/snapshots/x86_64-linux/-lts-2.22 lts-3.1 lts-3.2 nightly-2015-08-26-```--These databases don't get layered on top of each other; they are each used-separately.--In reality, you'll rarely — if ever — interact directly with these databases,-but it's good to have a basic understanding of how they work so you can-understand why rebuilding may occur at different points.--## The build synonyms--Let's look at a subset of the `stack --help` output:--```-build Build the package(s) in this directory/configuration-install Shortcut for 'build --copy-bins'-test Shortcut for 'build --test'-bench Shortcut for 'build --bench'-haddock Shortcut for 'build --haddock'-```--Note that four of these commands are just synonyms for the `build` command. They-are provided for convenience for common cases (e.g., `stack test` instead of-`stack build --test`) and so that commonly expected commands just work.--What's so special about these commands being synonyms? It allows us to make-much more composable command lines. For example, we can have a command that-builds executables, generates Haddock documentation (Haskell API-level docs),-and builds and runs your test suites, with:--```-stack build --haddock --test-```--You can even get more inventive as you learn about other flags. For example,-take the following:--```-stack build --pedantic --haddock --test --exec "echo Yay, it succeeded" --file-watch-```--This will:--* turn on all warnings and errors-* build your library and executables-* generate Haddocks-* build and run your test suite-* run the command `echo Yay, it succeeded` when that completes-* after building, watch for changes in the files used to build the project, and- kick off a new build when done--### install and copy-bins--It's worth calling out the behavior of the install command and `--copy-bins`-option, since this has confused a number of users (especially when compared to-behavior of other tools like cabal-install). The `install` command does-precisely one thing in addition to the build command: it copies any generated-executables to the local bin path. You may recognize the default value for that-path:--```-michael@d30748af6d3d:~/helloworld$ stack path --local-bin-path-/home/michael/.local/bin-```--That's why the download page recommends adding that directory to your `PATH`-environment variable. This feature is convenient, because now you can simply-run `executable-name` in your shell instead of having to run `stack exec-executable-name` from inside your project directory.--Since it's such a point of confusion, let me list a number of things stack does-*not* do specially for the install command:--* stack will always build any necessary dependencies for your code. The install- command is not necessary to trigger this behavior. If you just want to build a- project, run `stack build`.-* stack will *not* track which files it's copied to your local bin path nor- provide a way to automatically delete them. There are many great tools out- there for managing installation of binaries, and stack does not attempt to- replace those.-* stack will not necessarily be creating a relocatable executable. If your- executables hard-codes paths, copying the executable will not change those- hard-coded paths.- * At the time of writing, there's no way to change those kinds of paths with- stack, but see [issue #848 about- --prefix](https://github.com/commercialhaskell/stack/issues/848) for- future plans.--That's really all there is to the install command: for the simplicity of what-it does, it occupies a much larger mental space than is warranted.--## Targets, locals, and extra-deps--We haven't discussed this too much yet, but, in addition to having a number of-synonyms *and* taking a number of options on the command line, the build command-*also* takes many arguments. These are parsed in different ways, and can be used-to achieve a high level of flexibility in telling stack exactly what you want-to build.--We're not going to cover the full generality of these arguments here; instead,-there's [documentation covering the full build command-syntax](build_command.md).-Here, we'll just point out a few different types of arguments:--* You can specify a *package name*, e.g. `stack build vector`.- * This will attempt to build the vector package, whether it's a local- package, in your extra-deps, in your snapshot, or just available upstream.- If it's just available upstream but not included in your locals,- extra-deps, or snapshot, the newest version is automatically promoted to- an extra-dep.-* You can also give a *package identifier*, which is a package name plus- version, e.g. `stack build yesod-bin-1.4.14`.- * This is almost identical to specifying a package name, except it will (1)- choose the given version instead of latest, and (2) error out if the given- version conflicts with the version of a local package.-* The most flexibility comes from specifying individual *components*, e.g.- `stack build helloworld:test:helloworld-test` says "build the test suite- component named helloworld-test from the helloworld package."- * In addition to this long form, you can also shorten it by skipping what- type of component it is, e.g. `stack build helloworld:helloworld-test`, or- even skip the package name entirely, e.g. `stack build :helloworld-test`.-* Finally, you can specify individual *directories* to build to trigger building- of any local packages included in those directories or subdirectories.--When you give no specific arguments on the command line (e.g., `stack build`),-it's the same as specifying the names of all of your local packages. If you-just want to build the package for the directory you're currently in, you can-use `stack build .`.--### Components, --test, and --bench--Here's one final important yet subtle point. Consider our helloworld package:-it has a library component, an executable helloworld-exe, and a test suite-helloworld-test. When you run `stack build helloworld`, how does it know which-ones to build? By default, it will build the library (if any) and all of the-executables but ignore the test suites and benchmarks.--This is where the `--test` and `--bench` flags come into play. If you use them,-those components will also be included. So `stack build --test helloworld` will-end up including the helloworld-test component as well.--You can bypass this implicit adding of components by being much more explicit,-and stating the components directly. For example, the following will not build-the helloworld-exe executable:--```-michael@d30748af6d3d:~/helloworld$ stack clean-michael@d30748af6d3d:~/helloworld$ stack build :helloworld-test-helloworld-0.1.0.0: configure (test)-Configuring helloworld-0.1.0.0...-helloworld-0.1.0.0: build (test)-Preprocessing library helloworld-0.1.0.0...-[1 of 1] Compiling Lib ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )-In-place registering helloworld-0.1.0.0...-Preprocessing test suite 'helloworld-test' for helloworld-0.1.0.0...-[1 of 1] Compiling Main ( test/Spec.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test-tmp/Main.o )-Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/helloworld-test/helloworld-test ...-helloworld-0.1.0.0: test (suite: helloworld-test)-Test suite not yet implemented-```--We first cleaned our project to clear old results so we know exactly what stack-is trying to do. Notice that it builds the helloworld-test test suite, and the-helloworld library (since it's used by the test suite), but it does not build-the helloworld-exe executable.--And now the final point: the last line shows that our command also *runs* the-test suite it just built. This may surprise some people who would expect tests-to only be run when using `stack test`, but this design decision is what allows-the `stack build` command to be as composable as it is (as described-previously). The same rule applies to benchmarks. To spell it out completely:--* The --test and --bench flags simply state which components of a package should- be built, if no explicit set of components is given-* The default behavior for any test suite or benchmark component which has been- built is to also run it--You can use the `--no-run-tests` and `--no-run-benchmarks` (from stack-0.1.4.0-and on) flags to disable running of these components. You can also use-`--no-rerun-tests` to prevent running a test suite which has already passed and-has not changed.--NOTE: stack doesn't build or run test suites and benchmarks for non-local-packages. This is done so that running a command like `stack test` doesn't need-to run 200 test suites!--## Multi-package projects--Until now, everything we've done with stack has used a single-package project.-However, stack's power truly shines when you're working on multi-package-projects. All the functionality you'd expect to work just does: dependencies-between packages are detected and respected, dependencies of all packages are-just as one cohesive whole, and if anything fails to build, the build commands-exits appropriately.--Let's demonstrate this with the wai-app-static and yackage packages:--```-michael@d30748af6d3d:~$ mkdir multi-michael@d30748af6d3d:~$ cd multi/-michael@d30748af6d3d:~/multi$ stack unpack wai-app-static-3.1.1 yackage-0.8.0-wai-app-static-3.1.1: download-Unpacked wai-app-static-3.1.1 to /home/michael/multi/wai-app-static-3.1.1/-Unpacked yackage-0.8.0 to /home/michael/multi/yackage-0.8.0/-michael@d30748af6d3d:~/multi$ stack init-Writing default config file to: /home/michael/multi/stack.yaml-Basing on cabal files:-- /home/michael/multi/yackage-0.8.0/yackage.cabal-- /home/michael/multi/wai-app-static-3.1.1/wai-app-static.cabal--Checking against build plan lts-3.2-Selected resolver: lts-3.2-Wrote project config to: /home/michael/multi/stack.yaml-michael@d30748af6d3d:~/multi$ stack build --haddock --test-# Goes off to build a whole bunch of packages-```--If you look at the stack.yaml, you'll see exactly what you'd expect:--```yaml-flags:- yackage:- upload: true- wai-app-static:- print: false-packages:-- yackage-0.8.0/-- wai-app-static-3.1.1/-extra-deps: []-resolver: lts-3.2-```--Notice that multiple directories are listed in the `packages` key.--In addition to local directories, you can also refer to packages available in a-Git repository or in a tarball over HTTP/HTTPS. This can be useful for using a-modified version of a dependency that hasn't yet been released upstream. This is-a slightly more advanced usage that we won't go into detail with here, but it's-covered in the [stack.yaml documentation](yaml_configuration.md#packages).--## Flags and GHC options--There are two common ways to alter how a package will install: with Cabal flags-and with GHC options.--### Cabal flag management--In the stack.yaml file above, you can see that `stack init` has detected that —-for the yackage package — the upload flag can be set to true, and for-wai-app-static, the print flag to false (it's chosen those values because-they're the default flag values, and their dependencies are compatible with the-snapshot we're using.) To change a flag setting, we can use the command-line `--flag` option:-- stack build --flag yackage:-upload--This means: when compiling the yackage package, turn off the upload flag (thus-the `-`). Unlike other tools, stack is explicit about which package's flag you-want to change. It does this for two reasons:--1. There's no global meaning for Cabal flags, and therefore two packages can- use the same flag name for completely different things.-2. By following this approach, we can avoid unnecessarily recompiling snapshot- packages that happen to use a flag that we're using.--You can also change flag values on the command line for extra-dep and snapshot-packages. If you do this, that package will automatically be promoted to an-extra-dep, since the build plan is different than what the plan snapshot-definition would entail.--### GHC options--GHC options follow a similar logic as in managing Cabal flags, with a few-nuances to adjust for common use cases. Let's consider:-- stack build --ghc-options="-Wall -Werror"--This will set the `-Wall -Werror` options for all *local targets*. Note that-this will not affect extra-dep and snapshot packages at all. This design-provides us with reproducible and fast builds.--(By the way: the above GHC options have a special convenience flag:-`--pedantic`.)--There's one extra nuance about command line GHC options: Since they only apply-to local targets, if you change your local targets, they will no longer apply-to other packages. Let's play around with an example from the wai repository,-which includes the wai and warp packages, the latter depending on the former.-If we run:-- stack build --ghc-options=-O0 wai--It will build all of the dependencies of wai, and then build wai with all-optimizations disabled. Now let's add in warp as well:-- stack build --ghc-options=-O0 wai warp--This builds the additional dependencies for warp, and then builds warp with-optimizations disabled. Importantly: it does not rebuild wai, since wai's-configuration has not been altered. Now the surprising case:--```-michael@d30748af6d3d:~/wai$ stack build --ghc-options=-O0 warp-wai-3.0.3.0-5a49351d03cba6cbaf906972d788e65d: unregistering (flags changed from ["--ghc-options","-O0"] to [])-warp-3.1.3-a91c7c3108f63376877cb3cd5dbe8a7a: unregistering (missing dependencies: wai)-wai-3.0.3.0: configure-```--You may expect this to be a no-op: neither wai nor warp has changed. However,-stack will instead recompile wai with optimizations enabled again, and then-rebuild warp (with optimizations disabled) against this newly built wai. The-reason: reproducible builds. If we'd never built wai or warp before, trying to-build warp would necessitate building all of its dependencies, and it would do-so with default GHC options (optimizations enabled). This dependency would-include wai. So when we run:-- stack build --ghc-options=-O0 warp--We want its behavior to be unaffected by any previous build steps we took.-While this specific corner case does catch people by surprise, the overall goal-of reproducible builds is- in the stack maintainers' views- worth the-confusion.--Final point: if you have GHC options that you'll be regularly passing to your-packages, you can add them to your stack.yaml file (starting with-stack-0.1.4.0). See [the documentation section on-ghc-options](yaml_configuration.md#ghc-options)-for more information.--## path--NOTE: That's it, the heavy content of this guide is done! Everything from here-on out is simple explanations of commands. Congratulations!--Generally, you don't need to worry about where stack stores various files. But-some people like to know this stuff. That's when the `stack path` command is-useful.--```-michael@d30748af6d3d:~/wai$ stack path-global-stack-root: /home/michael/.stack-project-root: /home/michael/wai-config-location: /home/michael/wai/stack.yaml-bin-path: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4/bin:/home/michael/.stack/programs/x86_64-linux/ghc-7.8.4/bin:/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin-ghc-paths: /home/michael/.stack/programs/x86_64-linux-local-bin-path: /home/michael/.local/bin-extra-include-dirs:-extra-library-dirs:-snapshot-pkg-db: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4/pkgdb-local-pkg-db: /home/michael/wai/.stack-work/install/x86_64-linux/lts-2.17/7.8.4/pkgdb-snapshot-install-root: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4-local-install-root: /home/michael/wai/.stack-work/install/x86_64-linux/lts-2.17/7.8.4-snapshot-doc-root: /home/michael/.stack/snapshots/x86_64-linux/lts-2.17/7.8.4/doc-local-doc-root: /home/michael/wai/.stack-work/install/x86_64-linux/lts-2.17/7.8.4/doc-dist-dir: .stack-work/dist/x86_64-linux/Cabal-1.18.1.5-```--In addition, `stack path` accepts command line arguments to state which of-these keys you're interested in, which can be convenient for scripting. As a-simple example, let's find out which versions of GHC are installed locally:--```-michael@d30748af6d3d:~/wai$ ls $(stack path --ghc-paths)/*.installed-/home/michael/.stack/programs/x86_64-linux/ghc-7.10.2.installed-/home/michael/.stack/programs/x86_64-linux/ghc-7.8.4.installed-```--(Yes, that command requires a \*nix shell, and likely won't run on Windows.)--While we're talking about paths, to wipe our stack install completely, here's-what needs to be removed:--1. The stack executable itself-2. The stack root, e.g. `$HOME/.stack` on non-Windows systems.- * See `stack path --global-stack-root`- * On Windows, you will also need to delete `stack path --ghc-paths`-3. Any local `.stack-work` directories inside a project--## exec--We've already used `stack exec` used 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-`GHC_PACKAGE_PATH`, which tells GHC which package databases to use).--If you want to see exactly what the modified environment looks like, try:-- stack exec env--The only issue is how to distinguish flags to be passed to stack versus those-for the underlying program. Thanks to the optparse-applicative library, stack-follows the Unix convention of `--` to separate these, e.g.:--```-michael@d30748af6d3d:~$ stack exec --package stm -- echo I installed the stm package via --package stm-Run from outside a project, using implicit global project config-Using latest snapshot resolver: lts-3.2-Writing global (non-project-specific) config file to: /home/michael/.stack/global/stack.yaml-Note: You can change the snapshot via the resolver field there.-I installed the stm package via --package stm-```--Flags worth mentioning:--* `--package foo` can be used to force a package to be installed before running- the given command.-* `--no-ghc-package-path` can be used to stop the `GHC_PACKAGE_PATH` environment- variable from being set. Some tools — notably cabal-install — do not behave- well with that variable set.--## ghci (the repl)--GHCi is the interactive GHC environment, a.k.a. the REPL. You *could* access it-with:-- stack exec ghci--But that won't load up locally written modules for access. For that, use the-`stack ghci` command. To then load modules from your project, use the `:m`-command (for "module") followed by the module name.--## ghc/runghc--You'll sometimes want to just compile (or run) a single Haskell source file,-instead of creating an entire Cabal package for it. You can use `stack exec-ghc` or `stack exec runghc` for that. As simple helpers, we also provide the-`stack ghc` and `stack runghc` commands, for these common cases.--stack also offers a very useful feature for running files: a script-interpreter. For too long have Haskellers felt shackled to bash or Python-because it's just too hard to create reusable source-only Haskell scripts.-stack attempts to solve that. An example will be easiest to understand:--```-michael@d30748af6d3d:~$ cat turtle.hs-#!/usr/bin/env stack--- stack --resolver lts-3.2 --install-ghc runghc --package turtle-{-# LANGUAGE OverloadedStrings #-}-import Turtle-main = echo "Hello World!"-michael@d30748af6d3d:~$ chmod +x turtle.hs-michael@d30748af6d3d:~$ ./turtle.hs-Run from outside a project, using implicit global project config-Using resolver: lts-3.2 specified on command line-hashable-1.2.3.3: configure-# installs some more dependencies-Completed all 22 actions.-Hello World!-michael@d30748af6d3d:~$ ./turtle.hs-Run from outside a project, using implicit global project config-Using resolver: lts-3.2 specified on command line-Hello World!-```--If you're on Windows: you can run `stack turtle.hs` instead of `./turtle.hs`.--The first line is the usual "shebang" to use stack as a script interpreter. The-second line, which is required, provides additional options to stack (due to-the common limitation of the "shebang" line only being allowed a single-argument). In this case, the options tell stack to use the lts-3.2 resolver,-automatically install GHC if it is not already installed, and ensure the turtle-package is available.--The first run can take a while (as it has to download GHC if necessary and build-dependencies), but subsequent runs are able to reuse everything already built,-and are therefore quite fast.--## Finding project configs, and the implicit global--Whenever you run something with stack, it needs a stack.yaml project file. The-algorithm stack uses to find this is:--1. Check for a `--stack-yaml` option on the command line-2. Check for a `STACK_YAML` environment variable-3. Check the current directory and all ancestor directories for a `stack.yaml`--The first two provide a convenient method for using an alternate configuration.-For example: `stack build --stack-yaml stack-7.8.yaml` can be used by your CI-system to check your code against GHC 7.8. Setting the `STACK_YAML` environment-variable can be convenient if you're going to be running commands like `stack-ghc` in other directories, but you want to use the configuration you defined in-a specific project.--If stack does not find a stack.yaml in any of the three specified locations,-the *implicit global* logic kicks in. You've probably noticed that phrase a few-times in the output from commands above. Implicit global is essentially a hack-to allow stack to be useful in a non-project setting. When no implicit global-config file exists, stack creates one for you with the latest LTS snapshot as-the resolver. This allows you to do things like:--* compile individual files easily with `stack ghc`-* build executables without starting a project, e.g. `stack install pandoc`--Keep in mind that there's nothing magical about this implicit global-configuration. It has no impact on projects at all. Every package you install-with it is put into isolated databases just like everywhere else. The only magic-is that it's the catch-all project whenever you're running stack somewhere else.--## stack.yaml vs .cabal files--Now that we've covered a lot of stack use cases, this quick summary of-stack.yaml vs .cabal files will hopefully make sense and be a good reminder for-future uses of stack:--* A project can have multiple packages.-* Each project has a stack.yaml.-* Each package has a .cabal file.-* The .cabal file specifies which packages are dependencies.-* The stack.yaml file specifies which packages are available to be used.-* .cabal specifies the components, modules, and build flags provided by a package-* stack.yaml can override the flag settings for individual packages-* stack.yaml specifies which packages to include--## Comparison to other tools--stack is not the only tool around for building Haskell code. stack came into-existence due to limitations with some of the existing tools. If you're-unaffected by those limitations and are happily building Haskell code, you may-not need stack. If you're suffering from some of the common problems in other-tools, give stack a try instead.--If you're a new user who has no experience with other tools, we recommend going-with stack. The defaults match modern best practices in Haskell development, and-there are less corner cases you need to be aware of. You *can* develop Haskell-code with other tools, but you probably want to spend your time writing code,-not convincing a tool to do what you want.--Before jumping into the differences, let me clarify an important similarity:--__Same package format.__ stack, cabal-install, and presumably all other tools-share the same underlying Cabal package format, consisting of a .cabal file,-modules, etc. This is a Good Thing: we can share the same set of upstream-libraries, and collaboratively work on the same project with stack,-cabal-install, and NixOS. In that sense, we're sharing the same ecosystem.--Now the differences:--* __Curation vs dependency solving as a default__.- * stack defaults to using curation (Stackage snapshots, LTS Haskell,- Nightly, etc) as a default instead of defaulting to dependency solving, as- cabal-install does. This is just a default: as described above, stack can- use dependency solving if desired, and cabal-install can use curation.- However, most users will stick to the defaults. The stack team firmly- believes that the majority of users want to simply ignore dependency- resolution nightmares and get a valid build plan from day 1, which is why- we've made this selection of default behavior.-* __Reproducible__.- * stack goes to great lengths to ensure that `stack build` today does the- same thing tomorrow. cabal-install does not: build plans can be affected- by the presence of preinstalled packages, and running `cabal update` can- cause a previously successful build to fail. With stack, changing the- build plan is always an explicit decision.-* __Automatically building dependencies__.- * In cabal-install, you need to use `cabal install` to trigger dependency- building. This is somewhat necessary due to the previous point, since- building dependencies can, in some cases, break existing installed- packages. So for example, in stack, `stack test` does the same job as- `cabal install --run-tests`, though the latter *additionally* performs an- installation that you may not want. The closer command equivalent is- `cabal install --enable-tests --only-dependencies && cabal configure- --enable-tests && cabal build && cabal test` (newer versions of- cabal-install may make this command shorter).-* __Isolated by default__.- * This has been a pain point for new stack users. In cabal, the- default behavior is a non-isolated build where working on two projects can- cause the user package database to become corrupted. The cabal solution to- this is sandboxes. stack, however, provides this behavior by default via- its databases. In other words: when you use stack, there's __no need for- sandboxes__, everything is (essentially) sandboxed by default.--__Other tools for comparison (including active and historical)__-* [cabal-dev](https://hackage.haskell.org/package/cabal-dev) (deprecated in favor of cabal-install)-* [cabal-meta](https://hackage.haskell.org/package/cabal-meta) inspired a lot of the multi-package functionality of stack. If you're still using cabal-install, cabal-meta is relevant. For stack work, the feature set is fully subsumed by stack.-* [cabal-src](https://hackage.haskell.org/package/cabal-src) is mostly irrelevant in the presence of both stack and cabal sandboxes, both of which make it easier to add additional package sources easily. The mega-sdist executable that ships with cabal-src is, however, still relevant. Its functionality may some day be folded into stack-* [stackage-cli](https://hackage.haskell.org/package/stackage-cli) was an initial attempt to make cabal-install work more easily with curated snapshots, but due to a slight impedance mismatch between cabal.config constraints and snapshots, it did not work as well as hoped. It is deprecated in favor of stack.--## More resources--There are lots of resources available for learning more about stack:--* `stack --help`-* `stack --version` — identify the version and Git hash of the stack executable-* `--verbose` (or `-v`) — much more info about internal operations (useful for bug reports)-* The [README](https://github.com/commercialhaskell/stack#readme)-* The [stack mailing list](https://groups.google.com/d/forum/haskell-stack)-* The [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)-* [Why is stack not cabal?](https://www.fpcomplete.com/blog/2015/06/why-is-stack-not-cabal)---## Fun features--This is just a quick collection of fun and useful feature stack supports.--### Templates--We started off using the `new` command to create a project. stack provides-multiple templates to start a new project from:--```-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-Downloading template "yesod-simple" to create project "my-yesod-project" in my-yesod-project/ ...-Using the following authorship configuration:-author-email: example@example.com-author-name: Example Author Name-Copy these to /home/michael/.stack/config.yaml and edit to use different values.-Writing default config file to: /home/michael/my-yesod-project/stack.yaml-Basing on cabal files:-- /home/michael/my-yesod-project/my-yesod-project.cabal--Checking against build plan lts-3.2-Selected resolver: lts-3.2-Wrote project config to: /home/michael/my-yesod-project/stack.yaml-```--To add more templates, see [the stack-templates-repository](https://github.com/commercialhaskell/stack-templates#readme).--### IDE--stack has a work-in-progress suite of editor integrations, to do things like-getting type information in Emacs. For more information, see-[stack-ide](https://github.com/commercialhaskell/stack-ide#readme).--### Visualizing dependencies--If you'd like to get some insight into the dependency tree of your packages, you-can use the `stack dot` command and Graphviz. More information is-[available in the Dependency visualization documentation](dependency_visualization.md).--### Travis with caching--Many people use Travis CI to test out a project for every Git push. We have [a-Wiki page devoted to-Travis](https://github.com/commercialhaskell/stack/wiki/Travis). However, for-most people, the following example will be sufficient to get started:--```yaml-# Use new container infrastructure to enable caching-sudo: false--# Choose a lightweight base image; we provide our own build tools.-language: c--# GHC depends on GMP. You can add other dependencies here as well.-addons:- apt:- packages:- - libgmp-dev--# The different configurations we want to test. You could also do things like-# change flags or use --stack-yaml to point to a different file.-env:-- ARGS=""-- ARGS="--resolver lts-2"-- ARGS="--resolver lts-3"-- ARGS="--resolver lts"-- ARGS="--resolver nightly"--before_install:-# Download and unpack the stack executable-- mkdir -p ~/.local/bin-- export PATH=$HOME/.local/bin:$PATH-- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'--# This line does all of the work: installs GHC if necessary, build the library,-# executables, and test suites, and runs the test suites. --no-terminal works-# around some quirks in Travis's terminal implementation.-script: stack $ARGS --no-terminal --install-ghc test --haddock--# Caching so the next build will be fast too.-cache:- directories:- - $HOME/.stack-```--Not only will this build and test your project against multiple GHC versions-and snapshots, but it will cache your snapshot built packages, meaning that-subsequent builds will be much faster.--Once Travis whitelists the stack .deb files, we'll be able to simply include-stack in the `addons` section, and automatically use the newest version of-stack, avoiding that complicated `before_install` section This is being-tracked in the-[apt-source-whitelist](https://github.com/travis-ci/apt-source-whitelist/pull/7)-and-[apt-package-whitelist](https://github.com/travis-ci/apt-package-whitelist/issues/379)-issue trackers.--In case you're wondering: we need `--no-terminal` because stack does some fancy-sticky display on smart terminals to give nicer status and progress messages,-and the terminal detection is broken on Travis.--### Shell autocompletion--Love tab-completion of commands? You're not alone. If you're on bash, just run-the following (or add it to `.bashrc`):-- eval "$(stack --bash-completion-script "$(which stack)")"--For more information and other shells, see [the Shell autocompletion wiki-page](https://github.com/commercialhaskell/stack/wiki/Shell-autocompletion)--### Docker--stack provides two built-in Docker integrations. Firstly, you can 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:--```yaml-image:- # YOU NEED A `container` YAML SECTION FOR `stack image container`- container:- # YOU NEED A BASE IMAGE NAME. STACK LAYERS EXES ON TOP OF- # THE BASE IMAGE. PREPARE YOUR PROJECT IMAGE IN ADVANCE. PUT- # ALL YOUR RUNTIME DEPENDENCIES IN THE IMAGE.- base: "fpco/ubuntu-with-libgmp:14.04"- # YOU CAN OPTIONALY NAME THE IMAGE. STACK WILL USE THE PROJECT- # DIRECTORY NAME IF YOU LEAVE OUT THIS OPTION.- name: "fpco/hello-world"- # OPTIONALLY ADD A HASH OF LOCAL PROJECT DIRECTORIES AND THEIR- # DESTINATIONS INSIDE THE DOCKER IMAGE.- add:- man/: /usr/local/share/man/- # OPTIONALLY SPECIFY A LIST OF EXECUTABLES. STACK WILL CREATE- # A TAGGED IMAGE FOR EACH IN THE LIST. THESE IMAGES WILL HAVE- # THEIR RESPECTIVE "ENTRYPOINT" SET.- entrypoints:- - stack-```--and then run `stack image container` and then `docker images` to list-the images.--## Power user commands--The following commands are a little more powerful, and won't be needed by all-users. Here's a quick rundown:--* `stack update` will download the most recent set of packages from your package- indices (e.g. Hackage). Generally, stack runs this for you automatically- when necessary, but it can be useful to do this manually sometimes (e.g.,- before running `stack solver`, to guarantee you have the most recent- upstream packages available).-* `stack unpack` is a command we've already used quite a bit for examples, but- most users won't use it regularly. It does what you'd expect: downloads a- tarball and unpacks it.-* `stack sdist` generates an uploading tarball containing your package code-* `stack upload` uploads an sdist to Hackage. In the future, it will also- perform automatic GPG signing of your packages for additional security, when- configured.-* `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 list-dependencies` lists all of the packages and versions used for a- project--## Debugging--The following command installs with profiling enabled:--`stack install --enable-executable-profiling --enable-library-profiling---ghc-options="-rtsopts"`--This command will allow you to use various tools to profile the time,-allocation, heap, and more of a program. The `-prof` GHC option is unnecessary-and will result in a warning. Additional compilation options can be added to-`--ghc-options` if needed. To see a general overview of the time and allocation-of a program called `main` compiled with the above command, you can run--`./main +RTS -p`--to generate a `main.prof` file containing the requested profiling information.-For more commands and uses, see [the official GHC chapter on-profiling](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html),-[the Haskell wiki](https://wiki.haskell.org/How_to_profile_a_Haskell_program),-and [the chapter on profiling in Real World-Haskell](http://book.realworldhaskell.org/read/profiling-and-optimization.html).
− doc/MAINTAINER_GUIDE.md
@@ -1,135 +0,0 @@-## Pre-release checks--The following should be tested minimally before a release is considered good-to go:--* Integration tests pass on a representative sample of platforms: `stack test- --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-* stack can build the wai repo-* Running `stack build` a second time on either stack or wai is a no-op-* Build something that depends on `happy` (suggestion: `hlint`), since `happy`- has special logic for moving around the `dist` directory-* Make sure to bump the version number in the .cabal file and the ChangeLog- appropriately (check for any entries that snuck into the previous version's- changes)-* In release candidate, remove the Changelog's "unreleased changes" section-* Review documentation for any changes that need to be made- * Search for old Stack version and replace with new version-* Ensure all `doc/*.md` files are listed in `stack.cabal`'s 'extra-source-files`-* Check that any new Linux distribution versions added to- `etc/scripts/release.hs` and `etc/scripts/vagrant-releases.sh`-* 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](https://github.com/commercialhaskell/stack/blob/master/README.md)--## 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.--* Create a- [new draft Github release](https://github.com/commercialhaskell/stack/releases/new)- with tag `vX.Y.Z` (where X.Y.Z is the stack package's version)--* On each machine you'll be releasing from, set environment variables:- `GITHUB_AUTHORIZATION_TOKEN`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`--* On a machine with Vagrant installed:- * Run `etc/scripts/vagrant-releases.sh`--* On Mac OS X:- * 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`--* Push signed Git tag, matching Github release tag name, e.g.: `git tag -u- 9BEFB442 vX.Y.Z && git push origin vX.Y.Z`--* Reset the `release` branch to the released commit, e.g.: `git merge --ff-only- vX.Y.Z && git push origin release`--* Publish Github release--* Edit- [stack-setup-2.yaml](https://github.com/fpco/stackage-content/blob/master/stack/stack-setup-2.yaml),- and add the new linux64 stack bindist--* Upload package to Hackage: `stack upload . --pvp-bounds=both`--* On a machine with Vagrant installed:- * Run `etc/scripts/vagrant-distros.sh`--* Update in Arch Linux's- [haskell-stack.git](ssh+git://aur@aur.archlinux.org/haskell-stack.git):- `PKGBUILD` and `.SRCINFO`- * Be sure to reset `pkgrel` in both files, and update the SHA1 sum--* Submit a PR for the- [haskell-stack Homebrew formula](https://github.com/Homebrew/homebrew/blob/master/Library/Formula/haskell-stack.rb).- The commit message should just be `haskell-stack <VERSION>`- * Note: for v0.1.8.0, check if `pcre` should still be a dependency- * Also, update the homepage--* Build Windows installers. See https://github.com/borsboom/stack-installer#readme--* [Build new MinGHC distribution](#build_minghc)--* [Upload haddocks to Hackage](#upload_haddocks), if hackage couldn't build on its own--* Announce to haskell-cafe, commercialhaskell, and haskell-stack mailing lists--# Extra steps--## Upload haddocks to Hackage <a name="upload_haddocks"></a>--* Set `STACKVER` environment variable to the Stack version (e.g. `0.1.6.0`)-* Run:--```-STACKDOCDIR=stack-$STACKVER-docs-rm -rf _release/$STACKDOCDIR-mkdir -p _release-cp -r $(stack path --local-doc-root)/stack-$STACKVER _release/$STACKDOCDIR-sed -i '' 's/href="\.\.\/\([^/]*\)\//href="..\/..\/\1\/docs\//g' _release/$STACKDOCDIR/*.html-(cd _release && tar cvz --format=ustar -f $STACKDOCDIR.tar.gz $STACKDOCDIR)-curl -X PUT \- -H 'Content-Type: application/x-tar' \- -H 'Content-Encoding: gzip' \- -u borsboom \- --data-binary "@_release/$STACKDOCDIR.tar.gz" \- "https://hackage.haskell.org/package/stack-$STACKVER/docs"-```--## Update MinGHC <a name="build_minghc"></a>--Full details of prerequisites and steps for building MinGHC are in its-[README](https://github.com/fpco/minghc#building-installers). What follows is an-abbreviated set specifically for including the latest stack version.--* Ensure `makensis.exe` and `signtool.exe` are on your PATH.-* If you edit build-post-install.hs, run `stack exec -- cmd /c build-post-install.bat`-* Set `STACKVER` environment variable to latest Stack verion (e.g. `0.1.6.0`)-* Adjust commands below for new GHC versions-* Run:--```-stack build-stack exec -- minghc-generate 7.10.2 --stack=%STACKVER%-signtool sign /v /n "FP Complete, Corporation" /t "http://timestamp.verisign.com/scripts/timestamp.dll" .build\minghc-7.10.2-i386.exe-stack exec -- minghc-generate 7.10.2 --arch64 --stack=%STACKVER%-signtool sign /v /n "FP Complete, Corporation" /t "http://timestamp.verisign.com/scripts/timestamp.dll" .build\minghc-7.10.2-x86_64.exe-stack exec -- minghc-generate 7.8.4 --stack=%STACKVER%-signtool sign /v /n "FP Complete, Corporation" /t "http://timestamp.verisign.com/scripts/timestamp.dll" .build\minghc-7.8.4-i386.exe-stack exec -- minghc-generate 7.8.4 --arch64 --stack=%STACKVER%-signtool sign /v /n "FP Complete, Corporation" /t "http://timestamp.verisign.com/scripts/timestamp.dll" .build\minghc-7.8.4-x86_64.exe-```--* Upload the built binaries to a new Github release-* Edit [README.md](https://github.com/fpco/minghc/blob/master/README.md#using-the-installer) and update download links
− doc/SIGNING_KEY.md
@@ -1,34 +0,0 @@-Releases are signed with this key:--```------BEGIN PGP PUBLIC KEY BLOCK------Version: GnuPG v1--mQENBFVs+cMBCAC5IsLWTikd1V70Ur1FPJMn14Sc/C2fbXc0zRcPuWX+JaXgrIJQ-74A3UGBpa07wJDZiQLLz4AasDQj++9gXdiM9MlK/xWt8BQpgQqSMgkktFVajSWX2-rSXPjqLtsl5dLsc8ziBkd/AARXoeITmXX+n6oRTy6QfdMv2Tacnq7r9M9J6bAz6/-7UsKkyZVwsbUPea4SuD/s7jkXAuly15APaYDmF5mMlpoRWp442lJFpA0h52mREX1-s5FDbuKRQW7OpZdLcmOgoknJBDSpKHuHEoUhdG7Y3WDUGYFZcTtta1qSVHrm3nYa-7q5yOzPW4/VpftkBs1KzIxx0nQ5INT5W5+oTABEBAAG0H0ZQQ29tcGxldGUgPGRl-dkBmcGNvbXBsZXRlLmNvbT6JATcEEwEKACEFAlVs+cMCGwMFCwkIBwMFFQoJCAsF-FgMCAQACHgECF4AACgkQV1FZaJvvtEIP8gf/S/k4C3lp/BFb0K9DHHSt6EaGQPwy-g+O8d+JvL7ghkvMjlQ+UxDw+LfRKANTpl8a4vHtEQLHEy1tPJfrnMA8DNci8HLVx-rK3lIqMfv5t85VST9rz3X8huSw7qwFyxsmIqFtJC/BBQfsOXC+Q5Z2nbResXHMeA-5ZvDopZnqKPdmMOngabPGZd89hOKn6r8k7+yvZ/mXmrGOB8q5ZGbOXUbCshst7lc-yZWmoK3VJdErQjGHCdF4MC9KFBQsYYUy9b1q0OUv9QLtq/TeKxfpvYk9zMWAoafk-M8QBE/qqOpqkBRoKbQHCDQgx7AXJMKnOA0jPx1At57hWl7PuEH4rK38UtLkBDQRV-bPnDAQgAx1+4ENyaMk8XznQQ4l+nl8qw4UedZhnR5Xxr6z2kcMO/0VdwmIDCpxaM-spurOF+yExfY/Chbex7fThWTwVgfsItUc/QLLv9jkvpveMUDuPyh/4QrAQBYoW09-jMJcOTFQU+f4CtKaN/1PNoTSU2YkVpbhvtV3Jn2LPFjUSPb7z2NZ9NKe10M0/yN+-l0CuPlqu6GZR5L3pA5i8PZ0Nh47j0Ux5KIjrjCGne4p+J8qqeRhUf04yHAYfDLgE-aLAG4v4pYbb1jNPUm1Kbk0lo2c3dxx0IU201uAQ6LNLdF/WW/ZF7w3iHn7kbbzXO-jhbq2rvZEn3K9xDr7homVnnj21/LSQARAQABiQEfBBgBCgAJBQJVbPnDAhsMAAoJ-EFdRWWib77RC3ukH/R9jQ4q6LpXynQPJJ9QKwstglKfoKNpGeAYVTEn0e7NB0HV5-BC+Da5SzBowboxC2YCD1wTAjBjLLQfAYNyR+tHpJBaBmruafj87nBCDhSWwWDXwx-OUDpNOwKUkrwZDRlM7n4byoMRl7Vh/7CXxaTqkyao1c5v3mHh/DremiTvOJ4OXgJ-77NHaPXezHkCFZC8/sX6aY0DJxF+LIE84CoLI1LYBatH+NKxoICKA+yeF3RIVw0/-F3mtEFEtmJ6ljSks5tECxfJFvQlkpILBbGvHfuljKMeaj+iN+bsHmV4em/ELB1ku-N9Obs/bFDBMmQklIdLP7dOunDjY4FwwcFcXdNyg=-=YUsC------END PGP PUBLIC KEY BLOCK------```
− doc/architecture.md
@@ -1,131 +0,0 @@-## Terminology--* Package identifier: a package name and version, e.g. text-1.2.1.0-* GhcPkgId: a package identifier plus the unique hash for the generated binary, e.g. text-1.2.1.0-bb83023b42179dd898ebe815ada112c2-* Package index: a collection of packages available for download. This is a combination of an index containing all of the .cabal files (either a tarball downloaded via HTTP(S) or a Git repository) and some way to download package tarballs.- * By default, stack uses a single package index (the Github/S3 mirrors of Hackage), but supports customization and adding more than one index-* Package database: a collection of metadata about built libraries-* Install root: a destination for installing packages into. Contains a bin path (for generated executables), lib (for the compiled libraries), pkgdb (for the package database), and a few other things-* Snapshot: an LTS Haskell or Stackage Nightly, which gives information on a complete set of packages. This contains a lot of metadata, but importantly it can be converted into a mini build plan...-* Mini build plan: a collection of package identifiers and their build flags that are known to build together-* Resolver: the means by which stack resolves dependencies for your packages. The two currently supported options are snapshot (using LTS or Nightly), and GHC (which installs no extra dependencies). Others may be added in the future (such as a SAT-based dependency solver). These packages are always taken from a package index-* extra-deps: additional packages to be taken from the package index for dependencies. This list will *shadow* packages provided by the resolver-* Local packages: source code actually present on your file system, and referred to by the `packages` field in your stack.yaml file. Each local package has exactly one .cabal file-* Project: a stack.yaml config file and all of the local packages it refers to. --## Databases--Every build uses three distinct install roots, which means three separate package databases and bin paths. These are:--* Global: the packages that ship with GHC. We never install anything into this database-* Snapshot: a database shared by all projects using the same snapshot. Packages installed in this database must use the exact same dependencies and build flags as specified in the snapshot, and cannot be affected by user flags, ensuring that one project cannot corrupt another. There are two caveats to this:- * If different projects use different package indices, then their definitions of what package foo-1.2.3 are may be different, in which case they *can* corrupt each other's shared databases. This is warned about in the FAQ- * Turning on profiling may cause a package to be recompiled, which will result in a different GhcPkgId-* Local: extra-deps, local packages, and snapshot packages which depend on them (more on that in shadowing)--## Building--### Shadowing--Every project must have precisely one version of a package. If one of your-local packages or extra dependencies conflicts with a package in the snapshot,-the local/extradep *shadows* the snapshot version. The way this works is:--* The package is removed from the list of packages in the snapshot-* Any package that depends on that package (directly or indirectly) is moved from the snapshot to extra-deps, so that it is available to your packages as dependencies.- * Note that there is no longer any guarantee that this package will build, since you're using an untested dependency--After shadowing, you end up with what is called internally a `SourceMap`, which-is `Map PackageName PackageSource`, where a `PackageSource` can be either a-local package, or a package taken from a package index (specified as a version-number and the build flags).--### Installed packages--Once you have a `SourceMap`, you can inspect your three available databases and-decide which of the installed packages you wish to use from them. We move from-the global, to snapshot, and finally local, with the following rules:--* If we require profiling, and the library does not provide profiling, do not use it-* If the package is in the `SourceMap`, but belongs to a difference database, or has a different version, do not use it-* If after the above two steps, any of the dependencies are unavailable, do not use it-* Otherwise: include the package in the list of installed packages--We do something similar for executables, but maintain our own database of-installed executables, since GHC does not track them for us.--### Plan construction--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-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:--* If any of the dependencies have changed, reconfigure and rebuild-* If a local package has any files changed, rebuild (but don't bother reconfiguring)-* If a local package is wanted and we're running tests or benchmarks, run the test or benchmark even if the code and dependencies haven't changed--### Plan execution--Once we have the plan, execution is a relatively simple process of calling-`runghc Setup.hs` in the correct order with the correct parameters. See-Stack.Build.Execute for more information.--## Configuration--stack has two layers of configuration: project and non-project. All of these-are stored in stack.yaml files, but the former has extra fields (resolver,-packages, extra-deps, and flags). The latter can be monoidally combined so that-a system config file provides defaults, which a user can override with-`~/.stack/config.yaml`, and a project can further customize. In addition,-environment variables STACK\_ROOT and STACK\_YAML can be used to tweak where-stack gets its configuration from.--stack follows a simple algorithm for finding your project configuration file:-start in the current directory, and keep going to the parent until it finds a-`stack.yaml`. When using `stack ghc` or `stack exec` as mentioned above, you'll-sometimes want to override that behavior and point to a specific project in-order to use its databases and bin directories. To do so, simply set the-`STACK_YAML` environment variable to point to the relevant `stack.yaml` file.--## Snapshot auto-detection--When you run `stack build` with no stack.yaml, it will create a basic-configuration with a single package (the current directory) and an-auto-detected snapshot. The algorithm it uses for selecting this snapshot is:--* Try the latest two LTS major versions at their most recent minor version release, and the most recent Stackage Nightly. For example, at the time of writing, this would be lts-2.10, lts-1.15, and nightly-2015-05-26-* For each of these, test the version bounds in the package's .cabal file to see if they are compatible with the snapshot, choosing the first one that matches-* If no snapshot matches, uses the most recent LTS snapshot, even though it will not compile--If you end up in the no compatible snapshot case, you typically have three options to fix things:--* Manually specify a different snapshot that you know to be compatible. If you can do that, great, but typically if the auto-detection fails, it means that there's no compatible snapshot-* Modify version bounds in your .cabal file to be compatible with the selected snapshot-* Add `extra-deps` to your stack.yaml file to fix compatibility problems--Remember that running `stack build` will give you information on why your build-cannot occur, which should help guide you through the steps necessary for the-second and third option above. Also, note that those options can be-mixed-and-matched, e.g. you may decide to relax some version bounds in your-.cabal file, while also adding some extra-deps.--## Explicit breakage--As mentioned above, updating your package indices will not cause stack to-invalidate any existing package databases. That's because stack is always-explicit about build plans, via:--1. the selected snapshot-2. the extra-deps-3. local packages--The only way to change a plan for packages to be installed is by modifying one-of the above. This means that breakage of a set of installed packages is an-*explicit* and *contained* activity. Specifically, you get the following-guarantees:--* Since snapshots are immutable, the snapshot package database will not be invalidated by any action. If you change the snapshot you're using, however, you may need to build those packages from scratch.-* If you modify your extra-deps, stack may need to unregister and reinstall them.-* Any changes to your local packages trigger a rebuild of that package and its dependencies.
− doc/build_command.md
@@ -1,114 +0,0 @@-## Overview--The primary command you use in stack is build. This page describes the details-of build's command line interface. The goal of the interface is to do the right-thing for simple input, and allow a lot of flexibility for more complicated-goals.--## Synonyms--One potential point of confusion is the synonym commands for `build`. These are-provided to match commonly expected command line interfaces, and to make common-workflows shorter. The important thing to note is that all of these are just-the `build` command in disguise. Each of these commands are called out as-synonyms in the `--help` output. These commands are:--* `stack test` is the same as `stack build --test`-* `stack bench` is the same as `stack build --bench`-* `stack haddock` is the same as `stack build --haddock`-* `stack install` is the same as `stack build --copy-bins`--The advantage of the synonym commands is that they're convenient and short. The-advantage of the options is that they compose. For example, `stack build --test---copy-bins` will build libraries, executables, and test suites, run the test-suites, and then copy the executables to your local bin path (more on this-below).--## Components--Components are a subtle yet important point to how build operates under the-surface. Every cabal package is made up of one or more components. It can have-0 or 1 libraries, and then 0 or more of executable, test, and benchmark-components. stack allows you to call out a specific component to be built, e.g.-`stack build mypackage:test:mytests` will build the `mytests` component of the-`mypackage` package. `mytests` must be a test suite component.--We'll get into the details of the target syntax for how to select components in-the next section. In this section, the important point is: whenever you target-a test suite or a benchmark, it's built __and also run__, unless you explicitly-disable running via `--no-run-tests` or `--no-run-benchmarks`. Case in point:-the previous command will in fact build the `mytests` test suite *and* run it,-even though you haven't used the `stack test` command or the `--test` option.-(We'll get to what exactly `--test` does below.)--This gives you a lot of flexibility in choosing what you want stack to do. You-can run a single test component from a package, run a test component from one-package and a benchmark from another package, etc.--One final note on components: you can only control components for local-packages, not dependencies. With dependencies, stack will *always* build the-library (if present) and all executables, and ignore test suites and-benchmarks. If you want more control over a package, you must add it to your-`packages` setting in your stack.yaml file.--## Target syntax--In addition to a number of options (like the aforementioned `--test`), `stack-build` takes a list of zero or more *targets* to be built. There are a number-of different syntaxes supported for this list:--* *package*, e.g. `stack build foobar`, is the most commonly used target. It will try to find the package in the following locations: local packages, extra dependencies, snapshots, and package index (e.g. Hackage). If it's found in the package index, then the latest version of that package from the index is implicitly added to your extra dependencies.-- This is where the `--test` and `--bench` flags come into play. If the package is a local package, then all of the test suite and benchmark components are selected to be built, respectively. In any event, the library and executable components are also selected to be built.--* *package identifier*, e.g. `stack build foobar-1.2.3`, is usually used to include specific package versions from the index. If the version selected conflicts with an existing local package or extra dep, then stack fails with an error. Otherwise, this is the same as calling `stack build foobar`, except instead of using the latest version from the index, the version specified is used.--* *component*. Instead of referring to an entire package and letting stack decide which components to build, you select individual components from inside a package. This can be done for more fine-grained control over which test suites to run, or to have a faster compilation cycle. There are multiple ways to refer to a specific component (provided for convenience):-- * `packagename:comptype:compname` is the most explicit. The available comptypes are `exe`, `test`, and `bench`.- * `packagename:compname` allows you to leave off the component type, as that will (almost?) always be redundant with the component name. For example, `stack build mypackage:mytestsuite`.- * `:compname` is a useful shortcut, saying "find the component in all of the local packages." This will result in an error if multiple packages have a component with the same name. To continue the above example, `stack build :mytestsuite`.- * Side note: the commonly requested `run` command is not available because it's a simple combination of `stack build :exename && stack exec exename`--* *directory*, e.g. `stack build foo/bar`, will find all local packages that exist in the given directory hierarchy and then follow the same procedure as passing in package names as mentioned above. There's an important caveat here: if your directory name is parsed as one of the above target types, it will be treated as that. Explicitly starting your target with `./` can be a good way to avoid that, e.g. `stack build ./foo`--Finally: if you provide no targets (e.g., running `stack build`), stack will-implicitly pass in all of your local packages. If you only want to target-packages in the current directory or deeper, you can pass in `.`, e.g. `stack-build .`.--### Examples--FIXME: what examples would be helpful? Need feedback on what's confusing above--## Dependencies--stack will always automatically build all dependencies necessary for its targets.--## Other flags--There are a number of other flags accepted by `stack build`. Instead of listing-all of them, please use `stack build --help`. Some particularly convenient ones-worth mentioning here since they compose well with the rest of the build system-as described:--* `--file-watch` will rebuild your project every time a file changes-* `--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/):--```-stack build --file-watch --test --copy-bins --haddock wai-extra :warp warp:doctest --exec 'echo Yay, it worked!'-```--This command will:--* Start stack up in file watch mode, waiting for files in your project to change. When first starting, and each time a file changes, it will do all of the following.-* Build the wai-extra package and its test suites-* Build the `warp` executable-* Build the warp package's doctest component (which, as you may guess, is a test site)-* Run all of the wai-extra package's test suite components and the doctest test suite component-* If all of that succeeds:- * Copy generated executables to the local bin path- * Run the command `echo Yay, it worked!`
− doc/dependency_visualization.md
@@ -1,41 +0,0 @@-You can use stack to visualize the dependencies between your packages and optionally also external dependencies.--As an example, let's look at `wreq`:--```-$ stack dot | dot -Tpng -o wreq.png-```-[](https://cloud.githubusercontent.com/assets/591567/8478591/ae10a418-20d2-11e5-8945-55246dcfac62.png)--Okay that is a little boring, let's also look at external dependencies:-```-$ stack dot --external | dot -Tpng -o wreq.png-```-[](https://cloud.githubusercontent.com/assets/591567/8478621/d247247e-20d2-11e5-993d-79096e382abd.png)--Well that is certainly a lot. As a start we can exclude `base` and then depending on our needs we can either limit the depth:--```-$ stack dot --no-include-base --external --depth 1 | dot -Tpng -o wreq.png-```-[](https://cloud.githubusercontent.com/assets/591567/8484310/45b399a0-20f7-11e5-8068-031c2b352961.png)--or prune packages explicitly:--```-$ stack dot --external --prune base,lens,wreq-examples,http-client,aeson,tls,http-client-tls,exceptions | dot -Tpng -o wreq_pruned.png-```-[](https://cloud.githubusercontent.com/assets/591567/8478768/adbad280-20d3-11e5-9992-914dc24fe569.png)--Keep in mind that you can also save the dot file:-```-$ stack dot --external --depth 1 > wreq.dot-$ dot -Tpng -o wreq.png wreq.dot-```--and pass in options to `dot` or use another graph layout engine like `twopi`:--```-$ stack dot --external --prune base,lens,wreq-examples,http-client,aeson,tls,http-client-tls,exceptions | twopi -Groot=wreq -Goverlap=false -Tpng -o wreq_pruned.png-```-[](https://cloud.githubusercontent.com/assets/591567/8495538/9fae1184-216e-11e5-9931-99e6147f8aed.png)
− doc/docker_integration.md
@@ -1,477 +0,0 @@-Using Docker with Stack-===============================================================================--`stack` has support for automatically performing builds inside a Docker-container, using volume mounts and user ID switching to make it mostly seamless.-FP Complete provides images for use with stack that include GHC, tools, and-optionally have all of the Stackage LTS packages pre-installed in in the global-package database.--The primary purpose for using stack/docker this way is for teams to ensure all-developers are building in an exactly consistent environment without team-members needing to deal with Docker themselves.--See the-[how stack can use Docker under the hood](https://www.fpcomplete.com/blog/2015/08/stack-docker)-blog post for more information about the motivation and implementation of stack's-Docker support.--Usage----------------------------------------------------------------------------------This section assumes that you already have Docker installed and working. If-not, see the [prerequisites](#prerequisites) section. If you run into any-trouble, see the [troubleshooting](#troubleshooting) section.--### Enable in stack.yaml--The most basic configuration is to add this to your project's `stack.yaml`:-- docker:- enable: true--See [configuration](#configuration) for additional options.--### Use stack as normal--With Docker enabled, most stack sub-commands will automatically launch-themselves in an ephemeral Docker container (the container is deleted as soon as-the command completes). The project directory and `~/.stack` are volume-mounted-into the container, so any build artifacts are "permanent" (not deleted with the-container).--The first time you run a command with a new image, you will be prompted to run-`stack docker pull` to pull the image first. This will pull a Docker-image with a tag that matches your resolver. Only LTS resolvers are supported-(we do not generate images for nightly snapshots). Not every LTS version is-guaranteed to have an image existing, and new LTS images tend to lag behind-the LTS snapshot being published on stackage.org. Be warned: these images are-rather large!--Docker sub-commands----------------------------------------------------------------------------------These `stack docker` sub-commands have Docker-specific functionality. Most other-`stack` commands will also use a Docker container under the surface if Docker is-enabled.--### pull - Pull latest version of image--`stack docker pull` pulls an image from the Docker registry for the first time,-or updates the image by pulling the latest version.--### cleanup - Clean up old images and containers--Docker images can take up quite a lot of disk space, and it's easy for them to-build up if you switch between projects or your projects update their images.-This sub-command will help to remove old images and containers.--By default, `stack docker cleanup` will bring up an editor showing the images-and containers on your system, with any stack images that haven't been used-in the last seven days marked for removal. You can add or remove the `R` in-the left-most column to flag or unflag an image/container for removal. When-you save the file and quit the text editor, those images marked for removal-will be deleted from your system. If you wish to abort the cleanup, delete-all all the lines from your editor.--If you use Docker for purposes other than stack, you may have other images on-your system as well. These will also appear in in a separate section, but they-will not be marked for removal by default.--Run `stack docker cleanup --help` to see additional options to customize its-behaviour.--### reset - Reset the Docker "sandbox"--In order to preserve the contents of the in-container home directory between-runs, a special "sandbox" directory is volume-mounted into the container. `stack-docker reset` will reset that sandbox to its defaults.--Note: this leaves of `~/.stack` (which is separately volume-mounted) alone.--Command-line options----------------------------------------------------------------------------------The default Docker configuration can be overridden on the command-line. See-`stack --docker-help` for a list of all Docker options, and consult-[configuration](#configuration) section below for more information about-their meanings. These are global options, and apply to all commands (not just-`stack docker` sub-commands).--Configuration----------------------------------------------------------------------------------`stack.yaml` contains a `docker:` section with Docker settings. If this-section is omitted, Docker containers will not be used. These settings can-be included in project, user, or global configuration.--Here is an annotated configuration file. The default values are shown unless-otherwise noted.-- docker:-- # Set to false to disable using Docker. In the project configuration,- # the presence of a `docker:` section implies docker is enabled unless- # `enable: false` is set. In user and global configuration, this is not- # the case.- enable: true-- # The name of the repository to pull the image from. See the "reposities"- # section of this document for more information about available repositories.- # If this includes a tag (e.g. "my/image:tag"), that tagged image will be- # used. Without a tag specified, the LTS version slug is added automatically.- # Either `repo` or `image` may be specified, but not both.- repo: "fpco/stack-build"-- # Exact Docker image name or ID. Overrides `repo`. Either `repo` or `image`- # may be specified, but not both. (default none)- image: "5c624ec1d63f"-- # Registry requires login. A login will be requested before attempting to- # pull.- registry-login: false-- # Username to log into the registry. (default none)- registry-username: "myuser"-- # Password to log into the registry. (default none)- registry-password: "SETME"-- # If true, the image will be pulled from the registry automatically, without- # needing to run `stack docker pull`. See the "security" section of this- # document for implications of enabling this.- auto-pull: false-- # If true, the container will be run "detached" (in the background). Refer- # to the Docker users guide for information about how to manage containers.- # This option would rarely make sense in the configuration file, but can be- # useful on the command-line. When true, implies `persistent`.`- detach: false-- # If true, the container will not be deleted after it terminates. Refer to- # the Docker users guide for information about how to manage containers. This- # option would rarely make sense in the configuration file, but can be- # useful on the command-line. `detach` implies `persistent`.- persistent: false-- # What to name the Docker container. Only useful with `detach` or- # `persistent` true. (default none)- container-name: "example-name"-- # Additional arguments to pass to `docker run`. (default none)- run-args: ["--net=bridge"]-- # Directories from the host to volume-mount into the container. If it- # contains a `:`, the part before the `:` is the directory on the host and- # the part after the `:` is where it should be mounted in the container.- # (default none, aside from the project and stack root directories which are- # always mounted)- mount:- - "/foo/bar"- - "/baz:/tmp/quux"-- # Environment variables to set in the container. Environment variables- # are not automatically inherited from the host, so if you need any specific- # variables, use the '--docker-env` command-line argument version of this to- # pass them in. (default none)- env:- - "FOO=BAR"- - "BAR=BAZ QUUX"-- # Location of database used to track image usage, which `stack docker cleanup`- # uses to determine which images should be kept. On shared systems, it may- # be useful to override this in the global configuration file so that- # all users share a single database.- database-path: "~/.stack/docker.db"-- # Location of a Docker container-compatible 'stack' executable with the- # matching version. This executable must be built on linux-x86_64 and- # statically linked.- # Valid values are:- # host: use the host's executable. This is the default when the host's- # executable is known to work (e.g., from official linux-x86_64 bindist)- # download: download a compatible executable matching the host's version.- # This is the default when the host's executable is not known to work- # image: use the 'stack' executable baked into the image. The version- # must match the host's version- # /path/to/stack: path on the host's local filesystem- stack-exe: host-- # If true (the default when using the local Docker Engine), run processes- # in the Docker container as the same UID/GID as the host. The ensures- # that files written by the container are owned by you on the host.- # When the Docker Engine is remote (accessed by tcp), defaults to false.- set-user: true-- # Require the version of the Docker client to be within the specified- # Cabal-style version range (e.g., ">= 1.6.0 && < 1.9.0")- require-docker-version: "any"--Image Repositories----------------------------------------------------------------------------------FP Complete provides the following public image repositories on Docker Hub:--- [fpco/stack-build](https://registry.hub.docker.com/u/fpco/stack-build/) (the- default) - GHC (patched), tools (stack, cabal-install, happy, alex, etc.), and- system developer libraries required to build all Stackage packages.-- [fpco/stack-ghcjs-build](https://registry.hub.docker.com/u/fpco/stack-ghcjs-build/) -- Like `stack-build`, but adds GHCJS.-- [fpco/stack-full](https://registry.hub.docker.com/u/fpco/stack-full/) -- Includes all Stackage packages pre-installed in GHC's global package database.- These images are over 10 GB!-- [fpco/stack-ghcjs-full](https://registry.hub.docker.com/u/fpco/stack-ghcjs-full/) -- Like `stack-full`, but adds GHCJS.-- [fpco/stack-run](https://registry.hub.docker.com/u/fpco/stack-run/) -- Runtime environment for binaries built with Stackage. Includes system shared- libraries required by all Stackage packages. Does not necessarily include all- data required for every use (e.g. has texlive-binaries for HaTeX, but does not- include LaTeX fonts), as that would be prohibitively large. Based on- [phusion/baseimage](https://registry.hub.docker.com/u/phusion/baseimage/).--FP Complete also builds custom variants of these images for their clients.--These images can also be used directory with `docker run` and provide a complete-Haskell build environment.--In addition, most Docker images that contain the basics for running GHC can be-used with Stack's Docker integration. For example, the-[official Haskell image repository](https://hub.docker.com/_/haskell/) works.-See [Custom images](#custom-images) for more details.--Prerequisites----------------------------------------------------------------------------------### Linux 64-bit--Docker use requires machine (virtual or metal) running a Linux distribution-[that Docker supports](https://docs.docker.com/installation/#installation), with-a 64-bit kernel. If you do not already have one, we suggest Ubuntu 14.04-("trusty") since this is what we test with.--While Docker does support non-Linux operating systems through the `boot2docker`-VM, there are issues with host volume mounting that prevent stack from being-usable in this configuration. See-[#194](https://github.com/commercialhaskell/stack/issues/194) for details and-workarounds.--### Docker--Install the latest version of Docker by following the-[instructions for your operating system](http://docs.docker.com/installation/).--The Docker client should be able to connect to the Docker daemon as a non-root-user. For example (from-[here](http://docs.docker.com/installation/ubuntulinux/#ubuntu-raring-1304-and-saucy-1310-64-bit)):-- # Add the connected user "${USER}" to the docker group.- # Change the user name to match your preferred user.- sudo gpasswd -a ${USER} docker-- # Restart the Docker daemon.- sudo service docker restart--You will now need to log out and log in again for the the group addition-to take effect.--Note the above has security implications. See [security](#security) for more.--Security----------------------------------------------------------------------------------Having `docker` usable as a non-root user is always a security risk, and will-allow root access to your system. It is also possible to craft a `stack.yaml`-that will run arbitrary commands in an arbirary docker container through that-vector, thus a `stack.yaml` could cause stack to run arbitrary commands as root.-While this is a risk, it is not really a greater risk than is posed by the-docker permissions in the first place (for example, if you ever run an unknown-shell script or executable, or ever compile an unknown Haskell package that uses-Template Haskell, you are at equal risk). Nevertheless, there are-[plans to close the stack.yaml loophole](https://github.com/commercialhaskell/stack/issues/260).--One way to mitigate this risk is, instead of allowing `docker` to run as-non-root, replace `docker` with a wrapper script that uses `sudo` to run the-real Docker client as root. This way you will at least be prompted for your root-password. As [@gregwebs](https://github.com/gregwebs) pointed out, put this-script named `docker` in your PATH (and make sure you remove your user from the-`docker` group as well, if you added it earlier):-- #!/bin/bash -e- # The goal of this script is to maintain the security privileges of sudo- # Without having to constantly type "sudo"- exec sudo /usr/bin/docker "$@"--Additional notes----------------------------------------------------------------------------------### Volume-mounts and ephemeral containers--Since filesystem changes outside of the volume-mounted project directory are not-persisted across runs, this means that if you `stack exec sudo apt-get install-some-ubuntu-package`, that package will be installed but then the container it's-installed in will disappear, thus causing it to have no effect. If you wish to-make this kind of change permanent, see later instructions for how to create a-[derivative Docker image](#derivativeimage).--Inside the container, your home directory is a special location that volume--mounted from within your project directory's `.stack-work` in such a-way as that installed GHC/cabal packages are not shared between different-Stackage snapshots. In addition, `~/.stack` is volume-mounted from the host.--### Network--stack containers use use the host's network stack within the container-by default, meaning a process running in the container can connect to-services running on the host, and a server process run within the container-can be accessed from the host without needing to explicitly publish its port.-To run the container with an isolated network, use `--docker-run-args` to pass-a the `--net` argument to `docker-run`. For example:-- stack --docker-run-args='--net=bridge --publish=3000:3000' \- exec some-server--will run the container's network in "bridge" mode (which is Docker's default)-and publish port 3000.--### Persistent container--If you do want to do all your work, including editing, in the container, it-might be better to use a persistent container in which you can install Ubuntu-packages. You could get that by running something like `stack---docker-container-name=NAME --docker-persist docker exec bash`. This-means when the container exits, it won't be deleted. You can then restart it-using `docker start -a -i NAME`. It's also possible to detach from a container-while it continues running in the background using by pressing Ctrl-P Ctrl-Q,-and then reattach to it using `docker attach NAME`.--Note that each time you run `stack --docker-persist`, a _new_ persistent-container is created (it will not automatically reuse the previous one).-See the [Docker user guide](https://docs.docker.com/userguide/) for more-information about managing Docker containers.--### Derivative image--Creating your own custom derivative image can be useful if you need to install-additional Ubuntu packages or make other changes to the operating system. Here-is an example (replace `custom` if you prefer a different name for your derived-container):-- # On host- $ stack --docker-persist --docker-container-name=temp docker exec bash-- # In container, make changes to OS- $ sudo apt-get install r-cran-numderiv- [...]- $ exit-- # On host again- $ docker commit temp custom- $ docker rm temp--Now you have a new Docker image named `custom`. To use the new image, run-a command such as the following or update the corresponding values in your-`stack.yaml`:-- stack --docker-image=custom <COMMAND>--Note, however, that any time a new image is used, you will have to re-do this-process. You could also use a Dockerfile to make this reusable. Consult the-[Docker user guide](https://docs.docker.com/userguide/) for more-on creating Docker images.--### <a name="custom-images"></a>Custom images--The easiest way to create your own custom image us by extending FP Complete's-images, but if you prefer to start from scratch, most images that include the-basics for building code with GHC will work. The image doesn't even, strictly-speaking, need to include GHC, but it does need to have libraries and tools that-GHC requires (e.g., libgmp, gcc, etc.).--There are also a few ways to set up images that tightens the integration:--* Create a user and group named `stack`, and create a `~/.stack` directory for- it. Any build plans and caches from it will be copied from the image by Stack,- meaning they don't need to be downloaded separately.-* Any packages in GHC's global package database will be available. This can be- used to add private libraries to the image, or the make available a set of- packages from an LTS release.-* The `DOCKER_SANDBOX_ID` environment variable (set via `ENV` in the Dockerfile)- introduces extra isolation between images, to ensure that parts of the home- directory and stack root are kept separate.--Troubleshooting----------------------------------------------------------------------------------### "No Space Left on Device", but 'df' shows plenty of disk space--This is likely due to the storage driver Docker is using, in combination with-the large size and number of files in these images. Use `docker info|grep-'Storage Driver'` to determine the current storage driver.--We recommend using either the `overlay` or `aufs` storage driver for stack, as-they are least likely to give you trouble. On Ubuntu, `aufs` is the default for-new installations, but older installations sometimes used `devicemapper`.--The `devicemapper` storage driver's default configuration limits it to a 10 GB-file system, which the "full" images exceed. We have experienced other-instabilities with it as well on Ubuntu, and recommend against its use for this-purpose.--The `btrfs` storage driver has problems running out of metadata space long-before running out of actual disk space, which requires rebalancing or adding-more metadata space. See-[CoreOS's btrfs troubleshooting page](https://coreos.com/docs/cluster-management/debugging/btrfs-troubleshooting/)-for details about how to do this.--Pass the `-s <driver>` argument to the Docker daemon to set the storage driver-(in `/etc/default/docker` on Ubuntu). See-[Docker daemon storage-driver option](https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option)-for more details.--You may also be running out of inodes on your filesystem. Use `df -i` to check-for this condition. Unfortunately, the number of inodes is set when creating-the filesystem, so fixing this requires reformatting and passing the `-N`-argument to mkfs.ext4.--### Name resolution doesn't work from within container--On Ubuntu 12.04, by default `NetworkManager` runs `dnsmasq` service, which sets-`127.0.0.1` as your DNS server. Since Docker containers cannot access this-dnsmasq, Docker falls back to using Google DNS (8.8.8.8/8.8.4.4). This causes-problems if you are forced to use internal DNS server. This can be fixed by-executing:-- sudo sed 's@dns=dnsmasq@#dns=dnsmasq@' -i \- /etc/NetworkManager/NetworkManager.conf && \- sudo service network-manager restart--If you have already installed Docker, you must restart the daemon for this-change to take effect:-- sudo service docker restart--<small>-The above commands turn off `dnsmasq` usage in NetworkManager-configuration and restart network manager. They can be reversed by executing-`sudo sed 's@#dns=dnsmasq@dns=dnsmasq@' -i-/etc/NetworkManager/NetworkManager.conf && sudo service network-manager-restart`. These instructions are adapted from-[the Shipyard Project's QuickStart guide](https://github.com/shipyard/shipyard/wiki/QuickStart#127011-dns-server-problem-on-ubuntu).-</small>--### Cannot pull images from behind firewall that blocks TLS/SSL--If you are behind a firewall that blocks TLS/SSL and pulling images from a-private Docker registry, you must edit the system configuration so that the-`--insecure-registry <registry-hostname>` option is passed to the Docker daemon.-For example, on Ubuntu:-- echo 'DOCKER_OPTS="--insecure-registry registry.example.com"' \- |sudo tee -a /etc/default/docker- sudo service docker restart--This does require the private registry to be available over plaintext HTTP.--See-[Docker daemon insecure registries documentation](https://docs.docker.com/reference/commandline/cli/#insecure-registries)-for details.
− doc/faq.md
@@ -1,281 +0,0 @@-So that this doesn't become repetitive: for the reasons behind the answers-below, see the [Architecture](architecture.md) page. The goal of the answers here is to be as-helpful and concise as possible.--#### Where is stack installed and will it interfere with `ghc` (etc) I already have installed?--Stack itself is installed in normal system locations based on the mechanism you used (see the [Install and upgrade](install_and_upgrade.md) page). Stack installs the Stackage libraries in `~/.stack` and any project libraries or extra dependencies in a `.stack-work` directory within each project's directory. None of this should affect any existing Haskell tools at all.--#### What is the relationship between stack and cabal?--* Cabal-the-library is used by stack to build your Haskell code.-* cabal-install (the executable) is used by stack for its dependency solver functionality.-* A .cabal file is provided for each package, and defines all package-level metadata just like it does in the cabal-install world: modules, executables, test suites, etc. No change at all on this front.-* A stack.yaml file references 1 or more packages, and provides information on where dependencies come from.-* `stack build` currently initializes a stack.yaml from the existing .cabal file. Project initialization is something that is still being discussed and there may be more options here for new projects in the future (see issue [253](https://github.com/commercialhaskell/stack/issues/253))--#### I need to use a different version of a package than what is provided by the LTS Haskell snapshot I'm using, what should I do?--You can make tweaks to a snapshot by modifying the `extra-deps` configuration value in your `stack.yaml` file, e.g.:--```yaml-resolver: lts-2.9-packages:-- '.'-extra-deps:-- text-1.2.1.1-```--#### I need to use a package (or version of a package) that is not available on hackage, what should I do?--Add it to the `packages` list in your project's `stack.yaml`, specifying the package's source code location relative to the directory where your `stack.yaml` file lives, e.g.--```yaml-resolver: lts-2.10-packages:-- '.'-- third-party/proprietary-dep-- github-version-of/conduit-- patched/diagrams-extra-deps: []-```--The above example specifies that the `proprietary-dep` package is found in the project's `third-party` folder, that the `conduit` package is found in the project's `github-version-of` folder, and that the `diagrams` package is found in the project's `patched` folder. This autodetects changes and reinstalls the package.--#### What is the meaning of the arguments given to stack build, test, etc?--Those are the targets of the build, and can have one of three formats:--* A package name (e.g., `my-package`) will mean that the `my-package` package must be built-* A package identifier (e.g., `my-package-1.2.3`), which includes a specific version. This is useful for passing to `stack install` for getting a specific version from upstream-* A directory (e.g., `./my-package`) for including a local directory's package, including any packages in subdirectories--#### I need to modify an upstream package, how should I do it?--Typically, you will want to get the source for the package and then add it to-your `packages` list in stack.yaml. (See the previous question.)-`stack unpack` is one approach for getting the source.-Another would be to add the upstream package as a submodule to your-project.--#### Am I required to use a Stackage snapshot to use stack?--No, not at all. If you prefer dependency solving to curation, you can continue with that workflow. Instead of describing the details of how that works here, it's probably easiest to just say: run `stack init --solver` and look at the generated stack.yaml.--#### How do I use this with sandboxes?--Explicit sandboxing on the part of the user is not required by stack. All-builds are automatically isolated into separate package databases without any-user interaction. This ensures that you won't accidentally corrupt your-installed packages with actions taken in other projects.--#### Can I run `cabal` commands inside `stack exec`?--With a recent enough version of cabal-install (>= 1.22), you can. For older versions, due to [haskell/cabal#1800](https://github.com/haskell/cabal/issues/1800), this does not work. Note that even with recent versions, for some commands you may need this extra level of indirection:-```-$ stack exec -- cabal exec -- cabal <command>-```--However, virtually all `cabal` commands have an equivalent in stack, so this should not be necessary. In particular, `cabal` users may be accustomed to the `cabal run` command. In stack:-```-$ stack build && stack exec <program-name>-````-Or, if you want to install the binaries in a shared location:-```-$ stack install-$ <program-name>-```-assuming your `$PATH` has been set appropriately.--#### Using custom preprocessors--If you have a custom preprocessor, for example, Ruby, you may have a-file like:--***B.erb***--``` haskell-module B where--<% (1..5).each do |i| %>-test<%= i %> :: Int-test<%= i %> = <%= i %>-<% end %>-```--To ensure that Stack picks up changes to this file for rebuilds, add-the following line to your .cabal file:-- extra-source-files: B.erb--#### I already have GHC installed, can I still use stack?--Yes. stack will default to using whatever GHC is on your `PATH`. If that GHC is a-compatible version with the snapshot you're using, it will simply use it.-Otherwise, it will prompt you to run `stack setup`. Note that `stack setup` installs GHC into `~/.stack/programs/$platform/ghc-$version/` and not a global location.--Note that GHC installation doesn't work for all OSes, so in some cases the-first option will need to install GHC yourself.--#### How does stack determine what GHC to use?--It uses the first GHC that it finds on the `PATH`. If that GHC does not comply with the various requirements (version, architecture) that your project needs, it will prompt you to run `stack setup` to get it. `stack` is fully aware of all GHCs that it has installed itself.--See [this issue](https://github.com/commercialhaskell/stack/issues/420) for a detailed discussion.--#### How do I upgrade to GHC 7.10.2 with stack?--If you already have a prior version of GHC use `stack --resolver ghc-7.10 setup --reinstall`. If you don't have any GHC installed, you can skip the `--reinstall`. --#### How do I get extra build tools?--stack will automatically install build tools required by your packages or their-dependencies, in particular alex and happy.--__NOTE__: This works when using lts or nightly resolvers, not with ghc or custom resolvers. You can manually install build tools by running, e.g., `stack build alex happy`.--#### How does stack choose which snapshot to use when creating a new config file?--It checks the two most recent LTS Haskell major versions and the most recent-Stackage Nightly for a snapshot that is compatible with all of the version-bounds in your .cabal file, favoring the most recent LTS. For more information,-see the snapshot auto-detection section in the architecture document.--#### I'd like to use my installed packages in a different directory. How do I tell stack where to find my packages?--Set the `STACK_YAML` environment variable to point to the `stack.yaml` config-file for your project. Then you can run `stack exec`, `stack ghc`, etc., from-any directory and still use your packages.--#### My tests are failing. What should I do?--Like all other targets, `stack test` runs test suites in parallel by default. This can cause problems with test suites that depend on global resources such as a database or binding to a fixed port number. A quick hack is to force stack to run all test suites in sequence, using `stack test --jobs=1`. For test suites to run in parallel developers should ensure that their test suites do not depend on global resources (e.g. by asking the OS for a random port to bind to) and where unavoidable, add a lock in order to serialize access to shared resources.--#### Can I get bash autocompletion?--Yes, see the [shell-autocompletion documentation](shell_autocompletion.md)--#### How do I update my package index?--Users of cabal are used to running `cabal update` regularly. You can do the-same with stack by running `stack update`. But generally, it's not necessary:-if the package index is missing, or if a snapshot refers to package/version-that isn't available, stack will automatically update and then try again. If-you run into a situation where stack doesn't automatically do the update for-you, please report it as a bug.--#### Isn't it dangerous to automatically update the index? Can't that corrupt build plans?--No, stack is very explicit about which packages it's going to build for you.-There are three sources of information to tell it which packages to install:-the selected snapshot, the `extra-deps` configuration value, and your local-packages. The only way to get stack to change its build plan is to modify one-of those three. Updating the index will have no impact on stack's behavior.--#### I have a custom package index I'd like to use, how do I do so?--You can configure this in your stack.yaml. See [YAML configuration](yaml_configuration.md).--#### How can I make sure my project builds against multiple ghc versions?--You can create multiple yaml files for your project,-one for each build plan. For example, you might set up your project directory like so:--```-myproject/- stack-7.8.yaml- stack-7.10.yaml- stack.yaml --> symlink to stack-7.8.yaml- myproject.cabal- src/- ...-```--When you run `stack build`, you can set the-`STACK_YAML` environment variable to indicate which build plan to use.--```-$ stack build # builds using the default stack.yaml-$ STACK_YAML=stack-7.10.yaml stack build # builds using the given yaml file-```--#### I heard you can use this with Docker?--Yes, stack supports using Docker with images that contain preinstalled Stackage-packages and the tools. See [Docker integration](docker_integration.md) for details.--#### How do I use this with Travis CI?--See the [Travis section in the GUIDE](GUIDE.md#travis-with-caching)--#### What is licensing restrictions on Windows?--Currently on Windows GHC produces binaries linked statically with [GNU Multiple Precision Arithmetic Library](https://gmplib.org/) (GMP), which is used by [integer-gmp](https://hackage.haskell.org/package/integer-gmp) library to provide big integer implementation for Haskell. Contrary to the majority of Haskell code licensed under permissive BSD3 license, GMP library is licensed under LGPL, which means resulting binaries [have to be provided with source code or object files](http://www.gnu.org/licenses/gpl-faq.html#LGPLStaticVsDynamic). That may or may not be acceptable for your situation. Current workaround is to use GHC built with alternative big integer implementation called integer-simple, which is free from LGPL limitations as it's pure Haskell and does not use GMP. Unfortunately it has yet to be available out of the box with stack. See [issue #399](https://github.com/commercialhaskell/stack/issues/399) for the ongoing effort and information on workarounds.--#### How to get a working executable on Windows?--When executing a binary after building with `stack build` (e.g. for target "foo"), the command `foo.exe` might complain about missing runtime libraries (whereas `stack exec foo` works).--Windows is not able to find the necessary C++ libraries from the standard prompt because they're not in the PATH environment variable. `stack exec` works because it's modifying PATH to include extra things.--Those libraries are shipped with GHC (and, theoretically in some cases, MSYS). The easiest way to find them is `stack exec which`. E.g.-- >stack exec which libstdc++-6.dll- /c/Users/Michael/AppData/Local/Programs/stack/i386-windows/ghc-7.8.4/mingw/bin/libstdc++-6.dll--A quick workaround is adding this path to the PATH environment variable or copying the files somewhere Windows finds them (cf. https://msdn.microsoft.com/de-de/library/7d83bc18.aspx).--Cf. issue [#425](https://github.com/commercialhaskell/stack/issues/425).--#### Can I change stack's default temporary directory?--Stack makes use of a temporary directory for some commands (/tmp by default on linux). If there is not enough free space in this directory, stack may fail (see issue [#429](https://github.com/commercialhaskell/stack/issues/429) ). For instance `stack setup` with a GHC installation requires roughly 1GB free.--A custom temporary directory can be forced:-* on Linux by setting the environment variable TMPDIR (eg `$ TMPDIR=path-to-tmp stack setup`)-* on Windows by setting one of the environment variable (given in priority order), TMP, TEMP, USERPROFILE--#### stack sometimes rebuilds based on flag changes when I wouldn't expect it to. How come?--stack tries to give you reproducibility whenever possible. In some cases, this means that you get a recompile when one may not seem necessary. The most common example is running something like this in a multi-package project:-- stack build --ghc-options -O0 && stack build --ghc-options -O0 one-of-the-packages--This may end up recompiling local dependencies of `one-of-the-packages` without optimizations on. Whether stack should or shouldn't do this depends on the needs of the user at the time, and unfortunately we can't make a solution that will make everyone happy in all cases. If you're curious for details, there's [a long discussion about it](https://github.com/commercialhaskell/stack/issues/382) on the issue tracker.--#### stack setup on a windows system only tells me to add certain paths to the PATH variable instead of doing it--If you are using a powershell session, it is easy to automate even that step:-- $env:Path = ( stack setup | %{ $_ -replace '[^ ]+ ', ''} ), $env:Path -join ";"--#### How do I reset / remove Stack (such as to to do a completely fresh build)?--The first thing to remove is project-specific `.stack-work` directory within the project's directory. Next, remove `~/.stack` directory overall. You may have errors if you remove the latter but leave the former. Removing Stack itself will relate to how it was installed, and if you used GHC installed outside of Stack, that would need to be removed separately.--#### How does stack handle parallel builds? What exactly does it run in parallel?--See [issue #644](https://github.com/commercialhaskell/stack/issues/644) for more details.--#### I get strange `ld` errors about recompiling with "-fPIC"--Some users (myself included!) have come across a linker errors (example below) that seem to be dependent on the local environment, i.e. the package may compile on a different machine. There is no known workaround (if you come across one please include details), however the issue has been reported to be [non-deterministic]-(https://github.com/commercialhaskell/stack/issues/614) in some cases. I've had success using the docker functionality to build the project on a machine that would not compile it otherwise.--```-tmp-0.1.0.0: build-Building tmp-0.1.0.0...-Preprocessing executable 'tmp' for tmp-0.1.0.0...-Linking dist-stack/x86_64-linux/Cabal-1.22.2.0/build/tmp/tmp ...-/usr/bin/ld: dist-stack/x86_64-linux/Cabal-1.22.2.0/build/tmp/tmp-tmp/Main.o: relocation R_X86_64_32S against `stg_bh_upd_frame_info' can not be used when making a shared object; recompile with -fPIC-dist-stack/x86_64-linux/Cabal-1.22.2.0/build/tmp/tmp-tmp/Main.o: error adding symbols: Bad value-collect2: error: ld returned 1 exit status---- While building package tmp-0.1.0.0 using:- /home/philip/.stack/programs/x86_64-linux/ghc-7.10.1/bin/runghc-7.10.1 -package=Cabal-1.22.2.0 -clear-package-db -global-package-db /home/philip/tmp/Setup.hs --builddir=dist-stack/x86_64-linux/Cabal-1.22.2.0/ build- Process exited with code: ExitFailure 1-```--#### Where does the output from `--ghc-options=-ddump-splices` (and other `-ddump*` options) go?--These are written to `*.dump-*` files inside the package's `.stack-work` directory.
− doc/install_and_upgrade.md
@@ -1,251 +0,0 @@-Distribution packages are available for [Ubuntu](#ubuntu), [Debian](#debian),-[CentOS / Red Hat](#centos--red-hat), [Fedora](#fedora) and-[Arch Linux](#arch-linux). Binaries for other operating systems are listed-below, and available on-[the Github releases page](https://github.com/fpco/stack/releases). For the-future, we are open to supporting more OSes (to request one, please-[submit an issue](https://github.com/commercialhaskell/stack/issues/new)).--Binary packages are signed with this [signing key](SIGNING_KEY.md).--If you are writing a script that needs to download the latest binary, you can-find links that always point to the latest bindists-[here](https://www.stackage.org/stack).--## Windows--*Note*: Due to specific Windows limitations,- [some temporary workarounds](https://www.fpcomplete.com/blog/2015/08/stack-ghc-windows)- may be required. It is strongly advised to set your `STACK_ROOT` environment- variable similarly to your root (e.g., `set STACK_ROOT=c:\stack_root`) *before*- running `stack`.--*Note:* while generally 32-bit GHC is better tested on Windows, there are-reports that recent versions of Windows only work with the 64-bit version of-Stack (see-[issue #393](https://github.com/commercialhaskell/stack/issues/393)).--### Installer--We recommend installing to the default location with these installers, as that-will make `stack install` and `stack upgrade` work correctly out of the box.-- * [Windows 32-bit Installer](https://www.stackage.org/stack/windows-i386-installer)- * [Windows 64-bit Installer](https://www.stackage.org/stack/windows-x86_64-installer)--### Manual download--* Download the latest release:-- * [Windows 32-bit](https://www.stackage.org/stack/windows-i386)- * [Windows 64-bit](https://www.stackage.org/stack/windows-x86_64)--* Unpack the archive and place `stack.exe` somewhere on your `%PATH%` (see- [Path section below](#path)) and you can then run `stack` on the command line.--* Now you can run `stack` from the terminal.--NOTE: These executables have been built and tested on a Windows 7, 8.1, and 10-64-bit machines. They should run on older Windows installs as well, but have not-been tested. If you do test, please edit and update this page to indicate as-such.--## Mac OS X--### Using brew--If you have a popular [brew](http://brew.sh/) tool installed, you can just do:--```-brew install haskell-stack-```--### Manual download--* Download the latest release:- * [Mac OS X 64-bit](https://www.stackage.org/stack/osx-x86_64)-* Extract the archive and place `stack` somewhere on your `$PATH` (see- [Path section below](#path))-* Now you can run `stack` from the terminal.--We generally test on the current version of Mac OS X, but stack is known to work on-Yosemite and Mavericks as well, and may also work on older versions (YMMV).--## Ubuntu--*note*: for 32-bit, use the [generic Linux option](#linux)--1. Get the FP Complete key:-- wget -q -O- https://s3.amazonaws.com/download.fpcomplete.com/ubuntu/fpco.key | sudo apt-key add ---2. Add the appropriate source repository (if not sure, run ``lsb_release -a`` to find out your Ubuntu version):-- * Ubuntu 15.10 (amd64):-- echo 'deb http://download.fpcomplete.com/ubuntu/wily stable main'|sudo tee /etc/apt/sources.list.d/fpco.list-- * Ubuntu 15.04 (amd64):-- echo 'deb http://download.fpcomplete.com/ubuntu/vivid stable main'|sudo tee /etc/apt/sources.list.d/fpco.list-- * Ubuntu 14.10 (amd64)-- echo 'deb http://download.fpcomplete.com/ubuntu/utopic stable main'|sudo tee /etc/apt/sources.list.d/fpco.list-- * Ubuntu 14.04 (amd64)-- echo 'deb http://download.fpcomplete.com/ubuntu/trusty stable main'|sudo tee /etc/apt/sources.list.d/fpco.list-- * Ubuntu 12.04 (amd64)-- echo 'deb http://download.fpcomplete.com/ubuntu/precise stable main'|sudo tee /etc/apt/sources.list.d/fpco.list--3. Update apt and install-- sudo apt-get update && sudo apt-get install stack -y--## Debian--*note*: for 32-bit, use the [generic Linux option](#linux)--1. Get the FP Complete key:-- wget -q -O- https://s3.amazonaws.com/download.fpcomplete.com/debian/fpco.key | sudo apt-key add ---2. Add the appropriate source repository:-- * Debian 8 (amd64):-- echo 'deb http://download.fpcomplete.com/debian/jessie stable main'|sudo tee /etc/apt/sources.list.d/fpco.list-- * Debian 7 (amd64)-- echo 'deb http://download.fpcomplete.com/debian/wheezy stable main'|sudo tee /etc/apt/sources.list.d/fpco.list--3. Update apt and install-- sudo apt-get update && sudo apt-get install stack -y--## CentOS / Red Hat / Amazon Linux--*note*: for 32-bit, use the [generic Linux option](#linux)--1. Add the appropriate source repository:-- * CentOS 7 / RHEL 7 (x86_64)-- curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/centos/7/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo-- * CentOS 6 / RHEL 6 (x86_64)-- curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/centos/6/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo--2. Install:-- sudo yum -y install stack--## Fedora--*note*: for 32-bit, you can use this [Fedora Copr repo](https://copr.fedoraproject.org/coprs/petersen/stack/) which can be enabled with:-- sudo dnf copr enable petersen/stack--1. Add the appropriate source repository:-- * Fedora 23 (x86_64)-- curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/fedora/23/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo-- * Fedora 22 (x86_64)-- curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/fedora/22/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo-- * Fedora 21 (x86_64)-- curl -sSL https://s3.amazonaws.com/download.fpcomplete.com/fedora/21/fpco.repo | sudo tee /etc/yum.repos.d/fpco.repo--2. Install:-- * Fedora 22 and above-- sudo dnf -y install stack-- * Fedora < 22-- sudo yum -y install stack--## Arch Linux--*note*: for 32-bit, use the [generic Linux option](#linux). (You will need to ensure libtinfo is installed, see below.)--stack can be found in the AUR:- - [haskell-stack](https://aur.archlinux.org/packages/haskell-stack/) _latest stable version_- - [haskell-stack-git](https://aur.archlinux.org/packages/haskell-stack-git/) _git version_--In order to install stack from Hackage or from source, you will need the [libtinfo](https://aur.archlinux.org/packages/libtinfo/) Arch Linux package installed. If this package is not installed, stack will not be able to install GHC. --If you use the [ArchHaskell repository](https://wiki.archlinux.org/index.php/ArchHaskell), you can also get the `haskell-stack` package from there.--## NixOS--Users who follow the `nixos-unstable` channel or the Nixpkgs `master` branch can install the latest `stack` release into their profile by running:-- nix-env -f "<nixpkgs>" -iA haskellPackages.stack--Alternatively, the package can be built from source as follows.--1. Clone the git repo:-- git clone https://github.com/commercialhaskell/stack.git--2. Create a `shell.nix` file:-- cabal2nix --shell ./. --no-check --no-haddock > shell.nix-- Note that the tests fail on NixOS, so disable them with `--no-check`. Also, haddock currently doesn't work for stack, so `--no-haddock` disables it.--3. Install stack to your user profile:-- nix-env -i -f shell.nix--For more information on using Stack together with Nix, please see [the NixOS-manual section on-Stack](http://nixos.org/nixpkgs/manual/#using-stack-together-with-nix).--## Linux--(64-bit and 32-bit options available)--* Download the latest release:-- * [Linux 64-bit, standard](https://www.stackage.org/stack/linux-x86_64)- * [Linux 32-bit, standard](https://www.stackage.org/stack/linux-i386)-- If you are on an older distribution that only includes libgmp4 (libgmp.so.3), such as CentOS/RHEL/Amazon Linux 6.x, use one of these instead:-- * [Linux 64-bit, libgmp4](https://www.stackage.org/stack/linux-x86_64-gmp4)- * [Linux 32-bit, libgmp4](https://www.stackage.org/stack/linux-i386-gmp4)--* Extract the archive and place `stack` somewhere on your `$PATH` (see [Path section below](#path))--* Now you can run `stack` from the terminal.--Tested on Fedora 20: make sure to install the following packages `sudo yum install perl make automake gcc gmp-devel`.-For Gentoo users, make sure to have the `ncurses` package with `USE=tinfo` (without it, stack will not be able to install GHC).--## Path--You can install stack by copying it anywhere on your PATH environment variable. We recommend installing in the same directory where stack itself will install executables (that way stack is able to upgrade itself!). On Windows, that directory is `%APPDATA%\local\bin`, e.g. "c:\Users\Michael\AppData\Roaming\local\bin". For other systems, use `$HOME/.local/bin`.--If you don't have that directory in your PATH, you may need to update your PATH (such as by editing .bashrc).--If you're curious about the choice of these paths, see [issue #153](https://github.com/commercialhaskell/stack/issues/153)--## Upgrade--There are essentially three different approaches to upgrade:--* If you're using a package manager (e.g., the Ubuntu debs listed above) and are happy with sticking with the officially released binaries, simply follow your normal package manager strategies for upgrading (e.g. `apt-get update && apt-get upgrade`).-* If you're not using a package manager but want to stick with the official binaries (such as on Windows or Mac), you'll need to manually follow the steps above to download the newest binaries from the release page and replace the old binary.-* The `stack` tool itself ships with an `upgrade` command, which will build `stack` from source and install it to the default install path (see the previous section). You can use `stack upgrade` to get the latest official release, and `stack upgrade --git` to install from Git and live on the bleeding edge. If you follow this, make sure that this directory is on your `PATH` and takes precedence over the system installed `stack`. For more information, see [this discussion](https://github.com/commercialhaskell/stack/issues/237#issuecomment-126793301).
− doc/nonstandard_project_init.md
@@ -1,101 +0,0 @@-# Introduction-The purpose of this page is to collect information about issues that arise when users either have an existing cabal project or another nonstandard setup such as a private hackage database.--# Using a Cabal File-New users may be confused by the fact that you must add dependencies to the package's cabal file, even in the case when you have already listed the package in the `stack.yaml`. In most cases, dependencies for your package that are in the Stackage snapshot need *only* be added to the cabal file. stack makes heavy use of Cabal the library under the hood. In general, your stack packages should also end up being valid cabal-install packages.--## Issues Referenced- - https://github.com/commercialhaskell/stack/issues/105--# Passing Flags to Cabal--Any build command, `bench`, `install`, `haddock`, `test`, etc. takes a `--flag` option which passes flags to cabal. Another way to do this is using the flags field in a `stack.yaml`, with the option to specify flags on a per package basis.--As an example, in a `stack.yaml` for multi-package project with packages `foo`, `bar`, `baz`:--```-flags:- foo:- release: true- bar:- default: true- baz:- manual: true-```--It is also possible to pass the same flag to multiple packages, i.e. `stack build --flag *:necessary`--Currently one needs to list all of your modules that interpret flags in the `other-modules` section of a cabal file. `cabal-install` has a different behavior currently and doesn't require that the modules be listed. This may change in a future release.---## Issues Referenced- - https://github.com/commercialhaskell/stack/issues/191- - https://github.com/commercialhaskell/stack/issues/417- - https://github.com/commercialhaskell/stack/issues/335- - https://github.com/commercialhaskell/stack/issues/301- - https://github.com/commercialhaskell/stack/issues/365- - https://github.com/commercialhaskell/stack/issues/105--# Selecting a Resolver--`stack init` or `stack new` will try to default to the current Haskell LTS present on `https://www.stackage.org/snapshots` if no snapshot has been previously used locally, and to the latest LTS snapshot locally used for a build otherwise. Using an incorrect resolver can cause a build to fail if the version of GHC it requires is not present.--In order to override the resolver entry at project initialization one can pass `--prefer-lts` or `--prefer-nightly`. These options will choose the latest LTS or nightly versions locally used.-Alternatively the `--resolver` option can be used with the name of any snapshots on Stackage, or with `lts` or `nightly` to select the latest versions, disregarding previously used ones. This is not the default so as to avoid unnecessary recompilation time.--:TODO: Document `--solver`--## Issues Referenced- - https://github.com/commercialhaskell/stack/issues/468- - https://github.com/commercialhaskell/stack/issues/464--# Using git Repositories-stack has support for packages that reside in remote git locations.--Example:--```-packages:-- '.'-- location:- git: https://github.com/kolmodin/binary- commit: 8debedd3fcb6525ac0d7de2dd49217dce2abc0d9-```--## Issues Referenced- - https://github.com/commercialhaskell/stack/issues/254- - https://github.com/commercialhaskell/stack/issues/199--# Private Hackage-Working with a private Hackage is currently supported in certain situations.-There exist special entries in `stack.yaml` that may help you. In a `stack.yaml` file, it is possible-to add lines for packages in your database referencing the sdist locations via an `http` entry, or to use a `Hackage` entry.--The recommended stack workflow is to use git submodules instead of a private Hackage. Either by using git submodules and listing the directories in the packages section of `stack.yaml`, or by adding the private dependencies as git URIs with a commit SHA to the `stack.yaml`. This has the large benefit of eliminating the need to manage a Hackage database and pointless version bumps.--For further information see [YAML configuration](yaml_configuration.md)--## Issues Referenced- - https://github.com/commercialhaskell/stack/issues/445- - https://github.com/commercialhaskell/stack/issues/565--# Custom Snapshots-Currently WIP?-## Issues Referenced- - https://github.com/commercialhaskell/stack/issues/111- - https://github.com/commercialhaskell/stack/issues/253- - https://github.com/commercialhaskell/stack/issues/137--# Intra-package Targets-stack supports intra-package targets, similar to `cabal build COMPONENTS` for situations when you don't want to build every target inside your package.--Example:-```-stack build stack:lib:stack-stack test stack:test:stack-integration-test-```--Note: this does require prefixing the component name with the package name.--## Issues referenced- - https://github.com/commercialhaskell/stack/issues/201
− doc/shell_autocompletion.md
@@ -1,35 +0,0 @@-## Shell Autocompletion:--Note: if you installed a package for you Linux distribution, the bash completion-file was automatically installed (you may need the `bash-completion` package to-have it take effect).--The following adds support for shell tab completion for standard Stack arguments, although completion for filenames and executables etc. within stack is still lacking (see [issue 823](https://github.com/commercialhaskell/stack/issues/832)).--### for bash users--you need to run following command-```-eval "$(stack --bash-completion-script "$(which stack)")"-```-You can also add it to your `.bashrc` file if you want.--### for ZSH users:--documentation says:-> Zsh can handle bash completions functions. The latest development version of zsh has a function bashcompinit, that when run will allow zsh to read bash completion specifications and functions. This is documented in the zshcompsys man page. To use it all **you need to do is run bashcompinit at any time after compinit**. It will define complete and compgen functions corresponding to the bash builtins.--You must so:- 1. launch compinint- 2. launch bashcompinit- 3. eval stack bash completion script--```shell-autoload -U +X compinit && compinit-autoload -U +X bashcompinit && bashcompinit-eval "$(stack --bash-completion-script "$(which stack)")"-```--:information_source: If you already have quite a large zshrc, or if you use oh-my-zsh, **compinit** will probably already be loaded. If you have a blank zsh config, all of the 3 lines above are necessary.--:gem: tip: instead of running those 3 lines from your shell every time you want to use stack, you can add those 3 lines in your $HOME/.zshrc file
− doc/stack_and_ghcjs.md
@@ -1,75 +0,0 @@-# Stack & GHCJS--To set up and use GHCJS with stack, you should place GHCJS `resolver` in your project's `stack.yaml` (see instructions for [old base](#ghcjs-old-base) and [`master` - a.k.a. improved base](#ghcjs-master-aka-improved-base)). Once this has been done, Stack will use GHCJS for most commands, with the exception of `ghc`, `runghc` and `ide`. (Support for `ghc` and `runghc` will likely be added before the next release - see [#1054](https://github.com/commercialhaskell/stack/issues/1054)).--After creating a `stack.yaml`, which specifies that ghcjs is to be used (see below), you can have Stack automatically set up and boot GHCJS. Stack must be newer than `0.1.6`:--```-$ stack setup-```--(this will take a long time)--## Using a stackage snapshot--The configurations below use a compiler resolver, which means that you can't use packages from a stackage snapshot. The latest development version (which will probably be released as `0.1.7`) also supports using GHCJS with a stackage snapshot, via a `compiler` field. To use the latest development version, do the following:--```-$ stack upgrade --git-```--For example, the old-base configuration looks like this:--```yaml-resolver: lts-3.10-compiler: ghcjs-0.1.0.20150924_ghc-7.10.2-compiler-check: match-exact-```--You can also build existing stack projects which target GHC and instead build them with GHCJS. To do this, invoke stack like this: `stack build --compiler ghcjs-0.1.0.20150924_ghc-7.10.2`--## Example Configurations--### GHCJS (old base)--You can use this resolver for GHCJS (old base) in your `stack.yaml`:--```yaml-resolver: ghcjs-0.1.0.20150924_ghc-7.10.2-compiler-check: match-exact-```--### GHCJS `master` (a.k.a. improved base)--To use the master branch, a.k.a improved base, add the following to your `stack.yaml`:--```yaml-resolver: ghcjs-0.2.0.20151001_ghc-7.10.2-compiler-check: match-exact-setup-info:- ghcjs:- source:- ghcjs-0.2.0.20151001_ghc-7.10.2:- url: "https://github.com/fizruk/ghcjs/releases/download/v0.2.0.20151001/ghcjs-0.2.0.20151001.tar.gz"-```--or for the 2015-10-29 master branch -```yaml-resolver: ghcjs-0.2.0.20151029_ghc-7.10.2-compiler-check: match-exact-setup-info:- ghcjs:- source:- ghcjs-0.2.0.20151029_ghc-7.10.2:- url: "https://github.com/nrolland/ghcjs/releases/download/v0.2.0.20151029/ghcjs-0.2.0.20151029.tar.gz"-```--### Custom installed GHCJS (development branch)--In order to use a GHCJS installed on your path, just add the following to your `stack.yaml`:--```yaml-resolver: ghcjs-0.2.0_ghc-7.10.2-```--(Or, `ghcjs-0.1.0_ghc-7.10.2` if you are working with an older version)
− doc/yaml_configuration.md
@@ -1,407 +0,0 @@-This page is intended to fully document all configuration options available in the stack.yaml file. Note that this page is likely to be both *incomplete* and sometimes *inaccurate*. If you see such cases, please update the page, and if you're not sure how, open an issue labeled "question".--The stack.yaml configuration options break down into [project specific](#project-config) options in:--- `<project dir>/stack.yaml`--and [non-project specific](#non-project-config) options in:--- `/etc/stack/config.yaml` -- for system global non-project default options-- `~/.stack/config.yaml` -- for user non-project default options-- The project file itself may also contain non-project specific options--*Note:* When stack is invoked outside a stack project it will source project specific options from `~/.stack/global/stack.yaml`. Options in this file will be ignored for a project with its own `<project dir>/stack.yaml`.--## Project config--Project specific options are only valid in the `stack.yaml` file local to a project, not in the user or global config files.--### packages--This lists all local packages. In the simplest usage, it will be a list of directories, e.g.:--```yaml-packages:-- dir1-- dir2-- dir3-```--However, it supports two other location types: an HTTP URL referring to a tarball that can be downloaded, and information on a Git repo to clone, together with this SHA1 commit. For example:--```yaml-packages:-- some-directory-- https://example.com/foo/bar/baz-0.0.2.tar.gz-- location:- git: git@github.com:commercialhaskell/stack- commit: 6a86ee32e5b869a877151f74064572225e1a0398-```--Note: it is highly recommended that you only use SHA1 values for a Git commit. Other values may work, but they are not officially supported, and may result in unexpected behavior (namely, stack will not automatically pull to update to new versions).--stack further allows you to tweak your packages by specifying two additional-settings:--* A list of subdirectories to build (useful for mega-repos like-[wai](https://github.com/yesodweb/wai/) or-[digestive-functors](https://github.com/jaspervdj/digestive-functors))-* Whether a package should be treated as a dependency: a package marked `extra-dep: true` will only be built if demanded by a non-dependency, and its test suites and benchmarks will not be run. This is useful for tweaking upstream packages.--To tie this all together, here's an example of the different settings:--```yaml-packages:-- local-package-- location: vendor/binary- extra-dep: true-- location:- git: git@github.com:yesodweb/wai- commit: 2f8a8e1b771829f4a8a77c0111352ce45a14c30f- subdirs:- - auto-update- - wai-```--### extra-deps--This is a list of package identifiers for additional packages from upstream to-be included. This is usually used to augment an LTS Haskell or Stackage Nightly-snapshot with a package that is not present or is at an older version than you-wish to use.--```yaml-extra-deps:-- acme-missiles-0.3-```--### resolver--Specifies how dependencies are resolved. There are currently four resolver types:--* LTS Haskell snapshots, e.g. `resolver: lts-2.14`-* Stackage Nightly snapshot, e.g. `resolver: nightly-2015-06-16`-* No snapshot, just use packages shipped with the compiler- * For GHC this looks like `resolver: ghc-7.10.2`- * For GHCJS this looks like `resolver: ghcjs-0.1.0_ghc-7.10.2`.-* [Custom snapshot](https://github.com/commercialhaskell/stack/wiki/Custom-Snapshot)--Each of these resolvers will also determine what constraints are placed on the compiler version. See the [compiler-check](#compiler-check) option for some additional control over compiler version.--### flags--Flags can be set for each package separately, e.g.--```yaml-flags:- package-name:- flag-name: true-```--Flags will only affect packages in your `packages` and `extra-deps` settings.-Packages that come from the snapshot global database or are not affected.--### image-The image settings are used for the creation of container images using `stack image container`, e.g.-```yaml-image:- container:- base: "fpco/stack-build"- add:- static: /data/static-```-`base` is the docker image that will be used to built upon. The `add` lines allow you to add additional directories to your image. You can also specify `entrypoints`. Your executables are placed in `/usr/local/bin`.--## Non-project config--Non-project config options may go in the global config (`/etc/stack/config.yaml`) or the user config (`~/.stack/config.yaml`).--### docker--See [Docker configuration](https://github.com/commercialhaskell/stack/blob/release/doc/docker_integration.md).--### connection-count--Integer indicating how many simultaneous downloads are allowed to happen--Default: `8`--### hide-th-loading--Strip out the "Loading ..." lines from GHC build output, produced when using Template Haskell--Default: `true`--### latest-snapshot-url--URL providing a JSON with information on the latest LTS and Nightly snapshots, used for automatic project configuration.--Default: `https://www.stackage.org/download/snapshots.json`--### local-bin-path--Target directory for `stack install` and `stack build --copy-bins`.--Default: `~/.local/bin`--### package-indices--```yaml-package-indices:-- name: Hackage- download-prefix: https://s3.amazonaws.com/hackage.fpcomplete.com/package/-- # at least one of the following must be present- git: https://github.com/commercialhaskell/all-cabal-hashes.git- http: https://s3.amazonaws.com/hackage.fpcomplete.com/00-index.tar.gz-- # optional fields, both default to false- gpg-verify: false- require-hashes: false-```--One thing you should be aware of: if you change the contents of package-version-combination by setting a different package index, this *can* have an effect on-other projects by installing into your shared snapshot database.--### system-ghc--Enables or disables using the GHC available on the PATH. Useful to disable if-you want to force stack to use its own installed GHC (via `stack setup`), in-cases where your system GHC my be incomplete for some reason. Default is `true`.--```yaml-# Turn off system GHC-system-ghc: false-```--### install-ghc--Whether or not to automatically install GHC when necessary. Default is `false`,-which means stack will prompt you to run `stack setup` as needed.--### skip-ghc-check--Should we skip the check to confirm that your system GHC version (on the PATH) matches what your project expects? Default is `false`.--### require-stack-version--Require a version of stack within the specified range-([cabal-style](https://www.haskell.org/cabal/users-guide/developing-packages.html#build-information))-to be used for this project. Example: `require-stack-version: "== 0.1.*"`--Default: `"-any"`--### arch/os--Set the architecture and operating system for GHC, build directories, etc. Values are those recognized by Cabal, e.g.:-- arch: i386, x86_64- os: windows, linux--You likely only ever want to change the arch value. This can also be set via the command line.--### extra-include-dirs/extra-lib-dirs--A list of extra paths to be searched for header files and libraries, respectively. Paths should be absolute--```yaml-extra-include-dirs:-- /opt/foo/include-extra-lib-dirs:-- /opt/foo/lib-```--### compiler-check--(Since 0.1.4)--Specifies how the compiler version in the resolver is matched against concrete versions. Valid values:--* `match-minor`: make sure that the first three components match, but allow patch-level differences. For example< 7.8.4.1 and 7.8.4.2 would both match 7.8.4. This is useful to allow for custom patch levels of a compiler. This is the default-* `match-exact`: the entire version number must match precisely-* `newer-minor`: the third component can be increased, e.g. if your resolver is `ghc-7.10.1`, then 7.10.2 will also be allowed. This was the default up through stack 0.1.3--### compiler--(Since 0.1.7)--Overrides the compiler version in the resolver. Note that the `compiler-check`-flag also applies to the version numbers. This uses the same syntax as compiler-resolvers like `ghc-7.10.2` or `ghcjs-0.1.0.20150924_ghc-7.10.2` (version used-for the 'old-base' version of GHCJS). While it's useful to override the-compiler for a variety of reasons, the main usecase is to use GHCJS with a-stackage snapshot, like this:--```yaml-resolver: lts-3.10-compiler: ghcjs-0.1.0.20150924_ghc-7.10.2-compiler-check: match-exact-```--### ghc-options--(Since 0.1.4)--Allows specifying per-package and global GHC options:--```yaml-ghc-options:- # All packages- "*": -Wall- some-package: -DSOME_CPP_FLAG-```--Caveat emptor: setting options like this will affect your snapshot packages,-which can lead to unpredictable behavior versus official Stackage snapshots.-This is in contrast to the `ghc-options` command line flag, which will only-affect local packages.--### ghc-variant--(Since 0.1.5)--Specify a variant binary distribution of GHC to use. Known values:--* `standard`: This is the default, uses the standard GHC binary distribution-* `gmp4`: Use the "centos6" GHC bindist, for Linux systems with libgmp4 (aka- `libgmp.so.3`), such as CentOS 6. This variant will be used automatically on such systems; you should not need to specify it in the configuration-* `integersimple`: Use a GHC bindist that uses- [integer-simple instead of GMP](https://ghc.haskell.org/trac/ghc/wiki/ReplacingGMPNotes)-* any other value: Use a custom GHC bindist. You should specify- [setup-info](#setup-info) so `stack setup` knows where to download it, or- pass the `stack setup --ghc-bindist` argument on the command-line--### setup-info--(Since 0.1.5)--Allows overriding from where tools like GHC and msys2 (on Windows) are-downloaded. Most useful for specifying locations of custom GHC binary-distributions (for use with the [ghc-variant](#ghc-variant) option):--```yaml-setup-info:- ghc:- windows32-custom-foo:- 7.10.2:- url: "https://example.com/ghc-7.10.2-i386-unknown-mingw32-foo.tar.xz"-```--### pvp-bounds--(Since 0.1.5)--When using the `sdist` and `upload` commands, this setting determines whether-the cabal file's dependencies should be modified to reflect PVP lower and upper-bounds. Values are `none` (unchanged), `upper` (add upper bounds), `lower` (add-lower bounds), and both (and upper and lower bounds). The algorithm it follows-is:--* If an upper or lower bound already exists on a dependency, it's left alone-* When adding a lower bound, we look at the current version specified by stack.yaml, and set it as the lower bound (e.g., `foo >= 1.2.3`)-* When adding an upper bound, we require less than the next major version (e.g., `foo < 1.3`)--```yaml-pvp-bounds: none-```--For more information, see [the announcement blog post](https://www.fpcomplete.com/blog/2015/09/stack-pvp).--### modify-code-page--(Since 0.1.6)--Modify the code page for UTF-8 output when running on Windows. Default behavior-is to modify.--```yaml-modify-code-page: false-```--### explicit-setup-deps--(Since 0.1.6)--Decide whether a custom `Setup.hs` script should be run with an explicit list of-dependencies, based on the dependencies of the package itself. It associates the-name of a local package with a boolean. When it's `true`, the `Setup.hs` script-is built with an explicit list of packages. When it's `false` (default), the-`Setup.hs` script is built without access to the local DB, but can access any-package in the snapshot / global DB.--Note that in the future, this will be unnecessary, once Cabal provides full-support for explicit Setup.hs dependencies.--```yaml-explicit-setup-deps:- "*": true # change the default- entropy: false # override the new default for one package-```--### rebuild-ghc-options--(Since 0.1.6)--Should we rebuild a package when its GHC options change? Before 0.1.6, this was a non-configurable true. However, in most cases, the flag is used to affect optimization levels and warning behavior, for which GHC itself doesn't actually recompile the modules anyway. Therefore, the new behavior is to not recompile on an options change, but this behavior can be changed back with the following:--```yaml-rebuild-ghc-options: true-```--### apply-ghc-options--(Since 0.1.6)--Which packages do ghc-options on the command line get applied to? Before 0.1.6, the default value was `targets`--```yaml-apply-ghc-options: locals # all local packages, the default-# apply-ghc-options: targets # all local packages that are targets-# apply-ghc-options: everything # applied even to snapshot and extra-deps-```--Note that `everything` is a slightly dangerous value, as it can break invariants about your snapshot database.--### allow-newer--(Since 0.1.7)--Ignore version bounds in .cabal files. Default is false.--```yaml-allow-newer: true-```--Note that this also ignores lower bounds. The name "allow-newer" is chosen to-match the commonly used cabal option.--### templates--Templates used with `stack new` have a number of parameters that affect the generated code. These can be set for all new projects you create. The result of them can be observed in the generated LICENSE and cabal files.--The 5 parameters are: `author-email`, `author-name`, `category`, `copyright` and `github-username`.--* _author-email_ - sets the `maintainer` property in cabal-* _author-name_ - sets the `author` property in cabal and the name used in LICENSE-* _category_ - sets the `category` property in cabal. This is used in Hackage. For examples of categories see [Packages by category](https://hackage.haskell.org/packages/). It makes sense for `category` to be set on a per project basis because it is uncommon for all projects a user creates to belong to the same category. The category can be set per project by passing `-p "category:value"` to the `stack new` command.-* _copyright_ - sets the `copyright` property in cabal. It is typically the name of the holder of the copyright on the package and the year(s) from which copyright is claimed. For example: `Copyright: (c) 2006-2007 Joe Bloggs`-* _github-username_ - used to generate `homepage` and `source-repository` in cabal. For instance `github-username: myusername` and `stack new my-project new-template` would result:-```yaml-homepage: http://github.com/myusername/my-project#readme--source-repository head- type: git- location: https://github.com/myusername/my-project-```--These properties can be set in `config.yaml` as follows:-```yaml-templates:- params:- author-name: Your Name- author-email: youremail@example.com- category: Your Projects Category- copyright: Copyright: (c) 2015 Your Name- github-username: yourusername-```
src/Network/HTTP/Download/Verified.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PackageImports #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RecordWildCards #-}@@ -31,7 +32,7 @@ import Control.Monad.Reader import Control.Retry (recovering,limitRetries,RetryPolicy,constantDelay) import Control.Applicative-import Crypto.Hash+import "cryptohash" Crypto.Hash import Crypto.Hash.Conduit (sinkHash) import Data.ByteString (ByteString) import Data.ByteString.Char8 (readInteger)
src/Options/Applicative/Complicated.hs view
@@ -35,13 +35,18 @@ -- ^ program description -> Parser a -- ^ common settings+ -> Maybe (ParserFailure ParserHelp -> [String] -> IO (a,(b,a)))+ -- ^ optional handler for parser failure; 'handleParseResult' is called by+ -- default -> EitherT b (Writer (Mod CommandFields (b,a))) () -- ^ commands (use 'addCommand') -> IO (a,b)-complicatedOptions numericVersion versionString h pd commonParser commandParser =+complicatedOptions numericVersion versionString h pd commonParser mOnFailure commandParser = do args <- getArgs (a,(b,c)) <- case execParserPure (prefs noBacktrack) parser args of Failure _ | null args -> withArgs ["--help"] (execParser parser)+ -- call onFailure handler if it's present and parsing options failed+ Failure f | Just onFailure <- mOnFailure -> onFailure f args parseResult -> handleParseResult parseResult return (mappend c a,b) where parser = info (helpOption <*> versionOptions <*> complicatedParser commonParser commandParser) desc
src/Stack/Build.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-}@@ -29,8 +28,13 @@ import Data.Function import qualified Data.HashMap.Strict as HM import Data.IORef.RunOnce (runOnce)+import Data.List ((\\))+import Data.List.Extra (groupSort)+import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.List.NonEmpty as NE import qualified Data.Map as Map import Data.Map.Strict (Map)+import Data.Monoid import Data.Set (Set) import qualified Data.Set as Set import Data.Text (Text)@@ -106,6 +110,8 @@ liftIO $ unlockFile lk _ -> return () + warnIfExecutablesWithSameNameCouldBeOverwritten locals plan+ when (boptsPreFetch bopts) $ preFetch plan @@ -127,6 +133,79 @@ map taskLocation . Map.elems . planTasks++-- | See https://github.com/commercialhaskell/stack/issues/1198.+warnIfExecutablesWithSameNameCouldBeOverwritten+ :: MonadLogger m => [LocalPackage] -> Plan -> m ()+warnIfExecutablesWithSameNameCouldBeOverwritten locals plan =+ forM_ (Map.toList warnings) $ \(exe,(toBuild,otherLocals)) -> do+ let exe_s+ | length toBuild > 1 = "several executables with the same name:"+ | otherwise = "executable"+ exesText pkgs =+ T.intercalate+ ", "+ ["'" <> packageNameText p <> ":" <> exe <> "'" | p <- pkgs]+ ($logWarn . T.unlines . concat)+ [ [ "Building " <> exe_s <> " " <> exesText toBuild <> "." ]+ , [ "Only one of them will be available via 'stack exec' or locally installed."+ | length toBuild > 1+ ]+ , [ "Other executables with the same name might be overwritten: " <>+ exesText otherLocals <> "."+ | not (null otherLocals)+ ]+ ]+ where+ -- Cases of several local packages having executables with the same name.+ -- The Map entries have the following form:+ --+ -- executable name: ( package names for executables that are being built+ -- , package names for other local packages that have an+ -- executable with the same name+ -- )+ warnings :: Map Text ([PackageName],[PackageName])+ warnings =+ Map.mapMaybe+ (\(pkgsToBuild,localPkgs) ->+ case (pkgsToBuild,NE.toList localPkgs \\ NE.toList pkgsToBuild) of+ (_ :| [],[]) ->+ -- We want to build the executable of single local package+ -- and there are no other local packages with an executable of+ -- the same name. Nothing to warn about, ignore.+ Nothing+ (_,otherLocals) ->+ -- We could be here for two reasons (or their combination):+ -- 1) We are building two or more executables with the same+ -- name that will end up overwriting each other.+ -- 2) In addition to the executable(s) that we want to build+ -- there are other local packages with an executable of the+ -- same name that might get overwritten.+ -- Both cases warrant a warning.+ Just (NE.toList pkgsToBuild,otherLocals))+ (Map.intersectionWith (,) exesToBuild localExes)+ exesToBuild :: Map Text (NonEmpty PackageName)+ exesToBuild =+ collect+ [ (exe,pkgName)+ | (pkgName,task) <- Map.toList (planTasks plan)+ , isLocal task+ , exe <- (Set.toList . exeComponents . lpComponents . taskLP) task+ ]+ where+ isLocal Task{taskType = (TTLocal _)} = True+ isLocal _ = False+ taskLP Task{taskType = (TTLocal lp)} = lp+ taskLP _ = error "warnIfExecutablesWithSameNameCouldBeOverwritten/taskLP: task isn't local"+ localExes :: Map Text (NonEmpty PackageName)+ localExes =+ collect+ [ (exe,packageName pkg)+ | pkg <- map (lpPackage) locals+ , exe <- Set.toList (packageExes pkg)+ ]+ collect :: Ord k => [(k,v)] -> Map k (NonEmpty v)+ collect = Map.map NE.fromList . Map.fromDistinctAscList . groupSort -- | Get the @BaseConfigOpts@ necessary for constructing configure options mkBaseConfigOpts :: (MonadIO m, MonadReader env m, HasEnvConfig env, MonadThrow m)
src/Stack/Build/ConstructPlan.hs view
@@ -11,7 +11,7 @@ ( constructPlan ) where -import Control.Arrow ((&&&))+import Control.Arrow ((&&&), second) import Control.Exception.Lifted import Control.Monad import Control.Monad.Catch (MonadCatch)@@ -106,7 +106,7 @@ , ctxEnvConfig :: !EnvConfig , callStack :: ![PackageName] , extraToBuild :: !(Set PackageName)- , latestVersions :: !(Map PackageName Version)+ , ctxVersions :: !(Map PackageName (Set Version)) , wanted :: !(Set PackageName) , localNames :: !(Set PackageName) }@@ -134,9 +134,9 @@ constructPlan mbp0 baseConfigOpts0 locals extraToBuild0 localDumpPkgs loadPackage0 sourceMap installedMap = do let locallyRegistered = Map.fromList $ map (dpGhcPkgId &&& dpPackageIdent) localDumpPkgs bconfig <- asks getBuildConfig- let latest =- Map.fromListWith max $- map toTuple $+ let versions =+ Map.fromListWith Set.union $+ map (second Set.singleton . toTuple) $ Map.keys (bcPackageCaches bconfig) econfig <- asks getEnvConfig@@ -145,7 +145,7 @@ mapM_ onWanted $ filter lpWanted locals mapM_ (addDep False) $ Set.toList extraToBuild0 ((), m, W efinals installExes dirtyReason deps warnings) <-- liftIO $ runRWST inner (ctx econfig latest) M.empty+ liftIO $ runRWST inner (ctx econfig versions) M.empty mapM_ $logWarn (warnings []) let toEither (_, Left e) = Left e toEither (k, Right v) = Right (k, v)@@ -173,7 +173,7 @@ } else throwM $ ConstructPlanExceptions errs (bcStackYaml $ getBuildConfig econfig) where- ctx econfig latest = Ctx+ ctx econfig versions = Ctx { mbp = mbp0 , baseConfigOpts = baseConfigOpts0 , loadPackage = loadPackage0@@ -184,7 +184,7 @@ , ctxEnvConfig = econfig , callStack = [] , extraToBuild = extraToBuild0- , latestVersions = latest+ , ctxVersions = versions , wanted = wantedLocalPackages locals , localNames = Set.fromList $ map (packageName . lpPackage) locals }@@ -431,14 +431,15 @@ deps' <- packageDepsWithTools package deps <- forM (Map.toList deps') $ \(depname, range) -> do eres <- addDep treatAsDep depname- let mlatest = Map.lookup depname $ latestVersions ctx+ let mlatestApplicable =+ (latestApplicableVersion range <=< Map.lookup depname) (ctxVersions ctx) case eres of Left e -> let bd = case e of UnknownPackage name -> assert (name == depname) NotInBuildPlan _ -> Couldn'tResolveItsDependencies- in return $ Left (depname, (range, mlatest, bd))+ in return $ Left (depname, (range, mlatestApplicable, bd)) Right adr -> do inRange <- if adrVersion adr `withinRange` range then return True@@ -477,7 +478,7 @@ (Set.empty, Map.empty, loc) ADRFound loc (Library ident gid) -> return $ Right (Set.empty, Map.singleton ident gid, loc)- else return $ Left (depname, (range, mlatest, DependencyMismatch $ adrVersion adr))+ else return $ Left (depname, (range, mlatestApplicable, DependencyMismatch $ adrVersion adr)) case partitionEithers deps of ([], pairs) -> return $ Right $ mconcat pairs (errs, _) -> return $ Left $ DependencyPlanFailures@@ -536,8 +537,8 @@ describeConfigDiff :: Config -> ConfigCache -> ConfigCache -> Maybe Text describeConfigDiff config old new- | configCacheDeps old /= configCacheDeps new = Just "dependencies changed"- | not $ Set.null $ Set.filter isLibExe newComponents =+ | not (configCacheDeps new `Set.isSubsetOf` configCacheDeps old) = Just "dependencies changed"+ | not $ Set.null newComponents = Just $ "components added: " `T.append` T.intercalate ", " (map (decodeUtf8With lenientDecode) (Set.toList newComponents)) | not (configCacheHaddock old) && configCacheHaddock new = Just "rebuilding with haddocks"@@ -549,11 +550,6 @@ ] | otherwise = Nothing where- isLibExe t = not $ any (`S8.isPrefixOf` t)- [ "test:"- , "bench:"- ]- -- options set by stack isStackOpt t = any (`T.isPrefixOf` t) [ "--dependency="@@ -561,8 +557,16 @@ , "--package-db=" , "--libdir=" , "--bindir="+ , "--datadir="+ , "--libexecdir="+ , "--sysconfdir"+ , "--docdir="+ , "--htmldir="+ , "--haddockdir=" , "--enable-tests" , "--enable-benchmarks"+ ] || elem t+ [ "--user" ] stripGhcOptions =
src/Stack/Build/Execute.hs view
@@ -56,9 +56,9 @@ import Data.Time.Clock (getCurrentTime) import Data.Traversable (forM) import Data.Word8 (_colon)+import qualified Distribution.PackageDescription as C import Distribution.System (OS (Windows), Platform (Platform))-import qualified Distribution.Text import Language.Haskell.TH as TH (location) import Network.HTTP.Client.Conduit (HasHttpManager) import Path@@ -92,7 +92,7 @@ import System.Process.Internals (createProcess_) #endif -type M env m = (MonadIO m,MonadReader env m,HasHttpManager env,HasBuildConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,MonadMask m,HasLogLevel env,HasEnvConfig env,HasTerminal env)+type M env m = (MonadIO m,MonadReader env m,HasHttpManager env,HasBuildConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,MonadMask m,HasLogLevel env,HasEnvConfig env,HasTerminal env, HasConfig env) -- | Fetch the packages necessary for a build, for example in combination with a dry run. preFetch :: M env m => Plan -> m ()@@ -222,13 +222,12 @@ getSetupExe setupHs tmpdir = do wc <- getWhichCompiler econfig <- asks getEnvConfig+ platformDir <- platformVariantRelDir let config = getConfig econfig baseNameS = concat [ "setup-Simple-Cabal-" , versionString $ envConfigCabalVersion econfig , "-"- , Distribution.Text.display $ configPlatform config- , "-" , compilerVersionString $ envConfigCompilerVersion econfig ] exeNameS = baseNameS ++@@ -243,7 +242,8 @@ baseNameS ++ ".jsexe" setupDir = configStackRoot config </>- $(mkRelDir "setup-exe-cache")+ $(mkRelDir "setup-exe-cache") </>+ platformDir exePath <- fmap (setupDir </>) $ parseRelFile exeNameS jsExePath <- fmap (setupDir </>) $ parseRelDir jsExeNameS@@ -273,7 +273,7 @@ , toFilePath tmpOutputPath ] ++ ["-build-runner" | wc == Ghcjs]- runIn tmpdir (compilerExeName wc) menv args Nothing+ runCmd' (\cp -> cp { std_out = UseHandle stderr }) (Cmd (Just tmpdir) (compilerExeName wc) menv args) Nothing when (wc == Ghcjs) $ renameDir tmpJsExePath jsExePath renameFile tmpExePath exePath return $ Just exePath@@ -413,7 +413,7 @@ } forM_ (boptsExec bopts) $ \(cmd, args) -> do $logProcessRun cmd args- callProcess Nothing menv' cmd args+ callProcess (Cmd Nothing cmd menv' args) -- | Windows can't write over the current executable. Instead, we rename the -- current executable to something else and then do the copy.@@ -557,8 +557,7 @@ unless (Set.null tests) $ do singleTest runInBase topts (Set.toList tests) ac ee task installedMap unless (Set.null benches) $ do- -- FIXME: shouldn't this use the list of benchmarks to run?- singleBench runInBase beopts ac ee task installedMap+ singleBench runInBase beopts (Set.toList benches) ac ee task installedMap } ] where@@ -633,7 +632,7 @@ mOldCabalMod <- tryGetCabalMod pkgDir - return $ mOldConfigCache /= Just newConfigCache+ return $ fmap configCacheOpts mOldConfigCache /= Just (configCacheOpts newConfigCache) || mOldCabalMod /= Just newCabalMod let ConfigureOpts dirs nodirs = configCacheOpts newConfigCache when needConfig $ withMVar eeConfigureLock $ \_ -> do@@ -822,19 +821,22 @@ case ec of ExitSuccess -> return () _ -> do- bs <- liftIO $+ bss <- case mlogFile of- Nothing -> return ""+ Nothing -> return [] Just (logFile, h) -> do- hClose h- S.readFile $ toFilePath logFile+ liftIO $ hClose h+ runResourceT+ $ CB.sourceFile (toFilePath logFile)+ $$ mungeBuildOutput stripTHLoading makeAbsolute pkgDir+ =$ CL.consume throwM $ CabalExitedUnsuccessfully ec taskProvides exeName fullArgs (fmap fst mlogFile)- bs+ bss where cp0 = proc (toFilePath exeName) fullArgs cp = cp0@@ -1019,14 +1021,14 @@ bindir = toFilePath $ bcoSnapInstallRoot eeBaseConfigOpts </> bindirSuffix realConfigAndBuild cache allDepsMap = withSingleContext runInBase ac ee task (Just allDepsMap) Nothing- $ \package cabalfp pkgDir cabal announce console _mlogFile -> do+ $ \package cabalfp pkgDir cabal announce _console _mlogFile -> do _neededConfig <- ensureConfig cache pkgDir ee (announce ("configure" <> annSuffix)) cabal cabalfp if boptsOnlyConfigure eeBuildOpts then return Nothing- else liftM Just $ realBuild cache package pkgDir cabal announce console+ else liftM Just $ realBuild cache package pkgDir cabal announce - realBuild cache package pkgDir cabal announce console = do+ realBuild cache package pkgDir cabal announce = do wc <- getWhichCompiler markExeNotInstalled (taskLocation task) taskProvides@@ -1040,7 +1042,7 @@ config <- asks getConfig extraOpts <- extraBuildOptions eeBuildOpts preBuildTime <- modTime <$> liftIO getCurrentTime- cabal (console && configHideTHLoading config) $ ("build" :) $ (++ extraOpts) $+ cabal (configHideTHLoading config) $ ("build" :) $ (++ extraOpts) $ case (taskType, taskAllInOne, isFinalBuild) of (_, True, True) -> fail "Invariant violated: cannot have an all-in-one build that also has a final build step." (TTLocal lp, False, False) -> primaryComponentOptions lp@@ -1166,22 +1168,23 @@ else return True when toRun $ do- bconfig <- asks getBuildConfig buildDir <- distDirFromDir pkgDir hpcDir <- hpcDirFromDir pkgDir when needHpc (createTree hpcDir)- let exeExtension =- case configPlatform $ getConfig bconfig of- Platform _ Windows -> ".exe"- _ -> "" - errs <- liftM Map.unions $ forM testsToRun $ \testName -> do- nameDir <- parseRelDir $ T.unpack testName- nameExe <- parseRelFile $ T.unpack testName ++ exeExtension- nameTix <- liftM (pkgDir </>) $ parseRelFile $ T.unpack testName ++ ".tix"- let exeName = buildDir </> $(mkRelDir "build") </> nameDir </> nameExe- exists <- fileExists exeName- menv <- liftIO $ configEnvOverride config EnvSettings+ errs <- liftM Map.unions $ forM (Map.toList (packageTests package)) $ \(testName, suiteInterface) -> do+ let stestName = T.unpack testName+ (testName', isTestTypeLib) <-+ case suiteInterface of+ C.TestSuiteLibV09{} -> return (stestName ++ "Stub", True)+ C.TestSuiteExeV10{} -> return (stestName, False)+ interface -> throwM (TestSuiteTypeUnsupported interface)++ exeName <- testExeName testName'+ tixPath <- liftM (pkgDir </>) $ parseRelFile $ exeName ++ ".tix"+ exePath <- liftM (buildDir </>) $ parseRelFile $ "build/" ++ testName' ++ "/" ++ exeName+ exists <- fileExists exePath+ menv <- liftIO $ configEnvOverride config EnvSettings { esIncludeLocals = taskLocation task == Local , esIncludeGhcPackagePath = True , esStackExe = True@@ -1191,17 +1194,17 @@ then do -- We clear out the .tix files before doing a run. when needHpc $ do- tixexists <- fileExists nameTix+ tixexists <- fileExists tixPath when tixexists $- $logWarn ("Removing HPC file " <> T.pack (toFilePath nameTix))- removeFileIfExists nameTix+ $logWarn ("Removing HPC file " <> T.pack (toFilePath tixPath))+ removeFileIfExists tixPath let args = toAdditionalArgs topts argsDisplay = case args of [] -> "" _ -> ", args: " <> T.intercalate " " (map showProcessArgDebug args) announce $ "test (suite: " <> testName <> argsDisplay <> ")"- let cp = (proc (toFilePath exeName) args)+ let cp = (proc (toFilePath exePath) args) { cwd = Just $ toFilePath pkgDir , Process.env = envHelper menv , std_in = CreatePipe@@ -1217,13 +1220,17 @@ -- Use createProcess_ to avoid the log file being closed afterwards (Just inH, Nothing, Nothing, ph) <- liftIO $ createProcess_ "singleBuild.runTests" cp+ when isTestTypeLib $ do+ logPath <- buildLogPath package (Just stestName)+ createTree (parent logPath)+ liftIO $ hPutStr inH $ show (logPath, testName) liftIO $ hClose inH ec <- liftIO $ waitForProcess ph -- Move the .tix file out of the package -- directory into the hpc work dir, for -- tidiness. when needHpc $- updateTixFile (packageName package) nameTix+ updateTixFile (packageName package) tixPath return $ case ec of ExitSuccess -> Map.empty _ -> Map.singleton testName $ Just ec@@ -1236,7 +1243,13 @@ ] return $ Map.singleton testName Nothing - when needHpc $ generateHpcReport pkgDir package testsToRun+ when needHpc $ do+ let testsToRun' = map f testsToRun+ f tName =+ case Map.lookup tName (packageTests package) of+ Just C.TestSuiteLibV09{} -> tName <> "Stub"+ _ -> tName+ generateHpcReport pkgDir package testsToRun' bs <- liftIO $ case mlogFile of@@ -1254,17 +1267,18 @@ singleBench :: M env m => (m () -> IO ()) -> BenchmarkOpts+ -> [Text] -> ActionContext -> ExecuteEnv -> Task -> InstalledMap -> m ()-singleBench runInBase beopts ac ee task installedMap = do+singleBench runInBase beopts benchesToRun ac ee task installedMap = do -- FIXME: Since this doesn't use cabal, we should be able to avoid using a -- fullblown 'withSingleContext'. (allDepsMap, _cache) <- getConfigCache ee task installedMap False True withSingleContext runInBase ac ee task (Just allDepsMap) (Just "bench") $ \_package _cabalfp _pkgDir cabal announce _console _mlogFile -> do- let args = maybe []+ let args = map T.unpack benchesToRun <> maybe [] ((:[]) . ("--benchmark-options=" <>)) (beoAdditionalArgs beopts) @@ -1280,21 +1294,32 @@ announce "benchmarks" cabal False ("bench" : args) --- | Grab all output from the given @Handle@ and print it to stdout, stripping--- Template Haskell "Loading package" lines. Does work in a separate thread.+-- | Grab all output from the given @Handle@ and log it, stripping+-- Template Haskell "Loading package" lines and making paths absolute.+-- thread. printBuildOutput :: (MonadIO m, MonadBaseControl IO m, MonadLogger m) => Bool -- ^ exclude TH loading? -> Bool -- ^ convert paths to absolute? -> Path Abs Dir -- ^ package's root directory -> LogLevel- -> Handle -> m ()+ -> Handle+ -> m () printBuildOutput excludeTHLoading makeAbsolute pkgDir level outH = void $ CB.sourceHandle outH- $$ CB.lines+ $$ mungeBuildOutput excludeTHLoading makeAbsolute pkgDir+ =$ CL.mapM_ (monadLoggerLog $(TH.location >>= liftLoc) "" level)++-- | Strip Template Haskell "Loading package" lines and making paths absolute.+mungeBuildOutput :: MonadIO m+ => Bool -- ^ exclude TH loading?+ -> Bool -- ^ convert paths to absolute?+ -> Path Abs Dir -- ^ package's root directory+ -> ConduitM ByteString ByteString m ()+mungeBuildOutput excludeTHLoading makeAbsolute pkgDir = void $+ CB.lines =$ CL.map stripCarriageReturn =$ CL.filter (not . isTHLoading) =$ CL.mapM toAbsolutePath- =$ CL.mapM_ (monadLoggerLog $(TH.location >>= liftLoc) "" level) where -- | Is this line a Template Haskell "Loading package" line -- ByteString
src/Stack/Build/Source.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PackageImports #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -15,9 +16,9 @@ , loadLocalPackage , parseTargetsFromBuildOpts , addUnlistedToBuildCache+ , getPackageConfig ) where - import Control.Applicative import Control.Arrow ((&&&)) import Control.Exception (assert, catch)@@ -27,7 +28,7 @@ import Control.Monad.Logger import Control.Monad.Reader (MonadReader, asks) import Control.Monad.Trans.Resource-import Crypto.Hash (Digest, SHA256)+import "cryptohash" Crypto.Hash (Digest, SHA256) import Crypto.Hash.Conduit (sinkHash) import qualified Data.ByteString as S import Data.Byteable (toBytes)@@ -286,17 +287,9 @@ -> (PackageName, (LocalPackageView, GenericPackageDescription)) -> m LocalPackage loadLocalPackage bopts targets (name, (lpv, gpkg)) = do- bconfig <- asks getBuildConfig- econfig <- asks getEnvConfig+ config <- getPackageConfig bopts name - let config = PackageConfig- { packageConfigEnableTests = False- , packageConfigEnableBenchmarks = False- , packageConfigFlags = localFlags (boptsFlags bopts) bconfig name- , packageConfigCompilerVersion = envConfigCompilerVersion econfig- , packageConfigPlatform = configPlatform $ getConfig bconfig- }- pkg = resolvePackage config gpkg+ let pkg = resolvePackage config gpkg mtarget = Map.lookup name targets (exes, tests, benches) =@@ -305,7 +298,7 @@ Just STLocalAll -> ( packageExes pkg , if boptsTests bopts- then packageTests pkg+ then Map.keysSet (packageTests pkg) else Set.empty , if boptsBenchmarks bopts then packageBenchmarks pkg@@ -374,7 +367,7 @@ -- present, then they must not be buildable. , lpUnbuildable = toComponents (exes `Set.difference` packageExes pkg)- (tests `Set.difference` packageTests pkg)+ (tests `Set.difference` Map.keysSet (packageTests pkg)) (benches `Set.difference` packageBenchmarks pkg) } @@ -571,3 +564,19 @@ | lp <- lps , c <- Set.toList (lpUnbuildable lp) ]++-- | Get 'PackageConfig' for package given its name.+getPackageConfig :: (MonadIO m, MonadThrow m, MonadCatch m, MonadLogger m, MonadReader env m, HasEnvConfig env)+ => BuildOpts+ -> PackageName+ -> m PackageConfig+getPackageConfig bopts name = do+ econfig <- asks getEnvConfig+ bconfig <- asks getBuildConfig+ return PackageConfig+ { packageConfigEnableTests = False+ , packageConfigEnableBenchmarks = False+ , packageConfigFlags = localFlags (boptsFlags bopts) bconfig name+ , packageConfigCompilerVersion = envConfigCompilerVersion econfig+ , packageConfigPlatform = configPlatform $ getConfig bconfig+ }
src/Stack/Config.hs view
@@ -67,6 +67,7 @@ import Safe (headMay) import Stack.BuildPlan import Stack.Config.Docker+import Stack.Config.Nix import Stack.Constants import qualified Stack.Image as Image import Stack.Init@@ -95,10 +96,12 @@ :: (MonadLogger m, MonadIO m, MonadCatch m, MonadReader env m, HasHttpManager env) => Path Abs Dir -- ^ stack root, e.g. ~/.stack -> Path Abs File -- ^ user config file path, e.g. ~/.stack/config.yaml+ -> Maybe AbstractResolver -> Maybe (Project, Path Abs File) -> ConfigMonoid -> m Config-configFromConfigMonoid configStackRoot configUserConfigPath mproject configMonoid@ConfigMonoid{..} = do+configFromConfigMonoid configStackRoot configUserConfigPath mresolver mproject configMonoid@ConfigMonoid{..} = do+ configWorkDir <- parseRelDir (fromMaybe ".stack-work" configMonoidWorkDir) let configConnectionCount = fromMaybe 8 configMonoidConnectionCount configHideTHLoading = fromMaybe True configMonoidHideTHLoading configLatestSnapshotUrl = fromMaybe@@ -143,8 +146,13 @@ configCompilerCheck = fromMaybe MatchMinor configMonoidCompilerCheck - configDocker <- dockerOptsFromMonoid (fmap fst mproject) configStackRoot configMonoidDockerOpts+ configPlatformVariant <- liftIO $+ maybe PlatformVariantNone PlatformVariant <$> lookupEnv platformVariantEnvVar + configDocker <-+ dockerOptsFromMonoid (fmap fst mproject) configStackRoot mresolver configMonoidDockerOpts+ configNix <- nixOptsFromMonoid (fmap fst mproject) configStackRoot configMonoidNixOpts+ rawEnv <- liftIO getEnvironment origEnv <- mkEnvOverride configPlatform $ augmentPathMap (map toFilePath configMonoidExtraPath)@@ -152,7 +160,7 @@ $ map (T.pack *** T.pack) rawEnv let configEnvOverride _ = return origEnv - platformOnlyDir <- runReaderT platformOnlyRelDir configPlatform+ platformOnlyDir <- runReaderT platformOnlyRelDir (configPlatform,configPlatformVariant) configLocalProgramsBase <- case configPlatform of Platform _ Windows -> do@@ -269,8 +277,10 @@ -- ^ Config monoid from parsed command-line arguments -> Maybe (Path Abs File) -- ^ Override stack.yaml+ -> Maybe (AbstractResolver)+ -- ^ Override resolver -> m (LoadConfig m)-loadConfig configArgs mstackYaml = do+loadConfig configArgs mstackYaml mresolver = do stackRoot <- determineStackRoot userConfigPath <- getDefaultUserConfigPath stackRoot extraConfigs0 <- getExtraConfigs userConfigPath >>= mapM loadYaml@@ -282,7 +292,7 @@ extraConfigs0 mproject <- loadProjectConfig mstackYaml let mproject' = (\(project, stackYaml, _) -> (project, stackYaml)) <$> mproject- config <- configFromConfigMonoid stackRoot userConfigPath mproject' $ mconcat $+ config <- configFromConfigMonoid stackRoot userConfigPath mresolver mproject' $ mconcat $ case mproject of Nothing -> configArgs : extraConfigs Just (_, _, projectConfig) -> configArgs : projectConfig : extraConfigs@@ -290,7 +300,7 @@ (throwM (BadStackVersionException (configRequireStackVersion config))) return LoadConfig { lcConfig = config- , lcLoadBuildConfig = loadBuildConfig mproject config+ , lcLoadBuildConfig = loadBuildConfig mproject config mresolver , lcProjectRoot = fmap (\(_, fp, _) -> parent fp) mproject } @@ -408,7 +418,7 @@ -- necessary. resolvePackageEntry :: (MonadIO m, MonadThrow m, MonadReader env m, HasHttpManager env, MonadLogger m, MonadCatch m- ,MonadBaseControl IO m)+ ,MonadBaseControl IO m, HasConfig env) => EnvOverride -> Path Abs Dir -- ^ project root -> PackageEntry@@ -428,16 +438,25 @@ -- necessary. resolvePackageLocation :: (MonadIO m, MonadThrow m, MonadReader env m, HasHttpManager env, MonadLogger m, MonadCatch m- ,MonadBaseControl IO m)+ ,MonadBaseControl IO m, HasConfig env) => EnvOverride -> Path Abs Dir -- ^ project root -> PackageLocation -> m (Path Abs Dir) resolvePackageLocation _ projRoot (PLFilePath fp) = resolveDir projRoot fp-resolvePackageLocation _ projRoot (PLHttpTarball url) = do- let name = T.unpack $ decodeUtf8 $ B16.encode $ SHA256.hash $ encodeUtf8 url- root = projRoot </> workDirRel </> $(mkRelDir "downloaded")- fileRel <- parseRelFile $ name ++ ".tar.gz"+resolvePackageLocation menv projRoot (PLRemote url remotePackageType) = do+ workDir <- getWorkDir+ let nameBeforeHashing = case remotePackageType of+ RPTHttpTarball -> url+ RPTGit commit -> T.unwords [url, commit]+ RPTHg commit -> T.unwords [url, commit, "hg"]+ name = T.unpack $ decodeUtf8 $ B16.encode $ SHA256.hash $ encodeUtf8 nameBeforeHashing+ root = projRoot </> workDir </> $(mkRelDir "downloaded")+ fileExtension = case remotePackageType of+ RPTHttpTarball -> ".tar.gz"+ _ -> ".unused"++ fileRel <- parseRelFile $ name ++ fileExtension dirRel <- parseRelDir name dirRelTmp <- parseRelDir $ name ++ ".tmp" let file = root </> fileRel@@ -446,51 +465,46 @@ exists <- dirExists dir unless exists $ do- req <- parseUrl $ T.unpack url- _ <- download req file- removeTreeIfExists dirTmp- liftIO $ withBinaryFile (toFilePath file) ReadMode $ \h -> do- lbs <- L.hGetContents h- let entries = Tar.read $ GZip.decompress lbs- Tar.unpack (toFilePath dirTmp) entries- renameDir dirTmp dir - x <- listDirectory dir- case x of- ([dir'], []) -> return dir'- (dirs, files) -> do- removeFileIfExists file- removeTreeIfExists dir- throwM $ UnexpectedTarballContents dirs files+ let cloneAndExtract commandName resetCommand commit = do+ createTree (parent dirTmp)+ readInNull (parent dirTmp) commandName menv+ [ "clone"+ , T.unpack url+ , toFilePathNoTrailingSep dirTmp+ ]+ Nothing+ readInNull dirTmp commandName menv+ (resetCommand ++ [T.unpack commit])+ Nothing -resolvePackageLocation menv projRoot (PLGit url commit) = do- let name = T.unpack $ decodeUtf8 $ B16.encode $ SHA256.hash $ encodeUtf8 $ T.unwords [url, commit]- root = projRoot </> workDirRel </> $(mkRelDir "downloaded")- dirRel <- parseRelDir $ name ++ ".git"- dirRelTmp <- parseRelDir $ name ++ ".git.tmp"- let dir = root </> dirRel- dirTmp = root </> dirRelTmp+ case remotePackageType of+ RPTHttpTarball -> do+ req <- parseUrl $ T.unpack url+ _ <- download req file - exists <- dirExists dir- unless exists $ do- removeTreeIfExists dirTmp- createTree (parent dirTmp)- readInNull (parent dirTmp) "git" menv- [ "clone"- , T.unpack url- , toFilePathNoTrailingSep dirTmp- ]- Nothing- readInNull dirTmp "git" menv- [ "reset"- , "--hard"- , T.unpack commit- ]- Nothing+ liftIO $ withBinaryFile (toFilePath file) ReadMode $ \h -> do+ lbs <- L.hGetContents h+ let entries = Tar.read $ GZip.decompress lbs+ Tar.unpack (toFilePath dirTmp) entries++ RPTGit commit -> cloneAndExtract "git" ["reset", "--hard"] commit+ RPTHg commit -> cloneAndExtract "hg" ["update", "-C"] commit+ renameDir dirTmp dir - return dir+ case remotePackageType of+ RPTHttpTarball -> do+ x <- listDirectory dir+ case x of+ ([dir'], []) -> return dir'+ (dirs, files) -> do+ removeFileIfExists file+ removeTreeIfExists dir+ throwM $ UnexpectedTarballContents dirs files++ _ -> return dir -- | Get the stack root, e.g. ~/.stack determineStackRoot :: (MonadIO m, MonadThrow m) => m (Path Abs Dir)
src/Stack/Config/Docker.hs view
@@ -17,22 +17,36 @@ -- | Interprets DockerOptsMonoid options. dockerOptsFromMonoid :: MonadThrow m- => Maybe Project -> Path Abs Dir -> DockerOptsMonoid -> m DockerOpts-dockerOptsFromMonoid mproject stackRoot DockerOptsMonoid{..} = do+ => Maybe Project+ -> Path Abs Dir+ -> Maybe AbstractResolver+ -> DockerOptsMonoid+ -> m DockerOpts+dockerOptsFromMonoid mproject stackRoot maresolver DockerOptsMonoid{..} = do let dockerEnable = fromMaybe dockerMonoidDefaultEnable dockerMonoidEnable dockerImage =- let defaultTag =- case mproject of+ let mresolver =+ case maresolver of+ Just (ARResolver resolver) ->+ Just resolver+ Just aresolver ->+ throw+ (ResolverNotSupportedException $+ show aresolver)+ Nothing ->+ fmap projectResolver mproject+ defaultTag =+ case mresolver of Nothing -> ""- Just proj ->- case projectResolver proj of+ Just resolver ->+ case resolver of ResolverSnapshot n@(LTS _ _) -> ":" ++ T.unpack (renderSnapName n) _ ->- throwM+ throw (ResolverNotSupportedException $- show $ projectResolver proj)+ show resolver) in case dockerMonoidRepoOrImage of Nothing -> "fpco/stack-build" ++ defaultTag Just (DockerMonoidImage image) -> image
+ src/Stack/Config/Nix.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE RecordWildCards, DeriveDataTypeable #-}++-- | Nix configuration+module Stack.Config.Nix+ (nixOptsFromMonoid+ ,StackNixException(..)+ ) where++import Data.Text (pack)+import Data.Maybe+import Data.Typeable+import Path+import Stack.Types+import Control.Exception.Lifted+import Control.Monad.Catch (throwM,MonadCatch)+++-- | Interprets NixOptsMonoid options.+nixOptsFromMonoid :: (Monad m, MonadCatch m) => Maybe Project -> Path Abs Dir -> NixOptsMonoid -> m NixOpts+nixOptsFromMonoid mproject _stackRoot NixOptsMonoid{..} = do+ let nixEnable = fromMaybe nixMonoidDefaultEnable nixMonoidEnable+ nixPackages = case mproject of+ Nothing -> nixMonoidPackages+ Just p -> nixMonoidPackages ++ [case projectResolver p of+ ResolverSnapshot (LTS x y) ->+ pack ("haskell.packages.lts-" ++ show x ++ "_" ++ show y ++ ".ghc")+ _ -> pack "ghc"]+ nixInitFile = nixMonoidInitFile+ nixShellOptions = nixMonoidShellOptions+ if not (null nixMonoidPackages) && isJust nixInitFile then+ throwM NixCannotUseShellFileAndPackagesException+ else return ()+ return NixOpts{..}++-- Exceptions thown specifically by Stack.Nix+data StackNixException+ = NixCannotUseShellFileAndPackagesException+ -- ^ Nix can't be given packages and a shell file at the same time+ deriving (Typeable)++instance Exception StackNixException++instance Show StackNixException where+ show NixCannotUseShellFileAndPackagesException =+ "You cannot have packages and a shell-file filled at the same time in your nix-shell configuration."
src/Stack/Constants.hs view
@@ -25,6 +25,7 @@ ,testBuiltFile ,benchBuiltFile ,stackProgName+ ,stackProgNameUpper ,wiredInPackages ,ghcjsBootPackages ,cabalPackageName@@ -38,11 +39,13 @@ ,defaultUserConfigPath ,defaultGlobalConfigPathDeprecated ,defaultGlobalConfigPath+ ,platformVariantEnvVar ) where import Control.Monad.Catch (MonadThrow) import Control.Monad.Reader+import Data.Char (toUpper) import Data.HashSet (HashSet) import qualified Data.HashSet as HashSet import Data.Text (Text)@@ -119,8 +122,11 @@ userDocsDir config = configStackRoot config </> $(mkRelDir "doc/") -- | Output .o/.hi directory.-objectInterfaceDir :: BuildConfig -> Path Abs Dir-objectInterfaceDir bconfig = bcWorkDir bconfig </> $(mkRelDir "odir/")+objectInterfaceDir :: (MonadReader env m, HasConfig env)+ => BuildConfig -> m (Path Abs Dir)+objectInterfaceDir bconfig = do+ bcwd <- bcWorkDir bconfig+ return (bcwd </> $(mkRelDir "odir/")) -- | The filename used for dirtiness check of source files. buildCacheFile :: (MonadThrow m, MonadReader env m, HasPlatform env,HasEnvConfig env)@@ -215,8 +221,9 @@ packageIdentifierString $ PackageIdentifier cabalPackageName cabalPkgVer platformAndCabal <- useShaPathOnWindows (platform </> envDir)+ workDir <- getWorkDir return $- workDirRel </>+ workDir </> $(mkRelDir "dist") </> platformAndCabal @@ -252,13 +259,25 @@ -- haddockExtension = "haddock" -- | Docker sandbox from project root.-projectDockerSandboxDir :: Path Abs Dir -> Path Abs Dir-projectDockerSandboxDir projectRoot = projectRoot </> workDirRel </> $(mkRelDir "docker/")+projectDockerSandboxDir :: (MonadReader env m, HasConfig env)+ => Path Abs Dir -- ^ Project root+ -> m (Path Abs Dir) -- ^ Docker sandbox+projectDockerSandboxDir projectRoot = do+ workDir <- getWorkDir+ return $ projectRoot </> workDir </> $(mkRelDir "docker/") -- | Image staging dir from project root.-imageStagingDir :: Path Abs Dir -> Path Abs Dir-imageStagingDir p = p </> workDirRel </> $(mkRelDir "image/")+imageStagingDir :: (MonadReader env m, HasConfig env)+ => Path Abs Dir -- ^ Project root+ -> m (Path Abs Dir) -- ^ Docker sandbox+imageStagingDir projectRoot = do+ workDir <- getWorkDir+ return $ projectRoot </> workDir </> $(mkRelDir "image/") +-- | Name of the 'stack' program, uppercased+stackProgNameUpper :: String+stackProgNameUpper = map toUpper stackProgName+ -- | Name of the 'stack' program. stackProgName :: String stackProgName = "stack"@@ -380,3 +399,8 @@ buildPlanDir :: Path Abs Dir -- ^ Stack root -> Path Abs Dir buildPlanDir = (</> $(mkRelDir "build-plan"))++-- | Environment variable that stores a variant to append to platform-specific directory+-- names. Used to ensure incompatible binaries aren't shared between Docker builds and host+platformVariantEnvVar :: String+platformVariantEnvVar = stackProgNameUpper ++ "_PLATFORM_VARIANT"
src/Stack/Coverage.hs view
@@ -8,6 +8,7 @@ module Stack.Coverage ( deleteHpcReports , updateTixFile+ , testExeName , generateHpcReport , HpcReportOpts(..) , generateHpcReportForTargets@@ -27,6 +28,7 @@ import Data.Foldable (forM_, asum, toList) import Data.Function import Data.List+import Data.List.Extra (stripSuffix) import qualified Data.Map.Strict as Map import Data.Maybe import Data.Maybe.Extra (mapMaybeM)@@ -37,6 +39,7 @@ import qualified Data.Text.IO as T import qualified Data.Text.Lazy as LT import Data.Traversable (forM)+import Distribution.System (OS (Windows), Platform (Platform)) import Network.HTTP.Download (HasHttpManager) import Path import Path.Extra (toFilePathNoTrailingSep)@@ -48,7 +51,7 @@ import Stack.Package import Stack.Types import qualified System.Directory as D-import System.FilePath (dropExtension, isPathSeparator)+import System.FilePath (isPathSeparator) import System.Process.Read import Text.Hastache (htmlEscape) import Trace.Hpc.Tix@@ -65,20 +68,32 @@ updateTixFile :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env) => PackageName -> Path Abs File -> m () updateTixFile pkgName tixSrc = do- exists <- fileExists tixSrc- when exists $ do- tixDest <- tixFilePath pkgName (dropExtension (toFilePath (filename tixSrc)))- removeFileIfExists tixDest- createTree (parent tixDest)- -- Remove exe modules because they are problematic. This could be revisited if there's a GHC- -- version that fixes https://ghc.haskell.org/trac/ghc/ticket/1853- mtix <- readTixOrLog tixSrc- case mtix of- Nothing -> $logError $ "Failed to read " <> T.pack (toFilePath tixSrc)- Just tix -> do- liftIO $ writeTix (toFilePath tixDest) (removeExeModules tix)- removeFileIfExists tixSrc+ case stripSuffix ".tix" (toFilePath (filename tixSrc)) of+ Nothing -> error "Invariant violated: updateTixFile expected a tix filepath."+ Just testName -> do+ exists <- fileExists tixSrc+ when exists $ do+ tixDest <- tixFilePath pkgName testName+ removeFileIfExists tixDest+ createTree (parent tixDest)+ -- Remove exe modules because they are problematic. This could be revisited if there's a GHC+ -- version that fixes https://ghc.haskell.org/trac/ghc/ticket/1853+ mtix <- readTixOrLog tixSrc+ case mtix of+ Nothing -> $logError $ "Failed to read " <> T.pack (toFilePath tixSrc)+ Just tix -> do+ liftIO $ writeTix (toFilePath tixDest) (removeExeModules tix)+ removeFileIfExists tixSrc +testExeName :: (MonadReader env m,HasConfig env) => String -> m String+testExeName testName = do+ config <- asks getConfig+ let exeExtension =+ case configPlatform config of+ Platform _ Windows -> ".exe"+ _ -> ""+ return $ testName ++ exeExtension+ -- | Get the directory used for hpc reports for the given pkgId. hpcPkgPath :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env) => PackageName -> m (Path Abs Dir)@@ -91,9 +106,10 @@ -- identifier string. tixFilePath :: (MonadIO m,MonadReader env m,HasConfig env,MonadLogger m,MonadBaseControl IO m,MonadCatch m,HasEnvConfig env) => PackageName -> String -> m (Path Abs File)-tixFilePath pkgName tixName = do+tixFilePath pkgName testName = do pkgPath <- hpcPkgPath pkgName- tixRel <- parseRelFile (tixName ++ "/" ++ tixName ++ ".tix")+ exeName <- testExeName testName+ tixRel <- parseRelFile (testName ++ "/" ++ exeName ++ ".tix") return (pkgPath </> tixRel) -- | Generates the HTML coverage report and shows a textual coverage summary for a package.@@ -396,5 +412,9 @@ distDir <- distDirFromDir pkgDir path <- liftM (distDir </>) $ parseRelFile ("package.conf.inplace/" ++ packageIdentifierString pkgId ++ "-inplace.conf")- contents <- liftIO $ T.readFile (toFilePath path)- return $ asum (map (T.stripPrefix "key: ") (T.lines contents))+ exists <- fileExists path+ if exists+ then do+ contents <- liftIO $ T.readFile (toFilePath path)+ return $ asum (map (T.stripPrefix "key: ") (T.lines contents))+ else return Nothing
src/Stack/Docker.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP, ConstraintKinds, DeriveDataTypeable, FlexibleContexts, MultiWayIf, NamedFieldPuns,- OverloadedStrings, RankNTypes, RecordWildCards, ScopedTypeVariables, TemplateHaskell,- TupleSections #-}+ OverloadedStrings, PackageImports, RankNTypes, RecordWildCards, ScopedTypeVariables,+ TemplateHaskell, TupleSections #-} -- | Run commands in Docker containers module Stack.Docker@@ -16,6 +16,7 @@ ,reexecWithOptionalContainer ,reset ,reExecArgName+ ,StackDockerException(..) ) where import Control.Applicative@@ -28,6 +29,7 @@ import Control.Monad.Reader (MonadReader,asks,runReaderT) import Control.Monad.Writer (execWriter,runWriter,tell) import Control.Monad.Trans.Control (MonadBaseControl)+import qualified "cryptohash" Crypto.Hash as Hash import Data.Aeson.Extended (FromJSON(..),(.:),(.:?),(.!=),eitherDecode) import Data.ByteString.Builder (stringUtf8,charUtf8,toLazyByteString) import qualified Data.ByteString.Char8 as BS@@ -56,7 +58,7 @@ import Path.IO import qualified Paths_stack as Meta import Prelude -- Fix redundant import warnings-import Stack.Constants (projectDockerSandboxDir,stackProgName,stackRootEnvVar,buildPlanDir)+import Stack.Constants import Stack.Docker.GlobalDB import Stack.Types import Stack.Types.Internal@@ -77,6 +79,7 @@ import Text.Printf (printf) #ifndef WINDOWS+import Control.Concurrent (threadDelay) import Control.Monad.Trans.Control (liftBaseWith) import System.Posix.Signals #endif@@ -232,11 +235,11 @@ -- | Run a command in a new Docker container, then exit the process. runContainerAndExit :: M env m- => GetCmdArgs env m- -> Maybe (Path Abs Dir)- -> m ()- -> m ()- -> m ()+ => GetCmdArgs env m+ -> Maybe (Path Abs Dir) -- ^ Project root (maybe)+ -> m () -- ^ Action to run before+ -> m () -- ^ Action to run after+ -> m () runContainerAndExit getCmdArgs mprojectRoot before@@ -270,39 +273,31 @@ Just ii2 -> return ii2 Nothing -> throwM (InspectFailedException image) | otherwise -> throwM (NotPulledException image)+ sandboxDir <- projectDockerSandboxDir projectRoot let ImageConfig {..} = iiConfig imageEnvVars = map (break (== '=')) icEnv- msandboxID = lookupImageEnv sandboxIDEnvVar imageEnvVars- sandboxID = fromMaybe "default" msandboxID- sandboxIDDir <- parseRelDir (sandboxID ++ "/")- let stackRoot = configStackRoot config- sandboxDir = projectDockerSandboxDir projectRoot- sandboxSandboxDir = sandboxDir </> $(mkRelDir "_sandbox/") </> sandboxIDDir+ platformVariant = BS.unpack $ Hash.digestToHexByteString $ hashRepoName image+ stackRoot = configStackRoot config sandboxHomeDir = sandboxDir </> homeDirName- sandboxRepoDir = sandboxDir </> sandboxIDDir- sandboxSubdirs = map (\d -> sandboxRepoDir </> d)- sandboxedHomeSubdirectories isTerm = not (dockerDetach docker) && isStdinTerminal && isStdoutTerminal && isStderrTerminal keepStdinOpen = not (dockerDetach docker) && -- Workaround for https://github.com/docker/docker/issues/12319+ -- This is fixed in Docker 1.9.1, but will leave the workaround+ -- in place for now, for users who haven't upgraded yet. (isTerm || (isNothing bamboo && isNothing jenkins)) newPathEnv = intercalate [Posix.searchPathSeparator] $ nubOrd $- [toFilePathNoTrailingSep $ sandboxRepoDir </> $(mkRelDir ".local/bin")- ,toFilePathNoTrailingSep $ sandboxRepoDir </> $(mkRelDir ".cabal/bin")- ,toFilePathNoTrailingSep $ sandboxRepoDir </> $(mkRelDir "bin")- ,hostBinDir] +++ [hostBinDir+ ,toFilePathNoTrailingSep $ sandboxHomeDir </> $(mkRelDir ".local/bin")] ++ maybe [] Posix.splitSearchPath (lookupImageEnv "PATH" imageEnvVars) (cmnd,args,envVars,extraMount) <- getCmdArgs docker envOverride imageInfo isRemoteDocker pwd <- getWorkingDir liftIO (do updateDockerImageLastUsed config iiId (toFilePath projectRoot)- mapM_ createTree- ([sandboxHomeDir, sandboxSandboxDir, stackRoot] ++- sandboxSubdirs))+ mapM_ createTree ([sandboxHomeDir, stackRoot])) containerID <- (trim . decodeUtf8) <$> readDockerProcess envOverride (concat@@ -310,22 +305,19 @@ ,"--net=host" ,"-e",inContainerEnvVar ++ "=1" ,"-e",stackRootEnvVar ++ "=" ++ toFilePathNoTrailingSep stackRoot- ,"-e","HOME=" ++ toFilePathNoTrailingSep sandboxRepoDir+ ,"-e",platformVariantEnvVar ++ "=dk" ++ platformVariant+ ,"-e","HOME=" ++ toFilePathNoTrailingSep sandboxHomeDir ,"-e","PATH=" ++ newPathEnv ,"-v",toFilePathNoTrailingSep stackRoot ++ ":" ++ toFilePathNoTrailingSep stackRoot ,"-v",toFilePathNoTrailingSep projectRoot ++ ":" ++ toFilePathNoTrailingSep projectRoot- ,"-v",toFilePathNoTrailingSep sandboxSandboxDir ++ ":" ++ toFilePathNoTrailingSep sandboxDir- ,"-v",toFilePathNoTrailingSep sandboxHomeDir ++ ":" ++ toFilePathNoTrailingSep sandboxRepoDir- ,"-v",toFilePathNoTrailingSep stackRoot ++ ":" ++- toFilePathNoTrailingSep (sandboxRepoDir </> $(mkRelDir ("." ++ stackProgName ++ "/")))+ ,"-v",toFilePathNoTrailingSep sandboxHomeDir ++ ":" ++ toFilePathNoTrailingSep sandboxHomeDir ,"-w",toFilePathNoTrailingSep pwd] -- Disable the deprecated entrypoint in FP Complete-generated images ,["--entrypoint=/usr/bin/env"- | isJust msandboxID &&+ | isJust (lookupImageEnv oldSandboxIdEnvVar imageEnvVars) && (icEntrypoint == ["/usr/local/sbin/docker-entrypoint"] || icEntrypoint == ["/root/entrypoint.sh"])] ,concatMap (\(k,v) -> ["-e", k ++ "=" ++ v]) envVars- ,concatMap sandboxSubdirArg sandboxSubdirs ,concatMap mountArg (extraMount ++ dockerMount docker) ,concatMap (\nv -> ["-e", nv]) (dockerEnv docker) ,case dockerContainerName docker of@@ -340,39 +332,51 @@ before #ifndef WINDOWS runInBase <- liftBaseWith $ \run -> return (void . run)- oldHandlers <- forM ([sigINT | not keepStdinOpen] ++ [sigTERM]) $ \sig -> do- let sigHandler = do- runInBase (readProcessNull Nothing envOverride "docker"- ["kill","--signal=" ++ show sig,containerID])+ oldHandlers <- forM ([sigINT,sigABRT,sigHUP,sigPIPE,sigTERM,sigUSR1,sigUSR2]) $ \sig -> do+ let sigHandler = runInBase $ do+ readProcessNull Nothing envOverride "docker"+ ["kill","--signal=" ++ show sig,containerID]+ when (sig `elem` [sigTERM,sigABRT]) $ do+ -- Give the container 30 seconds to exit gracefully, then send a sigKILL to force it+ liftIO $ threadDelay 30000000+ readProcessNull Nothing envOverride "docker" ["kill",containerID] oldHandler <- liftIO $ installHandler sig (Catch sigHandler) Nothing return (sig, oldHandler) #endif- e <- try (callProcess'- (if keepStdinOpen then id else (\cp -> cp { delegate_ctlc = False }))- Nothing- envOverride+ let cmd = Cmd Nothing "docker"+ envOverride (concat [["start"] ,["-a" | not (dockerDetach docker)] ,["-i" | keepStdinOpen]- ,[containerID]]))+ ,[containerID]])+ e <- finally+ (try $ callProcess'+ (\cp -> cp { delegate_ctlc = False })+ cmd)+ (do unless (dockerPersist docker || dockerDetach docker) $+ catch+ (readProcessNull Nothing envOverride "docker" ["rm","-f",containerID])+ (\(_::ReadProcessException) -> return ()) #ifndef WINDOWS- forM_ oldHandlers $ \(sig,oldHandler) ->- liftIO $ installHandler sig oldHandler Nothing+ forM_ oldHandlers $ \(sig,oldHandler) ->+ liftIO $ installHandler sig oldHandler Nothing #endif- unless (dockerPersist docker || dockerDetach docker)- (readProcessNull Nothing envOverride "docker" ["rm","-f",containerID])+ ) case e of Left (ProcessExitedUnsuccessfully _ ec) -> liftIO (exitWith ec) Right () -> do after liftIO exitSuccess where+ -- This is using a hash of the Docker repository (without tag or digest) to ensure+ -- binaries/libraries aren't shared between Docker and host (or incompatible Docker images)+ hashRepoName :: String -> Hash.Digest Hash.MD5+ hashRepoName = Hash.hash . BS.pack . takeWhile (\c -> c /= ':' && c /= '@') lookupImageEnv name vars = case lookup name vars of Just ('=':val) -> Just val _ -> Nothing mountArg (Mount host container) = ["-v",host ++ ":" ++ container]- sandboxSubdirArg subdir = ["-v",toFilePathNoTrailingSep subdir++ ":" ++ toFilePathNoTrailingSep subdir] projectRoot = fromMaybeProjectRoot mprojectRoot -- | Clean-up old docker images and containers.@@ -444,8 +448,8 @@ | otherwise -> throwM (InvalidCleanupCommandException line) e <- try (readDockerProcess envOverride args) case e of- Left (ReadProcessException{}) ->- $logError (concatT ["Could not remove: '",v,"'"])+ Left ex@ReadProcessException{} ->+ $logError (concatT ["Could not remove: '",v,"': ", show ex]) Left e' -> throwM e' Right _ -> return () _ -> throwM (InvalidCleanupCommandException line)@@ -625,8 +629,7 @@ case eitherDecode (LBS.pack (filter isAscii (decodeUtf8 inspectOut))) of Left msg -> throwM (InvalidInspectOutputException msg) Right results -> return (Map.fromList (map (\r -> (iiId r,r)) results))- Left (ReadProcessException{}) -> return Map.empty- Left e -> throwM e+ Left e -> throwM (e :: ReadProcessException) -- | Pull latest version of configured Docker image from registry. pull :: M env m => m ()@@ -644,16 +647,16 @@ do $logInfo (concatT ["Pulling image from registry: '",image,"'"]) when (dockerRegistryLogin docker) (do $logInfo "You may need to log in."- callProcess+ callProcess $ Cmd Nothing- envOverride "docker"+ envOverride (concat [["login"] ,maybe [] (\n -> ["--username=" ++ n]) (dockerRegistryUsername docker) ,maybe [] (\p -> ["--password=" ++ p]) (dockerRegistryPassword docker) ,[takeWhile (/= '/') image]]))- e <- try (callProcess Nothing envOverride "docker" ["pull",image])+ e <- try (callProcess (Cmd Nothing "docker" envOverride ["pull",image])) case e of Left (ProcessExitedUnsuccessfully _ _) -> throwM (PullFailedException image) Right () -> return ()@@ -684,10 +687,12 @@ prohibitedDockerVersions = [] -- | Remove the project's Docker sandbox.-reset :: (MonadIO m) => Maybe (Path Abs Dir) -> Bool -> m ()-reset maybeProjectRoot keepHome =+reset :: (MonadIO m, MonadReader env m, HasConfig env)+ => Maybe (Path Abs Dir) -> Bool -> m ()+reset maybeProjectRoot keepHome = do+ dockerSandboxDir <- projectDockerSandboxDir projectRoot liftIO (removeDirectoryContents- (projectDockerSandboxDir projectRoot)+ dockerSandboxDir [homeDirName | keepHome] []) where projectRoot = fromMaybeProjectRoot maybeProjectRoot@@ -696,7 +701,7 @@ -- a container, such as switching the UID/GID to the "outside-Docker" user's. entrypoint :: (MonadIO m, MonadBaseControl IO m, MonadCatch m, MonadLogger m) => Config -> DockerEntrypoint -> m ()-entrypoint config@Config{..} DockerEntrypoint{..} = do+entrypoint config@Config{..} DockerEntrypoint{..} = modifyMVar_ entrypointMVar $ \alreadyRan -> do -- Only run the entrypoint once unless alreadyRan $ do@@ -806,13 +811,6 @@ => EnvOverride -> [String] -> m BS.ByteString readDockerProcess envOverride = readProcessStdout Nothing envOverride "docker" --- | Subdirectories of the home directory to sandbox between GHC/Stackage versions.-sandboxedHomeSubdirectories :: [Path Rel Dir]-sandboxedHomeSubdirectories =- [$(mkRelDir ".ghc/")- ,$(mkRelDir ".cabal/")- ,$(mkRelDir ".ghcjs/")]- -- | Name of home directory within docker sandbox. homeDirName :: Path Rel Dir homeDirName = $(mkRelDir "_home/")@@ -833,13 +831,14 @@ fromMaybeProjectRoot :: Maybe (Path Abs Dir) -> Path Abs Dir fromMaybeProjectRoot = fromMaybe (throw CannotDetermineProjectRootException) --- | Environment variable that contains the sandbox ID.-sandboxIDEnvVar :: String-sandboxIDEnvVar = "DOCKER_SANDBOX_ID"+-- | Environment variable that contained the old sandbox ID.+-- | Use of this variable is deprecated, and only used to detect old images.+oldSandboxIdEnvVar :: String+oldSandboxIdEnvVar = "DOCKER_SANDBOX_ID" -- | Environment variable used to indicate stack is running in container. inContainerEnvVar :: String-inContainerEnvVar = fmap toUpper stackProgName ++ "_IN_CONTAINER"+inContainerEnvVar = stackProgNameUpper ++ "_IN_CONTAINER" -- | Command-line argument for "docker" dockerCmdName :: String
src/Stack/Exec.hs view
@@ -14,12 +14,13 @@ import Control.Monad.Trans.Control (MonadBaseControl) import Stack.Types import System.Process.Log+import System.Process.Read (EnvOverride) #ifdef WINDOWS import Control.Exception.Lifted import Data.Streaming.Process (ProcessExitedUnsuccessfully(..)) import System.Exit-import System.Process.Run (callProcess)+import System.Process.Run (callProcess, Cmd(..)) #else import System.Process.Read (envHelper, preProcess) import System.Posix.Process (executeFile)@@ -44,14 +45,12 @@ } -- | Execute a process within the Stack configured environment.-exec :: (HasConfig r, MonadReader r m, MonadIO m, MonadLogger m, MonadThrow m, MonadBaseControl IO m)- => EnvSettings -> String -> [String] -> m b-exec envSettings cmd0 args = do- config <- asks getConfig- menv <- liftIO (configEnvOverride config envSettings)+exec :: (MonadIO m, MonadLogger m, MonadThrow m, MonadBaseControl IO m)+ => EnvOverride -> String -> [String] -> m b+exec menv cmd0 args = do $logProcessRun cmd0 args #ifdef WINDOWS- e <- try (callProcess Nothing menv cmd0 args)+ e <- try (callProcess (Cmd Nothing cmd0 menv args)) liftIO $ case e of Left (ProcessExitedUnsuccessfully _ ec) -> exitWith ec Right () -> exitSuccess
src/Stack/Fetch.hs view
@@ -7,6 +7,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE PackageImports #-} {-# LANGUAGE ViewPatterns #-} -- | Functionality for downloading packages securely for cabal's usage.@@ -40,7 +41,7 @@ import Control.Monad.Logger import Control.Monad.Reader (asks, runReaderT) import Control.Monad.Trans.Control-import Crypto.Hash (SHA512 (..))+import "cryptohash" Crypto.Hash (SHA512 (..)) import Data.ByteString (ByteString) import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L
src/Stack/Ghci.hs view
@@ -18,8 +18,10 @@ import Control.Monad.Catch import Control.Monad.IO.Class import Control.Monad.Logger-import Control.Monad.Reader+import Control.Monad.RWS.Strict+import Control.Monad.State.Strict import Control.Monad.Trans.Resource+import qualified Data.ByteString.Char8 as S8 import Data.Either import Data.Function import Data.List@@ -28,7 +30,6 @@ import qualified Data.Map.Strict as M import Data.Maybe import Data.Maybe.Extra (forMaybeM)-import Data.Monoid import Data.Set (Set) import qualified Data.Set as S import Data.Text (Text)@@ -59,6 +60,7 @@ , ghciNoLoadModules :: !Bool , ghciAdditionalPackages :: ![String] , ghciMainIs :: !(Maybe Text)+ , ghciSkipIntermediate :: !Bool , ghciBuildOpts :: !BuildOpts } deriving Show @@ -85,58 +87,59 @@ { boptsTestOpts = (boptsTestOpts ghciBuildOpts) { toDisableRun = True } , boptsBenchmarkOpts = (boptsBenchmarkOpts ghciBuildOpts) { beoDisableRun = True } }- (targets,mainIsTargets,pkgs) <- ghciSetup bopts ghciNoBuild ghciMainIs+ (targets,mainIsTargets,pkgs) <- ghciSetup bopts ghciNoBuild ghciSkipIntermediate ghciMainIs config <- asks getConfig bconfig <- asks getBuildConfig mainFile <- figureOutMainFile bopts mainIsTargets targets pkgs wc <- getWhichCompiler let pkgopts = hidePkgOpt ++ genOpts ++ ghcOpts hidePkgOpt = if null pkgs then [] else ["-hide-all-packages"]- genOpts = nubOrd (concatMap (concatMap (bioGeneratedOpts . snd) . ghciPkgOpts) pkgs)+ genOpts = nubOrd (concatMap (concatMap (bioOneWordOpts . snd) . ghciPkgOpts) pkgs) (omittedOpts, ghcOpts) = partition badForGhci $- concatMap (concatMap (bioGhcOpts . snd) . ghciPkgOpts) pkgs +++ concatMap (concatMap (bioOpts . snd) . ghciPkgOpts) pkgs ++ getUserOptions Nothing ++ concatMap (getUserOptions . Just . ghciPkgName) pkgs getUserOptions mpkg = map T.unpack (M.findWithDefault [] mpkg (configGhcOptions config)) badForGhci x =- isPrefixOf "-O" x || elem x (words "-debug -threaded -ticky -static")+ isPrefixOf "-O" x || elem x (words "-debug -threaded -ticky -static -Werror") unless (null omittedOpts) $ $logWarn ("The following GHC options are incompatible with GHCi and have not been passed to it: " <> T.unwords (map T.pack (nubOrd omittedOpts)))+ oiDir <- objectInterfaceDir bconfig let modulesToLoad = nubOrd $- maybe [] (return . toFilePath) mainFile <> concatMap (map display . S.toList . ghciPkgModules) pkgs+ thingsToLoad =+ maybe [] (return . toFilePath) mainFile <> modulesToLoad odir =- [ "-odir=" <> toFilePathNoTrailingSep (objectInterfaceDir bconfig)- , "-hidir=" <> toFilePathNoTrailingSep (objectInterfaceDir bconfig)]+ [ "-odir=" <> toFilePathNoTrailingSep oiDir+ , "-hidir=" <> toFilePathNoTrailingSep oiDir ] $logInfo ("Configuring GHCi with the following packages: " <> T.intercalate ", " (map (packageNameText . ghciPkgName) pkgs))- let execGhci extras =- exec defaultEnvSettings+ let execGhci extras = do+ menv <- liftIO $ configEnvOverride config defaultEnvSettings+ exec menv (fromMaybe (compilerExeName wc) ghciGhcCommand) ("--interactive" : -- This initial "-i" resets the include directories to not -- include CWD. "-i" : odir <> pkgopts <> ghciArgs <> extras)- case ghciNoLoadModules of- True -> execGhci []- False -> do- tmp <- liftIO getTemporaryDirectory- withCanonicalizedTempDirectory- tmp- "ghci-script"- (\tmpDir ->- do let scriptPath = tmpDir </> $(mkRelFile "ghci-script")- fp = toFilePath scriptPath- loadModules = ":load " <> unwords modulesToLoad- bringIntoScope = ":module + " <> unwords modulesToLoad- liftIO (writeFile fp (unlines [loadModules,bringIntoScope]))- finally (execGhci ["-ghci-script=" <> fp])- (removeFile scriptPath))+ tmp <- liftIO getTemporaryDirectory+ withCanonicalizedTempDirectory tmp "ghci" $ \tmpDir -> do+ let macrosFile = tmpDir </> $(mkRelFile "cabal_macros.h")+ macrosOpts <- preprocessCabalMacros pkgs macrosFile+ if ghciNoLoadModules+ then execGhci macrosOpts+ else do+ let scriptPath = tmpDir </> $(mkRelFile "ghci-script")+ fp = toFilePath scriptPath+ loadModules = ":load " <> unwords (map show thingsToLoad)+ bringIntoScope = ":module + " <> unwords modulesToLoad+ liftIO (writeFile fp (unlines [loadModules,bringIntoScope]))+ execGhci (macrosOpts ++ ["-ghci-script=" <> fp]) -- | Figure out the main-is file to load based on the targets. Sometimes there -- is none, sometimes it's unambiguous, sometimes it's@@ -203,9 +206,10 @@ :: (HasConfig r, HasHttpManager r, HasBuildConfig r, MonadMask m, HasTerminal r, HasLogLevel r, HasEnvConfig r, MonadReader r m, MonadIO m, MonadThrow m, MonadLogger m, MonadCatch m, MonadBaseControl IO m) => BuildOpts -> Bool+ -> Bool -> Maybe Text -> m (Map PackageName SimpleTarget, Maybe (Map PackageName SimpleTarget), [GhciPkgInfo])-ghciSetup bopts noBuild mainIs = do+ghciSetup bopts noBuild skipIntermediate mainIs = do (_,_,targets) <- parseTargetsFromBuildOpts AllowNoTargets bopts mainIsTargets <- case mainIs of@@ -223,7 +227,7 @@ , getInstalledHaddock = False } sourceMap- locals <-+ directlyWanted <- forMaybeM (M.toList (envConfigPackages econfig)) $ \(dir,validWanted) -> do cabalfp <- getCabalFileName dir@@ -234,6 +238,18 @@ return (Just (name, (cabalfp, simpleTargets))) Nothing -> return Nothing else return Nothing+ let intermediateDeps = getIntermediateDeps sourceMap directlyWanted+ wanted <-+ if skipIntermediate || null intermediateDeps+ then return directlyWanted+ else do+ $logInfo $ T.concat+ [ "The following libraries will also be loaded into GHCi because "+ , "they are intermediate dependencies of your targets:\n "+ , T.intercalate ", " (map (packageNameText . fst) intermediateDeps)+ , "\n(Use --skip-intermediate-deps to omit these)"+ ]+ return (directlyWanted ++ intermediateDeps) -- Try to build, but optimistically launch GHCi anyway if it fails (#1065) unless noBuild $ do eres <- tryAny $ build (const (return ())) Nothing bopts@@ -243,9 +259,9 @@ $logError $ T.pack (show err) $logWarn "Warning: build failed, but optimistically launching GHCi anyway" -- Load the list of modules _after_ building, to catch changes in unlisted dependencies (#1180)- let localLibs = [name | (name, (_, target)) <- locals, hasLocalComp isCLib target]+ let localLibs = [name | (name, (_, target)) <- wanted , hasLocalComp isCLib target] infos <-- forM locals $+ forM wanted $ \(name,(cabalfp,target)) -> makeGhciPkgInfo bopts sourceMap installedMap localLibs name cabalfp target checkForIssues infos@@ -306,7 +322,7 @@ wantedPackageComponents bopts STLocalAll pkg = S.fromList $ (if packageHasLibrary pkg then [CLib] else []) ++ map CExe (S.toList (packageExes pkg)) <>- (if boptsTests bopts then map CTest (S.toList (packageTests pkg)) else []) <>+ (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 @@ -332,9 +348,25 @@ , mixedFlag "-XNoTraditionalRecordSyntax" [ "-XNoTraditionalRecordSyntax will be used, but it break modules which use record syntax." ] , mixedFlag "-XTemplateHaskell"- [ "-XTemplateHaskell will be used, but it may cause compilation issues due to different parsing of ($)." ]+ [ "-XTemplateHaskell will be used, but it may cause compilation issues due to different parsing of '$' when there's no space after it." ]+ , mixedFlag "-XQuasiQuotes"+ [ "-XQuasiQuotes will be used, but it may cause parse failures due to a different meaning for list comprehension syntax like [x| ... ]" ] , mixedFlag "-XSafe" [ "-XSafe will be used, but it will fail to compile unsafe modules." ]+ , mixedFlag "-XArrows"+ [ "-XArrows will be used, but it will cause non-arrow usages of proc, (-<), (-<<) to fail" ]+ , mixedFlag "-XOverloadedStrings"+ [ "-XOverloadedStrings will be used, but it can cause type ambiguity in code not usually compiled with it." ]+ , mixedFlag "-XOverloadedLists"+ [ "-XOverloadedLists will be used, but it can cause type ambiguity in code not usually compiled with it." ]+ , mixedFlag "-XMonoLocalBinds"+ [ "-XMonoLocalBinds will be used, but it can cause type errors in code which expects generalized local bindings." ]+ , mixedFlag "-XTypeFamilies"+ [ "-XTypeFamilies will be used, but it implies -XMonoLocalBinds, and so can cause type errors in code which expects generalized local bindings." ]+ , mixedFlag "-XGADTs"+ [ "-XGADTs will be used, but it implies -XMonoLocalBinds, and so can cause type errors in code which expects generalized local bindings." ]+ , mixedFlag "-XNewQualifiedOperators"+ [ "-XNewQualifiedOperators will be used, but this will break usages of the old qualified operator syntax." ] ] mixedFlag flag msgs = let x = partitionComps (== flag) in@@ -349,7 +381,7 @@ partitionComps f = (map fst xs, map fst ys) where (xs, ys) = partition (any f . snd) compsWithOpts- compsWithOpts = map (\(k, bio) -> (k, bioGeneratedOpts bio ++ bioGhcOpts bio)) compsWithBios+ compsWithOpts = map (\(k, bio) -> (k, bioOneWordOpts bio ++ bioOpts bio)) compsWithBios compsWithBios = [ ((ghciPkgName pkg, c), bio) | pkg <- pkgs@@ -364,3 +396,50 @@ $logWarn "* * * * * * * *" $logWarn "" return x++-- Adds in intermediate dependencies between ghci targets. Note that it+-- will return a Lib component for these intermediate dependencies even+-- if they don't have a library (but that's fine for the usage within+-- this module).+getIntermediateDeps+ :: SourceMap+ -> [(PackageName, (Path Abs File, SimpleTarget))]+ -> [(PackageName, (Path Abs File, SimpleTarget))]+getIntermediateDeps sourceMap targets =+ M.toList $+ (\mp -> foldl' (flip M.delete) mp (map fst targets)) $+ M.mapMaybe id $+ execState (mapM_ (mapM_ go . getDeps . fst) targets)+ (M.fromList (map (\(k, x) -> (k, Just x)) targets))+ where+ getDeps :: PackageName -> [PackageName]+ getDeps name =+ case M.lookup name sourceMap of+ Just (PSLocal lp) -> M.keys (packageDeps (lpPackage lp))+ _ -> []+ go :: PackageName -> State (Map PackageName (Maybe (Path Abs File, SimpleTarget))) Bool+ go name = do+ cache <- get+ case (M.lookup name cache, M.lookup name sourceMap) of+ (Just (Just _), _) -> return True+ (Just Nothing, _) -> return False+ (_, Just (PSLocal lp)) -> do+ let deps = M.keys (packageDeps (lpPackage lp))+ isIntermediate <- liftM or $ mapM go deps+ if isIntermediate+ then do+ modify (M.insert name (Just (lpCabalFile lp, STLocalComps (S.singleton CLib))))+ return True+ else do+ modify (M.insert name Nothing)+ return False+ (_, Just PSUpstream{}) -> return False+ (Nothing, Nothing) -> return False++preprocessCabalMacros :: MonadIO m => [GhciPkgInfo] -> Path Abs File -> m [String]+preprocessCabalMacros pkgs out = liftIO $ do+ let fps = nubOrd (concatMap (catMaybes . map (bioCabalMacros . snd) . ghciPkgOpts) pkgs)+ files <- mapM (S8.readFile . toFilePath) fps+ if null files then return [] else do+ S8.writeFile (toFilePath out) $ S8.intercalate "\n#undef CURRENT_PACKAGE_KEY\n" files+ return ["-optP-include", "-optP" <> toFilePath out]
src/Stack/Ide.hs view
@@ -48,7 +48,7 @@ { boptsTargets = targets , boptsBuildSubset = BSOnlyDependencies }- (_realTargets,_,pkgs) <- ghciSetup bopts False Nothing+ (_realTargets,_,pkgs) <- ghciSetup bopts False False Nothing pwd <- getWorkingDir (pkgopts,_srcfiles) <- liftM mconcat $ forM pkgs $ getPackageOptsAndTargetFiles pwd@@ -73,9 +73,9 @@ Platform _ os <- asks getPlatform when (os == OSX)- (catch (callProcess (Just pwd) menv "stty" ["cbreak", "-imaxbel"])+ (catch (callProcess (Cmd (Just pwd) "stty" menv ["cbreak", "-imaxbel"])) (\(_ :: ProcessExitedUnsuccessfully) -> return ()))- callProcess (Just pwd) menv "stack-ide" args+ callProcess (Cmd (Just pwd) "stack-ide" menv args) where includeDirs pkgopts = intercalate@@ -97,9 +97,13 @@ (parseRelFile ("Paths_" ++ packageNameString (ghciPkgName pkg) ++ ".hs")) paths_foo_exists <- fileExists paths_foo+ let ghcOptions bio =+ bioOneWordOpts bio +++ bioOpts bio +++ maybe [] (\cabalMacros -> ["-optP-include", "-optP" <> toFilePath cabalMacros]) (bioCabalMacros bio) return ( ("--dist-dir=" <> toFilePathNoTrailingSep dist) :- map ("--ghc-option=" ++) (concatMap (\(_, bio) -> bioGeneratedOpts bio ++ bioGhcOpts bio) (ghciPkgOpts pkg))+ map ("--ghc-option=" ++) (concatMap (ghcOptions . snd) (ghciPkgOpts pkg)) , mapMaybe (fmap toFilePath . stripDir pwd) (S.toList (ghciPkgCFiles pkg) <> S.toList (ghciPkgModFiles pkg) <>
src/Stack/Image.hs view
@@ -43,10 +43,9 @@ -- | Stages the executables & additional content in a staging -- directory under '.stack-work'-stageContainerImageArtifacts :: Build e m- => m ()+stageContainerImageArtifacts :: Build e m => m () stageContainerImageArtifacts = do- imageDir <- imageStagingDir <$> getWorkingDir+ imageDir <- getWorkingDir >>= imageStagingDir removeTreeIfExists imageDir createTree imageDir stageExesInDir imageDir@@ -56,10 +55,9 @@ -- specified in the project's stack.yaml. Then new image will be -- extended with an ENTRYPOINT specified for each `entrypoint` listed -- in the config file.-createContainerImageFromStage :: Assemble e m- => m ()+createContainerImageFromStage :: Assemble e m => m () createContainerImageFromStage = do- imageDir <- imageStagingDir <$> getWorkingDir+ imageDir <- getWorkingDir >>= imageStagingDir createDockerImage imageDir extendDockerImageWithEntrypoint imageDir @@ -113,17 +111,15 @@ (dir </> $(mkRelFile "Dockerfile"))) (unlines ["FROM " ++ base, "ADD ./ /"]))- callProcess- Nothing- menv- "docker"- [ "build"- , "-t"- , fromMaybe- (imageName (parent (parent dir)))- (imgDockerImageName =<< dockerConfig)- , toFilePathNoTrailingSep dir]+ let args = [ "build"+ , "-t"+ , fromMaybe+ (imageName (parent (parent dir)))+ (imgDockerImageName =<< dockerConfig)+ , toFilePathNoTrailingSep dir]+ callProcess $ Cmd Nothing "docker" menv args + -- | Extend the general purpose docker image with entrypoints (if -- specified). extendDockerImageWithEntrypoint :: Assemble e m => Path Abs Dir -> m ()@@ -151,10 +147,10 @@ , "ENTRYPOINT [\"/usr/local/bin/" ++ ep ++ "\"]" , "CMD []"]))- callProcess+ callProcess $ Cmd Nothing- menv "docker"+ menv [ "build" , "-t" , dockerImageName ++ "-" ++ ep
src/Stack/Init.hs view
@@ -130,7 +130,7 @@ \# system-ghc: true\n\n\ \# Require a specific version of stack, using version ranges\n\ \# require-stack-version: -any # Default\n\- \# require-stack-version: >= 0.1.4.0\n\n\+ \# require-stack-version: >= 0.1.10.0\n\n\ \# Override the architecture used by stack, especially useful on Windows\n\ \# arch: i386\n\ \# arch: x86_64\n\n\
src/Stack/New.hs view
@@ -213,7 +213,7 @@ case configScmInit config of Nothing -> return () Just Git ->- catch (callProcess (Just dir) menv "git" ["init"])+ catch (callProcess $ Cmd (Just dir) "git" menv ["init"]) (\(_ :: ProcessExitedUnsuccessfully) -> $logInfo "git init failed to run, ignoring ...")
+ src/Stack/Nix.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}++-- | Run commands in a nix-shell+module Stack.Nix+ (reexecWithOptionalShell+ ,nixCmdName+ ) where++import Control.Applicative+import Control.Monad+import Control.Monad.Catch (try,MonadCatch)+import Control.Monad.IO.Class (MonadIO,liftIO)+import Control.Monad.Logger (MonadLogger,logDebug)+import Control.Monad.Reader (MonadReader,asks)+import Control.Monad.Trans.Control (MonadBaseControl)+import Data.Char (toUpper)+import Data.List (intercalate)+import Data.Maybe+import Data.Monoid+import Data.Streaming.Process (ProcessExitedUnsuccessfully(..))+import qualified Data.Text as T+import Data.Version (showVersion)+import Network.HTTP.Client.Conduit (HasHttpManager)+import qualified Paths_stack as Meta+import Prelude -- Fix redundant import warnings+import Stack.Constants (stackProgName)+import Stack.Docker (reExecArgName)+import Stack.Exec (exec)+import System.Process.Read (getEnvOverride)+import Stack.Types+import Stack.Types.Internal+import System.Environment (lookupEnv,getArgs,getExecutablePath)+import System.Exit (exitSuccess, exitWith)+++-- | If Nix is enabled, re-runs the currently running OS command in a Nix container.+-- Otherwise, runs the inner action.+reexecWithOptionalShell+ :: M env m+ => IO ()+ -> m ()+reexecWithOptionalShell inner =+ do config <- asks getConfig+ inShell <- getInShell+ isReExec <- asks getReExec+ if nixEnable (configNix config) && not inShell && not isReExec+ then runShellAndExit getCmdArgs+ else liftIO (inner >> exitSuccess)+ where+ getCmdArgs = do+ args <-+ fmap+ (("--" ++ reExecArgName ++ "=" ++ showVersion Meta.version) :)+ (liftIO getArgs)+ exePath <- liftIO getExecutablePath+ return (exePath, args)++runShellAndExit :: M env m+ => m (String, [String])+ -> m ()+runShellAndExit getCmdArgs = do+ config <- asks getConfig+ envOverride <- getEnvOverride (configPlatform config)+ (cmnd,args) <- getCmdArgs+ let mshellFile = nixInitFile (configNix config)+ pkgsInConfig = nixPackages (configNix config)+ nixopts = case mshellFile of+ Just filePath -> [filePath]+ Nothing -> ["-E", T.unpack $ T.intercalate " " $ concat+ [["with (import <nixpkgs> {});"+ ,"runCommand \"myEnv\" {"+ ,"buildInputs=lib.optional stdenv.isLinux glibcLocales ++ ["],pkgsInConfig,["];"+ ,T.pack inShellEnvVar,"=1 ;"+ ,"STACK_IN_NIX_EXTRA_ARGS=''"]+ , (map (\p -> T.concat+ ["--extra-lib-dirs=${",p,"}/lib"+ ," --extra-include-dirs=${",p,"}/include "])+ pkgsInConfig), ["'' ;"+ ,"} \"\""]]]+ -- glibcLocales is necessary on Linux to avoid warnings about GHC being incapable to set the locale.+ fullArgs = concat [ -- ["--pure"],+ map T.unpack (nixShellOptions (configNix config))+ ,nixopts+ ,["--command", intercalate " " (map escape (cmnd:args))+ ++ " $STACK_IN_NIX_EXTRA_ARGS"]+ ]+ $logDebug $+ "Using a nix-shell environment " <> (case mshellFile of+ Just filePath -> "from file: " <> (T.pack filePath)+ Nothing -> "with nix packages: " <> (T.intercalate ", " pkgsInConfig))+ e <- try (exec envOverride "nix-shell" fullArgs)+ case e of+ Left (ProcessExitedUnsuccessfully _ ec) -> liftIO (exitWith ec)+ Right () -> liftIO exitSuccess++-- | Shell-escape quotes inside the string and enclose it in quotes.+escape :: String -> String+escape str = "'" ++ foldr (\c -> if c == '\'' then+ ("'\"'\"'"++)+ else (c:)) "" str+ ++ "'"++-- | 'True' if we are currently running inside a Nix.+getInShell :: (MonadIO m) => m Bool+getInShell = liftIO (isJust <$> lookupEnv inShellEnvVar)++-- | Environment variable used to indicate stack is running in container.+-- although we already have STACK_IN_NIX_EXTRA_ARGS that is set in the same conditions,+-- it can happen that STACK_IN_NIX_EXTRA_ARGS is set to empty.+inShellEnvVar :: String+inShellEnvVar = concat [map toUpper stackProgName,"_IN_NIXSHELL"]++-- | Command-line argument for "nix"+nixCmdName :: String+nixCmdName = "nix"++type M env m =+ (MonadIO m+ ,MonadReader env m+ ,MonadLogger m+ ,MonadBaseControl IO m+ ,MonadCatch m+ ,HasConfig env+ ,HasTerminal env+ ,HasReExec env+ ,HasHttpManager env+ )
src/Stack/Options.hs view
@@ -15,6 +15,7 @@ ,globalOptsParser ,initOptsParser ,newOptsParser+ ,nixOptsParser ,logLevelOptsParser ,ghciOptsParser ,solverOptsParser@@ -52,6 +53,7 @@ import Stack.Ghci (GhciOpts(..)) import Stack.Init import Stack.New+import Stack.Nix import Stack.Types import Stack.Types.TemplateName @@ -74,17 +76,10 @@ <*> switch (long "no-run-benchmarks" <> help "Disable running of benchmarks. (Benchmarks will still be built.)") -addCoverageFlags :: BuildOpts -> BuildOpts-addCoverageFlags bopts- | toCoverage $ boptsTestOpts bopts- = bopts { boptsGhcOptions = "-fhpc" : boptsGhcOptions bopts }- | otherwise = bopts- -- | Parser for build arguments. buildOptsParser :: Command -> Parser BuildOpts buildOptsParser cmd =- fmap addCoverageFlags $ BuildOpts <$> target <*> libProfiling <*> exeProfiling <*> haddock <*> haddockDeps <*> dryRun <*> ghcOpts <*> flags <*> copyBins <*> preFetch <*> buildSubset <*>@@ -151,11 +146,11 @@ (long "dependencies-only" <> help "A synonym for --only-dependencies") <|> flag' BSOnlySnapshot- (long ("only-snapshot") <>- help ("Only build packages for the snapshot database, not the local database"))+ (long "only-snapshot" <>+ help "Only build packages for the snapshot database, not the local database") <|> flag' BSOnlyDependencies- (long ("only-dependencies") <>- help ("Only build packages that are dependencies of targets on the command line"))+ (long "only-dependencies" <>+ help "Only build packages that are dependencies of targets on the command line") <|> pure BSAll fileWatch' =@@ -239,8 +234,10 @@ -- | Command-line arguments parser for configuration. configOptsParser :: Bool -> Parser ConfigMonoid configOptsParser hide0 =- (\opts systemGHC installGHC arch os ghcVariant jobs includes libs skipGHCCheck skipMsys localBin modifyCodePage -> mempty- { configMonoidDockerOpts = opts+ (\workDir dockerOpts nixOpts systemGHC installGHC arch os ghcVariant jobs includes libs skipGHCCheck skipMsys localBin modifyCodePage -> mempty+ { configMonoidWorkDir = workDir+ , configMonoidDockerOpts = dockerOpts+ , configMonoidNixOpts = nixOpts , configMonoidSystemGHC = systemGHC , configMonoidInstallGHC = installGHC , configMonoidSkipGHCCheck = skipGHCCheck@@ -254,7 +251,14 @@ , configMonoidLocalBinPath = localBin , configMonoidModifyCodePage = modifyCodePage })- <$> dockerOptsParser True+ <$> optional (strOption+ ( long "work-dir"+ <> metavar "WORK-DIR"+ <> help "Override work directory (default: .stack-work)"+ <> hide+ ))+ <*> dockerOptsParser True+ <*> nixOptsParser True <*> maybeBoolFlags "system-ghc" "using the system installed GHC (on the PATH) if available and a matching version"@@ -315,6 +319,24 @@ hide where hide = hideMods hide0 +nixOptsParser :: Bool -> Parser NixOptsMonoid+nixOptsParser hide0 =+ NixOptsMonoid+ <$> pure False+ <*> maybeBoolFlags nixCmdName+ "using a Nix-shell"+ hide+ <*> pure []+ <*> pure Nothing+ <*> ((map T.pack . fromMaybe [])+ <$> optional (argsOption (long "nix-shell-options" <>+ metavar "OPTION" <>+ help "Additional options passed to nix-shell" <>+ hide)))+ where+ hide = hideMods hide0++ -- | Options parser configuration for Docker. dockerOptsParser :: Bool -> Parser DockerOptsMonoid dockerOptsParser hide0 =@@ -490,6 +512,7 @@ help "Specify which target should contain the main \ \module to load, such as for an executable for \ \test suite or benchmark."))+ <*> switch (long "skip-intermediate-deps" <> help "Skip loading intermediate target dependencies") <*> buildOptsParser Build -- | Parser for exec command@@ -567,11 +590,11 @@ globalOptsFromMonoid defaultTerminal GlobalOptsMonoid{..} = GlobalOpts { globalReExecVersion = globalMonoidReExecVersion , globalDockerEntrypoint = globalMonoidDockerEntrypoint- , globalLogLevel = fromMaybe defaultLogLevel (globalMonoidLogLevel)+ , globalLogLevel = fromMaybe defaultLogLevel globalMonoidLogLevel , globalConfigMonoid = globalMonoidConfigMonoid , globalResolver = globalMonoidResolver , globalCompiler = globalMonoidCompiler- , globalTerminal = fromMaybe defaultTerminal (globalMonoidTerminal)+ , globalTerminal = fromMaybe defaultTerminal globalMonoidTerminal , globalStackYaml = globalMonoidStackYaml } initOptsParser :: Parser InitOpts@@ -605,7 +628,7 @@ metavar "RESOLVER" <> help "Use the given resolver, even if not all dependencies are met") --- | Parse for a logging level.+-- | Parser for a logging level. logLevelOptsParser :: Bool -> Parser (Maybe LogLevel) logLevelOptsParser hide = fmap (Just . parse)
src/Stack/Package.hs view
@@ -16,7 +16,7 @@ module Stack.Package (readPackage ,readPackageBS- ,readPackageDir+ ,readPackageDescriptionDir ,readPackageUnresolved ,readPackageUnresolvedBS ,resolvePackage@@ -33,9 +33,14 @@ ,packageIdentifier ,autogenDir ,checkCabalFileName- ,printCabalFileWarning)+ ,printCabalFileWarning+ ,cabalFilePackageId) where +#if __GLASGOW_HASKELL__ < 710+import Control.Applicative (Applicative, (<$>), (<*>))+#endif+ import Control.Arrow ((&&&)) import Control.Exception hiding (try,catch) import Control.Monad@@ -60,16 +65,21 @@ import qualified Data.Text as T import Data.Text.Encoding (decodeUtf8, decodeUtf8With) import Data.Text.Encoding.Error (lenientDecode)+import Data.Version (showVersion) import Distribution.Compiler import Distribution.ModuleName (ModuleName) import qualified Distribution.ModuleName as Cabal import Distribution.Package hiding (Package,PackageName,packageName,packageVersion,PackageIdentifier)+import qualified Distribution.Package as D import Distribution.PackageDescription hiding (FlagName)+import qualified Distribution.PackageDescription as D import Distribution.PackageDescription.Parse+import qualified Distribution.PackageDescription.Parse as D import Distribution.ParseUtils import Distribution.Simple.Utils import Distribution.System (OS (..), Arch, Platform (..)) import Distribution.Text (display, simpleParse)+import qualified Distribution.Verbosity as D import Path as FL import Path.Extra import Path.Find@@ -133,17 +143,16 @@ do (warnings,gpkg) <- readPackageUnresolvedBS Nothing bs return (warnings,resolvePackage packageConfig gpkg) --- | Convenience wrapper around @readPackage@ that first finds the cabal file--- in the given directory.-readPackageDir :: (MonadLogger m, MonadIO m, MonadThrow m, MonadCatch m)- => PackageConfig- -> Path Abs Dir- -> m (Path Abs File, [PWarning], Package)-readPackageDir packageConfig dir = do- cabalfp <- getCabalFileName dir- (warnings,pkg) <- readPackage packageConfig cabalfp- checkCabalFileName (packageName pkg) cabalfp- return (cabalfp, warnings, pkg)+-- | Get 'GenericPackageDescription' and 'PackageDescription' reading info+-- from given directory.+readPackageDescriptionDir :: (MonadLogger m, MonadIO m, MonadThrow m, MonadCatch m)+ => PackageConfig+ -> Path Abs Dir+ -> m (GenericPackageDescription, PackageDescription)+readPackageDescriptionDir config pkgDir = do+ cabalfp <- getCabalFileName pkgDir+ gdesc <- liftM snd (readPackageUnresolved cabalfp)+ return (gdesc, resolvePackageDescription config gdesc) -- | Print cabal file warnings. printCabalFileWarning@@ -187,9 +196,9 @@ , packageFlags = packageConfigFlags packageConfig , packageAllDeps = S.fromList (M.keys deps) , packageHasLibrary = maybe False (buildable . libBuildInfo) (library pkg)- , packageTests = S.fromList- [T.pack (testName t) | t <- testSuites pkg- , buildable (testBuildInfo t)]+ , packageTests = M.fromList+ [(T.pack (testName t), testInterface t) | t <- testSuites pkg+ , buildable (testBuildInfo t)] , packageBenchmarks = S.fromList [T.pack (benchmarkName b) | b <- benchmarks pkg , buildable (benchmarkBuildInfo b)]@@ -238,18 +247,18 @@ -> m (Map NamedComponent BuildInfoOpts) generatePkgDescOpts sourceMap installedMap omitPkgs cabalfp pkg componentPaths = do distDir <- distDirFromDir cabalDir- let cabalmacros = autogenDir distDir </> $(mkRelFile "cabal_macros.h")- exists <- fileExists cabalmacros- let mcabalmacros =+ let cabalMacros = autogenDir distDir </> $(mkRelFile "cabal_macros.h")+ exists <- fileExists cabalMacros+ let mcabalMacros = if exists- then Just cabalmacros+ then Just cabalMacros else Nothing let generate namedComponent binfo = ( namedComponent , generateBuildInfoOpts sourceMap installedMap- mcabalmacros+ mcabalMacros cabalDir distDir omitPkgs@@ -296,9 +305,9 @@ -> Set DotCabalPath -> NamedComponent -> BuildInfoOpts-generateBuildInfoOpts sourceMap installedMap mcabalmacros cabalDir distDir omitPkgs b dotCabalPaths componentName =+generateBuildInfoOpts sourceMap installedMap mcabalMacros cabalDir distDir omitPkgs b dotCabalPaths componentName = BuildInfoOpts- { bioGhcOpts = ghcOpts b+ { bioOpts = ghcOpts b ++ cppOptions b -- NOTE for future changes: Due to this use of nubOrd (and other uses -- downstream), these generated options must not rely on multiple -- argument sequences. For example, ["--main-is", "Foo.hs", "--main-@@ -306,8 +315,9 @@ -- "--main-is" being removed. -- -- See https://github.com/commercialhaskell/stack/issues/1255- , bioGeneratedOpts = nubOrd $ concat- [extOpts b, srcOpts, includeOpts, macros, deps, extra b, extraDirs, fworks b, cObjectFiles]+ , bioOneWordOpts = nubOrd $ concat+ [extOpts b, srcOpts, includeOpts, deps, extra b, extraDirs, fworks b, cObjectFiles]+ , bioCabalMacros = mcabalMacros } where cObjectFiles =@@ -328,11 +338,6 @@ -- Generates: -package=base -package=base16-bytestring-0.1.1.6 ... sourceVersion (PSUpstream ver _ _) = ver sourceVersion (PSLocal localPkg) = packageVersion (lpPackage localPkg)- macros =- case mcabalmacros of- Nothing -> []- Just cabalmacros ->- ["-optP-include", "-optP" <> toFilePath cabalmacros] ghcOpts = concatMap snd . filter (isGhc . fst) . options where isGhc GHC = True@@ -1095,3 +1100,16 @@ => FilePath.FilePath -> m (Maybe (Path Abs Dir)) resolveDirOrWarn = resolveOrWarn "Directory" resolveDirMaybe++-- | Extract the @PackageIdentifier@ given an exploded haskell package+-- path.+cabalFilePackageId+ :: (Applicative m, MonadIO m, MonadThrow m)+ => Path Abs File -> m PackageIdentifier+cabalFilePackageId fp = do+ pkgDescr <- liftIO (D.readPackageDescription D.silent $ toFilePath fp)+ (toStackPI . D.package . D.packageDescription) pkgDescr+ where+ toStackPI (D.PackageIdentifier (D.PackageName name) ver) =+ PackageIdentifier <$> parsePackageNameFromString name <*>+ parseVersionFromString (showVersion ver)
src/Stack/SDist.hs view
@@ -4,9 +4,12 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE DeriveDataTypeable #-} -- Create a source distribution tarball module Stack.SDist ( getSDistTarball+ , checkSDistTarball+ , checkSDistTarball' ) where import qualified Codec.Archive.Tar as Tar@@ -14,8 +17,8 @@ import qualified Codec.Compression.GZip as GZip import Control.Applicative import Control.Concurrent.Execute (ActionContext(..))-import Control.Monad (unless, void)-import Control.Monad.Catch (MonadMask)+import Control.Monad (unless, void, liftM)+import Control.Monad.Catch import Control.Monad.IO.Class import Control.Monad.Logger import Control.Monad.Reader (MonadReader, asks)@@ -26,6 +29,8 @@ import Data.Data (Data, Typeable, cast, gmapT) import Data.Either (partitionEithers) import Data.List+import Data.List.NonEmpty (NonEmpty)+import qualified Data.List.NonEmpty as NE import qualified Data.Map.Strict as Map import Data.Maybe (fromMaybe) import Data.Monoid ((<>))@@ -35,6 +40,7 @@ import qualified Data.Text.Lazy.Encoding as TLE import Data.Time.Clock.POSIX import Distribution.Package (Dependency (..))+import qualified Distribution.PackageDescription.Check as Check import Distribution.PackageDescription.PrettyPrint (showGenericPackageDescription) import Distribution.Version (simplifyVersionRange, orLaterVersion, earlierVersion) import Distribution.Version.Extra@@ -45,15 +51,30 @@ import Stack.Build (mkBaseConfigOpts) import Stack.Build.Execute import Stack.Build.Installed-import Stack.Build.Source (loadSourceMap, localFlags)+import Stack.Build.Source (loadSourceMap, getPackageConfig) import Stack.Build.Target import Stack.Constants import Stack.Package import Stack.Types import Stack.Types.Internal import System.Directory (getModificationTime, getPermissions, Permissions(..))+import System.IO.Temp (withSystemTempDirectory) import qualified System.FilePath as FP +-- | Special exception to throw when you want to fail because of bad results+-- of package check.++data CheckException+ = CheckException (NonEmpty Check.PackageCheck)+ deriving (Typeable)++instance Exception CheckException++instance Show CheckException where+ show (CheckException xs) =+ "Package check reported the following errors:\n" +++ (intercalate "\n" . fmap show . NE.toList $ xs)+ type M env m = (MonadIO m,MonadReader env m,HasHttpManager env,MonadLogger m,MonadBaseControl IO m,MonadMask m,HasLogLevel env,HasEnvConfig env,HasTerminal env) -- | Given the path to a local package, creates its source@@ -62,10 +83,11 @@ -- While this yields a 'FilePath', the name of the tarball, this -- tarball is not written to the disk and instead yielded as a lazy -- bytestring.-getSDistTarball :: M env m- => Maybe PvpBounds -- ^ override Config value- -> Path Abs Dir- -> m (FilePath, L.ByteString)+getSDistTarball+ :: M env m+ => Maybe PvpBounds -- ^ Override Config value+ -> Path Abs Dir -- ^ Path to local package+ -> m (FilePath, L.ByteString) -- ^ Filename and tarball contents getSDistTarball mpvpBounds pkgDir = do config <- asks getConfig let pvpBounds = fromMaybe (configPvpBounds config) mpvpBounds@@ -149,24 +171,14 @@ Nothing -> gtraverseT f x Just b -> fromMaybe x (cast (f b))) --- Read in a 'LocalPackage' config. This makes some default decisions+-- | Read in a 'LocalPackage' config. This makes some default decisions -- about 'LocalPackage' fields that might not be appropriate for other--- usecases.------ TODO: Dedupe with similar code in "Stack.Build.Source".+-- use-cases. readLocalPackage :: M env m => Path Abs Dir -> m LocalPackage readLocalPackage pkgDir = do- econfig <- asks getEnvConfig- bconfig <- asks getBuildConfig cabalfp <- getCabalFileName pkgDir- name <- parsePackageNameFromFilePath cabalfp- let config = PackageConfig- { packageConfigEnableTests = False- , packageConfigEnableBenchmarks = False- , packageConfigFlags = localFlags Map.empty bconfig name- , packageConfigCompilerVersion = envConfigCompilerVersion econfig- , packageConfigPlatform = configPlatform $ getConfig bconfig- }+ name <- parsePackageNameFromFilePath cabalfp+ config <- getPackageConfig defaultBuildOpts name (warnings,package) <- readPackage config cabalfp mapM_ (printCabalFileWarning cabalfp) warnings return LocalPackage@@ -219,8 +231,8 @@ normalizeTarballPaths :: M env m => [FilePath] -> m [FilePath] normalizeTarballPaths fps = do- --TODO: consider whether erroring out is better - otherwise the- --user might upload an incomplete tar?+ -- TODO: consider whether erroring out is better - otherwise the+ -- user might upload an incomplete tar? unless (null outsideDir) $ $logWarn $ T.concat [ "Warning: These files are outside of the package directory, and will be omitted from the tarball: "@@ -245,6 +257,60 @@ go s x | Set.member x s = s | otherwise = go (Set.insert x s) (FP.takeDirectory x)++-- | Check package in given tarball. This will log all warnings+-- and will throw an exception in case of critical errors.+--+-- Note that we temporarily decompress the archive to analyze it.+checkSDistTarball :: (MonadIO m, MonadMask m, MonadThrow m, MonadCatch m, MonadLogger m, MonadReader env m, HasEnvConfig env)+ => Path Abs File -- ^ Absolute path to tarball+ -> m ()+checkSDistTarball tarball = withTempTarGzContents tarball $ \pkgDir' -> do+ pkgDir <- (pkgDir' </>) `liftM`+ (parseRelDir . FP.takeBaseName . FP.takeBaseName . toFilePath $ tarball)+ -- ^ drop ".tar" ^ drop ".gz"+ cabalfp <- getCabalFileName pkgDir+ name <- parsePackageNameFromFilePath cabalfp+ config <- getPackageConfig defaultBuildOpts name+ (gdesc, pkgDesc) <- readPackageDescriptionDir config pkgDir+ $logInfo $+ "Checking package '" <> packageNameText name <> "' for common mistakes"+ let pkgChecks = Check.checkPackage gdesc (Just pkgDesc)+ fileChecks <- liftIO $ Check.checkPackageFiles pkgDesc (toFilePath pkgDir)+ let checks = pkgChecks ++ fileChecks+ (errors, warnings) =+ let criticalIssue (Check.PackageBuildImpossible _) = True+ criticalIssue (Check.PackageDistInexcusable _) = True+ criticalIssue _ = False+ in partition criticalIssue checks+ unless (null warnings) $+ $logWarn $ "Package check reported the following warnings:\n" <>+ T.pack (intercalate "\n" . fmap show $ warnings)+ case NE.nonEmpty errors of+ Nothing -> return ()+ Just ne -> throwM $ CheckException ne++-- | Version of 'checkSDistTarball' that first saves lazy bytestring to+-- temporary directory and then calls 'checkSDistTarball' on it.+checkSDistTarball' :: (MonadIO m, MonadMask m, MonadThrow m, MonadCatch m, MonadLogger m, MonadReader env m, HasEnvConfig env)+ => String -- ^ Tarball name+ -> L.ByteString -- ^ Tarball contents as a byte string+ -> m ()+checkSDistTarball' name bytes = withSystemTempDirectory "stack" $ \tdir -> do+ tpath <- parseAbsDir tdir+ npath <- (tpath </>) `liftM` parseRelFile name+ liftIO $ L.writeFile (toFilePath npath) bytes+ checkSDistTarball npath++withTempTarGzContents :: (MonadIO m, MonadMask m, MonadThrow m)+ => Path Abs File -- ^ Location of tarball+ -> (Path Abs Dir -> m a) -- ^ Perform actions given dir with tarball contents+ -> m a+withTempTarGzContents apath f = withSystemTempDirectory "stack" $ \tdir -> do+ tpath <- parseAbsDir tdir+ archive <- liftIO $ L.readFile (toFilePath apath)+ liftIO . Tar.unpack (toFilePath tpath) . Tar.read . GZip.decompress $ archive+ f tpath --------------------------------------------------------------------------------
src/Stack/Setup.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PackageImports #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-}@@ -28,7 +29,7 @@ import Control.Monad.Reader (MonadReader, ReaderT (..), asks) import Control.Monad.State (get, put, modify) import Control.Monad.Trans.Control-import Crypto.Hash (SHA1(SHA1))+import "cryptohash" Crypto.Hash (SHA1(SHA1)) import Data.Aeson.Extended import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8@@ -86,7 +87,7 @@ import qualified System.FilePath as FP import System.Process (rawSystem) import System.Process.Read-import System.Process.Run (runIn)+import System.Process.Run (runCmd, Cmd(..)) import Text.Printf (printf) -- | Default location of the stack-setup.yaml file@@ -113,7 +114,7 @@ -- version. Only works reliably with a stack-managed installation. , soptsResolveMissingGHC :: !(Maybe Text) -- ^ Message shown to user for how to resolve the missing GHC- , soptsStackSetupYaml :: !String+ , soptsStackSetupYaml :: !FilePath -- ^ Location of the main stack-setup.yaml file , soptsGHCBindistURL :: !(Maybe String) -- ^ Alternate GHC binary distribution (requires custom GHCVariant)@@ -439,7 +440,7 @@ => Platform -> m (Path Abs File) ensureDockerStackExe containerPlatform = do config <- asks getConfig- containerPlatformDir <- runReaderT platformOnlyRelDir containerPlatform+ containerPlatformDir <- runReaderT platformOnlyRelDir (containerPlatform,PlatformVariantNone) let programsPath = configLocalProgramsBase config </> containerPlatformDir stackVersion = fromCabalVersion Meta.version tool = Tool (PackageIdentifier $(mkPackageName "stack") stackVersion)@@ -511,7 +512,7 @@ Nothing -> error "upgradeCabal: Invariant violated, dir missing" Just dir -> return dir - runIn dir (compilerExeName wc) menv ["Setup.hs"] Nothing+ runCmd (Cmd (Just dir) (compilerExeName wc) menv ["Setup.hs"]) Nothing platform <- asks getPlatform let setupExe = toFilePath $ dir </> (case platform of@@ -523,13 +524,10 @@ , "dir=" , installRoot FP.</> name' ]- runIn dir setupExe menv- ( "configure"- : map dirArgument (words "lib bin data doc")- )- Nothing- runIn dir setupExe menv ["build"] Nothing- runIn dir setupExe menv ["install"] Nothing+ args = ( "configure": map dirArgument (words "lib bin data doc") )+ runCmd (Cmd (Just dir) setupExe menv args) Nothing+ runCmd (Cmd (Just dir) setupExe menv ["build"]) Nothing+ runCmd (Cmd (Just dir) setupExe menv ["install"]) Nothing $logInfo "New Cabal library installed" -- | Get the version of the system compiler, if available@@ -790,7 +788,7 @@ withCanonicalizedSystemTempDirectory "stack-setup" $ \root -> do dir <-- liftM (root Path.</>) $+ liftM (root </>) $ parseRelDir $ "ghc-" ++ versionString version @@ -799,7 +797,7 @@ readInNull root tarTool menv ["xf", toFilePath archiveFile] Nothing $logSticky "Configuring GHC ..."- readInNull dir (toFilePath $ dir Path.</> $(mkRelFile "configure"))+ readInNull dir (toFilePath $ dir </> $(mkRelFile "configure")) menv ["--prefix=" ++ toFilePath destDir] Nothing $logSticky "Installing GHC ..."@@ -835,7 +833,7 @@ -- environment of the stack.yaml which came with ghcjs, in order to -- install cabal-install. This lets us also fix the version of -- cabal-install used.- let unpackDir = destDir Path.</> $(mkRelDir "src")+ let unpackDir = destDir </> $(mkRelDir "src") tarComponent <- parseRelDir ("ghcjs-" ++ versionString version) runUnpack <- case platform of Platform _ Cabal.Windows -> return $@@ -855,7 +853,7 @@ return $ do removeTreeIfExists unpackDir readInNull destDir tarTool menv ["xf", toFilePath archiveFile] Nothing- renameDir (destDir Path.</> tarComponent) unpackDir+ renameDir (destDir </> tarComponent) unpackDir $logSticky $ T.concat ["Unpacking GHCJS into ", T.pack . toFilePath $ unpackDir, " ..."] $logDebug $ "Unpacking " <> T.pack (toFilePath archiveFile)@@ -863,7 +861,7 @@ $logSticky "Setting up GHCJS build environment" let stackYaml = unpackDir </> $(mkRelFile "stack.yaml")- destBinDir = destDir Path.</> $(mkRelDir "bin")+ destBinDir = destDir </> $(mkRelDir "bin") createTree destBinDir envConfig <- loadGhcjsEnvConfig stackYaml destBinDir @@ -933,7 +931,7 @@ actualStackYaml <- if stackYamlExists then return stackYaml else case cv of GhcjsVersion version _ ->- liftM ((destDir Path.</> $(mkRelDir "src")) Path.</>) $+ liftM ((destDir </> $(mkRelDir "src")) </>) $ parseRelFile $ "ghcjs-" ++ versionString version ++ "/stack.yaml" _ -> fail "ensureGhcjsBooted invoked on non GhcjsVersion" actualStackYamlExists <- fileExists actualStackYaml@@ -990,7 +988,8 @@ , configMonoidLocalBinPath = Just (toFilePath binPath) }) (Just stackYaml)- bconfig <- lcLoadBuildConfig lc Nothing Nothing+ Nothing+ bconfig <- lcLoadBuildConfig lc Nothing runInnerStackT bconfig $ setupEnv Nothing getCabalInstallVersion :: (MonadIO m, MonadBaseControl IO m, MonadLogger m, MonadCatch m)@@ -1076,14 +1075,14 @@ -- I couldn't find this officially documented anywhere, but you need to run -- the shell once in order to initialize some pacman stuff. Once that run -- happens, you can just run commands as usual.- runIn destDir "sh" menv ["--login", "-c", "true"] Nothing+ runCmd (Cmd (Just destDir) "sh" menv ["--login", "-c", "true"]) Nothing -- No longer installing git, it's unreliable -- (https://github.com/commercialhaskell/stack/issues/1046) and the -- MSYS2-installed version has bad CRLF defaults. -- -- Install git. We could install other useful things in the future too.- -- runIn destDir "pacman" menv ["-Sy", "--noconfirm", "git"] Nothing+ -- runCmd (Cmd (Just destDir) "pacman" menv ["-Sy", "--noconfirm", "git"]) Nothing -- | Unpack a compressed tarball using 7zip. Expects a single directory in -- the unpacked results, which is renamed to the destination directory.
+ src/Stack/Sig.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}++{-|+Module : Stack.Sig+Description : GPG Signatures for Stack+Copyright : (c) FPComplete.com, 2015+License : BSD3+Maintainer : Tim Dysinger <tim@fpcomplete.com>+Stability : experimental+Portability : POSIX+-}++module Stack.Sig+ ( module Sig+ , sigCmdName+ , sigSignCmdName+ , sigSignHackageCmdName+ , sigSignHackageOpts+ , sigSignSdistCmdName+ , sigSignSdistOpts+ )+ where++import Options.Applicative+import Stack.Sig.GPG as Sig+import Stack.Sig.Sign as Sig++-- | The command name for dealing with signatures.+sigCmdName :: String+sigCmdName = "sig"++-- | The command name for signing packages.+sigSignCmdName :: String+sigSignCmdName = "sign"++-- | The command name for signing an sdist package file.+sigSignSdistCmdName :: String+sigSignSdistCmdName = "sdist"++-- | The command name for signing all your packages from hackage.org.+sigSignHackageCmdName :: String+sigSignHackageCmdName = "hackage"++-- | The URL of the running signature service to use (sig-service)+url :: Parser String+url = strOption+ (long "url" <>+ short 'u' <>+ metavar "URL" <>+ showDefault <>+ value "https://sig.commercialhaskell.org")++-- | Signature sign (sdist) options+sigSignSdistOpts :: Parser (String, String)+sigSignSdistOpts = helper <*>+ ((,) <$> url <*>+ argument str (metavar "PATH"))++-- | Signature sign (hackage) options+sigSignHackageOpts :: Parser (String, String)+sigSignHackageOpts = helper <*>+ ((,) <$> url <*>+ argument str (metavar "USER"))
+ src/Stack/Sig/GPG.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}++{-|+Module : Stack.Sig.GPG+Description : GPG Functions+Copyright : (c) FPComplete.com, 2015+License : BSD3+Maintainer : Tim Dysinger <tim@fpcomplete.com>+Stability : experimental+Portability : POSIX+-}++module Stack.Sig.GPG (fullFingerprint, signPackage, verifyFile)+ where++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative ((<$>))+#endif++import Control.Monad.Catch (MonadThrow, throwM)+import Control.Monad.IO.Class (MonadIO, liftIO)+import qualified Data.ByteString.Char8 as C+import Data.Char (isSpace)+import Data.List (find)+import Data.Monoid ((<>))+import qualified Data.Text as T+import Path+import Stack.Types+import System.Exit (ExitCode(..))+import System.Process (readProcessWithExitCode)++-- | Extract the full long @fingerprint@ given a short (or long)+-- @fingerprint@+fullFingerprint+ :: (Monad m, MonadIO m, MonadThrow m)+ => Fingerprint -> m Fingerprint+fullFingerprint (Fingerprint fp) = do+ (code,out,err) <-+ liftIO+ (readProcessWithExitCode "gpg" ["--fingerprint", T.unpack fp] [])+ if code /= ExitSuccess+ then throwM (GPGFingerprintException (out ++ "\n" ++ err))+ else maybe+ (throwM+ (GPGFingerprintException+ ("unable to extract full fingerprint from output:\n " <>+ out)))+ return+ (let hasFingerprint =+ (==) ["Key", "fingerprint", "="] . take 3+ fingerprint =+ T.filter (not . isSpace) . T.pack . unwords . drop 3+ in Fingerprint . fingerprint <$>+ find hasFingerprint (map words (lines out)))++-- | Sign a file path with GPG, returning the @Signature@.+signPackage+ :: (Monad m, MonadIO m, MonadThrow m)+ => Path Abs File -> m Signature+signPackage path = do+ (code,out,err) <-+ liftIO+ (readProcessWithExitCode+ "gpg"+ [ "--output"+ , "-"+ , "--use-agent"+ , "--detach-sig"+ , "--armor"+ , toFilePath path]+ [])+ if code /= ExitSuccess+ then throwM (GPGSignException (out ++ "\n" ++ err))+ else return (Signature (C.pack out))++-- | Verify the @Signature@ of a file path returning the+-- @Fingerprint@.+verifyFile+ :: (Monad m, MonadIO m, MonadThrow m)+ => Signature -> Path Abs File -> m Fingerprint+verifyFile (Signature signature) path = do+ let process =+ readProcessWithExitCode+ "gpg"+ ["--verify", "-", toFilePath path]+ (C.unpack signature)+ (code,out,err) <- liftIO process+ if code /= ExitSuccess+ then throwM (GPGVerifyException (out ++ "\n" ++ err))+ else maybe+ (throwM+ (GPGFingerprintException+ ("unable to extract short fingerprint from output\n: " <>+ out)))+ return+ (let hasFingerprint =+ (==) ["gpg:", "Signature", "made"] . take 3+ fingerprint = T.pack . last+ in Fingerprint . fingerprint <$>+ find hasFingerprint (map words (lines err)))
+ src/Stack/Sig/Sign.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TemplateHaskell #-}++{-|+Module : Stack.Sig.Sign+Description : Signing Packages+Copyright : (c) FPComplete.com, 2015+License : BSD3+Maintainer : Tim Dysinger <tim@fpcomplete.com>+Stability : experimental+Portability : POSIX+-}++module Stack.Sig.Sign (sign, signTarBytes) where++import qualified Codec.Archive.Tar as Tar+import qualified Codec.Compression.GZip as GZip+import Control.Monad (when)+import Control.Monad.Catch+import Control.Monad.IO.Class+import Control.Monad.Logger+import Control.Monad.Trans.Control+import qualified Data.ByteString.Lazy as BS+import qualified Data.ByteString.Lazy as L+import Data.Monoid ((<>))+import qualified Data.Text as T+import Data.UUID (toString)+import Data.UUID.V4 (nextRandom)+import Network.HTTP.Conduit+ (Response(..), RequestBody(..), Request(..), httpLbs, newManager,+ tlsManagerSettings)+import Network.HTTP.Download+import Network.HTTP.Types (status200, methodPut)+import Path+import Path.IO+import Stack.Package+import qualified Stack.Sig.GPG as GPG+import Stack.Types+import qualified System.FilePath as FP++-- | Sign a haskell package with the given url of the signature+-- service and a path to a tarball.+sign+ :: (MonadCatch m, MonadBaseControl IO m, MonadIO m, MonadMask m, MonadLogger m, MonadThrow m, MonadReader env m, HasConfig env)+ => Maybe (Path Abs Dir) -> String -> Path Abs File -> m ()+sign Nothing _ _ = throwM SigNoProjectRootException+sign (Just projectRoot) url filePath = do+ withStackWorkTempDir+ projectRoot+ (\tempDir ->+ do bytes <-+ liftIO+ (fmap+ GZip.decompress+ (BS.readFile (toFilePath filePath)))+ maybePath <- extractCabalFile tempDir (Tar.read bytes)+ case maybePath of+ Nothing -> throwM SigInvalidSDistTarBall+ Just cabalPath -> do+ pkg <- cabalFilePackageId (tempDir </> cabalPath)+ signPackage url pkg filePath)+ where+ extractCabalFile tempDir (Tar.Next entry entries) = do+ case Tar.entryContent entry of+ (Tar.NormalFile lbs _) ->+ case FP.splitFileName (Tar.entryPath entry) of+ (folder,file)+ | length (FP.splitDirectories folder) == 1 &&+ FP.takeExtension file == ".cabal" -> do+ cabalFile <- parseRelFile file+ liftIO+ (BS.writeFile+ (toFilePath (tempDir </> cabalFile))+ lbs)+ return (Just cabalFile)+ (_,_) -> extractCabalFile tempDir entries+ _ -> extractCabalFile tempDir entries+ extractCabalFile _ _ = return Nothing++-- | Sign a haskell package with the given url to the signature+-- service, a package tarball path (package tarball name) and a lazy+-- bytestring of bytes that represent the tarball bytestream. The+-- function will write the bytes to the path in a temp dir and sign+-- the tarball with GPG.+signTarBytes+ :: (MonadCatch m, MonadBaseControl IO m, MonadIO m, MonadMask m, MonadLogger m, MonadThrow m, MonadReader env m, HasConfig env)+ => Maybe (Path Abs Dir) -> String -> Path Rel File -> L.ByteString -> m ()+signTarBytes Nothing _ _ _ = throwM SigNoProjectRootException+signTarBytes (Just projectRoot) url tarPath bs =+ withStackWorkTempDir+ projectRoot+ (\tempDir ->+ do let tempTarBall = tempDir </> tarPath+ liftIO (L.writeFile (toFilePath tempTarBall) bs)+ sign (Just projectRoot) url tempTarBall)++-- | Sign a haskell package given the url to the signature service, a+-- @PackageIdentifier@ and a file path to the package on disk.+signPackage+ :: (MonadCatch m, MonadBaseControl IO m, MonadIO m, MonadMask m, MonadLogger m, MonadThrow m)+ => String -> PackageIdentifier -> Path Abs File -> m ()+signPackage url pkg filePath = do+ $logInfo ("GPG signing " <> T.pack (toFilePath filePath))+ sig@(Signature signature) <- GPG.signPackage filePath+ let (PackageIdentifier n v) = pkg+ name = show n+ version = show v+ verify <- GPG.verifyFile sig filePath+ fingerprint <- GPG.fullFingerprint verify+ req <-+ parseUrl+ (url <> "/upload/signature/" <> name <> "/" <> version <> "/" <>+ T.unpack (fingerprintSample fingerprint))+ let put =+ req+ { method = methodPut+ , requestBody = RequestBodyBS signature+ }+ mgr <- liftIO (newManager tlsManagerSettings)+ res <- liftIO (httpLbs put mgr)+ when+ (responseStatus res /= status200)+ (throwM (GPGSignException "unable to sign & upload package"))++withStackWorkTempDir+ :: (MonadCatch m, MonadIO m, MonadMask m, MonadLogger m, MonadReader env m, HasConfig env)+ => Path Abs Dir -> (Path Abs Dir -> m ()) -> m ()+withStackWorkTempDir projectRoot f = do+ uuid <- liftIO nextRandom+ uuidPath <- parseRelDir (toString uuid)+ workDir <- getWorkDir+ let tempDir = projectRoot </> workDir </> $(mkRelDir "tmp") </> uuidPath+ bracket+ (createTree tempDir)+ (const (removeTree tempDir))+ (const (f tempDir))
src/Stack/Types.hs view
@@ -13,7 +13,9 @@ import Stack.Types.Version as X import Stack.Types.Config as X import Stack.Types.Docker as X+import Stack.Types.Nix as X import Stack.Types.Image as X import Stack.Types.Build as X import Stack.Types.Package as X import Stack.Types.Compiler as X+import Stack.Types.Sig as X
src/Stack/Types/Build.hs view
@@ -64,6 +64,7 @@ import Data.Time.Calendar import Data.Time.Clock import Distribution.System (Arch)+import Distribution.PackageDescription (TestSuiteInterface) import Distribution.Text (display) import GHC.Generics import Path (Path, Abs, File, Dir, mkRelDir, toFilePath, parseRelDir, (</>))@@ -99,6 +100,7 @@ (Map PackageName Version) -- not in snapshot, here's the most recent version in the index (Path Abs File) -- stack.yaml | TestSuiteFailure PackageIdentifier (Map Text (Maybe ExitCode)) (Maybe (Path Abs File)) S.ByteString+ | TestSuiteTypeUnsupported TestSuiteInterface | ConstructPlanExceptions [ConstructPlanException] (Path Abs File) -- stack.yaml@@ -108,7 +110,7 @@ (Path Abs File) -- cabal Executable [String] -- cabal arguments (Maybe (Path Abs File)) -- logfiles location- S.ByteString -- log contents+ [S.ByteString] -- log contents | ExecutionFailure [SomeException] | LocalPackageDoesn'tMatchTarget PackageName@@ -209,6 +211,8 @@ where indent = dropWhileEnd isSpace . unlines . fmap (\line -> " " ++ line) . lines doubleIndent = indent . indent+ show (TestSuiteTypeUnsupported interface) =+ ("Unsupported test suite type: " <> show interface) show (ConstructPlanExceptions exceptions stackYaml) = "While constructing the BuildPlan the following exceptions were encountered:" ++ appendExceptions exceptions' ++@@ -238,7 +242,7 @@ Map.singleton name version go _ = Map.empty -- Supressing duplicate output- show (CabalExitedUnsuccessfully exitCode taskProvides' execName fullArgs logFiles bs) =+ show (CabalExitedUnsuccessfully exitCode taskProvides' execName fullArgs logFiles bss) = let fullCmd = unwords $ dropQuotes (toFilePath execName) : map (T.unpack . showProcessArgDebug) fullArgs@@ -250,14 +254,12 @@ then " (THIS MAY INDICATE OUT OF MEMORY)" else "") ++ logLocations ++- (if S.null bs+ (if null bss then ""- else "\n\n" ++ doubleIndent (T.unpack $ decodeUtf8With lenientDecode bs))+ else "\n\n" ++ doubleIndent (map (T.unpack . decodeUtf8With lenientDecode) bss)) where- -- appendLines = foldr (\pName-> (++) ("\n" ++ show pName)) ""- indent = dropWhileEnd isSpace . unlines . fmap (\line -> " " ++ line) . lines+ doubleIndent = dropWhileEnd isSpace . unlines . fmap (\line -> " " ++ line) dropQuotes = filter ('\"' /=)- doubleIndent = indent . indent show (ExecutionFailure es) = intercalate "\n\n" $ map show es show (LocalPackageDoesn'tMatchTarget name localV requestedV) = concat [ "Version for local package "@@ -341,13 +343,13 @@ data ConstructPlanException = DependencyCycleDetected [PackageName]- | DependencyPlanFailures PackageIdentifier (Map PackageName (VersionRange, LatestVersion, BadDependency))+ | DependencyPlanFailures PackageIdentifier (Map PackageName (VersionRange, LatestApplicableVersion, BadDependency)) | UnknownPackage PackageName -- TODO perhaps this constructor will be removed, and BadDependency will handle it all -- ^ Recommend adding to extra-deps, give a helpful version number? deriving (Typeable, Eq) -- | For display purposes only, Nothing if package not found-type LatestVersion = Maybe Version+type LatestApplicableVersion = Maybe Version -- | Reason why a dependency was not used data BadDependency@@ -374,26 +376,26 @@ indent = dropWhileEnd isSpace . unlines . fmap (\line -> " " ++ line) . lines doubleIndent = indent . indent appendDeps = foldr (\dep-> (++) ("\n" ++ showDep dep)) ""- showDep (name, (range, mlatest, badDep)) = concat+ showDep (name, (range, mlatestApplicable, badDep)) = concat [ show name , ": needed (" , display range , ")" , ", "- , let latestStr =- case mlatest of+ , let latestApplicableStr =+ case mlatestApplicable of Nothing -> ""- Just latest -> " (latest is " ++ versionString latest ++ ")"+ Just la -> " (latest applicable is " ++ versionString la ++ ")" in case badDep of- NotInBuildPlan -> "not present in build plan" ++ latestStr+ NotInBuildPlan -> "not present in build plan" ++ latestApplicableStr Couldn'tResolveItsDependencies -> "couldn't resolve its dependencies" DependencyMismatch version ->- case mlatest of- Just latest- | latest == version ->+ case mlatestApplicable of+ Just la+ | la == version -> versionString version ++- " found (latest version available)"- _ -> versionString version ++ " found" ++ latestStr+ " found (latest applicable version available)"+ _ -> versionString version ++ " found" ++ latestApplicableStr ] {- TODO Perhaps change the showDep function to look more like this: dropQuotes = filter ((/=) '\"')@@ -727,6 +729,7 @@ allGhcOptions = concat [ Map.findWithDefault [] Nothing (configGhcOptions config) , Map.findWithDefault [] (Just $ packageName package) (configGhcOptions config)+ , concat [["-fhpc"] | isLocal && toCoverage (boptsTestOpts bopts)] , if includeExtraOptions then boptsGhcOptions bopts else []
src/Stack/Types/Config.hs view
@@ -19,6 +19,7 @@ -- ** HasPlatform & HasStackRoot HasPlatform(..) ,HasStackRoot(..)+ ,PlatformVariant(..) -- ** Config & HasConfig ,Config(..) ,HasConfig(..)@@ -62,6 +63,7 @@ ,PackageEntry(..) ,peExtraDep ,PackageLocation(..)+ ,RemotePackageType(..) -- ** PackageIndex, IndexName & IndexLocation ,PackageIndex(..) ,IndexName(..)@@ -102,7 +104,7 @@ ,platformOnlyRelDir ,platformVariantRelDir ,useShaPathOnWindows- ,workDirRel+ ,getWorkDir -- * Command-specific types -- ** Eval ,EvalOpts(..)@@ -159,6 +161,7 @@ import Stack.Types.BuildPlan (SnapName, renderSnapName, parseSnapName) import Stack.Types.Compiler import Stack.Types.Docker+import Stack.Types.Nix import Stack.Types.FlagName import Stack.Types.Image import Stack.Types.PackageIdentifier@@ -176,10 +179,14 @@ data Config = Config {configStackRoot :: !(Path Abs Dir) -- ^ ~/.stack more often than not+ ,configWorkDir :: !(Path Rel Dir)+ -- ^ this allows to override .stack-work directory ,configUserConfigPath :: !(Path Abs File) -- ^ Path to user configuration file (usually ~/.stack/config.yaml) ,configDocker :: !DockerOpts -- ^ Docker configuration+ ,configNix :: !NixOpts+ -- ^ Execution environment (e.g nix-shell) configuration ,configEnvOverride :: !(EnvSettings -> IO EnvOverride) -- ^ Environment variables to be passed to external tools ,configLocalProgramsBase :: !(Path Abs Dir)@@ -193,6 +200,8 @@ -- console ,configPlatform :: !Platform -- ^ The platform we're building for, used in many directory names+ ,configPlatformVariant :: !PlatformVariant+ -- ^ Variant of the platform, also used in directory names ,configGHCVariant0 :: !(Maybe GHCVariant) -- ^ The variant of GHC requested by the user. -- In most cases, use 'BuildConfig' or 'MiniConfig's version instead,@@ -467,8 +476,10 @@ bcRoot = parent . bcStackYaml -- | @"'bcRoot'/.stack-work"@-bcWorkDir :: BuildConfig -> Path Abs Dir-bcWorkDir = (</> workDirRel) . bcRoot+bcWorkDir :: (MonadReader env m, HasConfig env) => BuildConfig -> m (Path Abs Dir)+bcWorkDir bconfig = do+ workDir <- getWorkDir+ return (bcRoot bconfig </> workDir) -- | Configuration after the environment has been setup. data EnvConfig = EnvConfig@@ -491,7 +502,7 @@ data LoadConfig m = LoadConfig { lcConfig :: !Config -- ^ Top-level Stack configuration.- , lcLoadBuildConfig :: !(Maybe AbstractResolver -> Maybe CompilerVersion -> m BuildConfig)+ , lcLoadBuildConfig :: !(Maybe CompilerVersion -> m BuildConfig) -- ^ Action to load the remaining 'BuildConfig'. , lcProjectRoot :: !(Maybe (Path Abs Dir)) -- ^ The project root directory, if in a project.@@ -551,25 +562,39 @@ = PLFilePath FilePath -- ^ Note that we use @FilePath@ and not @Path@s. The goal is: first parse -- the value raw, and then use @canonicalizePath@ and @parseAbsDir@.- | PLHttpTarball Text- | PLGit Text Text- -- ^ URL and commit+ | PLRemote Text RemotePackageType+ -- ^ URL and further details deriving Show++data RemotePackageType+ = RPTHttpTarball+ | RPTGit Text -- ^ Commit+ | RPTHg Text -- ^ Commit+ deriving Show+ instance ToJSON PackageLocation where toJSON (PLFilePath fp) = toJSON fp- toJSON (PLHttpTarball t) = toJSON t- toJSON (PLGit x y) = toJSON $ T.unwords ["git", x, y]+ toJSON (PLRemote t RPTHttpTarball) = toJSON t+ toJSON (PLRemote x (RPTGit y)) = toJSON $ T.unwords ["git", x, y]+ toJSON (PLRemote x (RPTHg y)) = toJSON $ T.unwords ["hg", x, y]+ instance FromJSON (PackageLocation, [JSONWarning]) where- parseJSON v = ((,[]) <$> withText "PackageLocation" (\t -> http t <|> file t) v) <|> git v+ parseJSON v+ = ((,[]) <$> withText "PackageLocation" (\t -> http t <|> file t) v)+ <|> git v+ <|> hg v where file t = pure $ PLFilePath $ T.unpack t http t = case parseUrl $ T.unpack t of Left _ -> mzero- Right _ -> return $ PLHttpTarball t- git = withObjectWarnings "PackageGitLocation" $ \o -> PLGit+ Right _ -> return $ PLRemote t RPTHttpTarball+ git = withObjectWarnings "PackageGitLocation" $ \o -> PLRemote <$> o ..: "git"- <*> o ..: "commit"+ <*> (RPTGit <$> o ..: "commit")+ hg = withObjectWarnings "PackageHgLocation" $ \o -> PLRemote+ <$> o ..: "hg"+ <*> (RPTHg <$> o ..: "commit") -- | A project is a collection of packages. We can have multiple stack.yaml -- files, but only one of them may contain project information.@@ -658,8 +683,13 @@ default getPlatform :: HasConfig env => env -> Platform getPlatform = configPlatform . getConfig {-# INLINE getPlatform #-}-instance HasPlatform Platform where- getPlatform = id+ getPlatformVariant :: env -> PlatformVariant+ default getPlatformVariant :: HasConfig env => env -> PlatformVariant+ getPlatformVariant = configPlatformVariant . getConfig+ {-# INLINE getPlatformVariant #-}+instance HasPlatform (Platform,PlatformVariant) where+ getPlatform (p,_) = p+ getPlatformVariant (_,v) = v -- | Class for environment values which have a GHCVariant class HasGHCVariant env where@@ -697,8 +727,12 @@ -- Configurations may be "cascaded" using mappend (left-biased). data ConfigMonoid = ConfigMonoid- { configMonoidDockerOpts :: !DockerOptsMonoid+ { configMonoidWorkDir :: !(Maybe FilePath)+ -- ^ See: 'configWorkDir'.+ , configMonoidDockerOpts :: !DockerOptsMonoid -- ^ Docker options.+ , configMonoidNixOpts :: !NixOptsMonoid+ -- ^ Options for the execution environment (nix-shell or container) , configMonoidConnectionCount :: !(Maybe Int) -- ^ See: 'configConnectionCount' , configMonoidHideTHLoading :: !(Maybe Bool)@@ -764,7 +798,9 @@ instance Monoid ConfigMonoid where mempty = ConfigMonoid- { configMonoidDockerOpts = mempty+ { configMonoidWorkDir = Nothing+ , configMonoidDockerOpts = mempty+ , configMonoidNixOpts = mempty , configMonoidConnectionCount = Nothing , configMonoidHideTHLoading = Nothing , configMonoidLatestSnapshotUrl = Nothing@@ -797,7 +833,9 @@ , configMonoidAllowNewer = Nothing } mappend l r = ConfigMonoid- { configMonoidDockerOpts = configMonoidDockerOpts l <> configMonoidDockerOpts r+ { configMonoidWorkDir = configMonoidWorkDir l <|> configMonoidWorkDir r+ , configMonoidDockerOpts = configMonoidDockerOpts l <> configMonoidDockerOpts r+ , configMonoidNixOpts = configMonoidNixOpts l <> configMonoidNixOpts r , configMonoidConnectionCount = configMonoidConnectionCount l <|> configMonoidConnectionCount r , configMonoidHideTHLoading = configMonoidHideTHLoading l <|> configMonoidHideTHLoading r , configMonoidLatestSnapshotUrl = configMonoidLatestSnapshotUrl l <|> configMonoidLatestSnapshotUrl r@@ -839,7 +877,9 @@ -- warnings for missing fields. parseConfigMonoidJSON :: Object -> WarningParser ConfigMonoid parseConfigMonoidJSON obj = do+ configMonoidWorkDir <- obj ..:? configMonoidWorkDirName configMonoidDockerOpts <- jsonSubWarnings (obj ..:? configMonoidDockerOptsName ..!= mempty)+ configMonoidNixOpts <- jsonSubWarnings (obj ..:? configMonoidNixOptsName ..!= mempty) configMonoidConnectionCount <- obj ..:? configMonoidConnectionCountName configMonoidHideTHLoading <- obj ..:? configMonoidHideTHLoadingName configMonoidLatestSnapshotUrl <- obj ..:? configMonoidLatestSnapshotUrlName@@ -916,9 +956,15 @@ Right x -> return $ Just x return (name, b) +configMonoidWorkDirName :: Text+configMonoidWorkDirName = "work-dir"+ configMonoidDockerOptsName :: Text configMonoidDockerOptsName = "docker" +configMonoidNixOptsName :: Text+configMonoidNixOptsName = "nix"+ configMonoidConnectionCountName :: Text configMonoidConnectionCountName = "connection-count" @@ -1114,14 +1160,15 @@ return (root </> $(mkRelDir "packages") </> name </> ver </> base) -- | @".stack-work"@-workDirRel :: Path Rel Dir-workDirRel = $(mkRelDir ".stack-work")+getWorkDir :: (MonadReader env m, HasConfig env) => m (Path Rel Dir)+getWorkDir = configWorkDir `liftM` asks getConfig -- | Per-project work dir configProjectWorkDir :: (HasBuildConfig env, MonadReader env m) => m (Path Abs Dir) configProjectWorkDir = do- bc <- asks getBuildConfig- return (bcRoot bc </> workDirRel)+ bc <- asks getBuildConfig+ workDir <- getWorkDir+ return (bcRoot bc </> workDir) -- | File containing the installed cache, see "Stack.PackageDump" configInstalledCache :: (HasBuildConfig env, MonadReader env m) => m (Path Abs File)@@ -1133,7 +1180,8 @@ => m (Path Rel Dir) platformOnlyRelDir = do platform <- asks getPlatform- parseRelDir (Distribution.Text.display platform)+ platformVariant <- asks getPlatformVariant+ parseRelDir (Distribution.Text.display platform ++ platformVariantSuffix platformVariant) -- | Directory containing snapshots snapshotsDir :: (MonadReader env m, HasConfig env, HasGHCVariant env, MonadThrow m) => m (Path Abs Dir)@@ -1175,8 +1223,11 @@ => m (Path Rel Dir) platformVariantRelDir = do platform <- asks getPlatform+ platformVariant <- asks getPlatformVariant ghcVariant <- asks getGHCVariant- parseRelDir (Distribution.Text.display platform <> ghcVariantSuffix ghcVariant)+ parseRelDir (mconcat [ Distribution.Text.display platform+ , platformVariantSuffix platformVariant+ , ghcVariantSuffix ghcVariant ]) -- | This is an attempt to shorten stack paths on Windows to decrease our -- chances of hitting 260 symbol path limit. The idea is to calculate@@ -1344,6 +1395,15 @@ instance ToJSON SCM where toJSON Git = toJSON ("git" :: Text)++-- | A variant of the platform, used to differentiate Docker builds from host+data PlatformVariant = PlatformVariantNone+ | PlatformVariant String++-- | Render a platform variant to a String suffix.+platformVariantSuffix :: PlatformVariant -> String+platformVariantSuffix PlatformVariantNone = ""+platformVariantSuffix (PlatformVariant v) = "-" ++ v -- | Specialized bariant of GHC (e.g. libgmp4 or integer-simple) data GHCVariant
src/Stack/Types/Internal.hs view
@@ -22,6 +22,7 @@ getStackRoot = getStackRoot . envConfig instance HasPlatform config => HasPlatform (Env config) where getPlatform = getPlatform . envConfig+ getPlatformVariant = getPlatformVariant . envConfig instance HasGHCVariant config => HasGHCVariant (Env config) where getGHCVariant = getGHCVariant . envConfig instance HasConfig config => HasConfig (Env config) where
+ src/Stack/Types/Nix.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Nix types.++module Stack.Types.Nix where++import Control.Applicative+import Data.Aeson.Extended+import Data.Monoid+import Data.Text (Text)++-- | Nix configuration.+data NixOpts = NixOpts+ {nixEnable :: !Bool+ ,nixPackages :: ![Text]+ -- ^ The system packages to be installed in the environment before it runs+ ,nixInitFile :: !(Maybe String)+ -- ^ The path of a file containing preconfiguration of the environment (e.g shell.nix)+ ,nixShellOptions :: ![Text]+ -- ^ Options to be given to the nix-shell command line+ }+ deriving (Show)++-- | An uninterpreted representation of nix options.+-- Configurations may be "cascaded" using mappend (left-biased).+data NixOptsMonoid = NixOptsMonoid+ {nixMonoidDefaultEnable :: !Bool+ -- ^ Should nix-shell be defaulted to enabled (does @nix:@ section exist in the config)?+ ,nixMonoidEnable :: !(Maybe Bool)+ -- ^ Is using nix-shell enabled?+ ,nixMonoidPackages :: ![Text]+ -- ^ System packages to use (given to nix-shell)+ ,nixMonoidInitFile :: !(Maybe String)+ -- ^ The path of a file containing preconfiguration of the environment (e.g shell.nix)+ ,nixMonoidShellOptions :: ![Text]+ -- ^ Options to be given to the nix-shell command line+ }+ deriving (Show)++-- | Decode uninterpreted nix options from JSON/YAML.+instance FromJSON (NixOptsMonoid, [JSONWarning]) where+ parseJSON = withObjectWarnings "DockerOptsMonoid"+ (\o -> do nixMonoidDefaultEnable <- pure True+ nixMonoidEnable <- o ..:? nixEnableArgName+ nixMonoidPackages <- o ..:? nixPackagesArgName ..!= []+ nixMonoidInitFile <- o ..:? nixInitFileArgName+ nixMonoidShellOptions <- o ..:? nixShellOptsArgName ..!= []+ return NixOptsMonoid{..})++-- | Left-biased combine nix options+instance Monoid NixOptsMonoid where+ mempty = NixOptsMonoid+ {nixMonoidDefaultEnable = False+ ,nixMonoidEnable = Nothing+ ,nixMonoidPackages = []+ ,nixMonoidInitFile = Nothing+ ,nixMonoidShellOptions = []+ }+ mappend l r = NixOptsMonoid+ {nixMonoidDefaultEnable = nixMonoidDefaultEnable l || nixMonoidDefaultEnable r+ ,nixMonoidEnable = nixMonoidEnable l <|> nixMonoidEnable r+ ,nixMonoidPackages = nixMonoidPackages l <> nixMonoidPackages r+ ,nixMonoidInitFile = nixMonoidInitFile l <|> nixMonoidInitFile r+ ,nixMonoidShellOptions = nixMonoidShellOptions l <> nixMonoidShellOptions r+ }++-- | Nix enable argument name.+nixEnableArgName :: Text+nixEnableArgName = "enable"++-- | Nix packages (build inputs) argument name.+nixPackagesArgName :: Text+nixPackagesArgName = "packages"++-- | shell.nix file path argument name.+nixInitFileArgName :: Text+nixInitFileArgName = "shell-file"++-- | Extra options for the nix-shell command argument name.+nixShellOptsArgName :: Text+nixShellOptsArgName = "nix-shell-options"
src/Stack/Types/Package.hs view
@@ -30,6 +30,7 @@ import Distribution.InstalledPackageInfo (PError) import Distribution.ModuleName (ModuleName) import Distribution.Package hiding (Package,PackageName,packageName,packageVersion,PackageIdentifier)+import Distribution.PackageDescription (TestSuiteInterface) import Distribution.System (Platform (..)) import Distribution.Text (display) import GHC.Generics@@ -87,7 +88,7 @@ ,packageAllDeps :: !(Set PackageName) -- ^ Original dependencies (not sieved). ,packageFlags :: !(Map FlagName Bool) -- ^ Flags used on package. ,packageHasLibrary :: !Bool -- ^ does the package have a buildable library stanza?- ,packageTests :: !(Set Text) -- ^ names of test suites+ ,packageTests :: !(Map Text TestSuiteInterface) -- ^ names and interfaces of test suites ,packageBenchmarks :: !(Set Text) -- ^ names of benchmarks ,packageExes :: !(Set Text) -- ^ names of executables ,packageOpts :: !GetPackageOpts -- ^ Args to pass to GHC.@@ -112,13 +113,14 @@ instance Show GetPackageOpts where show _ = "<GetPackageOpts>" +-- | GHC options based on cabal information and ghc-options. data BuildInfoOpts = BuildInfoOpts- { bioGhcOpts :: [String]- -- ^ Options from the ghc-options cabal field- , bioGeneratedOpts :: [String]- -- ^ Other options from cabal information. These options can safely have- -- 'nubOrd' applied to them, as there are no multi-word options (see+ { bioOpts :: [String]+ , bioOneWordOpts :: [String]+ -- ^ These options can safely have 'nubOrd' applied to them, as+ -- there are no multi-word options (see -- https://github.com/commercialhaskell/stack/issues/1255)+ , bioCabalMacros :: Maybe (Path Abs File) } deriving Show -- | Files to get for a cabal package.
+ src/Stack/Types/Sig.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{-|+Module : Stack.Types.Sig+Description : Signature Types+Copyright : (c) FPComplete.com, 2015+License : BSD3+Maintainer : Tim Dysinger <tim@fpcomplete.com>+Stability : experimental+Portability : POSIX+-}++module Stack.Types.Sig+ (Signature(..), Fingerprint(..), SigException(..))+ where++import Control.Exception (Exception)+import Data.Aeson (Value(..), ToJSON(..), FromJSON(..))+import Data.ByteString (ByteString)+import qualified Data.ByteString as SB+import Data.Char (isDigit, isAlpha, isSpace)+import Data.Monoid ((<>))+import Data.String (IsString(..))+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import Data.Typeable (Typeable)+import Stack.Types.PackageName++-- | A GPG signature.+newtype Signature =+ Signature ByteString+ deriving (Ord,Eq)++instance Show Signature where+ show (Signature s) = "Signature " +++ (if SB.length s > 140+ then show (SB.take 140 s) +++ "..."+ else show (SB.take 140 s))++-- | The GPG fingerprint.+newtype Fingerprint = Fingerprint+ { fingerprintSample :: Text+ } deriving (Eq,Ord,Show)++instance FromJSON Fingerprint where+ parseJSON j = do+ s <- parseJSON j+ let withoutSpaces = T.filter (not . isSpace) s+ if T.null withoutSpaces ||+ T.all+ (\c ->+ isAlpha c || isDigit c || isSpace c)+ withoutSpaces+ then return (Fingerprint withoutSpaces)+ else fail ("Expected fingerprint, but got: " ++ T.unpack s)++instance ToJSON Fingerprint where+ toJSON (Fingerprint txt) = String txt++instance IsString Fingerprint where+ fromString = Fingerprint . T.pack++instance FromJSON (Aeson PackageName) where+ parseJSON j = do+ s <- parseJSON j+ case (parsePackageName . T.encodeUtf8) s of+ Just name -> return (Aeson name)+ Nothing -> fail ("Invalid package name: " <> T.unpack s)++-- | Handy wrapper for orphan instances.+newtype Aeson a = Aeson+ { _unAeson :: a+ } deriving (Ord,Eq)++-- | Exceptions+data SigException+ = GPGFingerprintException String+ | GPGSignException String+ | GPGVerifyException String+ | SigInvalidSDistTarBall+ | SigNoProjectRootException+ | SigServiceException String+ deriving (Typeable)++instance Exception SigException++instance Show SigException where+ show (GPGFingerprintException e) =+ "Error extracting a GPG fingerprint " <> e+ show (GPGSignException e) = "Error signing with GPG " <> e+ show (GPGVerifyException e) = "Error verifying with GPG " <> e+ show SigNoProjectRootException = "Missing Project Root"+ show SigInvalidSDistTarBall = "Invalid sdist tarball"+ show (SigServiceException e) = "Error with the Signature Service " <> e
src/Stack/Types/StackT.hs view
@@ -89,8 +89,8 @@ -- | Run a Stack action, using global options. runStackTGlobal :: (MonadIO m,MonadBaseControl IO m) => Manager -> config -> GlobalOpts -> StackT config m a -> m a-runStackTGlobal manager config GlobalOpts{..} m =- runStackT manager globalLogLevel config globalTerminal (isJust globalReExecVersion) m+runStackTGlobal manager config GlobalOpts{..} =+ runStackT manager globalLogLevel config globalTerminal (isJust globalReExecVersion) -- | Run a Stack action. runStackT :: (MonadIO m,MonadBaseControl IO m)@@ -188,8 +188,8 @@ -- | Run the logging monad, using global options. runStackLoggingTGlobal :: MonadIO m => Manager -> GlobalOpts -> StackLoggingT m a -> m a-runStackLoggingTGlobal manager GlobalOpts{..} m =- runStackLoggingT manager globalLogLevel globalTerminal (isJust globalReExecVersion) m+runStackLoggingTGlobal manager GlobalOpts{..} =+ runStackLoggingT manager globalLogLevel globalTerminal (isJust globalReExecVersion) -- | Run the logging monad. runStackLoggingT :: MonadIO m@@ -317,15 +317,15 @@ return (" @(" ++ fileLocStr ++ ")") | otherwise = return "" fileLocStr =- (loc_package loc) +++ loc_package loc ++ ':' :- (loc_module loc) +++ loc_module loc ++ ' ' :- (loc_filename loc) +++ loc_filename loc ++ ':' :- (line loc) +++ line loc ++ ':' :- (char loc)+ char loc where line = show . fst . loc_start char = show . snd . loc_start
src/Stack/Types/Version.hs view
@@ -24,6 +24,7 @@ ,withinRange ,Stack.Types.Version.intersectVersionRanges ,toMajorVersion+ ,latestApplicableVersion ,checkVersion ,nextMajorVersion) where@@ -41,6 +42,9 @@ import Data.List import Data.Map (Map) import qualified Data.Map as Map+import Data.Maybe (listToMaybe)+import Data.Set (Set)+import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T import Data.Vector.Binary ()@@ -175,6 +179,11 @@ 0 -> Version (V.fromList [0, 0]) 1 -> Version (V.fromList [V.head v, 0]) _ -> Version (V.fromList [V.head v, v V.! 1])++-- | Given a version range and a set of versions, find the latest version from+-- the set that is within the range.+latestApplicableVersion :: Cabal.VersionRange -> Set Version -> Maybe Version+latestApplicableVersion r = listToMaybe . filter (`withinRange` r) . Set.toDescList -- | Get the next major version number for the given version nextMajorVersion :: Version -> Version
src/Stack/Upgrade.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE TemplateHaskell #-} module Stack.Upgrade (upgrade) where +import Control.Monad (when) import Control.Monad.Catch import Control.Monad.IO.Class import Control.Monad.Logger@@ -11,11 +12,11 @@ import Control.Monad.Trans.Control import Data.Foldable (forM_) import qualified Data.Map as Map+import Data.Maybe (isNothing) import Data.Monoid ((<>)) import qualified Data.Monoid import qualified Data.Set as Set import qualified Data.Text as T-import Development.GitRev (gitHash) import Network.HTTP.Client.Conduit (HasHttpManager) import Path import Path.IO@@ -35,25 +36,28 @@ upgrade :: (MonadIO m, MonadMask m, MonadReader env m, HasConfig env, HasHttpManager env, MonadLogger m, HasTerminal env, HasReExec env, HasLogLevel env, MonadBaseControl IO m) => Maybe String -- ^ git repository to use -> Maybe AbstractResolver+ -> Maybe String -- ^ git hash at time of building, if known -> m ()-upgrade gitRepo mresolver = withCanonicalizedSystemTempDirectory "stack-upgrade" $ \tmp -> do+upgrade gitRepo mresolver builtHash =+ withCanonicalizedSystemTempDirectory "stack-upgrade" $ \tmp -> do menv <- getMinimalEnvOverride mdir <- case gitRepo of Just repo -> do remote <- liftIO $ readProcess "git" ["ls-remote", repo, "master"] [] let latestCommit = head . words $ remote- if latestCommit == $gitHash then do- $logInfo "Already up-to-date, no upgrade required"- return Nothing- else do $logInfo "Cloning stack"- runIn tmp "git" menv- [ "clone"- , repo- , "stack"- , "--depth"- , "1"- ]- Nothing+ when (isNothing builtHash) $+ $logWarn $ "Information about the commit this version of stack was "+ <> "built from is not available due to how it was built. "+ <> "Will continue by assuming an upgrade is needed "+ <> "because we have no information to the contrary."+ if builtHash == Just latestCommit+ then do+ $logInfo "Already up-to-date, no upgrade required"+ return Nothing+ else do+ $logInfo "Cloning stack"+ let args = [ "clone", repo , "stack", "--depth", "1"]+ runCmd (Cmd (Just tmp) "git" menv args) Nothing return $ Just $ tmp </> $(mkRelDir "stack") Nothing -> do updateAllIndices menv@@ -88,7 +92,8 @@ { configMonoidInstallGHC = Just True }) (Just $ dir </> $(mkRelFile "stack.yaml"))- lcLoadBuildConfig lc mresolver Nothing+ mresolver+ lcLoadBuildConfig lc Nothing envConfig1 <- runInnerStackT bconfig $ setupEnv $ Just $ "Try rerunning with --install-ghc to install the correct GHC into " <> T.pack (toFilePath (configLocalPrograms config))
src/Stack/Upload.hs view
@@ -4,7 +4,8 @@ -- | Provide ability to upload tarballs to Hackage. module Stack.Upload ( -- * Upload- mkUploader+ nopUploader+ , mkUploader , Uploader , upload , uploadBytes@@ -180,6 +181,11 @@ fmap T.pack getLine putStrLn "" return passwd++nopUploader :: Config -> UploadSettings -> IO Uploader+nopUploader _ _ = return (Uploader nop)+ where nop :: String -> L.ByteString -> IO ()+ nop _ _ = return () -- | Turn the given settings into an @Uploader@. --
src/System/Process/Read.hs view
@@ -179,7 +179,7 @@ -- | Produce a strict 'S.ByteString' from the stdout of a process. ----- Throws a 'ProcessExitedUnsuccessfully' exception if the process fails.+-- Throws a 'ReadProcessException' exception if the process fails. readProcessStdout :: (MonadIO m, MonadLogger m, MonadBaseControl IO m, MonadCatch m) => Maybe (Path Abs Dir) -- ^ Optional directory to run in -> EnvOverride
src/System/Process/Run.hs view
@@ -5,14 +5,17 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleContexts #-}-+{-# LANGUAGE RecordWildCards #-} -- | Run sub-processes. module System.Process.Run- (runIn+ (runCmd+ ,runCmd' ,callProcess ,callProcess'- ,ProcessExitedUnsuccessfully)+ ,ProcessExitedUnsuccessfully+ ,Cmd(..)+ ) where import Control.Exception.Lifted@@ -23,38 +26,54 @@ import Data.Foldable (forM_) import Data.Text (Text) import qualified Data.Text as T-import Path (Path, Abs, Dir, toFilePath)+import Path (toFilePath) import Prelude -- Fix AMP warning import System.Exit (exitWith, ExitCode (..)) import qualified System.Process import System.Process.Read+import Path (Dir, Abs, Path) +-- | Cmd holds common infos needed to running a process in most cases+data Cmd = Cmd+ { cmdDirectoryToRunIn :: Maybe (Path Abs Dir) -- ^ directory to run in+ , cmdCommandToRun :: FilePath -- ^ command to run+ , cmdEnvOverride::EnvOverride+ , cmdCommandLineArguments :: [String] -- ^ command line arguments+ }+ -- | Run the given command in the given directory, inheriting stdout and stderr. -- -- If it exits with anything but success, prints an error -- and then calls 'exitWith' to exit the program.-runIn :: forall (m :: * -> *).+runCmd :: forall (m :: * -> *). (MonadLogger m,MonadIO m,MonadBaseControl IO m)- => Path Abs Dir -- ^ directory to run in- -> FilePath -- ^ command to run- -> EnvOverride- -> [String] -- ^ command line arguments- -> Maybe Text -- ^ optional additional error message+ => Cmd+ -> Maybe Text -- ^ optional additional error message -> m ()-runIn wd cmd menv args errMsg = do- result <- try (callProcess (Just wd) menv cmd args)+runCmd = runCmd' id++runCmd' :: forall (m :: * -> *).+ (MonadLogger m,MonadIO m,MonadBaseControl IO m)+ => (CreateProcess -> CreateProcess)+ -> Cmd+ -> Maybe Text -- ^ optional additional error message+ -> m ()+runCmd' modCP cmd@(Cmd{..}) mbErrMsg = do+ result <- try (callProcess' modCP cmd) case result of Left (ProcessExitedUnsuccessfully _ ec) -> do $logError $ T.pack $- concat+ concat $ [ "Exit code " , show ec , " while running "- , show (cmd : args)- , " in "- , toFilePath wd]- forM_ errMsg $logError+ , show (cmdCommandToRun : cmdCommandLineArguments)+ ] ++ (case cmdDirectoryToRunIn of+ Nothing -> []+ Just mbDir -> [" in ", toFilePath mbDir]+ )+ forM_ mbErrMsg $logError liftIO (exitWith ec) Right () -> return () @@ -63,14 +82,8 @@ -- process exits unsuccessfully. -- -- Inherits stdout and stderr.-callProcess :: (MonadIO m, MonadLogger m)- => Maybe (Path Abs Dir) -- ^ optional directory to run in- -> EnvOverride- -> String -- ^ command to run- -> [String] -- ^ command line arguments- -> m ()-callProcess =- callProcess' id+callProcess :: (MonadIO m, MonadLogger m) => Cmd -> m ()+callProcess = callProcess' id -- | Like 'System.Process.callProcess', but takes an optional working directory and -- environment override, and throws 'ProcessExitedUnsuccessfully' if the@@ -78,13 +91,8 @@ -- -- Inherits stdout and stderr. callProcess' :: (MonadIO m, MonadLogger m)- => (CreateProcess -> CreateProcess)- -> Maybe (Path Abs Dir) -- ^ optional directory to run in- -> EnvOverride- -> String -- ^ command to run- -> [String] -- ^ command line arguments- -> m ()-callProcess' modCP wd menv cmd0 args = do+ => (CreateProcess -> CreateProcess) -> Cmd -> m ()+callProcess' modCP (Cmd wd cmd0 menv args) = do cmd <- preProcess wd menv cmd0 let c = modCP $ (proc cmd args) { delegate_ctlc = True , cwd = fmap toFilePath wd
src/main/Main.hs view
@@ -9,7 +9,7 @@ -- | Main stack tool entry point. -module Main where+module Main (main) where import Control.Exception import qualified Control.Exception.Lifted as EL@@ -34,8 +34,10 @@ import Data.Traversable import Data.Typeable (Typeable) import Data.Version (showVersion)-import Development.GitRev (gitCommitCount)-import Distribution.System (buildArch)+#ifdef USE_GIT_INFO+import Development.GitRev (gitCommitCount, gitHash)+#endif+import Distribution.System (buildArch, buildPlatform) import Distribution.Text (display) import GHC.IO.Encoding (mkTextEncoding, textEncodingName) import Network.HTTP.Client@@ -43,7 +45,9 @@ import Options.Applicative.Args import Options.Applicative.Builder.Extra import Options.Applicative.Complicated+#ifdef USE_GIT_INFO import Options.Applicative.Simple (simpleVersion)+#endif import Options.Applicative.Types (readerAsk) import Path import Path.Extra (toFilePathNoTrailingSep)@@ -59,6 +63,7 @@ import qualified Stack.Docker as Docker import Stack.Dot import Stack.Exec+import qualified Stack.Nix as Nix import Stack.Fetch import Stack.FileWatch import Stack.GhcPkg (getGlobalDB, mkGhcPackagePath)@@ -70,8 +75,9 @@ import Stack.Options import Stack.Package (getCabalFileName) import qualified Stack.PackageIndex-import Stack.SDist (getSDistTarball)+import Stack.SDist (getSDistTarball, checkSDistTarball, checkSDistTarball') import Stack.Setup+import qualified Stack.Sig as Sig import Stack.Solver (solveExtraDeps) import Stack.Types import Stack.Types.Internal@@ -79,6 +85,7 @@ import Stack.Upgrade import qualified Stack.Upload as Upload import System.Directory (canonicalizePath, doesFileExist, doesDirectoryExist, createDirectoryIfMissing)+import qualified System.Directory as Directory (findExecutable) import System.Environment (getEnvironment, getProgName) import System.Exit import System.FileLock (lockFile, tryLockFile, unlockFile, SharedExclusive(Exclusive), FileLock)@@ -114,6 +121,11 @@ dockerHelpOptName (dockerOptsParser False) ("Only showing --" ++ Docker.dockerCmdName ++ "* options.")+ execExtraHelp args+ nixHelpOptName+ (nixOptsParser False)+ ("Only showing --" ++ Nix.nixCmdName ++ "* options.")+#ifdef USE_GIT_INFO let commitCount = $gitCommitCount versionString' = concat $ concat [ [$(simpleVersion Meta.version)]@@ -123,9 +135,13 @@ commitCount /= ("UNKNOWN" :: String)] , [" ", display buildArch] ]+#else+ let versionString' = showVersion Meta.version ++ ' ' : display buildArch+#endif let globalOpts hide = extraHelpOption hide progName (Docker.dockerCmdName ++ "*") dockerHelpOptName <*>+ extraHelpOption hide progName (Nix.nixCmdName ++ "*") nixHelpOptName <*> globalOptsParser hide addCommand' cmd title footerStr constr = addCommand cmd title footerStr constr (globalOpts True)@@ -138,6 +154,21 @@ "stack - The Haskell Tool Stack" "" (globalOpts False)+ -- when there's a parse failure+ (Just $ \f as ->+ -- fall-through to external executables in `git` style if they exist+ -- (i.e. `stack something` looks for `stack-something` before+ -- failing with "Invalid argument `something'")+ case stripPrefix "Invalid argument" (fst (renderFailure f "")) of+ Just _ -> do+ mExternalExec <- Directory.findExecutable ("stack-" ++ head as)+ case mExternalExec of+ Just ex -> do+ menv <- getEnvOverride buildPlatform+ runNoLoggingT (exec menv ex (tail as))+ Nothing -> handleParseResult (Failure f)+ Nothing -> handleParseResult (Failure f)+ ) (do addCommand' "build" "Build the package(s) in this directory/configuration" cmdFooter@@ -230,16 +261,21 @@ "Upload a package to Hackage" cmdFooter uploadCmd- ((,)+ ((,,,) <$> many (strArgument $ metavar "TARBALL/DIR")- <*> optional pvpBoundsOption)+ <*> optional pvpBoundsOption+ <*> ignoreCheckSwitch+ <*> flag False True+ (long "sign" <>+ help "GPG sign & submit signature")) addCommand' "sdist" "Create source distribution tarballs" cmdFooter sdistCmd- ((,)+ ((,,) <$> many (strArgument $ metavar "DIR")- <*> optional pvpBoundsOption)+ <*> optional pvpBoundsOption+ <*> ignoreCheckSwitch) addCommand' "dot" "Visualize your project's dependency graph using Graphviz dot" cmdFooter@@ -379,7 +415,21 @@ "Generate HPC report a combined HPC report" cmdFooter hpcReportCmd- hpcReportOptsParser))+ hpcReportOptsParser)+ addSubCommands'+ Sig.sigCmdName+ "Subcommands specific to package signatures (EXPERIMENTAL)"+ cmdFooter+ (addSubCommands'+ Sig.sigSignCmdName+ "Sign a a single package or all your packages"+ cmdFooter+ (addCommand'+ Sig.sigSignSdistCmdName+ "Sign a single sdist package file"+ cmdFooter+ sigSignSdistCmd+ Sig.sigSignSdistOpts))) case eGlobalRun of Left (exitCode :: ExitCode) -> do when isInterpreter $@@ -408,7 +458,9 @@ printExceptionStderr e exitFailure where+ ignoreCheckSwitch = switch (long "ignore-check" <> help "Do not check package for common mistakes") dockerHelpOptName = Docker.dockerCmdName ++ "-help"+ nixHelpOptName = Nix.nixCmdName ++ "-help" cmdFooter = "Run 'stack --help' for global options that apply to all subcommands." -- | Print out useful path information in a human-readable format (and@@ -586,16 +638,18 @@ setupCmd SetupCmdOpts{..} go@GlobalOpts{..} = do (manager,lc) <- loadConfigWithOpts go withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk ->- runStackTGlobal manager (lcConfig lc) go $+ runStackTGlobal manager (lcConfig lc) go $ Docker.reexecWithOptionalContainer (lcProjectRoot lc) Nothing- (runStackLoggingTGlobal manager go $ do+ (runStackTGlobal manager (lcConfig lc) go $+ Nix.reexecWithOptionalShell $+ runStackLoggingTGlobal manager go $ do (wantedCompiler, compilerCheck, mstack) <- case scoCompilerVersion of Just v -> return (v, MatchMinor, Nothing) Nothing -> do- bc <- lcLoadBuildConfig lc globalResolver globalCompiler+ bc <- lcLoadBuildConfig lc globalCompiler return ( bcWantedCompiler bc , configCompilerCheck (lcConfig lc) , Just $ bcStackYaml bc@@ -739,7 +793,7 @@ let inner'' lk = do bconfig <- runStackLoggingTGlobal manager go $- lcLoadBuildConfig lc globalResolver globalCompiler+ lcLoadBuildConfig lc globalCompiler envConfig <- runStackTGlobal manager bconfig go@@ -751,10 +805,16 @@ (inner' lk) runStackTGlobal manager (lcConfig lc) go $- Docker.reexecWithOptionalContainer (lcProjectRoot lc) mbefore (inner'' lk0) mafter- (Just $ liftIO $- do lk' <- readIORef curLk- munlockFile lk')+ Docker.reexecWithOptionalContainer+ (lcProjectRoot lc)+ mbefore+ (runStackTGlobal manager (lcConfig lc) go $+ Nix.reexecWithOptionalShell (inner'' lk0)+ )+ mafter+ (Just $ liftIO $+ do lk' <- readIORef curLk+ munlockFile lk') cleanCmd :: CleanOpts -> GlobalOpts -> IO () cleanCmd opts go = withBuildConfigAndLock go (const (clean opts))@@ -794,12 +854,18 @@ upgradeCmd :: (Bool, String) -> GlobalOpts -> IO () upgradeCmd (fromGit, repo) go = withConfigAndLock go $- upgrade (if fromGit then Just repo else Nothing) (globalResolver go)+ upgrade (if fromGit then Just repo else Nothing)+ (globalResolver go)+#ifdef USE_GIT_INFO+ (find (/= "UNKNOWN") [$gitHash])+#else+ Nothing+#endif -- | Upload to Hackage-uploadCmd :: ([String], Maybe PvpBounds) -> GlobalOpts -> IO ()-uploadCmd ([], _) _ = error "To upload the current package, please run 'stack upload .'"-uploadCmd (args, mpvpBounds) go = do+uploadCmd :: ([String], Maybe PvpBounds, Bool, Bool) -> GlobalOpts -> IO ()+uploadCmd ([], _, _, _) _ = error "To upload the current package, please run 'stack upload .'"+uploadCmd (args, mpvpBounds, ignoreCheck, shouldSign) go = do let partitionM _ [] = return ([], []) partitionM f (x:xs) = do r <- f x@@ -810,6 +876,7 @@ unless (null invalid) $ error $ "stack upload expects a list sdist tarballs or cabal directories. Can't find " ++ show invalid+ (_,lc) <- liftIO $ loadConfigWithOpts go let getUploader :: (HasStackRoot config, HasPlatform config, HasConfig config) => StackT config IO Upload.Uploader getUploader = do config <- asks getConfig@@ -817,20 +884,40 @@ let uploadSettings = Upload.setGetManager (return manager) Upload.defaultUploadSettings liftIO $ Upload.mkUploader config uploadSettings- if null dirs- then withConfigAndLock go $ do- uploader <- getUploader- liftIO $ forM_ files (canonicalizePath >=> Upload.upload uploader)- else withBuildConfigAndLock go $ \_ -> do- uploader <- getUploader- liftIO $ forM_ files (canonicalizePath >=> Upload.upload uploader)+ sigServiceUrl = "https://sig.commercialhaskell.org/"+ withBuildConfigAndLock go $ \_ -> do+ uploader <- getUploader+ unless ignoreCheck $+ mapM_ (parseRelAsAbsFile >=> checkSDistTarball) files+ forM_+ files+ (\file ->+ do tarFile <- parseRelAsAbsFile file+ liftIO+ (Upload.upload uploader (toFilePath tarFile))+ when+ shouldSign+ (Sig.sign+ (lcProjectRoot lc)+ sigServiceUrl+ tarFile))+ unless (null dirs) $ forM_ dirs $ \dir -> do- pkgDir <- parseAbsDir =<< liftIO (canonicalizePath dir)+ pkgDir <- parseRelAsAbsDir dir (tarName, tarBytes) <- getSDistTarball mpvpBounds pkgDir+ unless ignoreCheck $ checkSDistTarball' tarName tarBytes liftIO $ Upload.uploadBytes uploader tarName tarBytes+ tarPath <- parseRelFile tarName+ when+ shouldSign+ (Sig.signTarBytes+ (lcProjectRoot lc)+ sigServiceUrl+ tarPath+ tarBytes) -sdistCmd :: ([String], Maybe PvpBounds) -> GlobalOpts -> IO ()-sdistCmd (dirs, mpvpBounds) go =+sdistCmd :: ([String], Maybe PvpBounds, Bool) -> GlobalOpts -> IO ()+sdistCmd (dirs, mpvpBounds, ignoreCheck) go = withBuildConfig go $ do -- No locking needed. -- If no directories are specified, build all sdist tarballs. dirs' <- if null dirs@@ -842,6 +929,7 @@ tarPath <- (distDir </>) <$> parseRelFile tarName liftIO $ createTree $ parent tarPath liftIO $ L.writeFile (toFilePath tarPath) tarBytes+ unless ignoreCheck (checkSDistTarball tarPath) $logInfo $ "Wrote sdist tarball to " <> T.pack (toFilePath tarPath) -- | Execute a command.@@ -855,17 +943,22 @@ (ExecRunGhc, args) -> return ("runghc", args) (manager,lc) <- liftIO $ loadConfigWithOpts go withUserFileLock go (configStackRoot $ lcConfig lc) $ \lk ->- runStackTGlobal manager (lcConfig lc) go $+ runStackTGlobal manager (lcConfig lc) go $ Docker.reexecWithOptionalContainer (lcProjectRoot lc) -- Unlock before transferring control away, whether using docker or not: (Just $ munlockFile lk)- (runStackTGlobal manager (lcConfig lc) go $- exec plainEnvSettings cmd args)+ (runStackTGlobal manager (lcConfig lc) go $ do+ config <- asks getConfig+ menv <- liftIO $ configEnvOverride config plainEnvSettings+ Nix.reexecWithOptionalShell+ (runStackTGlobal manager (lcConfig lc) go $+ exec menv cmd args)) Nothing Nothing -- Unlocked already above. ExecOptsEmbellished {..} -> withBuildConfigAndLock go $ \lk -> do+ config <- asks getConfig (cmd, args) <- case (eoCmd, eoArgs) of (ExecCmd cmd, args) -> return (cmd, args) (ExecGhc, args) -> execCompiler "" args@@ -878,7 +971,8 @@ { boptsTargets = map T.pack targets } munlockFile lk -- Unlock before transferring control away.- exec eoEnvSettings cmd args+ menv <- liftIO $ configEnvOverride config eoEnvSettings+ exec menv cmd args where execCompiler cmdPrefix args = do wc <- getWhichCompiler@@ -930,7 +1024,7 @@ targetsCmd target go@GlobalOpts{..} = withBuildConfig go $ do let bopts = defaultBuildOpts { boptsTargets = [target] }- (_realTargets,_,pkgs) <- ghciSetup bopts False Nothing+ (_realTargets,_,pkgs) <- ghciSetup bopts False False Nothing pwd <- getWorkingDir targets <- fmap@@ -953,7 +1047,7 @@ (manager,lc) <- liftIO (loadConfigWithOpts go) -- TODO: can we eliminate this lock if it doesn't touch ~/.stack/? withUserFileLock go (configStackRoot $ lcConfig lc) $ \_ ->- runStackLoggingTGlobal manager go $+ runStackTGlobal manager (lcConfig lc) go $ Docker.preventInContainer $ Docker.reset (lcProjectRoot lc) keepHome -- | Cleanup Docker images and containers.@@ -988,6 +1082,18 @@ Image.stageContainerImageArtifacts) (Just Image.createContainerImageFromStage) +sigSignSdistCmd :: (String, String) -> GlobalOpts -> IO ()+sigSignSdistCmd (url,path) go =+ withConfigAndLock+ go+ (do (manager,lc) <- liftIO (loadConfigWithOpts go)+ tarBall <- parseRelAsAbsFile path+ runStackTGlobal+ manager+ (lcConfig lc)+ go+ (Sig.sign (lcProjectRoot lc) url tarBall))+ -- | Load the configuration with a manager. Convenience function used -- throughout this module. loadConfigWithOpts :: GlobalOpts -> IO (Manager,LoadConfig (StackLoggingT IO))@@ -1000,7 +1106,7 @@ path <- canonicalizePath fp >>= parseAbsFile return $ Just path lc <- runStackLoggingTGlobal manager go $ do- lc <- loadConfig globalConfigMonoid mstackYaml+ lc <- loadConfig globalConfigMonoid mstackYaml globalResolver -- If we have been relaunched in a Docker container, perform in-container initialization -- (switch UID, etc.). We do this after first loading the configuration since it must -- happen ASAP but needs a configuration.
src/test/Stack/BuildPlanSpec.hs view
@@ -40,7 +40,7 @@ spec :: Spec spec = beforeAll setup $ afterAll teardown $ do let logLevel = LevelDebug- let loadConfig' m = runStackLoggingT m logLevel False False (loadConfig mempty Nothing)+ let loadConfig' m = runStackLoggingT m logLevel False False (loadConfig mempty Nothing Nothing) let loadBuildConfigRest m = runStackLoggingT m logLevel False False let inTempDir action = do currentDirectory <- getCurrentDirectory@@ -54,7 +54,7 @@ -- github still depends on failure. writeFile "stack.yaml" "resolver: lts-2.9" LoadConfig{..} <- loadConfig' manager- bconfig <- loadBuildConfigRest manager (lcLoadBuildConfig Nothing Nothing)+ bconfig <- loadBuildConfigRest manager (lcLoadBuildConfig Nothing) runStackT manager logLevel bconfig False False $ do mbp <- loadMiniBuildPlan $ LTS 2 9 eres <- try $ resolveBuildPlan
src/test/Stack/ConfigSpec.hs view
@@ -62,7 +62,7 @@ describe "loadConfig" $ do- let loadConfig' m = runStackLoggingT m logLevel False False (loadConfig mempty Nothing)+ let loadConfig' m = runStackLoggingT m logLevel False False (loadConfig mempty Nothing Nothing) let loadBuildConfigRest m = runStackLoggingT m logLevel False False -- TODO(danburton): make sure parent dirs also don't have config file it "works even if no config file exists" $ \T{..} -> example $ do@@ -82,7 +82,7 @@ setCurrentDirectory childDir LoadConfig{..} <- loadConfig' manager bc@BuildConfig{..} <- loadBuildConfigRest manager- (lcLoadBuildConfig Nothing Nothing)+ (lcLoadBuildConfig Nothing) bcRoot bc `shouldBe` parentDir it "respects the STACK_YAML env variable" $ \T{..} -> inTempDir $ do@@ -92,7 +92,7 @@ withEnvVar "STACK_YAML" stackYamlFp $ do LoadConfig{..} <- loadConfig' manager BuildConfig{..} <- loadBuildConfigRest manager- (lcLoadBuildConfig Nothing Nothing)+ (lcLoadBuildConfig Nothing) bcStackYaml `shouldBe` dir </> stackDotYaml parent bcStackYaml `shouldBe` dir @@ -106,5 +106,5 @@ withEnvVar "STACK_YAML" (toFilePath yamlRel) $ do LoadConfig{..} <- loadConfig' manager BuildConfig{..} <- loadBuildConfigRest manager- (lcLoadBuildConfig Nothing Nothing)+ (lcLoadBuildConfig Nothing) bcStackYaml `shouldBe` yamlAbs
+ src/test/Stack/NixSpec.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell, OverloadedStrings #-}+module Stack.NixSpec where++import Test.Hspec++import Control.Monad.Logger+import Control.Exception+import Data.Monoid+import Network.HTTP.Conduit (Manager)+import System.Environment+import Path+import System.Directory+import System.IO.Temp (withSystemTempDirectory)++import Stack.Config+import Stack.Types.Config+import Stack.Types.StackT+import Stack.Types.Nix++import Prelude -- to remove the warning about Data.Monoid being redundant on GHC 7.10+++sampleConfig :: String+sampleConfig =+ "resolver: lts-2.10\n" +++ "packages: ['.']\n" +++ "nix:\n" +++ " enable: True\n" +++ " packages: [glpk]"++stackDotYaml :: Path Rel File+stackDotYaml = $(mkRelFile "stack.yaml")++data T = T+ { manager :: Manager+ }++setup :: IO T+setup = do+ manager <- newTLSManager+ unsetEnv "STACK_YAML"+ return T{..}++teardown :: T -> IO ()+teardown _ = return ()++spec :: Spec+spec = beforeAll setup $ afterAll teardown $ do+ let loadConfig' m = runStackLoggingT m LevelDebug False False (loadConfig mempty Nothing Nothing)+ inTempDir action = do+ currentDirectory <- getCurrentDirectory+ withSystemTempDirectory "Stack_ConfigSpec" $ \tempDir -> do+ let enterDir = setCurrentDirectory tempDir+ exitDir = setCurrentDirectory currentDirectory+ bracket_ enterDir exitDir action+ describe "nix" $ do+ it "sees that the nix shell is enabled" $ \T{..} -> inTempDir $ do+ writeFile (toFilePath stackDotYaml) sampleConfig+ lc <- loadConfig' manager+ (nixEnable $ configNix $ lcConfig lc) `shouldBe` True+ it "sees that the only package asked for is glpk and adds GHC from nixpkgs mirror of LTS resolver" $ \T{..} -> inTempDir $ do+ writeFile (toFilePath stackDotYaml) sampleConfig+ lc <- loadConfig' manager+ (nixPackages $ configNix $ lcConfig lc) `shouldBe` ["glpk", "haskell.packages.lts-2_10.ghc"]+
stack.cabal view
@@ -1,11 +1,11 @@ name: stack-version: 0.1.8.0+version: 0.1.10.0 cabal-version: >=1.10 build-type: Simple license: BSD3 license-file: LICENSE maintainer: manny@fpcomplete.com-homepage: https://github.com/commercialhaskell/stack+homepage: http://haskellstack.org synopsis: The Haskell Tool Stack description: Please see the README.md for usage information, and@@ -19,19 +19,6 @@ CONTRIBUTING.md ChangeLog.md README.md- doc/GUIDE.md- doc/MAINTAINER_GUIDE.md- doc/SIGNING_KEY.md- doc/architecture.md- doc/build_command.md- doc/dependency_visualization.md- doc/docker_integration.md- doc/faq.md- doc/install_and_upgrade.md- doc/nonstandard_project_init.md- doc/shell_autocompletion.md- doc/stack_and_ghcjs.md- doc/yaml_configuration.md test/package-dump/ghc-7.8.txt test/package-dump/ghc-7.8.4-osx.txt test/package-dump/ghc-7.10.txt@@ -39,7 +26,7 @@ source-repository head type: git- location: https://github.com/commercialhaskell/stack+ location: https://github.com/commercialhaskell/stack.git flag integration-tests description:@@ -47,6 +34,12 @@ default: False manual: True +flag disable-git-info+ description:+ Disable compile-time inclusion of current git info in stack+ default: False+ manual: True+ library if os(windows)@@ -64,6 +57,7 @@ Stack.Clean Stack.Config Stack.Config.Docker+ Stack.Config.Nix Stack.ConfigCmd Stack.Constants Stack.Coverage@@ -76,6 +70,7 @@ Stack.GhcPkg Stack.Init Stack.New+ Stack.Nix Stack.Options Stack.Package Stack.PackageDump@@ -96,11 +91,13 @@ Stack.Types.FlagName Stack.Types.GhcPkgId Stack.Types.Image+ Stack.Types.Nix Stack.Types.PackageIdentifier Stack.Types.PackageIndex Stack.Types.PackageName Stack.Types.TemplateName Stack.Types.Version+ Stack.Types.Sig Stack.Types.StackT Stack.Types.Build Stack.Types.Package@@ -112,6 +109,9 @@ Stack.Build.Installed Stack.Build.Source Stack.Build.Target+ Stack.Sig+ Stack.Sig.GPG+ Stack.Sig.Sign Stack.Upgrade Stack.Upload System.Process.Read@@ -128,7 +128,7 @@ ansi-terminal >=0.6.2.3 && <0.7, async >=2.0.2 && <2.1, attoparsec >=0.12.1.5 && <0.14,- base ==4.*,+ base >=4.7 && <5, base16-bytestring >=0.1.1.6 && <0.2, base64-bytestring >=1.0.0.1 && <1.1, bifunctors >=4.2.1 && <5.1,@@ -153,7 +153,6 @@ filelock >=0.1.0.1 && <0.2, filepath >=1.3.0.2 && <1.5, fsnotify >=0.2.1 && <0.3,- gitrev ==1.1.*, hashable >=1.2.3.2 && <1.3, hpc >=0.6.0.2 && <0.7, http-client >=0.4.17 && <0.5,@@ -176,12 +175,12 @@ resourcet >=1.1.4.1 && <1.2, retry >=0.6 && <0.8, safe ==0.3.*,- semigroups >=0.5 && <0.17,+ semigroups >=0.5 && <0.18, split >=0.2.2 && <0.3, stm >=2.4.4 && <2.5, streaming-commons >=0.1.10.0 && <0.2, tar >=0.4.1.0 && <0.5,- template-haskell >=2.10.0.0 && <2.11,+ template-haskell >=2.9.0.0 && <2.11, temporary >=1.2.0.3 && <1.3, text >=1.2.0.4 && <1.3, time >=1.4.2 && <1.6,@@ -198,7 +197,9 @@ file-embed >=0.0.9 && <0.1, word8 >=0.1.2 && <0.2, hastache >=0.6.1 && <0.7,- project-template ==0.2.*+ project-template ==0.2.*,+ email-validate >=2.0 && <2.2,+ uuid >=1.3.11 && <1.4 default-language: Haskell2010 hs-source-dirs: src/ other-modules:@@ -221,6 +222,12 @@ build-depends: Win32 >=2.3.1.0 && <2.4 cpp-options: -DWINDOWS+ + if !flag(disable-git-info)+ build-depends:+ gitrev ==1.1.*,+ optparse-simple >=0.0.3 && <0.1+ cpp-options: -DUSE_GIT_INFO main-is: Main.hs build-depends: base >=4.7 && <5,@@ -230,7 +237,6 @@ exceptions >=0.8.0.2 && <0.9, filepath >=1.4.0.0 && <1.5, filelock >=0.1.0.1 && <0.2,- gitrev ==1.1.*, http-conduit >=2.1.5 && <2.2, lifted-base >=0.2.3.6 && <0.3, monad-control >=1.0.0.4 && <1.1,@@ -238,18 +244,17 @@ mtl >=2.1.3.1 && <2.3, old-locale >=1.0.0.6 && <1.1, optparse-applicative >=0.11.0.2 && <0.12,- optparse-simple >=0.0.3 && <0.1, path >=0.5.2 && <0.6, process >=1.2.3.0 && <1.3, resourcet >=1.1.4.1 && <1.2,- stack >=0.1.8.0 && <0.2,+ stack >=0.1.10.0 && <0.2, text >=1.2.0.4 && <1.3, either >=4.4.1 && <4.5, directory >=1.2.2.0 && <1.3, split >=0.2.2 && <0.3, unordered-containers >=0.2.5.1 && <0.3, hashable >=1.2.3.3 && <1.3,- conduit >=1.2.5 && <1.3,+ conduit >=1.2.5.1 && <1.3, transformers >=0.4.2.0 && <0.5, http-client >=0.4.24 && <0.5 default-language: Haskell2010@@ -263,19 +268,19 @@ main-is: Test.hs build-depends: base >=4.7 && <5,- hspec >=2.1.10 && <2.2,+ hspec >=2.1.10 && <2.3, containers >=0.5.6.2 && <0.6, directory >=1.2.2.0 && <1.3, exceptions >=0.8.0.2 && <0.9, filepath >=1.4.0.0 && <1.5, path >=0.5.2 && <0.6, temporary >=1.2.0.3 && <1.3,- stack >=0.1.8.0 && <0.2,- monad-logger >=0.3.13.2 && <0.4,+ stack >=0.1.10.0 && <0.2,+ monad-logger >=0.3.15 && <0.4, http-conduit >=2.1.8 && <2.2, cryptohash >=0.11.6 && <0.12, transformers >=0.4.2.0 && <0.5,- conduit >=1.2.5 && <1.3,+ conduit >=1.2.5.1 && <1.3, conduit-extra >=1.1.9.1 && <1.2, resourcet >=1.1.6 && <1.2, Cabal >=1.22.4.0 && <1.23,@@ -295,6 +300,7 @@ Stack.DotSpec Stack.PackageDumpSpec Stack.ArgsSpec+ Stack.NixSpec Network.HTTP.Download.VerifiedSpec ghc-options: -Wall -threaded test-suite stack-integration-test@@ -304,16 +310,16 @@ type: exitcode-stdio-1.0 main-is: IntegrationSpec.hs build-depends:- base >=4.7 && <10,+ base >=4.7 && <5, temporary >=1.2.0.3 && <1.3,- hspec >=2.1.10 && <2.2,+ hspec >=2.1.10 && <2.3, process >=1.2.3.0 && <1.3, filepath >=1.4.0.0 && <1.5, directory >=1.2.2.0 && <1.3, text >=1.2.1.3 && <1.3, unix-compat >=0.4.1.4 && <0.5, containers >=0.5.6.2 && <0.6,- conduit >=1.2.5 && <1.3,+ conduit >=1.2.5.1 && <1.3, conduit-extra >=1.1.9.1 && <1.2, resourcet >=1.1.6 && <1.2, async >=2.0.2 && <2.1,
stack.yaml view
@@ -1,5 +1,4 @@-resolver: lts-3.7-extra-deps: []+resolver: lts-3.14 image: container: base: "fpco/ubuntu-with-libgmp:14.04"
test/integration/lib/StackTest.hs view
@@ -41,6 +41,18 @@ then error "stack was supposed to fail, but didn't" else return () +-- | Run stack with arguments and apply a check to the resulting+-- stderr output if the process succeeded.+stackCheckStderr :: [String] -> (String -> IO ()) -> IO ()+stackCheckStderr args check = do+ stack <- getEnv "STACK_EXE"+ logInfo $ "Running: " ++ stack ++ " " ++ intercalate " " (map showProcessArgDebug args)+ (ec, _, err) <- readProcessWithExitCode stack args ""+ hPutStr stderr err+ if ec /= ExitSuccess+ then error $ "Exited with exit code: " ++ show ec+ else check err+ doesNotExist :: FilePath -> IO () doesNotExist fp = do logInfo $ "doesNotExist " ++ fp