Skip to content

Commit 79f2b1f

Browse files
authored
Merge pull request #12 from cdepillabout/new-package-set
Add method for creating completely new package set
2 parents ebe4011 + 867cd13 commit 79f2b1f

9 files changed

Lines changed: 275 additions & 11 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ jobs:
102102
run: "nix develop -L --command cabal test all"
103103
working-directory: "./my-example-haskell-lib-advanced/"
104104

105+
- name: "Tests"
106+
run: "nix-build"
107+
working-directory: "./test/"
108+
105109
nix-commit-from-flake-lock:
106110
name: nix / ubuntu-latest / using stacklock2nix commit from flake.lock
107111
runs-on: ubuntu-latest

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
# Nix result files
3-
/result
3+
result
4+
result-*
45

56
# Haskell .gitignore
67
dist

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1+
## 1.1.0
2+
3+
* Added two new attributes to the attribute set returned from a call to
4+
`stacklock2nix`: `newPkgSet` and `newPkgSetDevShell`. These two values are
5+
similar to the existing `pkgSet` and `devShell` attributes. Whereas
6+
`pkgSet` and `devShell` take the `baseHaskellPkgSet` argument and overlay
7+
it with package overrides created from your `stack.yaml` file, `newPkgSet`
8+
and `newPkgSetDevShell` are a completely new package set, containing _only_
9+
packages from your `stack.yaml`.
10+
11+
The effect of this is that `pkgSet` will contain packages that are in
12+
Nixpkgs, but not in Stackage. For instance, when using `pkgSet`, you
13+
should be able to access the package
14+
[`pkgSet.termonad`](https://hackage.haskell.org/package/termonad) because
15+
it is available on Hackage (and in Nixpkgs), even though it is not in any
16+
Stackage resolver.
17+
18+
However, `newPkgSet` will only contain packages in your `stack.yaml` file.
19+
For instance, you'll never be able to access `newPkgSet.termonad` or
20+
`newPkgSet.spago`, because they will likely never be available on Stackage.
21+
22+
In general, in your own projects, should you use `pkgSet` or `newPkgSet`?
23+
24+
For building your own projects, most of the time `pkgSet` and `newPkgSet`
25+
should be similar. `newPkgSet` may be slightly safer, since there is
26+
almost no chance you accidentally use a Haskell package outside of your
27+
`stack.yaml`. `pkgSet` may be slightly more convenient depending on what
28+
you're trying to do.
29+
130
## 1.0.0
231

332
* This is the 1.0 release of `stacklock2nix`. I've tested `stacklock2nix` on

nix/build-support/stacklock2nix/cabal2nixArgsForPkg.nix

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,55 @@
3636
# for testing, but this is not necessary to build the Haskell library.
3737
#
3838
# Please feel free to send PRs adding necessary overrides here.
39+
#
40+
# Make sure to keep this list in alphabetical order.
3941

4042
cabal2nixArgsOverrides {
4143
"gi-cairo" = ver: { cairo = pkgs.cairo; };
44+
4245
"gi-gdk" = ver: { gtk3 = pkgs.gtk3; };
46+
4347
"gi-gio" = ver: { glib = pkgs.glib; };
48+
4449
"gi-glib" = ver: { glib = pkgs.glib; };
50+
4551
"gi-gtk" = ver: { gtk3 = pkgs.gtk3; };
52+
4653
"gi-gmodule" = ver: { gmodule = null; };
54+
4755
"gi-gobject" = ver: { glib = pkgs.glib; };
56+
4857
"gi-harfbuzz" = ver: { harfbuzz-gobject = null; };
58+
4959
"gi-pango" = ver: { cairo = pkgs.cairo; pango = pkgs.pango; };
60+
5061
"gi-vte" = ver: { vte_291 = pkgs.vte; };
62+
5163
"glib" = ver: { glib = pkgs.glib; };
64+
5265
"haskell-gi" = ver: { glib = pkgs.glib; gobject-introspection = pkgs.gobject-introspection; };
66+
5367
"haskell-gi-base" = ver: { glib = pkgs.glib; };
68+
69+
# The PSQueue and fingertree-psqueue packages are used in benchmarks, but they are not on Stackage.
70+
"psqueues" = ver: { fingertree-psqueue = null; PSQueue = null; };
71+
5472
"saltine" = ver: { libsodium = pkgs.libsodium; };
73+
5574
"secp256k1-haskell" = ver: { secp256k1 = pkgs.secp256k1; };
75+
5676
"splitmix" = ver: { testu01 = null; };
77+
78+
"test-framework" = ver: { libxml = pkgs.libxml; };
79+
5780
"termonad" = ver: { vte_291 = pkgs.vte; gtk3 = pkgs.gtk3; pcre2 = pkgs.pcre2;};
81+
82+
# unordered-containers uses the Haskell package nothunks in its test-suite,
83+
# but nothunks is not in Stackage. We disable the tests for unordered-containers
84+
# in the suggestedOverlay.nix file, but callCabal2Nix is called on it before
85+
# suggestedOverlay.nix is applied. So here we need to just pass in null for
86+
# the nothunks dependency, since it won't end up being used.
87+
"unordered-containers" = ver: { nothunks = null; };
88+
5889
"zlib" = ver: { zlib = pkgs.zlib; };
5990
}

nix/build-support/stacklock2nix/default.nix

Lines changed: 127 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
, lib
66
, runCommand
77
, stdenv
8+
, path
89
}@topargs:
910

