system: grub: Add preliminary support for themes.
[guix.git] / gnu / system / grub.scm
blob67375b45cf6cd94e0c6db1bce700286182108e5e
1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2013, 2014 Ludovic Courtès <ludo@gnu.org>
3 ;;;
4 ;;; This file is part of GNU Guix.
5 ;;;
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
10 ;;;
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ;;; GNU General Public License for more details.
15 ;;;
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
19 (define-module (gnu system grub)
20   #:use-module (guix store)
21   #:use-module (guix packages)
22   #:use-module (guix derivations)
23   #:use-module (guix records)
24   #:use-module (guix monads)
25   #:use-module (guix gexp)
26   #:use-module (guix download)
27   #:use-module (guix git-download)
28   #:autoload   (gnu packages grub) (grub)
29   #:autoload   (gnu packages inkscape) (inkscape)
30   #:autoload   (gnu packages imagemagick) (imagemagick)
31   #:autoload   (gnu packages compression) (gzip)
32   #:use-module (ice-9 match)
33   #:use-module (srfi srfi-1)
34   #:export (grub-image
35             grub-image?
36             grub-image-aspect-ratio
37             grub-image-file
39             grub-theme
40             grub-theme?
41             grub-theme-images
42             grub-theme-color-normal
43             grub-theme-color-highlight
45             %background-image
46             %default-theme
48             grub-configuration
49             grub-configuration?
50             grub-configuration-device
52             menu-entry
53             menu-entry?
55             grub-configuration-file))
57 ;;; Commentary:
58 ;;;
59 ;;; Configuration of GNU GRUB.
60 ;;;
61 ;;; Code:
63 (define-record-type* <grub-image>
64   grub-image make-grub-image
65   grub-image?
66   (aspect-ratio    grub-image-aspect-ratio        ;rational number
67                    (default 4/3))
68   (file            grub-image-file))              ;file-valued gexp (SVG)
70 (define-record-type* <grub-theme>
71   grub-theme make-grub-theme
72   grub-theme?
73   (images          grub-theme-images
74                    (default '()))                 ;list of <grub-image>
75   (color-normal    grub-theme-color-normal
76                    (default '((fg . cyan) (bg . blue))))
77   (color-highlight grub-theme-color-highlight
78                    (default '((fg . white) (bg . blue)))))
80 (define %artwork-repository
81   (origin
82     (method git-fetch)
83     (uri (git-reference
84           (url "git://git.savannah.gnu.org/guix/guix-artwork.git")
85           (commit "281157a")))
86     (sha256
87      (base32
88       "02x1myh013mzqnr28d4k1mxs4malv5vszpxdwkjarbhbbkchypz5"))))
90 (define %background-image
91   (grub-image
92    (aspect-ratio 4/3)
93    (file #~(string-append #$%artwork-repository "/grub/guix-4-3.svg"))))
95 (define %default-theme
96   ;; Default theme contributed by Felipe López.
97   (grub-theme
98    (images (list %background-image))
99    (color-highlight '((fg . white) (bg . black))) ;XXX: fg should be #x3bb7f5
100    (color-normal    '((fg . light-gray) (bg . black))))) ;XXX: #x303030
102 (define-record-type* <grub-configuration>
103   grub-configuration make-grub-configuration
104   grub-configuration?
105   (grub            grub-configuration-grub           ; package
106                    (default (@ (gnu packages grub) grub)))
107   (device          grub-configuration-device)        ; string
108   (menu-entries    grub-configuration-menu-entries   ; list
109                    (default '()))
110   (default-entry   grub-configuration-default-entry  ; integer
111                    (default 0))
112   (timeout         grub-configuration-timeout        ; integer
113                    (default 5))
114   (theme           grub-configuration-theme          ; <grub-theme>
115                    (default %default-theme)))
117 (define-record-type* <menu-entry>
118   menu-entry make-menu-entry
119   menu-entry?
120   (label           menu-entry-label)
121   (linux           menu-entry-linux)
122   (linux-arguments menu-entry-linux-arguments
123                    (default '()))          ; list of string-valued gexps
124   (initrd          menu-entry-initrd))     ; file name of the initrd as a gexp
128 ;;; Background image & themes.
131 (define (svg->png svg)
132   "Build a PNG from SVG."
133   ;; Don't use #:local-build? so that it's substitutable.
134   (gexp->derivation "grub-image.png"
135                     #~(zero?
136                        (system* (string-append #$inkscape "/bin/inkscape")
137                                 "--without-gui"
138                                 (string-append "--export-png=" #$output)
139                                 #$svg))))
141 (define (resize-image image width height)
142   "Resize IMAGE to WIDTHxHEIGHT."
143   ;; Don't use #:local-build? so that it's substitutable.
144   (let ((size (string-append (number->string width)
145                              "x" (number->string height))))
146     (gexp->derivation "grub-image.resized.png"
147                       #~(zero?
148                          (system* (string-append #$imagemagick "/bin/convert")
149                                   "-resize" #$size #$image #$output)))))
151 (define* (grub-background-image config #:key (width 640) (height 480))
152   "Return the GRUB background image defined in CONFIG with a ratio of
153 WIDTH/HEIGHT, or #f if none was found."
154   (let* ((ratio (/ width height))
155          (image (find (lambda (image)
156                         (= (grub-image-aspect-ratio image) ratio))
157                       (grub-theme-images (grub-configuration-theme config)))))
158     (if image
159         (mlet %store-monad ((png (svg->png (grub-image-file image))))
160           (resize-image png width height))
161         (with-monad %store-monad
162           (return #f)))))
164 (define (eye-candy config port)
165   "Return in %STORE-MONAD a gexp that writes to PORT (a port-valued gexp) the
166 'grub.cfg' part concerned with graphics mode, background images, colors, and
167 all that."
168   (define (theme-colors type)
169     (let* ((theme  (grub-configuration-theme config))
170            (colors (type theme)))
171       (string-append (symbol->string (assoc-ref colors 'fg)) "/"
172                      (symbol->string (assoc-ref colors 'bg)))))
174   (mlet* %store-monad ((image (grub-background-image config)))
175     (return (and image #~(format #$port "
176 function load_video {
177   insmod vbe
178   insmod vga
179   insmod video_bochs
180   insmod video_cirrus
183 if loadfont ~a/share/grub/unicode.pf2; then
184   set gfxmode=640x480
185   load_video
186   insmod gfxterm
187   terminal_output gfxterm
190 insmod png
191 if background_image ~a; then
192   set color_normal=~a
193   set color_highlight=~a
194 else
195   set menu_color_normal=cyan/blue
196   set menu_color_highlight=white/blue
197 fi~%"
198                         #$grub
199                         #$image
200                         #$(theme-colors grub-theme-color-normal)
201                         #$(theme-colors grub-theme-color-highlight))))))
205 ;;; Configuration file.
208 (define* (grub-configuration-file config entries
209                                   #:key
210                                   (system (%current-system))
211                                   (old-entries '()))
212   "Return the GRUB configuration file corresponding to CONFIG, a
213 <grub-configuration> object.  OLD-ENTRIES is taken to be a list of menu
214 entries corresponding to old generations of the system."
215   (define all-entries
216     (append entries (grub-configuration-menu-entries config)))
218   (define entry->gexp
219     (match-lambda
220      (($ <menu-entry> label linux arguments initrd)
221       #~(format port "menuentry ~s {
222   linux ~a/bzImage ~a
223   initrd ~a
224 }~%"
225                 #$label
226                 #$linux (string-join (list #$@arguments))
227                 #$initrd))))
229   (mlet %store-monad ((sugar (eye-candy config #~port)))
230     (define builder
231       #~(call-with-output-file #$output
232           (lambda (port)
233             #$sugar
234             (format port "
235 set default=~a
236 set timeout=~a
237 search.file ~a/bzImage~%"
238                     #$(grub-configuration-default-entry config)
239                     #$(grub-configuration-timeout config)
240                     #$(any (match-lambda
241                             (($ <menu-entry> _ linux)
242                              linux))
243                            all-entries))
244             #$@(map entry->gexp all-entries)
246             #$@(if (pair? old-entries)
247                    #~((format port "
248 submenu \"GNU system, old configurations...\" {~%")
249                       #$@(map entry->gexp old-entries)
250                       (format port "}~%"))
251                    #~()))))
253     (gexp->derivation "grub.cfg" builder)))
255 ;;; grub.scm ends here