diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2019-01-11 17:23:39 +0100 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2019-01-15 20:24:09 +0100 |
| commit | 5fbdc9a5aa63fd51c65d30fe3d30608d01fe1bc8 (patch) | |
| tree | ab2940f0c7250e8267609e3db9f6e4b517bd0546 /gnu/packages.scm | |
| parent | 1d90e9d7c906b1e9e94d1642bfd60c51609fd0df (diff) | |
channels: Compute a package cache and use it.
* gnu/packages.scm (cache-is-authoritative?, load-package-cache)
(cache-lookup, generate-package-cache): New procedures.
(%package-cache-file): New variable.
(find-packages-by-name): Rename to...
(find-packages-by-name/direct): ... this.
(find-packages-by-name): Rewrite to use the package cache when
'cache-is-authoritative?' returns true.
* tests/packages.scm ("find-packages-by-name + version, with cache")
("find-packages-by-name with cache"): New tests.
* guix/channels.scm (package-cache-file): New procedure.
(%channel-profile-hooks): New variable.
(channel-instances->derivation): Use it in #:hooks.
* guix/scripts/package.scm (build-and-use-profile): Add #:hooks and
honor it.
* guix/scripts/pull.scm (build-and-install): Pass #:hooks to
UPDATE-PROFILE.
Diffstat (limited to 'gnu/packages.scm')
| -rw-r--r-- | gnu/packages.scm | 127 |
1 files changed, 124 insertions, 3 deletions
diff --git a/gnu/packages.scm b/gnu/packages.scm index 4a85cf4b877..6796db80a47 100644 --- a/gnu/packages.scm +++ b/gnu/packages.scm | |||
| @@ -28,11 +28,14 @@ | |||
| 28 | #:use-module (guix memoization) | 28 | #:use-module (guix memoization) |
| 29 | #:use-module ((guix build utils) | 29 | #:use-module ((guix build utils) |
| 30 | #:select ((package-name->name+version | 30 | #:select ((package-name->name+version |
| 31 | . hyphen-separated-name->name+version))) | 31 | . hyphen-separated-name->name+version) |
| 32 | mkdir-p)) | ||
| 32 | #:autoload (guix profiles) (packages->manifest) | 33 | #:autoload (guix profiles) (packages->manifest) |
| 33 | #:use-module (guix describe) | 34 | #:use-module (guix describe) |
| 34 | #:use-module (ice-9 vlist) | 35 | #:use-module (ice-9 vlist) |
| 35 | #:use-module (ice-9 match) | 36 | #:use-module (ice-9 match) |
| 37 | #:autoload (ice-9 binary-ports) (put-bytevector) | ||
| 38 | #:autoload (system base compile) (compile) | ||
| 36 | #:use-module (srfi srfi-1) | 39 | #:use-module (srfi srfi-1) |
| 37 | #:use-module (srfi srfi-11) | 40 | #:use-module (srfi srfi-11) |
| 38 | #:use-module (srfi srfi-26) | 41 | #:use-module (srfi srfi-26) |
| @@ -56,7 +59,9 @@ | |||
| 56 | 59 | ||
| 57 | specification->package | 60 | specification->package |
| 58 | specification->package+output | 61 | specification->package+output |
| 59 | specifications->manifest)) | 62 | specifications->manifest |
| 63 | |||
| 64 | generate-package-cache)) | ||
| 60 | 65 | ||
| 61 | ;;; Commentary: | 66 | ;;; Commentary: |
| 62 | ;;; | 67 | ;;; |
| @@ -135,6 +140,14 @@ for system '~a'") | |||
| 135 | ;; Default search path for package modules. | 140 | ;; Default search path for package modules. |
| 136 | `((,%distro-root-directory . "gnu/packages"))) | 141 | `((,%distro-root-directory . "gnu/packages"))) |
| 137 | 142 | ||
| 143 | (define (cache-is-authoritative?) | ||
| 144 | "Return true if the pre-computed package cache is authoritative. It is not | ||
| 145 | authoritative when entries have been added via GUIX_PACKAGE_PATH or '-L' | ||
| 146 | flags." | ||
| 147 | (equal? (%package-module-path) | ||
| 148 | (append %default-package-module-path | ||
| 149 | (package-path-entries)))) | ||
| 150 | |||
| 138 | (define %package-module-path | 151 | (define %package-module-path |
| 139 | ;; Search path for package modules. Each item must be either a directory | 152 | ;; Search path for package modules. Each item must be either a directory |
| 140 | ;; name or a pair whose car is a directory and whose cdr is a sub-directory | 153 | ;; name or a pair whose car is a directory and whose cdr is a sub-directory |
| @@ -183,7 +196,35 @@ is guaranteed to never traverse the same package twice." | |||
| 183 | init | 196 | init |
| 184 | modules)) | 197 | modules)) |
| 185 | 198 | ||
| 186 | (define find-packages-by-name | 199 | (define %package-cache-file |
| 200 | ;; Location of the package cache. | ||
| 201 | "/lib/guix/package.cache") | ||
| 202 | |||
| 203 | (define load-package-cache | ||
| 204 | (mlambda (profile) | ||
| 205 | "Attempt to load the package cache. On success return a vhash keyed by | ||
| 206 | package names. Return #f on failure." | ||
| 207 | (match profile | ||
| 208 | (#f #f) | ||
| 209 | (profile | ||
| 210 | (catch 'system-error | ||
| 211 | (lambda () | ||
| 212 | (define lst | ||
| 213 | (load-compiled (string-append profile %package-cache-file))) | ||
| 214 | (fold (lambda (item vhash) | ||
| 215 | (match item | ||
| 216 | (#(name version module symbol outputs | ||
| 217 | supported? deprecated? | ||
| 218 | file line column) | ||
| 219 | (vhash-cons name item vhash)))) | ||
| 220 | vlist-null | ||
| 221 | lst)) | ||
| 222 | (lambda args | ||
| 223 | (if (= ENOENT (system-error-errno args)) | ||
| 224 | #f | ||
| 225 | (apply throw args)))))))) | ||
| 226 | |||
| 227 | (define find-packages-by-name/direct ;bypass the cache | ||
| 187 | (let ((packages (delay | 228 | (let ((packages (delay |
| 188 | (fold-packages (lambda (p r) | 229 | (fold-packages (lambda (p r) |
| 189 | (vhash-cons (package-name p) p r)) | 230 | (vhash-cons (package-name p) p r)) |
| @@ -202,6 +243,37 @@ decreasing version order." | |||
| 202 | matching) | 243 | matching) |
| 203 | matching))))) | 244 | matching))))) |
| 204 | 245 | ||
| 246 | (define (cache-lookup cache name) | ||
| 247 | "Lookup package NAME in CACHE. Return a list sorted in increasing version | ||
| 248 | order." | ||
| 249 | (define (package-version<? v1 v2) | ||
| 250 | (version>? (vector-ref v2 1) (vector-ref v1 1))) | ||
| 251 | |||
| 252 | (sort (vhash-fold* cons '() name cache) | ||
| 253 | package-version<?)) | ||
| 254 | |||
| 255 | (define* (find-packages-by-name name #:optional version) | ||
| 256 | "Return the list of packages with the given NAME. If VERSION is not #f, | ||
| 257 | then only return packages whose version is prefixed by VERSION, sorted in | ||
| 258 | decreasing version order." | ||
| 259 | (define cache | ||
| 260 | (load-package-cache (current-profile))) | ||
| 261 | |||
| 262 | (if (and (cache-is-authoritative?) cache) | ||
| 263 | (match (cache-lookup cache name) | ||
| 264 | (#f #f) | ||
| 265 | ((#(_ versions modules symbols _ _ _ _ _ _) ...) | ||
| 266 | (fold (lambda (version* module symbol result) | ||
| 267 | (if (or (not version) | ||
| 268 | (version-prefix? version version*)) | ||
| 269 | (cons (module-ref (resolve-interface module) | ||
| 270 | symbol) | ||
| 271 | result) | ||
| 272 | result)) | ||
| 273 | '() | ||
| 274 | versions modules symbols))) | ||
| 275 | (find-packages-by-name/direct name version))) | ||
| 276 | |||
| 205 | (define (find-best-packages-by-name name version) | 277 | (define (find-best-packages-by-name name version) |
| 206 | "If version is #f, return the list of packages named NAME with the highest | 278 | "If version is #f, return the list of packages named NAME with the highest |
| 207 | version numbers; otherwise, return the list of packages named NAME and at | 279 | version numbers; otherwise, return the list of packages named NAME and at |
| @@ -218,6 +290,55 @@ VERSION." | |||
| 218 | (string=? (package-version p) highest)) | 290 | (string=? (package-version p) highest)) |
| 219 | matches)))))) | 291 | matches)))))) |
| 220 | 292 | ||
| 293 | (define (generate-package-cache directory) | ||
| 294 | "Generate under DIRECTORY a cache of all the available packages. | ||
| 295 | |||
| 296 | The primary purpose of the cache is to speed up package lookup by name such | ||
| 297 | that we don't have to traverse and load all the package modules, thereby also | ||
| 298 | reducing the memory footprint." | ||
| 299 | (define cache-file | ||
| 300 | (string-append directory %package-cache-file)) | ||
| 301 | |||
| 302 | (define (expand-cache module symbol variable result) | ||
| 303 | (match (false-if-exception (variable-ref variable)) | ||
| 304 | ((? package? package) | ||
| 305 | (if (hidden-package? package) | ||
| 306 | result | ||
| 307 | (cons `#(,(package-name package) | ||
| 308 | ,(package-version package) | ||
| 309 | ,(module-name module) | ||
| 310 | ,symbol | ||
| 311 | ,(package-outputs package) | ||
| 312 | ,(->bool (member (%current-system) | ||
| 313 | (package-supported-systems package))) | ||
| 314 | ,(->bool (package-superseded package)) | ||
| 315 | ,@(let ((loc (package-location package))) | ||
| 316 | (if loc | ||
| 317 | `(,(location-file loc) | ||
| 318 | ,(location-line loc) | ||
| 319 | ,(location-column loc)) | ||
| 320 | '(#f #f #f)))) | ||
| 321 | result))) | ||
| 322 | (_ | ||
| 323 | result))) | ||
| 324 | |||
| 325 | (define exp | ||
| 326 | (fold-module-public-variables* expand-cache '() | ||
| 327 | (all-modules (%package-module-path) | ||
| 328 | #:warn | ||
| 329 | warn-about-load-error))) | ||
| 330 | |||
| 331 | (mkdir-p (dirname cache-file)) | ||
| 332 | (call-with-output-file cache-file | ||
| 333 | (lambda (port) | ||
| 334 | ;; Store the cache as a '.go' file. This makes loading fast and reduces | ||
| 335 | ;; heap usage since some of the static data is directly mmapped. | ||
| 336 | (put-bytevector port | ||
| 337 | (compile `'(,@exp) | ||
| 338 | #:to 'bytecode | ||
| 339 | #:opts '(#:to-file? #t))))) | ||
| 340 | cache-file) | ||
| 341 | |||
| 221 | 342 | ||
| 222 | (define %sigint-prompt | 343 | (define %sigint-prompt |
| 223 | ;; The prompt to jump to upon SIGINT. | 344 | ;; The prompt to jump to upon SIGINT. |
