Skip to content

Commit 5312958

Browse files
authored
unflake (#60)
1 parent 1515b77 commit 5312958

11 files changed

Lines changed: 285 additions & 51 deletions

File tree

.github/workflows/flake-check.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ jobs:
2323
strategy:
2424
matrix:
2525
template: ${{ fromJSON(needs.find-templates.outputs.templates) }}
26+
exclude:
27+
- template: "unflake"
2628
steps:
2729
- uses: wimpysworld/nothing-but-nix@main
2830
- uses: cachix/install-nix-action@v31
@@ -44,6 +46,20 @@ jobs:
4446
nix flake metadata
4547
nix run .#write-flake -L --show-trace
4648
nix flake check -L --show-trace
49+
unflake:
50+
name: Check unflake
51+
runs-on: ubuntu-latest
52+
steps:
53+
- uses: actions/checkout@v4
54+
- uses: wimpysworld/nothing-but-nix@main
55+
- uses: cachix/install-nix-action@v31
56+
- uses: DeterminateSystems/magic-nix-cache-action@main
57+
- run: |
58+
set -e -o pipefail
59+
cd templates/unflake
60+
sed -i 's/# flake-file = import/flake-file = import/' default.nix
61+
echo "{ inputs, ... }: { unflake.pkgs = import inputs.nixpkgs {}; }" | tee modules/pkgs.nix
62+
nix-shell . -A unflake.env --run 'write-unflake --verbose'
4763
dev:
4864
name: Check flake dev
4965
runs-on: ubuntu-latest

README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,32 @@
99
<a href="LICENSE"> <img src="https://img.shields.io/github/license/vic/flake-file" alt="License"/> </a>
1010
</p>
1111

12-
# flake-file — Generate flake.nix from flake-parts modules.
12+
# flake-file — Generate flake.nix or unflake.nix from inputs defined as module options.
1313

1414
> `flake-file` and [vic](https://bsky.app/profile/oeiuwq.bsky.social)'s [dendritic libs](https://vic.github.io/dendrix/Dendritic-Ecosystem.html#vics-dendritic-libraries) made for you with Love++ and AI--. If you like my work, consider [sponsoring](https://github.com/sponsors/vic)
1515
16-
**flake-file** lets you generate a clean, maintainable `flake.nix` from modular options, using [flake-parts](https://flake.parts/).
16+
**flake-file** lets you generate a clean, maintainable `flake.nix` from modular options. It works on both flakes and non-flakes environments.
1717

1818
It makes your flake configuration modular and based on the Nix module system. This means you can use
1919
`lib.mkDefault` or anything you normally do with Nix modules, and have them reflected in flake schema values.
2020

21+
> Despite the original flake-oriented name, it NOW also works on _stable Nix_, [_non flakes_](templates/unflake) environments.
22+
2123
<table><tr><td>
2224

2325
## Features
2426

25-
- Flake definition aggregated from all flake-parts modules.
27+
- Flake definition aggregated from Nix modules.
2628
- Schema as [options](https://github.com/vic/flake-file/blob/main/modules/options/default.nix).
2729
- Syntax for nixConfig and follows is the same as in flakes.
2830
- `flake check` ensures files are up to date.
29-
- App for generator: `nix run .#write-flake`
31+
- App for `flake.nix` generator: `nix run .#write-flake`
3032
- Custom do-not-edit header.
3133
- Automatic flake.lock [flattening](#automatic-flakelock-flattening).
3234
- Incrementally add [flake-parts-builder](#parts_templates) templates.
3335
- Pick flakeModules for different feature sets.
3436
- [Dendritic](https://vic.github.io/dendrix/Dendritic.html) flake template.
37+
- Works on stable Nix, [unflake](templates/unflake) environments.
3538

3639
</td><td>
3740

@@ -60,7 +63,7 @@ It makes your flake configuration modular and based on the Nix module system. Th
6063
## Who is this for?
6164

6265
- Nix users who want to keep their `flake.nix` modular and maintainable
63-
- Anyone using [flake-parts](https://flake.parts/) and looking to automate or simplify flake input management
66+
- Anyone using Nix modules and looking to automate or simplify flake input management
6467
- Teams or individuals who want to share and reuse flake modules across projects
6568

6669
---
@@ -148,9 +151,14 @@ The following is a complete example from our [`templates/dendritic`](https://git
148151

149152
> Previously, this module included `flake-aspects` and `den` as dependencies. It now provides a pure flake-parts Dendritic setup. If you need the complete [den](https://github.com/vic/den) functionality, use den's `flakeModules.dendritic` instead.
150153
154+
#### [`flakeModules.unflake`](https://github.com/vic/flake-file/tree/main/modules/unflake.nix)
155+
156+
- Defines `flake-file` options.
157+
- Exposes `write-unflake` to generate `unflake.nix` or `npins`. See [templates/unflake](templates/unflake) for usage.
158+
151159
### Flake Templates
152160

153-
#### `default` template
161+
#### [`default`](templates/default) template
154162

155163
A more basic, explicit setup.
156164

@@ -178,14 +186,18 @@ A more basic, explicit setup.
178186
> [!TIP]
179187
> You can use the `write-flake` app as part of a devshell or git hook.
180188
181-
#### `dendritic` template
189+
#### [`dendritic`](templates/dendritic) template
182190

183191
A template for dendritic setups; includes `flakeModules.dendritic`.
184192

185-
#### `parts` template
193+
#### [`parts`](templates/parts) template
186194

187195
A template that uses `lib.flakeModules.flake-parts-builder`.
188196

197+
#### [`unflake`](templates/unflake) template
198+
199+
Uses [goldstein/unflake](https://codeberg.org/goldstein/unflake) to pin and fetch inputs that were defined as options for non-flakes stable Nix environments.
200+
189201
---
190202

191203
## Available Options

dev/modules/_lib/default.nix

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,48 @@ let
7575
}
7676
);
7777

78+
nixAttr =
79+
name: value:
80+
let
81+
childIsAttr = builtins.isAttrs value;
82+
childIsOne = builtins.length (builtins.attrNames value) == 1;
83+
nested = lib.head (lib.mapAttrsToList nixAttr value);
84+
in
85+
if childIsAttr && childIsOne then
86+
{
87+
name = "${name}.${nested.name}";
88+
value = nested.value;
89+
}
90+
else
91+
{
92+
inherit name;
93+
value = value;
94+
};
95+
96+
# expr to code
97+
nixCode =
98+
x:
99+
if lib.isStringLike x then
100+
lib.strings.escapeNixString x
101+
else if lib.isAttrs x then
102+
lib.pipe x [
103+
(lib.mapAttrsToList nixAttr)
104+
(map ({ name, value }: "${name} = ${nixCode value}; "))
105+
(values: "{ ${lib.concatStringsSep " " values} }")
106+
]
107+
else if lib.isList x then
108+
lib.pipe x [
109+
(lib.map nixCode)
110+
(values: "[ ${lib.concatStringsSep " " values} ]")
111+
]
112+
else if x == true then
113+
"true"
114+
else if x == false then
115+
"false"
116+
else
117+
toString x;
118+
78119
in
79120
{
80-
inherit inputsExpr isNonEmptyString;
121+
inherit inputsExpr isNonEmptyString nixCode;
81122
}

dev/modules/formatter.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
".envrc"
3232
".direnv/*"
3333
"*/.gitignore"
34+
"**/unflake.nix" # generated by: nix-shell . -A unflake.env --run write-unflake
35+
"**/inputs.nix" # generated by: nix-shell . -A unflake.env --run write-inputs
3436
];
3537
};
3638
};

modules/default.nix

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ let
66
nix-auto-follow
77
dendritic
88
import-tree
9+
unflake
910
;
1011
};
1112

13+
unflake.imports = [
14+
./options
15+
./unflake.nix
16+
];
17+
1218
default.imports = [
1319
./options
1420
./write-flake.nix
@@ -36,6 +42,11 @@ let
3642
path = ./../templates/default;
3743
};
3844

45+
templates.unflake = {
46+
description = "unflake template";
47+
path = ./../templates/unflake;
48+
};
49+
3950
templates.dendritic = {
4051
description = "dendritic template";
4152
path = ./../templates/dendritic;

modules/unflake.nix

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{ lib, config, ... }:
2+
let
3+
inherit (config.unflake) pkgs;
4+
inherit (import ./../dev/modules/_lib lib) inputsExpr nixCode;
5+
6+
inputsString = ''
7+
# DO-NOT-EDIT: Generated by github:vic/flake-file for unflake.
8+
# To re-generate use: nix-shell . -A unflake.env --run write-inputs
9+
''
10+
+ (nixCode (inputsExpr config.flake-file.inputs));
11+
12+
inputsFile = pkgs.stdenvNoCC.mkDerivation {
13+
name = "inputs";
14+
passAsFile = [ "inputsString" ];
15+
inherit inputsString;
16+
phases = [ "copy" ];
17+
copy = ''
18+
cp $inputsStringPath $out
19+
'';
20+
};
21+
22+
write-inputs = pkgs.writeShellApplication {
23+
name = "write-inputs";
24+
text = ''
25+
cp ${inputsFile} "''${1:-inputs.nix}"
26+
'';
27+
};
28+
29+
write-unflake = pkgs.writeShellApplication {
30+
name = "write-unflake";
31+
text = ''
32+
nix-shell "${config.unflake.url}" -A unflake-shell --run "unflake -i ${inputsFile} $*"
33+
'';
34+
};
35+
36+
env = pkgs.mkShell {
37+
buildInputs = [
38+
write-inputs
39+
write-unflake
40+
];
41+
};
42+
in
43+
{
44+
options.unflake = {
45+
url = lib.mkOption {
46+
type = lib.types.str;
47+
description = "unflake archive url";
48+
default = "https://codeberg.org/goldstein/unflake/archive/main.tar.gz";
49+
};
50+
51+
pkgs = lib.mkOption {
52+
type = lib.types.raw;
53+
description = "nixpkgs instance for unflake generator";
54+
default = import <nixpkgs> { };
55+
};
56+
57+
env = lib.mkOption {
58+
type = lib.types.raw;
59+
readOnly = true;
60+
internal = true;
61+
default = env;
62+
};
63+
};
64+
}

modules/write-flake.nix

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
...
77
}:
88
let
9-
inherit (import ./../dev/modules/_lib lib) inputsExpr isNonEmptyString;
9+
inherit (import ./../dev/modules/_lib lib) inputsExpr isNonEmptyString nixCode;
1010

1111
flake-file = config.flake-file;
1212

@@ -27,47 +27,6 @@ let
2727
addHeader
2828
];
2929

30-
nixAttr =
31-
name: value:
32-
let
33-
childIsAttr = builtins.isAttrs value;
34-
childIsOne = builtins.length (builtins.attrNames value) == 1;
35-
nested = lib.head (lib.mapAttrsToList nixAttr value);
36-
in
37-
if childIsAttr && childIsOne then
38-
{
39-
name = "${name}.${nested.name}";
40-
value = nested.value;
41-
}
42-
else
43-
{
44-
inherit name;
45-
value = value;
46-
};
47-
48-
# expr to code
49-
nixCode =
50-
x:
51-
if lib.isStringLike x then
52-
lib.strings.escapeNixString x
53-
else if lib.isAttrs x then
54-
lib.pipe x [
55-
(lib.mapAttrsToList nixAttr)
56-
(map ({ name, value }: "${name} = ${nixCode value}; "))
57-
(values: "{ ${lib.concatStringsSep " " values} }")
58-
]
59-
else if lib.isList x then
60-
lib.pipe x [
61-
(lib.map nixCode)
62-
(values: "[ ${lib.concatStringsSep " " values} ]")
63-
]
64-
else if x == true then
65-
"true"
66-
else if x == false then
67-
"false"
68-
else
69-
toString x;
70-
7130
description =
7231
if isNonEmptyString flake-file.description then
7332
''

templates/unflake/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Unflake
2+
3+
This template is an example of using `flake-file.inputs` in a non-flakes project.
4+
5+
It uses [unflake](https://codeberg.org/goldstein/unflake) to pin and fetch inputs defined as options inside `./modules`.
6+
7+
## Generate `unflake.nix`
8+
9+
The following command is a convenience for generating `unflake.nix` by
10+
first producing a temporary `inputs.nix` from your config and then
11+
running unflake on it.
12+
13+
```shell
14+
nix-shell . -A unflake.env --run write-unflake
15+
```
16+
17+
You can also pass any unflake option:
18+
19+
```shell
20+
nix-shell . -A unflake.env --run 'write-unflake --verbose --backend nix'
21+
```
22+
23+
If you need to see the file that is being passed as `--inputs inputs.nix`
24+
to the unflake command, you can generate it with:
25+
26+
```shell
27+
# (only recommended for debugging)
28+
nix-shell . -A unflake.env --run write-inputs
29+
30+
# then, you can run unflake yourself:
31+
nix-shell https://ln-s.sh/unflake -A unflake-shell --run unflake
32+
```
33+
34+
## Using with [npins](https://github.com/andir/npins)
35+
36+
Unflake has an npins backend to use it run:
37+
38+
```shell
39+
nix-shell . -A unflake.env --run 'write-unflake --backend npins'
40+
```

templates/unflake/default.nix

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
let
2+
3+
outputs =
4+
inputs:
5+
(inputs.nixpkgs.lib.evalModules {
6+
modules = [ (inputs.import-tree ./modules) ];
7+
specialArgs = { inherit inputs; };
8+
}).config;
9+
10+
withInputs =
11+
inputs: outputs:
12+
outputs (
13+
inputs
14+
// {
15+
# uncomment to use local checkout on CI
16+
# flake-file = import ./../../modules;
17+
}
18+
);
19+
20+
in
21+
(import ./unflake.nix withInputs) outputs
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{ inputs, ... }:
2+
{
3+
imports = [ inputs.flake-file.flakeModules.unflake ];
4+
5+
flake-file.inputs = {
6+
flake-file.url = "github:vic/flake-file";
7+
import-tree.url = "github:vic/import-tree";
8+
nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
9+
};
10+
}

0 commit comments

Comments
 (0)