2013-01-06 00:47:50 +01:00
|
|
|
|
;;; GNU Guix --- Functional package management for GNU
|
2015-01-03 23:49:42 +01:00
|
|
|
|
;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
|
2013-02-13 02:29:30 +01:00
|
|
|
|
;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
|
2014-07-20 18:29:48 +02:00
|
|
|
|
;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
|
2012-06-30 16:37:19 +02:00
|
|
|
|
;;;
|
2013-01-06 00:47:50 +01:00
|
|
|
|
;;; This file is part of GNU Guix.
|
2012-06-30 16:37:19 +02:00
|
|
|
|
;;;
|
2013-01-06 00:47:50 +01:00
|
|
|
|
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
2012-06-30 16:37:19 +02:00
|
|
|
|
;;; 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.
|
|
|
|
|
;;;
|
2013-01-06 00:47:50 +01:00
|
|
|
|
;;; GNU Guix is distributed in the hope that it will be useful, but
|
2012-06-30 16:37:19 +02:00
|
|
|
|
;;; 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
|
2013-01-06 00:47:50 +01:00
|
|
|
|
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
2012-06-30 16:37:19 +02:00
|
|
|
|
|
2013-01-18 01:06:47 +01:00
|
|
|
|
(define-module (gnu packages)
|
2012-06-30 16:37:19 +02:00
|
|
|
|
#:use-module (guix packages)
|
2013-04-21 10:08:40 +02:00
|
|
|
|
#:use-module (guix ui)
|
2012-08-22 17:24:38 +02:00
|
|
|
|
#:use-module (guix utils)
|
2014-08-16 20:00:34 +02:00
|
|
|
|
#:use-module ((guix ftp-client) #:select (ftp-open))
|
|
|
|
|
#:use-module (guix gnu-maintenance)
|
2012-06-30 16:37:19 +02:00
|
|
|
|
#:use-module (ice-9 ftw)
|
2013-02-13 02:29:30 +01:00
|
|
|
|
#:use-module (ice-9 vlist)
|
Build newest versions unless specified, and implement upgrades.
* gnu/packages.scm (find-newest-available-packages):
New exported procedure.
* guix-build.in (newest-available-packages, find-best-packages-by-name):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
* guix-package.in (%options): Add --upgrade/-u option.
(newest-available-packages, find-best-packages-by-name, upgradeable?):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
(process-actions): Implement upgrade option.
* doc/guix.texi (Invoking guix-package): In the description of --install,
mention that if no version number is specified, the newest available
version will be selected.
2013-02-12 07:24:21 +01:00
|
|
|
|
#:use-module (ice-9 match)
|
2012-06-30 16:37:19 +02:00
|
|
|
|
#:use-module (srfi srfi-1)
|
2014-09-01 01:45:09 +02:00
|
|
|
|
#:use-module (srfi srfi-11)
|
2012-06-30 16:37:19 +02:00
|
|
|
|
#:use-module (srfi srfi-26)
|
2015-01-20 10:17:24 +01:00
|
|
|
|
#:use-module (srfi srfi-34)
|
|
|
|
|
#:use-module (srfi srfi-35)
|
2012-08-22 17:24:38 +02:00
|
|
|
|
#:use-module (srfi srfi-39)
|
|
|
|
|
#:export (search-patch
|
2012-10-17 21:44:25 +02:00
|
|
|
|
search-bootstrap-binary
|
2015-04-02 14:51:05 +02:00
|
|
|
|
%patch-path
|
2012-11-25 16:28:52 +01:00
|
|
|
|
%bootstrap-binaries-path
|
2014-09-24 13:53:02 +02:00
|
|
|
|
%package-module-path
|
2014-07-20 18:29:48 +02:00
|
|
|
|
|
2012-11-19 22:37:50 +01:00
|
|
|
|
fold-packages
|
2014-07-20 18:29:48 +02:00
|
|
|
|
|
Build newest versions unless specified, and implement upgrades.
* gnu/packages.scm (find-newest-available-packages):
New exported procedure.
* guix-build.in (newest-available-packages, find-best-packages-by-name):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
* guix-package.in (%options): Add --upgrade/-u option.
(newest-available-packages, find-best-packages-by-name, upgradeable?):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
(process-actions): Implement upgrade option.
* doc/guix.texi (Invoking guix-package): In the description of --install,
mention that if no version number is specified, the newest available
version will be selected.
2013-02-12 07:24:21 +01:00
|
|
|
|
find-packages-by-name
|
2013-12-21 22:36:32 +01:00
|
|
|
|
find-best-packages-by-name
|
2014-07-20 18:29:48 +02:00
|
|
|
|
find-newest-available-packages
|
|
|
|
|
|
|
|
|
|
package-direct-dependents
|
|
|
|
|
package-transitive-dependents
|
2014-08-16 20:00:34 +02:00
|
|
|
|
package-covering-dependents
|
|
|
|
|
|
2014-09-01 01:45:09 +02:00
|
|
|
|
check-package-freshness
|
|
|
|
|
|
|
|
|
|
specification->package))
|
2012-06-30 16:37:19 +02:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
;;;
|
|
|
|
|
;;; General utilities for the software distribution---i.e., the modules under
|
2013-01-18 01:06:47 +01:00
|
|
|
|
;;; (gnu packages ...).
|
2012-06-30 16:37:19 +02:00
|
|
|
|
;;;
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
2012-11-25 16:28:52 +01:00
|
|
|
|
;; By default, we store patches and bootstrap binaries alongside Guile
|
|
|
|
|
;; modules. This is so that these extra files can be found without
|
|
|
|
|
;; requiring a special setup, such as a specific installation directory
|
|
|
|
|
;; and an extra environment variable. One advantage of this setup is
|
|
|
|
|
;; that everything just works in an auto-compilation setting.
|
2012-10-27 22:30:42 +02:00
|
|
|
|
|
|
|
|
|
(define %bootstrap-binaries-path
|
2012-10-17 21:44:25 +02:00
|
|
|
|
(make-parameter
|
2013-01-18 01:06:24 +01:00
|
|
|
|
(map (cut string-append <> "/gnu/packages/bootstrap")
|
2012-11-25 16:28:52 +01:00
|
|
|
|
%load-path)))
|
2012-10-17 21:44:25 +02:00
|
|
|
|
|
2012-08-22 17:24:38 +02:00
|
|
|
|
(define (search-patch file-name)
|
2015-01-20 10:17:24 +01:00
|
|
|
|
"Search the patch FILE-NAME. Raise an error if not found."
|
|
|
|
|
(or (search-path (%patch-path) file-name)
|
|
|
|
|
(raise (condition
|
|
|
|
|
(&message (message (format #f (_ "~a: patch not found")
|
|
|
|
|
file-name)))))))
|
2012-08-22 17:24:38 +02:00
|
|
|
|
|
2012-10-17 21:44:25 +02:00
|
|
|
|
(define (search-bootstrap-binary file-name system)
|
2015-01-25 23:07:50 +01:00
|
|
|
|
"Search the bootstrap binary FILE-NAME for SYSTEM. Raise an error if not
|
|
|
|
|
found."
|
|
|
|
|
(or (search-path (%bootstrap-binaries-path)
|
|
|
|
|
(string-append system "/" file-name))
|
|
|
|
|
(raise (condition
|
|
|
|
|
(&message
|
|
|
|
|
(message
|
|
|
|
|
(format #f (_ "could not find bootstrap binary '~a' \
|
|
|
|
|
for system '~a'")
|
|
|
|
|
file-name system)))))))
|
2012-10-17 21:44:25 +02:00
|
|
|
|
|
2014-09-24 10:23:27 +02:00
|
|
|
|
(define %distro-root-directory
|
|
|
|
|
;; Absolute file name of the module hierarchy.
|
|
|
|
|
(dirname (search-path %load-path "guix.scm")))
|
2012-06-30 16:37:19 +02:00
|
|
|
|
|
2014-09-24 13:53:02 +02:00
|
|
|
|
(define %package-module-path
|
|
|
|
|
;; Search path for package modules. Each item must be either a directory
|
|
|
|
|
;; name or a pair whose car is a directory and whose cdr is a sub-directory
|
|
|
|
|
;; to narrow the search.
|
2014-09-24 14:05:52 +02:00
|
|
|
|
(let* ((not-colon (char-set-complement (char-set #\:)))
|
|
|
|
|
(environment (string-tokenize (or (getenv "GUIX_PACKAGE_PATH") "")
|
|
|
|
|
not-colon)))
|
|
|
|
|
;; Automatically add items from $GUIX_PACKAGE_PATH to Guile's search path.
|
|
|
|
|
(for-each (lambda (directory)
|
|
|
|
|
(set! %load-path (cons directory %load-path))
|
|
|
|
|
(set! %load-compiled-path
|
|
|
|
|
(cons directory %load-compiled-path)))
|
|
|
|
|
environment)
|
|
|
|
|
|
|
|
|
|
(make-parameter
|
|
|
|
|
(append environment `((,%distro-root-directory . "gnu/packages"))))))
|
2014-09-24 13:53:02 +02:00
|
|
|
|
|
2015-01-03 23:49:42 +01:00
|
|
|
|
(define %patch-path
|
|
|
|
|
;; Define it after '%package-module-path' so that '%load-path' contains user
|
|
|
|
|
;; directories, allowing patches in $GUIX_PACKAGE_PATH to be found.
|
|
|
|
|
(make-parameter
|
|
|
|
|
(map (lambda (directory)
|
|
|
|
|
(if (string=? directory %distro-root-directory)
|
|
|
|
|
(string-append directory "/gnu/packages/patches")
|
|
|
|
|
directory))
|
|
|
|
|
%load-path)))
|
|
|
|
|
|
2014-09-24 10:23:27 +02:00
|
|
|
|
(define* (scheme-files directory)
|
2014-12-21 12:28:10 +01:00
|
|
|
|
"Return the list of Scheme files found under DIRECTORY, recursively. The
|
|
|
|
|
returned list is sorted in alphabetical order."
|
|
|
|
|
|
|
|
|
|
;; Sort entries so that 'fold-packages' works in a deterministic fashion
|
|
|
|
|
;; regardless of details of the underlying file system.
|
|
|
|
|
(sort (file-system-fold (const #t) ; enter?
|
|
|
|
|
(lambda (path stat result) ; leaf
|
|
|
|
|
(if (string-suffix? ".scm" path)
|
|
|
|
|
(cons path result)
|
|
|
|
|
result))
|
|
|
|
|
(lambda (path stat result) ; down
|
|
|
|
|
result)
|
|
|
|
|
(lambda (path stat result) ; up
|
|
|
|
|
result)
|
|
|
|
|
(const #f) ; skip
|
|
|
|
|
(lambda (path stat errno result)
|
|
|
|
|
(warning (_ "cannot access `~a': ~a~%")
|
|
|
|
|
path (strerror errno))
|
|
|
|
|
result)
|
|
|
|
|
'()
|
|
|
|
|
directory
|
|
|
|
|
stat)
|
|
|
|
|
string<?))
|
2012-06-30 16:37:19 +02:00
|
|
|
|
|
2014-09-24 13:53:02 +02:00
|
|
|
|
(define file-name->module-name
|
|
|
|
|
(let ((not-slash (char-set-complement (char-set #\/))))
|
|
|
|
|
(lambda (file)
|
|
|
|
|
"Return the module name (a list of symbols) corresponding to FILE."
|
|
|
|
|
(map string->symbol
|
|
|
|
|
(string-tokenize (string-drop-right file 4) not-slash)))))
|
2014-09-24 10:23:27 +02:00
|
|
|
|
|
|
|
|
|
(define* (package-modules directory #:optional sub-directory)
|
|
|
|
|
"Return the list of modules that provide packages for the distribution.
|
|
|
|
|
Optionally, narrow the search to SUB-DIRECTORY."
|
|
|
|
|
(define prefix-len
|
|
|
|
|
(string-length directory))
|
|
|
|
|
|
|
|
|
|
(filter-map (lambda (file)
|
2015-04-07 22:27:45 +02:00
|
|
|
|
(let* ((file (substring file prefix-len))
|
|
|
|
|
(module (file-name->module-name file)))
|
|
|
|
|
(catch #t
|
|
|
|
|
(lambda ()
|
|
|
|
|
(resolve-interface module))
|
|
|
|
|
(lambda args
|
|
|
|
|
;; Report the error, but keep going.
|
|
|
|
|
(warn-about-load-error module args)
|
|
|
|
|
#f))))
|
2014-09-24 10:23:27 +02:00
|
|
|
|
(scheme-files (if sub-directory
|
|
|
|
|
(string-append directory "/" sub-directory)
|
|
|
|
|
directory))))
|
2012-06-30 16:37:19 +02:00
|
|
|
|
|
2014-09-24 13:53:02 +02:00
|
|
|
|
(define* (all-package-modules #:optional (path (%package-module-path)))
|
|
|
|
|
"Return the list of package modules found in PATH, a list of directories to
|
|
|
|
|
search."
|
|
|
|
|
(fold-right (lambda (spec result)
|
|
|
|
|
(match spec
|
|
|
|
|
((? string? directory)
|
|
|
|
|
(append (package-modules directory) result))
|
|
|
|
|
((directory . sub-directory)
|
|
|
|
|
(append (package-modules directory sub-directory)
|
|
|
|
|
result))))
|
|
|
|
|
'()
|
|
|
|
|
path))
|
|
|
|
|
|
2012-11-19 22:37:50 +01:00
|
|
|
|
(define (fold-packages proc init)
|
|
|
|
|
"Call (PROC PACKAGE RESULT) for each available package, using INIT as
|
2013-02-13 02:29:30 +01:00
|
|
|
|
the initial value of RESULT. It is guaranteed to never traverse the
|
|
|
|
|
same package twice."
|
|
|
|
|
(identity ; discard second return value
|
|
|
|
|
(fold2 (lambda (module result seen)
|
|
|
|
|
(fold2 (lambda (var result seen)
|
|
|
|
|
(if (and (package? var)
|
|
|
|
|
(not (vhash-assq var seen)))
|
|
|
|
|
(values (proc var result)
|
|
|
|
|
(vhash-consq var #t seen))
|
|
|
|
|
(values result seen)))
|
|
|
|
|
result
|
|
|
|
|
seen
|
|
|
|
|
(module-map (lambda (sym var)
|
|
|
|
|
(false-if-exception (variable-ref var)))
|
|
|
|
|
module)))
|
|
|
|
|
init
|
|
|
|
|
vlist-null
|
2014-09-24 13:53:02 +02:00
|
|
|
|
(all-package-modules))))
|
2012-11-19 22:37:50 +01:00
|
|
|
|
|
2014-09-29 21:39:39 +02:00
|
|
|
|
(define find-packages-by-name
|
|
|
|
|
(let ((packages (delay
|
|
|
|
|
(fold-packages (lambda (p r)
|
|
|
|
|
(vhash-cons (package-name p) p r))
|
|
|
|
|
vlist-null))))
|
|
|
|
|
(lambda* (name #:optional version)
|
|
|
|
|
"Return the list of packages with the given NAME. If VERSION is not #f,
|
2012-06-30 16:37:19 +02:00
|
|
|
|
then only return packages whose version is equal to VERSION."
|
2014-09-29 21:39:39 +02:00
|
|
|
|
(let ((matching (vhash-fold* cons '() name (force packages))))
|
|
|
|
|
(if version
|
|
|
|
|
(filter (lambda (package)
|
|
|
|
|
(string=? (package-version package) version))
|
|
|
|
|
matching)
|
|
|
|
|
matching)))))
|
Build newest versions unless specified, and implement upgrades.
* gnu/packages.scm (find-newest-available-packages):
New exported procedure.
* guix-build.in (newest-available-packages, find-best-packages-by-name):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
* guix-package.in (%options): Add --upgrade/-u option.
(newest-available-packages, find-best-packages-by-name, upgradeable?):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
(process-actions): Implement upgrade option.
* doc/guix.texi (Invoking guix-package): In the description of --install,
mention that if no version number is specified, the newest available
version will be selected.
2013-02-12 07:24:21 +01:00
|
|
|
|
|
2013-12-21 22:36:32 +01:00
|
|
|
|
(define find-newest-available-packages
|
|
|
|
|
(memoize
|
|
|
|
|
(lambda ()
|
|
|
|
|
"Return a vhash keyed by package names, and with
|
Build newest versions unless specified, and implement upgrades.
* gnu/packages.scm (find-newest-available-packages):
New exported procedure.
* guix-build.in (newest-available-packages, find-best-packages-by-name):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
* guix-package.in (%options): Add --upgrade/-u option.
(newest-available-packages, find-best-packages-by-name, upgradeable?):
New procedures.
(find-package): Use find-best-packages-by-name, to guarantee that
if a version number is not specified, only the newest versions will
be considered.
(process-actions): Implement upgrade option.
* doc/guix.texi (Invoking guix-package): In the description of --install,
mention that if no version number is specified, the newest available
version will be selected.
2013-02-12 07:24:21 +01:00
|
|
|
|
associated values of the form
|
|
|
|
|
|
|
|
|
|
(newest-version newest-package ...)
|
|
|
|
|
|
|
|
|
|
where the preferred package is listed first."
|
|
|
|
|
|
2013-12-21 22:36:32 +01:00
|
|
|
|
;; FIXME: Currently, the preferred package is whichever one
|
|
|
|
|
;; was found last by 'fold-packages'. Find a better solution.
|
|
|
|
|
(fold-packages (lambda (p r)
|
|
|
|
|
(let ((name (package-name p))
|
|
|
|
|
(version (package-version p)))
|
|
|
|
|
(match (vhash-assoc name r)
|
|
|
|
|
((_ newest-so-far . pkgs)
|
|
|
|
|
(case (version-compare version newest-so-far)
|
|
|
|
|
((>) (vhash-cons name `(,version ,p) r))
|
|
|
|
|
((=) (vhash-cons name `(,version ,p ,@pkgs) r))
|
|
|
|
|
((<) r)))
|
|
|
|
|
(#f (vhash-cons name `(,version ,p) r)))))
|
|
|
|
|
vlist-null))))
|
|
|
|
|
|
|
|
|
|
(define (find-best-packages-by-name name version)
|
|
|
|
|
"If version is #f, return the list of packages named NAME with the highest
|
|
|
|
|
version numbers; otherwise, return the list of packages named NAME and at
|
|
|
|
|
VERSION."
|
|
|
|
|
(if version
|
|
|
|
|
(find-packages-by-name name version)
|
|
|
|
|
(match (vhash-assoc name (find-newest-available-packages))
|
|
|
|
|
((_ version pkgs ...) pkgs)
|
|
|
|
|
(#f '()))))
|
2014-07-20 18:29:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define* (vhash-refq vhash key #:optional (dflt #f))
|
|
|
|
|
"Look up KEY in the vhash VHASH, and return the value (if any) associated
|
|
|
|
|
with it. If KEY is not found, return DFLT (or `#f' if no DFLT argument is
|
|
|
|
|
supplied). Uses `eq?' for equality testing."
|
|
|
|
|
(or (and=> (vhash-assq key vhash) cdr)
|
|
|
|
|
dflt))
|
|
|
|
|
|
|
|
|
|
(define package-dependencies
|
|
|
|
|
(memoize
|
|
|
|
|
(lambda ()
|
|
|
|
|
"Return a vhash keyed by package, and with associated values that are a
|
|
|
|
|
list of packages that depend on that package."
|
|
|
|
|
(fold-packages
|
|
|
|
|
(lambda (package dag)
|
|
|
|
|
(fold
|
|
|
|
|
(lambda (in d)
|
|
|
|
|
;; Insert a graph edge from each of package's inputs to package.
|
|
|
|
|
(vhash-consq in
|
|
|
|
|
(cons package (vhash-refq d in '()))
|
|
|
|
|
(vhash-delq in d)))
|
|
|
|
|
dag
|
|
|
|
|
(match (package-direct-inputs package)
|
|
|
|
|
(((labels packages . _) ...)
|
|
|
|
|
packages) )))
|
|
|
|
|
vlist-null))))
|
|
|
|
|
|
|
|
|
|
(define (package-direct-dependents packages)
|
|
|
|
|
"Return a list of packages from the distribution that directly depend on the
|
|
|
|
|
packages in PACKAGES."
|
|
|
|
|
(delete-duplicates
|
|
|
|
|
(concatenate
|
|
|
|
|
(map (lambda (p)
|
|
|
|
|
(vhash-refq (package-dependencies) p '()))
|
|
|
|
|
packages))))
|
|
|
|
|
|
|
|
|
|
(define (package-transitive-dependents packages)
|
|
|
|
|
"Return the transitive dependent packages of the distribution packages in
|
|
|
|
|
PACKAGES---i.e. the dependents of those packages, plus their dependents,
|
|
|
|
|
recursively."
|
|
|
|
|
(let ((dependency-dag (package-dependencies)))
|
|
|
|
|
(fold-tree
|
|
|
|
|
cons '()
|
|
|
|
|
(lambda (node) (vhash-refq dependency-dag node))
|
|
|
|
|
;; Start with the dependents to avoid including PACKAGES in the result.
|
|
|
|
|
(package-direct-dependents packages))))
|
|
|
|
|
|
|
|
|
|
(define (package-covering-dependents packages)
|
|
|
|
|
"Return a minimal list of packages from the distribution whose dependencies
|
|
|
|
|
include all of PACKAGES and all packages that depend on PACKAGES."
|
|
|
|
|
(let ((dependency-dag (package-dependencies)))
|
|
|
|
|
(fold-tree-leaves
|
|
|
|
|
cons '()
|
|
|
|
|
(lambda (node) (vhash-refq dependency-dag node))
|
|
|
|
|
;; Start with the dependents to avoid including PACKAGES in the result.
|
|
|
|
|
(package-direct-dependents packages))))
|
2014-08-16 20:00:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define %sigint-prompt
|
|
|
|
|
;; The prompt to jump to upon SIGINT.
|
|
|
|
|
(make-prompt-tag "interruptible"))
|
|
|
|
|
|
|
|
|
|
(define (call-with-sigint-handler thunk handler)
|
|
|
|
|
"Call THUNK and return its value. Upon SIGINT, call HANDLER with the signal
|
|
|
|
|
number in the context of the continuation of the call to this function, and
|
|
|
|
|
return its return value."
|
|
|
|
|
(call-with-prompt %sigint-prompt
|
|
|
|
|
(lambda ()
|
|
|
|
|
(sigaction SIGINT
|
|
|
|
|
(lambda (signum)
|
|
|
|
|
(sigaction SIGINT SIG_DFL)
|
|
|
|
|
(abort-to-prompt %sigint-prompt signum)))
|
|
|
|
|
(dynamic-wind
|
|
|
|
|
(const #t)
|
|
|
|
|
thunk
|
|
|
|
|
(cut sigaction SIGINT SIG_DFL)))
|
|
|
|
|
(lambda (k signum)
|
|
|
|
|
(handler signum))))
|
|
|
|
|
|
|
|
|
|
(define-syntax-rule (waiting exp fmt rest ...)
|
|
|
|
|
"Display the given message while EXP is being evaluated."
|
|
|
|
|
(let* ((message (format #f fmt rest ...))
|
|
|
|
|
(blank (make-string (string-length message) #\space)))
|
|
|
|
|
(display message (current-error-port))
|
|
|
|
|
(force-output (current-error-port))
|
|
|
|
|
(call-with-sigint-handler
|
|
|
|
|
(lambda ()
|
|
|
|
|
(dynamic-wind
|
|
|
|
|
(const #f)
|
|
|
|
|
(lambda () exp)
|
|
|
|
|
(lambda ()
|
|
|
|
|
;; Clear the line.
|
|
|
|
|
(display #\cr (current-error-port))
|
|
|
|
|
(display blank (current-error-port))
|
|
|
|
|
(display #\cr (current-error-port))
|
|
|
|
|
(force-output (current-error-port)))))
|
|
|
|
|
(lambda (signum)
|
|
|
|
|
(format (current-error-port) " interrupted by signal ~a~%" SIGINT)
|
|
|
|
|
#f))))
|
|
|
|
|
|
|
|
|
|
(define ftp-open*
|
|
|
|
|
;; Memoizing version of `ftp-open'. The goal is to avoid initiating a new
|
|
|
|
|
;; FTP connection for each package, esp. since most of them are to the same
|
|
|
|
|
;; server. This has a noticeable impact when doing "guix upgrade -u".
|
|
|
|
|
(memoize ftp-open))
|
|
|
|
|
|
|
|
|
|
(define (check-package-freshness package)
|
|
|
|
|
"Check whether PACKAGE has a newer version available upstream, and report
|
|
|
|
|
it."
|
|
|
|
|
;; TODO: Automatically inject the upstream version when desired.
|
|
|
|
|
|
|
|
|
|
(catch #t
|
|
|
|
|
(lambda ()
|
|
|
|
|
(when (false-if-exception (gnu-package? package))
|
|
|
|
|
(let ((name (package-name package))
|
|
|
|
|
(full-name (package-full-name package)))
|
|
|
|
|
(match (waiting (latest-release name
|
|
|
|
|
#:ftp-open ftp-open*
|
|
|
|
|
#:ftp-close (const #f))
|
|
|
|
|
(_ "looking for the latest release of GNU ~a...") name)
|
2014-11-11 14:59:38 +01:00
|
|
|
|
((? gnu-release? release)
|
|
|
|
|
(let ((latest-version
|
|
|
|
|
(string-append (gnu-release-package release) "-"
|
|
|
|
|
(gnu-release-version release))))
|
|
|
|
|
(when (version>? latest-version full-name)
|
|
|
|
|
(format (current-error-port)
|
|
|
|
|
(_ "~a: note: using ~a \
|
2014-08-16 20:00:34 +02:00
|
|
|
|
but ~a is available upstream~%")
|
2014-11-11 14:59:38 +01:00
|
|
|
|
(location->string (package-location package))
|
|
|
|
|
full-name latest-version))))
|
2014-08-16 20:00:34 +02:00
|
|
|
|
(_ #t)))))
|
|
|
|
|
(lambda (key . args)
|
|
|
|
|
;; Silently ignore networking errors rather than preventing
|
|
|
|
|
;; installation.
|
|
|
|
|
(case key
|
|
|
|
|
((getaddrinfo-error ftp-error) #f)
|
|
|
|
|
(else (apply throw key args))))))
|
2014-09-01 01:45:09 +02:00
|
|
|
|
|
|
|
|
|
(define (specification->package spec)
|
|
|
|
|
"Return a package matching SPEC. SPEC may be a package name, or a package
|
|
|
|
|
name followed by a hyphen and a version number. If the version number is not
|
|
|
|
|
present, return the preferred newest version."
|
|
|
|
|
(let-values (((name version)
|
|
|
|
|
(package-name->name+version spec)))
|
|
|
|
|
(match (find-best-packages-by-name name version)
|
|
|
|
|
((p) ; one match
|
|
|
|
|
p)
|
|
|
|
|
((p x ...) ; several matches
|
|
|
|
|
(warning (_ "ambiguous package specification `~a'~%") spec)
|
|
|
|
|
(warning (_ "choosing ~a from ~a~%")
|
|
|
|
|
(package-full-name p)
|
|
|
|
|
(location->string (package-location p)))
|
|
|
|
|
p)
|
|
|
|
|
(_ ; no matches
|
|
|
|
|
(if version
|
|
|
|
|
(leave (_ "~A: package not found for version ~a~%")
|
|
|
|
|
name version)
|
|
|
|
|
(leave (_ "~A: unknown package~%") name))))))
|