Skip to content

Commit

Permalink
Add a crude file generation mechanism
Browse files Browse the repository at this point in the history
Running `nix run .\#regenerate-files` now generates files locally
according to the `files` option in `project.ncl`.

This is still rather crude in a number of ways, but it is already
working (and used to generate this project's own `.gitignore`).

Fixes #144
  • Loading branch information
Théophane Hufschmitt committed Oct 17, 2023
1 parent a417d1c commit a8b283b
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/examples/*/result
/result
/result
84 changes: 84 additions & 0 deletions lib/files.ncl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
let nix = import "./nix-interop/nix.ncl" in
{
File = {
target
| doc m%"
The file to write to.
If null, defaults to the attribute name of the file.
"%
| String
| optional,
content
| doc m%"
The content of the file.
"%
| nix.derivation.NixString,
materialisation_method
: [| 'Symlink, 'Copy |]
| doc m%"
How the file should be materialized on-disk.

Symlinking makes it easier to track where the files are coming from,
but their target only exists after a first call to Organist, which
might be undesirable.
"%
| default
= 'Copy,
..
},
Files = { _ : File },
NormaliseTargets = fun label files =>
files
|> std.record.map (fun name file_descr => file_descr & { target | default = name }),

Schema = {
files
| Files
| NormaliseTargets
| doc m%"
Set of files that should be generated in the project's directory.
"%
= {},
flake.apps.regenerate-files.program = nix-s%"%{regenerate_files files}/bin/regenerate-files"%,
},

regenerate_files | Files -> nix.derivation.Derivation = fun files_to_generate =>
let regnerate_one | String -> File -> nix.derivation.NixString = fun key file_descr =>
let file_content = file_descr.content in
let target = file_descr.target in
let copy_command =
match {
'Symlink => "ln -s",
'Copy => "cp",
}
file_descr.materialisation_method
in
let file_in_store =
nix.builtins.to_file
(nix.utils.escape_drv_name key)
file_content
in
nix-s%"
rm -f %{target}
echo "Regenerating %{target}"
%{copy_command} %{file_in_store} %{target}
"%
in
{
name = "regenerate-files",
content.text =
files_to_generate
|> std.record.to_array
|> std.array.map (fun { field, value } => regnerate_one field value)
|> std.array.fold_left
(
fun acc elt =>
nix-s%"
%{acc}
%{elt}
"%
)
"",
}
| nix.builders.ShellApplication,
}
1 change: 1 addition & 0 deletions lib/nix-interop/nix.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
builders = import "builders.ncl",
shells = import "shells.ncl",
builtins = import "builtins.ncl",
utils = import "utils.ncl",

import_nix = builtins.import_nix,
}
12 changes: 12 additions & 0 deletions lib/nix-interop/utils.ncl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
escape_drv_name
: String -> String
| doc m%"
Escape the given string to make it an allowed derivation name
"%
= fun str =>
if std.string.is_match "^\\." str then
"-" ++ str
else
str
}
17 changes: 10 additions & 7 deletions lib/schema.ncl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let nix = import "./nix-interop/nix.ncl" in
let filegen = import "files.ncl" in
{
OrganistShells = {
dev | nix.derivation.NickelDerivation = build,
Expand All @@ -20,11 +21,13 @@ let nix = import "./nix-interop/nix.ncl" in
#
# The contract must be: what the Nix side of the code can "parse" without
# erroring out.
OrganistExpression = {
shells
| OrganistShells
| optional,
flake | FlakeOutputs | optional,
..
},
OrganistExpression =
{
shells
| OrganistShells
| optional,
flake | FlakeOutputs = {},
}
& filegen.Schema
}

8 changes: 8 additions & 0 deletions project.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,13 @@ let import_nix = organist.nix.import_nix in
},

flake.checks = import "tests/main.ncl",

files.".gitignore".materialisation_method = 'Copy,
files.".gitignore".content = m%"
# This file is generated by Organist, please don't edit directly
/examples/*/result
/result

"%,
}
| organist.OrganistExpression

0 comments on commit a8b283b

Please sign in to comment.