We're happy to announce the first release of stackage-cli (Command Line Interface). This project got started by a request in a somewhat unlikely place: a MinGHC issue. We started on this as a way to automate some of the instructions available on stackage.org, but quickly realized there was a lot more potential to make lives of developers even better.
To get started, just run
cabal update && cabal install
stackage-cli. You can see more information on
the Github README. In the rest of this blog post, we'll cover
some of the motivation for the tool, and directions to see it head
in the future.
Manage your cabal.config
Stackage's primary mechanism for setup is to give cabal-install
a set of constraints of which package versions to install, via a
cabal.config file in your project. Typically, setting up Stackage
is a matter of running
https://www.stackage.org/lts/cabal.config. However, there
are a few minor annoyances around this:
- Windows users may not have
wgetavailable (this was the main point of the original MinGHC issue).
- There's a non-obvious upgrade process, which can require wiping out your old package database
With stackage-cli, you just run
stackage init to
get a cabal.config file.
stackage purge deletes that
file and wipes your package database. And
upgrade does both.
The above is nice, but not especially noteworthy. The sandbox feature is where the tool really begins to shine. As many of you know, cabal sandboxes are highly touted for minimizing "cabal hell" problems, by isolating interactions between different projects. However, there are two downsides of sandboxes:
- They still don't solve the problem of coming up with an initial installation plan
- Having a separate sandbox for each projects takes a lot of disk space, and requires significant CPU time to get started on a new project
stackage-cli fixes both of those by introducing automated shared sandboxes. The idea is this: when you use a single LTS Haskell version, you're hardcoding your dependency tree. Therefore, multiple projects using the same LTS version can share the same sandbox. To demonstrate this, let me proceed by making fun of Yesod a bit with a shell session:
$ yesod init # Answer some questions, get a bunch of output $ cd project1 $ stackage sandbox init Writing a default package environment file to /home/vagrant/Desktop/project1/cabal.sandbox.config Creating a new sandbox at /home/vagrant/.stackage/sandboxes/ghc-7.8.4/lts-2.3 $ cabal install --run-tests # Let's get some coffee # OK, lunch time # Fine, I'll actually go work out today # Still not done??? # OK, done $ cd .. $ yesod init # Start project 2 $ cd project2 $ stackage sandbox init Initializing at snapshot: lts-2.3 Writing a default package environment file to /home/vagrant/Desktop/project2/cabal.sandbox.config Using an existing sandbox located at /home/vagrant/.stackage/sandboxes/ghc-7.8.4/lts-2.3 $ cabal install --run-tests # Wait, it's already configuring # Oh, it's done. Crap, no coffee
The point of this little demonstration is: you compile your package set once. You then get to reuse it across multiple projects. Yes, the first installation takes just as long and just as much disk space. But subsequent uses will be immediate.
By the way, please pay attention to the caveats.
Better team collaboration
We use LTS Haskell at FP Complete and on client projects, and it
has eliminated problems of incompatible package versions. Our
recommendation is to check in the cabal.config file to your repo,
or equivalently make sure that everyone on your team starts
development by running the same init command, e.g.
sandbox init lts-1.15.
To sandbox or not to sandbox?
We'd typically recommend to start off with sandboxes, and only
leave them if you have a good reason. Given that, you may be
wondering why we have two versions of the command. One answer is
that there are multiple sandboxing technologies already out there.
hsenv still provides some functionality
that people prefer to cabal sandboxes. Another answer is that there
are other sandboxing approaches that have yet to be fully explored,
such as Docker containers, which may provide significant
advantages. We don't want to tie the tool down to one
One final point. If you pay close attention, you may notice that
stackage-cli provides a few different executables. We've decided to
emulate the Git approach to the command line tool: we have a
wrapper executable called
stackage (and a shorter
stk) which will call out to any other
tools with the name
stackage-*. stackage-cli ships
with executables called
stackage-sandbox. These all work as plugins to the
main executable. This provides for a number of nice features:
- The main
stackage-clican remain light-weight
- New functionality can be added easily by other packages
- Others in the community are welcome to release their own Stackage plugins
The only requirements placed on a Stackage plugin are that it must:
- Be named stackage-something
- When called with the argument
--summary, give a short description of its functionality
The Stackage.CLI module provides some helper functions for this.
There are already a few Stackage plugins on Hackage.
provides a faster, more secure variant of
cabal update. With both
stackage-updateinstalled, you now just run
- stackage-view is an interactive code explorer
- stackage-curator is used by the Stackage team to produce Nightly and LTS releases
We hope others will join in the fun with both the core stackage-cli tool, and by producing their own plugins. If you have ideas, please bring them up on the mailing list, issue trackers, or elsewhere. We also have plans for further open sourcing of our internally built code bases. We're still fixing up some details, but the tools we've developed have been in production use by our customers for a while now, and we're excited to get them into the community's hands. We're also looking at providing tools to provide greater package download security, and to automate the process of getting a Haskell development environment up and running. Stay tuned.