nixpkgs.overlays and nixpkgs.config.packageOverrides not being reflected in environment.systemPackages - nixos

It seems that when I override a python3 package in nixpkgs.config.packageOverrides or nixpkgs.overlays, a python application in environment.systemPackages is not using those overrides. How can I get that overridden python3 package to be used in a python3 application?
Example darwin-configuration.nix that uses nixpkgs.overlays:
{ config, pkgs, lib, ... }:
{
environment.systemPackages =
[
pkgs.myawscli2
];
nixpkgs.overlays = let overlayRemovePyopenssl = self: super:
let removePyopenssl = pythonpkgs:
lib.filter
(pythonpkg: !(pythonpkg != null && pythonpkg ? pname && pythonpkg.pname == "pyopenssl"))
pythonpkgs;
in {
python3 = super.python3.override {
packageOverrides = python-self: python-super: rec {
# Delete pyopenssl; workaround for broken package on darwin-aarch64
# “Package ‘python3.10-pyopenssl-22.0.0’ in /nix/store/<hash>-nixpkgs/nixpkgs/pkgs/development/python-modules/pyopenssl/default.nix:73 is marked as broken, refusing to evaluate”
# https://github.com/NixOS/nixpkgs/issues/174457
urllib3 = python-super.urllib3.overridePythonAttrs (origattrs: rec {
propagatedBuildInputs = removePyopenssl origattrs.propagatedBuildInputs;
});
twisted = python-super.twisted.overridePythonAttrs (origattrs: {
checkInputs = removePyopenssl origattrs.checkInputs;
});
};
};
myawscli2 = (self.awscli2.override {
# override the python3 arg of awscli2
# https://github.com/NixOS/nixpkgs/blob/f72be3af76fb7dc45e2088d8cb9aba1e6767a930/pkgs/tools/admin/awscli2/default.nix#L2
python3 = self.python3;
});
}; in
[
overlayRemovePyopenssl
];
system.stateVersion = 4;
}
The overlay is applied properly in the individual python package urllib3:
nix-repl> lib = import <nixpkgs>.lib
nix-repl> :l <darwin>
nix-repl> lib.forEach pkgs.python3.pkgs.urllib3.propagatedBuildInputs (x: x.pname)
[ "brotli" "certifi" "cryptography" "idna" "python3" ]
However, the overlay was not applied to the python application that uses urllib3. Note that pyopenssl is in the dependencies of urllib3 when used by awscli2:
nix-repl> lib.forEach (lib.findFirst (x: x.pname == "urllib3") null pkgs.awscli2.propagatedBuildInputs).propagatedBuildInputs (x: x.pname)
[ "brotli" "certifi" "cryptography" "idna" "pyopenssl" "python3" ]
I also tried the same thing with nixpkgs.config.packageOverrides with the same effect:
{ config, pkgs, lib, ... }:
{
environment.systemPackages =
[
pkgs.myawscli2
];
nixpkgs.config.packageOverrides = super:
let removePyopenssl = pythonpkgs:
lib.filter
(pythonpkg: !(pythonpkg != null && lib.hasAttr "pname" pythonpkg && pythonpkg.pname == "pyopenssl"))
pythonpkgs;
in {
python3 = super.python3.override {
packageOverrides = python-self: python-super: rec {
# workaround for
# “Package ‘python3.10-pyopenssl-22.0.0’ in /nix/store/<hash>-nixpkgs/nixpkgs/pkgs/development/python-modules/pyopenssl/default.nix:73 is marked as broken, refusing to evaluate”
# https://github.com/NixOS/nixpkgs/issues/174457
urllib3 = python-super.urllib3.overridePythonAttrs (origattrs: rec {
propagatedBuildInputs = removePyopenssl origattrs.propagatedBuildInputs;
});
twisted = python-super.twisted.overridePythonAttrs (origattrs: {
checkInputs = removePyopenssl origattrs.checkInputs;
});
};
};
myawscli2 = (pkgs.awscli2.override {
python3 = pkgs.python3;
});
};
system.stateVersion = 4;
}
This seems to contradict the nixpkgs manual, which says: “pythonPackages.twisted is now globally overridden. All packages and also all NixOS services that reference twisted (such as services.buildbot-worker) now use the new definition”

I also asked this on Element. The problem is that awscli2/default.nix calls python3.override {packageOverrides = …;}:
py = python3.override {
packageOverrides = self: super: {
…
};
};
This unfortunately overwrites my own .override {packageOverrides = …;}. Unfortunately you can’t compose (python.override {packageOverrides = …;}).override {packageOverrides = …;}
I worked around this by checking out nixpkgs and editing the awscli2 nix to combine the python application’s packageOverrides with packageOverrides from the arguments:
py = python3.override (oldargs: {
packageOverrides = self: super: {
…
} // (if oldargs?packageOverrides then (oldargs.packageOverrides self super) else super);
});

