Skip to content

Instantly share code, notes, and snippets.

@jkarni
Created November 16, 2024 12:35
Show Gist options
  • Save jkarni/e0a6b6c4c574db25b21e2899508a71a3 to your computer and use it in GitHub Desktop.
Save jkarni/e0a6b6c4c574db25b21e2899508a71a3 to your computer and use it in GitHub Desktop.
makeNormalizedFlake :: [Build] -> M NormalizedFlake
makeNormalizedFlake = foldM go mempty
where
getStorePath :: Build -> M (Maybe StorePath)
getStorePath build = case build ^. drvPath of
Nothing -> pure Nothing
Just path -> do
nixConfig <- view userNixConfig
-- We here fetch the drv from the cache. The drv might be private, so
-- we need the authentication token.
-- Note that there is a small race condition here, since it could be
-- that between us fetching the drv and using it, or between checking
-- that it exists and using it, garbage collection runs. So we make
-- sure the build still succeeds (just not with a cache) if so.
drvExistsLocally <- liftIO $ doesFileExist path
unless drvExistsLocally $ do
(StderrRaw err, exit) <-
run
$ cmd "nix-store"
& addArgs ["--realize", path]
& addNixConfigEnvironment nixConfig
case exit of
ExitSuccess ->
log Informational
$ "Successfully fetched "
<> cs path
<> " from the cache for incremental build"
ExitFailure c ->
log Error
$ "'nix-store --realize' failed with exit code "
<> show c
<> " and stderr "
<> cs err
(StdoutTrimmed result, StderrRaw err, exit) <-
run
$ cmd "nix"
& addArgs ["derivation", "show", path]
& addNixConfigEnvironment nixConfig
case exit of
ExitSuccess ->
pure
$ result
^? key (fromString $ cs path)
. key "outputs"
. key "intermediates"
. key "path"
. _String
. to StorePath
ExitFailure c -> do
log Error
$ "'nix derivation show' failed with exit code "
<> show c
<> " and stderr "
<> cs err
pure Nothing
go :: NormalizedFlake -> Build -> M NormalizedFlake
go f build
| build ^. packageType == TypeOverall = pure f
| otherwise = do
storePath <- getStorePath build
pure
$ f
& at
( build ^. packageType,
build ^. system,
build ^. package
)
.~ storePath
renderNormalizedFlakeWithHelpers :: FilePath -> NormalizedFlake -> IO Text
renderNormalizedFlakeWithHelpers emptyDir' (NormalizedFlake f) = cs <$> rendered
where
renderSingle :: (PackageType, MaybeSystem, PackageName) -> StorePath -> Text -> Text
renderSingle (typ, sys, PackageName name) (StorePath s) prev =
prev
<> "\n"
<> (typ ^. re asPackageType)
<> "s."
<> case sys of
NoSystem -> ""
IsSystem s -> s ^. systemTextIso <> "."
<> name
<> case typ of
TypeNixosConfiguration -> ".config.system.build.toplevel"
_ -> ""
<> ".intermediates"
<> " = builtins.fetchClosure { "
<> " inputAddressed = true;" -- Is this worth changing?
<> " fromStore = \"https://cache.garnix.io\"; "
<> " fromPath = "
<> show s
<> ";"
<> " };"
attrs :: Text
attrs = Map.foldrWithKey renderSingle "" f
helpers = do
pure
[i|
lib.withCaches = args.self.lib.withCachesFor args.self;
lib.withCachesFor = prev: outputs:
let wantedAttrs = ["packages" "checks" "devShells"];
emptyDir = "${#{emptyDir'}}";
mapAttrsIfSet = fn : s : if builtins.isAttrs s then builtins.mapAttrs fn s else s;
in (mapAttrsIfSet (type:
mapAttrsIfSet (sys:
mapAttrsIfSet (pkg: def:
if builtins.elem type wantedAttrs && builtins.isFunction def
then (def (prev.${type}.${sys}.${pkg}.intermediates or emptyDir))
else def
)))) outputs;
|]
rendered = do
h <- helpers
pure
[i|
{
outputs = args : {
#{attrs}
#{h}
};
}
|]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment