nixpkgs-bootstrap/mkNixpkgs: rework to more reliably support updateScripts
This commit is contained in:
@@ -2,6 +2,24 @@
|
||||
# this means it has to be evaluatable using only builtins,
|
||||
# though i'm free to include optional functionality (e.g. update scripts) so long as i gate it behind availability checks.
|
||||
#
|
||||
# some considerations in order to keep this file compatible with updateScripts (e.g. `scripts/update sane.nixpkgs-bootstrap.master`):
|
||||
# - <repo:nixos/nixpkgs:pkgs/common-updater/scripts/update-source-version>, used by `{git,unstableGit}updater`,
|
||||
# updates the src attributes (rev, url, etc), then attempts to `nix-build` the package, discovers the new
|
||||
# source hash by scraping the nix error, "hash mismatch in fixed-output derivation ...", then patches in the new hash.
|
||||
# - this logic only works for nixpkgs fetchers -- NOT (necessarily) the nix builtin fetcher.
|
||||
# - this process requires that attrs like `sane.nixpkgs-bootstrap.master.src` be _evaluatable_, even if
|
||||
# e.g. the `patches` i intend to apply don't cleanly apply to the new rev.
|
||||
#
|
||||
# this leads to the following updateScript-aware implementation:
|
||||
# 1. impure.nix evaluates (approximately) to `(import nixpkgs-bootstrap/master.nix { ... }).pkgs.extend (overlays)`.
|
||||
# - that's `(mkNixpkgs { branch = "master", rev = ... }).pkgs.extend (overlays)`
|
||||
# 2. we can't guarantee that `sane.nixpkgs-bootstrap.master.src` is actually evaluatable, when updating the bootstrap,
|
||||
# however we _can_ detect that the bootstrap is being updated during eval of `mkNixpkgs`(*),
|
||||
# and if so force a failure which the update script will parse identically as if the actual `sane.nixpkgs-bootstrap.master.src` had failed to build.
|
||||
# (*) `mkNixpkgs` can detect that an updateScript for `foo.src` is running by testing `foo.src.hash`
|
||||
# against the sentinel value which `update-source-version` assigns during updates.
|
||||
#
|
||||
#
|
||||
# branch workflow:
|
||||
# - daily:
|
||||
# - nixos-unstable cut from master after enough packages have been built in caches.
|
||||
@@ -18,51 +36,75 @@
|
||||
# - staging-next: if testing stuff that's been PR'd into staging, i.e. base library updates.
|
||||
# - staging: maybe if no staging-next -> master PR has been cut yet?
|
||||
{
|
||||
#VVV these may or may not be available when called VVV
|
||||
#VVV these may or may not be available when called. VVV
|
||||
applyPatches ? null,
|
||||
fetchpatch2 ? null,
|
||||
fetchzip ? null,
|
||||
stdenv ? null,
|
||||
unstableGitUpdater ? null,
|
||||
}:
|
||||
let
|
||||
inBootstrap = fetchzip == null;
|
||||
fetchzip' = if inBootstrap then builtins.fetchTarball else fetchzip;
|
||||
optionalAttrs = cond: attrs: if cond then attrs else {};
|
||||
# nixpkgs' update-source-version (updateScript) calculates the new hash for a `src` by specifying this hardcoded bogus hash and then attempting to realize it.
|
||||
sentinelSha256 = "sha256-AzH1rZFqEH8sovZZfJykvsEmCedEZWigQFHWHl6/PdE=";
|
||||
fetchBootstrap = { url, pname, version, ... }@args: {
|
||||
# N.B. `outPath` is a special attr name which nix consults when coercing an attrset to a string.
|
||||
outPath = builtins.fetchTarball ({
|
||||
inherit url;
|
||||
name = if version != "" then "${pname}-${version}" else pname;
|
||||
} // (
|
||||
builtins.removeAttrs args [ "url" "pname" "version" ]
|
||||
));
|
||||
inherit pname version;
|
||||
};
|
||||
|
||||
mkNixpkgs = {
|
||||
branch,
|
||||
rev ? null,
|
||||
sha256 ? null,
|
||||
version ? null,
|
||||
rev ? "",
|
||||
sha256 ? "",
|
||||
version ? "",
|
||||
#VVV config
|
||||
localSystem ? if stdenv != null then stdenv.buildPlatform.system else builtins.currentSystem, #< not available in pure mode
|
||||
system ? if stdenv != null then stdenv.hostPlatform.system else localSystem,
|
||||
}@args: let
|
||||
src' = fetchzip' ({
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
|
||||
# nixpkgs' update-source-version (updateScript) finds the new hash by specifying this hardcoded bogus hash
|
||||
# and then checking the error messages.
|
||||
# but that doesn't work for builtins; instead we leave the builtin hash unspec'd,
|
||||
# and let eval progress to where pkgs.fetchzip exists and errors.
|
||||
} // optionalAttrs (sha256 != "sha256-AzH1rZFqEH8sovZZfJykvsEmCedEZWigQFHWHl6/PdE=") {
|
||||
inherit sha256;
|
||||
} // optionalAttrs (!inBootstrap) {
|
||||
pname = "nixpkgs";
|
||||
version = rev;
|
||||
inherit sha256; #< if out of the bootstrap, then *always* pin with hashes!
|
||||
});
|
||||
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
|
||||
pname = "nixpkgs-${branch}";
|
||||
commonNixpkgsArgs = {
|
||||
inherit localSystem;
|
||||
# reset impurities
|
||||
config = {};
|
||||
overlays = [];
|
||||
};
|
||||
# first, fetch the unpatched nixpkgs src:
|
||||
src' = if fetchzip != null then
|
||||
fetchzip { inherit url pname version sha256; }
|
||||
else if sha256 != "" && sha256 != sentinelSha256 then
|
||||
# fetch nixpkgs using `builtins.fetchTarball`.
|
||||
# a proper bootstrap would be to return `(import (fetchBootstrap src) {}).fetchzip src`.
|
||||
# this would be more immune to bugs like <https://github.com/NixOS/nixpkgs/pull/404702#issuecomment-2861798821>,
|
||||
# however it would force an extra eval of nixpkgs for _every_ user invocation of `nix`.
|
||||
fetchBootstrap { inherit url pname version sha256; }
|
||||
else
|
||||
# we don't know the hash for our nixpkgs.
|
||||
# likely that an updateScript is running, and attempting to discover the new hash.
|
||||
# then, use an impure bootstrap to fetch nixpkgs, and then invoke that nixpkgs' `fetchzip`.
|
||||
# this is expected to fail, however by failing inside a nixpkgs' fetcher, we allow the updateScript to complete.
|
||||
let
|
||||
impureNixpkgsSrc = fetchBootstrap { inherit url pname version; };
|
||||
impureNixpkgs = import impureNixpkgsSrc commonNixpkgsArgs;
|
||||
in
|
||||
impureNixpkgs.fetchzip { inherit url pname version sha256; }
|
||||
;
|
||||
|
||||
unpatchedNixpkgs = import src' commonNixpkgsArgs;
|
||||
|
||||
patchedSrc = unpatchedNixpkgs.applyPatches {
|
||||
applyPatches' = if applyPatches != null then applyPatches else unpatchedNixpkgs.applyPatches;
|
||||
fetchpatch2' = if fetchpatch2 != null then fetchpatch2 else unpatchedNixpkgs.fetchpatch2;
|
||||
|
||||
patchedSrc = applyPatches' {
|
||||
src = src';
|
||||
name = "nixpkgs-patched-uninsane";
|
||||
inherit version;
|
||||
patches = unpatchedNixpkgs.callPackage ./patches.nix { };
|
||||
patches = import ./patches.nix { fetchpatch2 = fetchpatch2'; };
|
||||
# skip applied patches
|
||||
prePatch = ''
|
||||
realpatch=$(command -v patch)
|
||||
@@ -82,9 +124,11 @@ let
|
||||
# so avoid specifying hostPlatform.system on non-cross builds, so i can use upstream caches.
|
||||
crossSystem = system;
|
||||
} else {});
|
||||
nixpkgs = import "${patchedSrc}" nixpkgsArgs;
|
||||
nixpkgs = import patchedSrc nixpkgsArgs;
|
||||
in
|
||||
if rev == null && sha256 == null && version == null then
|
||||
if rev == "" && sha256 == "" && version == "" then
|
||||
# allow `impure.nix` to invoke this with only `branch`, and we figure out the details for it.
|
||||
# TODO: remove this code path.
|
||||
import ./${branch}.nix {
|
||||
mkNixpkgs = args': mkNixpkgs ({
|
||||
inherit localSystem system;
|
||||
@@ -92,11 +136,13 @@ let
|
||||
}
|
||||
else
|
||||
patchedSrc.overrideAttrs (base: {
|
||||
# attributes needed for update scripts
|
||||
# attributes needed for update scripts.
|
||||
# TODO: should be possible to pass these straight through `applyPatches` instead of using `overrideAttrs`.
|
||||
inherit version;
|
||||
pname = "nixpkgs";
|
||||
passthru = (base.passthru or {}) // {
|
||||
# override is used to configure hostPlatform higher up.
|
||||
# TODO: refactor to avoid overriding.
|
||||
override = overrideArgs: mkNixpkgs (args // overrideArgs);
|
||||
|
||||
pkgs = nixpkgs;
|
||||
|
Reference in New Issue
Block a user