summary refs log tree commit diff
diff options
context:
space:
mode:
authorArun Isaac2024-09-30 18:55:16 +0100
committerArun Isaac2024-10-02 00:53:27 +0100
commit1cbbce81004545315b02cc08a50375b72ebfde85 (patch)
tree82814315b0f27f8d5897ae30a10524d2a2d577e9
parentf331839f339c4366695c43f8def047e223099e7d (diff)
downloadravanan-1cbbce81004545315b02cc08a50375b72ebfde85.tar.gz
ravanan-1cbbce81004545315b02cc08a50375b72ebfde85.tar.lz
ravanan-1cbbce81004545315b02cc08a50375b72ebfde85.zip
command-line-tool: Canonicalize inputs before embedding in G-exp.
* ravanan/command-line-tool.scm (canonicalize-json): New function.
(build-command-line-tool-script): Use canonicalize-json.
-rw-r--r--ravanan/command-line-tool.scm24
1 files changed, 23 insertions, 1 deletions
diff --git a/ravanan/command-line-tool.scm b/ravanan/command-line-tool.scm
index 8d1f8ef..1723d96 100644
--- a/ravanan/command-line-tool.scm
+++ b/ravanan/command-line-tool.scm
@@ -533,6 +533,28 @@ The returned G-expression will reference an @code{inputs-directory} variable."
                 (list id (copy-input-files input))))
              inputs)))
 
+(define (canonicalize-json tree)
+  "Canonicalize JSON @var{tree} by recursively sorting objects in lexicographic
+order of keys."
+  ;; We need to canonicalize JSON trees before inserting them into
+  ;; G-expressions. If we don't, we would have degenerate G-expressions that
+  ;; produce exactly the same result.
+  (cond
+   ;; Sort objects by lexicographic order of keys, and recurse.
+   ((list? tree)
+    (sort (map (match-lambda
+                 ((key . value)
+                  (cons key (canonicalize-json value))))
+               tree)
+          (match-lambda*
+            (((key1 . _) (key2 . _))
+             (string< key1 key2)))))
+   ;; Do not rearrange arrays. Just recurse.
+   ((vector? tree)
+    (vector-map canonicalize-json tree))
+   ;; Atoms
+   (else tree)))
+
 (define (build-command-line-tool-script name manifest cwl inputs
                                         scratch store guix-daemon-socket)
   "Build and return script to run @code{CommandLineTool} class workflow @var{cwl}
@@ -883,7 +905,7 @@ directory of the workflow."
 
               (call-with-temporary-directory
                (lambda (inputs-directory)
-                 (let ((inputs #$(copy-input-files-gexp inputs))
+                 (let ((inputs #$(copy-input-files-gexp (canonicalize-json inputs)))
                        (runtime `(("cores" . ,(total-processor-count)))))
 
                    ;; Set environment defined by workflow.