about summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorzimbatm <zimbatm@zimbatm.com>2023-07-22 11:14:51 +0200
committerzimbatm <zimbatm@zimbatm.com>2023-07-22 17:54:41 +0200
commit504e42b559d74b013e95d93f5fc3868f756fd46b (patch)
treea04fd81529a3db9c95e5f5f7d0fffd49cd1e1d01 /pkgs/build-support
parentd0c7ffc596bd8da9298d693d1bdd0559c6777311 (diff)
writers: introduce data writers
Make it easy to write structured data back to disk.
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/writers/data.nix80
-rw-r--r--pkgs/build-support/writers/default.nix12
-rw-r--r--pkgs/build-support/writers/test.nix38
3 files changed, 126 insertions, 4 deletions
diff --git a/pkgs/build-support/writers/data.nix b/pkgs/build-support/writers/data.nix
new file mode 100644
index 0000000000000..a080f8c29d0e0
--- /dev/null
+++ b/pkgs/build-support/writers/data.nix
@@ -0,0 +1,80 @@
+{ lib, runCommandNoCC, dasel }:
+let
+  daselBin = lib.getExe dasel;
+
+  inherit (lib)
+    last
+    optionalString
+    types
+    ;
+in
+rec {
+  # Creates a transformer function that writes input data to disk, transformed
+  # by both the `input` and `output` arguments.
+  #
+  # Type: makeDataWriter :: input -> output -> nameOrPath -> data -> (any -> string) -> string -> string -> any -> derivation
+  #
+  #   input :: T -> string: function that takes the nix data and returns a string
+  #   output :: string: script that takes the $inputFile and write the result into $out
+  #   nameOrPath :: string: if the name contains a / the files gets written to a sub-folder of $out. The derivation name is the basename of this argument.
+  #   data :: T: the data that will be converted.
+  #
+  # Example:
+  #   writeJSON = makeDataWriter { input = builtins.toJSON; output = "cp $inputPath $out"; };
+  #   myConfig = writeJSON "config.json" { hello = "world"; }
+  #
+  makeDataWriter = { input ? lib.id, output ? "cp $inputPath $out" }: nameOrPath: data:
+    assert lib.or (types.path.check nameOrPath) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null);
+    let
+      name = last (builtins.split "/" nameOrPath);
+    in
+    runCommandNoCC name
+      {
+        input = input data;
+        passAsFile = [ "input" ];
+      } ''
+      ${output}
+
+      ${optionalString (types.path.check nameOrPath) ''
+        mv $out tmp
+        mkdir -p $out/$(dirname "${nameOrPath}")
+        mv tmp $out/${nameOrPath}
+      ''}
+    '';
+
+  # Writes the content to text.
+  #
+  # Example:
+  #   writeText "filename.txt" "file content"
+  writeText = makeDataWriter {
+    input = toString;
+    output = "cp $inputPath $out";
+  };
+
+  # Writes the content to a JSON file.
+  #
+  # Example:
+  #   writeJSON "data.json" { hello = "world"; }
+  writeJSON = makeDataWriter {
+    input = builtins.toJSON;
+    output = "${daselBin} -f $inputPath -r json -w json > $out";
+  };
+
+  # Writes the content to a TOML file.
+  #
+  # Example:
+  #   writeTOML "data.toml" { hello = "world"; }
+  writeTOML = makeDataWriter {
+    input = builtins.toJSON;
+    output = "${daselBin} -f $inputPath -r json -w toml > $out";
+  };
+
+  # Writes the content to a YAML file.
+  #
+  # Example:
+  #   writeYAML "data.yaml" { hello = "world"; }
+  writeYAML = makeDataWriter {
+    input = builtins.toJSON;
+    output = "${daselBin} -f $inputPath -r json -w yaml > $out";
+  };
+}
diff --git a/pkgs/build-support/writers/default.nix b/pkgs/build-support/writers/default.nix
index c26ada8bc5718..5ef5794221953 100644
--- a/pkgs/build-support/writers/default.nix
+++ b/pkgs/build-support/writers/default.nix
@@ -3,8 +3,16 @@
 let
   aliases = if config.allowAliases then (import ./aliases.nix lib) else prev: {};
 
-  scriptWriters = import ./scripts.nix { inherit pkgs lib; };
+  # Writers for JSON-like data structures
+  dataWriters = import ./data.nix {
+    inherit lib; inherit (pkgs) runCommandNoCC dasel;
+  };
 
-  writers = scriptWriters;
+  # Writers for scripts
+  scriptWriters = import ./scripts.nix {
+    inherit lib pkgs;
+  };
+
+  writers = scriptWriters // dataWriters;
 in
 writers // (aliases writers)
diff --git a/pkgs/build-support/writers/test.nix b/pkgs/build-support/writers/test.nix
index 9484f8bbe31b5..2411f8c03a70b 100644
--- a/pkgs/build-support/writers/test.nix
+++ b/pkgs/build-support/writers/test.nix
@@ -14,7 +14,7 @@ with writers;
 let
   expectSuccess = test:
     runCommand "run-${test.name}" {} ''
-      if test "$(${test})" != "success"; then
+      if [[ "$(${test})" != success ]]; then
         echo 'test ${test.name} failed'
         exit 1
       fi
@@ -24,13 +24,26 @@ let
 
   expectSuccessBin = test:
     runCommand "run-${test.name}" {} ''
-      if test "$(${lib.getExe test})" != "success"; then
+      if [[ "$(${lib.getExe test})" != success ]]; then
         echo 'test ${test.name} failed'
         exit 1
       fi
 
       touch $out
     '';
+
+  expectDataEqual = { file, expected }:
+    let
+      expectedFile = writeText "${file.name}-expected" expected;
+    in
+    runCommand "run-${file.name}" {} ''
+      if ! diff -u ${file} ${expectedFile}; then
+        echo 'test ${file.name} failed'
+        exit 1
+      fi
+
+      touch $out
+    '';
 in
 lib.recurseIntoAttrs {
   bin = lib.recurseIntoAttrs {
@@ -235,4 +248,25 @@ lib.recurseIntoAttrs {
         _ -> print "fail"
     ''));
   };
+
+  data = {
+    json = expectDataEqual {
+      file = writeJSON "data.json" { hello = "world"; };
+      expected = ''
+        {
+          "hello": "world"
+        }
+      '';
+    };
+
+    toml = expectDataEqual {
+      file = writeTOML "data.toml" { hello = "world"; };
+      expected = "hello = 'world'\n";
+    };
+
+    yaml = expectDataEqual {
+      file = writeYAML "data.yaml" { hello = "world"; };
+      expected = "hello: world\n";
+    };
+  };
 }