MONAPP-3634: Improve stack/nix experience and MacOS development environment sanity (#84)

* Update tests.patch

* release.nix fixes for building and running cabal test suite from inside the nix-shell environment

* Update build instructions

* More README updates

* Fix stack tooling and improve documentation

* Update grpc sha256, cleanup build instructions

* Whups, DYLD_LIBRARY_PATH and substituteInPlace is still needed for hydra / macos builds with no brew-installed grpc!

* PR feedback tweaks
This commit is contained in:
Joel Stanley 2016-12-19 16:53:44 -06:00 committed by GitHub Enterprise
parent b78b15ecdb
commit 8a6a7c3715
7 changed files with 107 additions and 84 deletions

106
README.md
View file

@ -1,66 +1,80 @@
Running the tests Building and testing
----------------- --------------------
In order to run the tests, you will need to have the `grpcio`, `gevent`, and You will need to have GRPC installed already. See the "Installing GRPC" section
`grpcio-tools` python packages installed. You can install them using below for more information.
`pip`. It is recommended that you use a python virtualenv to do this.
``` `nix-build release.nix -A grpc-haskell` will build and test the whole thing and
$ virtualenv path/to/virtualenv # to create a virtualenv put the completed package into the nix store.
$ . path/to/virtualenv/bin/activate # to use an existing virtualenv
$ pip install grpcio-tools gevent `nix-shell` can be used to give you a development environment where you can use
$ pip install grpcio # Need to install grpcio-tools first to avoid a versioning problem the `cabal` and `stack test` toolchains for development and testing iteration.
```bash
$ nix-shell release-nix -A grpc-haskell.env
[nix-shell]$ cabal configure --with-gcc=clang --enable-tests && cabal build && cabal test
``` ```
Building GRPC ```bash
------------- $ nix-shell release-nix -A grpc-haskell.env
[nix-shell]$ stack build --fast && stack test --fast
```
In order to compile this project, and anything which depends on it, you will need a working installation Note that, for `stack`, the `nix-shell` environment only needed to run the
of the GRPC C core libraries. This library currently uses the 0.15 version range. If you are on OS X, you can install it with homebrew: tests, because it uses some custom python tooling (for grpc interop
testing). You should still be able to `stack build` without using the
`nix-shell` environment at all. See the section below on installing GRPC for use
by `stack`.
NB: You can also instruct `stack` to run the tests inside the `nix-shell`
environment directly, via `stack --nix test --fast`. However, this will
frequently rebuild the custom ghc that is used by the `nix` tooling so is not
recommended for development iterations.
Finally, since `stack` does not use `nix` for any Haskell dependencies,
repository references for dependent packages such as `protobuf-wire` must be
updated both in `nix/<pkg>.nix` AND in the `stack.yaml`.
Installing GRPC for `stack`
---------------------------
If you want to use the `stack` tooling, you will need a working installation of
the GRPC C core libraries.
On MacOS, because
of [this](https://github.com/commercialhaskell/stack/issues/1161), dependencies
on the nix-built `grpc` don't work properly, so the library needs to be
installed somewhere the linker will pick it up without `DYLD_LIBRARY_PATH` set.
We suggest that use `brew` to do this:
``` ```
brew tap grpc/grpc brew tap grpc/grpc
brew edit grpc
...
brew install grpc brew install grpc
``` ```
Alternatively, you can build gRPC from source by checking out an appropriate revision Make sure you select a release version that is reasonably close to our grpc
of the repository, and installing as follows: dependency, e.g.:
```sh ```
git clone https://github.com/grpc/grpc.git url "https://github.com/grpc/grpc/archive/release-0_15_0.tar.gz"
git checkout release-0_15_1 sha256 "d02235dff278869e94cb0dcb31cfea935693c6f87bd73f43d44147185e6becdd"
cd grpc
git submodule update --init
make
sudo make install
``` ```
Alternatively, using Nix, pass the following expression to `nix-build` and point Stack to the build products in the Nix store: or
```nix ```
let pkgs = import <nixpkgs> {}; url "https://github.com/grpc/grpc/archive/v1.0.1.tar.gz"
in pkgs.stdenv.mkDerivation rec sha256 "efad782944da13d362aab9b81f001b7b8b1458794751de818e9848c47acd4b32"
{ name = "grpc";
src = pkgs.fetchgit
{ url = "https://github.com/grpc/grpc.git";
rev = "674b30373e2d6a1e26425952805179f8d52a8c00";
sha256 = "05vj48w4h7bn6xyf1wyg2l6psl38h4yz6j1cl0yd2p5h7f5hb3s7";
};
preInstall = "export prefix";
buildInputs =
[ pkgs.darwin.cctools
pkgs.autoconf
pkgs.automake
pkgs.libtool
pkgs.which
pkgs.zlib
pkgs.openssl
];
}
``` ```
Using the Library Using the Library
----------------- -----------------
You must compile with `-threaded`, because we rely on being able to execute Haskell while blocking on foreign calls to the gRPC library. If not using code generation, the recommended place to start is in the `Network.GRPC.HighLevel.Server.Unregistered` module, where `serverLoop` provides a handler loop. You must compile with `-threaded`, because we rely on being able to execute
Haskell while blocking on foreign calls to the gRPC library. If not using code
generation, the recommended place to start is in the
`Network.GRPC.HighLevel.Server.Unregistered` module, where `serverLoop` provides
a handler loop.

View file

@ -8,7 +8,7 @@ stdenv.mkDerivation rec {
src = fetchgit { src = fetchgit {
inherit rev; inherit rev;
url = "https://github.com/grpc/grpc.git"; url = "https://github.com/grpc/grpc.git";
sha256 = "1pac3jby5p5a6p6vpqc5whkgy36hnn2ph2jbckg3w73hrxrnwmdh"; sha256 = "0a48swsip09bd0yk80gl9r7pny9dal3byyd22bdz4fcvydna43m0";
}; };
preInstall = "export prefix"; preInstall = "export prefix";
buildInputs = buildInputs =

View file

@ -3,7 +3,7 @@
# $ # Consider adding the following command to your `~/.profile` # $ # Consider adding the following command to your `~/.profile`
# $ NIX_PATH="${NIX_PATH}:ssh-config-file=${HOME}/.ssh/config:ssh-auth-sock=${SSH_AUTH_SOCK}" # $ NIX_PATH="${NIX_PATH}:ssh-config-file=${HOME}/.ssh/config:ssh-auth-sock=${SSH_AUTH_SOCK}"
# $ nix-shell -A grpc-haskell.env release.nix # $ nix-shell -A grpc-haskell.env release.nix
# [nix-shell]$ cabal configure --with-gcc=clang --enable tests # [nix-shell]$ cabal configure --with-gcc=clang --enable tests && cabal build && cabal test
# #
# This will open up a Nix shell where all of your Haskell tools will work like # This will open up a Nix shell where all of your Haskell tools will work like
# normal, except that all dependencies (including C libraries) are managed by # normal, except that all dependencies (including C libraries) are managed by
@ -163,7 +163,7 @@ let
]; ];
}; };
haskellPackages = pkgs.haskell.packages.ghc7103.override { haskellPackages = pkgs.haskellPackages.override {
overrides = haskellPackagesNew: haskellPackagesOld: rec { overrides = haskellPackagesNew: haskellPackagesOld: rec {
proto3-wire = proto3-wire =
haskellPackagesNew.callPackage ./nix/proto3-wire.nix { }; haskellPackagesNew.callPackage ./nix/proto3-wire.nix { };
@ -194,6 +194,10 @@ let
ghc = ghc =
haskellPackagesNew.ghcWithPackages (pkgs: [ haskellPackagesNew.ghcWithPackages (pkgs: [
pkgs.grpc-haskell-no-tests pkgs.grpc-haskell-no-tests
# Include some additional packages in this custom ghc for
# running tests in the nix-shell environment.
pkgs.tasty-quickcheck
pkgs.turtle
]); ]);
python = pkgs.python.withPackages (pkgs: [ python = pkgs.python.withPackages (pkgs: [
@ -201,8 +205,17 @@ let
grpcio-tools grpcio-tools
]); ]);
# So users can use `stack` inside of `nix-shell` if they do not
# already have it installed.
stack = haskellPackages.stack;
in rec { in rec {
buildDepends = [ pkgs.makeWrapper ]; buildDepends = [
pkgs.makeWrapper
# Give our nix-shell its own cabal so we don't pick up one
# from the user's environment by accident.
haskellPackagesNew.cabal-install
];
patches = [ tests/tests.patch ]; patches = [ tests/tests.patch ];
@ -231,16 +244,10 @@ let
--prefix PATH : ${ghc}/bin --prefix PATH : ${ghc}/bin
''; '';
postInstall = pkgs.lib.optionalString pkgs.stdenv.isDarwin '' shellHook = ''
wrapProgram $out/bin/hellos-client --prefix DYLD_LIBRARY_PATH : ${grpc}/lib
wrapProgram $out/bin/hellos-server --prefix DYLD_LIBRARY_PATH : ${grpc}/lib
wrapProgram $out/bin/echo-client --prefix DYLD_LIBRARY_PATH : ${grpc}/lib
wrapProgram $out/bin/echo-server --prefix DYLD_LIBRARY_PATH : ${grpc}/lib
'';
shellHook =
pkgs.lib.optionalString pkgs.stdenv.isDarwin ''
export DYLD_LIBRARY_PATH=${grpc}/lib''${DYLD_LIBRARY_PATH:+:}$DYLD_LIBRARY_PATH export DYLD_LIBRARY_PATH=${grpc}/lib''${DYLD_LIBRARY_PATH:+:}$DYLD_LIBRARY_PATH
# This lets us use our custom ghc and python environments in the shell.
export PATH=${stack}/bin:${ghc}/bin:${python}/bin''${PATH:+:}$PATH
''; '';
}); });
}; };

