tar: Support --list and --verbose.
* gash/ustar.scm (extract-ustar-file): Add keyword argument: extract? (extract-ustar-archive): Add keyword arguments: extract?, verbose?: (display-rwx, display-header, list-ustar-archive): New function * gash/bournish-commands.scm (tar-command): Support --list, --verbose.
This commit is contained in:
parent
463b71acc9
commit
28d62b6169
|
@ -364,6 +364,10 @@ Options:
|
||||||
(for-each display-match matches)
|
(for-each display-match matches)
|
||||||
0)))))))))
|
0)))))))))
|
||||||
|
|
||||||
|
(define (multi-opt options name)
|
||||||
|
(let ((opt? (lambda (o) (and (eq? (car o) name) (cdr o)))))
|
||||||
|
(filter-map opt? options)))
|
||||||
|
|
||||||
(define (tar-command . args)
|
(define (tar-command . args)
|
||||||
(lambda _
|
(lambda _
|
||||||
(let* ((option-spec
|
(let* ((option-spec
|
||||||
|
@ -373,19 +377,24 @@ Options:
|
||||||
(file (single-char #\f) (value #t))
|
(file (single-char #\f) (value #t))
|
||||||
(help (single-char #\h))
|
(help (single-char #\h))
|
||||||
(mtime (value #t))
|
(mtime (value #t))
|
||||||
|
(list (single-char #\t))
|
||||||
(numeric-owner?)
|
(numeric-owner?)
|
||||||
(owner (value #t))
|
(owner (value #t))
|
||||||
(sort (value #t))
|
(sort (value #t))
|
||||||
(version (single-char #\V))))
|
(verbose (single-char #\v))
|
||||||
|
(version (single-char #\V))))
|
||||||
(args (cons "tar" args))
|
(args (cons "tar" args))
|
||||||
(options (getopt-long args option-spec))
|
(options (getopt-long args option-spec))
|
||||||
(create? (option-ref options 'create #f))
|
(create? (option-ref options 'create #f))
|
||||||
|
(list? (option-ref options 'list #f))
|
||||||
(extract? (option-ref options 'extract #f))
|
(extract? (option-ref options 'extract #f))
|
||||||
(file (option-ref options 'file "/dev/stdout"))
|
(file (option-ref options 'file "/dev/stdout"))
|
||||||
(files (option-ref options '() '()))
|
(files (option-ref options '() '()))
|
||||||
(help? (option-ref options 'help #f))
|
(help? (option-ref options 'help #f))
|
||||||
(usage? (and (not help?) (not (or (and create? (pair? files)) extract?))))
|
(usage? (and (not help?) (not (or (and create? (pair? files))
|
||||||
(version? (option-ref options 'version #f)))
|
extract? list?))))
|
||||||
|
(verbosity (length (multi-opt options 'verbose)))
|
||||||
|
(version? (option-ref options 'version #f)))
|
||||||
(cond ((or help? usage?) (format (if usage? (current-error-port) #t)
|
(cond ((or help? usage?) (format (if usage? (current-error-port) #t)
|
||||||
"\
|
"\
|
||||||
Usage: tar [OPTION]... [FILE]...
|
Usage: tar [OPTION]... [FILE]...
|
||||||
|
@ -398,7 +407,9 @@ Usage: tar [OPTION]... [FILE]...
|
||||||
--owner=NAME force NAME as owner for added files
|
--owner=NAME force NAME as owner for added files
|
||||||
--sort=ORDER directory sorting order: none (default), name or
|
--sort=ORDER directory sorting order: none (default), name or
|
||||||
inode
|
inode
|
||||||
|
-t, --list list the contents of an archive
|
||||||
-V, --version display version
|
-V, --version display version
|
||||||
|
-v, --verbose verbosely list files processed
|
||||||
-x, --extract extract files from an archive
|
-x, --extract extract files from an archive
|
||||||
")
|
")
|
||||||
(exit (if usage? 2 0)))
|
(exit (if usage? 2 0)))
|
||||||
|
@ -416,9 +427,13 @@ Usage: tar [OPTION]... [FILE]...
|
||||||
,@(if group `(#:group ,group) '())
|
,@(if group `(#:group ,group) '())
|
||||||
,@(if mtime `(#:mtime ,mtime) '())
|
,@(if mtime `(#:mtime ,mtime) '())
|
||||||
,@(if numeric-owner? `(#:numeric-owner? ,numeric-owner?) '())
|
,@(if numeric-owner? `(#:numeric-owner? ,numeric-owner?) '())
|
||||||
,@(if owner `(#:owner ,owner) '())))))
|
,@(if owner `(#:owner ,owner) '())
|
||||||
|
,@(if owner `(#:owner ,owner) '())
|
||||||
|
#:verbosity ,verbosity))))
|
||||||
(extract?
|
(extract?
|
||||||
(extract-ustar-archive file files))))))
|
(extract-ustar-archive file files #:verbosity verbosity))
|
||||||
|
(list?
|
||||||
|
(list-ustar-archive file files #:verbosity (1+ verbosity)))))))
|
||||||
|
|
||||||
(define %bournish-commands
|
(define %bournish-commands
|
||||||
`(
|
`(
|
||||||
|
|
120
gash/ustar.scm
120
gash/ustar.scm
|
@ -26,8 +26,9 @@
|
||||||
#:use-module (rnrs bytevectors)
|
#:use-module (rnrs bytevectors)
|
||||||
#:use-module (rnrs io ports)
|
#:use-module (rnrs io ports)
|
||||||
#:use-module (gash guix-build-utils)
|
#:use-module (gash guix-build-utils)
|
||||||
#:export (extract-ustar-archive
|
#:export (create-ustar-archive
|
||||||
create-ustar-archive))
|
extract-ustar-archive
|
||||||
|
list-ustar-archive))
|
||||||
|
|
||||||
(define (fmt-error fmt . args)
|
(define (fmt-error fmt . args)
|
||||||
(error (apply format #f fmt args)))
|
(error (apply format #f fmt args)))
|
||||||
|
@ -396,7 +397,7 @@
|
||||||
%uname %gname %dev-major %dev-minor
|
%uname %gname %dev-major %dev-minor
|
||||||
%prefix))))))
|
%prefix))))))
|
||||||
|
|
||||||
(define* (write-ustar-file port file-name #:key group mtime numeric-owner? owner)
|
(define* (write-ustar-file port file-name #:key group mtime numeric-owner? owner verbosity)
|
||||||
(let* ((file-name (if (string-every file-name-separator? file-name)
|
(let* ((file-name (if (string-every file-name-separator? file-name)
|
||||||
file-name-separator-string
|
file-name-separator-string
|
||||||
(string-trim-right file-name file-name-separator?)))
|
(string-trim-right file-name file-name-separator?)))
|
||||||
|
@ -422,51 +423,70 @@
|
||||||
(for-each (lambda (file-name) (write-ustar-file port file-name))
|
(for-each (lambda (file-name) (write-ustar-file port file-name))
|
||||||
(files-in-directory file-name))))))
|
(files-in-directory file-name))))))
|
||||||
|
|
||||||
(define (extract-ustar-file port header)
|
(define (ustar-header-file-name header)
|
||||||
|
(let ((name (ustar-header-name header))
|
||||||
|
(prefix (ustar-header-prefix header)))
|
||||||
|
(if (string-null? prefix) name
|
||||||
|
(string-append prefix "/" name))))
|
||||||
|
|
||||||
|
(define* (extract-ustar-file port header #:key (extract? #t))
|
||||||
(let* ((size (ustar-header-size header))
|
(let* ((size (ustar-header-size header))
|
||||||
(name (ustar-header-name header))
|
(file-name (ustar-header-file-name header))
|
||||||
(prefix (ustar-header-prefix header))
|
(dir (dirname file-name))
|
||||||
(file-name (if (string-null? prefix) name
|
(thunk (lambda _
|
||||||
(string-append prefix "/" name)))
|
(let loop ((record (read-ustar-record port)) (wrote 0))
|
||||||
(dir (dirname file-name)))
|
(let* ((read (+ wrote 512))
|
||||||
(mkdir-p dir)
|
(block (if (< read size) record
|
||||||
(with-output-to-file file-name
|
(sub-bytevector record 0 (- size wrote)))))
|
||||||
(lambda _
|
(when extract?
|
||||||
(let loop ((record (read-ustar-record port)) (wrote 0))
|
(display (bv->ustar-0string block "block")))
|
||||||
(let* ((read (+ wrote 512))
|
(and (not (eof-object? record))
|
||||||
(block (if (< read size) record
|
(< read size)
|
||||||
(sub-bytevector record 0 (- size wrote)))))
|
(loop (read-ustar-record port) read)))))))
|
||||||
(display (bv->ustar-0string block "block"))
|
(when extract?
|
||||||
(and (not (eof-object? record))
|
(mkdir-p dir))
|
||||||
(< read size)
|
(if extract? (with-output-to-file file-name thunk)
|
||||||
(loop (read-ustar-record port) read))))))
|
(thunk))
|
||||||
(chmod file-name (ustar-header-mode header))
|
(when extract?
|
||||||
(let ((mtime (ustar-header-mtime header)))
|
(chmod file-name (ustar-header-mode header))
|
||||||
(utime file-name mtime mtime))))
|
(let ((mtime (ustar-header-mtime header)))
|
||||||
|
(utime file-name mtime mtime)))))
|
||||||
|
|
||||||
(define (extract-ustar-archive file-name files)
|
(define (display-rwx perm)
|
||||||
|
(display (if (zero? (logand perm 4)) "-" "r"))
|
||||||
|
(display (if (zero? (logand perm 2)) "-" "w"))
|
||||||
|
(display (if (zero? (logand perm 1)) "-" "x")))
|
||||||
|
|
||||||
|
(define* (display-header header #:key verbose?)
|
||||||
|
(when verbose?
|
||||||
|
(let ((mode (ustar-header-mode header))
|
||||||
|
(uid (ustar-header-uid header))
|
||||||
|
(gid (ustar-header-gid header))
|
||||||
|
(size (ustar-header-size header))
|
||||||
|
(date (strftime "%c" (localtime (ustar-header-mtime header)))))
|
||||||
|
(display "-")
|
||||||
|
(display-rwx (ash mode -6))
|
||||||
|
(display-rwx (ash (logand mode #o70) -3))
|
||||||
|
(display-rwx (logand mode #o7))
|
||||||
|
(display " ")
|
||||||
|
(format #t "~8s" uid)
|
||||||
|
(display " ")
|
||||||
|
(format #t "~8s" gid)
|
||||||
|
(format #t "~8d" size)
|
||||||
|
(display " ")
|
||||||
|
(display date)
|
||||||
|
(display " ")))
|
||||||
|
(display (ustar-header-file-name header))
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define* (create-ustar-archive file-name files #:key group mtime numeric-owner? owner verbosity)
|
||||||
(catch #t
|
(catch #t
|
||||||
(lambda ()
|
|
||||||
(call-with-port* (open-file file-name "rb")
|
|
||||||
(lambda (in)
|
|
||||||
(let loop ((header (read-ustar-header in)))
|
|
||||||
(when (and header
|
|
||||||
(not (eof-object? header)))
|
|
||||||
(extract-ustar-file in header)
|
|
||||||
(loop (read-ustar-header in)))))))
|
|
||||||
(lambda (key subr message args . rest)
|
|
||||||
(format (current-error-port) "ERROR: ~a\n"
|
|
||||||
(apply format #f message args))
|
|
||||||
(exit 1))))
|
|
||||||
|
|
||||||
(define* (create-ustar-archive file-name files #:key group mtime numeric-owner? owner)
|
|
||||||
(catch 'fubar
|
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(call-with-port* (open-file file-name "wb")
|
(call-with-port* (open-file file-name "wb")
|
||||||
(lambda (out)
|
(lambda (out)
|
||||||
(for-each
|
(for-each
|
||||||
(cut write-ustar-file out <>
|
(cut write-ustar-file out <>
|
||||||
#:group group #:mtime mtime #:numeric-owner? numeric-owner? #:owner owner)
|
#:group group #:mtime mtime #:numeric-owner? numeric-owner? #:owner owner #:verbosity verbosity)
|
||||||
files)
|
files)
|
||||||
(write-ustar-footer out))))
|
(write-ustar-footer out))))
|
||||||
(lambda (key subr message args . rest)
|
(lambda (key subr message args . rest)
|
||||||
|
@ -475,6 +495,26 @@
|
||||||
(apply format #f message args))
|
(apply format #f message args))
|
||||||
(exit 1))))
|
(exit 1))))
|
||||||
|
|
||||||
|
(define* (extract-ustar-archive file-name files #:key (extract? #t) verbosity)
|
||||||
|
(catch #t
|
||||||
|
(lambda ()
|
||||||
|
(call-with-port* (open-file file-name "rb")
|
||||||
|
(lambda (in)
|
||||||
|
(let loop ((header (read-ustar-header in)))
|
||||||
|
(when (and header
|
||||||
|
(not (eof-object? header)))
|
||||||
|
(unless (zero? verbosity)
|
||||||
|
(display-header header #:verbose? (not (zero? verbosity))))
|
||||||
|
(extract-ustar-file in header #:extract? extract?)
|
||||||
|
(loop (read-ustar-header in)))))))
|
||||||
|
(lambda (key subr message args . rest)
|
||||||
|
(format (current-error-port) "ERROR: ~a\n"
|
||||||
|
(apply format #f message args))
|
||||||
|
(exit 1))))
|
||||||
|
|
||||||
|
(define* (list-ustar-archive file-name files #:key verbosity)
|
||||||
|
(extract-ustar-archive file-name files #:extract? #:verbosity verbosity))
|
||||||
|
|
||||||
;;; Local Variables:
|
;;; Local Variables:
|
||||||
;;; mode: scheme
|
;;; mode: scheme
|
||||||
;;; eval: (put 'call-with-port* 'scheme-indent-function 1)
|
;;; eval: (put 'call-with-port* 'scheme-indent-function 1)
|
||||||
|
|
Loading…
Reference in New Issue