diff --git a/extra/files/file-format.nix b/extra/files/file-format.nix new file mode 100644 index 00000000..ac46d0f9 --- /dev/null +++ b/extra/files/file-format.nix @@ -0,0 +1,31 @@ +format: {pkgs, config, lib, ...}: +let + yj-args.json = "-jji"; + yj-args.yaml = "-jy"; + yj-args.toml = "-jt"; + yj-args.hcl = "-jc"; + yj-arg = yj-args.${format}; + cfg = config.files.${format}; + type = (pkgs.formats.json {}).type; + generate = name: value: pkgs.runCommand name { + nativeBuildInputs = [ pkgs.yj ]; + value = builtins.toJSON value; + passAsFile = [ "value" ]; + } '' + cat "$valuePath"| yj ${yj-arg} > "$out" + ''; + toFile = name: value: { + source = generate (builtins.baseNameOf name) value; + }; +in { + options.files.${format} = lib.mkOption { + type = lib.types.attrsOf type; + description = '' + Create ${format} files with correponding content + ''; + default = {}; + example."/hello.${format}".greeting = "hello World"; + example."/hellows.${format}".greetings = [ ["Hello World"] ["Ola Mundo" ["Holla Que Tal"]]]; + }; + config.file = lib.mapAttrs toFile cfg; +} diff --git a/extra/files/file-type.nix b/extra/files/file-type.nix new file mode 100644 index 00000000..a3959857 --- /dev/null +++ b/extra/files/file-type.nix @@ -0,0 +1,67 @@ +{ pkgs, config, lib, ... }: +let + inherit (lib) hasPrefix literalExpression mkDefault mkIf mkOption removePrefix types; +in +{ + # all rights reserved to nix-community + # copy of https://github.com/nix-community/home-manager/blob/master/modules/lib/file-type.nix + # Constructs a type suitable for a `devshell.file` like option. The + # target path may be absolute, in which case it + # is relative to project root + # Arguments: + # - basePathDesc docbook compatible description of the base path + # - basePath the file base path + fileType = basePathDesc: types.attrsOf (types.submodule ( + { name, config, ... }: { + options = { + target = mkOption { + type = types.str; + defaultText = literalExpression ""; + description = '' + Path to target file relative to ${basePathDesc}. + ''; + }; + + text = mkOption { + default = null; + type = types.nullOr types.lines; + description = '' + Text of the file. If this option is null then + devshel.file.<name?>.source + must be set. + ''; + }; + + source = mkOption { + type = types.path; + description = '' + Path of the source file or directory. If + devshell.file.<name?>.text + is non-null then this option will automatically point to a file + containing that text. + ''; + }; + + executable = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Set the execute bit. If null, defaults to the mode + of the source file or to false + for files created through the text option. + ''; + }; + }; + + config = { + target = mkDefault name; + source = mkIf (config.text != null) ( + mkDefault (pkgs.writeTextFile { + inherit (config) executable text; + name = name; + }) + ); + }; + } + )); +} diff --git a/extra/files/files.nix b/extra/files/files.nix new file mode 100644 index 00000000..5011e43f --- /dev/null +++ b/extra/files/files.nix @@ -0,0 +1,42 @@ +{ pkgs, config, lib, ... }: +let + files = config.file; + fileType = (import ./file-type.nix { inherit pkgs config lib; }).fileType; + chmod = file: + if file.executable == null then "" + else if file.executable then "chmod +x $target" + else "chmod -x $target"; + # Execute this script to update the project's files + nameToScript = name: builtins.replaceStrings ["/" "."] ["-" "-"] (lib.removePrefix "/" name); + copy-file = name: file: pkgs.writeShellScriptBin (nameToScript name) '' + export PATH=${pkgs.coreutils}/bin:$PATH + out="$(git rev-parse --show-toplevel)" + realOut="$(realpath -m "$out")" + target="$(realpath -m "$realOut/${file.target}")" + mkdir -p "$(dirname "$target")" + cp --no-preserve=mode,ownership,timestamps "${file.source}" "$target" + ${chmod file} + ''; + startups = lib.mapAttrsToList (n: f: + let name = nameToScript n; + in { + ${name}.text = '' + $DEVSHELL_DIR/bin/${name} + ''; + }) files; +in { + options.file = lib.mkOption { + description = "Attribute set of files to create into the project root."; + default = {}; + type = fileType "PRJ_ROOT"; + }; + config.commands = [ + { + name = "files"; + help = "Regenerate files"; + command = "nix develop --build"; + } + ]; + config.devshell.packages = lib.mapAttrsToList copy-file files; + config.devshell.startup = lib.foldAttrs lib.mergeAttrs {} startups; +} diff --git a/extra/files/hcl.nix b/extra/files/hcl.nix new file mode 100644 index 00000000..6287e1d4 --- /dev/null +++ b/extra/files/hcl.nix @@ -0,0 +1 @@ +import ./file-format.nix "hcl" diff --git a/extra/files/json.nix b/extra/files/json.nix new file mode 100644 index 00000000..e09c512c --- /dev/null +++ b/extra/files/json.nix @@ -0,0 +1 @@ +import ./file-format.nix "json" diff --git a/extra/files/toml.nix b/extra/files/toml.nix new file mode 100644 index 00000000..f43f720e --- /dev/null +++ b/extra/files/toml.nix @@ -0,0 +1 @@ +import ./file-format.nix "toml" diff --git a/extra/files/yaml.nix b/extra/files/yaml.nix new file mode 100644 index 00000000..44cc29d4 --- /dev/null +++ b/extra/files/yaml.nix @@ -0,0 +1 @@ +import ./file-format.nix "yaml"