aboutsummaryrefslogtreecommitdiff
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2018 Mathieu Othacehe <m.othacehe@gmail.com>
;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2024 Janneke Nieuwenhuizen <janneke@gnu.org>
;;; Copyright © 2024 Florian Pelz <pelzflorian@pelzflorian.de>
;;;
;;; 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 <http://www.gnu.org/licenses/>.

(define-module (gnu installer newt locale)
  #:use-module (gnu installer locale)
  #:use-module (gnu installer steps)
  #:use-module (gnu installer newt page)
  #:use-module (guix i18n)
  #:use-module (srfi srfi-1)
  #:use-module (ice-9 match)
  #:export (run-locale-page))

(define (run-language-page languages language->text)
  (define result
    (run-listbox-selection-page
     #:title (G_ "Locale language")
     #:info-text (G_ "Choose the language to use for the \
installation process and for the installed system.")
     #:info-textbox-width 70
     #:listbox-items languages
     #:listbox-item->text language->text
     #:sort-listbox-items? #f
     #:button-text (G_ "Exit")
     #:button-callback-procedure
     (lambda _
       (abort-to-prompt 'installer-step 'abort))))

  ;; Immediately install the chosen language so that the territory page that
  ;; comes after (optionally) is displayed in the chosen language.
  (setenv "LANGUAGE" result)

  result)

(define (run-territory-page territories territory->text)
  (define result
    (run-listbox-selection-page
     #:title (G_ "Locale location")
     #:info-text (G_ "Choose a territory for this language.")
     #:listbox-items territories
     #:listbox-item->text territory->text
     #:button-text (G_ "Back")
     #:button-callback-procedure
     (lambda _
       (abort-to-prompt 'installer-step 'abort))))

  ;; Some languages, such as pt, cannot be installed early in the
  ;; run-language-page step.  Install them now, when we know the territory.
  (setenv "LANGUAGE" (string-append (getenv "LANGUAGE") "_" result))

  result)

(define (run-codeset-page codesets)
  (let ((title (G_ "Locale codeset")))
    (run-listbox-selection-page
     #:title title
     #:info-text (G_ "Choose the locale encoding.")
     #:listbox-items codesets
     #:listbox-item->text identity
     #:listbox-default-item "UTF-8"
     #:button-text (G_ "Back")
     #:button-callback-procedure
     (lambda _
       (abort-to-prompt 'installer-step 'abort)))))

(define (run-modifier-page modifiers modifier->text)
  (let ((title (G_ "Locale modifier")))
    (run-listbox-selection-page
     #:title title
     #:info-text (G_ "Choose your locale's modifier. The most frequent \
modifier is euro. It indicates that you want to use Euro as the currency \
symbol.")
     #:listbox-items modifiers
     #:listbox-item->text modifier->text
     #:button-text (G_ "Back")
     #:button-callback-procedure
     (lambda _
       (abort-to-prompt 'installer-step 'abort)))))

(define* (run-locale-page #:key
                          supported-locales
                          iso639-languages
                          iso3166-territories
                          dry-run?)
  "Run a page asking the user to select a locale language and possibly
territory, codeset and modifier. Use SUPPORTED-LOCALES as the list of glibc
available locales. ISO639-LANGUAGES is an association list associating a
locale code to a locale name. ISO3166-TERRITORIES is an association list
associating a territory code with a territory name. The formatted locale, under
glibc format is returned."

  (define (break-on-locale-found locales)
    "Break to the installer step if LOCALES contains exactly one
element."
    (and (= (length locales) 1)
         (abort-to-prompt 'installer-step 'break)))

  (define (filter-locales locales result)
    "Filter the list of locale records LOCALES using the RESULT returned by
the installer-steps defined below."
    (filter
     (lambda (locale)
       (and-map identity
                `(,(string=? (locale-language locale)
                             (result-step result 'language))
                  ,@(if (result-step-done? result 'territory)
                        (list (equal? (locale-territory locale)
                                      (result-step result 'territory)))
                        '())
                  ,@(if (result-step-done? result 'codeset)
                        (list (equal? (locale-codeset locale)
                                      (result-step result 'codeset)))
                        '())
                  ,@(if (result-step-done? result 'modifier)
                        (list (equal? (locale-modifier locale)
                                      (result-step result 'modifier)))
                        '()))))
     locales))

  (define (result->locale-string locales result)
    "Supposing that LOCALES contains exactly one locale record, turn it into a
glibc locale string and return it."
    (match (filter-locales locales result)
      ((locale)
       (locale->locale-string locale))))

  (define (sort-languages languages)
    "Extract some languages from LANGUAGES list and place them ahead."
    (let* ((first-languages '("en"))
           (other-languages (lset-difference equal?
                                             languages
                                             first-languages)))
      `(,@first-languages ,@other-languages)))

  (define locale-steps
    (list
     (installer-step
      (id 'language)
      (compute
       (lambda _
         (run-language-page
          (sort-languages
           (delete-duplicates (map locale-language supported-locales)))
          (lambda (language)
            (let ((english (language-code->language-name iso639-languages
                                                         language)))
              (setenv "LANGUAGE" language)
              (let ((native (gettext english "iso_639-3")))
                (unsetenv "LANGUAGE")
                native)))))))
     (installer-step
      (id 'territory)
      (compute
       (lambda (result _)
         (let ((locales (filter-locales supported-locales result)))
           ;; Stop the process if the language returned by the previous step
           ;; is matching one and only one supported locale.
           (break-on-locale-found locales)

           ;; Otherwise, ask the user to select a territory among those
           ;; supported by the previously selected language.
           (run-territory-page
            (delete-duplicates (map locale-territory locales))
            (lambda (territory)
              (if territory
                  (let ((english (territory-code->territory-name
                                  iso3166-territories territory)))
                    (gettext english "iso_3166-1"))
                  (G_ "No location"))))))))
     (installer-step
      (id 'codeset)
      (compute
       (lambda (result _)
         (let ((locales (filter-locales supported-locales result)))
           ;; Same as above but we now have a language and a territory to
           ;; narrow down the search of a locale.
           (break-on-locale-found locales)

           ;; Otherwise, choose a codeset.
           (let ((codesets (delete-duplicates (map locale-codeset locales))))
             (if (member "UTF-8" codesets)
                 "UTF-8"                          ;don't even ask
                 (run-codeset-page codesets)))))))
     (installer-step
      (id 'modifier)
      (compute
       (lambda (result _)
         (let ((locales (filter-locales supported-locales result)))
           ;; Same thing with a language, a territory and a codeset this time.
           (break-on-locale-found locales)

           ;; Otherwise, ask for a modifier.
           (run-modifier-page
            (delete-duplicates (map locale-modifier locales))
            (lambda (modifier)
              (or modifier (G_ "No modifier"))))))))))

  ;; If run-installer-steps returns locally, it means that the user had to go
  ;; through all steps (language, territory, codeset and modifier) to select a
  ;; locale. In that case, like if we exited by breaking to the installer
  ;; step, turn the result into a glibc locale string and return it.
  (result->locale-string
   supported-locales
   (run-installer-steps #:steps locale-steps #:dry-run? dry-run?)))
ld. (commit-short-id, verify-introductory-commit) (authenticate-channel): New procedures. (latest-channel-instance): Call 'authenticate-channel' when CHANNEL has an introduction. * tests/channels.scm (gpg+git-available?, commit-id-string): New procedures. ("authenticate-channel, wrong first commit signer"): ("authenticate-channel, .guix-authorizations"): New tests. * doc/guix.texi (Invoking guix pull): Mention authentication. Ludovic Courtès 2020-06-10database: separate transaction-handling and retry-handling....Previously call-with-transaction would both retry when SQLITE_BUSY errors were thrown and do what its name suggested (start and rollback/commit a transaction). This changes it to do only what its name implies, which simplifies its implementation. Retrying is provided by the new call-with-SQLITE_BUSY-retrying procedure. * guix/store/database.scm (call-with-transaction): no longer restarts, new #:restartable? argument controls whether "begin" or "begin immediate" is used. (call-with-SQLITE_BUSY-retrying, call-with-retrying-transaction, call-with-retrying-savepoint): new procedures. (register-items): use call-with-retrying-transaction to preserve old behavior. * .dir-locals.el (call-with-retrying-transaction, call-with-retrying-savepoint): add indentation information. Caleb Ristvedt 2020-06-10database: ensure update-or-insert is run within a transaction...update-or-insert can break if an insert occurs between when it decides whether to update or insert and when it actually performs that operation. Putting the check and the update/insert operation in the same transaction ensures that the update/insert will only succeed if no other write has occurred in the middle. * guix/store/database.scm (call-with-savepoint): new procedure. (update-or-insert): use call-with-savepoint to ensure the read and the insert/update occur within the same transaction. Caleb Ristvedt 2020-06-10database: rewrite query procedures in terms of with-statement....Most of our queries would fail to finalize their statements properly if sqlite returned an error during their execution. This resolves that, and also makes them somewhat more concise as a side-effect. This also makes some small changes to improve certain queries where behavior was strange or overly verbose. * guix/store/database.scm (call-with-statement): new procedure. (with-statement): new macro. (last-insert-row-id, path-id, update-or-insert, add-references): rewrite to use with-statement. (update-or-insert): factor last-insert-row-id out of the end of both branches. (add-references): remove pointless last-insert-row-id call. * .dir-locals.el (with-statement): add indenting information. Caleb Ristvedt 2020-06-06ui: 'display-search-results' automatically invokes the pager....* guix/ui.scm (call-with-paginated-output-port): New procedure. (with-paginated-output-port): New macro. (display-search-results): Use it instead of displaying a hint. Ludovic Courtès 2020-06-05git-authenticate: Add tests....* guix/tests/git.scm (call-with-environment-variables) (with-environment-variables): Remove. * guix/tests/git.scm (populate-git-repository): Add clauses for signed commits and signed merges. * guix/tests/gnupg.scm: New file. * tests/git-authenticate.scm: New file. * tests/ed25519bis.key, tests/ed25519bis.sec: New files. * Makefile.am (dist_noinst_DATA): Add 'guix/tests/gnupg.scm'. (SCM_TESTS): Add 'tests/git-authenticate.scm'. (EXTRA_DIST): Add tests/ed25519bis.{key,sec}. Ludovic Courtès 2020-05-16gexp: Add 'let-system'....* guix/gexp.scm (<system-binding>): New record type. (let-system): New macro. (system-binding-compiler): New procedure. (default-expander): Add 'self-quoting?' case. (self-quoting?): New procedure. (lower-inputs): Add 'filterm'. Pass the result of 'mapm/accumulate-builds' through FILTERM. (gexp->sexp)[self-quoting?]: Remove. * tests/gexp.scm ("let-system", "let-system, target") ("let-system, ungexp-native, target") ("let-system, nested"): New tests. * doc/guix.texi (G-Expressions): Document it. Ludovic Courtès 2020-03-22store: Add 'with-build-handler'....* guix/store.scm (current-build-prompt): New variable. (call-with-build-handler, invoke-build-handler): New procedures. (with-build-handler): New macro. * tests/store.scm ("with-build-handler"): New test. Ludovic Courtès 2020-03-12gexp: Add 'with-parameters'....* guix/gexp.scm (<parameterized>): New record type. (with-parameters): New macro. (compile-parameterized): New gexp compiler. * tests/gexp.scm ("with-parameters for %current-system") ("with-parameters for %current-target-system") ("with-parameters + file-append"): New tests. * doc/guix.texi (G-Expressions): Document it. Ludovic Courtès 2019-11-29ui: Factorize 'with-profile-lock'....* guix/ui.scm (profile-lock-handler, profile-lock-file): New procedures. (with-profile-lock): New macro. * guix/scripts/package.scm (process-actions): Use 'with-profile-lock' instead of 'with-file-lock/no-wait'. * guix/scripts/pull.scm (guix-pull): Likewise. Ludovic Courtès 2019-11-19pull: Acquire a lock for the target profile....This is a followup to b1fb663404894268b5ee92c040f12c52c0bee425. * guix/scripts/pull.scm (guix-pull): Wrap 'run-with-store' call in 'with-file-lock/no-wait'. Ludovic Courtès 2019-09-23git: Add 'commit-difference'....* guix/git.scm (commit-closure, commit-difference): New procedures. * guix/tests/git.scm, tests/git.scm: New files. * Makefile.am (dist_noinst_DATA): Add guix/tests/git.scm. (SCM_TESTS): Add tests/git.scm. Ludovic Courtès 2019-06-05syscalls: Add 'with-file-lock' macro....* guix/scripts/offload.scm (lock-file, unlock-file, with-file-lock): Move to... * guix/build/syscalls.scm: ... here. Ludovic Courtès 2019-05-27publish: Add support for lzip....* guix/scripts/publish.scm (show-help, %options): Support '-C METHOD' and '-C METHOD:LEVEL'. (default-compression): New procedure. (bake-narinfo+nar): Add lzip. (nar-response-port): Likewise. (string->compression-type): New procedure. (make-request-handler): Generalize /nar/gzip handler to handle /nar/lzip as well. * tests/publish.scm ("/nar/lzip/*"): New test. ("/*.narinfo with lzip compression"): New test. * doc/guix.texi (Invoking guix publish): Document it. (Requirements): Mention lzlib. Ludovic Courtès 2019-03-07database: Make 'register-items' transactional....* guix/store/database.scm (SQLITE_BUSY, register-output-sql): New variables. (add-references): Don't try finalizing after each use, only after all the uses (otherwise a finalized statement would be used if #:cache? was #f). (call-with-transaction): New procedure. (register-items): Use call-with-transaction to prevent broken intermediate states from being visible. * .dir-locals.el (call-with-transaction): indent it. Signed-off-by: Ludovic Courtès <ludo@gnu.org> Caleb Ristvedt 2019-01-11status: Add 'with-status-verbosity'....* guix/status.scm (logger-for-level, call-with-status-verbosity): New procedures. (with-status-verbosity): New macro. * guix/scripts/environment.scm (guix-environment): Use 'with-status-verbosity' instead of 'with-status-report'. * guix/scripts/pack.scm (guix-pack): Likewise. * guix/scripts/package.scm (guix-package): Likewise. * guix/scripts/pull.scm (guix-pull): Likewise. * guix/scripts/system.scm (guix-system): Likewise. * build-aux/run-system-tests.scm (run-system-tests): Likewise. Ludovic Courtès 2018-10-19tests: Run 'guix pack' tests using the external store....Fixes <https://bugs.gnu.org/32184>. * guix/tests.scm (call-with-external-store): New procedure. (with-external-store): New macro. * tests/pack.scm (%store): Remove. (test-assertm): Add 'store' parameter. ("self-contained-tarball"): Wrap in 'with-external-store'. * tests/guix-pack.sh: Connect to the external store, if possible, by setting NIX_STORE_DIR and GUIX_DAEMON_SOCKET. Remove most uses of '--bootstrap'. Ludovic Courtès 2018-09-27Add (guix status) and use it for pretty colored output....* guix/progress.scm (progress-reporter/trace): New procedure. (%progress-interval): New variable. (progress-reporter/file): Use it. * guix/scripts/build.scm (set-build-options-from-command-line): Pass #:print-extended-build-trace?. (%default-options): Add 'print-extended-build-trace?'. (guix-build): Parameterize CURRENT-TERMINAL-COLUMNS. Use 'build-status-updater'. * guix/scripts/environment.scm (%default-options): Add 'print-extended-build-trace?'. (guix-environment): Wrap body in 'with-status-report'. * guix/scripts/pack.scm (%default-options): Add 'print-build-trace?' and 'print-extended-build-trace?'. (guix-pack): Wrap body in 'with-status-report'. * guix/scripts/package.scm (%default-options, guix-package): Likewise. * guix/scripts/system.scm (%default-options, guix-system): Likewise. * guix/scripts/pull.scm (%default-options, guix-pull): Likewise. * guix/scripts/substitute.scm (progress-report-port): Don't call STOP when TOTAL is zero. (process-substitution): Add #:print-build-trace? and honor it. (guix-substitute)[print-build-trace?]: New variable. Pass #:print-build-trace? to 'process-substitution'. * guix/status.scm: New file. * guix/store.scm (set-build-options): Add #:print-extended-build-trace?; pass it into PAIRS. (%protocol-version): Bump. (protocol-version, nix-server-version): New procedures. (current-store-protocol-version): New variable. (with-store, build-things): Parameterize it. * guix/ui.scm (build-output-port): Remove. (colorize-string): Export. * po/guix/POTFILES.in: Add guix/status.scm. * tests/status.scm: New file. * Makefile.am (SCM_TESTS): Add it. * nix/libstore/worker-protocol.hh (PROTOCOL_VERSION): Bump to 0x162. * nix/libstore/build.cc (DerivationGoal::registerOutputs) (SubstitutionGoal::finished): Print a "@ hash-mismatch" trace before throwing. Ludovic Courtès