diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2016-06-12 23:22:54 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2016-06-12 23:55:22 +0200 |
| commit | fe585be9aa8f5158a7dfb6477d19ece3d643dec3 (patch) | |
| tree | 855b01af0646dee9186ae539fd9f561e47777649 | |
| parent | 31d968fbcfa78b52c5280503417b67943f8a9660 (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.scm | 78 | ||||
| -rw-r--r-- | tests/nar.scm | 42 |
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 |
| 261 | sub-directories of FILE as needed." | 262 | sub-directories of FILE as needed. For each directory entry, call (SELECT? |
| 263 | FILE STAT), where FILE is the entry's absolute file name and STAT is the | ||
| 264 | result 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 |
