utils: Add `patch-shebang'.
* guix/build/utils.scm (search-path-as-string->list): New procedure. (dump-port, patch-shebang): New procedures.master
parent
ad102c4683
commit
ebe2f31f19
|
@ -22,14 +22,20 @@
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 regex)
|
#:use-module (ice-9 regex)
|
||||||
#:use-module (ice-9 rdelim)
|
#:use-module (ice-9 rdelim)
|
||||||
|
#:use-module (rnrs bytevectors)
|
||||||
|
#:use-module (rnrs io ports)
|
||||||
#:export (directory-exists?
|
#:export (directory-exists?
|
||||||
with-directory-excursion
|
with-directory-excursion
|
||||||
set-path-environment-variable
|
set-path-environment-variable
|
||||||
|
search-path-as-string->list
|
||||||
|
list->search-path-as-string
|
||||||
alist-cons-before
|
alist-cons-before
|
||||||
alist-cons-after
|
alist-cons-after
|
||||||
alist-replace
|
alist-replace
|
||||||
substitute
|
substitute
|
||||||
substitute*))
|
substitute*
|
||||||
|
dump-port
|
||||||
|
patch-shebang))
|
||||||
|
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
|
@ -80,6 +86,9 @@ INPUT-DIRS. Example:
|
||||||
(define (list->search-path-as-string lst separator)
|
(define (list->search-path-as-string lst separator)
|
||||||
(string-join lst separator))
|
(string-join lst separator))
|
||||||
|
|
||||||
|
(define* (search-path-as-string->list path #:optional (separator #\:))
|
||||||
|
(string-tokenize path (char-set-complement (char-set separator))))
|
||||||
|
|
||||||
(define* (set-path-environment-variable env-var sub-directories input-dirs
|
(define* (set-path-environment-variable env-var sub-directories input-dirs
|
||||||
#:key (separator ":"))
|
#:key (separator ":"))
|
||||||
"Look for each of SUB-DIRECTORIES in INPUT-DIRS. Set ENV-VAR to a
|
"Look for each of SUB-DIRECTORIES in INPUT-DIRS. Set ENV-VAR to a
|
||||||
|
@ -228,6 +237,72 @@ match substring."
|
||||||
(display (begin body ...) p))))
|
(display (begin body ...) p))))
|
||||||
...)))
|
...)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Patching shebangs---e.g., /bin/sh -> /nix/store/xyz...-bash/bin/sh.
|
||||||
|
;;;
|
||||||
|
|
||||||
|
(define (dump-port in out)
|
||||||
|
"Read as much data as possible from IN and write it to OUT."
|
||||||
|
(define buffer-size 4096)
|
||||||
|
(define buffer
|
||||||
|
(make-bytevector buffer-size))
|
||||||
|
|
||||||
|
(let loop ((bytes (get-bytevector-n! in buffer 0 buffer-size)))
|
||||||
|
(or (eof-object? bytes)
|
||||||
|
(begin
|
||||||
|
(put-bytevector out buffer 0 bytes)
|
||||||
|
(loop (get-bytevector-n! in buffer 0 buffer-size))))))
|
||||||
|
|
||||||
|
(define patch-shebang
|
||||||
|
(let ((shebang-rx (make-regexp "^[[:blank:]]*([[:graph:]]*)/([[:alnum:]]+)(.*)$")))
|
||||||
|
(lambda (file)
|
||||||
|
"Patch the #! interpreter path in FILE, if FILE actually starts with a
|
||||||
|
shebang."
|
||||||
|
(define (patch p interpreter rest-of-line)
|
||||||
|
(let* ((template (string-append file ".XXXXXX"))
|
||||||
|
(out (mkstemp! template))
|
||||||
|
(mode (stat:mode (stat file))))
|
||||||
|
(with-throw-handler #t
|
||||||
|
(lambda ()
|
||||||
|
(format out "#!~a~a~%"
|
||||||
|
interpreter rest-of-line)
|
||||||
|
(dump-port p out)
|
||||||
|
(close out)
|
||||||
|
(chmod template mode)
|
||||||
|
(rename-file template file)
|
||||||
|
#t)
|
||||||
|
(lambda (key . args)
|
||||||
|
(format (current-error-port)
|
||||||
|
"patch-shebang: ~a: error: ~a ~s~%"
|
||||||
|
file key args)
|
||||||
|
(false-if-exception (delete-file template))
|
||||||
|
#f))))
|
||||||
|
|
||||||
|
(with-fluids ((%default-port-encoding #f)) ; ASCII
|
||||||
|
(call-with-input-file file
|
||||||
|
(lambda (p)
|
||||||
|
(and (eq? #\# (read-char p))
|
||||||
|
(eq? #\! (read-char p))
|
||||||
|
(let ((line (false-if-exception (read-line p))))
|
||||||
|
(and=> (and line (regexp-exec shebang-rx line))
|
||||||
|
(lambda (m)
|
||||||
|
(let* ((PATH
|
||||||
|
(search-path-as-string->list (getenv "PATH")))
|
||||||
|
(cmd (match:substring m 2))
|
||||||
|
(bin (search-path PATH cmd)))
|
||||||
|
(if bin
|
||||||
|
(begin
|
||||||
|
(format (current-error-port)
|
||||||
|
"patch-shebang: ~a: changing `~a/~a' to `~a'~%"
|
||||||
|
file (match:substring m 1)
|
||||||
|
cmd bin)
|
||||||
|
(patch p bin (match:substring m 3)))
|
||||||
|
(begin
|
||||||
|
(format (current-error-port)
|
||||||
|
"patch-shebang: ~a: warning: no binary for interpreter `~a' found in $PATH~%"
|
||||||
|
file cmd)
|
||||||
|
#f)))))))))))))
|
||||||
|
|
||||||
;;; Local Variables:
|
;;; Local Variables:
|
||||||
;;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 1)
|
;;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 1)
|
||||||
|
|
Reference in New Issue