| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 |
|
| 19 | (define-module (gnu installer timezone)
|
| 20 | #:use-module (gnu installer utils)
|
| 21 | #:use-module (guix i18n)
|
| 22 | #:use-module (srfi srfi-1)
|
| 23 | #:use-module (srfi srfi-26)
|
| 24 | #:use-module (srfi srfi-34)
|
| 25 | #:use-module (srfi srfi-35)
|
| 26 | #:use-module (ice-9 match)
|
| 27 | #:use-module (ice-9 receive)
|
| 28 | #:export (locate-children
|
| 29 | timezone->posix-tz
|
| 30 | timezone-has-child?
|
| 31 | zonetab->timezone-tree
|
| 32 | posix-tz->configuration))
|
| 33 |
|
| 34 | (define %not-blank
|
| 35 | (char-set-complement char-set:blank))
|
| 36 |
|
| 37 | (define (posix-tz->timezone tz)
|
| 38 | "Convert given TZ in Posix format like \"Europe/Paris\" into a list like
|
| 39 | (\"Europe\" \"Paris\")."
|
| 40 | (string-split tz #\/))
|
| 41 |
|
| 42 | (define (timezone->posix-tz timezone)
|
| 43 | "Convert given TIMEZONE like (\"Europe\" \"Paris\") into a Posix timezone
|
| 44 | like \"Europe/Paris\"."
|
| 45 | (string-join timezone "/"))
|
| 46 |
|
| 47 | (define (zonetab->timezones zonetab)
|
| 48 | "Parse ZONETAB file and return the corresponding list of timezones."
|
| 49 |
|
| 50 | (define (zonetab-line->posix-tz line)
|
| 51 | (let ((tokens (string-tokenize line %not-blank)))
|
| 52 | (match tokens
|
| 53 | ((code coordinates tz _ ...)
|
| 54 | tz))))
|
| 55 |
|
| 56 | (call-with-input-file zonetab
|
| 57 | (lambda (port)
|
| 58 | (let* ((lines (read-lines port))
|
| 59 | |
| 60 | (tz-lines (filter (lambda (line)
|
| 61 | (not (eq? (string-ref line 0)
|
| 62 | #\#)))
|
| 63 | lines)))
|
| 64 | (map (lambda (line)
|
| 65 | (posix-tz->timezone
|
| 66 | (zonetab-line->posix-tz line)))
|
| 67 | tz-lines)))))
|
| 68 |
|
| 69 | (define (timezones->timezone-tree timezones)
|
| 70 | "Convert the list of timezones, TIMEZONES into a tree under the form:
|
| 71 |
|
| 72 | (\"America\" (\"North_Dakota\" \"New_Salem\" \"Center\"))
|
| 73 |
|
| 74 | representing America/North_Dakota/New_Salem and America/North_Dakota/Center
|
| 75 | timezones."
|
| 76 |
|
| 77 | (define (remove-first lists)
|
| 78 | "Remove the first element of every sublists in the argument LISTS."
|
| 79 | (map (lambda (list)
|
| 80 | (if (null? list) list (cdr list)))
|
| 81 | lists))
|
| 82 |
|
| 83 | (let loop ((cur-timezones timezones))
|
| 84 | (match cur-timezones
|
| 85 | (() '())
|
| 86 | (((region . rest-region) . rest-timezones)
|
| 87 | (if (null? rest-region)
|
| 88 | (cons (list region) (loop rest-timezones))
|
| 89 | (receive (same-region other-region)
|
| 90 | (partition (lambda (timezone)
|
| 91 | (string=? (car timezone) region))
|
| 92 | cur-timezones)
|
| 93 | (acons region
|
| 94 | (loop (remove-first same-region))
|
| 95 | (loop other-region))))))))
|
| 96 |
|
| 97 | (define (locate-children tree path)
|
| 98 | "Return the children of the timezone indicated by PATH in the given
|
| 99 | TREE. Raise a condition if the PATH could not be found."
|
| 100 | (let ((extract-proc (cut map car <>)))
|
| 101 | (match path
|
| 102 | (() (sort (extract-proc tree) string<?))
|
| 103 | ((region . rest)
|
| 104 | (or (and=> (assoc-ref tree region)
|
| 105 | (cut locate-children <> rest))
|
| 106 | (raise
|
| 107 | (condition
|
| 108 | (&message
|
| 109 | (message
|
| 110 | (format #f (G_ "Unable to locate path: ~a.") path))))))))))
|
| 111 |
|
| 112 | (define (timezone-has-child? tree timezone)
|
| 113 | "Return #t if the given TIMEZONE any child in TREE and #f otherwise."
|
| 114 | (not (null? (locate-children tree timezone))))
|
| 115 |
|
| 116 | (define* (zonetab->timezone-tree zonetab)
|
| 117 | "Return the timezone tree corresponding to the given ZONETAB file."
|
| 118 | (timezones->timezone-tree (zonetab->timezones zonetab)))
|
| 119 |
|
| 120 |
|
| 121 | |
| 122 | |
| 123 | |
| 124 |
|
| 125 | (define (posix-tz->configuration timezone)
|
| 126 | "Return the configuration field for TIMEZONE."
|
| 127 | `((timezone ,timezone)))
|