View file

@ -28,7 +28,14 @@ flags: {}
extra-package-dbs: [] extra-package-dbs: []
# Control whether we use the GHC we find on the path # Control whether we use the GHC we find on the path
# system-ghc: true #
# NB: It is important that this is `false`, because we do NOT want `stack` to
# use our nix-built ghc which is used in the `nix`/`cabal` worfklows, we want it
# to use its own LTS version. Setting this to `true` and then trying to run
# tests via `stack` inside the `nix-shell` will result in some cryptic package
# collison messages: e.g., there's a `text` in the nix-built ghc which are
# using, and another `text` in what `stack` wants to use.
system-ghc: false
# Require a specific version of stack, using version ranges # Require a specific version of stack, using version ranges
# require-stack-version: -any # Default # require-stack-version: -any # Default
@ -44,3 +51,15 @@ extra-package-dbs: []
# Allow a newer minor version of GHC than the snapshot specifies # Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor # compiler-check: newer-minor
# NB: We really only rely on Nix integration for creating the environment for
# running tests. Thus `stack --nix test` can be used to run the tests. However,
# since this will rebuild a custom ghc often due to the structure of
# release.nix, it is suggested that `nix-shell release.nix -A grpc-haskell.env`
# is used and then `stack test` (sans `--nix`) is used during development and
# test iterations.
nix:
enable: false
pure: false
shell-file: release.nix
nix-shell-options: ["-A", "grpc-haskell.env"]

