Skip to content
Snippets Groups Projects
Select Git revision
  • 6a07dd9f2ae6d3c0a46ab95fff39a6239e125fb9
  • master default protected
2 results

path

user avatar
Tyson Whitehead authored
6a07dd9f
History

Overview

The regular nix-env operations manipulate (build new) environments consisting of a merge of several packages created by symlinking all the files from the individual packages together into common bin, lib, etc. directories which are then added to the users $PATH, $PYTHONPATH, etc. environment variables.

This is a project to add a more module style interface. The module utility provides a command that manipulates the users environment to enable multiple packages simultaneously by placing multiple entries in the users $PATH, $PYTHONPATH, etc. environment variables.

The following is an example of the sort of interaction we are looking to support

  1. user logs in with no Nix environment,
  2. user runs nix-path load nixpkgs.python27 nixpkgs.python27Packages.scipy,
  3. user runs nix-path unload nixpkgs.python27Packages.scipy, and
  4. user runs nix-path load nixpkgs.python27Packages.regex.

Modify user environment

As with the module command, the ultimate output of nix-path is shell script that can be sourced by the current shell in order to modify the user's environment as requested. This is done by creating a function such as

function module {
  eval "$(nix-path bash "$@")"
}

Assuming an initial empty environment, based on the final environment diff presented at the end of the computing enviroment additions section, a typical invocation would be

module load nixpkgs.python27 nixpkgs.python27Packages.scipy
export NIX_MODULES="nixpkgs.python27 nixpkgs.python27Packages.scipy"
export NIX_CC=/nix/store/jycz7ha7dm3ls1sjnznn3638193klbxv-gcc-wrapper-5.3.0
export NIX_CFLAGS_COMPILE= -isystem /nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/include -isystem /nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/include
export NIX_LDFLAGS=-rpath /nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell/lib64 -rpath /nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell/lib  -L/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/lib -L/nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0/lib -L/nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/lib -L/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/lib -L/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/lib
export PATH=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/bin:/nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/bin:/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/bin:/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/bin:/nix/store/wz6508rdk04wn5nilzil1c7zbqg7lx4w-patchelf-0.9/bin:/nix/store/krwiax9xcn6m745k5ifwbcmavmhpi43k-paxctl-0.9/bin:/nix/store/jycz7ha7dm3ls1sjnznn3638193klbxv-gcc-wrapper-5.3.0/bin:/nix/store/xmrh23qgsbrk9gd0z72sj58kg1czmpcd-binutils-2.26/bin:/nix/store/d2ljpb414jpmzik3cvl0xlmr5m4aggp7-gcc-5.3.0/bin:/nix/store/bb32xf954imhdrzn7j8h82xs1bx7p3fr-glibc-2.23/bin:/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin:/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin:/nix/store/jshnvw5qxcbz8hyjx0k5g9f5ddlny7lb-findutils-4.4.2/bin:/nix/store/sfcxcsswbgbv2vfkf6ma420zikbz4k9n-diffutils-3.3/bin:/nix/store/c2rnzsrhby57x1cg9kab7zbcgcqfam1y-gnused-4.2.2/bin:/nix/store/rlw8bhavsn39fgvvxif89f4w476x6z7p-gnugrep-2.22/bin:/nix/store/wskqdq2cif8lnr59d1yy41j5k45n21k5-gawk-4.1.3/bin:/nix/store/h0cy1px0jdr0j331r79zr3i3bybwpxqw-gnutar-1.28/bin:/nix/store/4yl71n9qsjw5bkndzdg1aarzassy6hpy-gzip-1.6/bin:/nix/store/nlhixpi844nri62cdkcp8d4dkhxwvj2j-bzip2-1.0.6/bin:/nix/store/cqnrdrxkwbq835rkyxcscdw119yppjpl-gnumake-4.1/bin:/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin:/nix/store/n1ih0w9qcjswvprycxxgx82wg10h8dpj-patch-2.7.5/bin:/nix/store/nbi1p1l7f25nr8ji9vf6bfi4blw9dhwa-xz-5.2.2/bin:"$PATH"
export CXX=g++
export PYTHONPATH=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/lib/python2.7/site-packages:/nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0/lib/python2.7/site-packages:/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/lib/python2.7/site-packages:/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/lib/python2.7/site-packages
export CC=gcc

where "$PATH" would actually be expanded by nix-path to be the original value of $PATH. Note that inclusion of $NIX_MODULES environment variable that keeps track of the currently loaded modules.