Related

How to get use `callCabal2nix` to supply package list to 'ghcWithPackages'?

I have a list of ~46 dependencies.
I produce a shell using among other things a call to:
server = pkgs.haskellPackages.callCabal2nix "server" ./server.cabal { };
within an override of pkgs.haskellPackages that goes into pkgs.myHaskellPackages.
The shell works fine. However, I have another nix for building a docker and this requires a build input that comes from:
ghc = pkgs.myHaskellPackages.ghcWithPackages (p: [ longlistofdependencies ]);
How do I specify the long list of dependencies without having to write them out manually, defeating the purpose of using callCabal2nix in the first place.
let
bootstrap = import <nixpkgs> { };
nixpkgs = builtins.fromJSON (builtins.readFile ./nixpkgs-unstable.json);
src = bootstrap.fetchFromGitHub {
owner = "NixOS";
repo = "nixpkgs";
inherit (nixpkgs) rev sha256;
};
config = {
allowBroken = true;
packageOverrides = pkgs: rec {
servantSrc = pkgs.fetchFromGitHub {
owner = "haskell-servant";
repo = "servant";
rev = "73c87bc2bc0685649f2337b06ab4fdc66c4ce1dd";
sha256 = "0sw4mrncmfna30cyxrvinc1krqhfxn5dcc1ggzqfy39s0yl9q98r";
#sha256 = "0000000000000000000000000000000000000000000000000000";
} + "/servant";
myHaskellPackages = pkgs.haskellPackages.override {
overrides = haskellPackagesNew: haskellPackagesOld: rec {
server =
haskellPackagesNew.callCabal2nix "server" ./server.cabal { };
servant =
haskellPackagesNew.callCabal2nix "servant" servantSrc {};
# several other overridden packages
};
};
};
};
pkgs = import src { inherit config; };
devShell = pkgs.myHaskellPackages.shellFor {
packages = p: [
p.server
];
buildInputs = with pkgs.haskellPackages; [
hlint
brittany
haskell-language-server
];
};
# Every time a dependency changes in the cabal file, this has to be edited as well.
ghc = pkgs.myHaskellPackages.ghcWithPackages (p: [
p.aeson p.aeson-qq p.base p.blaze-html p.bytestring p.cache p.containers
p.contravariant-extras p.criterion p.either p.hashable p.hasql
p.hasql-migration p.hasql-pool p.hasql-th p.hasql-transaction p.hspec
p.http-client p.http-conduit p.http-types p.immortal-queue p.lens p.linear
p.monad-logger p.mtl p.pqueue p.pretty-simple p.QuickCheck p.raw-strings-qq
p.servant-blaze p.servant-docs p.servant-server
p.string-interpolate p.text p.text-format p.time p.tuple p.unordered-containers
p.utf8-string p.vector p.vector-split p.wai p.wai-cors p.warp p.xlsx p.yaml
]);
in {
inherit devShell;
inherit ghc;
inherit pkgs;
}
The ghc output is used in docker.nix as a build input:
let
inherit (import ./pinned-nixpkgs.nix) ghc pkgs;
pricing-server =
pkgs.stdenv.mkDerivation {
name = "my-server";
pname = "my-server";
version = "1.1.0";
src = ./.;
buildPhase = ''
ghc -O2 --make -outputdir ./tmp2 Main.hs
'';
installPhase = ''
mkdir -p $out/bin
cp Main $out/bin
cp -r ./sql $out/bin
'';
buildInputs = [ ghc ];
};
in
dockerTools.buildImage {
# irrelevant to the question.
}
A possible solution is pkgs.myHaskellPackages.server.getBuildInputs.haskellBuildInputs, or pkgs.myHaskellPackages.server.getCabalDeps.libraryHaskellDepends.
You can explore these attributes, or any expression, with nix repl. You may have to expose some values from your let bindings though. In this case I just browsed through haskellPackages.warp in nix repl <nixpkgs>.
I also noticed you use rec in an overlay. This will work for you until it doesn't. I'd recommend to remove rec to avoid accessing attributes in a third way and use the more standard haskellPackagesNew.servant instead.

How to write a shell.nix file which combines other nix-shell environments?

