Skip to content

Commit 415103a

Browse files
authored
Nix and CI Improvements (#89)
* First take on Cachix config in GitHub Actions Ideally, this should both pull *and* push from the Haskell.org Cachix cache that we set up. * Put the install Nix step back in Looks like cachix-action itself doesn't install Nix for you * Enabled manual triggering of the PR build * Added --print-build-logs flag to nix build command in CI Also switched all our Nix commands to use long flags * Added --verbose to nix build command * Moved Haskell code into its own directory and started using Niv
1 parent ee66679 commit 415103a

File tree

9 files changed

+285
-52
lines changed

9 files changed

+285
-52
lines changed

.github/workflows/main.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name: CI
33
on:
44
pull_request:
55
push:
6+
workflow_dispatch:
67

78
jobs:
89
build:
@@ -14,12 +15,18 @@ jobs:
1415
- name: Install Nix
1516
uses: cachix/install-nix-action@v12
1617

18+
- name: Cachix
19+
uses: cachix/cachix-action@v10
20+
with:
21+
name: haskell-org
22+
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
23+
1724
- name: Build Site
1825
# we run the checks as a separate step
19-
run: nix build -f . built -o built-site --arg doCheck false
26+
run: nix build --verbose --print-build-logs --file . built -o built-site --arg doCheck false
2027

2128
- name: Check Links
22-
run: nix run --quiet -f . linkchecker -c linkchecker built-site
29+
run: nix run --quiet --file . linkchecker --command linkchecker built-site
2330

2431
- uses: actions/upload-artifact@v2
2532
with:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ dist-newstyle
1010
# Nix
1111
result*
1212
built-site
13+
14+
# Emacs
15+
*~

builder/LICENSE

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Copyright (c) 2019, Isaac Shapira
2+
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above
12+
copyright notice, this list of conditions and the following
13+
disclaimer in the documentation and/or other materials provided
14+
with the distribution.
15+
16+
* Neither the name of Isaac Shapira nor the names of other
17+
contributors may be used to endorse or promote products derived
18+
from this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

builder/default.nix

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{ sources ? import ../nix/sources.nix
2+
, pkgs ? import sources.nixpkgs {}
3+
}:
4+
(pkgs.haskellPackages.developPackage {
5+
name = builtins.baseNameOf ./.;
6+
root = pkgs.nix-gitignore.gitignoreSourcePure [
7+
../.gitignore
8+
"*.markdown"
9+
"*.md"
10+
"*.html"
11+
"templates/*"
12+
"css/*"
13+
"js/*"
14+
"img/*"
15+
".git"
16+
".github"
17+
] ./.;
18+
modifier = drv: pkgs.haskell.lib.overrideCabal drv (attrs: {
19+
buildTools = with pkgs.haskellPackages; (attrs.buildTools or []) ++ [
20+
cabal-install
21+
ghcid
22+
hakyll
23+
pkgs.linkchecker
24+
];
25+
});
26+
}).overrideAttrs (old: {
27+
LOCALE_ARCHIVE = "${pkgs.glibcLocales}/lib/locale/locale-archive";
28+
LC_ALL = "C.UTF-8";
29+
shellHook = ''
30+
alias buildAndWatch="cabal configure && cabal build && cabal exec haskell-org-site -- clean && cabal exec haskell-org-site -- watch"
31+
echo ""
32+
echo " Haskell.org Dev Shell"
33+
echo " \`buildAndWatch\` to serve the site, and rebuild when files change."
34+
echo " \`linkchecker\`, \`ghcid\` and \`cabal\` are provided in this environment."
35+
echo ""
36+
'';
37+
})
File renamed without changes.

site.hs renamed to builder/site.hs

File renamed without changes.

default.nix

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,16 @@
1-
{ compiler ? "ghc883"
2-
, rev ? "d4226e3a4b5fcf988027147164e86665d382bbfa" # from Nix 20.03 release
3-
, pkgs ?
4-
import (builtins.fetchTarball {
5-
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
6-
}) {}
7-
, doCheck ? true
1+
{ doCheck ? true
2+
, sources ? import ./nix/sources.nix
3+
, pkgs ? import sources.nixpkgs {}
84
}:
95

106
let
11-
12-
gitignore = pkgs.callPackage (pkgs.fetchFromGitHub {
13-
owner = "siers";
14-
repo = "nix-gitignore";
15-
rev = "4f2d85f2f1aa4c6bff2d9fcfd3caad443f35476e";
16-
sha256 = "1vzfi3i3fpl8wqs1yq95jzdi6cpaby80n8xwnwa8h2jvcw3j7kdz";
17-
}) {};
18-
19-
builder = (pkgs.haskell.packages.${compiler}.developPackage {
20-
name = builtins.baseNameOf ./.;
21-
root = gitignore.gitignoreSource [
22-
"*.markdown"
23-
"*.md"
24-
"*.html"
25-
"templates/*"
26-
"css/*"
27-
"js/*"
28-
"img/*"
29-
".git"
30-
".github"
31-
] ./.;
32-
modifier = drv: pkgs.haskell.lib.overrideCabal drv (attrs: {
33-
buildTools = with pkgs.haskell.packages.${compiler}; (attrs.buildTools or []) ++ [
34-
cabal-install
35-
ghcid
36-
hakyll
37-
pkgs.linkchecker
38-
];
39-
});
40-
}).overrideAttrs (old: {
41-
LOCALE_ARCHIVE = "${pkgs.glibcLocales}/lib/locale/locale-archive";
42-
LC_ALL = "C.UTF-8";
43-
shellHook = ''
44-
alias buildAndWatch="cabal configure && cabal build && cabal exec haskell-org-site -- clean && cabal exec haskell-org-site -- watch"
45-
echo ""
46-
echo " Haskell.org Dev Shell"
47-
echo " \`buildAndWatch\` to serve the site, and rebuild when files change."
48-
echo " \`linkchecker\`, \`ghcid\` and \`cabal\` are provided in this environment."
49-
echo ""
50-
'';
51-
});
52-
7+
builder = import ./builder { inherit sources pkgs; };
538
built = pkgs.stdenv.mkDerivation {
549
name = "haskell.org";
5510
inherit doCheck;
5611

57-
src = gitignore.gitignoreSource [
12+
src = pkgs.nix-gitignore.gitignoreSourcePure [
13+
./.gitignore
5814
".git"
5915
"*.cabal"
6016
"*.hs"

nix/sources.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"niv": {
3+
"branch": "master",
4+
"description": "Easy dependency management for Nix projects",
5+
"homepage": "https://github.com/nmattia/niv",
6+
"owner": "nmattia",
7+
"repo": "niv",
8+
"rev": "94080ae8286024820c570a2a24ed7c36d7ad04a9",
9+
"sha256": "0wlk52zwlrq727x3z1vg9d9qq4zw62ab5jzg4068iqb6hyb0cr0w",
10+
"type": "tarball",
11+
"url": "https://github.com/nmattia/niv/archive/94080ae8286024820c570a2a24ed7c36d7ad04a9.tar.gz",
12+
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
13+
},
14+
"nixpkgs": {
15+
"branch": "nixpkgs-20.09-darwin",
16+
"description": "Nix Packages collection",
17+
"homepage": "",
18+
"owner": "NixOS",
19+
"repo": "nixpkgs",
20+
"rev": "05f3800b80f159ee5ef0eccd8e31a645e6723feb",
21+
"sha256": "0zx8xaa58ldvw1vw2gslnj0zldjvm2kryk3jdzv1j32m29v6302v",
22+
"type": "tarball",
23+
"url": "https://github.com/NixOS/nixpkgs/archive/05f3800b80f159ee5ef0eccd8e31a645e6723feb.tar.gz",
24+
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
25+
}
26+
}

nix/sources.nix

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# This file has been generated by Niv.
2+
3+
let
4+
5+
#
6+
# The fetchers. fetch_<type> fetches specs of type <type>.
7+
#
8+
9+
fetch_file = pkgs: name: spec:
10+
let
11+
name' = sanitizeName name + "-src";
12+
in
13+
if spec.builtin or true then
14+
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
15+
else
16+
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
17+
18+
fetch_tarball = pkgs: name: spec:
19+
let
20+
name' = sanitizeName name + "-src";
21+
in
22+
if spec.builtin or true then
23+
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
24+
else
25+
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
26+
27+
fetch_git = name: spec:
28+
let
29+
ref =
30+
if spec ? ref then spec.ref else
31+
if spec ? branch then "refs/heads/${spec.branch}" else
32+
if spec ? tag then "refs/tags/${spec.tag}" else
33+
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
34+
in
35+
builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
36+
37+
fetch_local = spec: spec.path;
38+
39+
fetch_builtin-tarball = name: throw
40+
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
41+
$ niv modify ${name} -a type=tarball -a builtin=true'';
42+
43+
fetch_builtin-url = name: throw
44+
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
45+
$ niv modify ${name} -a type=file -a builtin=true'';
46+
47+
#
48+
# Various helpers
49+
#
50+
51+
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
52+
sanitizeName = name:
53+
(
54+
concatMapStrings (s: if builtins.isList s then "-" else s)
55+
(
56+
builtins.split "[^[:alnum:]+._?=-]+"
57+
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
58+
)
59+
);
60+
61+
# The set of packages used when specs are fetched using non-builtins.
62+
mkPkgs = sources: system:
63+
let
64+
sourcesNixpkgs =
65+
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
66+
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
67+
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
68+
in
69+
if builtins.hasAttr "nixpkgs" sources
70+
then sourcesNixpkgs
71+
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
72+
import <nixpkgs> {}
73+
else
74+
abort
75+
''
76+
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
77+
add a package called "nixpkgs" to your sources.json.
78+
'';
79+
80+
# The actual fetching function.
81+
fetch = pkgs: name: spec:
82+
83+
if ! builtins.hasAttr "type" spec then
84+
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
85+
else if spec.type == "file" then fetch_file pkgs name spec
86+
else if spec.type == "tarball" then fetch_tarball pkgs name spec
87+
else if spec.type == "git" then fetch_git name spec
88+
else if spec.type == "local" then fetch_local spec
89+
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
90+
else if spec.type == "builtin-url" then fetch_builtin-url name
91+
else
92+
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
93+
94+
# If the environment variable NIV_OVERRIDE_${name} is set, then use
95+
# the path directly as opposed to the fetched source.
96+
replace = name: drv:
97+
let
98+
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
99+
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
100+
in
101+
if ersatz == "" then drv else
102+
# this turns the string into an actual Nix path (for both absolute and
103+
# relative paths)
104+
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
105+
106+
# Ports of functions for older nix versions
107+
108+
# a Nix version of mapAttrs if the built-in doesn't exist
109+
mapAttrs = builtins.mapAttrs or (
110+
f: set: with builtins;
111+
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
112+
);
113+
114+
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
115+
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
116+
117+
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
118+
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
119+
120+
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
121+
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
122+
concatMapStrings = f: list: concatStrings (map f list);
123+
concatStrings = builtins.concatStringsSep "";
124+
125+
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
126+
optionalAttrs = cond: as: if cond then as else {};
127+
128+
# fetchTarball version that is compatible between all the versions of Nix
129+
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
130+
let
131+
inherit (builtins) lessThan nixVersion fetchTarball;
132+
in
133+
if lessThan nixVersion "1.12" then
134+
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
135+
else
136+
fetchTarball attrs;
137+
138+
# fetchurl version that is compatible between all the versions of Nix
139+
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
140+
let
141+
inherit (builtins) lessThan nixVersion fetchurl;
142+
in
143+
if lessThan nixVersion "1.12" then
144+
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
145+
else
146+
fetchurl attrs;
147+
148+
# Create the final "sources" from the config
149+
mkSources = config:
150+
mapAttrs (
151+
name: spec:
152+
if builtins.hasAttr "outPath" spec
153+
then abort
154+
"The values in sources.json should not have an 'outPath' attribute"
155+
else
156+
spec // { outPath = replace name (fetch config.pkgs name spec); }
157+
) config.sources;
158+
159+
# The "config" used by the fetchers
160+
mkConfig =
161+
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
162+
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
163+
, system ? builtins.currentSystem
164+
, pkgs ? mkPkgs sources system
165+
}: rec {
166+
# The sources, i.e. the attribute set of spec name to spec
167+
inherit sources;
168+
169+
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
170+
inherit pkgs;
171+
};
172+
173+
in
174+
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

0 commit comments

Comments
 (0)