From 96bb00d20336f43fac2c42662e4b1d300e624738 Mon Sep 17 00:00:00 2001 From: Mathieu Othacehe Date: Fri, 14 Oct 2022 17:28:27 +0200 Subject: installer: Run the "guix system init" command in a PTY. Fixes: * gnu/installer/utils.scm (run-external-command-with-handler/tty): New procedure. (run-external-command-with-line-hooks, run-command): Add a TTY? argument. * gnu/installer/final.scm (install-system): Call run-command with TTY? argument set to #true. --- gnu/installer/utils.scm | 50 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) (limited to 'gnu/installer/utils.scm') diff --git a/gnu/installer/utils.scm b/gnu/installer/utils.scm index 5fd2e2d425..061493e6a7 100644 --- a/gnu/installer/utils.scm +++ b/gnu/installer/utils.scm @@ -20,6 +20,7 @@ (define-module (gnu installer utils) #:use-module (gnu services herd) #:use-module (guix utils) + #:use-module ((guix build syscalls) #:select (openpty login-tty)) #:use-module (guix build utils) #:use-module (guix i18n) #:use-module (srfi srfi-1) @@ -45,6 +46,7 @@ nearest-exact-integer read-percentage run-external-command-with-handler + run-external-command-with-handler/tty run-external-command-with-line-hooks run-command run-command-in-installer @@ -124,10 +126,37 @@ the child process as returned by waitpid." (close-port input) (close-pipe dummy-pipe))) -(define (run-external-command-with-line-hooks line-hooks command) +(define (run-external-command-with-handler/tty handler command) + "Run command specified by the list COMMAND in a child operating in a +pseudoterminal with output handler HANDLER. HANDLER is a procedure taking an +input port, to which the command will write its standard output and error. +Returns the integer status value of the child process as returned by waitpid." + (define-values (controller inferior) + (openpty)) + + (match (primitive-fork) + (0 + (catch #t + (lambda () + (close-fdes controller) + (login-tty inferior) + (apply execlp (car command) command)) + (lambda _ + (primitive-exit 127)))) + (pid + (close-fdes inferior) + (let* ((port (fdopen controller "r0")) + (result (false-if-exception + (handler port)))) + (close-port port) + (cdr (waitpid pid)))))) + +(define* (run-external-command-with-line-hooks line-hooks command + #:key (tty? #false)) "Run command specified by the list COMMAND in a child, processing each -output line with the procedures in LINE-HOOKS. Returns the integer status -value of the child process as returned by waitpid." +output line with the procedures in LINE-HOOKS. If TTY is set to #true, the +COMMAND will be run in a pseudoterminal. Returns the integer status value of +the child process as returned by waitpid." (define (handler input) (and (and=> (get-line input) @@ -136,14 +165,17 @@ value of the child process as returned by waitpid." #f (begin (for-each (lambda (f) (f line)) (append line-hooks - %default-installer-line-hooks)) + %default-installer-line-hooks)) #t)))) (handler input))) - (run-external-command-with-handler handler command)) + (if tty? + (run-external-command-with-handler/tty handler command) + (run-external-command-with-handler handler command))) -(define* (run-command command) +(define* (run-command command #:key (tty? #f)) "Run COMMAND, a list of strings. Return true if COMMAND exited -successfully, #f otherwise." +successfully, #f otherwise. If TTY is set to #true, the COMMAND will be run +in a pseudoterminal." (define (pause) (format #t (G_ "Press Enter to continue.~%")) (send-to-clients '(pause)) @@ -154,8 +186,8 @@ successfully, #f otherwise." (installer-log-line "running command ~s" command) (define result (run-external-command-with-line-hooks - (list %display-line-hook) - command)) + (list %display-line-hook) command + #:tty? tty?)) (define exit-val (status:exit-val result)) (define term-sig (status:term-sig result)) (define stop-sig (status:stop-sig result)) -- cgit v1.2.3 From 591af24ade1021d91a3e7c62fcc7a8c90f00d4bb Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Fri, 9 Dec 2022 17:47:08 +0100 Subject: installer: Print progress bars and such as soon as \r is read. Fixes . Previously progress bars and related things would be buffered by 'run-external-command-with-line-hooks' until \n is read. * gnu/installer/utils.scm (run-external-command-with-line-hooks): Use 'read-delimited' rather than 'get-line'. Pass 'concat as the last argument. (%display-line-hook): Remove. (run-command): Use 'display' instead of '%display-line-hook'. (%syslog-line-hook): Add "\n" when LINE doesn't end in \n. (%installer-log-line-hook): Do not add an extra newline. (installer-log-line): Add an extra newline. --- gnu/installer/newt.scm | 2 +- gnu/installer/utils.scm | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'gnu/installer/utils.scm') diff --git a/gnu/installer/newt.scm b/gnu/installer/newt.scm index 798ff53af2..e1c4453168 100644 --- a/gnu/installer/newt.scm +++ b/gnu/installer/newt.scm @@ -116,7 +116,7 @@ report it by email to ~a.") uploaded-name %guix-bug-report-address) (define command-output "") (define (line-accumulator line) (set! command-output - (string-append/shared command-output line "\n"))) + (string-append/shared command-output line))) (define result (run-external-command-with-line-hooks (list line-accumulator) args)) (define exit-val (status:exit-val result)) diff --git a/gnu/installer/utils.scm b/gnu/installer/utils.scm index 061493e6a7..6838410166 100644 --- a/gnu/installer/utils.scm +++ b/gnu/installer/utils.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2018, 2020 Mathieu Othacehe -;;; Copyright © 2019, 2020 Ludovic Courtès +;;; Copyright © 2019, 2020, 2022 Ludovic Courtès ;;; ;;; This file is part of GNU Guix. ;;; @@ -159,7 +159,9 @@ COMMAND will be run in a pseudoterminal. Returns the integer status value of the child process as returned by waitpid." (define (handler input) (and - (and=> (get-line input) + ;; Lines for progress bars etc. end in \r; treat is as a line ending so + ;; those lines are printed right away. + (and=> (read-delimited "\r\n" input 'concat) (lambda (line) (if (eof-object? line) #f @@ -186,7 +188,7 @@ in a pseudoterminal." (installer-log-line "running command ~s" command) (define result (run-external-command-with-line-hooks - (list %display-line-hook) command + (list display) command #:tty? tty?)) (define exit-val (status:exit-val result)) (define term-sig (status:term-sig result)) @@ -264,7 +266,10 @@ values." (or port (%make-void-port "w"))))) (define (%syslog-line-hook line) - (format (syslog-port) "installer[~d]: ~a~%" (getpid) line)) + (let ((line (if (string-suffix? "\r" line) + (string-append (string-drop-right line 1) "\n") + line))) + (format (syslog-port) "installer[~d]: ~a" (getpid) line))) (define-syntax syslog (lambda (s) @@ -293,11 +298,7 @@ values." port))) (define (%installer-log-line-hook line) - (format (installer-log-port) "~a~%" line)) - -(define (%display-line-hook line) - (display line) - (newline)) + (display line (installer-log-port))) (define %default-installer-line-hooks (list %syslog-line-hook @@ -309,9 +310,10 @@ values." (syntax-case s () ((_ fmt args ...) (string? (syntax->datum #'fmt)) - #'(let ((formatted (format #f fmt args ...))) - (for-each (lambda (f) (f formatted)) - %default-installer-line-hooks)))))) + (with-syntax ((fmt (string-append (syntax->datum #'fmt) "\n"))) + #'(let ((formatted (format #f fmt args ...))) + (for-each (lambda (f) (f formatted)) + %default-installer-line-hooks))))))) ;;; -- cgit v1.2.3