I want to write a shell.nix file that will provide me a development environment which includes developer tools + haskell dependencies. I would like to keep my nix expressions separate - for now that means one file containing information about my editor, and one file containing information about my haskell project.
I have tried to set up a really basic environment, but can't get it to work. I have two files which I can create a nix-shell from already:
# my-haskell-shell.nix - generated by cabal2nix --shell
{ nixpkgs ? import <nixpkgs> {}, compiler ? "default", doBenchmark ? false }:
let
inherit (nixpkgs) pkgs;
f = { mkDerivation, base, cabal-install, hpack, stdenv }:
mkDerivation {
pname = "hello-world";
version = "0.1.0.0";
src = ./.;
isLibrary = false;
isExecutable = true;
libraryToolDepends = [ hpack ];
executableHaskellDepends = [ base ];
executableToolDepends = [ cabal-install hpack ];
preConfigure = "hpack";
license = stdenv.lib.licenses.mit;
};
haskellPackages = if compiler == "default"
then pkgs.haskellPackages
else pkgs.haskell.packages.${compiler};
variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;
drv = variant (haskellPackages.callPackage f {});
in
if pkgs.lib.inNixShell then drv.env else drv
# my-neovim-shell.nix
with import <nixpkgs> {};
let
my-neovim = neovim.override { vimAlias = false; };
in
stdenv.mkDerivation {
name = "neovim-dev-env";
buildInputs = [
my-neovim
];
}
Both of these produce useful shell environments! (That is, nix-shell my-haskell-env.nix and nix-shell my-neovim-env.nix give me cabal and neovim respectively, but not both).
My attempt at producing a shell.nix which will provide an environment with both neovim and cabal available is this:
# shell.nix
with import <nixpkgs> {};
let
my-neovim-shell-env = import ./my-neovim-shell.nix;
my-haskell-shell-env = import ./my-haskell-shell.nix {};
in
stdenv.mkDerivation {
name = "my-new-env";
buildInputs = [
my-neovim-shell-env
my-haskell-shell-env
];
}
This does not work however. It seems to try to build the neovim environment:
$ nix-shell
these derivations will be built:
/nix/store/k9ygid1wl75vf2nq7jzfh32mv5f8i956-neovim-dev-env.drv
building '/nix/store/k9ygid1wl75vf2nq7jzfh32mv5f8i956-neovim-dev-env.drv'...
unpacking sources
variable $src or $srcs should point to the source
builder for '/nix/store/k9ygid1wl75vf2nq7jzfh32mv5f8i956-neovim-dev-env.drv' failed with exit code 1
error: build of '/nix/store/k9ygid1wl75vf2nq7jzfh32mv5f8i956-neovim-dev-env.drv' failed
I don't know how to fix this; what am I doing wrong? I suspect maybe I should not be using mkDerivation?
Managed to find a solution. Maybe there is a better way, but this works:
Suppose you have a package.yaml, then
$ cabal2nix . > app.nix
# shell.nix
let
p = import <nixpkgs> {};
app = p.haskellPackages.callPackage (./app.nix) {};
lib = p.haskell.lib;
in
lib.overrideCabal app (old: { buildTools = [p.my-nvim] ++ (old.buildTools or []); })
(where I've added my-nvim to my ~/.config/nixpkgs/overlays/)
Now I have access to the my-nvim package and ghc, etc:
$ nix-shell
$ nvim # works
$ ghc # works
Inspiration from https://github.com/p-implies-q/nix-util

Building haskell package for n different version

I'm trying to build bytestring and it fails with an error related to quickcheck. After a quick check (no pun intended), I found out that bytestring has a dependency on quickcheck with version >= 2.4 && < 2.10 and by default nix build quickcheck version 2.10.1.
After reading this now I know I can switch the quickcheck's version.
shell.nix:
{ compiler ? "default", doBenchmark ? false }:
let
config = { packageOverrides = pkgs: rec {
haskellPackages = pkgs.haskellPackages.override {
overrides = haskellPackagesNew: haskellPackagesOld: rec {
myproject = haskellPackagesNew.callPackage ./default.nix { };
QuickCheck = haskellPackagesNew.callPackage ./quickcheck.nix { };
};
};
};
};
pkgs = (import <nixpkgs> { inherit config; }).pkgs;
f = import ./default.nix;
haskellPackages = if compiler == "default"
then pkgs.haskellPackages
else pkgs.haskell.packages.${compiler};
variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;
drv = variant (haskellPackages.callPackage f { development = true;});
in
{myproject = if pkgs.lib.inNixShell then drv.env else drv;}
default.nix and quickcheck.nix is generated with cabal2nix.
Now it throws a different error that some of the package are missing its dependencies which is quickcheck with version >=2.10.
How to tell that only bytestring will use the custom version?
Edit: quickcheck's version switched to 2.9.2
Overriding a dependency on a single package
The problem is that the package set was created with the original quickcheck version. Globally overriding a much-used package like that is bound to cause problems.
Instead, you can override specific edges in the dependency graph like this:
myproject.overrideScope (self: super: {
QuickCheck = haskellPackagesNew.callPackage ./quickcheck.nix { };
});
Composability
Your example can be improved further by using haskellPackages.extend instead of overrides. This will give freedom to further extend your package set after you have extended it before.
Another change you can make is to avoid rec recursive attribute sets in the definition of overrides and overlays. It is often best to use self instead. See this blog post on flyingcircus.io.
It's also a good idea to switch from packageOverrides to overlays.
These things may not cause issues right now, but will lead to surprises in larger projects, so it's better to avoid them in the first place.
End result
I hope I got this right because I don't have the complete example.
{ compiler ? "default", doBenchmark ? false }:
let
overlays = [(pkgs: super: {
haskellPackages = super.haskellPackages.extend ( hself: hsuper: {
myproject = (hself.callPackage ./default.nix {}).overrideScope (pself: psuper: {
QuickCheck = pself.QuickCheck_2_9;
});
QuickCheck_2_9 = hself.callPackage ./quickcheck.nix { };
};
);
};
)];
pkgs = (import <nixpkgs> { inherit overlays; }).pkgs;
f = import ./default.nix;
haskellPackages = if compiler == "default"
then pkgs.haskellPackages
else pkgs.haskell.packages.${compiler};
variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;
drv = variant (haskellPackages.callPackage f { development = true;});
in
{myproject = if pkgs.lib.inNixShell then drv.env else drv;}

How to add linux config in configuration.nix

I currently have this in my nixpkgs.config
packageOverrides = pkgs: rec {
netbeans81 = pkgs.stdenv.lib.overrideDerivation pkgs.netbeans ( oldAttrs: {
name = "netbeans-8.1";
src = pkgs.fetchurl {
url = http://download.netbeans.org/netbeans/8.1/final/zip/netbeans-8.1-201510222201.zip;
md5 = "361ce18421761a057bad5cb6cf7b58f4";
};
});
};
and I want to add a kernel config. I added this
packageOverrides = pkgs: {
stdenv = pkgs.stdenv // {
platform = pkgs.stdenv.platform // {
kernelExtraConfig = "SND_HDA_PREALLOC_SIZE 4096";
};
};
};
but that did not work. The problem is packageOverrides is already defined.
How can I add the kernel configs and my netbeans overrides?
In the nix language, braces ({}) indicate attribute sets (not scope like in C++ etc.). You can have multiple items in a single attribute set (attr. sets are like dicts in python). Also, nix is a functional language, which means there is no state. This, in turn, means that you can't redefine a variable in the same scope. In the words of Eminem, "You only get one shot".
Try this:
packageOverrides = pkgs: rec {
netbeans81 = pkgs.stdenv.lib.overrideDerivation pkgs.netbeans (oldAttrs: {
name = "netbeans-8.1";
src = pkgs.fetchurl {
url = http://download.netbeans.org/netbeans/8.1/final/zip/netbeans-8.1-201510222201.zip;
md5 = "361ce18421761a057bad5cb6cf7b58f4";
};
});
stdenv = pkgs.stdenv // {
platform = pkgs.stdenv.platform // {
kernelExtraConfig = "SND_HDA_PREALLOC_SIZE 4096";
};
};
};

