nix-for-devs

by uniphil

uniphil / nix-for-devs

nix-shell recipes

149 Stars 5 Forks Last release: Not found MIT License 13 Commits 0 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Nix for devs

This is collection of recipes focused on

nix-shell
to make setting up project environments easy. Pragmatism and low project impact are prioritized: it's not a goal to change a nodejs project to use nix instead of npm, but it is a goal to run npm projects without having to install any OS dependencies (including nodejs itself!).

nix-ops
and other super-cool nix tech are completely out of scope.

Every solution should work today. If something is broken, open an issue!. If there is a better solution that will be supported by nix soon, we wait until it's released before mentioning it here (but don't hesitate to open a tracking issue!).

Maybe in the best case, this document can be a kind of gateway to nix and nixos. I keep telling my developer friends about the cool things I do with nix, but I have to add huge warnings about how much time it's taken me to get to my current level of productivity. I'm annoyingly aware of the amount of trivia I'm carying in my head (though I still feel like a beginner!), and I constantly go back to old projects to look up what I did last time to fix problems. I frequently find myself running into hard-to-google issues. So, I'm finally writing it all down, for myself as much as for my friends :)

Work-in-progress

Current state: rough sketches and todos. Pull requests welcome!

nix-shell

TODO

Run stuff without installing anything

Stuff I used to do with docker. TODO :)

Node.js

shell.nix
with import  {};

stdenv.mkDerivation { name = "node"; buildInputs = [ nodejs ]; shellHook = '' export PATH="$PWD/node_modules/.bin/:$PATH" ''; }

The

nodejs
build input sets up
node
and
npm
in the shell. The shell hook adds the
.bin/
folder to your
PATH
, so you can install node command-line tools like
grunt
with
npm
without the
-g
flag. Finally, it automatically installs any dependencies found in
package.json
, if one exists. If you prefer to run
npm install
manually inside the shell, just delete that line from
shellHook
.

npm run <...>
shortcut

It's handy to have an alias

run
for
npm run
, which makes the following two commands equivalent:
$ npm run watch:test
$ run watch:test

You can add this to

shellHook
:
    alias run='npm run'

Newer nodejs

shell.nix
with import  {};

stdenv.mkDerivation { name = "node"; buildInputs = [ nodejs-8_x ]; shellHook = '' export PATH="$PWD/node_modules/.bin/:$PATH" ''; }

Node versions are published as -x, so etg., `nodejs-7x

and
nodejs-6_x` are also valid.

View available npm scripts

I use

jq
to quickly get a summary of all scripts defined in a package's
package.json
file:

shell.nix
with import  {};

stdenv.mkDerivation { name = "node"; buildInputs = [ jq nodejs ]; shellHook = '' export PATH="$PWD/node_modules/.bin/:$PATH" alias scripts='jq ".scripts" package.json' ''; }

This sets up an alias called

scripts
. Example output:
$ scripts
{
  "build": "babel --ignore __tests__,story.js -d lib/ src/",
  "lint": "eslint *.js src/ storybook/",
  "start": "start-storybook -p 9001 -c ./storybook/web",
  "test": "jest --roots src --silent",
  "test:watch": "jest --roots src --watch"
}

React native

shell.nix
with import  {};

