summaryrefslogtreecommitdiff
path: root/guix/utils.scm
diff options
context:
space:
mode:
Diffstat (limited to 'guix/utils.scm')
-rw-r--r--guix/utils.scm51
1 files changed, 50 insertions, 1 deletions
diff --git a/guix/utils.scm b/guix/utils.scm
index de541799fa..6c01edde21 100644
--- a/guix/utils.scm
+++ b/guix/utils.scm
@@ -41,6 +41,7 @@
#:use-module (ice-9 regex)
#:use-module (ice-9 match)
#:use-module (ice-9 format)
+ #:use-module ((ice-9 iconv) #:select (bytevector->string))
#:use-module (system foreign)
#:export (bytevector->base16-string
base16-string->bytevector
@@ -60,6 +61,7 @@
location-line
location-column
source-properties->location
+ location->source-properties
nix-system->gnu-triplet
gnu-triplet->nix-system
@@ -86,6 +88,7 @@
split
cache-directory
readlink*
+ edit-expression
filtered-port
compressed-port
@@ -318,6 +321,44 @@ a list of command-line arguments passed to the compression program."
(unless (every (compose zero? cdr waitpid) pids)
(error "compressed-output-port failure" pids))))))
+(define* (edit-expression source-properties proc #:key (encoding "UTF-8"))
+ "Edit the expression specified by SOURCE-PROPERTIES using PROC, which should
+be a procedure that takes the original expression in string and returns a new
+one. ENCODING will be used to interpret all port I/O, it default to UTF-8.
+This procedure returns #t on success."
+ (with-fluids ((%default-port-encoding encoding))
+ (let* ((file (assq-ref source-properties 'filename))
+ (line (assq-ref source-properties 'line))
+ (column (assq-ref source-properties 'column))
+ (in (open-input-file file))
+ ;; The start byte position of the expression.
+ (start (begin (while (not (and (= line (port-line in))
+ (= column (port-column in))))
+ (when (eof-object? (read-char in))
+ (error (format #f "~a: end of file~%" in))))
+ (ftell in)))
+ ;; The end byte position of the expression.
+ (end (begin (read in) (ftell in))))
+ (seek in 0 SEEK_SET) ; read from the beginning of the file.
+ (let* ((pre-bv (get-bytevector-n in start))
+ ;; The expression in string form.
+ (str (bytevector->string
+ (get-bytevector-n in (- end start))
+ (port-encoding in)))
+ (post-bv (get-bytevector-all in))
+ (str* (proc str)))
+ ;; Verify the edited expression is still a scheme expression.
+ (call-with-input-string str* read)
+ ;; Update the file with edited expression.
+ (with-atomic-file-output file
+ (lambda (out)
+ (put-bytevector out pre-bv)
+ (display str* out)
+ ;; post-bv maybe the end-of-file object.
+ (when (not (eof-object? post-bv))
+ (put-bytevector out post-bv))
+ #t))))))
+
;;;
;;; Advisory file locking.
@@ -767,7 +808,8 @@ elements after E."
(define (cache-directory)
"Return the cache directory for Guix, by default ~/.cache/guix."
(or (getenv "XDG_CONFIG_HOME")
- (and=> (getenv "HOME")
+ (and=> (or (getenv "HOME")
+ (passwd:dir (getpwuid (getuid))))
(cut string-append <> "/.cache/guix"))))
(define (readlink* file)
@@ -855,3 +897,10 @@ etc."
;; In accordance with the GCS, start line and column numbers at 1. Note
;; that unlike LINE and `port-column', COL is actually 1-indexed here...
(location file (and line (+ line 1)) col)))
+
+(define (location->source-properties loc)
+ "Return the source property association list based on the info in LOC,
+a location object."
+ `((line . ,(and=> (location-line loc) 1-))
+ (column . ,(location-column loc))
+ (filename . ,(location-file loc))))