Skip to content
This repository was archived by the owner on Feb 13, 2021. It is now read-only.

Commit ba4e8c7

Browse files
committed
Faster, more succeeding builds, better everything
- Now fetching nixpgks with fetchFromGitHub by computing and saving the sha256 at update time - Detecting core GHC libraries and setting them to null to fix builds, workaround for input-output-hk/stack2nix#134 - Add override directory to fix builds for specific ghc versions - Speed up builds by disabling library profiling for everything - New nix file structure with powerful selection mechanisms
1 parent 199a76b commit ba4e8c7

File tree

4 files changed

+162
-35
lines changed

4 files changed

+162
-35
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
result*

Design.org

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,31 @@ Assumption: The stack build does not depend on which nixpkgs version it uses, it
55
- history-nixpkgs-unstable
66
- nixpkgs
77
- haskell-ide-engine
8+
- per-ghcMinor
9+
- <major><minor>: File with the list of base libraries for that ghc version
810
- per-nixpkgs
9-
- <nixpkgsrev-ghcVersions>: File with a list of ghc versions this nixpkgs rev has
11+
- ghcVersions
12+
- <nixpkgsrev>: File with a list of ghc versions this nixpkgs rev has
13+
- sha256
14+
- <nixpkgsRev>: sha256 hash for fetchFromGitHub
1015
- per-haskell-ide-engine
1116
- <hie-rev>
1217
- <ghcVersion-stack2nix>.nix: File generated by stack2nix for hie-rev and ghcVersion
1318

14-
./generated/ layout:
19+
./ layout:
1520
- nixpkgsForGhc
1621
- <ghcVersion>: File containing the nixpkgsrev to use for that ghc
17-
- stable
18-
- <ghcVersion>.nix: File copied from the cache
19-
- revision: File with the git revision of current stable hie
20-
- unstable
21-
- <ghcVersion>.nix: File copied from the cache
22-
- revision: File with the git revision of current unstable hie
22+
- nixpkgsHashes
23+
- <nixpkgsRevision>: File containing the sha256 hash for fetchFromGitHub for a nixpkgs version
24+
- ghcBaseLibraries:
25+
- <ghcVersion>: List of base libraries for that ghc version
26+
- versions
27+
- stable
28+
- <ghcVersion>.nix: File copied from the cache
29+
- revision: File with the git revision of current stable hie
30+
- unstable
31+
- <ghcVersion>.nix: File copied from the cache
32+
- revision: File with the git revision of current unstable hie
2333

2434
Flags:
2535
- Whether master should be regenerated

default.nix

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,106 @@ with builtins;
33

44
let
55

6-
nixpkgsForGhc = mapAttrs (file: _: readFile (./nixpkgsForGhc + "/${file}"))
6+
7+
pkgsForGhc = mapAttrs (ghc: _: let
8+
rev = readFile (./nixpkgsForGhc + "/${ghc}");
9+
sha256 = readFile (./nixpkgsHashes + "/${rev}");
10+
in
11+
import (fetchTarball {
12+
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
13+
inherit sha256;
14+
}) {
15+
config = {};
16+
overlays = [];
17+
})
718
(readDir ./nixpkgsForGhc);
819

920
version = name:
1021
mapAttrs' (file: _: let
1122
ghcVersion = removeSuffix ".nix" file;
12-
pkgs = import (fetchGit {
13-
url = "https://github.com/NixOS/nixpkgs";
14-
rev = nixpkgsForGhc.${ghcVersion};
15-
}) {};
16-
build = pkgs.haskell.lib.justStaticExecutables
17-
(import (./versions + "/${name}/${file}") {
23+
pkgs = pkgsForGhc.${ghcVersion};
24+
inherit (pkgs) lib haskell;
25+
26+
overrideFun = old: {
27+
overrides = lib.composeExtensions
28+
(lib.composeExtensions
29+
(old.overrides or (self: super: {}))
30+
(hself: hsuper: {
31+
32+
# Disable library profiling for faster builds
33+
mkDerivation = args: hsuper.mkDerivation (args // {
34+
enableLibraryProfiling = false;
35+
});
36+
37+
# Embed the ghc version into the name
38+
haskell-ide-engine = haskell.lib.overrideCabal hsuper.haskell-ide-engine (old: {
39+
pname = "${old.pname}-${ghcVersion}";
40+
});
41+
}
42+
// lib.flip genAttrs (name: null)
43+
(lib.filter (name: name != "ghc" && name != "Cabal")
44+
(map (name: (builtins.parseDrvName name).name)
45+
(lib.splitString " "
46+
(builtins.readFile (./ghcBaseLibraries + "/${ghcVersion}")))))
47+
)
48+
)
49+
(if builtins.pathExists (./overrides + "/${ghcVersion}.nix") then
50+
import (./overrides + "/${ghcVersion}.nix")
51+
else self: super: {}
52+
);
53+
};
54+
55+
build = haskell.lib.justStaticExecutables
56+
((import (./versions + "/${name}/${file}") {
1857
inherit pkgs;
19-
}).haskell-ide-engine;
20-
in if hasSuffix ".nix" file then {
58+
}).override overrideFun).haskell-ide-engine;
59+
in {
2160
name = ghcVersion;
2261
value = build;
23-
} else {
24-
name = file;
25-
value = builtins.readFile (./versions + "/${name}/${file}");
26-
})
27-
(readDir (./versions + "/${name}"));
28-
29-
in rec {
62+
})
63+
(filterAttrs (file: _: file != "revision") (readDir (./versions + "/${name}")));
3064

