summaryrefslogtreecommitdiff
path: root/gnu/installer/utils.scm
diff options
context:
space:
mode:
authorMathieu Othacehe <othacehe@gnu.org>2020-06-08 15:14:49 +0200
committerMathieu Othacehe <othacehe@gnu.org>2020-06-09 10:32:19 +0200
commitf73ed5579157a074093bae7a2ffb59a85412be0d (patch)
tree4da9852eb057f0508fdb056591e53c4fc8f3ad03 /gnu/installer/utils.scm
parent8423c2d3097da2d9d25b6f56c1971ac7147d3ad9 (diff)
installer: utils: Dump command output to syslog when testing.
When debugging the installation tests, it can be very handy to be able to read "run-command" output, for instance when executing "guix system init". Introduce a new "invoke-with-log" procedure that is able to log a command standard and error outputs to the syslog. Use it, only when running the installation tests, to dump "run-command" output. * gnu/installer/utils.scm (open-pipe-with-stderr, invoke-with-log): New procedures, (invoke-log-port): new variable, (run-command): move to the end of the file and use invoke-with-log when running the installation tests.
Diffstat (limited to 'gnu/installer/utils.scm')
-rw-r--r--gnu/installer/utils.scm164
1 files changed, 120 insertions, 44 deletions
diff --git a/gnu/installer/utils.scm b/gnu/installer/utils.scm
index 5f8fe8ca019..d73698df156 100644
--- a/gnu/installer/utils.scm
+++ b/gnu/installer/utils.scm
@@ -22,8 +22,13 @@
22 #:use-module (guix build utils) 22 #:use-module (guix build utils)
23 #:use-module (guix i18n) 23 #:use-module (guix i18n)
24 #:use-module (srfi srfi-1) 24 #:use-module (srfi srfi-1)
25 #:use-module (srfi srfi-11)
26 #:use-module (srfi srfi-26)
25 #:use-module (srfi srfi-34) 27 #:use-module (srfi srfi-34)
28 #:use-module (srfi srfi-34)
29 #:use-module (srfi srfi-35)
26 #:use-module (ice-9 match) 30 #:use-module (ice-9 match)
31 #:use-module (ice-9 popen)
27 #:use-module (ice-9 rdelim) 32 #:use-module (ice-9 rdelim)
28 #:use-module (ice-9 regex) 33 #:use-module (ice-9 regex)
29 #:use-module (ice-9 format) 34 #:use-module (ice-9 format)
@@ -68,50 +73,6 @@ number. If no percentage is found, return #f"
68 (and result 73 (and result
69 (string->number (match:substring result 1))))) 74 (string->number (match:substring result 1)))))
70 75
71(define* (run-command command #:key locale)
72 "Run COMMAND, a list of strings, in the given LOCALE. Return true if
73COMMAND exited successfully, #f otherwise."
74 (define env (environ))
75
76 (define (pause)
77 (format #t (G_ "Press Enter to continue.~%"))
78 (send-to-clients '(pause))
79 (environ env) ;restore environment variables
80 (match (select (cons (current-input-port) (current-clients))
81 '() '())
82 (((port _ ...) _ _)
83 (read-line port))))
84
85 (setenv "PATH" "/run/current-system/profile/bin")
86
87 (when locale
88 (let ((supported? (false-if-exception
89 (setlocale LC_ALL locale))))
90 ;; If LOCALE is not supported, then set LANGUAGE, which might at
91 ;; least give us translated messages.
92 (if supported?
93 (setenv "LC_ALL" locale)
94 (setenv "LANGUAGE"
95 (string-take locale
96 (or (string-index locale #\_)
97 (string-length locale)))))))
98
99 (guard (c ((invoke-error? c)
100 (newline)
101 (format (current-error-port)
102 (G_ "Command failed with exit code ~a.~%")
103 (invoke-error-exit-status c))
104 (syslog "command ~s failed with exit code ~a"
105 command (invoke-error-exit-status c))
106 (pause)
107 #f))
108 (syslog "running command ~s~%" command)
109 (apply invoke command)
110 (syslog "command ~s succeeded~%" command)
111 (newline)
112 (pause)
113 #t))
114
115 76
116;;; 77;;;
117;;; Logging. 78;;; Logging.
@@ -219,3 +180,118 @@ accepting socket."
219 180
220 (current-clients (reverse remainder)) 181 (current-clients (reverse remainder))
221 exp) 182 exp)
183
184
185;;;
186;;; Run commands.
187;;;
188
189;; XXX: This is taken from (guix build utils) and could be factorized.
190(define (open-pipe-with-stderr program . args)
191 "Run PROGRAM with ARGS in an input pipe, but, unlike 'open-pipe*', redirect
192both its standard output and standard error to the pipe. Return two value:
193the pipe to read PROGRAM's data from, and the PID of the child process running
194PROGRAM."
195 ;; 'open-pipe*' doesn't attempt to capture stderr in any way, which is why
196 ;; we need to roll our own.
197 (match (pipe)
198 ((input . output)
199 (match (primitive-fork)
200 (0
201 (dynamic-wind
202 (const #t)
203 (lambda ()
204 (close-port input)
205 (close-port (syslog-port))
206 (dup2 (fileno output) 1)
207 (dup2 (fileno output) 2)
208 (apply execlp program program args))
209 (lambda ()
210 (primitive-exit 127))))
211 (pid
212 (close-port output)
213 (values input pid))))))
214
215(define invoke-log-port
216 ;; Port used by INVOKE-WITH-LOG for logging.
217 (make-parameter #f))
218
219(define* (invoke-with-log program . args)
220 "Invoke PROGRAM with ARGS and log PROGRAM's standard output and standard
221error to INVOKE-LOG-PORT. If PROGRAM succeeds, print nothing and return the
222unspecified value; otherwise, raise a '&message' error condition with the
223status code. This procedure is very similar to INVOKE/QUIET with the
224noticeable difference that the program output, that can be quite heavy, is not
225stored but directly sent to INVOKE-LOG-PORT if defined."
226 (let-values (((pipe pid)
227 (apply open-pipe-with-stderr program args)))
228 (let loop ()
229 (match (read-line pipe)
230 ((? eof-object?)
231 (close-port pipe)
232 (match (waitpid pid)
233 ((_ . status)
234 (unless (zero? status)
235 (raise
236 (condition (&invoke-error
237 (program program)
238 (arguments args)
239 (exit-status (status:exit-val status))
240 (term-signal (status:term-sig status))
241 (stop-signal (status:stop-sig status)))))))))
242 (line
243 (and=> (invoke-log-port) (cut format <> "~a~%" line))
244 (loop))))))
245
246(define* (run-command command #:key locale)
247 "Run COMMAND, a list of strings, in the given LOCALE. Return true if
248COMMAND exited successfully, #f otherwise."
249 (define env (environ))
250
251 (define (pause)
252 (format #t (G_ "Press Enter to continue.~%"))
253 (send-to-clients '(pause))
254 (environ env) ;restore environment variables
255 (match (select (cons (current-input-port) (current-clients))
256 '() '())
257 (((port _ ...) _ _)
258 (read-line port))))
259
260 (setenv "PATH" "/run/current-system/profile/bin")
261
262 (when locale
263 (let ((supported? (false-if-exception
264 (setlocale LC_ALL locale))))
265 ;; If LOCALE is not supported, then set LANGUAGE, which might at
266 ;; least give us translated messages.
267 (if supported?
268 (setenv "LC_ALL" locale)
269 (setenv "LANGUAGE"
270 (string-take locale
271 (or (string-index locale #\_)
272 (string-length locale)))))))
273
274 (guard (c ((invoke-error? c)
275 (newline)
276 (format (current-error-port)
277 (G_ "Command failed with exit code ~a.~%")
278 (invoke-error-exit-status c))
279 (syslog "command ~s failed with exit code ~a"
280 command (invoke-error-exit-status c))
281 (pause)
282 #f))
283 (syslog "running command ~s~%" command)
284 ;; If there are any connected clients, assume that we are running
285 ;; installation tests. In that case, dump the standard and error outputs
286 ;; to syslog.
287 (let ((testing? (not (null? (current-clients)))))
288 (if testing?
289 (parameterize ((invoke-log-port (syslog-port)))
290 (apply invoke-with-log command))
291 (apply invoke command)))
292 (syslog "command ~s succeeded~%" command)
293 (newline)
294 (pause)
295 #t))
296
297;;; utils.scm ends here