Commit 9930ea81 authored by ttuegel's avatar ttuegel Committed by GitHub
Browse files

Merge pull request #4193 from ttuegel/nix

Nix integration improvements
parents 19d9738f 10dc4ab4
{ mkDerivation, array, base, binary, bytestring, containers
, deepseq, directory, exceptions, filepath, old-time, pretty
, process, QuickCheck, regex-posix, stdenv, tagged, tasty
, tasty-hunit, tasty-quickcheck, time, transformers, unix
, deepseq, directory, filepath, pretty, process, QuickCheck, stdenv
, tagged, tasty, tasty-hunit, tasty-quickcheck, time, unix
}:
mkDerivation {
pname = "Cabal";
version = "1.25.0.0";
src = ./Cabal;
src = ./.;
libraryHaskellDepends = [
array base binary bytestring containers deepseq directory filepath
pretty process time unix
];
testHaskellDepends = [
array base bytestring containers directory exceptions filepath
old-time pretty process QuickCheck regex-posix tagged tasty
tasty-hunit tasty-quickcheck time transformers unix
array base containers directory filepath pretty QuickCheck tagged
tasty tasty-hunit tasty-quickcheck
];
doCheck = false;
homepage = "http://www.haskell.org/cabal/";
......
......@@ -12,7 +12,7 @@ To enable Nix integration, simply pass the ``--enable-nix`` global option when y
nix: True
If the package (which must be locally unpacked) provides a ``shell.nix`` file, this flag will cause ``cabal`` to run most commands through ``nix-shell``. The following commands are affected:
If the package (which must be locally unpacked) provides a ``shell.nix`` or ``default.nix`` file, this flag will cause ``cabal`` to run most commands through ``nix-shell``. If both expressions are present, ``shell.nix`` is preferred. The following commands are affected:
- ``cabal configure``
- ``cabal build``
......@@ -23,7 +23,7 @@ If the package (which must be locally unpacked) provides a ``shell.nix`` file, t
- ``cabal gen-bounds``
- ``cabal run``
If the package does not provide a ``shell.nix``, ``cabal`` runs normally.
If the package does not provide an expression, ``cabal`` runs normally.
Creating Nix Expressions
------------------------
......@@ -34,6 +34,15 @@ The Nix package manager is based on a lazy, pure, functional programming languag
$ cabal2nix --shell ./. >shell.nix
Nix Expression Evaluation
-------------------------
(This section describes for advanced users how Nix expressions are evaluated.)
First, the Nix expression (``shell.nix`` or ``default.nix``) is instantiated with ``nix-instantiate``. The ``--add-root`` and ``--indirect`` options are used to create an indirect root in the Cabal build directory, preventing Nix from garbage collecting the derivation while in use. The ``IN_NIX_SHELL`` environment variable is set so that ``builtins.getEnv`` works as it would in ``nix-shell``.
Next, the commands above are run through ``nix-shell`` using the instantiated derivation. Again, ``--add-root`` and ``--indirect`` are used to prevent Nix from garbage collecting the packages in the environment. The child ``cabal`` process reads the ``CABAL_IN_NIX_SHELL`` environment variable to prevent it from spawning additional child shells.
Further Reading
----------------
......
......@@ -14,18 +14,20 @@ module Distribution.Client.Nix
import Control.Applicative ((<$>))
#endif
import Control.Exception (catch)
import Control.Exception (bracket, catch)
import Control.Monad (filterM, when, unless)
import System.Directory
( createDirectoryIfMissing, doesDirectoryExist, doesFileExist
, makeAbsolute, removeDirectoryRecursive, removeFile )
import System.Environment (getExecutablePath, getArgs, lookupEnv)
import System.Environment (getArgs, getExecutablePath)
import System.FilePath
( (</>), (<.>), replaceExtension, takeDirectory, takeFileName )
import System.IO (IOMode(..), hClose, openFile)
import System.IO.Error (isDoesNotExistError)
import System.Process (showCommandForUser)
import Distribution.Compat.Environment
( lookupEnv, setEnv, unsetEnv )
import Distribution.Compat.Semigroup
import Distribution.Verbosity
......@@ -70,6 +72,18 @@ findNixExpr globalFlags config = do
else return Nothing
-- set IN_NIX_SHELL so that builtins.getEnv in Nix works as in nix-shell
inFakeNixShell :: IO a -> IO a
inFakeNixShell f =
bracket (fakeEnv "IN_NIX_SHELL" "1") (resetEnv "IN_NIX_SHELL") (\_ -> f)
where
fakeEnv var new = do
old <- lookupEnv var
setEnv var new
return old
resetEnv var = maybe (unsetEnv var) (setEnv var)
nixInstantiate
:: Verbosity
-> FilePath
......@@ -98,8 +112,9 @@ nixInstantiate verb dist force globalFlags config =
removeGCRoots verb dist
touchFile timestamp
_ <- getDbProgramOutput verb prog progdb
[ "--add-root", shellDrv, "--indirect", shellNix ]
_ <- inFakeNixShell
(getDbProgramOutput verb prog progdb
[ "--add-root", shellDrv, "--indirect", shellNix ])
return ()
......@@ -128,6 +143,9 @@ nixShell verb dist globalFlags config go = do
cabal <- getExecutablePath
-- alreadyInShell == True in child process
setEnv "CABAL_IN_NIX_SHELL" "1"
-- Run cabal with the same arguments inside nix-shell.
-- When the child process reaches the top of nixShell, it will
-- detect that it is running inside the shell and fall back
......@@ -151,7 +169,7 @@ gcrootPath dist = dist </> "nix" </> "gcroots"
inNixShell :: IO Bool
inNixShell = maybe False (const True) <$> lookupEnv "IN_NIX_SHELL"
inNixShell = maybe False (const True) <$> lookupEnv "CABAL_IN_NIX_SHELL"
removeGCRoots :: Verbosity -> FilePath -> IO ()
......
{ mkDerivation, array, async, base, base16-bytestring, binary
, bytestring, Cabal, containers, cryptohash-sha256, deepseq
, directory, filepath, hackage-security, hashable, HTTP, mtl
, network, network-uri, pretty, pretty-show, process, QuickCheck
, random, regex-posix, stdenv, stm, tagged, tar, tasty, tasty-hunit
, tasty-quickcheck, time, unix, zlib
, directory, echo, edit-distance, filepath, hackage-security
, hashable, HTTP, mtl, network, network-uri, pretty, pretty-show
, process, QuickCheck, random, regex-posix, stdenv, stm, tagged
, tar, tasty, tasty-hunit, tasty-quickcheck, time, unix, zlib
}:
mkDerivation {
pname = "cabal-install";
version = "1.25.0.0";
src = ./cabal-install;
src = ./.;
isLibrary = false;
isExecutable = true;
setupHaskellDepends = [ base Cabal filepath process ];
executableHaskellDepends = [
array async base base16-bytestring binary bytestring Cabal
containers cryptohash-sha256 deepseq directory filepath
hackage-security hashable HTTP mtl network network-uri pretty
process random stm tar time unix zlib
containers cryptohash-sha256 deepseq directory echo edit-distance
filepath hackage-security hashable HTTP mtl network network-uri
pretty process random stm tar time unix zlib
];
testHaskellDepends = [
array async base base16-bytestring binary bytestring Cabal
......@@ -25,6 +25,7 @@ mkDerivation {
pretty-show process QuickCheck random regex-posix stm tagged tar
tasty tasty-hunit tasty-quickcheck time unix zlib
];
doCheck = false;
postInstall = ''
mkdir $out/etc
mv bash-completion $out/etc/bash_completion.d
......
......@@ -16,7 +16,11 @@ let
in
haskellPackages.override {
overrides = self: super: {
Cabal = filterSource (self.callPackage ./Cabal.nix {});
cabal-install = filterSource (lib.dontCheck (self.callPackage ./cabal-install.nix {}));
Cabal =
filterSource (self.callPackage ./Cabal {});
cabal-install =
filterSource (lib.dontCheck (self.callPackage ./cabal-install {}));
hackage-security =
lib.dontCheck super.hackage-security;
};
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment