Prevent stack from recompiling external dependencies - haskell

I am relatively new to stack and haskell. Before I explain my question, let me explain our development setup. We use jenkins to build our repo. The haskell project will be a small subset of a larger python project. The haskell project is mainly used to generate artifacts.
The jenkins master does a git clean each time before building a git branch. My haskell project has some external dependency like argparser & aeson. Each time my build scripts execute a stack build, these external dependencies get compiled because they are deleted when jenkins executes the git clean command.
Is there anyway to tell stack to download the external deps to a global folder outside the project folder? Like the global-pkg-db path instead of the .stack-work folder? What is the best way to prevent stack to not recompile the external dependencies?
Should I download argparser & aeson into a custom folder and pass that path into extra-lib-dirs?
# This file was automatically generated by stack init
# For more information, see: http://docs.haskellstack.org/en/stable/yaml_configuration/
# Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2)
resolver: lts-5.8
# Local packages, usually specified by relative directory name
packages:
- '.'
# Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3)
extra-deps:
- aeson-0.11.1.1
- argparser-0.3.4
- text-1.2.2.0
# Override default flag values for local packages and extra-deps
flags: {}
# Extra package databases containing global packages
extra-package-dbs: []

Related

Create directory for configuration when running cargo install

I built a tool that requires configuration by means of a config.yaml. I'd like to provide a basic version of that file along with the installation. Is it possible to have customizable task carried out (such as creating a directory under /etc/mytool/ and creating a file herein) when running cargo install --path .?
Build Scripts are your friend.
The Rust file designated by the build command (relative to the package root) will be compiled and invoked before anything else is compiled in the package, allowing your Rust code to depend on the built or generated artifacts. By default Cargo looks up for "build.rs" file in a package root (even if you do not specify a value for build).
Use build = "custom_build_name.rs" to specify a custom build name, e.g. add in Cargo.toml:
[package]
# ...
build = "custom_build_name.rs"

gitlab-CI for a Haskell Stack project: How to cache built libraries?

I'm using the following .gitlab-ci.yml file for setting up gitlab-CI for a Haskell Stack project created with stack new actividad3 --resolver=lts-14.6.
image: haskell:8.6.5
cache:
paths:
- .stack
- .stack-work
- target
test:
stage: test
script:
- ghc --version
- stack --system-ghc build
- stack test
Building and testing the project last almost 5 minutes. Most of the time is spent building the hspec library. Is there any way to cache the used libraries between pipeline runs?
Thanks in advance.
Add these parts to your .gitlab-ci.yml:
variables:
STACK_ROOT: "${CI_PROJECT_DIR}/.stack-root"
cache:
paths:
- .stack-work/
- .stack-root/
The $STACK_ROOT env variable changes the folder stack uses for it's global files. This is required because GitLab CI can only cache files under the project folder, so caching $HOME/.stack, ~/.stack or /root/.stack won't work.
A few relevant references from the web:
http://blog.braulio.me/2018/10/24/use-haskell-stack-gitlab-ci.html;
https://vadosware.io/post/zero-to-continuous-integrated-testing-a-haskell-project-with-gitlab/
https://dev.to/drbearhands/haskell-for-madmen-setup-4cj9
https://github.com/bitemyapp/haskell-continuous-integration/blob/master/.gitlab-ci.yml
Most important for proper caching of a stack project is saving all folders being involved:
Project work directory (or many directories if it is a multi-package setup), usually .stack-work
Global stack directory, usually ~/.stack
Possibly a separate folder with binaries (ghc, ghc-pkg, ...)
These can vary between the operating systems and customized with environment variables, but can be easily discovered by asking stack itself. Run stack path within a stack project and you'll see all of the paths that stack might care about. These are the ones you'll need to cache and restore on CI in order to prevent recompilation:
stack path --stack-root
.stack-work directories in all of the packages within the project (paths from
packages in stack.yaml)
on Windows stack path --programs
Just in case, if you want to see how this stuff can be derived programmatically from Haskell itself, you can find it here
I wrote this tool called cache-s3 a while back that allows you to use an AWS S3 bucket as cache for your CI and it has separate mode that will save and restore all of the stack related directories. This is probably an overkill for a simple project, so the gitlab's caching mechanism will likely be sufficient, but in case you need it is an option.

Prevent rebuilding external dependency

