2020-09-29 18:42:00 +03:00
[![Chatroom Gitter ](https://img.shields.io/badge/Chatroom-Gitter-%23753a88 )](https://gitter.im/haskell-nix/Lobby)
[![Hackage ](https://img.shields.io/hackage/v/hnix?color=%235e5086&label=Latest%20release%20on%20Hackage )](https://hackage.haskell.org/package/hnix)
[![Hackage Matrix Builder ](https://img.shields.io/badge/Hackage%20Matrix-Builder-%235e5086 )](https://matrix.hackage.haskell.org/package/hnix)
[![Bounds ](https://img.shields.io/hackage-deps/v/hnix?label=Released%20dep%20bounds )](https://packdeps.haskellers.com/feed?needle=hnix)
[![Hydra CI ](https://img.shields.io/badge/Nixpkgs%20Hydra-CI-%234f72bb )](https://hydra.nixos.org/job/nixpkgs/trunk/haskellPackages.hnix.x86_64-linux#tabs-status)
[![Repology page ](https://img.shields.io/badge/Repology-page-%23005500 )](https://repology.org/project/haskell:hnix/versions)
2021-02-01 15:51:06 +03:00
# HNix
2016-02-08 02:53:22 +03:00
2020-09-30 16:29:22 +03:00
Parser, evaluator and type checker for the Nix language written in Haskell.
2020-09-29 16:55:00 +03:00
2020-09-29 18:42:00 +03:00
2016-02-08 02:53:22 +03:00
## Prerequisites
2020-09-29 18:04:24 +03:00
Tooling is WIP, `nix-shell` and `nix-store` are still used for their purpose, so, to access them Nix is required to be installed.
2016-02-08 02:53:22 +03:00
2021-02-04 00:14:32 +03:00
*Disclaimer*: Since still using Nix for some operations, current `derivationStrict` primOp implementation and so evaluations of a derivation into a store path currently rely on the `hnix-store-remote` , which for those operations relies on the running `nix-daemon` , and so operations use/produce effects into the `/nix/store` . Be cautious - it is effectful (produces `/nix/store` entries).
2021-01-04 23:41:29 +03:00
2021-05-07 16:31:09 +03:00
## Building the project
2016-02-08 02:53:22 +03:00
2021-02-04 00:52:06 +03:00
### Git clone
2021-01-05 01:12:24 +03:00
```shell
2021-02-04 00:52:06 +03:00
git clone --recursive 'https://github.com/haskell-nix/hnix.git' & & cd hnix
2020-09-28 21:31:22 +03:00
```
2020-09-30 17:11:08 +03:00
2021-02-04 00:44:22 +03:00
### (optional) Cachix prebuild binary caches
2020-09-30 17:11:08 +03:00
2021-02-04 00:44:22 +03:00
If you would use our Nix-shell environment for development, you can connect to our Cachix HNix build caches:
1. Run:
```shell
nix-env -iA cachix -f https://cachix.org/api/v1/install
```
2020-09-30 17:11:08 +03:00
2. Run: `cachix use hnix`
2021-05-07 16:31:09 +03:00
### Building with Cabal
2020-09-30 16:00:22 +03:00
2020-09-30 16:55:09 +03:00
Cabal [Quickstart ](https://cabal.readthedocs.io/en/3.4/nix-local-build.html ).
2020-09-30 17:24:24 +03:00
1. (Optional), to enter the projects reproducible Nix environment:
2021-02-03 23:32:32 +03:00
```shell
nix-shell
```
2020-09-30 16:00:22 +03:00
2. Building:
2021-02-03 23:32:32 +03:00
```shell
cabal v2-configure
cabal v2-build
```
2020-09-30 17:00:52 +03:00
3. Loading the project into `ghci` REPL:
2021-02-03 23:32:32 +03:00
```shell
cabal v2-repl
```
2020-09-30 20:37:59 +03:00
4. Testing:
2020-09-30 16:17:34 +03:00
2021-02-03 23:32:32 +03:00
* Default suite:
```shell
cabal v2-test
```
* All available tests:
```shell
env ALL_TESTS=yes cabal v2-test
```
* Selected (list of tests is in `tests/Main.hs` ):
```shell
env NIXPKGS_TESTS=yes PRETTY_TESTS=1 cabal v2-test
```
2018-05-07 22:45:37 +03:00
2021-01-14 16:11:23 +03:00
#### Checking the project
2020-09-29 01:49:12 +03:00
2021-01-14 16:11:23 +03:00
##### Benchmarks
2020-09-30 17:06:57 +03:00
2020-09-30 16:23:38 +03:00
To run benchmarks:
2020-07-03 18:00:03 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-28 21:20:40 +03:00
cabal v2-bench
2020-07-03 18:00:03 +03:00
```
2021-01-14 16:11:23 +03:00
##### Profiling
2018-04-10 21:49:18 +03:00
2021-01-25 17:20:05 +03:00
GHC User Manual has a full ["Profiling" ](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/profiling.html ) section of relevant info.
2018-04-10 21:49:18 +03:00
To build `hnix` with profiling enabled:
2021-01-05 01:12:24 +03:00
```shell
2021-02-04 00:54:33 +03:00
cabal v2-run hnix --enable-profiling --flags=profiling -- < args > +RTS -p
2020-07-03 18:00:03 +03:00
```
2021-02-04 00:45:34 +03:00
Or to put simply:
```shell
# Run profiling for evaluation of a Firefox package.
# Generate:
# * for all functions
# * time profiling data
# * memory allocation profiling data
# * in the JSON profiling format
cabal v2-run --enable-profiling --flags=profiling --enable-library-profiling --profiling-detail='all-functions' hnix -- --eval --expr '(import < nixpkgs > {}).firefox.outPath' +RTS -Pj
# Then, upload the `hnix.prof` to the https://www.speedscope.app/ to analyze it.
```
"RTS" stands for "RunTime System" and has a lot of options, GHC User Manual has ["Running a compiled program"/"Setting RTS options" ](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/runtime_control.html ) sections describing them.
2020-07-03 18:00:03 +03:00
2021-01-14 16:11:23 +03:00
##### Full debug info
2020-07-03 18:00:03 +03:00
2021-01-14 16:11:23 +03:00
To run stack traces & full tracing output on `hnix` :
2020-09-29 17:12:47 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-29 17:14:43 +03:00
cabal v2-configure --enable-tests --enable-profiling --flags=profiling --flags=tracing
cabal v2-run hnix -- -v5 --trace < args > +RTS -xc
```
2018-04-19 02:28:21 +03:00
2021-01-14 16:11:23 +03:00
This would give the most information as to what happens during parsing & evaluation.
2018-04-13 10:06:45 +03:00
2021-02-04 01:13:19 +03:00
#### Runing executable
2021-01-25 17:20:05 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 17:35:15 +03:00
cabal v2-run hnix -- --help
2018-04-13 10:06:45 +03:00
```
2020-09-30 17:35:15 +03:00
(`--` is for separation between `cabal` & `hnix` args)
2018-04-13 10:06:45 +03:00
2018-04-10 21:49:18 +03:00
2021-05-07 16:31:09 +03:00
### Building with Nix-build
2020-09-30 18:21:43 +03:00
There is a number of build options to use with `nix-build` , documentation of them is in: `./default.nix` , keys essentially pass-through the [Nixpkgs Haskell Lib API ](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/lib.nix ).
Options can be used as:
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 18:21:43 +03:00
nix-build \
--arg < option1 > < argument1 > \
--arg < option2 > < argument2 > \
--argstr < option3 > "< strinTypeArg > "
```
2021-01-14 16:11:23 +03:00
#### Checking the project
##### Benchmarks
2020-09-30 18:21:43 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 18:21:43 +03:00
nix-build \
--arg disableOptimization false \
--arg enableDeadCodeElimination true \
--arg doStrip true \
--arg doBenchmark true
```
2021-01-14 16:11:23 +03:00
##### Profiling
2020-09-30 18:21:43 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 18:21:43 +03:00
nix-build \
--arg disableOptimization false \
--arg enableDeadCodeElimination true \
--arg enableLibraryProfiling true \
--arg enableExecutableProfiling true
2021-01-14 16:11:23 +03:00
./result/bin/hnix < args > +RTS -p
2020-09-30 18:21:43 +03:00
```
2021-01-14 16:11:23 +03:00
##### Full debug info
2020-09-30 18:21:43 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 18:21:43 +03:00
nix-build \
--arg disableOptimization false \
--arg enableDeadCodeElimination true \
--arg doBenchmark true \
--arg doStrip false \
--arg enableLibraryProfiling true \
2021-01-26 14:01:26 +03:00
--arg enableExecutableProfiling true \
2020-09-30 18:21:43 +03:00
--arg doTracing true \
--arg enableDWARFDebugging true
2021-01-14 16:11:23 +03:00
./result/bin/hnix -v5 --trace < args > +RTS -xc
2020-09-30 18:21:43 +03:00
```
2021-02-04 01:13:19 +03:00
#### Runing executable
2020-09-30 18:25:39 +03:00
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 18:25:39 +03:00
./result/bin/hnix
```
2021-01-14 16:11:23 +03:00
## Using HNix
2021-01-14 15:53:45 +03:00
2021-01-14 17:26:49 +03:00
See:
```
hnix --help
```
It has a pretty full/good description of the current options.
### Parse & print
To parse a file with `hnix` and pretty print the result:
```shell
2021-02-04 01:13:19 +03:00
hnix file.nix
2021-01-14 17:26:49 +03:00
```
### Evaluating and printing the resulting value
Expression from a file:
```shell
2021-02-04 01:13:19 +03:00
hnix --eval file.nix
2021-01-14 17:26:49 +03:00
```
Expression:
```shell
hnix --eval --expr 'import < nixpkgs > {}'
```
2021-01-14 16:11:23 +03:00
### Evaluating Nixpkgs
2021-01-14 15:53:45 +03:00
Currently, the main high-level goal is to be able to evaluate all of Nixpkgs:
2018-04-10 21:49:18 +03:00
2021-01-14 15:53:45 +03:00
```shell
2021-02-04 01:13:19 +03:00
hnix --eval --expr "import < nixpkgs > {}" --find
2021-01-14 15:53:45 +03:00
```
2021-01-14 17:26:49 +03:00
### Options supported only by HNix
To see value provenance and thunk context:
```shell
hnix -v2 --values --thunk --eval --expr 'import < nixpkgs > {}'
```
To see tracing as the evaluator runs (note that building with `cabal configure --flags=tracing` will produce much more output than this):
```shell
hnix --trace --eval --expr 'import < nixpkgs > {}'
```
To attempt to generate a reduced test case demonstrating an error:
```shell
hnix --reduce bug.nix --eval --expr 'import < nixpkgs > {}'
```
2021-01-14 15:53:45 +03:00
### REPL
2021-02-03 23:32:32 +03:00
To enter REPL:
2021-01-05 01:12:24 +03:00
```shell
2020-09-30 17:35:51 +03:00
hnix --repl
2018-04-10 21:49:18 +03:00
```
2021-01-14 15:53:45 +03:00
Evaluate an expression and load it into REPL:
2021-01-05 01:12:24 +03:00
```shell
2021-02-04 01:13:19 +03:00
hnix --eval --expr '(import < nixpkgs > {}).pkgs.hello' --repl
2020-09-29 17:14:43 +03:00
```
2021-01-14 15:53:45 +03:00
This binds the evaluated expression result to the `input` variable, so that variable can be inspected.
2020-09-29 17:14:43 +03:00
2020-09-30 17:35:51 +03:00
Use the `:help` command for a list of all available REPL commands.
2020-09-29 17:14:43 +03:00
2021-01-14 15:53:45 +03:00
#### Language laziness
2020-10-04 17:29:50 +03:00
Nix is a lazy language with the ability of recursion, so by default REPL and eval prints are lazy:
2021-01-05 01:12:24 +03:00
```shell
2020-10-04 17:29:50 +03:00
hnix \
--eval \
--expr '{ x = true; }'
rename '<CYCLE>' to more direct understandable '<expr>' (#824)
In Nix the `<CYCLE>` only used in one case:
`data/nix/src/libexpr/eval.cc`
```cpp
static void printValue(std::ostream & str, std::set<const Value *> & active, const Value & v)
{
checkInterrupt();
if (active.find(&v) != active.end()) {
str << "<CYCLE>";
return;
}
...
}
```
it never appears otherwise and so is not checked in expression tests, so it is a cosmetic output.
Semantically `<CYCLE>` was remotely right only in `opaque` `src/Nix/Normal.hs`
which tries to detect cycles, and only partially right, even if just due to non-termination detection problem (halting problem).
In other cases, where `<CYCLE>` was used - they are no cycles, which people see: https://github.com/haskell-nix/hnix/issues/663#issue-646681651, and felt confused.
In REPL case - they are simply thunks, or as in XML - just mark expressions.
& they are all expressions after all.
Even most of the infinite nonterminating expressions can be WHNF & studied as expression layer by layer.
And since we can say "expr", that also saves users & devs from communicating what in the lazy FP programming "thunk" slang means.
And currently by itself explains the #777 situation.
2021-01-14 21:43:54 +03:00
{ x = "< expr > "; }
2020-10-04 17:29:50 +03:00
```
To disable laziness add the `--strict` to commands or `:set strict` in the REPL.
2021-01-05 01:12:24 +03:00
```shell
2020-10-04 17:29:50 +03:00
hnix \
--eval \
--strict \
--expr '{ x = true; }'
{ x = true; }
```
2020-09-29 17:14:43 +03:00
2021-01-14 01:00:52 +03:00
2020-09-29 03:07:07 +03:00
## Contributing
2018-04-04 08:57:23 +03:00
2021-02-04 00:53:59 +03:00
* The Haskell Language Server (HLS) works great with our project.
2021-01-14 17:06:37 +03:00
2021-02-04 00:53:59 +03:00
* [Design of the HNix code base Wiki article ](https://github.com/haskell-nix/hnix/wiki/Design-of-the-HNix-code-base ).
2021-01-14 01:01:09 +03:00
2020-09-29 03:19:10 +03:00
1. If something in the [quests ](https://github.com/haskell-nix/hnix/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+no%3Aassignee ) looks interesting, look through the thread and leave a comment taking it, to let others know you're working on it.
2020-09-29 03:17:20 +03:00
2020-09-29 03:19:10 +03:00
2. You are free to chat with everyone on [Gitter ](https://gitter.im/haskell-nix/Lobby ).
2018-04-04 08:57:23 +03:00
2020-09-30 17:23:18 +03:00
3. When the pull request is ready to be submitted, to save time - please, test it with:
2021-02-03 23:32:32 +03:00
```shell
cabal v2-test
2021-02-04 00:53:59 +03:00
# If forgot to clone recursively, run:
# git submodule update --init --recursive
2021-02-03 23:32:32 +03:00
```
2021-02-04 00:53:59 +03:00
Please, check that all default tests that were passing prior are still passing. It's OK if no new tests are passing.
2021-02-03 23:32:32 +03:00
2021-01-14 01:01:09 +03:00
### (optional) Minimalistic development status loop with amazing [`ghcid`](https://github.com/ndmitchell/ghcid)
2018-11-18 19:44:52 +03:00
2021-02-04 00:53:59 +03:00
If HLS is not your cup of yea:
2021-01-05 01:12:24 +03:00
```shell
2021-01-14 01:00:52 +03:00
ghcid --command="cabal v2-repl --repl-options=-fno-code --repl-options=-fno-break-on-exception --repl-options=-fno-break-on-error --repl-options=-v1 --repl-options=-ferror-spans --repl-options=-j"
2018-11-18 19:44:52 +03:00
```
2021-01-14 01:00:52 +03:00
(optional) To use projects reproducible environment, wrap `ghcid ...` command into a `nix-shell --command ' '` .
For simplicity `alias` the command in your shell.
2021-01-13 22:39:23 +03:00
2021-01-14 01:01:09 +03:00
2021-01-13 22:39:23 +03:00
## Current status
2021-02-04 01:13:19 +03:00
To understand the project implementation state see:
* [ChangeLog ](https://github.com/haskell-nix/hnix/blob/master/ChangeLog.md )
* [Opened reports ](https://github.com/haskell-nix/hnix/issues )
* [Project status ](https://github.com/haskell-nix/hnix/wiki/Project-status )
* [Design of the HNix code base ](https://github.com/haskell-nix/hnix/wiki/Design-of-the-HNix-code-base )
2021-01-13 22:39:23 +03:00