An external command system for cabal: what would you do with it?

Hi everyone!

Cabal is receiving a contribution that implements an external command system like the one implemented by git and cargo. The idea is that when you call cabal <external>, cabal will look for cabal-<external> in your PATH, and set up environment variables like cabal exec. The idea for us cabal developers is to be able to experiment with new sub-options before integrating them into the cabal-install code base.

But we are also interested in what you would like to do with such a feature! Are there things like workflow management that would want to implement through this external command system? Have you found interesting things in other programming language ecosystems that we could get as well?

The PR is here: [cabal-7825] Implement external command system by yvan-sraka · Pull Request #9063 · haskell/cabal · GitHub


Would it be possible to run cabal-edit (e.g. for “cabal add dep”)?
We could also use this for the upcoming “cabal audit”, powered by the security-advisories database.
What will be the provided environment for these external commands?


What environment variables would cabal set?

(I know I should have read the PR :joy:)

1 Like

Just because it’s you I’ll direct you to the CmdExec code :stuck_out_tongue:

1 Like

The two commands I am constantly using with Rust are cargo fmt and cargo clippy, now I can of course run ormolu / fourmolu / hlint myself, after I have installed them, but I would probably use cabal fmt and cabal lint instead if they were available as command aliases. And maybe at some future point in time we will have a linter and formatter available with every default installation and can tell beginners to just use these two commands.


Answering my own question:

  • GHC_ENVIRONMENT is set to a temp file containing a GHC environment with all the project dependencies. :thinking: what about setup dependencies? I need to check. They are not included.
  • The path to all exes in the plan in added to PATH.

I’d really love this. I am thinking about commands like cabal add <dependency> or cabal auto-modules <folder> which modify your .cabal file, simplifying current workflow. I guess these subcommands might be difficult to implement if you contribute to the cabal-install source code, but way more easy (and less burocratic) if you show a poc build by your own.

As someone said in the github discussion, a complementary subcomand like cabal metadata which prints useful data structures to the stdout, might be necessary so every external subcommand has a common initial point .


I’m not sure what I’d use it for; pretty much the main thing I want in cabal at the moment is file-watching and rebuilding :sweat_smile:

However, as you asked for other things, It’s only slightly related, but I have quite recently enjoyed the --then functionality in spago.


I would probably use it to get cabal b and cabal r as in cargo

1 Like

I can imagine that b is an alias for build, what about r?

1 Like

cargo r is short for cargo run. Saves 2 characters, but for whatever reason it really feels like it makes an enormous difference. Full list of aliases from cargo --help:

Some common cargo commands are (see all commands with --list):
    build, b    Compile the current package
    check, c    Analyze the current package and report errors, but don't build object files
    clean       Remove the target directory
    doc, d      Build this package's and its dependencies' documentation
    new         Create a new cargo package
    init        Create a new cargo package in an existing directory
    add         Add dependencies to a manifest file
    remove      Remove dependencies from a manifest file
    run, r      Run a binary or example of the local package
    test, t     Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this package to the registry
    install     Install a Rust binary. Default location is $HOME/.cargo/bin
    uninstall   Uninstall a Rust binary

I always have

alias cb='cabal build'
alias cr='cabal repl'

Another usecase I just discovered is generating ci workflow files (like Github’s .github/workflows/ci.yml) from cabal files. For example, the workflow for GitHub - haskell-CI/haskell-ci: Scripts and instructions for using CI services (e.g. Travis CI or Appveyor) with multiple GHC configurations currently consists in invoking haskell-ci with the name of the cabal file, but if cabal can provide the metadata from the cabal file itself, then cabal ci would also be a nice tool for managing CI workflows.


Perhaps we could also have a cabal doctests command?


Keep 'em coming, it’s very interesting!

1 Like

I would definitely love to see cabal add <dependency> and possibly even cabal remove <dependency>.

I remember when I first started with Haskell, it was very much a shock that I had to enter dependencies in the cabal file manually; esp coming from the world of nuget and npm and all of that. It really raised the bar for entry as a newcomer, and reading through the cabal manual was intimidating trying to figure out how it works.

This would go a long way towards fostering adoption of Haskell I think


Run cabal-prettify as cabal prettify. It already has a matching name!

1 Like

cabal stack ... /ducks


Of course once you have cabal add <dependency> you’ll want cabal expand-bounds [--lower] [--upper] [--test] <dependency>.


Let me understand, where would you want to add that dependency? Since v2, cabal-install is mostly project based, and a project can contain many packages. Any (or most) project configuration can be added with cabal configure; but we are a bit stuck at modifying cabal files.