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.
This commit is contained in:
parent
31d968fbcf
commit
fe585be9aa
|
@ -256,53 +256,57 @@ the size in bytes."
|
||||||
;; Magic cookie for Nix archives.
|
;; Magic cookie for Nix archives.
|
||||||
"nix-archive-1")
|
"nix-archive-1")
|
||||||
|
|
||||||
(define (write-file file port)
|
(define* (write-file file port
|
||||||
|
#:key (select? (const #t)))
|
||||||
"Write the contents of FILE to PORT in Nar format, recursing into
|
"Write the contents of FILE to PORT in Nar format, recursing into
|
||||||
sub-directories of FILE as needed."
|
sub-directories of FILE as needed. For each directory entry, call (SELECT?
|
||||||
|
FILE STAT), where FILE is the entry's absolute file name and STAT is the
|
||||||
|
result of 'lstat'; exclude entries for which SELECT? does not return true."
|
||||||
(define p port)
|
(define p port)
|
||||||
|
|
||||||
(write-string %archive-version-1 p)
|
(write-string %archive-version-1 p)
|
||||||
|
|
||||||
(let dump ((f file))
|
(let dump ((f file) (s (lstat file)))
|
||||||
(let ((s (lstat f)))
|
(write-string "(" p)
|
||||||
(write-string "(" p)
|
(case (stat:type s)
|
||||||
(case (stat:type s)
|
((regular)
|
||||||
((regular)
|
(write-string "type" p)
|
||||||
(write-string "type" p)
|
(write-string "regular" p)
|
||||||
(write-string "regular" p)
|
(if (not (zero? (logand (stat:mode s) #o100)))
|
||||||
(if (not (zero? (logand (stat:mode s) #o100)))
|
(begin
|
||||||
(begin
|
(write-string "executable" p)
|
||||||
(write-string "executable" p)
|
(write-string "" p)))
|
||||||
(write-string "" p)))
|
(write-contents f p (stat:size s)))
|
||||||
(write-contents f p (stat:size s)))
|
((directory)
|
||||||
((directory)
|
(write-string "type" p)
|
||||||
(write-string "type" p)
|
(write-string "directory" p)
|
||||||
(write-string "directory" p)
|
(let ((entries
|
||||||
(let ((entries
|
;; 'scandir' defaults to 'string-locale<?' to sort files, but
|
||||||
;; 'scandir' defaults to 'string-locale<?' to sort files, but
|
;; this happens to be case-insensitive (at least in 'en_US'
|
||||||
;; this happens to be case-insensitive (at least in 'en_US'
|
;; locale on libc 2.18.) Conversely, we want files to be
|
||||||
;; locale on libc 2.18.) Conversely, we want files to be
|
;; sorted in a case-sensitive fashion.
|
||||||
;; sorted in a case-sensitive fashion.
|
(scandir f (negate (cut member <> '("." ".."))) string<?)))
|
||||||
(scandir f (negate (cut member <> '("." ".."))) string<?)))
|
(for-each (lambda (e)
|
||||||
(for-each (lambda (e)
|
(let* ((f (string-append f "/" e))
|
||||||
(let ((f (string-append f "/" e)))
|
(s (lstat f)))
|
||||||
|
(when (select? f s)
|
||||||
(write-string "entry" p)
|
(write-string "entry" p)
|
||||||
(write-string "(" p)
|
(write-string "(" p)
|
||||||
(write-string "name" p)
|
(write-string "name" p)
|
||||||
(write-string e p)
|
(write-string e p)
|
||||||
(write-string "node" p)
|
(write-string "node" p)
|
||||||
(dump f)
|
(dump f s)
|
||||||
(write-string ")" p)))
|
(write-string ")" p))))
|
||||||
entries)))
|
entries)))
|
||||||
((symlink)
|
((symlink)
|
||||||
(write-string "type" p)
|
(write-string "type" p)
|
||||||
(write-string "symlink" p)
|
(write-string "symlink" p)
|
||||||
(write-string "target" p)
|
(write-string "target" p)
|
||||||
(write-string (readlink f) p))
|
(write-string (readlink f) p))
|
||||||
(else
|
(else
|
||||||
(raise (condition (&message (message "unsupported file type"))
|
(raise (condition (&message (message "unsupported file type"))
|
||||||
(&nar-error (file f) (port port))))))
|
(&nar-error (file f) (port port))))))
|
||||||
(write-string ")" p))))
|
(write-string ")" p)))
|
||||||
|
|
||||||
(define (restore-file port file)
|
(define (restore-file port file)
|
||||||
"Read a file (possibly a directory structure) in Nar format from PORT.
|
"Read a file (possibly a directory structure) in Nar format from PORT.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
;;; GNU Guix --- Functional package management for GNU
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
|
;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -241,6 +241,46 @@
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(rmdir input)))))
|
(rmdir input)))))
|
||||||
|
|
||||||
|
(test-assert "write-file #:select? + restore-file"
|
||||||
|
(let ((input (string-append %test-dir ".input")))
|
||||||
|
(mkdir input)
|
||||||
|
(dynamic-wind
|
||||||
|
(const #t)
|
||||||
|
(lambda ()
|
||||||
|
(with-file-tree input
|
||||||
|
(directory "root"
|
||||||
|
((directory "a" (("x") ("y") ("z")))
|
||||||
|
("b") ("c") ("d" -> "b")))
|
||||||
|
(let* ((output %test-dir)
|
||||||
|
(nar (string-append output ".nar")))
|
||||||
|
(dynamic-wind
|
||||||
|
(lambda () #t)
|
||||||
|
(lambda ()
|
||||||
|
(call-with-output-file nar
|
||||||
|
(lambda (port)
|
||||||
|
(write-file input port
|
||||||
|
#:select?
|
||||||
|
(lambda (file stat)
|
||||||
|
(and (not (string=? (basename file)
|
||||||
|
"a"))
|
||||||
|
(not (eq? (stat:type stat)
|
||||||
|
'symlink)))))))
|
||||||
|
(call-with-input-file nar
|
||||||
|
(cut restore-file <> output))
|
||||||
|
|
||||||
|
;; Make sure "a" and "d" have been filtered out.
|
||||||
|
(and (not (file-exists? (string-append output "/root/a")))
|
||||||
|
(file=? (string-append output "/root/b")
|
||||||
|
(string-append input "/root/b"))
|
||||||
|
(file=? (string-append output "/root/c")
|
||||||
|
(string-append input "/root/c"))
|
||||||
|
(not (file-exists? (string-append output "/root/d")))))
|
||||||
|
(lambda ()
|
||||||
|
(false-if-exception (delete-file nar))
|
||||||
|
(false-if-exception (rm-rf output)))))))
|
||||||
|
(lambda ()
|
||||||
|
(rmdir input)))))
|
||||||
|
|
||||||
;; 'restore-file-set' depends on 'open-sha256-input-port', which in turn
|
;; 'restore-file-set' depends on 'open-sha256-input-port', which in turn
|
||||||
;; relies on a Guile 2.0.10+ feature.
|
;; relies on a Guile 2.0.10+ feature.
|
||||||
(test-skip (if (false-if-exception
|
(test-skip (if (false-if-exception
|
||||||
|
|
Loading…
Reference in New Issue