summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2018-09-14 17:30:06 +0200
committerLudovic Courtès <ludo@gnu.org>2018-09-21 17:04:37 +0200
commit9daf046c5dd9256e45073dfd4647e12de10dcb3e (patch)
tree39a226beff081b10217ae1859ba3be43c32eb7a7
parent7e27393f82ff5e7237f870ded09652b89e457faa (diff)
inferior: Add 'inferior-package-derivation'.
* guix/inferior.scm (read-inferior-response) (send-inferior-request): New procedures. (inferior-eval): Rewrite in terms of these. (proxy, inferior-package-derivation, inferior-package->derivation) (package-compiler): New procedures. * tests/inferior.scm ("inferior-package-derivation"): New test.
-rw-r--r--guix/inferior.scm125
-rw-r--r--tests/inferior.scm22
2 files changed, 141 insertions, 6 deletions
diff --git a/guix/inferior.scm b/guix/inferior.scm
index af37233a037..5bef9648871 100644
--- a/guix/inferior.scm
+++ b/guix/inferior.scm
@@ -19,9 +19,21 @@
19(define-module (guix inferior) 19(define-module (guix inferior)
20 #:use-module (srfi srfi-9) 20 #:use-module (srfi srfi-9)
21 #:use-module (srfi srfi-9 gnu) 21 #:use-module (srfi srfi-9 gnu)
22 #:use-module ((guix utils) #:select (source-properties->location)) 22 #:use-module ((guix utils)
23 #:select (%current-system
24 source-properties->location
25 call-with-temporary-directory))
26 #:use-module ((guix store)
27 #:select (nix-server-socket
28 nix-server-major-version
29 nix-server-minor-version
30 store-lift))
31 #:use-module ((guix derivations)
32 #:select (read-derivation-from-file))
33 #:use-module (guix gexp)
23 #:use-module (ice-9 match) 34 #:use-module (ice-9 match)
24 #:use-module (ice-9 popen) 35 #:use-module (ice-9 popen)
36 #:use-module (ice-9 binary-ports)
25 #:export (inferior? 37 #:export (inferior?
26 open-inferior 38 open-inferior
27 close-inferior 39 close-inferior
@@ -36,7 +48,8 @@
36 inferior-package-synopsis 48 inferior-package-synopsis
37 inferior-package-description 49 inferior-package-description
38 inferior-package-home-page 50 inferior-package-home-page
39 inferior-package-location)) 51 inferior-package-location
52 inferior-package-derivation))
40 53
41;;; Commentary: 54;;; Commentary:
42;;; 55;;;
@@ -123,8 +136,7 @@ equivalent. Return #f if the inferior could not be launched."
123 136
124(set-record-type-printer! <inferior-object> write-inferior-object) 137(set-record-type-printer! <inferior-object> write-inferior-object)
125 138
126(define (inferior-eval exp inferior) 139(define (read-inferior-response inferior)
127 "Evaluate EXP in INFERIOR."
128 (define sexp->object 140 (define sexp->object
129 (match-lambda 141 (match-lambda
130 (('value value) 142 (('value value)
@@ -132,14 +144,21 @@ equivalent. Return #f if the inferior could not be launched."
132 (('non-self-quoting address string) 144 (('non-self-quoting address string)
133 (inferior-object address string)))) 145 (inferior-object address string))))
134 146
135 (write exp (inferior-socket inferior))
136 (newline (inferior-socket inferior))
137 (match (read (inferior-socket inferior)) 147 (match (read (inferior-socket inferior))
138 (('values objects ...) 148 (('values objects ...)
139 (apply values (map sexp->object objects))) 149 (apply values (map sexp->object objects)))
140 (('exception key objects ...) 150 (('exception key objects ...)
141 (apply throw key (map sexp->object objects))))) 151 (apply throw key (map sexp->object objects)))))
142 152
153(define (send-inferior-request exp inferior)
154 (write exp (inferior-socket inferior))
155 (newline (inferior-socket inferior)))
156
157(define (inferior-eval exp inferior)
158 "Evaluate EXP in INFERIOR."
159 (send-inferior-request exp inferior)
160 (read-inferior-response inferior))
161
143 162
144;;; 163;;;
145;;; Inferior packages. 164;;; Inferior packages.
@@ -216,3 +235,97 @@ record."
216 (location->source-properties 235 (location->source-properties
217 loc))) 236 loc)))
218 package-location)))) 237 package-location))))
238
239(define (proxy client backend) ;adapted from (guix ssh)
240 "Proxy communication between CLIENT and BACKEND until CLIENT closes the
241connection, at which point CLIENT is closed (both CLIENT and BACKEND must be
242input/output ports.)"
243 (define (select* read write except)
244 ;; This is a workaround for <https://bugs.gnu.org/30365> in Guile < 2.2.4:
245 ;; since 'select' sometimes returns non-empty sets for no good reason,
246 ;; call 'select' a second time with a zero timeout to filter out incorrect
247 ;; replies.
248 (match (select read write except)
249 ((read write except)
250 (select read write except 0))))
251
252 ;; Use buffered ports so that 'get-bytevector-some' returns up to the
253 ;; whole buffer like read(2) would--see <https://bugs.gnu.org/30066>.
254 (setvbuf client _IOFBF 65536)
255 (setvbuf backend _IOFBF 65536)
256
257 (let loop ()
258 (match (select* (list client backend) '() '())
259 ((reads () ())
260 (when (memq client reads)
261 (match (get-bytevector-some client)
262 ((? eof-object?)
263 (close-port client))
264 (bv
265 (put-bytevector backend bv)
266 (force-output backend))))
267 (when (memq backend reads)
268 (match (get-bytevector-some backend)
269 (bv
270 (put-bytevector client bv)
271 (force-output client))))
272 (unless (port-closed? client)
273 (loop))))))
274
275(define* (inferior-package-derivation store package
276 #:optional
277 (system (%current-system))
278 #:key target)
279 "Return the derivation for PACKAGE, an inferior package, built for SYSTEM
280and cross-built for TARGET if TARGET is true. The inferior corresponding to
281PACKAGE must be live."
282 ;; Create a named socket in /tmp and let the inferior of PACKAGE connect to
283 ;; it and use it as its store. This ensures the inferior uses the same
284 ;; store, with the same options, the same per-session GC roots, etc.
285 (call-with-temporary-directory
286 (lambda (directory)
287 (chmod directory #o700)
288 (let* ((name (string-append directory "/inferior"))
289 (socket (socket AF_UNIX SOCK_STREAM 0))
290 (inferior (inferior-package-inferior package))
291 (major (nix-server-major-version store))
292 (minor (nix-server-minor-version store))
293 (proto (logior major minor)))
294 (bind socket AF_UNIX name)
295 (listen socket 1024)
296 (send-inferior-request
297 `(let ((socket (socket AF_UNIX SOCK_STREAM 0)))
298 (connect socket AF_UNIX ,name)
299
300 ;; 'port->connection' appeared in June 2018 and we can hardly
301 ;; emulate it on older versions. Thus fall back to
302 ;; 'open-connection', at the risk of talking to the wrong daemon or
303 ;; having our build result reclaimed (XXX).
304 (let* ((store (if (defined? 'port->connection)
305 (port->connection socket #:version ,proto)
306 (open-connection)))
307 (package (hashv-ref %package-table
308 ,(inferior-package-id package)))
309 (drv ,(if target
310 `(package-cross-derivation store package
311 ,target
312 ,system)
313 `(package-derivation store package
314 ,system))))
315 (close-connection store)
316 (close-port socket)
317 (derivation-file-name drv)))
318 inferior)
319 (match (accept socket)
320 ((client . address)
321 (proxy client (nix-server-socket store))))
322 (close-port socket)
323 (read-derivation-from-file (read-inferior-response inferior))))))
324
325(define inferior-package->derivation
326 (store-lift inferior-package-derivation))
327
328(define-gexp-compiler (package-compiler (package <inferior-package>) system
329 target)
330 ;; Compile PACKAGE for SYSTEM, optionally cross-building for TARGET.
331 (inferior-package->derivation package system #:target target))
diff --git a/tests/inferior.scm b/tests/inferior.scm
index ff5cad4210a..817fcb6c6b5 100644
--- a/tests/inferior.scm
+++ b/tests/inferior.scm
@@ -17,9 +17,13 @@
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. 17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18 18
19(define-module (test-inferior) 19(define-module (test-inferior)
20 #:use-module (guix tests)
20 #:use-module (guix inferior) 21 #:use-module (guix inferior)
21 #:use-module (guix packages) 22 #:use-module (guix packages)
23 #:use-module (guix store)
24 #:use-module (guix derivations)
22 #:use-module (gnu packages) 25 #:use-module (gnu packages)
26 #:use-module (gnu packages bootstrap)
23 #:use-module (srfi srfi-1) 27 #:use-module (srfi srfi-1)
24 #:use-module (srfi srfi-64)) 28 #:use-module (srfi srfi-64))
25 29
@@ -29,6 +33,9 @@
29(define %top-builddir 33(define %top-builddir
30 (dirname (search-path %load-compiled-path "guix.go"))) 34 (dirname (search-path %load-compiled-path "guix.go")))
31 35
36(define %store
37 (open-connection-for-tests))
38
32 39
33(test-begin "inferior") 40(test-begin "inferior")
34 41
@@ -72,4 +79,19 @@
72 (close-inferior inferior) 79 (close-inferior inferior)
73 result)))) 80 result))))
74 81
82(test-equal "inferior-package-derivation"
83 (map derivation-file-name
84 (list (package-derivation %store %bootstrap-guile "x86_64-linux")
85 (package-derivation %store %bootstrap-guile "armhf-linux")))
86 (let* ((inferior (open-inferior %top-builddir
87 #:command "scripts/guix"))
88 (packages (inferior-packages inferior))
89 (guile (find (lambda (package)
90 (string=? (package-name %bootstrap-guile)
91 (inferior-package-name package)))
92 packages)))
93 (map derivation-file-name
94 (list (inferior-package-derivation %store guile "x86_64-linux")
95 (inferior-package-derivation %store guile "armhf-linux")))))
96
75(test-end "inferior") 97(test-end "inferior")