;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2016, 2017, 2018, 2019 Ludovic Courtès ;;; Copyright © 2018 Chris Marusich ;;; ;;; This file is part of GNU Guix. ;;; ;;; GNU Guix is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version. ;;; ;;; GNU Guix is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Guix. If not, see . (define-module (gnu build marionette) #:use-module (srfi srfi-9) #:use-module (srfi srfi-26) #:use-module (rnrs io ports) #:use-module (ice-9 match) #:use-module (ice-9 popen) #:export (marionette? make-marionette
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/packages')
-rw-r--r--gnu/packages/hurd.scm3
1 files changed, 3 insertions, 0 deletions
diff --git a/gnu/packages/hurd.scm b/gnu/packages/hurd.scm
index e5ad8e4f73..8d9ba1137d 100644
--- a/gnu/packages/hurd.scm
+++ b/gnu/packages/hurd.scm
@@ -31,6 +31,7 @@
#:use-module (guix build-system trivial)
#:use-module (gnu packages autotools)
#:use-module (gnu packages flex)
+ #:use-module (gnu packages gnupg)
#:use-module (gnu packages bison)
#:use-module (gnu packages linux)
#:use-module (gnu packages perl)
@@ -440,6 +441,7 @@ fsysopts / --writable\n"))
`(("glibc-hurd-headers" ,glibc/hurd-headers)
("hurd-rc" ,(hurd-rc-script))
+ ("libgcrypt" ,libgcrypt) ;for /hurd/random
;; Tools for the /libexec/* scripts.
("bash-minimal" ,bash-minimal)
("coreutils" ,coreutils)
@@ -449,6 +451,7 @@ fsysopts / --writable\n"))
(native-inputs
`(("autoconf" ,autoconf)
("automake" ,automake)
+ ("libgcrypt" ,libgcrypt) ;for 'libgcrypt-config'
("mig" ,(if (%current-target-system)
;; XXX: When targeting i586-pc-gnu, we need a 32-bit MiG,
;; hence this hack.
else 'failure))) marionette) (('success . result) result) ('failure (error "file didn't show up" file)))) (define* (wait-for-tcp-port port marionette #:key (timeout 20)) "Wait for up to TIMEOUT seconds for PORT to accept connections in MARIONETTE. Raise an error on failure." ;; Note: The 'connect' loop has to run within the guest because, when we ;; forward ports to the host, connecting to the host never raises ;; ECONNREFUSED. (match (marionette-eval `(begin (let ((sock (socket PF_INET SOCK_STREAM 0))) (let loop ((i 0)) (catch 'system-error (lambda () (connect sock AF_INET INADDR_LOOPBACK ,port) 'success) (lambda args (if (< i ,timeout) (begin (sleep 1) (loop (+ 1 i))) 'failure)))))) marionette) ('success #t) ('failure (error "nobody's listening on port" port)))) (define* (wait-for-unix-socket file-name marionette #:key (timeout 20)) "Wait for up to TIMEOUT seconds for FILE-NAME, a Unix domain socket, to accept connections in MARIONETTE. Raise an error on failure." (match (marionette-eval `(begin (let ((sock (socket PF_UNIX SOCK_STREAM 0))) (let loop ((i 0)) (catch 'system-error (lambda () (connect sock AF_UNIX ,file-name) 'success) (lambda args (if (< i ,timeout) (begin (sleep 1) (loop (+ 1 i))) 'failure)))))) marionette) ('success #t) ('failure (error "nobody's listening on unix domain socket" file-name)))) (define (marionette-control command marionette) "Run COMMAND in the QEMU monitor of MARIONETTE. COMMAND is a string such as \"sendkey ctrl-alt-f1\" or \"screendump foo.ppm\" (info \"(qemu-doc) pcsys_monitor\")." (match marionette (($ _ _ monitor) (display command monitor) (newline monitor) ;; The "quit" command terminates QEMU immediately, with no output. (unless (string=? command "quit") (wait-for-monitor-prompt monitor))))) (define* (marionette-screen-text marionette #:key (ocrad "ocrad")) "Take a screenshot of MARIONETTE, perform optical character recognition (OCR), and return the text read from the screen as a string. Do this by invoking OCRAD (file name for GNU Ocrad's command)" (define (random-file-name) (string-append "/tmp/marionette-screenshot-" (number->string (random (expt 2 32)) 16) ".ppm")) (let ((image (random-file-name))) (dynamic-wind (const #t) (lambda () (marionette-control (string-append "screendump " image) marionette) ;; Tell Ocrad to invert the image colors (make it black on white) and ;; to scale the image up, which significantly improves the quality of ;; the result. In spite of this, be aware that OCR confuses "y" and ;; "V" and sometimes erroneously introduces white space. (let* ((pipe (open-pipe* OPEN_READ ocrad "-i" "-s" "10" image)) (text (get-string-all pipe))) (unless (zero? (close-pipe pipe)) (error "'ocrad' failed" ocrad)) text)) (lambda () (false-if-exception (delete-file image)))))) (define* (wait-for-screen-text marionette predicate #:key (timeout 30) (ocrad "ocrad")) "Wait for TIMEOUT seconds or until the screen text on MARIONETTE matches PREDICATE, whichever comes first. Raise an error when TIMEOUT is exceeded." (define start (car (gettimeofday))) (define end (+ start timeout)) (let loop () (if (> (car (gettimeofday)) end) (error "'wait-for-screen-text' timeout" predicate) (or (predicate (marionette-screen-text marionette #:ocrad ocrad)) (begin (sleep 1) (loop)))))) (define %qwerty-us-keystrokes ;; Maps "special" characters to their keystrokes. '((#\newline . "ret") (#\space . "spc") (#\- . "minus") (#\+ . "shift-equal") (#\* . "shift-8") (#\= . "equal") (#\? . "shift-slash") (#\[ . "bracket_left") (#\] . "bracket_right") (#\{ . "shift-bracket_left") (#\} . "shift-bracket_right") (#\( . "shift-9") (#\) . "shift-0") (#\/ . "slash") (#\< . "less") (#\> . "shift-less") (#\. . "dot") (#\, . "comma") (#\; . "semicolon") (#\' . "apostrophe") (#\" . "shift-apostrophe") (#\` . "grave_accent") (#\bs . "backspace") (#\tab . "tab"))) (define (character->keystroke chr keystrokes) "Return the keystroke for CHR according to the keyboard layout defined by KEYSTROKES." (if (char-set-contains? char-set:upper-case chr) (string-append "shift-" (string (char-downcase chr))) (or (assoc-ref keystrokes chr) (string chr)))) (define* (string->keystroke-commands str #:optional (keystrokes %qwerty-us-keystrokes)) "Return a list of QEMU monitor commands to send the keystrokes corresponding to STR. KEYSTROKES is an alist specifying a mapping from characters to keystrokes." (string-fold-right (lambda (chr result) (cons (string-append "sendkey " (character->keystroke chr keystrokes)) result)) '() str)) (define* (marionette-type str marionette #:key (keystrokes %qwerty-us-keystrokes)) "Type STR on MARIONETTE's keyboard, using the KEYSTROKES alist to map characters to actual keystrokes." (for-each (cut marionette-control <> marionette) (string->keystroke-commands str keystrokes))) ;;; marionette.scm ends here