aboutsummaryrefslogtreecommitdiff
path: root/README
blob: b9f36f8344f59c591bb7c8abe2aeee2e296543fa (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
-*- mode: org -*-

[[https://www.gnu.org/software/guix/][GNU Guix]] (IPA: /ɡiːks/) is a purely functional package manager, and
associated free software distribution, for the [[https://www.gnu.org/gnu/gnu.html][GNU system]].  In addition
to standard package management features, Guix supports transactional
upgrades and roll-backs, unprivileged package management, per-user
profiles, and garbage collection.

It provides [[https://www.gnu.org/software/guile/][Guile]] Scheme APIs, including a high-level embedded
domain-specific languages (EDSLs) to describe how packages are to be
built and composed.

GNU Guix can be used on top of an already-installed GNU/Linux distribution, or
it can be used standalone (we call that “Guix System”).

Guix is based on the [[https://nixos.org/nix/][Nix]] package manager.


* Requirements

If you are building Guix from source, please see the manual for build
instructions and requirements, either by running:

  info -f doc/guix.info "Requirements"

or by checking the [[https://guix.gnu.org/manual/en/html_node/Requirements.html][web copy of the manual]].

* Installation

See the manual for the installation instructions, either by running

  info -f doc/guix.info "Installation"

or by checking the [[https://guix.gnu.org/manual/en/html_node/Installation.html][web copy of the manual]].

* Building from Git

For information on building Guix from a Git checkout, please see the relevant
section in the manual, either by running

  info -f doc/guix.info "Building from Git"

or by checking the [[https://guix.gnu.org/manual/en/html_node/Building-from-Git.html][web_copy of the manual]].

* How It Works

Guix does the high-level preparation of a /derivation/.  A derivation is
the promise of a build; it is stored as a text file under
=/gnu/store/xxx.drv=.  The (guix derivations) module provides the
`derivation' primitive, as well as higher-level wrappers such as
`build-expression->derivation'.

Guix does remote procedure calls (RPCs) to the build daemon (the =guix-daemon=
command), which in turn performs builds and accesses to the store on its
behalf.  The RPCs are implemented in the (guix store) module.

* Contact

GNU Guix is hosted at https://savannah.gnu.org/projects/guix/.

Please email <help-guix@gnu.org> for questions and <bug-guix@gnu.org> for bug
reports; email <gnu-system-discuss@gnu.org> for general issues regarding the
GNU system.

Join #guix on irc.libera.chat.

* Guix & Nix

GNU Guix is based on [[https://nixos.org/nix/][the Nix package manager]].  It implements the same
package deployment paradigm, and in fact it reuses some of its code.
Yet, different engineering decisions were made for Guix, as described
below.

Nix is really two things: a package build tool, implemented by a library
and daemon, and a special-purpose programming language.  GNU Guix relies
on the former, but uses Scheme as a replacement for the latter.

Using Scheme instead of a specific language allows us to get all the
features and tooling that come with Guile (compiler, debugger, REPL,
Unicode, libraries, etc.)  And it means that we have a general-purpose
language, on top of which we can have embedded domain-specific languages
(EDSLs), such as the one used to define packages.  This broadens what
can be done in package recipes themselves, and what can be done around them.

Technically, Guix makes remote procedure calls to the ‘nix-worker’
daemon to perform operations on the store.  At the lowest level, Nix
“derivations” represent promises of a build, stored in ‘.drv’ files in
the store.  Guix produces such derivations, which are then interpreted
by the daemon to perform the build.  Thus, Guix derivations can use
derivations produced by Nix (and vice versa).

With Nix and the [[https://nixos.org/nixpkgs][Nixpkgs]] distribution, package composition happens at
the Nix language level, but builders are usually written in Bash.
Conversely, Guix encourages the use of Scheme for both package
composition and builders.  Likewise, the core functionality of Nix is
written in C++ and Perl; Guix relies on some of the original C++ code,
but exposes all the API as Scheme.

* Related software

  - [[https://nixos.org][Nix, Nixpkgs, and NixOS]], functional package manager and associated
    software distribution, are the inspiration of Guix
  - [[https://www.gnu.org/software/stow/][GNU Stow]] builds around the idea of one directory per prefix, and a
    symlink tree to create user environments
  - [[https://www.pvv.ntnu.no/~arnej/store/storedoc_6.html][STORE]] shares the same idea
  - [[https://live.gnome.org/OSTree/][GNOME's OSTree]] allows bootable system images to be built from a
    specified set of packages
  - The [[https://www.gnu.org/s/gsrc/][GNU Source Release Collection]] (GSRC) is a user-land software
    distribution; unlike Guix, it relies on core tools available on the
    host system
d='n256' href='#n256'>256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019 Christopher Baines <mail@cbaines.net>
;;;
;;; 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 services getmail)
  #:use-module (gnu services)
  #:use-module (gnu services base)
  #:use-module (gnu services configuration)
  #:use-module (gnu services shepherd)
  #:use-module (gnu system pam)
  #:use-module (gnu system shadow)
  #:use-module (gnu packages mail)
  #:use-module (gnu packages admin)
  #:use-module (gnu packages tls)
  #:use-module (guix records)
  #:use-module (guix store)
  #:use-module (guix packages)
  #:use-module (guix gexp)
  #:use-module (ice-9 match)
  #:use-module (ice-9 format)
  #:use-module (srfi srfi-1)
  #:export (getmail-retriever-configuration
            getmail-retriever-configuration-extra-parameters
            getmail-destination-configuration
            getmail-options-configuration
            getmail-configuration-file
            getmail-configuration
            getmail-service-type))

;;; Commentary:
;;;
;;; Service for the getmail mail retriever.
;;;
;;; Code:

(define (uglify-field-name field-name)
  (let ((str (symbol->string field-name)))
    (string-join (string-split (if (string-suffix? "?" str)
                                   (substring str 0 (1- (string-length str)))
                                   str)
                               #\-)
                 "_")))

(define (serialize-field field-name val)
  #~(let ((val '#$val))
      (format #f "~a = ~a\n"
              #$(uglify-field-name field-name)
              (cond
               ((list? val)
                (string-append
                 "("
                 (string-concatenate
                  (map (lambda (list-val)
                         (format #f "\"~a\", " list-val))
                       val))
                 ")"))
               (else
                val)))))

(define (serialize-string field-name val)
  (if (string=? val "")
      ""
      (serialize-field field-name val)))

(define (string-or-filelike? val)
  (or (string? val)
      (file-like? val)))
(define (serialize-string-or-filelike field-name val)
  (if (equal? val "")
      ""
      (serialize-field field-name val)))

(define (serialize-boolean field-name val)
  (serialize-field field-name (if val "true" "false")))

(define (non-negative-integer? val)
  (and (exact-integer? val) (not (negative? val))))
(define (serialize-non-negative-integer field-name val)
  (serialize-field field-name val))

(define serialize-list serialize-field)

(define parameter-alist? list?)
(define (serialize-parameter-alist field-name val)
  #~(string-append
     #$@(map (match-lambda
               ((key . value)
                (serialize-field key value)))
             val)))

(define (serialize-getmail-retriever-configuration field-name val)
  (serialize-configuration val getmail-retriever-configuration-fields))

(define-configuration getmail-retriever-configuration
  (type
   (string "SimpleIMAPSSLRetriever")
   "The type of mail retriever to use.  Valid values include
@samp{passwd} and @samp{static}.")
  (server
   (string 'unset)
   "Name or IP address of the server to retrieve mail from.")
  (username
   (string 'unset)
   "Username to login to the mail server with.")
  (port
   (non-negative-integer #f)
   "Port number to connect to.")
  (password
   (string "")
   "Override fields from passwd.")
  (password-command
   (list '())
   "Override fields from passwd.")
  (keyfile
   (string "")
   "PEM-formatted key file to use for the TLS negotiation.")
  (certfile
   (string "")
   "PEM-formatted certificate file to use for the TLS negotiation.")
  (ca-certs
   (string "")
   "CA certificates to use.")
  (extra-parameters
   (parameter-alist '())
   "Extra retriever parameters."))

(define (serialize-getmail-destination-configuration field-name val)
  (serialize-configuration val getmail-destination-configuration-fields))

(define-configuration getmail-destination-configuration
  (type
   (string 'unset)
   "The type of mail destination.  Valid values include @samp{Maildir},
@samp{Mboxrd} and @samp{MDA_external}.")
  (path
   (string-or-filelike "")
   "The path option for the mail destination.  The behaviour depends on the
chosen type.")
  (extra-parameters
   (parameter-alist '())
   "Extra destination parameters"))

(define (serialize-getmail-options-configuration field-name val)
  (serialize-configuration val getmail-options-configuration-fields))

(define-configuration getmail-options-configuration
  (verbose
   (non-negative-integer 1)
   "If set to @samp{0}, getmail will only print warnings and errors.  A value
of @samp{1} means that messages will be printed about retrieving and deleting
messages. If set to @samp{2}, getmail will print messages about each of it's
actions.")
  (read-all
   (boolean #t)
   "If true, getmail will retrieve all available messages.  Otherwise it will
only retrieve messages it hasn't seen previously.")
  (delete
   (boolean #f)
   "If set to true, messages will be deleted from the server after retrieving
and successfully delivering them.  Otherwise, messages will be left on the
server.")
  (delete-after
   (non-negative-integer 0)
   "Getmail will delete messages this number of days after seeing them, if
they have been delivered.  This means messages will be left on the server this
number of days after delivering them.  A value of @samp{0} disabled this
feature.")
  (delete-bigger-than
   (non-negative-integer 0)
   "Delete messages larger than this of bytes after retrieving them, even if
the delete and delete-after options are disabled.  A value of @samp{0}
disables this feature.")
  (max-bytes-per-session
   (non-negative-integer 0)
   "Retrieve messages totalling up to this number of bytes before closing the
session with the server.  A value of @samp{0} disables this feature.")
  (max-message-size
   (non-negative-integer 0)
   "Don't retrieve messages larger than this number of bytes.  A value of
@samp{0} disables this feature.")
  (delivered-to
   (boolean #t)
   "If true, getmail will add a Delivered-To header to messages.")
  (received
   (boolean #t)
   "If set, getmail adds a Received header to the messages.")
  (message-log
   (string "")
   "Getmail will record a log of its actions to the named file.  A value of
@samp{\"\"} disables this feature.")
  (message-log-syslog
   (boolean #f)
   "If true, getmail will record a log of its actions using the system
logger.")
  (message-log-verbose
   (boolean #f)
   "If true, getmail will log information about messages not retrieved and the
reason for not retrieving them, as well as starting and ending information
lines.")
  (extra-parameters
   (parameter-alist '())
   "Extra options to include."))

(define (serialize-getmail-configuration-file field-name val)
  (match val
    (($ <getmail-configuration-file> location
                                     retriever destination options)
     #~(string-append
        "[retriever]\n"
        #$(serialize-getmail-retriever-configuration #f retriever)
        "\n[destination]\n"
        #$(serialize-getmail-destination-configuration #f destination)
        "\n[options]\n"
        #$(serialize-getmail-options-configuration #f options)))))

(define-configuration getmail-configuration-file
  (retriever
   (getmail-retriever-configuration (getmail-retriever-configuration))
   "What mail account to retrieve mail from, and how to access that account.")
  (destination
   (getmail-destination-configuration (getmail-destination-configuration))
   "What to do with retrieved messages.")
  (options
   (getmail-options-configuration (getmail-options-configuration))
   "Configure getmail."))

(define (serialize-symbol field-name val) "")
(define (serialize-getmail-configuration field-name val) "")

(define-configuration getmail-configuration
  (name
   (symbol "unset")
   "A symbol to identify the getmail service.")
  (package
   (file-like getmail)
   "The getmail package to use.")
  (user
   (string "getmail")
   "The user to run getmail as.")
  (group
   (string "getmail")
   "The group to run getmail as.")
  (directory
   (string "/var/lib/getmail/default")
   "The getmail directory to use.")
  (rcfile
   (getmail-configuration-file (getmail-configuration-file))
   "The getmail configuration file to use.")
  (idle
   (list '())
   "A list of mailboxes that getmail should wait on the server for new mail
notifications.  This depends on the server supporting the IDLE extension.")
  (environment-variables
   (list '())
   "Environment variables to set for getmail."))

(define (generate-getmail-documentation)
  (generate-documentation
   `((getmail-configuration
      ,getmail-configuration-fields
      (rcfile getmail-configuration-file))
     (getmail-configuration-file
      ,getmail-configuration-file-fields
      (retriever getmail-retriever-configuration)
      (destination getmail-destination-configuration)
      (options getmail-options-configuration))
     (getmail-retriever-configuration ,getmail-retriever-configuration-fields)
     (getmail-destination-configuration ,getmail-destination-configuration-fields)
     (getmail-options-configuration ,getmail-options-configuration-fields))
   'getmail-configuration))

(define-gexp-compiler (getmail-configuration-file-compiler
                       (rcfile <getmail-configuration-file>) system target)
  (gexp->derivation
   "getmailrc"
   #~(call-with-output-file #$output
       (lambda (port)
         (display #$(serialize-getmail-configuration-file #f rcfile)
                  port)))
   #:system system
   #:target target))

(define (getmail-accounts configs)
  (let ((users (delete-duplicates
                (map getmail-configuration-user
                     configs)))
        (groups (delete-duplicates
                 (map getmail-configuration-group
                      configs))))
    (append
     (map (lambda (group)
            (user-group
             (name group)
             (system? #t)))
          groups)
     (map (lambda (user)
            (user-account
             (name user)
             (group (getmail-configuration-group
                     (find (lambda (config)
                             (and
                              (string=? user (getmail-configuration-user config))
                              (getmail-configuration-group config)))
                           configs)))
             (system? #t)
             (comment "Getmail user")
             (home-directory "/var/empty")
             (shell (file-append shadow "/sbin/nologin"))))
          users))))

(define (getmail-activation configs)
  "Return the activation GEXP for CONFIGS."
  (with-imported-modules '((guix build utils))
    #~(begin
        (use-modules (guix build utils))
        #$@(map
            (lambda (config)
              #~(let* ((pw (getpw #$(getmail-configuration-user config)))
                       (uid (passwd:uid pw))
                       (gid (passwd:gid pw))
                       (getmaildir #$(getmail-configuration-directory config)))
                  (mkdir-p getmaildir)
                  (chown getmaildir uid gid)))
            configs))))

(define (getmail-shepherd-services configs)
  "Return a list of <shepherd-service> for CONFIGS."
  (map (match-lambda
         (($ <getmail-configuration> location name package
                                     user group directory rcfile idle
                                     environment-variables)
          (shepherd-service
           (documentation "Run getmail.")
           (provision (list (symbol-append 'getmail- name)))
           (requirement '(networking))
           (start #~(make-forkexec-constructor
                     `(#$(file-append package "/bin/getmail")
                       ,(string-append "--getmaildir=" #$directory)
                       #$@(map (lambda (idle)
                                 (string-append "--idle=" idle))
                               idle)
                       ,(string-append "--rcfile=" #$rcfile))
                     #:user #$user
                     #:group #$group
                     #:environment-variables
                     (list #$@environment-variables)
                     #:log-file
                     #$(string-append "/var/log/getmail-"
                                      (symbol->string name))))
           (stop #~(make-kill-destructor)))))
       configs))

(define getmail-service-type
  (service-type
   (name 'getmail)
   (extensions
    (list (service-extension shepherd-root-service-type
                             getmail-shepherd-services)
          (service-extension activation-service-type
                             getmail-activation)
          (service-extension account-service-type
                             getmail-accounts)))
   (description
    "Run @command{getmail}, a mail retriever program.")
   (default-value '())
   (compose concatenate)
   (extend append)))