utils: Add `with-atomic-file-replacement'.
* guix/build/utils.scm (with-atomic-file-replacement): New procedure. (substitute): Use it.
This commit is contained in:
parent
df1fab5837
commit
dcd7290654
|
@ -32,6 +32,7 @@
|
||||||
alist-cons-before
|
alist-cons-before
|
||||||
alist-cons-after
|
alist-cons-after
|
||||||
alist-replace
|
alist-replace
|
||||||
|
with-atomic-file-replacement
|
||||||
substitute
|
substitute
|
||||||
substitute*
|
substitute*
|
||||||
dump-port
|
dump-port
|
||||||
|
@ -157,45 +158,55 @@ An error is raised when no such pair exists."
|
||||||
;;; Text substitution (aka. sed).
|
;;; Text substitution (aka. sed).
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define (substitute file pattern+procs)
|
(define (with-atomic-file-replacement file proc)
|
||||||
"PATTERN+PROCS is a list of regexp/two-argument procedure. For each line
|
"Call PROC with two arguments: an input port for FILE, and an output
|
||||||
of FILE, and for each PATTERN that it matches, call the corresponding PROC
|
port for the file that is going to replace FILE. Upon success, FILE is
|
||||||
as (PROC LINE MATCHES); PROC must return the line that will be written as a
|
atomically replaced by what has been written to the output port, and
|
||||||
substitution of the original line."
|
PROC's result is returned."
|
||||||
(let* ((rx+proc (map (match-lambda
|
(let* ((template (string-append file ".XXXXXX"))
|
||||||
(((? regexp? pattern) . proc)
|
|
||||||
(cons pattern proc))
|
|
||||||
((pattern . proc)
|
|
||||||
(cons (make-regexp pattern regexp/extended)
|
|
||||||
proc)))
|
|
||||||
pattern+procs))
|
|
||||||
(template (string-append file ".XXXXXX"))
|
|
||||||
(out (mkstemp! template))
|
(out (mkstemp! template))
|
||||||
(mode (stat:mode (stat file))))
|
(mode (stat:mode (stat file))))
|
||||||
(with-throw-handler #t
|
(with-throw-handler #t
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(call-with-input-file file
|
(call-with-input-file file
|
||||||
(lambda (in)
|
(lambda (in)
|
||||||
(let loop ((line (read-line in 'concat)))
|
(let ((result (proc in out)))
|
||||||
(if (eof-object? line)
|
(close out)
|
||||||
#t
|
(chmod template mode)
|
||||||
(let ((line (fold (lambda (r+p line)
|
(rename-file template file)
|
||||||
(match r+p
|
result))))
|
||||||
((regexp . proc)
|
|
||||||
(match (list-matches regexp line)
|
|
||||||
((and m+ (_ _ ...))
|
|
||||||
(proc line m+))
|
|
||||||
(_ line)))))
|
|
||||||
line
|
|
||||||
rx+proc)))
|
|
||||||
(display line out)
|
|
||||||
(loop (read-line in 'concat)))))))
|
|
||||||
(close out)
|
|
||||||
(chmod template mode)
|
|
||||||
(rename-file template file))
|
|
||||||
(lambda (key . args)
|
(lambda (key . args)
|
||||||
(false-if-exception (delete-file template))))))
|
(false-if-exception (delete-file template))))))
|
||||||
|
|
||||||
|
(define (substitute file pattern+procs)
|
||||||
|
"PATTERN+PROCS is a list of regexp/two-argument procedure. For each line
|
||||||
|
of FILE, and for each PATTERN that it matches, call the corresponding PROC
|
||||||
|
as (PROC LINE MATCHES); PROC must return the line that will be written as a
|
||||||
|
substitution of the original line."
|
||||||
|
(let ((rx+proc (map (match-lambda
|
||||||
|
(((? regexp? pattern) . proc)
|
||||||
|
(cons pattern proc))
|
||||||
|
((pattern . proc)
|
||||||
|
(cons (make-regexp pattern regexp/extended)
|
||||||
|
proc)))
|
||||||
|
pattern+procs)))
|
||||||
|
(with-atomic-file-replacement file
|
||||||
|
(lambda (in out)
|
||||||
|
(let loop ((line (read-line in 'concat)))
|
||||||
|
(if (eof-object? line)
|
||||||
|
#t
|
||||||
|
(let ((line (fold (lambda (r+p line)
|
||||||
|
(match r+p
|
||||||
|
((regexp . proc)
|
||||||
|
(match (list-matches regexp line)
|
||||||
|
((and m+ (_ _ ...))
|
||||||
|
(proc line m+))
|
||||||
|
(_ line)))))
|
||||||
|
line
|
||||||
|
rx+proc)))
|
||||||
|
(display line out)
|
||||||
|
(loop (read-line in 'concat)))))))))
|
||||||
|
|
||||||
|
|
||||||
(define-syntax let-matches
|
(define-syntax let-matches
|
||||||
;; Helper macro for `substitute*'.
|
;; Helper macro for `substitute*'.
|
||||||
|
@ -329,4 +340,5 @@ patched, #f otherwise."
|
||||||
;;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 1)
|
;;; eval: (put 'call-with-output-file/atomic 'scheme-indent-function 1)
|
||||||
;;; eval: (put 'with-throw-handler 'scheme-indent-function 1)
|
;;; eval: (put 'with-throw-handler 'scheme-indent-function 1)
|
||||||
;;; eval: (put 'let-matches 'scheme-indent-function 3)
|
;;; eval: (put 'let-matches 'scheme-indent-function 3)
|
||||||
|
;;; eval: (put 'with-atomic-file-replacement 'scheme-indent-function 1)
|
||||||
;;; End:
|
;;; End:
|
||||||
|
|
Loading…
Reference in New Issue