Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cdepillabout/cabal2nixwithoutifd
https://github.com/cdepillabout/cabal2nixwithoutifd
hacktoberfest haskell nix purenix purescript
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/cdepillabout/cabal2nixwithoutifd
- Owner: cdepillabout
- License: bsd-3-clause
- Created: 2021-09-01T00:53:22.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2021-12-24T00:23:18.000Z (about 3 years ago)
- Last Synced: 2024-11-12T11:41:03.393Z (3 months ago)
- Topics: hacktoberfest, haskell, nix, purenix, purescript
- Language: PureScript
- Homepage:
- Size: 467 KB
- Stars: 30
- Watchers: 7
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# cabal2nixWithoutIFD
This repo contains a proof-of-concept for a
[`callCabal2nix`](https://github.com/NixOS/nixpkgs/blob/d263feb6f6392939c4c5e0a2608a450f65417d18/pkgs/development/haskell-modules/make-package-set.nix#L220)
function written in Nix. `callCabal2nix` uses
[Import From Derivation (IFD)](https://blog.hercules-ci.com/2019/08/30/native-support-for-import-for-derivation/)
and a Haskell program [cabal2nix](https://github.com/NixOS/cabal2nix) to take
a Haskell `.cabal` file (like
[`example-cabal-library.cabal`](`./example-cabal-library/example-cabal-library.cabal`))
and translate it into a derivation that can be built with Nix.One unfortunate part of `callCabal2nix` is that `cabal2nix` is written in
Haskell, so IFD must be used to build the resulting derivation. IFD can often
be slower than just doing things with native Nix, and it is not allowed
in Nixpkgs.This repo provides a `callCabal2nixWithoutIFD` function that is written in Nix,
so it doesn't have either of the above downsides. Cabal files are parsed in
Nix directly, so IFD is not needed.Internally, this `callCabal2nixWithoutIFD` function is written in PureScript
and transpiled to Nix using [PureNix](https://github.com/purenix-org/purenix).
Writing a parser for a complicated format like a Cabal file is much more
reasonable in a language like PureScript than Nix itself.While this repo is just a proof-of-concept, this approach of writing a
complicated parser in PureNix could reasonably be extended to write a full
parser for `.cabal` files. Writing a similar parser directly in raw Nix would
be considerably more difficult.## Compiling PureScript Code to Nix
Compiling `purescript-cabal-parser` to Nix can be done with the following
steps.First, get into a Nix devShell:
```console
$ nix develop
```The, change to `./purescript-cabal-parser` directory and run `spago build`:
```console
$ cd ./purescript-cabal-parser/
$ spago build
```This transpiles the PureScript code to Nix. The transpiled Nix code is placed
in `./purescript-cabal-parser/output/`.## Running Transpiled PureScript Code
The transpiled PureScript code can be tested by using the [`test.nix`](./test.nix)
script.Here's a derivation for a Haskell package that was built using
`callCabal2nixWithoutIFD`:```console
$ nix-build ./test.nix -A exampleHaskellPackage
...
/nix/store/xb0yxkpzdz3zjqmcxwa9z6r6r98yfizz-example-cabal-library-0.1.0.0
```Here's a derivation for a Haskell package that was built using
the normal `callCabal2nix`:```console
$ nix-build ./test.nix -A exampleHaskellPackageWithIFD
...
/nix/store/xb0yxkpzdz3zjqmcxwa9z6r6r98yfizz-example-cabal-library-0.1.0.0
```You can disable IFD in Nix and see that the Haskell derivation built with
`callCabal2nixWithoutIFD` still builds successfully:```console
$ nix-build --option allow-import-from-derivation false ./test.nix -A exampleHaskellPackage
...
/nix/store/xb0yxkpzdz3zjqmcxwa9z6r6r98yfizz-example-cabal-library-0.1.0.0
$ nix-build --option allow-import-from-derivation false ./test.nix -A exampleHaskellPackageWithIFD
error: cannot build '/nix/store/q5hq65ynrqnnnjs3kl1ggsx2pkwlw702-cabal2nix-example-cabal-library.drv'
during evaluation because the option 'allow-import-from-derivation' is disabled
```I recommend reading through the [`test.nix`](./test.nix) file to see what other
derivations have been defined that you can try building. The file is heavily
commented.## Playing around in the Nix REPL
You may be interested in taking a look at the PureScript code that defines the
above derivations. Most of the interesting code is in
[`purescript-cabal-parser/src/Main.purs`](./purescript-cabal-parser/src/Main.purs).You can load the transpiled PureScript code in a Nix REPL to play around with
it:```console
$ cd ./purescript-cabal-parser/
$ nix repl ./purescript-cabal-parser/output/Main
```This puts you in a Nix REPL with all the functions and datatypes from the
[`Main`](./purescript-cabal-parser/src/Main.purs) module available.For instance, `Main` defines a function called `cabalParser`:
```purescript
cabalParser :: String -> Either (Array String) CabalFile
```This takes the raw text of a Cabal file and parses it into a `CabalFile`
datatype:```purescript
type CabalFile =
{ name :: String
, version :: String
, license :: License
, executable :: Executable
}data License = LicenseBSD3
type Executable =
{ name :: String
, buildDepends :: Array String
}
```Let's try calling `cabalParser` from the Nix REPL:
```nix
nix-repl> rawCabalFile = builtins.readFile ./
nix-repl> :p cabalParser rawCabalFile
{ __field0 = { executable = { buildDepends = [ "base" "aeson" ]; name = "example-cabal-library"; }; license = { __tag = "LicenseBSD3"; }; name = "example-cabal-library"; version = "0.1.0.0"; }; __tag = "Right"; }
```If you squint, you can roughly see this attrset corresponds to the `CabalFile`
datatype.There are lots of comments in the
[`Main.purs`](./purescript-cabal-parser/src/Main.purs) file, so you may want to
skim through it to see what else is available.## Caveats
The cabal parser implemented in `./purescript-cabal-parser/` is completely a
proof-of-concept. It only parses the absolute simplest of `.cabal` files.
I wouldn't recommend using it any arbitrary Haskell package.However, I hope the PureScript code in this repository shows the potential of
PureNix for writing things that would be difficult in raw Nix.