let jdk = openjdk; node = nodejs-8_x; sdk = androidenv.androidsdk { platformVersions = [ "23" ]; abiVersions = [ "x86" ]; useGoogleAPIs = true; useExtraSupportLibs = false; useGooglePlayServices = false; }; unpatched-sdk = let version = "3859397"; in stdenv.mkDerivation { name = "unpatched-sdk"; src = fetchzip { url = "https://dl.google.com/android/repository/sdk-tools-linux-${version}.zip"; sha256 = "03vh2w1i7sjgsh91bpw40ryhwmz46rv8b9mp7xzg89zs18021plr"; }; installPhase = '' mkdir -p $out cp -r * $out/ ''; dontPatchELF = true; }; run-android = pkgs.buildFHSUserEnv { name = "run-android"; targetPkgs = (pkgs: [ node ]); profile = '' export JAVA_HOME=${jdk.home} export ANDROID_HOME=$PWD/.android export PATH=$PWD/node_modules/.bin:$PATH ''; runScript = "react-native run-android"; }; in stdenv.mkDerivation { name = "react-native-android"; nativeBuildInputs = [ run-android ]; buildInputs = [ coreutils node sdk unpatched-sdk ]; shellHook = '' export JAVA_HOME=${jdk} export ANDROID_HOME=$PWD/.android/sdk export PATH="$ANDROID_HOME/bin:$PWD/node_modules/.bin:$PATH"

  if ! test -d .android ; then
    echo doing hacky setup stuff:

    echo "=&gt; pull the sdk out of the nix store and into a writeable directory"
    mkdir -p .android/sdk
    cp -r ${unpatched-sdk}/* .android/sdk/

    echo "=&gt; don't track the sdk directory"
    echo .android/ &gt;&gt; .gitignore

    echo "=&gt; get react-native-cli in here"
    npm install --no-save react-native-cli

    echo "=&gt; set up react-native plugins... need an FHS env for... reasons."
    cd .android/sdk
      $PWD/bin/sdkmanager --update
      echo "=&gt; installing platform stuff (you'll need to accept a license in a second)..."
      $PWD/bin/sdkmanager "platforms;android-23" "build-tools;23.0.1" "add-ons;addon-google_apis-google-23"
    cd ../../
  fi;
'';

}

This one is super-hacky and requires usage instructions :( also probably only works on linux :/

1. Enter the environment

$ nix-shell
[...lots of console spam the first time]
[nix-shell:]$

2. If you don't have an avd set up, make one

[nix-shell:]$ android create avd -t android-23 -b x86 -d "Nexus 5" -n nexus

That command seeme to create slightly screwy avds. I ran

$ android avd
and then hit
edit
and
save
without any changes on mine, which seems to fix it :/

3. Start the JS server and emulator

Both commands block: either background then (add

&
at the end) to run in the same terminal, or open a terminal for each
[nix-shell:]$ npm start
[nix-shell:]$ emulator -avd nexus

4. Run it!

[nix-shell:]$ run-android

Note that this

run-android
is provided by
shell.nix
, and wraps the call to
react-native-cli
's
react-native run-android
command in the FHS environment so that the build works.

Python

shell.nix
with import  {};
with pkgs.python27Packages;

stdenv.mkDerivation { name = "python";

buildInputs = [ pip python27Full virtualenv ];

shellHook = '' SOURCE_DATE_EPOCH=$(date +%s) # so that we can use python wheels YELLOW='\033[1;33m' NC="$(printf '\033[0m')"

echo -e "''${YELLOW}Creating python environment...''${NC}"
virtualenv --no-setuptools venv &gt; /dev/null
export PATH=$PWD/venv/bin:$PATH &gt; /dev/null
pip install -r requirements.txt &gt; /dev/null

''; }

This expression sets up a python 2 environment, and installs any dependencies from

requirements.txt
with
pip
in a
virtualenv
.

OS library dependencies

There is a

LD_LIBRARY_PATH
attribute for nix packages that can help python dependencies find the libraries they may need to complete installation. You generally need to format two pieces of information together: the path to the dependency in the nix store, and
/lib
.

Usually this means you just need

LD_LIBRARY_PATH=${}/lib
. However, sometimes nix packages divide up their outputs, with the
/lib
folder and its contents at their own path in the nix store. Usually, the output with
lib//
is called
out
, and can be used like
LD_LIBRARY_PATH=${.out}/lib
.

If you need to put more than on dependency into

LD_LIBRARY_PATH
, separate them with a colon
:
, like for
$PATH
.

geos
and
gdal

shell.nix
with import  {};
with pkgs.python27Packages;

stdenv.mkDerivation { name = "python";

buildInputs = [ gdal geos pip python27Full virtualenv ];

LD_LIBRARY_PATH="${geos}/lib:${gdal}/lib";

shellHook = '' SOURCE_DATE_EPOCH=$(date +%s) # so that we can use python wheels YELLOW='\033[1;33m' NC="$(printf '\033[0m')"

echo -e "''${YELLOW}Creating python environment...''${NC}"
virtualenv --no-setuptools venv &gt; /dev/null
export PATH=$PWD/venv/bin:$PATH &gt; /dev/null
pip install -r requirements.txt &gt; /dev/null

''; }

zlib

TODO

sqlite3

TODO


also, http://nixos.org/nixpkgs/manual/#using-python

Rust

TODO: mozilla nix overlay for nightly

shell.nix
with import  {};

stdenv.mkDerivation { name = "rust"; buildInputs = [ rustChannels.nightly.cargo rustChannels.nightly.rust ]; }

OpenSSL

shell.nix
with import  {};

stdenv.mkDerivation { name = "rust"; buildInputs = [ openssl rustChannels.nightly.cargo rustChannels.nightly.rust ]; shellHook = '' export OPENSSL_DIR="${openssl.dev}" export OPENSSL_LIB_DIR="${openssl.out}/lib" ''; }

diesel

shell.nix
with import  {};

stdenv.mkDerivation { name = "rust"; buildInputs = [ postgresql rustChannels.nightly.cargo rustChannels.nightly.rust ]; shellHook = '' export OPENSSL_DIR="${openssl.dev}" export OPENSSL_LIB_DIR="${openssl.out}/lib" export PATH="$PWD/bin:$PATH" export DATABASE_URL="postgres://[email protected]/db" if ! type diesel > /dev/null 2> /dev/null; then cargo install diesel_cli --no-default-features --features postgres --root $PWD fi diesel setup ''; }

TODO: talk about running postgres in a nix-shell, and don't hard-code

DATABASE_URL
in such an ugly way

cargo.toml
[dependencies.diesel]
version = "0.11"
features = ["postgres"]

[dependencies.diesel_codegen] version = "0.11" features = ["postgres"]

.gitignore
bin/

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.