View file

@ -2,7 +2,7 @@
hsTmpDir=$1 hsTmpDir=$1
stack ghc -- \ ghc \
--make \ --make \
-threaded \ -threaded \
-odir $hsTmpDir \ -odir $hsTmpDir \

View file

@ -2,7 +2,7 @@
hsTmpDir=$1 hsTmpDir=$1
stack ghc -- \ ghc \
--make \ --make \
-threaded \ -threaded \
-odir $hsTmpDir \ -odir $hsTmpDir \

View file

@ -1,38 +1,21 @@
diff --git a/tests/simple-client.sh b/tests/simple-client.sh diff --git a/tests/simple-client.sh b/tests/simple-client.sh
index 8feb1f4..ca925b1 100755 index 066a0ca..fc5b693 100755
--- a/tests/simple-client.sh --- a/tests/simple-client.sh
+++ b/tests/simple-client.sh +++ b/tests/simple-client.sh
@@ -2,7 +2,7 @@ @@ -11,3 +11,8 @@ ghc \
hsTmpDir=$1
-stack ghc -- \
+ghc \
--make \
-threaded \
-odir $hsTmpDir \
@@ -11,3 +11,7 @@ stack ghc -- \
$hsTmpDir/Simple.hs \ $hsTmpDir/Simple.hs \
tests/TestClient.hs \ tests/TestClient.hs \
> /dev/null > /dev/null
+ +
+
+. @makeWrapper@/nix-support/setup-hook +. @makeWrapper@/nix-support/setup-hook
+ +
+flagsBefore="" wrapProgram "${hsTmpDir}/simple-client" --prefix DYLD_LIBRARY_PATH : @grpc@/lib +flagsBefore="" wrapProgram "${hsTmpDir}/simple-client" --prefix DYLD_LIBRARY_PATH : @grpc@/lib
diff --git a/tests/simple-server.sh b/tests/simple-server.sh diff --git a/tests/simple-server.sh b/tests/simple-server.sh
index 37a0a63..eb37776 100755 index b66db5c..c8a679a 100755
--- a/tests/simple-server.sh --- a/tests/simple-server.sh
+++ b/tests/simple-server.sh +++ b/tests/simple-server.sh
@@ -2,7 +2,7 @@ @@ -11,3 +11,7 @@ ghc \
hsTmpDir=$1
-stack ghc -- \
+ghc \
--make \
-threaded \
-odir $hsTmpDir \
@@ -11,3 +11,7 @@ stack ghc -- \
$hsTmpDir/Simple.hs \ $hsTmpDir/Simple.hs \
tests/TestServer.hs \ tests/TestServer.hs \
> /dev/null > /dev/null