1011
{ # The path to your stack.yaml file.
@@ -77,6 +78,10 @@
7778
# This is not used if `baseHaskellPkgSet` is `null`.
7879
all-cabal-hashes ? null
7980
, callPackage ? topargs.callPackage
81+
, # Path to Nixpkgs.
82+
#
83+
# nixpkgsPath :: Path
84+
nixpkgsPath ? topargs.path
8085
}:
8186

8287
# The stack.yaml path can be computed from the stack.yaml.lock path, or
@@ -372,7 +377,7 @@ let
372377
# This roughly returns an overlay that looks like the following:
373378
# ```
374379
# { lens = callHackage "lens" "5.0.1" {};
375-
# conduit = callHackage "conduit" "5.0.1" {};
380+
# conduit = callHackage "conduit" "1.3.4" {};
376381
# }
377382
# ```
378383
haskPkgLocksToOverlay = haskPkgLocks: hfinal: hprev:
@@ -635,22 +640,135 @@ let
635640
inherit all-cabal-hashes;
636641
});
637642

643+
devShellForPkgSet = packageSet:
644+
if packageSet == null then
645+
null
646+
else
647+
packageSet.shellFor {
648+
packages = localPkgsSelector;
649+
nativeBuildInputs = additionalDevShellNativeBuildInputs packageSet;
650+
};
651+
638652
# A development shell created by passing all your local packages (from
639653
# `localPkgsSelector`) to `pkgSet.shellFor`.
640654
#
641655
# devShell :: Drv
642656
#
643657
# Note that this derivation is specifically meant to be passed to `nix
644658
# develop` or `nix-shell`.
645-
devShell =
646-
if pkgSet == null then
659+
devShell = devShellForPkgSet pkgSet;
660+
661+
# An Nixpkgs Haskell overlay that has GHC boot packages set to `null`. This
662+
# is used as an initial overlay when creating a brand new package set.
663+
newPkgSetCompilerConfig = self: super: {
664+
# TODO: Should llvmPackages be enabled here?
665+
# llvmPackages = pkgs.lib.dontRecurseIntoAttrs self.ghc.llvmPackages;
666+
667+
# Disable GHC core libraries.
668+
array = null;
669+
base = null;
670+
binary = null;
671+
bytestring = null;
672+
Cabal = null;
673+
containers = null;
674+
deepseq = null;
675+
directory = null;
676+
exceptions = null;
677+
filepath = null;
678+
ghc-bignum = null;
679+
ghc-boot = null;
680+
ghc-boot-th = null;
681+
ghc-compact = null;
682+
ghc-heap = null;
683+
ghc-prim = null;
684+
ghci = null;
685+
haskeline = null;
686+
hpc = null;
687+
integer-gmp = null;
688+
libiserv = null;
689+
mtl = null;
690+
parsec = null;
691+
pretty = null;
692+
process = null;
693+
rts = null;
694+
stm = null;
695+
template-haskell = null;
696+
697+
# GHC only builds terminfo if it is a native compiler
698+
# terminfo = if pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform then null else self.terminfo_0_4_1_5;
699+
terminfo = null;
700+
701+
text = null;
702+
time = null;
703+
transformers = null;
704+
unix = null;
705+
706+
# GHC only bundles the xhtml library if haddock is enabled, check if this is
707+
# still the case when updating: https://gitlab.haskell.org/ghc/ghc/-/blob/0198841877f6f04269d6050892b98b5c3807ce4c/ghc.mk#L463
708+
# xhtml = if self.ghc.hasHaddock or true then null else self.xhtml_3000_2_2_1;
709+
xhtml = null;
710+
};
711+
712+
# This is similar to `pkgSet`.
713+
#
714+
# While `pkgSet` is `baseHaskellPkgSet` overridden with overlays from your
715+
# stack.yaml.lock file, `newPkgSet` is a completely new Nixpkgs Haskell
716+
# package set. It _only_ contains packages defined in the `stack.yaml` file.
717+
#
718+
# newPkgSet :: HaskellPkgSet
719+
#
720+
# `newPkgSet` will contain local packages. For instance, if you have a local
721+
# package called `my-haskell-pkg`:
722+
#
723+
# Example: `newPkgSet.my-haskell-pkg`
724+
#
725+
# `newPkgSet` will also contain packages in your stack.yaml resolver. For
726+
# instance:
727+
#
728+
# Example: `newPkgSet.lens`
729+
#
730+
# `pkgSet` will _not_ contain packages from the underlying Haskell package
731+
# set. For instance, `termonad` is not available in Stackage, so it is not
732+
# available in `newPkgSet`.
733+
newPkgSet =
734+
if baseHaskellPkgSet == null then
647735
null
648736
else
649-
pkgSet.shellFor {
650-
packages = localPkgsSelector;
651-
nativeBuildInputs = additionalDevShellNativeBuildInputs pkgSet;
652-
};
737+
let
738+
haskPkgSet = callPackage (nixpkgsPath + "/pkgs/development/haskell-modules") {
739+
haskellLib = haskell.lib.compose;
740+
741+
# TODO: Is it okay to use a completely different package set as the
742+
# base package set like this?
743+
buildHaskellPackages = baseHaskellPkgSet;
744+
745+
ghc = baseHaskellPkgSet.ghc;
746+
747+
compilerConfig = newPkgSetCompilerConfig;
748+
749+
initialPackages = _: _: {};
750+
751+
overrides = lib.composeManyExtensions [
752+
# It is not possible to put these overlays into the
753+
# `initialPackages` argument, because they use functions like
754+
# `callHackage` and `callCabal2nix`, which appear to not be
755+
# available when `initialPackages` gets evaluated.
756+
combinedOverlay
757+
additionalHaskellPkgSetOverrides
758+
];
759+
760+
nonHackagePackages = _: _: {};
761+
configurationCommon = _: _: _: {};
762+
configurationNix = _: _: _: {};
763+
configurationArm = _: _: _: {};
764+
configurationDarwin = _: _: _: {};
765+
};
766+
in haskPkgSet;
653767

