summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2016-06-12 23:22:54 +0200
committerLudovic Courtès <ludo@gnu.org>2016-06-12 23:55:22 +0200
commitfe585be9aa8f5158a7dfb6477d19ece3d643dec3 (patch)
tree855b01af0646dee9186ae539fd9f561e47777649
parent31d968fbcfa78b52c5280503417b67943f8a9660 (diff)
serialization: Add #:select? parameter to 'write-file'.
* guix/serialization.scm (write-file): Add #:select? parameter and honor it. * tests/nar.scm ("write-file #:select? + restore-file"): New test.
-rw-r--r--guix/serialization.scm78
-rw-r--r--tests/nar.scm42
2 files changed, 82 insertions, 38 deletions
diff --git a/guix/serialization.scm b/guix/serialization.scm
index 286b4cbf30e..f17f516c092 100644
--- a/guix/serialization.scm
+++ b/guix/serialization.scm
@@ -256,53 +256,57 @@ the size in bytes."
256 ;; Magic cookie for Nix archives. 256 ;; Magic cookie for Nix archives.
257 "nix-archive-1") 257 "nix-archive-1")
258 258
259(define (write-file file port) 259(define* (write-file file port
260 #:key (select? (const #t)))
260 "Write the contents of FILE to PORT in Nar format, recursing into 261 "Write the contents of FILE to PORT in Nar format, recursing into
261sub-directories of FILE as needed." 262sub-directories of FILE as needed. For each directory entry, call (SELECT?
263FILE STAT), where FILE is the entry's absolute file name and STAT is the
264result of 'lstat'; exclude entries for which SELECT? does not return true."
262 (define p port) 265 (define p port)
263 266
264 (write-string %archive-version-1 p) 267 (write-string %archive-version-1 p)
265 268
266 (let dump ((f file)) 269 (let dump ((f file) (s (lstat file)))
267 (let ((s (lstat f))) 270 (write-string "(" p)
268 (write-string "(" p) 271 (case (stat:type s)
269 (case (stat:type s) 272 ((regular)
270 ((regular) 273 (write-string "type" p)
271 (write-string "type" p) 274 (write-string "regular" p)
272 (write-string "regular" p) 275 (if (not (zero? (logand (stat:mode s) #o100)))
273 (if (not (zero? (logand (stat:mode s) #o100))) 276 (begin
274 (begin 277 (write-string "executable" p)
275 (write-string "executable" p) 278 (write-string "" p)))
276 (write-string "" p))) 279 (write-contents f p (stat:size s)))
277 (write-contents f p (stat:size s))) 280 ((directory)
278 ((directory) 281 (write-string "type" p)
279 (write-string "type" p) 282 (write-string "directory" p)
280 (write-string "directory" p) 283 (let ((entries
281 (let ((entries 284 ;; 'scandir' defaults to 'string-locale<?' to sort files, but
282 ;; 'scandir' defaults to 'string-locale<?' to sort files, but 285 ;; this happens to be case-insensitive (at least in 'en_US'
283 ;; this happens to be case-insensitive (at least in 'en_US' 286 ;; locale on libc 2.18.) Conversely, we want files to be
284 ;; locale on libc 2.18.) Conversely, we want files to be 287 ;; sorted in a case-sensitive fashion.
285 ;; sorted in a case-sensitive fashion. 288 (scandir f (negate (cut member <> '("." ".."))) string<?)))
286 (scandir f (negate (cut member <> '("." ".."))) string<?))) 289 (for-each (lambda (e)
287 (for-each (lambda (e) 290 (let* ((f (string-append f "/" e))
288 (let ((f (string-append f "/" e))) 291 (s (lstat f)))
292 (when (select? f s)
289 (write-string "entry" p) 293 (write-string "entry" p)
290 (write-string "(" p) 294 (write-string "(" p)
291 (write-string "name" p) 295 (write-string "name" p)
292 (write-string e p) 296 (write-string e p)
293 (write-string "node" p) 297 (write-string "node" p)
294 (dump f) 298 (dump f s)
295 (write-string ")" p))) 299 (write-string ")" p))))
296 entries))) 300 entries)))
297 ((symlink) 301 ((symlink)
298 (write-string "type" p) 302 (write-string "type" p)
299 (write-string "symlink" p) 303 (write-string "symlink" p)
300 (write-string "target" p) 304 (write-string "target" p)
301 (write-string (readlink f) p)) 305 (write-string (readlink f) p))
302 (else 306 (else
303 (raise (condition (&message (message "unsupported file type")) 307 (raise (condition (&message (message "unsupported file type"))
304 (&nar-error (file f) (port port)))))) 308 (&nar-error (file f) (port port))))))
305 (write-string ")" p)))) 309 (write-string ")" p)))
306 310
307(define (restore-file port file) 311(define (restore-file port file)
308 "Read a file (possibly a directory structure) in Nar format from PORT. 312 "Read a file (possibly a directory structure) in Nar format from PORT.
diff --git a/tests/nar.scm b/tests/nar.scm
index 9796980e350..4f4b304b1dd 100644
--- a/tests/nar.scm
+++ b/tests/nar.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> 2;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
3;;; 3;;;
4;;; This file is part of GNU Guix. 4;;; This file is part of GNU Guix.
5;;; 5;;;
@@ -241,6 +241,46 @@
241 (lambda () 241 (lambda ()
242 (rmdir input))))) 242 (rmdir input)))))
243 243
244(test-assert "write-file #:select? + restore-file"
245 (let ((input (string-append %test-dir ".input")))
246 (mkdir input)
247 (dynamic-wind
248 (const #t)
249 (lambda ()
250 (with-file-tree input
251 (directory "root"
252 ((directory "a" (("x") ("y") ("z")))
253 ("b") ("c") ("d" -> "b")))
254 (let* ((output %test-dir)
255 (nar (string-append output ".nar")))
256 (dynamic-wind
257 (lambda () #t)
258 (lambda ()
259 (call-with-output-file nar
260 (lambda (port)
261 (write-file input port
262 #:select?
263 (lambda (file stat)
264 (and (not (string=? (basename file)
265 "a"))
266 (not (eq? (stat:type stat)
267 'symlink)))))))
268 (call-with-input-file nar
269 (cut restore-file <> output))
270
271 ;; Make sure "a" and "d" have been filtered out.
272 (and (not (file-exists? (string-append output "/root/a")))
273 (file=? (string-append output "/root/b")
274 (string-append input "/root/b"))
275 (file=? (string-append output "/root/c")
276 (string-append input "/root/c"))
277 (not (file-exists? (string-append output "/root/d")))))
278 (lambda ()
279 (false-if-exception (delete-file nar))
280 (false-if-exception (rm-rf output)))))))
281 (lambda ()
282 (rmdir input)))))
283
244;; 'restore-file-set' depends on 'open-sha256-input-port', which in turn 284;; 'restore-file-set' depends on 'open-sha256-input-port', which in turn
245;; relies on a Guile 2.0.10+ feature. 285;; relies on a Guile 2.0.10+ feature.
246(test-skip (if (false-if-exception 286(test-skip (if (false-if-exception