This modification to the user's environment is computed as follows

  1. compute the environment additions required by the old package set given by $NIX_MODULES,
  2. compute the new set of packages requires according to the user's secified operation (i.e., add to $NIX_MODULES on module load and remove from $NIX_MODULES on module unload),
  3. compute the environment additions required by the new package set,
  4. compute the new user's environment based by making the additions, removals, and substitutions to the current environment dictated by the difference between old environment additions and the new ones,
  5. output the new environment created from the old one by making these changes and updating $NIX_MODULES to reflect the new packages.

Comparison to nix-shell

The nix-shell -p python27 python27Packages.scipy command builds the following derivation

nix-instantiate --expr 'with import <nixpkgs> { }; runCommand "shell" { buildInputs = [ python27 python27Packages.scipy ]; } "env"'
/nix/store/c5rxb8fkfqqzxwrxafhp7gjhpszag9dm-shell.drv
pp-aterm -i /nix/store/c5rxb8fkfqqzxwrxafhp7gjhpszag9dm-shell.drv
Derive(
  [("out", "/nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell", "", "")]
, [ ("/nix/store/9my5m5a8annapkzqjizn2156wv2v71ag-bash-4.3-p42.drv", ["out"])
  , ("/nix/store/dp8i98g0gs9qf09hm6ndc2jxh7qcx656-stdenv.drv", ["out"])
  , ("/nix/store/l62r4a1ngr22f935lrf72gq2lpvv82cx-python2.7-scipy-0.17.0.drv", ["out"])
  , ("/nix/store/nc9lg7f0f0mh8882vqnqpi0pkq8zkc79-python-2.7.11.drv", ["out"])
  ]
, ["/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"]
, "x86_64-linux"
, "/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin/bash"
, ["-e", "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"]
, [ ("buildCommand", "env")
  , ("buildInputs", "")
  , ("builder", "/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin/bash")
  , ("name", "shell")
  , ("nativeBuildInputs", "/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11 /nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0")
  , ("out", "/nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell")
  , ("propagatedBuildInputs", "")
  , ("propagatedNativeBuildInputs", "")
  , ("stdenv", "/nix/store/6k2hhari1vjiy0wjjv3lcvaf8s1pcbmm-stdenv")
  , ("system", "x86_64-linux")
  ]
)

It then parses this derivation, set the environment variables indicated in it, and then starts a shell with an rcfile that does source $stdenv/setup. This is the script that prepares for doing a build inside a Nix chroot environment and it uses the various Nix hook mechanisms to create an approriate environment.

We will do the same, except, instead of starting a shell, we will output commands to set the evnironment variables. This will allow our output to be evaluated by bash and modify the user's current environment to give access to the desired packages.

Computing environment additions

This section details how to determine what environment additions are required to enable a set of Nix packages.

We need the store paths for coreutils, stdenv, and each of the packages our user would like in their environment

nix-env --query --available --out-path --attr nixpkgs.bash
nix-env --query --available --out-path --attr nixpkgs.coreutils
nix-env --query --available --out-path --attr nixpkgs.stdenv
nix-env --query --available --out-path --attr nixpkgs.python27
nix-env --query --available --out-path --attr nixpkgs.python27Packages.scipy
bash-4.3-p42  doc=/nix/store/mzc36xa3w8djrafpc9sfxzyb9bafjbr3-bash-4.3-p42-doc;/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42
coreutils-8.25  /nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25
stdenv  /nix/store/6k2hhari1vjiy0wjjv3lcvaf8s1pcbmm-stdenv
python-2.7.11  /nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11
python2.7-scipy-0.17.0  /nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0

The bash and stdenv paths can be burned into nix-path, but the stdenv package should likely always be looked up to ensure the version agrees with the requested packages. If any of these store paths do not exist then we need to create them. See build packages for details.

cat << "EOF" | /nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin/env -i /nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin/bash
export TMPDIR="$(/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin/mktemp -d)"

echo '# Pre-setup environment'
export NIX_BUILD_TOP="$TMPDIR"
export NIX_STORE=/nix/store
export nativeBuildInputs="/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11 /nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0"
export out="/nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell"
export stdenv="/nix/store/6k2hhari1vjiy0wjjv3lcvaf8s1pcbmm-stdenv"
/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin/env

