utils: Add fold-port-matches' and remove-store-references'.
				
					
				
			* guix/build/utils.scm (fold-port-matches, remove-store-references): New
  procedures.
* tests/build-utils.scm ("fold-port-matches", "fold-port-matches,
  trickier", "fold-port-matches, with unmatched chars"): New tests.
			
			
This commit is contained in:
		
							parent
							
								
									dcd7290654
								
							
						
					
					
						commit
						91133c2d71
					
				
					 2 changed files with 120 additions and 1 deletions
				
			
		|  | @ -36,7 +36,9 @@ | ||||||
|             substitute |             substitute | ||||||
|             substitute* |             substitute* | ||||||
|             dump-port |             dump-port | ||||||
|             patch-shebang)) |             patch-shebang | ||||||
|  |             fold-port-matches | ||||||
|  |             remove-store-references)) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
| ;;; | ;;; | ||||||
|  | @ -336,6 +338,89 @@ patched, #f otherwise." | ||||||
|                                             file (basename cmd)) |                                             file (basename cmd)) | ||||||
|                                     #f))))))))))))) |                                     #f))))))))))))) | ||||||
| 
 | 
 | ||||||
|  | (define* (fold-port-matches proc init pattern port | ||||||
|  |                             #:optional (unmatched (lambda (_ r) r))) | ||||||
|  |   "Read from PORT character-by-character; for each match against | ||||||
|  | PATTERN, call (PROC MATCH RESULT), where RESULT is seeded with INIT. | ||||||
|  | PATTERN is a list of SRFI-14 char-sets.  Call (UNMATCHED CHAR RESULT) | ||||||
|  | for each unmatched character." | ||||||
|  |   (define initial-pattern | ||||||
|  |     ;; The poor developer's regexp. | ||||||
|  |     (if (string? pattern) | ||||||
|  |         (map char-set (string->list pattern)) | ||||||
|  |         pattern)) | ||||||
|  | 
 | ||||||
|  |   ;; Note: we're not really striving for performance here... | ||||||
|  |   (let loop ((chars   '()) | ||||||
|  |              (pattern initial-pattern) | ||||||
|  |              (matched '()) | ||||||
|  |              (result  init)) | ||||||
|  |     (cond ((null? chars) | ||||||
|  |            (loop (list (get-char port)) | ||||||
|  |                  pattern | ||||||
|  |                  matched | ||||||
|  |                  result)) | ||||||
|  |           ((null? pattern) | ||||||
|  |            (loop chars | ||||||
|  |                  initial-pattern | ||||||
|  |                  '() | ||||||
|  |                  (proc (list->string (reverse matched)) result))) | ||||||
|  |           ((eof-object? (car chars)) | ||||||
|  |            (fold-right unmatched result matched)) | ||||||
|  |           ((char-set-contains? (car pattern) (car chars)) | ||||||
|  |            (loop (cdr chars) | ||||||
|  |                  (cdr pattern) | ||||||
|  |                  (cons (car chars) matched) | ||||||
|  |                  result)) | ||||||
|  |           ((null? matched)                        ; common case | ||||||
|  |            (loop (cdr chars) | ||||||
|  |                  pattern | ||||||
|  |                  matched | ||||||
|  |                  (unmatched (car chars) result))) | ||||||
|  |           (else | ||||||
|  |            (let ((matched (reverse matched))) | ||||||
|  |              (loop (append (cdr matched) chars) | ||||||
|  |                    initial-pattern | ||||||
|  |                    '() | ||||||
|  |                    (unmatched (car matched) result))))))) | ||||||
|  | 
 | ||||||
|  | (define* (remove-store-references file | ||||||
|  |                                   #:optional (store (or (getenv "NIX_STORE") | ||||||
|  |                                                         "/nix/store"))) | ||||||
|  |   "Remove from FILE occurrences of file names in STORE; return #t when | ||||||
|  | store paths were encountered in FILE, #f otherwise.  This procedure is | ||||||
|  | known as `nuke-refs' in Nixpkgs." | ||||||
|  |   (define pattern | ||||||
|  |     (let ((nix-base32-chars | ||||||
|  |            '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9 | ||||||
|  |              #\a #\b #\c #\d #\f #\g #\h #\i #\j #\k #\l #\m #\n | ||||||
|  |              #\p #\q #\r #\s #\v #\w #\x #\y #\z))) | ||||||
|  |       `(,@(map char-set (string->list store)) | ||||||
|  |         ,(char-set #\/) | ||||||
|  |         ,@(make-list 32 (list->char-set nix-base32-chars)) | ||||||
|  |         ,(char-set #\-)))) | ||||||
|  | 
 | ||||||
|  |   (with-fluids ((%default-port-encoding #f)) | ||||||
|  |     (with-atomic-file-replacement file | ||||||
|  |       (lambda (in out) | ||||||
|  |         ;; We cannot use `regexp-exec' here because it cannot deal with | ||||||
|  |         ;; strings containing NUL characters. | ||||||
|  |         (format #t "removing store references from `~a'...~%" file) | ||||||
|  |         (setvbuf in _IOFBF 65536) | ||||||
|  |         (setvbuf out _IOFBF 65536) | ||||||
|  |         (fold-port-matches (lambda (match result) | ||||||
|  |                              (put-string out store) | ||||||
|  |                              (put-char out #\/) | ||||||
|  |                              (put-string out | ||||||
|  |                               "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-") | ||||||
|  |                              #t) | ||||||
|  |                            #f | ||||||
|  |                            pattern | ||||||
|  |                            in | ||||||
|  |                            (lambda (char result) | ||||||
|  |                              (put-char out char) | ||||||
|  |                              result)))))) | ||||||
|  | 
 | ||||||
| ;;; 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) | ||||||
| ;;; eval: (put 'with-throw-handler 'scheme-indent-function 1) | ;;; eval: (put 'with-throw-handler 'scheme-indent-function 1) | ||||||
|  |  | ||||||
|  | @ -47,6 +47,39 @@ | ||||||
|   (not (false-if-exception |   (not (false-if-exception | ||||||
|         (alist-replace 'z 77 '((a . 1) (b . 2) (c . 3)))))) |         (alist-replace 'z 77 '((a . 1) (b . 2) (c . 3)))))) | ||||||
| 
 | 
 | ||||||
|  | (test-equal "fold-port-matches" | ||||||
|  |   (make-list 3 "Guix") | ||||||
|  |   (call-with-input-string "Guix is cool, Guix rocks, and it uses Guile, Guix!" | ||||||
|  |     (lambda (port) | ||||||
|  |       (fold-port-matches cons '() "Guix" port)))) | ||||||
|  | 
 | ||||||
|  | (test-equal "fold-port-matches, trickier" | ||||||
|  |   (reverse '("Guix" "guix" "Guix" "guiX" "Guix")) | ||||||
|  |   (call-with-input-string "Guix, guix, GuiGuixguiX, Guix" | ||||||
|  |     (lambda (port) | ||||||
|  |       (fold-port-matches cons '() | ||||||
|  |                          (list (char-set #\G #\g) | ||||||
|  |                                (char-set #\u) | ||||||
|  |                                (char-set #\i) | ||||||
|  |                                (char-set #\x #\X)) | ||||||
|  |                          port)))) | ||||||
|  | 
 | ||||||
|  | (test-equal "fold-port-matches, with unmatched chars" | ||||||
|  |   '("Guix" #\, #\space | ||||||
|  |     "guix" #\, #\space | ||||||
|  |     #\G #\u #\i "Guix" "guiX" #\, #\space | ||||||
|  |     "Guix") | ||||||
|  |   (call-with-input-string "Guix, guix, GuiGuixguiX, Guix" | ||||||
|  |     (lambda (port) | ||||||
|  |       (reverse | ||||||
|  |        (fold-port-matches cons '() | ||||||
|  |                           (list (char-set #\G #\g) | ||||||
|  |                                 (char-set #\u) | ||||||
|  |                                 (char-set #\i) | ||||||
|  |                                 (char-set #\x #\X)) | ||||||
|  |                           port | ||||||
|  |                           cons))))) | ||||||
|  | 
 | ||||||
| (test-end) | (test-end) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -55,4 +88,5 @@ | ||||||
| ;;; Local Variables: | ;;; Local Variables: | ||||||
| ;;; eval: (put 'test-assert 'scheme-indent-function 1) | ;;; eval: (put 'test-assert 'scheme-indent-function 1) | ||||||
| ;;; eval: (put 'test-equal 'scheme-indent-function 1) | ;;; eval: (put 'test-equal 'scheme-indent-function 1) | ||||||
|  | ;;; eval: (put 'call-with-input-string 'scheme-indent-function 1) | ||||||
| ;;; End: | ;;; End: | ||||||
|  |  | ||||||
		Reference in a new issue