1
1
mirror of https://github.com/nmattia/snack.git synced 2024-09-11 11:55:36 +03:00

Update README

This commit is contained in:
Nicolas Mattia 2018-07-11 18:49:00 +02:00
parent 8bef714a9a
commit 4a47498e28
6 changed files with 226 additions and 61 deletions

224
README.md
View File

@ -3,73 +3,175 @@
# Snack
_snack_ is a Haskell build tool.
_snack_ is a build tool which
## Usage
You need a `snack.nix`:
``` nix
{ pkgs ? import <nixpkgs> {} }: # see #install for instructions
pkgs.snack-lib.executable
{ src = ./src; # Where you source code is located
main = "Main"; # The name of your main module
# You Haskell dependencies
dependencies =
[
"heterocephalus"
"servant"
"servant-server"
"warp"
"unliftio"
"uuid"
];
# GHC options
ghc-options = [ "-Wall" ];
# Extra directories to add to your build, by module
extra-directories = modName:
if modName == "Main" then
[ ./pages ]
else [];
}
```
You can then build with:
``` shell
$ snack build
```
or run with:
``` shell
$ snack run
> ...
```
or start an interactive session:
``` shell
$ snack ghci
> ...
```
Currently _snack_ only supports building executables. See the [test
suite](./script/test) for examples.
* uses Nix to build Haskell projects (HPack and special Nix configuration)
* is incremental: running `snack build` will only rebuild the modules that
have been modified since the previous build
* works in the Nix sandbox
* comes with lots of cool Nix features for free: strong reproducibility
guarantees, remote caching, remote builds, and more
* may improve build performance in some cases, for instance:
- all Haskell modules modules are built in parallel
- there is a single linking step performed (typically) on a fast tmpfs
## Install
The easiest way to install it is to add
it to your nix shell:
You need [nix][nix]. Then, clone this repo and run:
``` shell
$ nix-env -f ./default.nix -iA snack-exe
installing 'linker'
```
The _snack_ executable should now be available:
``` shell
$ snack --help
Usage: snack ([-s|--snack-nix PATH] | [-p|--package-yaml PATH]) COMMAND
Available options:
-h,--help Show this help text
Available commands:
build
run
ghci
```
## Usage
_snack_ uses HPack for building. If you need more power in your builds, you can
also use raw nix. The next sections will give example HPack and Nix
configurations for building the following project:
```shell
.
├── app
│   └── Main.hs
└── src
└── Lib.hs
```
***src/Lib.hs*** :
``` haskell
module Lib where
import Control.Lens
import Network.Wreq
import Data.Aeson.Lens
import Data.Text (Text)
topReddit :: IO Text
topReddit =
getWith opts url
<&> (^. responseBody
. key "data"
. key "children"
. nth 0
. key "data"
. key "title"
. _String)
where
url = "https://www.reddit.com/r/haskell/top.json"
opts = defaults
& param "limit" .~ ["1"]
& param "t" .~ ["all"]
```
***app/Main.hs*** :
``` haskell
module Main where
import Lib
main :: IO ()
main = topReddit >>= print
```
### HPack
_snack_ does not purport to support HPack entirely (yet) but merely uses some
heuristics that map relatively well to HPack's specification. The
aforementioned project could have the following `package.yaml`:
``` yaml
name: snack-readme
dependencies:
- lens
- wreq
library:
source-dirs: ./src
executable:
main: Main.hs
source-dirs: ./app
dependencies:
- snack-readme
default-extensions:
- OverloadedStrings
```
The project can be run by using the following command:
``` shell
$ snack run --package-yaml ./package.yaml
"\"Category Theory for Programmers\" has been finished!"
```
You may decide to simply build the project, or even start an interactive
session:
``` shell
$ snack build --package-yaml ./package.yaml
/nix/store/x3ahgw45qja93jrbm2qd3pywfy2zcq9c-hpack-build-json
$ snack ghci --package-yaml ./package.yaml
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling Lib ( /home/nicolas/projects/nmattia/snack/tests/readme/src/Lib.hs, interpreted )
[2 of 2] Compiling Main ( /home/nicolas/projects/nmattia/snack/tests/readme/app/Main.hs, interpreted )
Ok, two modules loaded.
*Main>
```
### Nix
Here is the equivalent Nix config :
``` nix
{ pkgs ? import <nixpkgs> {} }:
let
snack = (pkgs.callPackage path/to/snack {}).snack-exe;
in pkgs.mkShell
{ name = "snack-shell";
buildInputs = [ snack ];
lib =
{ src = ./src;
dependencies = [ "wreq" "lens" ];
extensions = [ "OverloadedStrings"];
};
in
{ main = "Main";
src = ./app;
packages = [ lib ];
dependencies = [ "wreq" "lens" ];
}
```
The same commands can then be used:
``` shell
$ snack --snack-nix ./snack.nix run
"\"Category Theory for Programmers\" has been finished!"
```
Note that the `--snack-nix` argument can be omitted if a `./snack.nix` file is
present. Using a Nix (as opposed to HPack) for building your projects gives you
a lot of power and flexibility. For instance see [_snack_'s
`snack.nix`](./bin/snack.nix) (yes, snack builds itself!).
[nix]: https://nixos.org/nix/

View File

@ -94,6 +94,12 @@ pushd tests/hpack
./test
popd
banner "Test readme folder"
pushd tests/readme
echo | snack ghci --package-yaml ./package.yaml
snack run --package-yaml ./package.yaml
popd
banner "Test this file's formatting"
list=$(shfmt -i 2 -l script/test)
if [[ -n "$list" ]]; then

6
tests/readme/app/Main.hs Normal file
View File

@ -0,0 +1,6 @@
module Main where
import Lib
main :: IO ()
main = topReddit >>= print

17
tests/readme/package.yaml Normal file
View File

@ -0,0 +1,17 @@
name: snack-readme
dependencies:
- lens
- wreq
library:
source-dirs: ./src
executable:
main: Main.hs
source-dirs: ./app
dependencies:
- snack-readme
default-extensions:
- OverloadedStrings

12
tests/readme/snack.nix Normal file
View File

@ -0,0 +1,12 @@
let
lib =
{ src = ./src;
dependencies = [ "wreq" "lens" ];
extensions = [ "OverloadedStrings"];
};
in
{ main = "Main";
src = ./app;
packages = [ lib ];
dependencies = [ "wreq" "lens" ];
}

22
tests/readme/src/Lib.hs Normal file
View File

@ -0,0 +1,22 @@
module Lib where
import Control.Lens
import Network.Wreq
import Data.Aeson.Lens
import Data.Text (Text)
topReddit :: IO Text
topReddit =
getWith opts url
<&> (^. responseBody
. key "data"
. key "children"
. nth 0
. key "data"
. key "title"
. _String)
where
url = "https://www.reddit.com/r/haskell/top.json"
opts = defaults
& param "limit" .~ ["1"]
& param "t" .~ ["all"]