echo '# Post-setup environment'
source "$stdenv/setup"
unset NIX_ENFORCE_PURITY NIX_INDENT_MAKE NIX_BUILD_CORES SOURCE_DATE_EPOCH TZ SSL_CERT_FILE _PATH shell SHELL CONFIG_SHELL
/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin/env

rm -fr "$TMPDIR"
EOF
# Pre-setup environment
TMPDIR=/tmp/tmp.wQwnLiyZVf
nativeBuildInputs=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11 /nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0
NIX_STORE=/nix/store
stdenv=/nix/store/6k2hhari1vjiy0wjjv3lcvaf8s1pcbmm-stdenv
NIX_BUILD_TOP=/tmp/tmp.wQwnLiyZVf
PWD=/home/tyson/nix-path
out=/nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell
SHLVL=1
_=/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin/env
# Post-setup environment
NIX_CC=/nix/store/jycz7ha7dm3ls1sjnznn3638193klbxv-gcc-wrapper-5.3.0
TMPDIR=/tmp/tmp.wQwnLiyZVf
NIX_CFLAGS_COMPILE= -isystem /nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/include -isystem /nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/include
nativeBuildInputs=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11 /nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0
NIX_STORE=/nix/store
stdenv=/nix/store/6k2hhari1vjiy0wjjv3lcvaf8s1pcbmm-stdenv
NIX_LDFLAGS=-rpath /nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell/lib64 -rpath /nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell/lib  -L/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/lib -L/nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0/lib -L/nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/lib -L/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/lib -L/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/lib
PATH=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/bin:/nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/bin:/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/bin:/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/bin:/nix/store/wz6508rdk04wn5nilzil1c7zbqg7lx4w-patchelf-0.9/bin:/nix/store/krwiax9xcn6m745k5ifwbcmavmhpi43k-paxctl-0.9/bin:/nix/store/jycz7ha7dm3ls1sjnznn3638193klbxv-gcc-wrapper-5.3.0/bin:/nix/store/xmrh23qgsbrk9gd0z72sj58kg1czmpcd-binutils-2.26/bin:/nix/store/d2ljpb414jpmzik3cvl0xlmr5m4aggp7-gcc-5.3.0/bin:/nix/store/bb32xf954imhdrzn7j8h82xs1bx7p3fr-glibc-2.23/bin:/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin:/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin:/nix/store/jshnvw5qxcbz8hyjx0k5g9f5ddlny7lb-findutils-4.4.2/bin:/nix/store/sfcxcsswbgbv2vfkf6ma420zikbz4k9n-diffutils-3.3/bin:/nix/store/c2rnzsrhby57x1cg9kab7zbcgcqfam1y-gnused-4.2.2/bin:/nix/store/rlw8bhavsn39fgvvxif89f4w476x6z7p-gnugrep-2.22/bin:/nix/store/wskqdq2cif8lnr59d1yy41j5k45n21k5-gawk-4.1.3/bin:/nix/store/h0cy1px0jdr0j331r79zr3i3bybwpxqw-gnutar-1.28/bin:/nix/store/4yl71n9qsjw5bkndzdg1aarzassy6hpy-gzip-1.6/bin:/nix/store/nlhixpi844nri62cdkcp8d4dkhxwvj2j-bzip2-1.0.6/bin:/nix/store/cqnrdrxkwbq835rkyxcscdw119yppjpl-gnumake-4.1/bin:/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin:/nix/store/n1ih0w9qcjswvprycxxgx82wg10h8dpj-patch-2.7.5/bin:/nix/store/nbi1p1l7f25nr8ji9vf6bfi4blw9dhwa-xz-5.2.2/bin
NIX_BUILD_TOP=/tmp/tmp.wQwnLiyZVf
PWD=/home/tyson/nix-path
CXX=g++
out=/nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell
CONFIG_SHELL=/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin/bash
SHLVL=1
PYTHONPATH=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/lib/python2.7/site-packages:/nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0/lib/python2.7/site-packages:/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/lib/python2.7/site-packages:/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/lib/python2.7/site-packages
CC=gcc
_=/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin/env

We then need to compute the difference between these two environments to see what the $stdenv/setup script has done

