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
stackage 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. For example,
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 implementation.
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
stk) which will call out to any other tools with the
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.
- stackage-update 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.