3165
versions = mapAttrs (file: _: version file) (readDir ./versions);
3266

33-
forGhc = versions.unstable // versions.stable;
67+
pkgs = import <nixpkgs> {};
68+
lib = pkgs.lib;
69+
70+
parseNixGhcVersion = version:
71+
lib.concatStringsSep "." (builtins.match "ghc(.)(.)(.)" version);
72+
73+
combine = versions: let
74+
wrapperVersion = lib.last (lib.attrNames versions);
75+
in pkgs.runCommand "haskell-ide-engine-combined" {
76+
nativeBuildInputs = [ pkgs.makeWrapper ];
77+
} ''
78+
mkdir -p $out/bin
79+
80+
${concatMapStringsSep "\n" (ghcVersion: ''
81+
ln -s ${versions.${ghcVersion}}/bin/hie $out/bin/hie-${parseNixGhcVersion ghcVersion}
82+
'') (lib.attrNames versions)}
83+
84+
makeWrapper ${versions.${wrapperVersion}}/bin/hie-wrapper $out/bin/hie-wrapper \
85+
--suffix PATH : $out/bin
86+
ln -s hie-wrapper $out/bin/hie
87+
'';
88+
89+
inherit (versions) stable unstable;
90+
91+
makeSet = versions: combine versions // {
92+
inherit versions;
93+
select = selector: makeSet (selector versions);
94+
minors = mapAttrs (name: makeSet)
95+
(foldl' (acc: el: let minor = lib.substring 0 (lib.stringLength el - 1) el; in
96+
acc // {
97+
${minor} = acc.${minor} or {} // { ${el} = versions.${el}; };
98+
}
99+
) {} (lib.attrNames versions));
100+
};
34101

35-
# forGhcs (p: [ p.ghc864 p.ghc863 ])
36-
forGhcs = selector: null;
102+
result = makeSet (unstable // stable) // {
103+
onlyStable = makeSet stable;
104+
onlyUnstable = makeSet unstable;
105+
allVersions = versions;
106+
};
37107

38-
}
108+
in result

update.hs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,23 @@ import System.Process
2828
import Text.Regex.Applicative
2929

