node-build-system.scm 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2015 David Thompson <davet@gnu.org>
  3. ;;; Copyright © 2016 Jelle Licht <jlicht@fsfe.org>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (guix build node-build-system)
  20. #:use-module ((guix build gnu-build-system) #:prefix gnu:)
  21. #:use-module (guix build json)
  22. #:use-module (guix build union)
  23. #:use-module (guix build utils)
  24. #:use-module (ice-9 match)
  25. #:use-module (ice-9 popen)
  26. #:use-module (ice-9 regex)
  27. #:use-module (srfi srfi-1)
  28. #:use-module (srfi srfi-26)
  29. #:export (%standard-phases
  30. node-build))
  31. ;; Commentary:
  32. ;;
  33. ;; Builder-side code of the standard Node/npm package build procedure.
  34. ;;
  35. ;; Code:
  36. (define* (read-package-data #:key (filename "package.json"))
  37. (call-with-input-file filename
  38. (lambda (port)
  39. (read-json port))))
  40. (define* (build #:key inputs #:allow-other-keys)
  41. (define (build-from-package-json? package-file)
  42. (let* ((package-data (read-package-data #:filename package-file))
  43. (scripts (assoc-ref package-data "scripts")))
  44. (assoc-ref scripts "build")))
  45. "Build a new node module using the appropriate build system."
  46. ;; XXX: Develop a more robust heuristic, allow override
  47. (cond ((file-exists? "gulpfile.js")
  48. (invoke "gulp"))
  49. ((file-exists? "gruntfile.js")
  50. (invoke "grunt"))
  51. ((file-exists? "Makefile")
  52. (invoke "make"))
  53. ((and (file-exists? "package.json")
  54. (build-from-package-json? "package.json"))
  55. (invoke "npm" "run" "build")))
  56. #t)
  57. (define* (link-npm-dependencies #:key inputs #:allow-other-keys)
  58. (define (inputs->node-inputs inputs)
  59. "Filter the directory part from INPUTS."
  60. (filter (lambda (input)
  61. (match input
  62. ((name . _) (node-package? name))))
  63. inputs))
  64. (define (inputs->directories inputs)
  65. "Extract the directory part from INPUTS."
  66. (match inputs
  67. (((names . directories) ...)
  68. directories)))
  69. (define (make-node-path root)
  70. (string-append root "/lib/node_modules/"))
  71. (let ((input-node-directories (inputs->directories
  72. (inputs->node-inputs inputs))))
  73. (union-build "node_modules"
  74. (map make-node-path input-node-directories))
  75. #t))
  76. (define configure link-npm-dependencies)
  77. (define* (check #:key tests? #:allow-other-keys)
  78. "Run 'npm test' if TESTS?"
  79. (if tests?
  80. ;; Should only be enabled once we know that there are tests
  81. (invoke "npm" "test"))
  82. #t)
  83. (define (node-package? name)
  84. "Check if NAME correspond to the name of an Node package."
  85. (string-prefix? "node-" name))
  86. (define* (install #:key outputs inputs #:allow-other-keys)
  87. "Install the node module to the output store item. The module itself is
  88. installed in a subdirectory of @file{node_modules} and its runtime dependencies
  89. as defined by @file{package.json} are symlinked into a @file{node_modules}
  90. subdirectory of the module's directory. Additionally, binaries are installed in
  91. the @file{bin} directory."
  92. (let* ((out (assoc-ref outputs "out"))
  93. (target (string-append out "/lib"))
  94. (binaries (string-append out "/bin"))
  95. (data (read-package-data))
  96. (modulename (assoc-ref data "name"))
  97. (binary-configuration (match (assoc-ref data "bin")
  98. (('@ configuration ...) configuration)
  99. ((? string? configuration) configuration)
  100. (#f #f)))
  101. (dependencies (match (assoc-ref data "dependencies")
  102. (('@ deps ...) deps)
  103. (#f #f))))
  104. (mkdir-p target)
  105. (copy-recursively "." (string-append target "/node_modules/" modulename))
  106. ;; Remove references to dependencies
  107. (delete-file-recursively
  108. (string-append target "/node_modules/" modulename "/node_modules"))
  109. (cond
  110. ((string? binary-configuration)
  111. (begin
  112. (mkdir-p binaries)
  113. (symlink (string-append target "/node_modules/" modulename "/"
  114. binary-configuration)
  115. (string-append binaries "/" modulename))))
  116. ((list? binary-configuration)
  117. (for-each
  118. (lambda (conf)
  119. (match conf
  120. ((key . value)
  121. (begin
  122. (mkdir-p (dirname (string-append binaries "/" key)))
  123. (symlink (string-append target "/node_modules/" modulename "/"
  124. value)
  125. (string-append binaries "/" key))))))
  126. binary-configuration))
  127. (else
  128. (symlink (string-append target "/node_modules/" modulename "/bin")
  129. binaries)))
  130. (when dependencies
  131. (mkdir-p
  132. (string-append target "/node_modules/" modulename "/node_modules"))
  133. (for-each
  134. (lambda (dependency)
  135. (let ((dependency (car dependency)))
  136. (symlink
  137. (string-append (assoc-ref inputs (string-append "node-" dependency))
  138. "/lib/node_modules/" dependency)
  139. (string-append target "/node_modules/" modulename
  140. "/node_modules/" dependency))))
  141. dependencies))
  142. #t))
  143. (define %standard-phases
  144. (modify-phases gnu:%standard-phases
  145. (replace 'configure configure)
  146. (replace 'build build)
  147. (replace 'install install)
  148. (delete 'check)
  149. (add-after 'install 'check check)
  150. (delete 'strip)))
  151. (define* (node-build #:key inputs (phases %standard-phases)
  152. #:allow-other-keys #:rest args)
  153. (apply gnu:gnu-build #:inputs inputs #:phases phases args))