NIX_CC=/nix/store/jycz7ha7dm3ls1sjnznn3638193klbxv-gcc-wrapper-5.3.0
NIX_CFLAGS_COMPILE= -isystem /nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/include -isystem /nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/include
NIX_LDFLAGS=-rpath /nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell/lib64 -rpath /nix/store/a2j8f1mvk039bkvyxfzdlpa5h31k3k0z-shell/lib  -L/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/lib -L/nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0/lib -L/nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/lib -L/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/lib -L/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/lib
PATH=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/bin:/nix/store/jvnlwk07wqwrry024x07isq83wz8j30k-openblas-0.2.14/bin:/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/bin:/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/bin:/nix/store/wz6508rdk04wn5nilzil1c7zbqg7lx4w-patchelf-0.9/bin:/nix/store/krwiax9xcn6m745k5ifwbcmavmhpi43k-paxctl-0.9/bin:/nix/store/jycz7ha7dm3ls1sjnznn3638193klbxv-gcc-wrapper-5.3.0/bin:/nix/store/xmrh23qgsbrk9gd0z72sj58kg1czmpcd-binutils-2.26/bin:/nix/store/d2ljpb414jpmzik3cvl0xlmr5m4aggp7-gcc-5.3.0/bin:/nix/store/bb32xf954imhdrzn7j8h82xs1bx7p3fr-glibc-2.23/bin:/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin:/nix/store/lphk3qrh53kv2j69b3sry5jmhfbrz1ns-coreutils-8.25/bin:/nix/store/jshnvw5qxcbz8hyjx0k5g9f5ddlny7lb-findutils-4.4.2/bin:/nix/store/sfcxcsswbgbv2vfkf6ma420zikbz4k9n-diffutils-3.3/bin:/nix/store/c2rnzsrhby57x1cg9kab7zbcgcqfam1y-gnused-4.2.2/bin:/nix/store/rlw8bhavsn39fgvvxif89f4w476x6z7p-gnugrep-2.22/bin:/nix/store/wskqdq2cif8lnr59d1yy41j5k45n21k5-gawk-4.1.3/bin:/nix/store/h0cy1px0jdr0j331r79zr3i3bybwpxqw-gnutar-1.28/bin:/nix/store/4yl71n9qsjw5bkndzdg1aarzassy6hpy-gzip-1.6/bin:/nix/store/nlhixpi844nri62cdkcp8d4dkhxwvj2j-bzip2-1.0.6/bin:/nix/store/cqnrdrxkwbq835rkyxcscdw119yppjpl-gnumake-4.1/bin:/nix/store/7sb42axk5lrxqz45nldrb2pchlys14s1-bash-4.3-p42/bin:/nix/store/n1ih0w9qcjswvprycxxgx82wg10h8dpj-patch-2.7.5/bin:/nix/store/nbi1p1l7f25nr8ji9vf6bfi4blw9dhwa-xz-5.2.2/bin
CXX=g++
PYTHONPATH=/nix/store/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11/lib/python2.7/site-packages:/nix/store/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0/lib/python2.7/site-packages:/nix/store/5ag1nw0s6mzhmhxrm0ij8s76yvi2wxpp-python2.7-numpy-1.10.4/lib/python2.7/site-packages:/nix/store/mkav3jmz0p6jd8ik7h9mnfa3i3k5vrjw-python2.7-setuptools-19.4/lib/python2.7/site-packages
CC=gcc

Building packages

We could just request nix-store to realize the outpaths, but this will only works if they are available via a substitution. We will instead go through the derivation even though this is a bit of a pain because only nix-env support the special handling of ~/.nix-defexpr (i.e., going through it and subdirectories to create an attribute set from all the top-level nix expressions in it).

To be entirely correct it is a good idea to throw in some GC links. We do this using the following scheme for the tempoary derivation links nix-path-<host>-<pid>-<n>

nix-instantiate --add-root /nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-1 --expr 'with import <nixpkgs> { }; python27'
nix-instantiate --add-root /nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-2 --expr 'with import <nixpkgs> { }; python27Packages.scipy'
/nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-1
/nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-2
nix-store --add-root /nix/var/nix/gcroots/per-user/tyson/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11 --realize /nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-1
nix-store --add-root /nix/var/nix/gcroots/per-user/tyson/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0 --realize /nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-2
rm /nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-1
rm /nix/var/nix/gcroots/per-user/tyson/nix-path-gb241-4534-2
/nix/var/nix/gcroots/per-user/tyson/88186csqfg6v6zldsip0w122hwp761m6-python-2.7.11
/nix/var/nix/gcroots/per-user/tyson/w7fj1fxrjvhshik2d71zlfxns8hjn0dh-python2.7-scipy-0.17.0

We leave the links to the actual packages in the store to avoid the garbage collector collecting them while the user is using them.