3030
data Env = Env
31-
{ gitBin :: FilePath
32-
, nixBin :: FilePath
33-
, cacheDir :: FilePath
34-
, manager :: Manager
31+
{ gitBin :: FilePath
32+
, nixBin :: FilePath
33+
, nixHashBin :: FilePath
34+
, nixBuildBin :: FilePath
35+
, cpBin :: FilePath
36+
, cacheDir :: FilePath
37+
, manager :: Manager
3538
}
3639

3740
-- | Initializes the read-only environment
3841
getEnv :: IO Env
3942
getEnv = Env
4043
<$> (fromMaybe (error "Can't find git executable") <$> findExecutable "git")
4144
<*> (fromMaybe (error "Can't find nix-instantiate executable") <$> findExecutable "nix-instantiate")
45+
<*> (fromMaybe (error "Can't find nix-hash executable") <$> findExecutable "nix-hash")
46+
<*> (fromMaybe (error "Can't find nix-build executable") <$> findExecutable "nix-build")
47+
<*> (fromMaybe (error "Can't find cp executable") <$> findExecutable "cp")
4248
<*> getXdgDirectory XdgCache "all-hies"
4349
<*> newTlsManager
4450

@@ -64,9 +70,13 @@ run = do
6470

6571
setupDirectories :: App ()
6672
setupDirectories = do
67-
cachePath "per-nixpkgs" >>= liftIO . createDirectoryIfMissing True
73+
cachePath "per-nixpkgs/ghcVersions" >>= liftIO . createDirectoryIfMissing True
74+
cachePath "per-nixpkgs/sha256" >>= liftIO . createDirectoryIfMissing True
6875
cachePath "per-hie" >>= liftIO . createDirectoryIfMissing True
76+
cachePath "per-ghcMinor" >>= liftIO . createDirectoryIfMissing True
6977
liftIO $ createDirectoryIfMissing True "nixpkgsForGhc"
78+
cleanDirectory "ghcBaseLibraries"
79+
cleanDirectory "nixpkgsHashes"
7080

7181
-- | Makes sure that the given directory is existent and empty
7282
cleanDirectory :: FilePath -> App ()
@@ -122,13 +132,49 @@ genS2N hash version = do
122132
exists <- liftIO $ doesFileExist path
123133

124134
nixpkgsRev <- findNixpkgsForGhc version
135+
sha <- nixpkgsSha nixpkgsRev
136+
liftIO $ writeFile ("nixpkgsHashes" </> nixpkgsRev) sha
137+
138+
genBaseLibraries version nixpkgsRev
125139

126140
unless exists $ do
127141
liftIO $ putStrLn $ "Using nixpkgs revision " ++ nixpkgsRev ++ " for ghc version " ++ show version
128142
git nixpkgs [ "checkout", nixpkgsRev ]
129143
callStack2nix hash path version
130144
return path
131145

146+
genBaseLibraries :: Version -> String -> App ()
147+
genBaseLibraries version@(Version major minor patch) nixpkgsRev = do
148+
cache <- cachePath $ "per-ghcMinor" </> show major ++ show minor
149+
exists <- liftIO $ doesFileExist cache
150+
unless exists $ do
151+
git nixpkgs [ "checkout", nixpkgsRev ]
152+
nix <- lift $ asks nixBuildBin
153+
ghcPath <- liftIO $ init <$> readProcess nix
154+
[ "--no-out-link", "<nixpkgs>", "-A", "haskell.compiler." ++ nixVersion version ] ""
155+
libs <- liftIO $ readProcess (ghcPath </> "bin/ghc-pkg")
156+
[ "list", "--no-user-package-db", "--simple" ] ""
157+
liftIO $ writeFile cache libs
158+
liftIO $ copyFile cache ("ghcBaseLibraries" </> nixVersion version)
159+
160+
nixpkgsSha :: String -> App String
161+
nixpkgsSha revision = do
162+
cacheFile <- cachePath $ "per-nixpkgs/sha256" </> revision
163+
exists <- liftIO $ doesFileExist cacheFile
164+
if exists then liftIO $ readFile cacheFile
165+
else do
166+
git nixpkgs [ "checkout", revision ]
167+
path <- repoPath nixpkgs
168+
tmp <- cachePath "tmp"
169+
cp <- lift $ asks cpBin
170+
liftIO $ readProcess cp ["-rl", path, tmp] ""
171+
liftIO $ removeDirectoryRecursive (tmp </> ".git")
172+
nixHash <- lift $ asks nixHashBin
173+
hash <- liftIO $ head . lines <$> readProcess nixHash ["--type", "sha256", "--base32", tmp] ""
174+
liftIO $ writeFile cacheFile hash
175+
liftIO $ removeDirectoryRecursive tmp
176+
return hash
177+
132178
-- | Finds a suitable nixpkgs revision that has a the specified compiler available
133179
findNixpkgsForGhc :: Version -> App String
134180
findNixpkgsForGhc version = do
@@ -154,7 +200,7 @@ findNixpkgsForGhc version = do
154200
-- | Determines the available GHC versions for a nixpkgs revision
155201
ghcVersionsForNixpkgs :: String -> App [Version]
156202
ghcVersionsForNixpkgs rev = do
157-
path <- cachePath $ "per-nixpkgs" </> rev
203+
path <- cachePath $ "per-nixpkgs/ghcVersions" </> rev
158204
exists <- liftIO $ doesFileExist path
159205
if exists then do
160206
contents <- liftIO $ readFile path
@@ -253,7 +299,7 @@ getHistory = do
253299
response <- liftIO $ responseBody <$> httpLbs (parseRequest_ url) mgr
254300
-- Because this file is downloaded in the order of oldest to newest
255301
-- We reverse it for easier processing
256-
let items = reverse . map (head . BS.words) $ BS.lines response
302+
let items = reverse . ("45e819dd49799d8b680084ed57f6d0633581b957":) . map (head . BS.words) $ BS.lines response
257303

258304
liftIO $ BS.writeFile path $ BS.unlines items
259305
return $ map BS.unpack items

0 commit comments

Comments
 (0)