# github.com/brianmcgee has lots of great ideas for going above and beyond for this { description = "Greg's homepage"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; devshell.url = "github:numtide/devshell"; flake-parts.url = "github:hercules-ci/flake-parts"; flake-root.url = "github:srid/flake-root"; process-compose.url = "github:Platonic-Systems/process-compose-flake"; treefmt-nix.url = "github:numtide/treefmt-nix"; }; outputs = { devshell, flake-parts, flake-root, process-compose, treefmt-nix, nixpkgs, ... }@inputs: let lib = nixpkgs.lib; providers = [ "qemu" "virtualbox-iso" "hyperv-iso" ]; distros = import ./distros; # Inserts the distro name into each element in the list insertNames = lib.attrsets.mapAttrsToList (distro: val: (builtins.map (x: x // { inherit distro; }) val)) distros; # Flattens all the distros into a single list flat = lib.lists.flatten insertNames; # Combines providers list with flattened list withProviders = lib.attrsets.mapCartesianProduct ({d, provider}: d // { inherit provider; }) { d = flat; provider = providers; }; active = builtins.filter (x: (x?eol) && (!x.eol)) withProviders; name = d: "-${d.distro}-${d.arch}-${d.provider}-${d.version}"; distroFile = d: "distros/${d.distro}/${d.version}/${d.arch}.pkrvars.hcl"; cmd = d: '' # This is a workaround for a goofy behavior in CI if [ -e "''${PACKER_CONFIG_DIR}" ]; then find "''${PACKER_CONFIG_DIR}" -name '*_linux_amd64' -exec chmod +x '{}' ";" fi packer init sources packer build -only=${d.provider}.${d.arch} -var-file=${distroFile d}''; in flake-parts.lib.mkFlake { inherit inputs; } { imports = [ inputs.devshell.flakeModule inputs.flake-root.flakeModule inputs.treefmt-nix.flakeModule ]; flake = { # Universal things }; systems = [ "x86_64-linux" "aarch64-linux" ]; perSystem = { config, pkgs, self', system, ... }: { _module.args.pkgs = import inputs.nixpkgs { inherit system; config.allowUnfree = true; }; # https://numtide.github.io/devshell/intro.html devshells.default = { # These commands will be shown in the motd that users read # upon entering the shell commands = [ { package = self'.packages.cache; category = "utils"; help = "Downloads ISO files and adds them to the S3 bucket"; } { package = self'.packages.generate; category = "utils"; help = "Generate dynamic HCL files"; } { package = self'.packages.shellcheck; category = "utils"; help = "Run shellchecks"; } { package = self'.packages.validate; category = "utils"; help = "Validate all the files"; } { package = pkgs.vagrant; category = "utils"; help = "Vagrant to help with testing"; } ] ++ (builtins.map (d: { package = self'.packages."build${name d}"; category = "builds"; }) withProviders); env = [{ name = "EFI_DIR"; value = "${pkgs.OVMF.fd}/FV/"; } { name = "PACKER_CONFIG_DIR"; value = "./packer_config"; } ]; }; # This is not special, this is just flakes packages = let base = { runtimeInputs = with pkgs; [ packer findutils qemu_full vagrant ]; }; build = d: let vp = x: if x.provider == "qemu" then "libvirt" else if x.provider == "virtualbox-iso" then "virtualbox" else if x.provider == "hyperv-iso" then "hyperv" else "unknown"; in pkgs.writeShellApplication (base // { name = "build${name d}"; text = '' set -x ${cmd d} -except=upload -var headless=false sources/ vagrant box add --provider ${vp d} ./output/${vp d}/${d.distro}-${d.version}.box --name test_box --force ''; }); cibuild = d: pkgs.writeShellApplication (base // { name = "ci${name d}"; text = '' set -x ${cmd d} -except=upload sources/ ''; }); upload = d: pkgs.writeShellApplication (base // { name = "upload${name d}"; text = '' set -x ${cmd d} sources/ ''; }); builds = lib.lists.foldr (d: acc: acc // { "build${name d}" = (build d); }) {} withProviders; uploads = lib.lists.foldr (d: acc: acc // { "upload${name d}" = (upload d); }) {} withProviders; cibuilds = lib.lists.foldr (d: acc: acc // { "ci${name d}" = (cibuild d); }) {} withProviders; qemu_list = builtins.toJSON (builtins.map (d: { buildcmd = (name d); }) (builtins.filter (x: x.provider == "qemu") active)); vbox_list = builtins.toJSON (builtins.map (d: { buildcmd = (name d); }) (builtins.filter (x: x.provider == "virtualbox-iso") active)); hyperv_list = builtins.toJSON (builtins.map (d: { distro = distroFile d; }) (builtins.filter (x: x.provider == "hyperv-iso") active)); in builds // uploads // cibuilds // { continue = pkgs.writeText "continue.yml" (builtins.replaceStrings ["QEMU_MATRIX" "VBOX_MATRIX" "HYPERV_MATRIX"] [qemu_list vbox_list hyperv_list] (builtins.readFile ./.gitlab-ci-build.yml.in) ); cache = pkgs.callPackage (import ./nix/cache.nix) { inherit active distroFile; }; validate = pkgs.callPackage (import ./nix/validate.nix) {}; cache-restore = pkgs.writeShellApplication { name = "cache-restore"; runtimeInputs = with pkgs; [ jq minio-client packer ]; text = builtins.readFile ./cache-restore.sh; }; generate = pkgs.writeShellApplication { name = "generate"; runtimeInputs = with pkgs; [ bash coreutils curl jq pup ]; text = '' shopt -s globstar for vars in distros/**/*.pkrvars.hcl.sh; do bash "./''${vars}" done set -x echo "BUILD=$(date "+%Y.%m.%d.%H")" >> build.env ''; }; shellcheck = pkgs.writeShellApplication { name = "shellcheck"; runtimeInputs = with pkgs; [ shellcheck ]; text = '' scripts=() shopt -s globstar for f in **/*.sh; do scripts+=("$f") done shellcheck -e SC2239 "''${scripts[@]}" ''; }; }; # https://numtide.github.io/treefmt/ treefmt.config = { inherit (config.flake-root) projectRootFile; package = pkgs.treefmt; programs = { deadnix.enable = true; }; settings.formatter = { }; }; }; }; }