Skip to content

cabal new-install UI design concept (WIP) #4558

@hvr

Description

@hvr

Status


There's at least two axes for use-cases which need to be considered for the UI design: Most importantly is the distinction between

  • making executables available
  • making libraries available in GHC_ENVIRONMENTs (for GHC 8.0.2+)

And then sources can be distinguished by being either

  • Non-local packages
  • Local packages/projects

With the new nix-store paradigm, the idiomatic way to "install" things would be to first populate the requested target in the nix-store, and install a reference to the materialised artifact in a "view" (this signficantly differs depending on whether it's an executable or a library).

In this paradigm, the "installation" rather refers to installing a symlink or adding a reference to a package-env, than to build the actual artifacts. In some cases, all a cabal new-install operation does degenerates into replacing the target of an existing symlink (e.g. if you first "install" alex-3.2.0, and then you install alex-3.2.1, and then decide to install alex-3.2.0 again; the 3rd operation would merely update the symlink, as the store would already contain both versions of alex)

Basic UI

The basic UI would look like

$ cabal new-install <build-target-spec> [<install-location>]

(NOTE: as of #4825, the syntax is cabal new-install [--symlink-bindir=<install-location>] <build-target-spec>)

A build-target would be something like

Omission of <install-location> would denote a default location.

For libraries the default would be the current value of GHC_ENVIRONMENT, or otherwise the default environment (this matches the ghc-env lookup logic of GHC 8.0.2+).

For executables, the install location denotes a bin folder; by default this would be the value configured in ~/.cabal/config (e.g. ${HOME}/.cabal/bin) or possibly in the in-scope cabal.project.

Executables

Non-local packages

Installing executables from non-local packages is the easiest case; in fact, this can be emulated already now via script like https://gist.github.com/hvr/c77c54d682555b7dd4fe1248732fe978

Which first causes the requested executable to be materialised (if it wasn't already cached) in the nix store via a dummy package description containing build-tool-depends: ${PKG}:${EXE}, and then
locates the resulting executable to install a symlink to the desired folder-location.

Local packages

This case is currently less straightforward when the non-local components have associated package-data (#4120).

However, this use-case is quite important, e.g. when a cabal project is embedded into a larger build-system which needs to invoke cabal to make available some "local" executable to the rest of the
build-system, then such a project is often just part of the source-tree and as such comprised of local
unpublished) packages.

Libraries

Libraries are a bit more complicated, as package-environments should ideally represent views into the nix-store providing a flat consistent install-plan where each package exposed shall be compatible with each other package in the same view.

The simple case is when creating a new package-environment, and specify /all/ libraries to be installed therein upfront. This is the known situation as handled already by cabal new-build via build-depends speecifications.

However, cabal new-install should also support installing new packages into an existing view in an incremental way. But this means that if we may get into a situation where the "old" cabal install
would warn about running into a "reinstall"-situation.

One way to design the UI would be to ask the user whether we should try to resolve, and come up with a new consistent monolithic install-plan for the set of packages that were already available in the package-environment plus the newly to be added packages.

This would take into account the original version constraints imposed if there were any specified for the pre-existing packages. We may need something like per package-environment "world" files, to basically
keep track of an incrementally growing list of build-depends lines (and also possibly constraint-lines and other flags such as profiling levels). This way the user could have control over the package environment in a direct way by editing the world-files in order to manually resolve hard conflicts.

Non-local packages

To some degree, this could be emulated right now with an external shell (similiar to the executable-install-case mentioned above) by using a dummy .cabal file where the requested libraries are
specified via build-depends, and the automatically resulting .ghc.environment.* file which is copied over to the package-environment specified as the install-location.

Local packages

For one, parts of this is already automatically provided by the automatic creation of .ghc.environment.* files, but you'd currently need to manually copy them to their <install-location>. But this would also be limited to single cabal.projects currently.

This is more complicated just as for the local executable case, as associated package-data of local libraries is not handled conveniently for this use-case currently (#4120).


TODO:

  • describe how extra-packages: fits into this scheme (see this comment)

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions