2013-01-05 23:47:50 +00:00
|
|
|
|
;;; GNU Guix --- Functional package management for GNU
|
2022-01-05 18:29:50 +00:00
|
|
|
|
;;; Copyright © 2012-2020, 2022 Ludovic Courtès <ludo@gnu.org>
|
2013-02-13 01:29:30 +00:00
|
|
|
|
;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
|
2014-07-20 16:29:48 +00:00
|
|
|
|
;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
|
2017-02-17 10:17:03 +00:00
|
|
|
|
;;; Copyright © 2016, 2017 Alex Kost <alezost@gmail.com>
|
2016-02-28 16:50:58 +00:00
|
|
|
|
;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
|
2022-05-27 17:13:28 +00:00
|
|
|
|
;;; Copyright © 2022 Antero Mejr <antero@mailbox.org>
|
2012-06-30 14:37:19 +00:00
|
|
|
|
;;;
|
2013-01-05 23:47:50 +00:00
|
|
|
|
;;; This file is part of GNU Guix.
|
2012-06-30 14:37:19 +00:00
|
|
|
|
;;;
|
2013-01-05 23:47:50 +00:00
|
|
|
|
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
2012-06-30 14:37:19 +00: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-05 23:47:50 +00:00
|
|
|
|
;;; GNU Guix is distributed in the hope that it will be useful, but
|
2012-06-30 14:37:19 +00: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-05 23:47:50 +00:00
|
|
|
|
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
2012-06-30 14:37:19 +00:00
|
|
|
|
|
2013-01-18 00:06:47 +00:00
|
|
|
|
(define-module (gnu packages)
|
2012-06-30 14:37:19 +00:00
|
|
|
|
#:use-module (guix packages)
|
2013-04-21 08:08:40 +00:00
|
|
|
|
#:use-module (guix ui)
|
2012-08-22 15:24:38 +00:00
|
|
|
|
#:use-module (guix utils)
|
2020-07-25 16:26:18 +00:00
|
|
|
|
#:use-module (guix diagnostics)
|
2017-05-03 21:03:20 +00:00
|
|
|
|
#:use-module (guix discovery)
|
Add (guix memoization).
* guix/combinators.scm (memoize): Remove.
* guix/memoization.scm: New file.
* Makefile.am (MODULES): Add it.
* gnu/packages.scm, gnu/packages/bootstrap.scm,
guix/build-system/gnu.scm, guix/build-system/python.scm,
guix/derivations.scm, guix/gnu-maintenance.scm,
guix/import/cran.scm, guix/import/elpa.scm,
guix/modules.scm, guix/scripts/build.scm,
guix/scripts/graph.scm, guix/scripts/lint.scm,
guix/store.scm, guix/utils.scm: Adjust imports accordingly.
2017-01-28 15:33:57 +00:00
|
|
|
|
#:use-module (guix memoization)
|
2016-03-08 10:38:46 +00:00
|
|
|
|
#:use-module ((guix build utils)
|
|
|
|
|
#:select ((package-name->name+version
|
2019-01-11 16:23:39 +00:00
|
|
|
|
. hyphen-separated-name->name+version)
|
|
|
|
|
mkdir-p))
|
2020-01-06 14:14:09 +00:00
|
|
|
|
#:use-module (guix profiles)
|
2018-08-27 13:38:59 +00:00
|
|
|
|
#:use-module (guix describe)
|
2019-03-28 14:46:18 +00:00
|
|
|
|
#:use-module (guix deprecation)
|
2013-02-13 01:29:30 +00: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 06:24:21 +00:00
|
|
|
|
#:use-module (ice-9 match)
|
2020-01-06 14:14:09 +00:00
|
|
|
|
#:use-module (ice-9 binary-ports)
|
2019-01-11 16:23:39 +00:00
|
|
|
|
#:autoload (system base compile) (compile)
|
2012-06-30 14:37:19 +00:00
|
|
|
|
#:use-module (srfi srfi-1)
|
|
|
|
|
#:use-module (srfi srfi-26)
|
2015-01-20 09:17:24 +00:00
|
|
|
|
#:use-module (srfi srfi-34)
|
|
|
|
|
#:use-module (srfi srfi-35)
|
2012-08-22 15:24:38 +00:00
|
|
|
|
#:use-module (srfi srfi-39)
|
2022-06-06 20:32:29 +00:00
|
|
|
|
#:use-module (srfi srfi-71)
|
2012-08-22 15:24:38 +00:00
|
|
|
|
#:export (search-patch
|
2016-04-08 08:28:40 +00:00
|
|
|
|
search-patches
|
2017-02-17 10:17:03 +00:00
|
|
|
|
search-auxiliary-file
|
2015-04-02 12:51:05 +00:00
|
|
|
|
%patch-path
|
2017-02-17 10:17:03 +00:00
|
|
|
|
%auxiliary-files-path
|
2014-09-24 11:53:02 +00:00
|
|
|
|
%package-module-path
|
2018-08-27 13:38:59 +00:00
|
|
|
|
%default-package-module-path
|
2022-01-05 18:29:50 +00:00
|
|
|
|
cache-is-authoritative?
|
2014-07-20 16:29:48 +00:00
|
|
|
|
|
2012-11-19 21:37:50 +00:00
|
|
|
|
fold-packages
|
2019-01-13 14:36:49 +00:00
|
|
|
|
fold-available-packages
|
2014-07-20 16:29:48 +00:00
|
|
|
|
|
2019-03-28 14:46:18 +00:00
|
|
|
|
find-newest-available-packages
|
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 06:24:21 +00:00
|
|
|
|
find-packages-by-name
|
2019-01-13 13:27:10 +00:00
|
|
|
|
find-package-locations
|
2013-12-21 21:36:32 +00:00
|
|
|
|
find-best-packages-by-name
|
2014-07-20 16:29:48 +00:00
|
|
|
|
|
2015-06-17 08:49:29 +00:00
|
|
|
|
specification->package
|
2017-06-11 21:05:23 +00:00
|
|
|
|
specification->package+output
|
2019-01-13 13:27:10 +00:00
|
|
|
|
specification->location
|
2019-01-11 16:23:39 +00:00
|
|
|
|
specifications->manifest
|
2022-05-27 17:13:28 +00:00
|
|
|
|
specifications->packages
|
2019-01-11 16:23:39 +00:00
|
|
|
|
|
2022-03-14 17:20:31 +00:00
|
|
|
|
package-unique-version-prefix
|
|
|
|
|
|
2019-01-11 16:23:39 +00:00
|
|
|
|
generate-package-cache))
|
2012-06-30 14:37:19 +00:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
;;;
|
|
|
|
|
;;; General utilities for the software distribution---i.e., the modules under
|
2013-01-18 00:06:47 +00:00
|
|
|
|
;;; (gnu packages ...).
|
2012-06-30 14:37:19 +00:00
|
|
|
|
;;;
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
2019-06-14 19:35:08 +00:00
|
|
|
|
;; By default, we store patches and auxiliary files
|
2017-02-17 10:17:03 +00:00
|
|
|
|
;; 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 20:30:42 +00:00
|
|
|
|
|
2017-02-17 10:17:03 +00:00
|
|
|
|
(define %auxiliary-files-path
|
|
|
|
|
(make-parameter
|
|
|
|
|
(map (cut string-append <> "/gnu/packages/aux-files")
|
|
|
|
|
%load-path)))
|
|
|
|
|
|
|
|
|
|
(define (search-auxiliary-file file-name)
|
|
|
|
|
"Search the auxiliary FILE-NAME. Return #f if not found."
|
|
|
|
|
(search-path (%auxiliary-files-path) file-name))
|
|
|
|
|
|
2012-08-22 15:24:38 +00:00
|
|
|
|
(define (search-patch file-name)
|
2015-01-20 09:17:24 +00:00
|
|
|
|
"Search the patch FILE-NAME. Raise an error if not found."
|
|
|
|
|
(or (search-path (%patch-path) file-name)
|
2020-07-25 16:26:18 +00:00
|
|
|
|
(raise (formatted-message (G_ "~a: patch not found")
|
|
|
|
|
file-name))))
|
2012-08-22 15:24:38 +00:00
|
|
|
|
|
2016-04-08 08:28:40 +00:00
|
|
|
|
(define-syntax-rule (search-patches file-name ...)
|
|
|
|
|
"Return the list of absolute file names corresponding to each
|
|
|
|
|
FILE-NAME found in %PATCH-PATH."
|
|
|
|
|
(list (search-patch file-name) ...))
|
|
|
|
|
|
2014-09-24 08:23:27 +00:00
|
|
|
|
(define %distro-root-directory
|
2018-03-23 14:36:12 +00:00
|
|
|
|
;; Absolute file name of the module hierarchy. Since (gnu packages …) might
|
|
|
|
|
;; live in a directory different from (guix), try to get the best match.
|
|
|
|
|
(letrec-syntax ((dirname* (syntax-rules ()
|
|
|
|
|
((_ file)
|
|
|
|
|
(dirname file))
|
|
|
|
|
((_ file head tail ...)
|
|
|
|
|
(dirname (dirname* file tail ...)))))
|
|
|
|
|
(try (syntax-rules ()
|
|
|
|
|
((_ (file things ...) rest ...)
|
|
|
|
|
(match (search-path %load-path file)
|
|
|
|
|
(#f
|
|
|
|
|
(try rest ...))
|
|
|
|
|
(absolute
|
|
|
|
|
(dirname* absolute things ...))))
|
|
|
|
|
((_)
|
|
|
|
|
#f))))
|
|
|
|
|
(try ("gnu/packages/base.scm" gnu/ packages/)
|
|
|
|
|
("gnu/packages.scm" gnu/)
|
|
|
|
|
("guix.scm"))))
|
2012-06-30 14:37:19 +00:00
|
|
|
|
|
2018-08-27 13:38:59 +00:00
|
|
|
|
(define %default-package-module-path
|
|
|
|
|
;; Default search path for package modules.
|
|
|
|
|
`((,%distro-root-directory . "gnu/packages")))
|
|
|
|
|
|
2019-01-11 16:23:39 +00:00
|
|
|
|
(define (cache-is-authoritative?)
|
|
|
|
|
"Return true if the pre-computed package cache is authoritative. It is not
|
|
|
|
|
authoritative when entries have been added via GUIX_PACKAGE_PATH or '-L'
|
|
|
|
|
flags."
|
|
|
|
|
(equal? (%package-module-path)
|
|
|
|
|
(append %default-package-module-path
|
|
|
|
|
(package-path-entries))))
|
|
|
|
|
|
2014-09-24 11:53:02 +00: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.
|
2022-06-06 20:32:29 +00:00
|
|
|
|
(let* ((not-colon (char-set-complement (char-set #\:)))
|
|
|
|
|
(environment (string-tokenize (or (getenv "GUIX_PACKAGE_PATH") "")
|
|
|
|
|
not-colon))
|
|
|
|
|
(channels-scm channels-go (package-path-entries)))
|
2018-08-27 13:38:59 +00:00
|
|
|
|
;; Automatically add channels and items from $GUIX_PACKAGE_PATH to Guile's
|
|
|
|
|
;; search path. For historical reasons, $GUIX_PACKAGE_PATH goes to the
|
|
|
|
|
;; front; channels go to the back so that they don't override Guix' own
|
|
|
|
|
;; modules.
|
|
|
|
|
(set! %load-path
|
2019-03-11 21:14:30 +00:00
|
|
|
|
(append environment %load-path channels-scm))
|
2018-08-27 13:38:59 +00:00
|
|
|
|
(set! %load-compiled-path
|
2019-03-11 21:14:30 +00:00
|
|
|
|
(append environment %load-compiled-path channels-go))
|
2014-09-24 12:05:52 +00:00
|
|
|
|
|
|
|
|
|
(make-parameter
|
2018-08-27 13:38:59 +00:00
|
|
|
|
(append environment
|
|
|
|
|
%default-package-module-path
|
2019-03-11 21:14:30 +00:00
|
|
|
|
channels-scm))))
|
2014-09-24 11:53:02 +00:00
|
|
|
|
|
2015-01-03 22:49:42 +00: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)))
|
|
|
|
|
|
2019-03-28 14:46:18 +00:00
|
|
|
|
;; This procedure is used by Emacs-Guix up to 0.5.1.1, so keep it for now.
|
|
|
|
|
;; See <https://github.com/alezost/guix.el/issues/30>.
|
|
|
|
|
(define-deprecated find-newest-available-packages
|
|
|
|
|
find-packages-by-name
|
|
|
|
|
(mlambda ()
|
|
|
|
|
"Return a vhash keyed by package names, and with
|
|
|
|
|
associated values of the form
|
|
|
|
|
|
|
|
|
|
(newest-version newest-package ...)
|
|
|
|
|
|
|
|
|
|
where the preferred package is listed first."
|
|
|
|
|
(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)))
|
|
|
|
|
|
2019-01-13 14:36:49 +00:00
|
|
|
|
(define (fold-available-packages proc init)
|
|
|
|
|
"Fold PROC over the list of available packages. For each available package,
|
|
|
|
|
PROC is called along these lines:
|
|
|
|
|
|
|
|
|
|
(PROC NAME VERSION RESULT
|
|
|
|
|
#:outputs OUTPUTS
|
|
|
|
|
#:location LOCATION
|
|
|
|
|
…)
|
|
|
|
|
|
|
|
|
|
PROC can use #:allow-other-keys to ignore the bits it's not interested in.
|
|
|
|
|
When a package cache is available, this procedure does not actually load any
|
|
|
|
|
package module."
|
|
|
|
|
(define cache
|
|
|
|
|
(load-package-cache (current-profile)))
|
|
|
|
|
|
|
|
|
|
(if (and cache (cache-is-authoritative?))
|
|
|
|
|
(vhash-fold (lambda (name vector result)
|
|
|
|
|
(match vector
|
|
|
|
|
(#(name version module symbol outputs
|
|
|
|
|
supported? deprecated?
|
|
|
|
|
file line column)
|
|
|
|
|
(proc name version result
|
|
|
|
|
#:outputs outputs
|
|
|
|
|
#:location (and file
|
|
|
|
|
(location file line column))
|
|
|
|
|
#:supported? supported?
|
|
|
|
|
#:deprecated? deprecated?))))
|
|
|
|
|
init
|
|
|
|
|
cache)
|
|
|
|
|
(fold-packages (lambda (package result)
|
|
|
|
|
(proc (package-name package)
|
|
|
|
|
(package-version package)
|
|
|
|
|
result
|
|
|
|
|
#:outputs (package-outputs package)
|
|
|
|
|
#:location (package-location package)
|
|
|
|
|
#:supported?
|
2019-10-14 21:41:24 +00:00
|
|
|
|
(->bool (supported-package? package))
|
2019-01-13 14:36:49 +00:00
|
|
|
|
#:deprecated?
|
|
|
|
|
(->bool
|
|
|
|
|
(package-superseded package))))
|
|
|
|
|
init)))
|
|
|
|
|
|
2017-09-01 08:26:27 +00:00
|
|
|
|
(define* (fold-packages proc init
|
|
|
|
|
#:optional
|
2018-03-26 21:42:59 +00:00
|
|
|
|
(modules (all-modules (%package-module-path)
|
|
|
|
|
#:warn
|
|
|
|
|
warn-about-load-error))
|
2017-11-06 22:21:08 +00:00
|
|
|
|
#:key (select? (negate hidden-package?)))
|
2017-09-01 08:26:27 +00:00
|
|
|
|
"Call (PROC PACKAGE RESULT) for each available package defined in one of
|
2017-11-06 22:21:08 +00:00
|
|
|
|
MODULES that matches SELECT?, using INIT as the initial value of RESULT. It
|
|
|
|
|
is guaranteed to never traverse the same package twice."
|
2017-05-03 21:03:20 +00:00
|
|
|
|
(fold-module-public-variables (lambda (object result)
|
2017-11-06 22:21:08 +00:00
|
|
|
|
(if (and (package? object) (select? object))
|
2017-05-03 21:03:20 +00:00
|
|
|
|
(proc object result)
|
|
|
|
|
result))
|
|
|
|
|
init
|
2017-09-01 08:26:27 +00:00
|
|
|
|
modules))
|
2012-11-19 21:37:50 +00:00
|
|
|
|
|
2019-01-11 16:23:39 +00:00
|
|
|
|
(define %package-cache-file
|
|
|
|
|
;; Location of the package cache.
|
|
|
|
|
"/lib/guix/package.cache")
|
|
|
|
|
|
|
|
|
|
(define load-package-cache
|
|
|
|
|
(mlambda (profile)
|
|
|
|
|
"Attempt to load the package cache. On success return a vhash keyed by
|
|
|
|
|
package names. Return #f on failure."
|
|
|
|
|
(match profile
|
|
|
|
|
(#f #f)
|
|
|
|
|
(profile
|
|
|
|
|
(catch 'system-error
|
|
|
|
|
(lambda ()
|
|
|
|
|
(define lst
|
|
|
|
|
(load-compiled (string-append profile %package-cache-file)))
|
|
|
|
|
(fold (lambda (item vhash)
|
|
|
|
|
(match item
|
|
|
|
|
(#(name version module symbol outputs
|
|
|
|
|
supported? deprecated?
|
|
|
|
|
file line column)
|
|
|
|
|
(vhash-cons name item vhash))))
|
|
|
|
|
vlist-null
|
|
|
|
|
lst))
|
|
|
|
|
(lambda args
|
|
|
|
|
(if (= ENOENT (system-error-errno args))
|
|
|
|
|
#f
|
|
|
|
|
(apply throw args))))))))
|
|
|
|
|
|
|
|
|
|
(define find-packages-by-name/direct ;bypass the cache
|
2014-09-29 19:39:39 +00:00
|
|
|
|
(let ((packages (delay
|
|
|
|
|
(fold-packages (lambda (p r)
|
|
|
|
|
(vhash-cons (package-name p) p r))
|
2015-04-18 20:30:07 +00:00
|
|
|
|
vlist-null)))
|
|
|
|
|
(version>? (lambda (p1 p2)
|
|
|
|
|
(version>? (package-version p1) (package-version p2)))))
|
2014-09-29 19:39:39 +00:00
|
|
|
|
(lambda* (name #:optional version)
|
|
|
|
|
"Return the list of packages with the given NAME. If VERSION is not #f,
|
2015-04-18 20:30:07 +00:00
|
|
|
|
then only return packages whose version is prefixed by VERSION, sorted in
|
|
|
|
|
decreasing version order."
|
|
|
|
|
(let ((matching (sort (vhash-fold* cons '() name (force packages))
|
|
|
|
|
version>?)))
|
2014-09-29 19:39:39 +00:00
|
|
|
|
(if version
|
|
|
|
|
(filter (lambda (package)
|
2018-05-13 10:16:34 +00:00
|
|
|
|
(version-prefix? version (package-version package)))
|
2014-09-29 19:39:39 +00:00
|
|
|
|
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 06:24:21 +00:00
|
|
|
|
|
2019-01-11 16:23:39 +00:00
|
|
|
|
(define (cache-lookup cache name)
|
|
|
|
|
"Lookup package NAME in CACHE. Return a list sorted in increasing version
|
|
|
|
|
order."
|
|
|
|
|
(define (package-version<? v1 v2)
|
|
|
|
|
(version>? (vector-ref v2 1) (vector-ref v1 1)))
|
|
|
|
|
|
|
|
|
|
(sort (vhash-fold* cons '() name cache)
|
|
|
|
|
package-version<?))
|
|
|
|
|
|
|
|
|
|
(define* (find-packages-by-name name #:optional version)
|
|
|
|
|
"Return the list of packages with the given NAME. If VERSION is not #f,
|
|
|
|
|
then only return packages whose version is prefixed by VERSION, sorted in
|
|
|
|
|
decreasing version order."
|
|
|
|
|
(define cache
|
|
|
|
|
(load-package-cache (current-profile)))
|
|
|
|
|
|
|
|
|
|
(if (and (cache-is-authoritative?) cache)
|
|
|
|
|
(match (cache-lookup cache name)
|
|
|
|
|
(#f #f)
|
|
|
|
|
((#(_ versions modules symbols _ _ _ _ _ _) ...)
|
|
|
|
|
(fold (lambda (version* module symbol result)
|
|
|
|
|
(if (or (not version)
|
|
|
|
|
(version-prefix? version version*))
|
|
|
|
|
(cons (module-ref (resolve-interface module)
|
|
|
|
|
symbol)
|
|
|
|
|
result)
|
|
|
|
|
result))
|
|
|
|
|
'()
|
|
|
|
|
versions modules symbols)))
|
|
|
|
|
(find-packages-by-name/direct name version)))
|
|
|
|
|
|
2019-01-13 13:27:10 +00:00
|
|
|
|
(define* (find-package-locations name #:optional version)
|
|
|
|
|
"Return a list of version/location pairs corresponding to each package
|
|
|
|
|
matching NAME and VERSION."
|
|
|
|
|
(define cache
|
|
|
|
|
(load-package-cache (current-profile)))
|
|
|
|
|
|
|
|
|
|
(if (and cache (cache-is-authoritative?))
|
|
|
|
|
(match (cache-lookup cache name)
|
|
|
|
|
(#f '())
|
|
|
|
|
((#(name versions modules symbols outputs
|
|
|
|
|
supported? deprecated?
|
|
|
|
|
files lines columns) ...)
|
|
|
|
|
(fold (lambda (version* file line column result)
|
|
|
|
|
(if (and file
|
|
|
|
|
(or (not version)
|
|
|
|
|
(version-prefix? version version*)))
|
|
|
|
|
(alist-cons version* (location file line column)
|
|
|
|
|
result)
|
|
|
|
|
result))
|
|
|
|
|
'()
|
|
|
|
|
versions files lines columns)))
|
|
|
|
|
(map (lambda (package)
|
|
|
|
|
(cons (package-version package) (package-location package)))
|
|
|
|
|
(find-packages-by-name/direct name version))))
|
2013-12-21 21:36:32 +00:00
|
|
|
|
|
|
|
|
|
(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)
|
2019-01-11 14:19:41 +00:00
|
|
|
|
(match (find-packages-by-name name)
|
|
|
|
|
(()
|
|
|
|
|
'())
|
|
|
|
|
((matches ...)
|
|
|
|
|
;; Return the subset of MATCHES with the higher version number.
|
|
|
|
|
(let ((highest (package-version (first matches))))
|
|
|
|
|
(take-while (lambda (p)
|
|
|
|
|
(string=? (package-version p) highest))
|
|
|
|
|
matches))))))
|
2014-07-20 16:29:48 +00:00
|
|
|
|
|
2020-01-17 10:19:42 +00:00
|
|
|
|
;; Prevent Guile 3 from inlining this procedure so we can mock it in tests.
|
|
|
|
|
(set! find-best-packages-by-name find-best-packages-by-name)
|
|
|
|
|
|
2019-01-11 16:23:39 +00:00
|
|
|
|
(define (generate-package-cache directory)
|
|
|
|
|
"Generate under DIRECTORY a cache of all the available packages.
|
|
|
|
|
|
|
|
|
|
The primary purpose of the cache is to speed up package lookup by name such
|
|
|
|
|
that we don't have to traverse and load all the package modules, thereby also
|
|
|
|
|
reducing the memory footprint."
|
|
|
|
|
(define cache-file
|
|
|
|
|
(string-append directory %package-cache-file))
|
|
|
|
|
|
2020-07-30 14:37:19 +00:00
|
|
|
|
(define expand-cache
|
|
|
|
|
(match-lambda*
|
|
|
|
|
(((module symbol variable) (result . seen))
|
|
|
|
|
(let ((package (variable-ref variable)))
|
|
|
|
|
(if (or (vhash-assq package seen)
|
|
|
|
|
(hidden-package? package))
|
|
|
|
|
(cons result seen)
|
|
|
|
|
(cons (cons `#(,(package-name package)
|
|
|
|
|
,(package-version package)
|
|
|
|
|
,(module-name module)
|
|
|
|
|
,symbol
|
|
|
|
|
,(package-outputs package)
|
|
|
|
|
,(->bool (supported-package? package))
|
|
|
|
|
,(->bool (package-superseded package))
|
|
|
|
|
,@(let ((loc (package-location package)))
|
|
|
|
|
(if loc
|
|
|
|
|
`(,(location-file loc)
|
|
|
|
|
,(location-line loc)
|
|
|
|
|
,(location-column loc))
|
|
|
|
|
'(#f #f #f))))
|
|
|
|
|
result)
|
|
|
|
|
(vhash-consq package #t seen)))))))
|
|
|
|
|
|
|
|
|
|
(define entry-key
|
|
|
|
|
(match-lambda
|
|
|
|
|
((module symbol variable)
|
|
|
|
|
(let ((value (variable-ref variable)))
|
|
|
|
|
(string-append (package-name value) (package-version value)
|
|
|
|
|
(object->string module)
|
|
|
|
|
(symbol->string symbol))))))
|
|
|
|
|
|
|
|
|
|
(define (entry<? a b)
|
|
|
|
|
(string<? (entry-key a) (entry-key b)))
|
|
|
|
|
|
|
|
|
|
(define variables
|
|
|
|
|
;; First sort variables so that 'expand-cache' later dismisses
|
|
|
|
|
;; already-seen package objects in a deterministic fashion.
|
|
|
|
|
(sort
|
|
|
|
|
(fold-module-public-variables* (lambda (module symbol variable lst)
|
|
|
|
|
(let ((value (false-if-exception
|
|
|
|
|
(variable-ref variable))))
|
|
|
|
|
(if (package? value)
|
|
|
|
|
(cons (list module symbol variable)
|
|
|
|
|
lst)
|
|
|
|
|
lst)))
|
|
|
|
|
'()
|
2019-02-15 21:58:29 +00:00
|
|
|
|
(all-modules (%package-module-path)
|
|
|
|
|
#:warn
|
2020-07-30 14:37:19 +00:00
|
|
|
|
warn-about-load-error))
|
|
|
|
|
entry<?))
|
|
|
|
|
|
|
|
|
|
(define exp
|
|
|
|
|
(first (fold expand-cache (cons '() vlist-null) variables)))
|
2019-01-11 16:23:39 +00:00
|
|
|
|
|
|
|
|
|
(mkdir-p (dirname cache-file))
|
|
|
|
|
(call-with-output-file cache-file
|
|
|
|
|
(lambda (port)
|
|
|
|
|
;; Store the cache as a '.go' file. This makes loading fast and reduces
|
|
|
|
|
;; heap usage since some of the static data is directly mmapped.
|
|
|
|
|
(put-bytevector port
|
|
|
|
|
(compile `'(,@exp)
|
|
|
|
|
#:to 'bytecode
|
|
|
|
|
#:opts '(#:to-file? #t)))))
|
|
|
|
|
cache-file)
|
2014-07-20 16:29:48 +00:00
|
|
|
|
|
2014-08-16 18:00:34 +00: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))))
|
|
|
|
|
|
2016-02-28 16:50:58 +00:00
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Package specification.
|
|
|
|
|
;;;
|
|
|
|
|
|
2017-05-01 13:45:41 +00:00
|
|
|
|
(define* (%find-package spec name version)
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(match (find-best-packages-by-name name version)
|
|
|
|
|
((pkg . pkg*)
|
|
|
|
|
(unless (null? pkg*)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 13:57:02 +00:00
|
|
|
|
(warning (G_ "ambiguous package specification `~a'~%") spec)
|
|
|
|
|
(warning (G_ "choosing ~a@~a from ~a~%")
|
2017-03-08 22:12:09 +00:00
|
|
|
|
(package-name pkg) (package-version pkg)
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(location->string (package-location pkg))))
|
2016-09-06 21:14:07 +00:00
|
|
|
|
(match (package-superseded pkg)
|
|
|
|
|
((? package? new)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 13:57:02 +00:00
|
|
|
|
(info (G_ "package '~a' has been superseded by '~a'~%")
|
2016-09-06 21:14:07 +00:00
|
|
|
|
(package-name pkg) (package-name new))
|
|
|
|
|
new)
|
|
|
|
|
(#f
|
|
|
|
|
pkg)))
|
2016-09-20 08:51:39 +00:00
|
|
|
|
(x
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(if version
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 13:57:02 +00:00
|
|
|
|
(leave (G_ "~A: package not found for version ~a~%") name version)
|
|
|
|
|
(leave (G_ "~A: unknown package~%") name)))))
|
2016-02-28 16:50:58 +00:00
|
|
|
|
|
2014-08-31 23:45:09 +00:00
|
|
|
|
(define (specification->package spec)
|
|
|
|
|
"Return a package matching SPEC. SPEC may be a package name, or a package
|
2016-02-28 22:11:36 +00:00
|
|
|
|
name followed by an at-sign and a version number. If the version number is not
|
2014-08-31 23:45:09 +00:00
|
|
|
|
present, return the preferred newest version."
|
2022-06-06 20:32:29 +00:00
|
|
|
|
(let ((name version (package-name->name+version spec)))
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(%find-package spec name version)))
|
2015-06-17 08:49:29 +00:00
|
|
|
|
|
2019-01-13 13:27:10 +00:00
|
|
|
|
(define (specification->location spec)
|
|
|
|
|
"Return the location of the highest-numbered package matching SPEC, a
|
|
|
|
|
specification such as \"guile@2\" or \"emacs\"."
|
2022-06-06 20:32:29 +00:00
|
|
|
|
(let ((name version (package-name->name+version spec)))
|
2019-01-13 13:27:10 +00:00
|
|
|
|
(match (find-package-locations name version)
|
|
|
|
|
(()
|
|
|
|
|
(if version
|
|
|
|
|
(leave (G_ "~A: package not found for version ~a~%") name version)
|
|
|
|
|
(leave (G_ "~A: unknown package~%") name)))
|
|
|
|
|
(lst
|
|
|
|
|
(let* ((highest (match lst (((version . _) _ ...) version)))
|
|
|
|
|
(locations (take-while (match-lambda
|
|
|
|
|
((version . location)
|
|
|
|
|
(string=? version highest)))
|
|
|
|
|
lst)))
|
|
|
|
|
(match locations
|
|
|
|
|
(((version . location) . rest)
|
|
|
|
|
(unless (null? rest)
|
|
|
|
|
(warning (G_ "ambiguous package specification `~a'~%") spec)
|
|
|
|
|
(warning (G_ "choosing ~a@~a from ~a~%")
|
|
|
|
|
name version
|
|
|
|
|
(location->string location)))
|
|
|
|
|
location)))))))
|
|
|
|
|
|
2015-06-17 08:49:29 +00:00
|
|
|
|
(define* (specification->package+output spec #:optional (output "out"))
|
|
|
|
|
"Return the package and output specified by SPEC, or #f and #f; SPEC may
|
|
|
|
|
optionally contain a version number and an output name, as in these examples:
|
|
|
|
|
|
|
|
|
|
guile
|
2016-02-28 22:11:36 +00:00
|
|
|
|
guile@2.0.9
|
2015-06-17 08:49:29 +00:00
|
|
|
|
guile:debug
|
2016-02-28 22:11:36 +00:00
|
|
|
|
guile@2.0.9:debug
|
2015-06-17 08:49:29 +00:00
|
|
|
|
|
|
|
|
|
If SPEC does not specify a version number, return the preferred newest
|
2019-06-23 16:28:45 +00:00
|
|
|
|
version; if SPEC does not specify an output, return OUTPUT.
|
|
|
|
|
|
|
|
|
|
When OUTPUT is false and SPEC does not specify any output, return #f as the
|
|
|
|
|
output."
|
2022-06-06 20:32:29 +00:00
|
|
|
|
(let ((name version sub-drv
|
|
|
|
|
(package-specification->name+version+output spec output)))
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(match (%find-package spec name version)
|
|
|
|
|
(#f
|
|
|
|
|
(values #f #f))
|
|
|
|
|
(package
|
2019-06-23 16:28:45 +00:00
|
|
|
|
(if (or (and (not output) (not sub-drv))
|
|
|
|
|
(member sub-drv (package-outputs package)))
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(values package sub-drv)
|
ui: Rename '_' to 'G_'.
This avoids collisions with '_' when the latter is used as a 'match'
pattern for instance. See
<https://lists.gnu.org/archive/html/guix-devel/2017-04/msg00464.html>.
* guix/ui.scm: Rename '_' to 'G_'.
* po/guix/Makevars (XGETTEXT_OPTIONS): Adjust accordingly.
* build-aux/compile-all.scm (warnings): Remove 'format'.
* gnu/packages.scm,
gnu/services.scm,
gnu/services/shepherd.scm,
gnu/system.scm,
gnu/system/shadow.scm,
guix/gnupg.scm,
guix/http-client.scm,
guix/import/cpan.scm,
guix/import/elpa.scm,
guix/import/pypi.scm,
guix/nar.scm,
guix/scripts.scm,
guix/scripts/archive.scm,
guix/scripts/authenticate.scm,
guix/scripts/build.scm,
guix/scripts/challenge.scm,
guix/scripts/container.scm,
guix/scripts/container/exec.scm,
guix/scripts/copy.scm,
guix/scripts/download.scm,
guix/scripts/edit.scm,
guix/scripts/environment.scm,
guix/scripts/gc.scm,
guix/scripts/graph.scm,
guix/scripts/hash.scm,
guix/scripts/import.scm,
guix/scripts/import/cpan.scm,
guix/scripts/import/cran.scm,
guix/scripts/import/crate.scm,
guix/scripts/import/elpa.scm,
guix/scripts/import/gem.scm,
guix/scripts/import/gnu.scm,
guix/scripts/import/hackage.scm,
guix/scripts/import/nix.scm,
guix/scripts/import/pypi.scm,
guix/scripts/import/stackage.scm,
guix/scripts/lint.scm,
guix/scripts/offload.scm,
guix/scripts/pack.scm,
guix/scripts/package.scm,
guix/scripts/perform-download.scm,
guix/scripts/publish.scm,
guix/scripts/pull.scm,
guix/scripts/refresh.scm,
guix/scripts/size.scm,
guix/scripts/substitute.scm,
guix/scripts/system.scm,
guix/ssh.scm,
guix/upstream.scm: Use 'G_' instead of '_'. Most of this change was
obtained by running: "sed -i -e's/(_ "/(G_ "/g' `find -name \*.scm`".
2017-05-03 13:57:02 +00:00
|
|
|
|
(leave (G_ "package `~a' lacks output `~a'~%")
|
2016-02-28 16:50:58 +00:00
|
|
|
|
(package-full-name package)
|
|
|
|
|
sub-drv))))))
|
2017-06-11 21:05:23 +00:00
|
|
|
|
|
2022-05-27 17:13:28 +00:00
|
|
|
|
(define (specifications->packages specs)
|
|
|
|
|
"Given SPECS, a list of specifications such as \"emacs@25.2\" or
|
|
|
|
|
\"guile:debug\", return a list of package/output tuples."
|
|
|
|
|
;; This procedure exists so users of 'guix home' don't have to write out the
|
|
|
|
|
;; (map (compose list specification->package+output)... boilerplate.
|
|
|
|
|
(map (compose list specification->package+output) specs))
|
|
|
|
|
|
2017-06-11 21:05:23 +00:00
|
|
|
|
(define (specifications->manifest specs)
|
|
|
|
|
"Given SPECS, a list of specifications such as \"emacs@25.2\" or
|
|
|
|
|
\"guile:debug\", return a profile manifest."
|
|
|
|
|
;; This procedure exists mostly so users of 'guix package -m' don't have to
|
|
|
|
|
;; fiddle with multiple-value returns.
|
|
|
|
|
(packages->manifest
|
2022-05-27 17:13:28 +00:00
|
|
|
|
(specifications->packages specs)))
|
2022-03-14 17:20:31 +00:00
|
|
|
|
|
|
|
|
|
(define (package-unique-version-prefix name version)
|
|
|
|
|
"Search among all the versions of package NAME that are available, and
|
|
|
|
|
return the shortest unambiguous version prefix to designate VERSION. If only
|
|
|
|
|
one version of the package is available, return the empty string."
|
|
|
|
|
(match (map package-version (find-packages-by-name name))
|
|
|
|
|
((_)
|
|
|
|
|
;; A single version of NAME is available, so do not specify the version
|
|
|
|
|
;; number, even if the available version doesn't match VERSION.
|
|
|
|
|
"")
|
|
|
|
|
(versions
|
|
|
|
|
;; If VERSION is the latest version, don't specify any version.
|
|
|
|
|
;; Otherwise return the shortest unique version prefix. Note that this
|
|
|
|
|
;; is based on the currently available packages so the result may vary
|
|
|
|
|
;; over time.
|
|
|
|
|
(if (every (cut version>? version <>)
|
|
|
|
|
(delete version versions))
|
|
|
|
|
""
|
|
|
|
|
(version-unique-prefix version versions)))))
|