diff mbox series

[bug#51838,v8,04/41] guix: node-build-system: Add avoid-node-gyp-rebuild phase.

Message ID 2329a631211eadbc790c3c8ea99aaf4acf473e8c.camel@gmail.com
State Accepted
Headers show
Series guix: node-build-system: Support compiling add-ons with node-gyp. | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch success View Laminar job
cbaines/issue success View issue
cbaines/applying patch success View Laminar job
cbaines/issue success View issue

Commit Message

Liliana Marie Prikler Dec. 30, 2021, 7:38 a.m. UTC
Packages with native addons currently try to write to store paths
when used as dependecies.  This patch adds a phase to replace that
behaviour with a no-op.

* guix/build/node-build-system.scm (avoid-node-gyp-rebuild): New
variable.
(%standard-phases): Add 'avoid-node-gyp-rebuild' after 'install'.

Signed-off-by: Liliana Marie Prikler <liliana.prikler@gmail.com>
---
 guix/build/node-build-system.scm | 54 +++++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/guix/build/node-build-system.scm b/guix/build/node-build-system.scm
index c6602b876b..49b3db34ad 100644
--- a/guix/build/node-build-system.scm
+++ b/guix/build/node-build-system.scm
@@ -239,6 +239,57 @@  (define* (install #:key outputs inputs #:allow-other-keys)
             "install" "../package.tgz")
     #t))
 
+(define* (avoid-node-gyp-rebuild #:key outputs #:allow-other-keys)
+  "Adjust the installed 'package.json' to remove an 'install' script that
+would try to run 'node-gyp rebuild'."
+  ;; We want to take advantage of `npm install`'s automatic support for
+  ;; building native addons with node-gyp: in particular, it helps us avoid
+  ;; hard-coding the specifics of how npm's internal copy of node-gyp is
+  ;; currently packaged. However, the mechanism by which the automatic support
+  ;; is implemented causes problems for us.
+  ;;
+  ;; If a package contains a 'binding.gyp' file and does not define an
+  ;; 'install' or 'preinstall' script, 'npm install' runs a default install
+  ;; script consisting of 'node-gyp rebuild'. In our 'install' phase, this
+  ;; implicit 'install' script, if it is applicable, is explicitly added to
+  ;; the "package.json" file. However, if another Guix package were to use a
+  ;; Node.js package with such an 'install' script, the dependent package's
+  ;; build process would fail, because 'node-gyp rebuild' would try to write
+  ;; to the store.
+  ;;
+  ;; Here, if the installed "package.json" defines scripts.install as
+  ;; "node-gyp rebuild", we replace it with a no-op. Importantly, deleting the
+  ;; install script definition would not be enough, because the default
+  ;; install script would cause the same problem.
+  ;;
+  ;; For further details, see:
+  ;; - https://docs.npmjs.com/cli/v8/configuring-npm/package-json#default-values
+  ;; - https://docs.npmjs.com/cli/v8/using-npm/scripts#best-practices
+  (define installed-package.json
+    (search-input-file outputs (string-append "/lib/node_modules/"
+                                              (module-name ".")
+                                              "/package.json")))
+  ;; We don't want to use an atomic replacement here, because we often don't
+  ;; even need to overwrite this file.  Therefore, let's use some helpers
+  ;; that we'd otherwise not need.
+  (define pkg-meta
+    (call-with-input-file installed-package.json read-json))
+  (define scripts
+    (jsobject-ref pkg-meta "scripts" '(@)))
+  (define (jsobject-set js key val)
+    (jsobject-update* js (list key (const val))))
+
+  (when (equal? "node-gyp rebuild" (jsobject-ref scripts "install" #f))
+    (call-with-output-file installed-package.json
+      (lambda (out)
+        (write-json
+         (jsobject-set pkg-meta
+                       "scripts"
+                       (jsobject-set scripts
+                                     "install"
+                                     "echo Guix: avoiding node-gyp rebuild"))
+         out)))))
+
 (define %standard-phases
   (modify-phases gnu:%standard-phases
     (add-after 'unpack 'set-home set-home)
@@ -248,7 +299,8 @@  (define %standard-phases
     (replace 'build build)
     (replace 'check check)
     (add-before 'install 'repack repack)
-    (replace 'install install)))
+    (replace 'install install)
+    (add-after 'install 'avoid-node-gyp-rebuild avoid-node-gyp-rebuild)))
 
 (define* (node-build #:key inputs (phases %standard-phases)
                      #:allow-other-keys #:rest args)