2021-06-02 11:18:22 -04:00
|
|
|
|
;;; GNU Guix --- Functional package management for GNU
|
|
|
|
|
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
|
2021-06-21 08:44:47 -04:00
|
|
|
|
;;; Copyright © 2021 Tobias Geerinckx-Rice <me@tobias.gr>
|
2021-07-14 21:40:34 -04:00
|
|
|
|
;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
|
2022-06-28 15:07:05 -04:00
|
|
|
|
;;; Copyright © 2022 Hartmut Goebel <h.goebel@crazy-compilers.com>
|
2021-06-02 11:18:22 -04:00
|
|
|
|
;;;
|
|
|
|
|
;;; This file is part of GNU Guix.
|
|
|
|
|
;;;
|
|
|
|
|
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
|
|
|
|
;;; 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.
|
|
|
|
|
;;;
|
|
|
|
|
;;; GNU Guix is distributed in the hope that it will be useful, but
|
|
|
|
|
;;; 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
|
|
|
|
|
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
(define-module (guix import egg)
|
|
|
|
|
#:use-module (ice-9 ftw)
|
|
|
|
|
#:use-module (ice-9 match)
|
|
|
|
|
#:use-module (srfi srfi-1)
|
|
|
|
|
#:use-module (srfi srfi-71)
|
|
|
|
|
#:use-module (gcrypt hash)
|
|
|
|
|
#:use-module (guix git)
|
|
|
|
|
#:use-module (guix i18n)
|
|
|
|
|
#:use-module (guix base32)
|
|
|
|
|
#:use-module (guix diagnostics)
|
|
|
|
|
#:use-module (guix memoization)
|
|
|
|
|
#:use-module (guix packages)
|
|
|
|
|
#:use-module (guix upstream)
|
|
|
|
|
#:use-module (guix build-system)
|
|
|
|
|
#:use-module (guix build-system chicken)
|
|
|
|
|
#:use-module (guix store)
|
|
|
|
|
#:use-module ((guix download) #:select (download-to-store url-fetch))
|
|
|
|
|
#:use-module (guix import utils)
|
|
|
|
|
#:use-module ((guix licenses) #:prefix license:)
|
|
|
|
|
#:export (egg->guix-package
|
|
|
|
|
egg-recursive-import
|
|
|
|
|
%egg-updater
|
|
|
|
|
|
|
|
|
|
;; For tests.
|
|
|
|
|
guix-package->egg-name))
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
;;;
|
|
|
|
|
;;; (guix import egg) provides package importer for CHICKEN eggs. See the
|
|
|
|
|
;;; official specification format for eggs
|
|
|
|
|
;;; <https://wiki.call-cc.org/man/5/Egg%20specification%20format>.
|
|
|
|
|
;;;
|
|
|
|
|
;;; The following happens under the hood:
|
|
|
|
|
;;;
|
2021-11-01 06:55:26 -04:00
|
|
|
|
;;; * <git://code.call-cc.org/eggs-5-all> is a Git repository that contains
|
|
|
|
|
;;; all versions of all CHICKEN eggs. We look clone this repository and, by
|
|
|
|
|
;;; default, retrieve the latest version number, and the PACKAGE.egg file,
|
|
|
|
|
;;; which contains a list of lists containing metadata about the egg.
|
2021-06-02 11:18:22 -04:00
|
|
|
|
;;;
|
|
|
|
|
;;; * All the eggs are stored as tarballs at
|
|
|
|
|
;;; <https://code.call-cc.org/egg-tarballs/5>, so we grab the tarball for
|
|
|
|
|
;;; the egg from there.
|
|
|
|
|
;;;
|
|
|
|
|
;;; * The rest of the package fields will be parsed from the PACKAGE.egg file.
|
|
|
|
|
;;;
|
|
|
|
|
;;; Todos:
|
|
|
|
|
;;;
|
|
|
|
|
;;; * Support for CHICKEN 4?
|
|
|
|
|
;;;
|
2022-11-18 21:26:09 -05:00
|
|
|
|
;;; * Some packages will specify a specific version of a dependency in the
|
2021-06-02 11:18:22 -04:00
|
|
|
|
;;; PACKAGE.egg file, how should we handle this?
|
|
|
|
|
;;;
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Egg metadata fetcher and helper functions.
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
(define package-name-prefix "chicken-")
|
|
|
|
|
|
|
|
|
|
(define %eggs-url
|
|
|
|
|
(make-parameter "https://code.call-cc.org/egg-tarballs/5"))
|
|
|
|
|
|
|
|
|
|
(define %eggs-home-page
|
|
|
|
|
(make-parameter "https://wiki.call-cc.org/egg"))
|
|
|
|
|
|
|
|
|
|
(define (egg-name->guix-name name)
|
|
|
|
|
"Return the package name for CHICKEN egg NAME."
|
|
|
|
|
(string-append package-name-prefix name))
|
|
|
|
|
|
|
|
|
|
(define (eggs-repository)
|
|
|
|
|
"Update or fetch the latest version of the eggs repository and return the path
|
|
|
|
|
to the repository."
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(let* ((url "git://code.call-cc.org/eggs-5-all")
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(directory commit _ (update-cached-checkout url)))
|
|
|
|
|
directory))
|
|
|
|
|
|
|
|
|
|
(define (egg-directory name)
|
|
|
|
|
"Return the directory containing the source code for the egg NAME."
|
|
|
|
|
(let ((eggs-directory (eggs-repository)))
|
|
|
|
|
(string-append eggs-directory "/" name)))
|
|
|
|
|
|
|
|
|
|
(define (find-latest-version name)
|
|
|
|
|
"Get the latest version of the egg NAME."
|
|
|
|
|
(let ((directory (scandir (egg-directory name))))
|
|
|
|
|
(if directory
|
|
|
|
|
(last directory)
|
|
|
|
|
#f)))
|
|
|
|
|
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(define* (egg-metadata name #:key (version #f) (file #f))
|
|
|
|
|
"Return the package metadata file for the egg NAME at version VERSION, or if
|
|
|
|
|
FILE is specified, return the package metadata in FILE."
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(call-with-input-file (or file
|
|
|
|
|
(string-append (egg-directory name) "/"
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(or version
|
|
|
|
|
(find-latest-version name))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
"/" name ".egg"))
|
|
|
|
|
read))
|
|
|
|
|
|
|
|
|
|
(define (guix-name->egg-name name)
|
|
|
|
|
"Return the CHICKEN egg name corresponding to the Guix package NAME."
|
|
|
|
|
(if (string-prefix? package-name-prefix name)
|
|
|
|
|
(string-drop name (string-length package-name-prefix))
|
|
|
|
|
name))
|
|
|
|
|
|
|
|
|
|
(define (guix-package->egg-name package)
|
|
|
|
|
"Return the CHICKEN egg name of the Guix CHICKEN PACKAGE."
|
|
|
|
|
(or (assq-ref (package-properties package) 'upstream-name)
|
|
|
|
|
(guix-name->egg-name (package-name package))))
|
|
|
|
|
|
|
|
|
|
(define (egg-package? package)
|
|
|
|
|
"Check if PACKAGE is an CHICKEN egg package."
|
|
|
|
|
(and (eq? (package-build-system package) chicken-build-system)
|
|
|
|
|
(string-prefix? package-name-prefix (package-name package))))
|
|
|
|
|
|
|
|
|
|
(define string->license
|
|
|
|
|
;; Doesn't seem to use a specific format.
|
|
|
|
|
;; <https://wiki.call-cc.org/eggs-licensing>
|
|
|
|
|
(match-lambda
|
|
|
|
|
("GPL-2" 'license:gpl2)
|
|
|
|
|
("GPL-2+" 'license:gpl2+)
|
|
|
|
|
("GPL-3" 'license:gpl3)
|
|
|
|
|
("GPL-3+" 'license:gpl3+)
|
|
|
|
|
("GPL" 'license:gpl?)
|
|
|
|
|
("AGPL-3" 'license:agpl3)
|
|
|
|
|
("AGPL" 'license:agpl?)
|
|
|
|
|
("LGPL-2.0" 'license:lgpl2.0)
|
|
|
|
|
("LGPL-2.0+" 'license:lgpl2.0+)
|
|
|
|
|
("LGPL-2.1" 'license:lgpl2.1)
|
|
|
|
|
("LGPL-2.1+" 'license:lgpl2.1+)
|
|
|
|
|
("LGPL-3" 'license:lgpl3)
|
|
|
|
|
("LGPL-3" 'license:lgpl3+)
|
|
|
|
|
("LGPL" 'license:lgpl?)
|
|
|
|
|
("BSD-1-Clause" 'license:bsd-1)
|
|
|
|
|
("BSD-2-Clause" 'license:bsd-2)
|
|
|
|
|
("BSD-3-Clause" 'license:bsd-3)
|
|
|
|
|
("BSD" 'license:bsd?)
|
|
|
|
|
("MIT" 'license:expat)
|
|
|
|
|
("ISC" 'license:isc)
|
|
|
|
|
("Artistic-2" 'license:artistic2.0)
|
|
|
|
|
("Apache-2.0" 'license:asl2.0)
|
|
|
|
|
("Public Domain" 'license:public-domain)
|
|
|
|
|
((x) (string->license x))
|
|
|
|
|
((lst ...) `(list ,@(map string->license lst)))
|
|
|
|
|
(_ #f)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Egg importer.
|
|
|
|
|
;;;
|
|
|
|
|
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(define* (egg->guix-package name version #:key (file #f) (source #f))
|
|
|
|
|
"Import a CHICKEN egg called NAME from either the given .egg FILE, or from the
|
|
|
|
|
latest NAME metadata downloaded from the official repository if FILE is #f.
|
|
|
|
|
Return a <package> record or #f on failure. If VERSION is specified, import
|
|
|
|
|
the particular version from the egg repository.
|
2021-06-21 08:44:47 -04:00
|
|
|
|
|
|
|
|
|
SOURCE is a ``file-like'' object containing the source code corresponding to
|
|
|
|
|
the egg. If SOURCE is not specified, the latest tarball for egg NAME will be
|
|
|
|
|
downloaded.
|
2021-06-02 11:18:22 -04:00
|
|
|
|
|
|
|
|
|
Specifying the SOURCE argument is mainly useful for developing a CHICKEN egg
|
|
|
|
|
locally. Note that if FILE and SOURCE are specified, recursive import will
|
|
|
|
|
not work."
|
|
|
|
|
(define egg-content (if file
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(egg-metadata name #:file file)
|
|
|
|
|
(egg-metadata name #:version version)))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(if (not egg-content)
|
|
|
|
|
(values #f '()) ; egg doesn't exist
|
|
|
|
|
(let* ((version* (or (assoc-ref egg-content 'version)
|
|
|
|
|
(find-latest-version name)))
|
|
|
|
|
(version (if (list? version*) (first version*) version*))
|
2022-06-28 15:01:11 -04:00
|
|
|
|
(source-url (if source #f `(egg-uri ,name version)))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(tarball (if source
|
|
|
|
|
#f
|
|
|
|
|
(with-store store
|
2021-08-12 03:17:20 -04:00
|
|
|
|
(download-to-store
|
|
|
|
|
store (egg-uri name version))))))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
|
|
|
|
|
(define egg-home-page
|
|
|
|
|
(string-append (%eggs-home-page) "/" name))
|
|
|
|
|
|
|
|
|
|
(define egg-synopsis
|
|
|
|
|
(match (assoc-ref egg-content 'synopsis)
|
|
|
|
|
((synopsis) synopsis)
|
|
|
|
|
(_ #f)))
|
|
|
|
|
|
|
|
|
|
(define egg-licenses
|
|
|
|
|
(let ((licenses*
|
|
|
|
|
(match (assoc-ref egg-content 'license)
|
|
|
|
|
((license)
|
|
|
|
|
(map string->license (string-split license #\/)))
|
|
|
|
|
(#f
|
|
|
|
|
'()))))
|
|
|
|
|
(match licenses*
|
|
|
|
|
((license) license)
|
|
|
|
|
((license1 license2 ...) `(list ,@licenses*)))))
|
|
|
|
|
|
|
|
|
|
(define (maybe-symbol->string sym)
|
|
|
|
|
(if (symbol? sym) (symbol->string sym) sym))
|
|
|
|
|
|
|
|
|
|
(define (prettify-system-dependency name)
|
|
|
|
|
;; System dependencies sometimes have spaces and/or upper case
|
|
|
|
|
;; letters in them.
|
|
|
|
|
;;
|
|
|
|
|
;; There will probably still be some weird edge cases.
|
|
|
|
|
(string-map (lambda (char)
|
|
|
|
|
(case char
|
|
|
|
|
((#\space) #\-)
|
|
|
|
|
(else char)))
|
|
|
|
|
(maybe-symbol->string name)))
|
|
|
|
|
|
|
|
|
|
(define* (egg-parse-dependency name #:key (system? #f))
|
|
|
|
|
(define extract-name
|
|
|
|
|
(match-lambda
|
|
|
|
|
((name version) name)
|
|
|
|
|
(name name)))
|
|
|
|
|
|
|
|
|
|
(define (prettify-name name)
|
|
|
|
|
(if system?
|
|
|
|
|
(prettify-system-dependency name)
|
|
|
|
|
(maybe-symbol->string name)))
|
|
|
|
|
|
|
|
|
|
(let ((name (prettify-name (extract-name name))))
|
|
|
|
|
;; Dependencies are sometimes specified as symbols and sometimes
|
|
|
|
|
;; as strings
|
2021-07-14 21:40:34 -04:00
|
|
|
|
(string->symbol (string-append
|
|
|
|
|
(if system? "" package-name-prefix)
|
|
|
|
|
name))))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
|
|
|
|
|
(define egg-propagated-inputs
|
|
|
|
|
(let ((dependencies (assoc-ref egg-content 'dependencies)))
|
|
|
|
|
(if (list? dependencies)
|
|
|
|
|
(map egg-parse-dependency
|
|
|
|
|
dependencies)
|
|
|
|
|
'())))
|
|
|
|
|
|
|
|
|
|
;; TODO: Or should these be propagated?
|
|
|
|
|
(define egg-inputs
|
|
|
|
|
(let ((dependencies (assoc-ref egg-content 'foreign-dependencies)))
|
|
|
|
|
(if (list? dependencies)
|
|
|
|
|
(map (lambda (name)
|
|
|
|
|
(egg-parse-dependency name #:system? #t))
|
|
|
|
|
dependencies)
|
|
|
|
|
'())))
|
|
|
|
|
|
|
|
|
|
(define egg-native-inputs
|
|
|
|
|
(let* ((test-dependencies (or (assoc-ref egg-content
|
|
|
|
|
'test-dependencies)
|
|
|
|
|
'()))
|
|
|
|
|
(build-dependencies (or (assoc-ref egg-content
|
|
|
|
|
'build-dependencies)
|
|
|
|
|
'()))
|
|
|
|
|
(test+build-dependencies (append test-dependencies
|
|
|
|
|
build-dependencies)))
|
|
|
|
|
(match test+build-dependencies
|
|
|
|
|
((_ _ ...) (map egg-parse-dependency
|
|
|
|
|
test+build-dependencies))
|
|
|
|
|
(() '()))))
|
|
|
|
|
|
|
|
|
|
;; Copied from (guix import hackage).
|
|
|
|
|
(define (maybe-inputs input-type inputs)
|
|
|
|
|
(match inputs
|
|
|
|
|
(()
|
|
|
|
|
'())
|
|
|
|
|
((inputs ...)
|
|
|
|
|
(list (list input-type
|
2021-07-14 21:40:34 -04:00
|
|
|
|
`(list ,@inputs))))))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
|
|
|
|
|
(values
|
|
|
|
|
`(package
|
|
|
|
|
(name ,(egg-name->guix-name name))
|
|
|
|
|
(version ,version)
|
|
|
|
|
(source
|
|
|
|
|
,(if source
|
|
|
|
|
source
|
|
|
|
|
`(origin
|
|
|
|
|
(method url-fetch)
|
|
|
|
|
(uri ,source-url)
|
|
|
|
|
(sha256
|
|
|
|
|
(base32 ,(if tarball
|
|
|
|
|
(bytevector->nix-base32-string
|
|
|
|
|
(file-sha256 tarball))
|
|
|
|
|
"failed to download tar archive"))))))
|
|
|
|
|
(build-system chicken-build-system)
|
|
|
|
|
(arguments ,(list 'quasiquote (list #:egg-name name)))
|
|
|
|
|
,@(maybe-inputs 'native-inputs egg-native-inputs)
|
|
|
|
|
,@(maybe-inputs 'inputs egg-inputs)
|
|
|
|
|
,@(maybe-inputs 'propagated-inputs egg-propagated-inputs)
|
|
|
|
|
(home-page ,egg-home-page)
|
|
|
|
|
(synopsis ,egg-synopsis)
|
|
|
|
|
(description #f)
|
|
|
|
|
(license ,egg-licenses))
|
|
|
|
|
(filter (lambda (name)
|
|
|
|
|
(not (member name '("srfi-4"))))
|
2021-07-14 21:40:34 -04:00
|
|
|
|
(map (compose guix-name->egg-name symbol->string)
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(append egg-propagated-inputs
|
|
|
|
|
egg-native-inputs)))))))
|
|
|
|
|
|
|
|
|
|
(define egg->guix-package/m ;memoized variant
|
|
|
|
|
(memoize egg->guix-package))
|
|
|
|
|
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(define* (egg-recursive-import package-name #:optional version)
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(recursive-import package-name
|
2021-11-01 06:55:26 -04:00
|
|
|
|
#:version version
|
2021-06-02 11:18:22 -04:00
|
|
|
|
#:repo->guix-package (lambda* (name #:key version repo)
|
2021-11-01 06:55:26 -04:00
|
|
|
|
(egg->guix-package/m name version))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
#:guix-name egg-name->guix-name))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
;;; Updater.
|
|
|
|
|
;;;
|
|
|
|
|
|
2022-06-28 15:07:05 -04:00
|
|
|
|
(define* (import-release package #:key (version #f))
|
|
|
|
|
"Return an @code{<upstream-source>} for the latest release of PACKAGE.
|
|
|
|
|
Optionally include a VERSION string to fetch a specific version."
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(let* ((egg-name (guix-package->egg-name package))
|
2022-06-28 15:07:05 -04:00
|
|
|
|
(version (or version (find-latest-version egg-name)))
|
2022-06-28 15:01:11 -04:00
|
|
|
|
(source-url (egg-uri egg-name version)))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
(upstream-source
|
|
|
|
|
(package (package-name package))
|
|
|
|
|
(version version)
|
|
|
|
|
(urls (list source-url)))))
|
|
|
|
|
|
|
|
|
|
(define %egg-updater
|
|
|
|
|
(upstream-updater
|
|
|
|
|
(name 'egg)
|
|
|
|
|
(description "Updater for CHICKEN egg packages")
|
|
|
|
|
(pred egg-package?)
|
2022-06-28 15:07:05 -04:00
|
|
|
|
(import import-release)))
|
2021-06-02 11:18:22 -04:00
|
|
|
|
|
|
|
|
|
;;; egg.scm ends here
|