Commit | Line | Data |
---|---|---|
09a1f92f JL |
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 | ||
20 | (define-module (guix build node-build-system) | |
21 | #:use-module ((guix build gnu-build-system) #:prefix gnu:) | |
a4bb1892 | 22 | #:use-module (guix build json) |
09a1f92f JL |
23 | #:use-module (guix build union) |
24 | #:use-module (guix build utils) | |
25 | #:use-module (ice-9 match) | |
26 | #:use-module (ice-9 popen) | |
27 | #:use-module (ice-9 regex) | |
28 | #:use-module (srfi srfi-1) | |
29 | #:use-module (srfi srfi-26) | |
30 | #:export (%standard-phases | |
31 | node-build)) | |
32 | ||
33 | ;; Commentary: | |
34 | ;; | |
35 | ;; Builder-side code of the standard Node/npm package build procedure. | |
36 | ;; | |
37 | ;; Code: | |
38 | ||
39 | (define* (read-package-data #:key (filename "package.json")) | |
40 | (call-with-input-file filename | |
41 | (lambda (port) | |
a4bb1892 | 42 | (read-json port)))) |
09a1f92f JL |
43 | |
44 | (define* (build #:key inputs #:allow-other-keys) | |
45 | (define (build-from-package-json? package-file) | |
46 | (let* ((package-data (read-package-data #:filename package-file)) | |
a4bb1892 | 47 | (scripts (assoc-ref package-data "scripts"))) |
09a1f92f JL |
48 | (assoc-ref scripts "build"))) |
49 | "Build a new node module using the appropriate build system." | |
50 | ;; XXX: Develop a more robust heuristic, allow override | |
51 | (cond ((file-exists? "gulpfile.js") | |
52 | (invoke "gulp")) | |
53 | ((file-exists? "gruntfile.js") | |
54 | (invoke "grunt")) | |
55 | ((file-exists? "Makefile") | |
56 | (invoke "make")) | |
57 | ((and (file-exists? "package.json") | |
58 | (build-from-package-json? "package.json")) | |
59 | (invoke "npm" "run" "build"))) | |
60 | #t) | |
61 | ||
62 | (define* (link-npm-dependencies #:key inputs #:allow-other-keys) | |
63 | (define (inputs->node-inputs inputs) | |
64 | "Filter the directory part from INPUTS." | |
65 | (filter (lambda (input) | |
66 | (match input | |
67 | ((name . _) (node-package? name)))) | |
68 | inputs)) | |
69 | (define (inputs->directories inputs) | |
70 | "Extract the directory part from INPUTS." | |
71 | (match inputs | |
72 | (((names . directories) ...) | |
73 | directories))) | |
74 | (define (make-node-path root) | |
75 | (string-append root "/lib/node_modules/")) | |
76 | ||
77 | (let ((input-node-directories (inputs->directories | |
78 | (inputs->node-inputs inputs)))) | |
79 | (union-build "node_modules" | |
80 | (map make-node-path input-node-directories)) | |
81 | #t)) | |
82 | ||
83 | (define configure link-npm-dependencies) | |
84 | ||
85 | (define* (check #:key tests? #:allow-other-keys) | |
86 | "Run 'npm test' if TESTS?" | |
87 | (if tests? | |
88 | ;; Should only be enabled once we know that there are tests | |
89 | (invoke "npm" "test")) | |
90 | #t) | |
91 | ||
92 | (define (node-package? name) | |
93 | "Check if NAME correspond to the name of an Node package." | |
94 | (string-prefix? "node-" name)) | |
95 | ||
96 | (define* (install #:key outputs inputs #:allow-other-keys) | |
97 | "Install the node module to the output store item. The module itself is | |
98 | installed in a subdirectory of @file{node_modules} and its runtime dependencies | |
99 | as defined by @file{package.json} are symlinked into a @file{node_modules} | |
100 | subdirectory of the module's directory. Additionally, binaries are installed in | |
101 | the @file{bin} directory." | |
102 | (let* ((out (assoc-ref outputs "out")) | |
103 | (target (string-append out "/lib")) | |
104 | (binaries (string-append out "/bin")) | |
105 | (data (read-package-data)) | |
a4bb1892 JL |
106 | (modulename (assoc-ref data "name")) |
107 | (binary-configuration (match (assoc-ref data "bin") | |
108 | (('@ configuration ...) configuration) | |
109 | ((? string? configuration) configuration) | |
110 | (#f #f))) | |
111 | (dependencies (match (assoc-ref data "dependencies") | |
112 | (('@ deps ...) deps) | |
09a1f92f JL |
113 | (#f #f)))) |
114 | (mkdir-p target) | |
115 | (copy-recursively "." (string-append target "/node_modules/" modulename)) | |
116 | ;; Remove references to dependencies | |
117 | (delete-file-recursively | |
118 | (string-append target "/node_modules/" modulename "/node_modules")) | |
119 | (cond | |
120 | ((string? binary-configuration) | |
121 | (begin | |
122 | (mkdir-p binaries) | |
123 | (symlink (string-append target "/node_modules/" modulename "/" | |
a4bb1892 | 124 | binary-configuration) |
09a1f92f JL |
125 | (string-append binaries "/" modulename)))) |
126 | ((list? binary-configuration) | |
127 | (for-each | |
128 | (lambda (conf) | |
129 | (match conf | |
130 | ((key . value) | |
131 | (begin | |
132 | (mkdir-p (dirname (string-append binaries "/" key))) | |
133 | (symlink (string-append target "/node_modules/" modulename "/" | |
a4bb1892 | 134 | value) |
09a1f92f | 135 | (string-append binaries "/" key)))))) |
c23b42dd | 136 | binary-configuration))) |
09a1f92f JL |
137 | (when dependencies |
138 | (mkdir-p | |
139 | (string-append target "/node_modules/" modulename "/node_modules")) | |
140 | (for-each | |
141 | (lambda (dependency) | |
142 | (let ((dependency (car dependency))) | |
143 | (symlink | |
144 | (string-append (assoc-ref inputs (string-append "node-" dependency)) | |
145 | "/lib/node_modules/" dependency) | |
146 | (string-append target "/node_modules/" modulename | |
147 | "/node_modules/" dependency)))) | |
148 | dependencies)) | |
149 | #t)) | |
150 | ||
151 | ||
152 | (define %standard-phases | |
153 | (modify-phases gnu:%standard-phases | |
154 | (replace 'configure configure) | |
155 | (replace 'build build) | |
156 | (replace 'install install) | |
157 | (delete 'check) | |
158 | (add-after 'install 'check check) | |
159 | (delete 'strip))) | |
160 | ||
161 | (define* (node-build #:key inputs (phases %standard-phases) | |
162 | #:allow-other-keys #:rest args) | |
163 | (apply gnu:gnu-build #:inputs inputs #:phases phases args)) |