430 lines
17 KiB
Nix
430 lines
17 KiB
Nix
{
|
||
description = "oleks's personal Flake hub – a place to publish custom packages and overlays";
|
||
|
||
inputs = {
|
||
fleet-pins.url = "git+https://git.oleks.space/oleks/fleet-pins?ref=main";
|
||
nixpkgs.follows = "fleet-pins/nixpkgs-projects";
|
||
flake-utils.url = "github:numtide/flake-utils";
|
||
|
||
# Shared per-archetype parity publish-app builders (cluster#104, emmett#44).
|
||
# flake-hub is an ATTIC-CLOSURE repo: it builds package closures and warms
|
||
# the Attic cache with them — there is NO registry artifact.
|
||
# mkAtticClosurePublish makes that archetype explicit to pipeline-doctor.
|
||
parity.url = "git+https://git.oleks.space/oleks/parity-lib";
|
||
|
||
# Hyprspace source; no flake.nix in the repo so we consume it as raw src.
|
||
# Pin tracks the last v0.52-compatible commit of Hyprspace.
|
||
hyprspace = {
|
||
url = "github:KZDKM/Hyprspace/0467be86b18cfc324fab04afbd40fe9ef80f7fa9";
|
||
flake = false;
|
||
};
|
||
|
||
# Google Antigravity packaging. Upstream auto-updates daily; we re-expose
|
||
# the overlay and build into our attic cache so emmett pulls from there.
|
||
antigravity-nix = {
|
||
url = "github:jacopone/antigravity-nix";
|
||
inputs.nixpkgs.follows = "nixpkgs";
|
||
};
|
||
|
||
# nix-deps: "see the real cost of installing packages on NixOS".
|
||
# Re-exposed through our overlay so CI builds it into attic.
|
||
nix-deps = {
|
||
url = "github:manelinux/nix-deps";
|
||
inputs.nixpkgs.follows = "nixpkgs";
|
||
};
|
||
|
||
# stalewood — find/reap merged git worktrees. Ships its own flake;
|
||
# re-expose its package (mirrors the nix-deps pattern).
|
||
stalewood = {
|
||
url = "github:retif/stalewood";
|
||
inputs.nixpkgs.follows = "nixpkgs";
|
||
};
|
||
|
||
# woodpecker-peek — tray app for Woodpecker CI (on git.oleks.space).
|
||
# Re-exposed so flake-hub CI warms attic and emmett pulls cached.
|
||
woodpecker-peek = {
|
||
url = "git+https://git.oleks.space/oleks/woodpecker-peek?ref=main";
|
||
inputs.nixpkgs.follows = "nixpkgs";
|
||
};
|
||
|
||
# mcp-chrome — Chrome MCP server + extension (English-localized fork of
|
||
# hangwin/mcp-chrome). Re-exposes the from-source wasm-simd worker (proven
|
||
# green, ~22 s) and the full chrome-mcp-extension build. The extension
|
||
# target is KNOWN-BROKEN under nix-daemon at this pin (see oleks/mcp-chrome
|
||
# issue #1 close comment); expect attic to miss it until that's resolved.
|
||
mcp-chrome = {
|
||
url = "git+https://git.oleks.space/oleks/mcp-chrome?ref=main";
|
||
inputs.nixpkgs.follows = "nixpkgs";
|
||
};
|
||
};
|
||
|
||
outputs =
|
||
{
|
||
self,
|
||
nixpkgs,
|
||
fleet-pins,
|
||
flake-utils,
|
||
parity,
|
||
hyprspace,
|
||
antigravity-nix,
|
||
nix-deps,
|
||
stalewood,
|
||
woodpecker-peek,
|
||
mcp-chrome,
|
||
...
|
||
}:
|
||
let
|
||
# Systems that have native builders
|
||
buildSystems = [
|
||
"x86_64-linux"
|
||
"aarch64-linux"
|
||
];
|
||
|
||
# Cross-compilation targets from x86_64-linux
|
||
crossTargets = {
|
||
"s390x-linux" = "s390x-linux";
|
||
};
|
||
|
||
mkPackages =
|
||
pkgs:
|
||
let
|
||
sys = pkgs.stdenv.hostPlatform.system;
|
||
# Antigravity ships a Google-provided x86_64/aarch64 Linux binary.
|
||
# Skip it for cross targets (e.g. s390x) where it can't run anyway.
|
||
supportsAntigravity = sys == "x86_64-linux" || sys == "aarch64-linux";
|
||
xontribs = import ./packages/xontribs.nix {
|
||
inherit (pkgs) python3Packages fetchurl;
|
||
};
|
||
in
|
||
{
|
||
hello-world = pkgs.callPackage ./packages/hello-world.nix { };
|
||
geesefs = pkgs.callPackage ./packages/geesefs.nix { };
|
||
metamcp = pkgs.callPackage ./packages/metamcp.nix { };
|
||
xonsh = pkgs.callPackage ./packages/xonsh.nix {
|
||
xonsh-unwrapped = import ./packages/xonsh-unwrapped.nix {
|
||
inherit (pkgs) lib python3Packages fetchFromGitHub;
|
||
};
|
||
};
|
||
}
|
||
# Native-only packages — skip on s390x cross (gitea's pnpm step and
|
||
# cgo+sqlite link don't cross-compile cleanly).
|
||
// nixpkgs.lib.optionalAttrs (sys == "x86_64-linux" || sys == "aarch64-linux") {
|
||
gitea-local-fork =
|
||
let
|
||
# Our fork's go.mod requires Go 1.26.3; nixpkgs at this pin has
|
||
# only 1.26.0 (and unstable has 1.26.2). Bump the package's src.
|
||
go = pkgs.go_1_26.overrideAttrs (_: rec {
|
||
version = "1.26.3";
|
||
src = pkgs.fetchurl {
|
||
url = "https://go.dev/dl/go${version}.src.tar.gz";
|
||
hash = "sha256-HGRoddCqh5kTMYTtV895/yS97+jIggRwYCqdPW2Rkrg=";
|
||
};
|
||
});
|
||
in
|
||
pkgs.callPackage ./packages/gitea-local-fork.nix {
|
||
buildGoModule = pkgs.buildGoModule.override { inherit go; };
|
||
};
|
||
}
|
||
# Xontribs: pass into `programs.xonsh.extraPackages` or
|
||
# `pkgs.xonsh.override { extraPackages = ps: [...]; }`.
|
||
// xontribs
|
||
# Antigravity: re-expose jacopone/antigravity-nix's outputs so emmett
|
||
# consumes a single flake-hub input and our CI builds into attic.
|
||
// nixpkgs.lib.optionalAttrs supportsAntigravity {
|
||
inherit (antigravity-nix.packages.${sys})
|
||
google-antigravity
|
||
google-antigravity-no-fhs
|
||
google-antigravity-ide
|
||
google-antigravity-ide-no-fhs
|
||
google-antigravity-cli
|
||
;
|
||
# nix-deps' flake only outputs eachDefaultSystem (no s390x), so
|
||
# gate it on the same native x86_64/aarch64 condition.
|
||
nix-deps = nix-deps.packages.${sys}.default;
|
||
# stalewood — re-exposed from its own flake. No s390x output,
|
||
# so it rides the same native-only gate.
|
||
stalewood = stalewood.packages.${sys}.default;
|
||
# woodpecker-peek — same pattern; consumers (emmett) read the
|
||
# attic-cached binary via flake-hub's overlay, then set
|
||
# services.woodpecker-peek.package = pkgs.woodpecker-peek;.
|
||
woodpecker-peek = woodpecker-peek.packages.${sys}.default;
|
||
# mcp-chrome — Rust→wasm worker (proven green) plus the full
|
||
# chrome-mcp-extension build. The latter is KNOWN-BROKEN under
|
||
# nix-daemon at this pin; flake-hub CI will miss the cache on it
|
||
# until upstream resolves that. wasm-simd alone is what consumers
|
||
# actually pull cached today (commits 9534234, b276465 in
|
||
# oleks/mcp-chrome sync the built wasm back into the tree).
|
||
mcp-chrome-wasm-simd = mcp-chrome.packages.${sys}.wasm-simd;
|
||
mcp-chrome-extension = mcp-chrome.packages.${sys}.chrome-mcp-extension;
|
||
};
|
||
|
||
# Overlay providing Hyprspace. Requires `pkgs.hyprland` to be present
|
||
# (consumer applies the Hyprland flake's overlay first). Kept out of
|
||
# `mkPackages` because standalone `nix build .#hyprspace` has no
|
||
# Hyprland in scope.
|
||
hyprspaceOverlay = final: _prev: {
|
||
hyprspace = final.callPackage ./packages/hyprspace.nix {
|
||
src = hyprspace;
|
||
};
|
||
};
|
||
|
||
# Rustc bootstrap: symlink_file panics with "File exists" during
|
||
# s390x cross-compilation. Multiple call sites use t!(symlink_file(...)).
|
||
# Patch the symlink_file method body to remove an existing dest first.
|
||
# Exported as overlays.s390xRustcSymlink so nixos-ci consumes this single
|
||
# definition (and the patch travels with it) instead of duplicating it.
|
||
s390xRustcSymlinkOverlay =
|
||
final: prev:
|
||
let
|
||
patchedRustcUnwrapped = prev.rustc-unwrapped.overrideAttrs (old: {
|
||
patches = (old.patches or [ ]) ++ [
|
||
./patches/rustc-symlink-file-eexist.patch
|
||
];
|
||
});
|
||
in
|
||
{
|
||
rustc-unwrapped = patchedRustcUnwrapped;
|
||
rustc = prev.rustc.override {
|
||
rustc-unwrapped = patchedRustcUnwrapped;
|
||
};
|
||
};
|
||
|
||
# Overlays needed for s390x cross-compilation of attic-client
|
||
s390xOverlays = [
|
||
# OpenSSL s390x assembly uses z10 instructions (cijne) that the
|
||
# nix-bootstrapped assembler doesn't recognize
|
||
(final: prev: {
|
||
openssl = prev.openssl.overrideAttrs (old: {
|
||
configureFlags = (old.configureFlags or [ ]) ++ [ "no-asm" ];
|
||
});
|
||
})
|
||
# musl doesn't support s390x long double (IBM double-double format:
|
||
# LDBL_MANT_DIG=106, sizeof=16). Make musl appear unavailable so
|
||
# busybox-sandbox-shell uses glibc static instead.
|
||
(final: prev: {
|
||
busybox-sandbox-shell = prev.busybox-sandbox-shell.override {
|
||
musl = prev.musl // {
|
||
meta = prev.musl.meta // {
|
||
platforms = [ ];
|
||
};
|
||
};
|
||
};
|
||
})
|
||
# libarchive tests fail in k8s pod sandboxes
|
||
(final: prev: {
|
||
libarchive = prev.libarchive.overrideAttrs (_: {
|
||
doCheck = false;
|
||
});
|
||
})
|
||
# nix 2.28 is a direct dependency of attic-client — disable tests
|
||
# and fix missing RPATH for boost/zstd/libarchive
|
||
(final: prev: {
|
||
nixVersions = prev.nixVersions // {
|
||
nix_2_28 = prev.nixVersions.nix_2_28.overrideAttrs (old: {
|
||
doCheck = false;
|
||
doInstallCheck = false;
|
||
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ final.patchelf ];
|
||
postFixup = (old.postFixup or "") + ''
|
||
for rpath in ${final.boost}/lib ${final.zstd.out}/lib ${final.libarchive.out}/lib; do
|
||
patchelf --add-rpath "$rpath" $out/bin/nix
|
||
for lib in $out/lib/lib*.so; do
|
||
[ -f "$lib" ] && patchelf --add-rpath "$rpath" "$lib"
|
||
done
|
||
done
|
||
'';
|
||
});
|
||
};
|
||
})
|
||
# LLVM test failures in CI pod environment — override libllvm
|
||
# (not llvm) so it propagates through rustc bootstrap chain
|
||
(final: prev: {
|
||
llvmPackages = prev.llvmPackages // {
|
||
libllvm = prev.llvmPackages.libllvm.overrideAttrs (old: {
|
||
doCheck = false;
|
||
doInstallCheck = false;
|
||
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ prev.gitMinimal ];
|
||
});
|
||
};
|
||
})
|
||
# Rustc symlink_file "File exists" fix (defined + exported above).
|
||
s390xRustcSymlinkOverlay
|
||
];
|
||
|
||
# Native builds
|
||
native = flake-utils.lib.eachSystem buildSystems (
|
||
system:
|
||
let
|
||
pkgs = import nixpkgs { inherit system; };
|
||
packages = mkPackages pkgs;
|
||
in
|
||
{
|
||
packages = packages // {
|
||
default = packages.hello-world;
|
||
};
|
||
|
||
formatter = pkgs.nixfmt-rfc-style;
|
||
|
||
devShells.default = pkgs.mkShell {
|
||
name = "oleks-hub-shell";
|
||
buildInputs = [ self.packages.${system}.default ];
|
||
nativeBuildInputs = with pkgs; [
|
||
nix
|
||
fmt
|
||
];
|
||
shellHook = ''
|
||
echo "Welcome to the oleks Flake hub development shell."
|
||
'';
|
||
};
|
||
}
|
||
);
|
||
|
||
# Cross-compiled builds (built from x86_64-linux)
|
||
cross = builtins.listToAttrs (
|
||
builtins.map (
|
||
target:
|
||
let
|
||
targetOverlays =
|
||
{
|
||
"s390x-linux" = s390xOverlays;
|
||
}
|
||
.${target} or [ ];
|
||
pkgs = import nixpkgs {
|
||
system = "x86_64-linux";
|
||
crossSystem.config =
|
||
nixpkgs.lib.systems.examples.${
|
||
{
|
||
"s390x-linux" = "s390x";
|
||
}
|
||
.${target}
|
||
}.config;
|
||
overlays = targetOverlays;
|
||
};
|
||
packages = mkPackages pkgs;
|
||
crossOnlyPackages =
|
||
{
|
||
"s390x-linux" = {
|
||
inherit (pkgs)
|
||
attic-client
|
||
rustc
|
||
cargo
|
||
rustfmt
|
||
sccache
|
||
mold
|
||
;
|
||
nix = pkgs.nixVersions.nix_2_28;
|
||
};
|
||
}
|
||
.${target} or { };
|
||
in
|
||
{
|
||
name = target;
|
||
value =
|
||
packages
|
||
// crossOnlyPackages
|
||
// {
|
||
default = packages.hello-world;
|
||
};
|
||
}
|
||
) (builtins.attrNames crossTargets)
|
||
);
|
||
in
|
||
native
|
||
// {
|
||
packages = (native.packages or { }) // cross;
|
||
overlays = {
|
||
default = final: _prev: mkPackages final;
|
||
gcc15-fixes = import ./overlays/gcc15-fixes.nix;
|
||
hyprspace = hyprspaceOverlay;
|
||
# Single home for the s390x rustc symlink_file patch overlay so
|
||
# consumers (nixos-ci) don't re-declare it + the patch file.
|
||
s390xRustcSymlink = s390xRustcSymlinkOverlay;
|
||
};
|
||
|
||
# `nix run .#<app>` — local-parity entrypoints (emmett#44, cluster#192,
|
||
# ATTIC-CLOSURE archetype, cluster#104). The stage/publish/push-staged
|
||
# apps come straight from parity-lib's mkAtticClosurePublish, so CI and a
|
||
# local run share one audited implementation and cannot drift. There is NO
|
||
# registry artifact — these apps build the package closures and warm the
|
||
# Attic cache with them.
|
||
#
|
||
# TWO HALVES (emmett#44): STAGE `nix build`s every package in the arch's
|
||
# list into the local /nix store (cluster-independent, runs on emmett);
|
||
# PUBLISH additionally `attic push`es each closure to the cache that lives
|
||
# next to the cluster. Local runs DRY-RUN (stage + show the pushes) unless
|
||
# `--publish`/PUBLISH=1.
|
||
#
|
||
# nix run .#stage-x86_64-linux stage amd64 closures, no publish
|
||
# nix run .#publish stage amd64 then push if PUBLISH=1
|
||
# nix run .#publish -- --publish actually push to attic
|
||
# nix run .#push-staged replay already-staged amd64 paths
|
||
#
|
||
# arm64 leg: aarch64-linux cannot be built on emmett (linux/amd64) and the
|
||
# native packages have no cross path, so it MUST run on an aarch64 node
|
||
# (.woodpecker/arm64.yaml runs `PUBLISH=1 nix run .#publish-aarch64-linux`).
|
||
#
|
||
# The package set per arch mirrors flake-hub's CI warm list (was
|
||
# ci/publish.py packages_for): the always-on core plus arch-conditional
|
||
# extras. Cross-only/known-broken targets stay out (see comments).
|
||
apps =
|
||
let
|
||
# The Attic cache token lives at `pass infra/attic/ci_token` and the
|
||
# cache is reached via the armer hairpin endpoint — preserve both so
|
||
# the push is byte-for-byte the pre-parity behaviour.
|
||
atticEndpoint = "https://nix-cache-upload.oleks.space";
|
||
atticPass = "infra/attic/ci_token";
|
||
|
||
# Package names to warm into Attic for a given native arch.
|
||
# Native arches only (amd64/arm64); mcp-chrome-extension stays OUT
|
||
# (known-broken under nix-daemon at this pin, see oleks/mcp-chrome #1).
|
||
packageNamesFor =
|
||
arch:
|
||
[
|
||
"hello-world"
|
||
"geesefs"
|
||
"xonsh"
|
||
]
|
||
++ nixpkgs.lib.optionals (arch == "x86_64-linux" || arch == "aarch64-linux") [
|
||
"woodpecker-peek"
|
||
"mcp-chrome-wasm-simd"
|
||
"gitea-local-fork"
|
||
"google-antigravity"
|
||
"google-antigravity-no-fhs"
|
||
"google-antigravity-ide"
|
||
"google-antigravity-ide-no-fhs"
|
||
"google-antigravity-cli"
|
||
];
|
||
|
||
drvsFor = arch: map (n: self.packages.${arch}.${n}) (packageNamesFor arch);
|
||
|
||
buildersFor = arch: parity.lib.mkParityBuilders (import nixpkgs { system = arch; });
|
||
|
||
atticAppsFor =
|
||
arch:
|
||
(buildersFor arch).mkAtticClosurePublish {
|
||
drvs = drvsFor arch;
|
||
inherit arch;
|
||
endpoint = atticEndpoint;
|
||
passEntry = atticPass;
|
||
};
|
||
|
||
amd64Apps = atticAppsFor "x86_64-linux";
|
||
arm64Apps = atticAppsFor "aarch64-linux";
|
||
in
|
||
nixpkgs.lib.genAttrs buildSystems (system:
|
||
# amd64 is the emmett-buildable arch: expose its stage/publish/
|
||
# push-staged plus the top-level `publish`. Also surface the arm64
|
||
# stage/publish under their arch-suffixed names for the node-bound
|
||
# CI leg (.woodpecker/arm64.yaml).
|
||
{
|
||
inherit (amd64Apps)
|
||
"stage-x86_64-linux"
|
||
"publish-x86_64-linux"
|
||
"publish"
|
||
"push-staged"
|
||
;
|
||
"stage-aarch64-linux" = arm64Apps."stage-aarch64-linux";
|
||
"publish-aarch64-linux" = arm64Apps."publish-aarch64-linux";
|
||
});
|
||
};
|
||
}
|