aboutsummaryrefslogtreecommitdiff
-*- mode: org; coding: utf-8; -*-

#+TITLE: What's left to do?
#+STARTUP: content hidestars

Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org>
Copyright © 2019 Mathieu Othacehe <m.othacehe@gmail.com>

  Copying and distribution of this file, with or without modification,
  are permitted in any medium without royalty provided the copyright
  notice and this notice are preserved.

* MAYBE Add a substituter that uses the GNUnet DHT or [[http://libswift.org][libswift]]

Would be neat if binaries could be pushed to and pulled from the GNUnet DHT or
rather libswift (since DHTs aren’t suited for large payloads).  Guix users
would sign their binaries, and define which binaries they trust.

Use UPnP and similar to traverse NAT, like ‘filegive’ does.

* user interface
** add guile-ncurses interface

* extend <package>
** add ‘recommends’ field

For instance, glibc, binutils, gcc, and ld-wrapper would recommend each other.
‘guix package -i’ could ask interactively (?), or allow users to follow all or
none of the recommendations.

** add a ‘user-environment-hook’

This should specify builder code to be run when building a user
environment with ‘guix-package’.  For instance, Texinfo’s hook would
create a new ‘dir’.

** extend ‘propagated-build-inputs’ with support for multiple outputs

#+BEGIN_SRC scheme
  (outputs '("out" "include"))
  (propagated-build-inputs
    `(((("i1" ,p1 "o1")
        ("i2" ,p2))
       => "include")
      ("i3" ,p3)))
#+END_SRC

* synchronize non-GNU package descriptions with the [[http://directory.fsf.org][FSD]]

Meta-data for GNU packages, including descriptions and synopses, can be
dumped from the FSD:
http://directory.fsf.org/wiki?title=GNU/Export&action=purge .
We could periodically synchronize with that.

* add a guildhall build system

The Guildhall is Guile’s packaging system.  It should be easy to add a
‘guildhall-build-system’ that does the right thing based on guildhall
recipes.

* union

Support sophisticated collision handling when building a union: honor
per-package priorities, etc.

* add GUIX_ALLOW_EXPENSIVE_TESTS

Tests that need to download stuff or otherwise take a long time would only be
run when that is defined.

* guix build utils
** MAYBE Change ‘ld-wrapper’ to add RPATH for libs passed by file name

** MAYBE Add equivalent to chrpath that uses [[https://gitorious.org/guile-dlhacks/guile-dlhacks/][guile-dlhacks]]

** MAYBE Add a hash-rewriting thing for deep dependency replacement without rebuild

See [[https://github.com/NixOS/nixpkgs/commit/d1662d715514e6ef9d3dc29f132f1b3d8e608a18][Shea Levy's `replace-dependency' in Nixpkgs]].

* distro
** port to GNU/Hurd, aka. ‘i686-gnu’

Problems include that current glibc releases do not build on GNU/Hurd.
In addition, there haven’t been stable releases of GNU Mach, MiG, and
Hurd, which would be a pre-condition.

* Installer
** Fix impossibility to restart on error after cow-store has been started
See https://lists.gnu.org/archive/html/guix-devel/2018-12/msg00161.html.
- Force reboot upon installer failure
- Unshare the installer process
- Run the installer process in a separate namespace
** Partitioning
*** Add RAID support
*** Add more partitioning schemes
The actual schemes are taken from Debian Installer but some are not
implemented yet: like "Separate partitions for /home /var and /tmp".
*** Replace wait page "Partition formating is in progress, please wait"
Create a new waiting page describing what's being done:

[              20%              ]
Running mkfs.ext4 on /dev/sda2 ...

[              40%              ]
Running mkfs.ext4 on /dev/sda3 ...
*** Add a confirmation page before formating/partitioning
** Desktop environments
*** Allow for no desktop environments
Propose to choose between "headless server" and "lightweight X11" in a new
page.
*** Add services selection feature
Add a services page to the configuration. Ask for services to be installed
like SSH, bluetooth, TLP in a checkbox list?
** Locale and keymap
*** Try to guess user locale and keymap by probing BIOS or HW (dmidecode)
** Timezone
*** Regroup everything in one single page
Under the form:
(UTC + 1) Europe/Paris
(UTC + 2) Africa/Cairo
...
** Display issue
*** Investigate display issue described here:
https://lists.gnu.org/archive/html/guix-devel/2019-01/msg00305.html
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. 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 ;; 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 (begin (for-each (lambda (f) (f line)) (append line-hooks %default-installer-line-hooks)) #t)))) (handler input))) (if tty? (run-external-command-with-handler/tty handler command) (run-external-command-with-handler handler command))) (define* (run-command command #:key (tty? #f)) "Run COMMAND, a list of strings. Return true if COMMAND exited 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)) (match (select (cons (current-input-port) (current-clients)) '() '()) (((port _ ...) _ _) (read-line port)))) (installer-log-line "running command ~s" command) (define result (run-external-command-with-line-hooks (list display) command #:tty? tty?)) (define exit-val (status:exit-val result)) (define term-sig (status:term-sig result)) (define stop-sig (status:stop-sig result)) (define succeeded? (cond ((and exit-val (not (zero? exit-val))) (installer-log-line "command ~s exited with value ~a" command exit-val) (format #t (G_ "Command ~s exited with value ~a") command exit-val) #f) (term-sig (installer-log-line "command ~s killed by signal ~a" command term-sig) (format #t (G_ "Command ~s killed by signal ~a") command term-sig) #f) (stop-sig (installer-log-line "command ~s stopped by signal ~a" command stop-sig) (format #t (G_ "Command ~s stopped by signal ~a") command stop-sig) #f) (else (installer-log-line "command ~s succeeded" command) (format #t (G_ "Command ~s succeeded") command) #t))) (newline) (pause) succeeded?) (define (dry-run-command . args) (format #t "dry-run-command: skipping: ~a\n" args)) (define %run-command-in-installer (make-parameter (lambda (. args) (raise (condition (&serious) (&message (message "%run-command-in-installer not set"))))))) ;;; ;;; Logging. ;;; (define (call-with-time thunk kont) "Call THUNK and pass KONT the elapsed time followed by THUNK's return values." (let* ((start (current-time time-monotonic)) (result (call-with-values thunk list)) (end (current-time time-monotonic))) (apply kont (time-difference end start) result))) (define-syntax-rule (let/time ((time result exp)) body ...) (call-with-time (lambda () exp) (lambda (time result) body ...))) (define (open-syslog-port) "Return an open port (a socket) to /dev/log or #f if that wasn't possible." (let ((sock (socket AF_UNIX SOCK_DGRAM 0))) (catch 'system-error (lambda () (connect sock AF_UNIX "/dev/log") (setvbuf sock 'line) sock) (lambda args (close-port sock) #f)))) (define syslog-port (let ((port #f)) (lambda () "Return an output port to syslog." (unless port (set! port (open-syslog-port))) (or port (%make-void-port "w"))))) (define (%syslog-line-hook 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) "Like 'format', but write to syslog." (syntax-case s () ((_ fmt args ...) (string? (syntax->datum #'fmt)) (with-syntax ((fmt (string-append "installer[~d]: " (syntax->datum #'fmt)))) #'(format (syslog-port) fmt (getpid) args ...)))))) (define (open-new-log-port) (define now (localtime (time-second (current-time)))) (define file-name (format #f "/tmp/installer.~a.log" (strftime "%F.%T" now))) (open file-name (logior O_RDWR O_CREAT))) (define installer-log-port (let ((port #f)) (lambda () "Return an input and output port to the installer log." (unless port (set! port (open-new-log-port))) port))) (define (%installer-log-line-hook line) (display line (installer-log-port))) (define %default-installer-line-hooks (list %syslog-line-hook %installer-log-line-hook)) (define-syntax installer-log-line (lambda (s) "Like 'format', but uses the default line hooks, and only formats one line." (syntax-case s () ((_ fmt args ...) (string? (syntax->datum #'fmt)) (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))))))) ;;; ;;; Client protocol. ;;; (define %client-socket-file ;; Unix-domain socket where the installer accepts connections. "/var/guix/installer-socket") (define current-server-socket ;; Socket on which the installer is currently accepting connections, or #f. (make-parameter #f)) (define current-clients ;; List of currently connected clients. (make-parameter '())) (define* (open-server-socket #:optional (socket-file %client-socket-file)) "Open SOCKET-FILE as a Unix-domain socket to accept incoming connections and return it." (mkdir-p (dirname socket-file)) (when (file-exists? socket-file) (delete-file socket-file)) (let ((sock (socket AF_UNIX SOCK_STREAM 0))) (bind sock AF_UNIX socket-file) (listen sock 0) sock)) (define (call-with-server-socket thunk) (if (current-server-socket) (thunk) (let ((socket (open-server-socket))) (dynamic-wind (const #t) (lambda () (parameterize ((current-server-socket socket)) (thunk))) (lambda () (close-port socket)))))) (define-syntax-rule (with-server-socket exp ...) "Evaluate EXP with 'current-server-socket' parameterized to a currently accepting socket." (call-with-server-socket (lambda () exp ...))) (define* (send-to-clients exp) "Send EXP to all the current clients." (define remainder (fold (lambda (client remainder) (catch 'system-error (lambda () (write exp client) (newline client) (force-output client) (cons client remainder)) (lambda args ;; We might get EPIPE if the client disconnects; when that ;; happens, remove CLIENT from the set of available clients. (let ((errno (system-error-errno args))) (if (memv errno (list EPIPE ECONNRESET ECONNABORTED)) (begin (installer-log-line "removing client ~s due to ~s while replying" (fileno client) (strerror errno)) (false-if-exception (close-port client)) remainder) (cons client remainder)))))) '() (current-clients))) (current-clients (reverse remainder)) exp) (define-syntax-rule (with-silent-shepherd exp ...) "Evaluate EXP while discarding shepherd messages." (parameterize ((shepherd-message-port (%make-void-port "w"))) exp ...))