768+
# Same as `devShell`, but based on `newPkgSet`.
769+
#
770+
# newPkgSetDevShell :: Drv
771+
newPkgSetDevShell = devShellForPkgSet newPkgSet;
654772
in
655773

656774
{ inherit
@@ -662,6 +780,8 @@ in
662780
localPkgsSelector
663781
pkgSet
664782
devShell
783+
newPkgSet
784+
newPkgSetDevShell
665785
;
666786

667787
# These are a bunch of internal attributes, used for testing.

nix/build-support/stacklock2nix/suggestedOverlay.nix

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
# ```
2929
#
3030
# These will be maintained on a best-effort basis. Again, please send PRs.
31+
#
32+
# Make sure to keep this list in alphabetical order.
3133

3234
hfinal: hprev: with haskell.lib.compose; {
3335

@@ -155,9 +157,6 @@ hfinal: hprev: with haskell.lib.compose; {
155157

156158
nanospec = dontCheck hprev.nanospec;
157159

158-
# test suite doesn't build
159-
nothunks = dontCheck hprev.nothunks;
160-
161160
# circular dependency in tests
162161
options = dontCheck hprev.options;
163162

@@ -213,6 +212,9 @@ hfinal: hprev: with haskell.lib.compose; {
213212
# tests don't support musl
214213
unix-time = dontCheck hprev.unix-time;
215214

215+
# Test suite requires the nothunks library, which isn't on stackage.
216+
unordered-containers = dontCheck hprev.unordered-containers;
217+
216218
vector = dontCheck hprev.vector;
217219

218220
# test suite uses phantom js

test/default.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
{...}:
3+
4+
(import ./nixpkgs.nix {}).stacklock2nix-tests

test/nixpkgs.nix

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
{...}:
3+
4+
let
5+
flake-lock = builtins.fromJSON (builtins.readFile ../my-example-haskell-lib-advanced/flake.lock);
6+
7+
# Use the Nixpkgs that the my-example-haskell-lib-advanced is pinned to.
8+
nixpkgs-src = builtins.fetchTarball {
9+
url = "https://github.com/NixOS/nixpkgs/archive/${flake-lock.nodes.nixpkgs.locked.rev}.tar.gz";
10+
sha256 = flake-lock.nodes.nixpkgs.locked.narHash;
11+
};
12+
13+
overlays = [
14+
# stacklock2nix overlay
15+
(import ../nix/overlay.nix)
16+
17+
# tests
18+
(final: prev: {
19+
stacklock2nix-tests =
20+
(final.callPackage ./test-new-package-set.nix {}) ++ [
21+
# new tests go here
22+
];
23+
})
24+
];
25+
26+
pkgs = import nixpkgs-src { inherit overlays; };
27+
28+
in
29+
30+
pkgs

test/test-new-package-set.nix

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
{ stacklock2nix
3+
, haskell
4+
, cabal-install
5+
, fetchurl
6+
}:
7+
8+
let
9+
hasklib = haskell.lib.compose;
10+
11+
stacklock = stacklock2nix {
12+
stackYaml = ../my-example-haskell-lib-advanced/stack.yaml;
13+
baseHaskellPkgSet = haskell.packages.ghc924;
14+
additionalHaskellPkgSetOverrides = hfinal: hprev: {
15+
# The servant-cassava.cabal file is malformed on GitHub:
16+
# https://github.com/haskell-servant/servant-cassava/pull/29
17+
servant-cassava =
18+
hasklib.overrideCabal
19+
{ editedCabalFile = null; revision = null; }
20+
hprev.servant-cassava;
21+
22+
amazonka = hasklib.dontCheck hprev.amazonka;
23+
amazonka-core = hasklib.dontCheck hprev.amazonka-core;
24+
amazonka-sso = hasklib.dontCheck hprev.amazonka-sso;
25+
amazonka-sts = hasklib.dontCheck hprev.amazonka-sts;
26+
};
27+
cabal2nixArgsOverrides = args: args // {
28+
amazonka-sso = ver: { amazonka-test = null; };
29+
amazonka-sts = ver: { amazonka-test = null; };
30+
};
31+
additionalDevShellNativeBuildInputs = stacklockHaskellPkgSet: [
32+
cabal-install
33+
];
34+
all-cabal-hashes = fetchurl {
35+
name = "all-cabal-hashes";
36+
url = "https://github.com/commercialhaskell/all-cabal-hashes/archive/9ab160f48cb535719783bc43c0fbf33e6d52fa99.tar.gz";
37+
sha256 = "sha256-QC07T3MEm9LIMRpxIq3Pnqul60r7FpAdope6S62sEX8=";
38+
};
39+
};
40+
in
41+
[ stacklock.newPkgSet.my-example-haskell-app
42+
stacklock.newPkgSetDevShell
43+
]

0 commit comments

Comments
 (0)