I'm new to Haskell.
I cloned a Haskell project (pandoc) from github, and compiled it with:
stack setup
stack install --test
After a while, the project is built.
Now I want to build another project (pandoc-crossref), an extension to the first one and which depends on it.
There is an extra-deps entry for pandoc in stack.yaml:
extra-deps:
...
- pandoc-2.0.1.1
...
In the README.md of the pandoc-crossref project I can see:
Pandoc will also be built, if it's not installed as a Haskell library system-wide.
But when I try to build pandoc-crossref, pandoc is built again.
What does installed as a Haskell library system-wide mean? Is it possible to prevent the first project being built again? Maybe by using the --extra-lib-dirs option?

Create hackage package that can be installed with stack

When running stack sdist in my project directory, the stack.yaml file isn't included in the tarball (this seems to be expected).
Consequently, when I upload the tarball to hackage, then stack install mypackage it complains about missing dependencies (extra-deps) which I specified in the stack.yaml file.
$ stack install pandoc-placetable
Run from outside a project, using implicit global project config
Using resolver: lts-5.17 from implicit global project's config file: ~/.stack/global-project/stack.yaml
While constructing the BuildPlan the following exceptions were encountered:
-- Failure when adding dependencies:
spreadsheet: needed (>=0.1.3 && <0.1.4), not present in build plan (latest applicable is 0.1.3.4)
needed for package: pandoc-placetable-0.4
-- While attempting to add dependency,
Could not find package spreadsheet in known packages
Recommended action: try adding the following to your extra-deps in /Users/maurobieg/.stack/global-project/stack.yaml
- spreadsheet-0.1.3.4
Or what's the recommended way to make a hackage package stack-installable if it has further hackage dependencies?
Update: I just added extra-source-files: stack.yaml to the cabal file and the stack.yaml is indeed included in the tarbal of the newly published version. Nevertheless, stack install pandoc-placetable-0.4.1 still comes up with the same error.
I could also just tell people who don't want to install cabal-install on their system to clone from GitHub, then build with stack. Is that the recommended approach for tiny packages? Or should I ask them to include the dependency of pandoc-placetable (i.e. spreadsheet) in their global stack.yaml? Smells like polluting a global file...
As mentioned by #mgsloan in the comments above: There's an open stack issue about using stack.yaml from hackage package.
I guess until it's fixed I'll just tell people to clone from GitHub (or as mentioned by #MichaelSnoyman to stack unpack) and then cd into the newly created directory and stack install there.

Failure to install hsev on Windows 10 via `stack install hsdev`

I get this error when running stack install hsdev outside and inside of a project:
λ stack install hsdev
Run from outside a project, using implicit global project config
Using resolver: lts-5.11 from implicit global project's config file: C:\Users\atc\AppData\Roaming\stack\global-project\stack.yaml
While constructing the BuildPlan the following exceptions were encountered:
-- While attempting to add dependency,
Could not find package hformat in known packages
-- Failure when adding dependencies:
hformat: needed (>=0.1), stack configuration has no specified version (latest applicable is 0.1.0.0)
simple-log: needed (>=0.3.4), stack configuration has no specified version (latest applicable is 0.3.4)
text-region: needed (>=0.1), stack configuration has no specified version (latest applicable is 0.1.0.0)
needed for package hsdev-0.1.8.2
-- While attempting to add dependency,
Could not find package simple-log in known packages
-- While attempting to add dependency,
Could not find package text-region in known packages
Recommended action: try adding the following to your extra-deps in C:\Users\atc\AppData\Roaming\stack\global-project\stack.yaml
- hformat-0.1.0.0
- simple-log-0.3.4
- text-region-0.1.0.0
I have run stack update prior to attempting this. I want to install hsdev so I can use SublimeHaskell.
stack solver gives:
λ stack solver
Run from outside a project, using implicit global project config
Using resolver: lts-5.11 from implicit global project's config file: C:\Users\atc\AppData\Roaming\stack\global-project\stack.yaml
Using configuration file: AppData\Roaming\stack\global-project\stack.yaml
The following packages are missing from the config:
<snip long list of references to directories in AppData\Local\Temp\stack14228\>
No cabal packages found in AppData\Roaming\stack\global-project\stack.yaml. Please add at least one directory containing a .cabal file. You can also use 'stack init' to automatically generate the config file.
Relevant stack info:
λ stack --version
Version 1.0.4, Git revision cf18703b1392a96a5a4896a560309e501af63260 (3220 commits) x86_6
I got hsdev installed on my windows machine by the following steps.
Run stack unpack hsdev to download the source of hsdev to the working directory.
Move into the directory, run stack init --solver to create a proper stack.yaml build config.
Run stack install to build and copy the executables to your local bin directory. If stack reports an error about a missing LICENSE file create an empty LICENSE file under ./tests/test-package.

Resources