flake: partition dev dependencies

This removes the need for end-users to manually set
`nixvim.inputs.devshell.follows = ""` (etc)

We offload evaluation of some of our flake modules into a `dev`
partition submodule.
- When its not needed, this submodule is not evaluated.
- When it is needed, it fetches extra inputs from `flake/dev/flake.nix`
  as part of evaluating the submodule.

See https://flake.parts/options/flake-parts-partitions.html
This commit is contained in:
Matt Sturgeon 2025-02-22 16:02:13 +00:00
parent 0ab9947137
commit 6d10fc0c87
No known key found for this signature in database
GPG key ID: 4F91844CED1A8299
16 changed files with 366 additions and 285 deletions

View file

@ -6,10 +6,14 @@ on:
# Allow manual triggering
workflow_dispatch:
inputs:
lock:
root_lock:
type: boolean
default: true
description: Update flake.lock
description: Update root flake.lock
dev_lock:
type: boolean
default: true
description: Update dev flake.lock
generate:
type: boolean
default: true
@ -100,9 +104,9 @@ jobs:
git fetch origin "$pr_branch"
git branch --set-upstream-to "origin/$pr_branch"
- name: Update flake.lock
id: flake_lock
if: inputs.lock || github.event_name == 'schedule'
- name: Update root flake.lock
id: root_flake_lock
if: inputs.root_lock || github.event_name == 'schedule'
run: |
old=$(git show --no-patch --format=%h)
nix flake update --commit-lock-file
@ -113,6 +117,22 @@ jobs:
echo "EOF" >> "$GITHUB_OUTPUT"
fi
- name: Update dev flake.lock
id: dev_flake_lock
if: inputs.dev_lock || github.event_name == 'schedule'
run: |
root_nixpkgs=$(nix eval -f . 'inputs.nixpkgs.rev')
old=$(git show --no-patch --format=%h)
nix flake update --commit-lock-file \
--override-input nixpkgs "github:NixOS/nixpkgs/$root_nixpkgs" \
--flake './flake/dev'
new=$(git show --no-patch --format=%h)
if [ "$old" != "$new" ]; then
echo "body<<EOF" >> "$GITHUB_OUTPUT"
git show --no-patch --format=%b >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
- name: Update generated files
id: generate
if: inputs.generate || github.event_name == 'schedule'
@ -185,9 +205,14 @@ jobs:
title: |
[${{ github.ref_name }}] Update flake.lock & generated files
body: |
## Flake lockfile
## Root lockfile
```
${{ steps.flake_lock.outputs.body || 'No changes' }}
${{ steps.root_flake_lock.outputs.body || 'No changes' }}
```
## Dev lockfile
```
${{ steps.dev_flake_lock.outputs.body || 'No changes' }}
```
## Generate

View file

@ -1,6 +1,6 @@
(import (
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
lock = builtins.fromJSON (builtins.readFile ./flake/dev/flake.lock);
in
fetchTarball {
url =

147
flake.lock generated
View file

@ -1,39 +1,5 @@
{
"nodes": {
"devshell": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1735644329,
"narHash": "sha256-tO3HrHriyLvipc4xr+Ewtdlo7wM1OjXNjlWRgmM7peY=",
"owner": "numtide",
"repo": "devshell",
"rev": "f7795ede5b02664b57035b3b757876703e2c3eac",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-compat": {
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"revCount": 69,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
@ -72,71 +38,6 @@
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"flake-compat"
],
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1737465171,
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738878603,
"narHash": "sha256-fmhq8B3MvQLawLbMO+LWLcdC2ftLMmwSk+P29icJ3tE=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "433799271274c9f2ab520a49527ebfe2992dcfbd",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"ixx": {
"inputs": {
"flake-utils": [
@ -163,26 +64,6 @@
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738743987,
"narHash": "sha256-O3bnAfsObto6l2tQOmQlrO6Z2kD6yKwOWfs7pA0CpOc=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "ae406c04577ff9a64087018c79b4fdc02468c87c",
"type": "github"
},
"original": {
"owner": "lnl7",
"repo": "nix-darwin",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1738797219,
@ -223,15 +104,9 @@
},
"root": {
"inputs": {
"devshell": "devshell",
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"home-manager": "home-manager",
"nix-darwin": "nix-darwin",
"nixpkgs": "nixpkgs",
"nuschtosSearch": "nuschtosSearch",
"treefmt-nix": "treefmt-nix"
"nuschtosSearch": "nuschtosSearch"
}
},
"systems": {
@ -248,26 +123,6 @@
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738680491,
"narHash": "sha256-8X7tR3kFGkE7WEF5EXVkt4apgaN85oHZdoTGutCFs6I=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "64dbb922d51a42c0ced6a7668ca008dded61c483",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",

View file

@ -9,60 +9,10 @@
inputs.nixpkgs-lib.follows = "nixpkgs";
};
/*
# NOTE: The inputs below this comment are optional
# You can remove them with `inputs.<input>.follows = ""`
For example:
```
nixvim = {
url = "github:nix-community/nixvim";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-parts.follows = "flake-parts";
devshell.follows = "";
flake-compat.follows = "";
git-hooks.follows = "";
home-manager.follows = "";
nix-darwin.follows = "";
treefmt-nix.follows = "";
};
};
```
*/
nuschtosSearch = {
url = "github:NuschtOS/search";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-darwin = {
url = "github:lnl7/nix-darwin";
inputs.nixpkgs.follows = "nixpkgs";
};
devshell = {
url = "github:numtide/devshell";
inputs.nixpkgs.follows = "nixpkgs";
};
treefmt-nix = {
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz";
git-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-compat.follows = "flake-compat";
};
};
nixConfig = {

View file

@ -1,6 +1,12 @@
{
lib,
inputs,
config,
partitionStack,
...
}:
{
imports = [
./dev
./flake-modules
./lib.nix
./legacy-packages.nix
@ -8,7 +14,43 @@
./overlays.nix
./packages.nix
./templates.nix
./tests.nix
./wrappers.nix
inputs.flake-parts.flakeModules.partitions
];
# Define flake partitions
# Each has a `module`, assigned to the partition's submodule,
# and an `extraInputsFlake`, used for its inputs.
# See https://flake.parts/options/flake-parts-partitions.html
partitions = {
dev = {
module = ./dev;
extraInputsFlake = ./dev;
};
};
# Specify which outputs are defined by which partitions
partitionedAttrs = {
checks = "dev";
devShells = "dev";
formatter = "dev";
};
# For any output attrs normally defined by the root flake configuration,
# any exceptions must be manually propagated from the `dev` partition.
#
# NOTE: Attrs should be explicitly propagated at the deepest level.
# Otherwise the partition won't be lazy, making it pointless.
# E.g. propagate `packages.${system}.foo` instead of `packages.${system}`
# See: https://github.com/hercules-ci/flake-parts/issues/258
perSystem =
{ system, ... }:
{
packages = lib.optionalAttrs (partitionStack == [ ]) {
# Propagate `packages` from the `dev` partition:
inherit (config.partitions.dev.module.flake.packages.${system})
list-plugins
;
};
};
}

View file

@ -1,21 +1,22 @@
{ lib, inputs, ... }:
{ inputs, ... }:
{
imports =
[
imports = [
./devshell.nix
./list-plugins
]
++ lib.optional (inputs.git-hooks ? flakeModule) inputs.git-hooks.flakeModule
++ lib.optional (inputs.treefmt-nix ? flakeModule) inputs.treefmt-nix.flakeModule;
./package-tests.nix
./template-tests.nix
./tests.nix
inputs.git-hooks.flakeModule
inputs.treefmt-nix.flakeModule
];
perSystem =
{
lib,
pkgs,
system,
...
}:
lib.optionalAttrs (inputs.treefmt-nix ? flakeModule) {
{
treefmt.config = {
projectRootFile = "flake.nix";
flakeCheck = true;
@ -66,8 +67,7 @@
formatter.ruff-format.options = [ "--isolated" ];
};
};
}
// lib.optionalAttrs (inputs.git-hooks ? flakeModule) {
pre-commit = {
# We have a treefmt check already, so this is redundant.
# We also can't run the test if it includes running `nix build`,

View file

@ -1,17 +1,18 @@
{ lib, inputs, ... }:
{
imports = lib.optional (inputs.devshell ? flakeModule) inputs.devshell.flakeModule;
imports = [
inputs.devshell.flakeModule
];
perSystem =
{
lib,
pkgs,
config,
self',
system,
...
}:
lib.optionalAttrs (inputs.devshell ? flakeModule) {
{
devshells.default = {
devshell.startup.pre-commit.text = config.pre-commit.installationScript;

172
flake/dev/flake.lock generated Normal file
View file

@ -0,0 +1,172 @@
{
"nodes": {
"devshell": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1735644329,
"narHash": "sha256-tO3HrHriyLvipc4xr+Ewtdlo7wM1OjXNjlWRgmM7peY=",
"owner": "numtide",
"repo": "devshell",
"rev": "f7795ede5b02664b57035b3b757876703e2c3eac",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-compat": {
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"revCount": 69,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"flake-compat"
],
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1737465171,
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738878603,
"narHash": "sha256-fmhq8B3MvQLawLbMO+LWLcdC2ftLMmwSk+P29icJ3tE=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "433799271274c9f2ab520a49527ebfe2992dcfbd",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738743987,
"narHash": "sha256-O3bnAfsObto6l2tQOmQlrO6Z2kD6yKwOWfs7pA0CpOc=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "ae406c04577ff9a64087018c79b4fdc02468c87c",
"type": "github"
},
"original": {
"owner": "lnl7",
"repo": "nix-darwin",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1738797219,
"narHash": "sha256-KRwX9Z1XavpgeSDVM/THdFd6uH8rNm/6R+7kIbGa+2s=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1da52dd49a127ad74486b135898da2cef8c62665",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devshell": "devshell",
"flake-compat": "flake-compat",
"git-hooks": "git-hooks",
"home-manager": "home-manager",
"nix-darwin": "nix-darwin",
"nixpkgs": "nixpkgs",
"treefmt-nix": "treefmt-nix"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1738680491,
"narHash": "sha256-8X7tR3kFGkE7WEF5EXVkt4apgaN85oHZdoTGutCFs6I=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "64dbb922d51a42c0ced6a7668ca008dded61c483",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

38
flake/dev/flake.nix Normal file
View file

@ -0,0 +1,38 @@
{
description = "Private inputs for development purposes. These are used by the top level flake in the `dev` partition, but do not appear in consumers' lock files.";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-darwin = {
url = "github:lnl7/nix-darwin";
inputs.nixpkgs.follows = "nixpkgs";
};
devshell = {
url = "github:numtide/devshell";
inputs.nixpkgs.follows = "nixpkgs";
};
treefmt-nix = {
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz";
git-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-compat.follows = "flake-compat";
};
};
# This flake is only used for its inputs.
outputs = inputs: { };
}

View file

@ -1,12 +1,8 @@
{ inputs, self, ... }:
{ self, ... }:
{
perSystem =
{
self',
config,
lib,
inputs',
system,
pkgs,
...
}:
@ -33,8 +29,6 @@
list-plugins --root-path ${self} > $out
'';
}
// lib.optionalAttrs (inputs.devshell ? flakeModule) {
devshells.default.commands = [
{
name = "list-plugins";

View file

@ -0,0 +1,8 @@
{
perSystem =
{ config, ... }:
{
# Test that all packages build fine when running `nix flake check`.
checks = config.packages;
};
}

View file

@ -0,0 +1,51 @@
{ self, inputs, ... }:
{
# The following adds the template flake's checks to the main (current) flake's checks.
# It ensures that the template's own checks are successful.
perSystem =
{
pkgs,
system,
lib,
...
}:
{
checks =
let
# Approximates https://github.com/NixOS/nix/blob/96e550ef/src/libexpr/call-flake.nix#L67-L85
callFlake =
flake@{
inputs,
outputs,
sourceInfo ? { },
}:
let
outputs = flake.outputs (inputs // { self = result; });
result =
outputs
// sourceInfo
// {
inherit inputs outputs sourceInfo;
_type = "flake";
};
in
result;
flakes = lib.mapAttrs (
name: template:
callFlake {
# Use inputs from our flake
inputs = {
inherit (inputs) flake-parts nixpkgs;
nixvim = self;
};
# Use outputs from the template flake
inherit (import "${template.path}/flake.nix") outputs;
}
) self.templates;
in
lib.concatMapAttrs (name: flake: {
"template-${name}" = pkgs.linkFarm name flake.checks.${system};
}) flakes;
};
}

View file

@ -7,7 +7,7 @@
perSystem =
{ pkgs, ... }:
{
checks = pkgs.callPackages ../tests {
checks = pkgs.callPackages ../../tests {
inherit helpers self;
};
};

View file

@ -6,7 +6,6 @@
{
perSystem =
{
config,
inputs',
system,
...
@ -18,8 +17,5 @@
inherit (inputs) nixpkgs;
inherit (inputs') nuschtosSearch;
};
# Test that all packages build fine when running `nix flake check`.
checks = config.packages;
};
}

View file

@ -1,4 +1,3 @@
{ self, inputs, ... }:
{
flake.templates = {
default = {
@ -10,54 +9,4 @@
description = "An experimental flake template for configuring nixvim using evalNixvim and flake.parts";
};
};
# The following adds the template flake's checks to the main (current) flake's checks.
# It ensures that the template's own checks are successful.
perSystem =
{
pkgs,
system,
lib,
...
}:
{
checks =
let
# Approximates https://github.com/NixOS/nix/blob/7cd08ae379746749506f2e33c3baeb49b58299b8/src/libexpr/flake/call-flake.nix#L46
# s/flake.outputs/args.outputs/
callFlake =
args@{
inputs,
outputs,
sourceInfo ? { },
}:
let
outputs = args.outputs (inputs // { self = result; });
result =
outputs
// sourceInfo
// {
inherit inputs outputs sourceInfo;
_type = "flake";
};
in
result;
flakes = lib.mapAttrs (
name: template:
callFlake {
# Use inputs from our flake
inputs = {
inherit (inputs) flake-parts nixpkgs;
nixvim = self;
};
# Use outputs from the template flake
inherit (import "${template.path}/flake.nix") outputs;
}
) self.templates;
in
lib.concatMapAttrs (name: flake: {
"template-${name}" = pkgs.linkFarm name flake.checks.${system};
}) flakes;
};
}

View file

@ -9,7 +9,7 @@ let
nixvim' =
(import (
let
lock = builtins.fromJSON (builtins.readFile ../flake.lock);
lock = builtins.fromJSON (builtins.readFile ../flake/dev/flake.lock);
in
fetchTarball {
url =