nix-shell: how to specify a custom environment variable?

I'm learning about nixos and nix expressions. In a project folder I created a shell.nix and I when I run nix-shell I want it to preset an environment variable for me.
For example to set the PGDATA env var.
I know there are several ways to write nix expression files (I'm not yet used to most of them). Here is my sample:
shell.nix
let
pkgs = import <nixpkgs> {};
name = "test";
in pkgs.myEnvFun {
buildInputs = [
pkgs.python
pkgs.libxml2
];
inherit name;
extraCmds = ''
export TEST="ABC"
'';
}
Use buildPythonPackage function (that uses mkDerivation). Passing anything to it will set env variables in bash shell:
with import <nixpkgs> {};
buildPythonPackage {
name = "test";
buildInputs = [ pkgs.python pkgs.libxml2 ];
src = null;
PGDATA = "...";
}
You may also use pkgs.stdenv.mkDerivation.shellHook.
let
pkgs = import <nixpkgs> {};
name = "test";
in pkgs.stdenv.mkDerivation {
buildInputs = [
pkgs.python
pkgs.libxml2
];
inherit name;
shellHook = ''
export TEST="ABC"
'';
}
To set environment variable for a nix-shell without creating a new package, shellHook option can be used. As shown in the example from the manual:
shellHook =
''
echo "Hello shell"
export SOME_API_TOKEN="$(cat ~/.config/some-app/api-token)"
'';
A full shell.nix example based on my use-case - with go of version 1.18 from unstable channel:
let
pkgs = import <nixpkgs> {};
unstable = import <nixos-unstable> { config = { allowUnfree = true; }; };
in pkgs.mkShell rec {
name = "go-1.18";
buildInputs = with pkgs; [
unstable.go_1_18
];
shellHook = ''
export PATH="$HOME/go/bin:$PATH"
'';
}
The script also sets name option, which is then shown in the shell prompt (works nicely with Starship shell prompt).

Resources