GNU bug report logs - #36760
[PATCH 0/3] Switch to Guile-JSON 3.x

Previous Next

Package: guix-patches;

Reported by: Ludovic Courtès <ludo <at> gnu.org>

Date: Mon, 22 Jul 2019 10:15:02 UTC

Severity: normal

Tags: patch

Done: Ludovic Courtès <ludo <at> gnu.org>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 36760 in the body.
You can then email your comments to 36760 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Mon, 22 Jul 2019 10:15:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Ludovic Courtès <ludo <at> gnu.org>:
New bug report received and forwarded. Copy sent to guix-patches <at> gnu.org. (Mon, 22 Jul 2019 10:15:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: guix-patches <at> gnu.org
Cc: Ludovic Courtès <ludo <at> gnu.org>
Subject: [PATCH 0/3] Switch to Guile-JSON 3.x
Date: Mon, 22 Jul 2019 12:13:37 +0200
Hello Guix!

This is the big switch to Guile-JSON 3.x!

As a reminder, Guile-JSON 3.x changes the mapping between JSON data
structures and Scheme data structures in an incompatible way compared
to 1.x.  Essentially, JSON dictionaries now map to alists (instead of
hash tables), and JSON arrays map to vectors (instead of lists.)

The patch updates all the code in one go, mostly because a single Guile
process cannot have two different (json) modules loaded at the same
time.

When we update the ‘guix’ package, everything that depends on it will
also have to be updated to a snapshot that uses Guile-JSON 3.x: cuirass,
hpcguix-web, and rcas-web.  I count on you, dear reader, to help in
those areas.  :-)

Comments?

Ludo’.

Ludovic Courtès (3):
  maint: Switch to Guile-JSON 3.x.
  gnu: guile-json: Define 'guile-json-1'.
  gnu: Explicitly refer to 'guile-json-1' when needed.

 configure.ac                        |  4 ++--
 doc/guix.texi                       |  2 +-
 gnu/installer.scm                   |  4 ++--
 gnu/installer/locale.scm            | 21 +++++++++--------
 gnu/packages/bioinformatics.scm     |  2 +-
 gnu/packages/ci.scm                 |  2 +-
 gnu/packages/guile-xyz.scm          |  6 ++---
 gnu/packages/guile.scm              |  4 ++++
 gnu/packages/mail.scm               |  4 ++--
 gnu/packages/package-management.scm |  4 ++--
 gnu/packages/web.scm                |  2 +-
 gnu/system/vm.scm                   |  2 +-
 guix/docker.scm                     | 19 ++++++++--------
 guix/git-download.scm               |  4 ++--
 guix/import/cpan.scm                | 14 ++++++------
 guix/import/crate.scm               |  6 ++---
 guix/import/gem.scm                 | 10 ++++++---
 guix/import/json.scm                | 11 ++-------
 guix/import/pypi.scm                |  8 +++----
 guix/import/stackage.scm            |  4 ++--
 guix/import/utils.scm               | 25 +++++----------------
 guix/scripts/import/json.scm        |  2 +-
 guix/scripts/pack.scm               |  2 +-
 guix/self.scm                       |  2 +-
 guix/swh.scm                        | 35 ++++++++++++++++-------------
 m4/guix.m4                          | 21 +++++++++++++++++
 tests/import-utils.scm              | 22 ++++++++++++++++++
 27 files changed, 140 insertions(+), 102 deletions(-)

-- 
2.22.0





Information forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Mon, 22 Jul 2019 10:20:01 GMT) Full text and rfc822 format available.

Message #8 received at 36760 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: 36760 <at> debbugs.gnu.org
Cc: Ludovic Courtès <ludo <at> gnu.org>
Subject: [PATCH 1/3] maint: Switch to Guile-JSON 3.x.
Date: Mon, 22 Jul 2019 12:18:41 +0200
* m4/guix.m4 (GUIX_CHECK_GUILE_JSON): New macro.
* configure.ac: Use it.
* doc/guix.texi (Requirements): Mention the Guile-JSON version.
* guix/git-download.scm (git-fetch)[guile-json]: Use GUILE-JSON-3.
* guix/import/cpan.scm (string->license): Expect vectors instead of
lists.
(module->dist-name): Use 'json-fetch' instead of 'json-fetch-alist'.
(cpan-fetch): Likewise.
* guix/import/crate.scm (crate-fetch): Likewise, and call 'vector->list'
for DEPS.
* guix/import/gem.scm (rubygems-fetch): Likewise.
* guix/import/json.scm (json-fetch-alist): Remove.
* guix/import/pypi.scm (pypi-fetch): Use 'json-fetch' instead of
'json-fetch-alist'.
(latest-source-release, latest-wheel-release): Call 'vector->list' on
RELEASES.
* guix/import/stackage.scm (stackage-lts-info-fetch): Use 'json-fetch'
instead of 'json-fetch-alist'.
(lts-package-version): Use 'vector->list'.
* guix/import/utils.scm (hash-table->alist): Remove.
(alist->package): Pass 'vector->list' on the inputs fields, and default
to the empty vector.
* guix/scripts/import/json.scm (guix-import-json): Remove call to
'hash-table->alist'.
* guix/swh.scm (define-json-reader): Expect pair? or null? instead of
hash-table?.
[extract-field]: Use 'assoc-ref' instead of 'hash-ref'.
(json->branches): Use 'map' instead of 'hash-map->list'.
(json->checksums): Likewise.
(json->directory-entries, origin-visits): Call 'vector->list' on the
result of 'json->scm'.
* tests/import-utils.scm ("alist->package with dependencies"): New test.
* gnu/installer.scm (build-compiled-file)[builder]: Use GUILE-JSON-3.
* gnu/installer.scm (installer-program)[installer-builder]: Likewise.
* gnu/installer/locale.scm (iso639->iso639-languages): Use 'assoc-ref'
instead of 'hash-ref', and pass vectors through 'vector->list'.
(iso3166->iso3166-territories): Likewise.
* gnu/system/vm.scm (system-docker-image)[build]: Use GUILE-JSON-3.
* guix/docker.scm (manifest, config): Adjust for Guile-JSON 3.
* guix/scripts/pack.scm (docker-image)[build]: Use GUILE-JSON-3.
---
 configure.ac                 |  4 ++--
 doc/guix.texi                |  2 +-
 gnu/installer.scm            |  4 ++--
 gnu/installer/locale.scm     | 21 ++++++++++++---------
 gnu/system/vm.scm            |  2 +-
 guix/docker.scm              | 19 ++++++++++---------
 guix/git-download.scm        |  4 ++--
 guix/import/cpan.scm         | 14 +++++++-------
 guix/import/crate.scm        |  6 +++---
 guix/import/gem.scm          | 10 +++++++---
 guix/import/json.scm         | 11 ++---------
 guix/import/pypi.scm         |  8 ++++----
 guix/import/stackage.scm     |  4 ++--
 guix/import/utils.scm        | 25 ++++++-------------------
 guix/scripts/import/json.scm |  2 +-
 guix/scripts/pack.scm        |  2 +-
 guix/self.scm                |  2 +-
 guix/swh.scm                 | 35 +++++++++++++++++++----------------
 m4/guix.m4                   | 21 +++++++++++++++++++++
 tests/import-utils.scm       | 22 ++++++++++++++++++++++
 20 files changed, 126 insertions(+), 92 deletions(-)

diff --git a/configure.ac b/configure.ac
index 3918550a79..689b28d984 100644
--- a/configure.ac
+++ b/configure.ac
@@ -119,8 +119,8 @@ if test "x$have_guile_git" != "xyes"; then
 fi
 
 dnl Check for Guile-JSON.
-GUILE_MODULE_AVAILABLE([have_guile_json], [(json)])
-if test "x$have_guile_json" != "xyes"; then
+GUIX_CHECK_GUILE_JSON
+if test "x$guix_cv_have_recent_guile_json" != "xyes"; then
   AC_MSG_ERROR([Guile-JSON is missing; please install it.])
 fi
 
diff --git a/doc/guix.texi b/doc/guix.texi
index 107c16b8db..3a37555721 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -746,7 +746,7 @@ or later;
 @c FIXME: Specify a version number once a release has been made.
 @uref{https://gitlab.com/guile-git/guile-git, Guile-Git}, from August
 2017 or later;
-@item @uref{https://savannah.nongnu.org/projects/guile-json/, Guile-JSON};
+@item @uref{https://savannah.nongnu.org/projects/guile-json/, Guile-JSON} 3.x;
 @item @url{https://zlib.net, zlib};
 @item @url{https://www.gnu.org/software/make/, GNU Make}.
 @end itemize
diff --git a/gnu/installer.scm b/gnu/installer.scm
index 1452c4dc7e..15d971dfc4 100644
--- a/gnu/installer.scm
+++ b/gnu/installer.scm
@@ -69,7 +69,7 @@ version of this file."
         (setlocale LC_ALL "en_US.utf8")))
 
   (define builder
-    (with-extensions (list guile-json)
+    (with-extensions (list guile-json-3)
       (with-imported-modules (source-module-closure
                               '((gnu installer locale)))
         #~(begin
@@ -313,7 +313,7 @@ selected keymap."
     ;; packages …), etc. modules.
     (with-extensions (list guile-gcrypt guile-newt
                            guile-parted guile-bytestructures
-                           guile-json guile-git guix)
+                           guile-json-3 guile-git guix)
       (with-imported-modules `(,@(source-module-closure
                                   `(,@modules
                                     (gnu services herd)
diff --git a/gnu/installer/locale.scm b/gnu/installer/locale.scm
index 13f3a1e881..ccffb6d8ef 100644
--- a/gnu/installer/locale.scm
+++ b/gnu/installer/locale.scm
@@ -134,16 +134,18 @@ ISO639-3 and ISO639-5 files."
         (lambda (port-iso639-5)
           (filter-map
            (lambda (hash)
-             (let ((alpha2 (hash-ref hash "alpha_2"))
-                   (alpha3 (hash-ref hash "alpha_3"))
-                   (name   (hash-ref hash "name")))
+             (let ((alpha2 (assoc-ref hash "alpha_2"))
+                   (alpha3 (assoc-ref hash "alpha_3"))
+                   (name   (assoc-ref hash "name")))
                (and (supported-locale? locales alpha2 alpha3)
                     `((alpha2 . ,alpha2)
                       (alpha3 . ,alpha3)
                       (name   . ,name)))))
            (append
-            (hash-ref (json->scm port-iso639-3) "639-3")
-            (hash-ref (json->scm port-iso639-5) "639-5"))))))))
+            (vector->list
+             (assoc-ref (json->scm port-iso639-3) "639-3"))
+            (vector->list
+             (assoc-ref (json->scm port-iso639-5) "639-5")))))))))
 
 (define (language-code->language-name languages language-code)
   "Using LANGUAGES as a list of ISO639 association lists, return the language
@@ -179,10 +181,11 @@ ISO3166 file."
   (call-with-input-file iso3166
     (lambda (port)
       (map (lambda (hash)
-             `((alpha2 . ,(hash-ref hash "alpha_2"))
-               (alpha3 . ,(hash-ref hash "alpha_3"))
-               (name   . ,(hash-ref hash "name"))))
-           (hash-ref (json->scm port) "3166-1")))))
+             `((alpha2 . ,(assoc-ref hash "alpha_2"))
+               (alpha3 . ,(assoc-ref hash "alpha_3"))
+               (name   . ,(assoc-ref hash "name"))))
+           (vector->list
+            (assoc-ref (json->scm port) "3166-1"))))))
 
 (define (territory-code->territory-name territories territory-code)
   "Using TERRITORIES as a list of ISO3166 association lists return the
diff --git a/gnu/system/vm.scm b/gnu/system/vm.scm
index e7f7d8ca51..ac6e4ded92 100644
--- a/gnu/system/vm.scm
+++ b/gnu/system/vm.scm
@@ -514,7 +514,7 @@ system."
         (name  (string-append name ".tar.gz"))
         (graph "system-graph"))
     (define build
-      (with-extensions (cons guile-json           ;for (guix docker)
+      (with-extensions (cons guile-json-3         ;for (guix docker)
                              gcrypt-sqlite3&co)   ;for (guix store database)
         (with-imported-modules `(,@(source-module-closure
                                     '((guix docker)
diff --git a/guix/docker.scm b/guix/docker.scm
index b1bd226fa1..c598a073f6 100644
--- a/guix/docker.scm
+++ b/guix/docker.scm
@@ -62,9 +62,9 @@
 
 (define (manifest path id)
   "Generate a simple image manifest."
-  `(((Config . "config.json")
-     (RepoTags . (,(generate-tag path)))
-     (Layers . (,(string-append id "/layer.tar"))))))
+  `#(((Config . "config.json")
+      (RepoTags . #(,(generate-tag path)))
+      (Layers . #(,(string-append id "/layer.tar"))))))
 
 ;; According to the specifications this is required for backwards
 ;; compatibility.  It duplicates information provided by the manifest.
@@ -81,17 +81,18 @@
   `((architecture . ,arch)
     (comment . "Generated by GNU Guix")
     (created . ,time)
-    (config . ,`((env . ,(map (match-lambda
-                                ((name . value)
-                                 (string-append name "=" value)))
-                              environment))
+    (config . ,`((env . ,(list->vector
+                          (map (match-lambda
+                                 ((name . value)
+                                  (string-append name "=" value)))
+                               environment)))
                  ,@(if entry-point
-                       `((entrypoint . ,entry-point))
+                       `((entrypoint . ,(list->vector entry-point)))
                        '())))
     (container_config . #nil)
     (os . "linux")
     (rootfs . ((type . "layers")
-               (diff_ids . (,(layer-diff-id layer)))))))
+               (diff_ids . #(,(layer-diff-id layer)))))))
 
 (define %tar-determinism-options
   ;; GNU tar options to produce archives deterministically.
diff --git a/guix/git-download.scm b/guix/git-download.scm
index f904d11c25..8f84681d46 100644
--- a/guix/git-download.scm
+++ b/guix/git-download.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo <at> gnu.org>
+;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2017 Mathieu Lirzin <mthl <at> gnu.org>
 ;;; Copyright © 2017 Christopher Baines <mail <at> cbaines.net>
 ;;;
@@ -85,7 +85,7 @@ HASH-ALGO (a symbol).  Use NAME as the file name, or a generic name if #f."
     (module-ref (resolve-interface '(gnu packages compression)) 'zlib))
 
   (define guile-json
-    (module-ref (resolve-interface '(gnu packages guile)) 'guile-json))
+    (module-ref (resolve-interface '(gnu packages guile)) 'guile-json-3))
 
   (define gnutls
     (module-ref (resolve-interface '(gnu packages tls)) 'gnutls))
diff --git a/guix/import/cpan.scm b/guix/import/cpan.scm
index d4bea84353..ec86f11743 100644
--- a/guix/import/cpan.scm
+++ b/guix/import/cpan.scm
@@ -76,8 +76,8 @@
    ;; ssleay
    ;; sun
    ("zlib" 'zlib)
-   ((x) (string->license x))
-   ((lst ...) `(list ,@(map string->license lst)))
+   (#(x) (string->license x))
+   (#(lst ...) `(list ,@(map string->license lst)))
    (_ #f)))
 
 (define (module->name module)
@@ -88,10 +88,10 @@
   "Return the base distribution module for a given module.  E.g. the 'ok'
 module is distributed with 'Test::Simple', so (module->dist-name \"ok\") would
 return \"Test-Simple\""
-  (assoc-ref (json-fetch-alist (string-append
-                                "https://fastapi.metacpan.org/v1/module/"
-                                module
-                                "?fields=distribution"))
+  (assoc-ref (json-fetch (string-append
+                          "https://fastapi.metacpan.org/v1/module/"
+                          module
+                          "?fields=distribution"))
              "distribution"))
 
 (define (package->upstream-name package)
@@ -114,7 +114,7 @@ return \"Test-Simple\""
   "Return an alist representation of the CPAN metadata for the perl module MODULE,
 or #f on failure.  MODULE should be e.g. \"Test::Script\""
   ;; This API always returns the latest release of the module.
-  (json-fetch-alist (string-append "https://fastapi.metacpan.org/v1/release/" name)))
+  (json-fetch (string-append "https://fastapi.metacpan.org/v1/release/" name)))
 
 (define (cpan-home name)
   (string-append "https://metacpan.org/release/" name))
diff --git a/guix/import/crate.scm b/guix/import/crate.scm
index 29318aac0e..52c5cb1c30 100644
--- a/guix/import/crate.scm
+++ b/guix/import/crate.scm
@@ -51,7 +51,7 @@
   (define (crate-kind-predicate kind)
     (lambda (dep) (string=? (assoc-ref dep "kind") kind)))
 
-  (and-let* ((crate-json (json-fetch-alist (string-append crate-url crate-name)))
+  (and-let* ((crate-json (json-fetch (string-append crate-url crate-name)))
              (crate (assoc-ref crate-json "crate"))
              (name (assoc-ref crate "name"))
              (version (assoc-ref crate "max_version"))
@@ -63,8 +63,8 @@
                                  string->license)
                           '()))                   ;missing license info
              (path (string-append "/" version "/dependencies"))
-             (deps-json (json-fetch-alist (string-append crate-url name path)))
-             (deps (assoc-ref deps-json "dependencies"))
+             (deps-json (json-fetch (string-append crate-url name path)))
+             (deps (vector->list (assoc-ref deps-json "dependencies")))
              (dep-crates (filter (crate-kind-predicate "normal") deps))
              (dev-dep-crates
               (filter (lambda (dep)
diff --git a/guix/import/gem.scm b/guix/import/gem.scm
index ea576b5e4a..0bf9ff2552 100644
--- a/guix/import/gem.scm
+++ b/guix/import/gem.scm
@@ -40,7 +40,7 @@
 (define (rubygems-fetch name)
   "Return an alist representation of the RubyGems metadata for the package NAME,
 or #f on failure."
-  (json-fetch-alist
+  (json-fetch
    (string-append "https://rubygems.org/api/v1/gems/" name ".json")))
 
 (define (ruby-package-name name)
@@ -130,14 +130,18 @@ VERSION, HASH, HOME-PAGE, DESCRIPTION, DEPENDENCIES, and LICENSES."
                                (assoc-ref package "info")))
                 (home-page    (assoc-ref package "homepage_uri"))
                 (dependencies-names (map (lambda (dep) (assoc-ref dep "name"))
-                                         (assoc-ref* package "dependencies" "runtime")))
+                                         (vector->list
+                                          (assoc-ref* package
+                                                      "dependencies"
+                                                      "runtime"))))
                 (dependencies (map (lambda (dep)
                                      (if (string=? dep "bundler")
                                          "bundler" ; special case, no prefix
                                          (ruby-package-name dep)))
                                    dependencies-names))
                 (licenses     (map string->license
-                                   (assoc-ref package "licenses"))))
+                                   (vector->list
+                                    (assoc-ref package "licenses")))))
            (values (make-gem-sexp name version hash home-page synopsis
                                   description dependencies licenses)
                    dependencies-names)))))
diff --git a/guix/import/json.scm b/guix/import/json.scm
index 81ea5e7b31..8900724dcd 100644
--- a/guix/import/json.scm
+++ b/guix/import/json.scm
@@ -1,7 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 David Thompson <davet <at> gnu.org>
 ;;; Copyright © 2015, 2016 Eric Bavier <bavier <at> member.fsf.org>
-;;; Copyright © 2018 Ludovic Courtès <ludo <at> gnu.org>
+;;; Copyright © 2018, 2019 Ludovic Courtès <ludo <at> gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -23,8 +23,7 @@
   #:use-module (guix http-client)
   #:use-module (guix import utils)
   #:use-module (srfi srfi-34)
-  #:export (json-fetch
-            json-fetch-alist))
+  #:export (json-fetch))
 
 (define* (json-fetch url
                      ;; Note: many websites returns 403 if we omit a
@@ -43,9 +42,3 @@ the query."
            (result (json->scm port)))
       (close-port port)
       result)))
-
-(define (json-fetch-alist url)
-  "Return an alist representation of the JSON resource URL, or #f if URL
-returns 403 or 404."
-  (and=> (json-fetch url)
-         hash-table->alist))
diff --git a/guix/import/pypi.scm b/guix/import/pypi.scm
index ab7a024ee0..9b3d80a02e 100644
--- a/guix/import/pypi.scm
+++ b/guix/import/pypi.scm
@@ -1,7 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2014 David Thompson <davet <at> gnu.org>
 ;;; Copyright © 2015 Cyril Roelandt <tipecaml <at> gmail.com>
-;;; Copyright © 2015, 2016, 2017 Ludovic Courtès <ludo <at> gnu.org>
+;;; Copyright © 2015, 2016, 2017, 2019 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe <at> gmail.com>
 ;;; Copyright © 2018 Ricardo Wurmus <rekado <at> elephly.net>
 ;;; Copyright © 2019 Maxim Cournoyer <maxim.cournoyer <at> gmail.com>
@@ -56,7 +56,7 @@
 (define (pypi-fetch name)
   "Return an alist representation of the PyPI metadata for the package NAME,
 or #f on failure."
-  (json-fetch-alist (string-append "https://pypi.org/pypi/" name "/json")))
+  (json-fetch (string-append "https://pypi.org/pypi/" name "/json")))
 
 ;; For packages found on PyPI that lack a source distribution.
 (define-condition-type &missing-source-error &error
@@ -69,7 +69,7 @@ or #f on failure."
                               (assoc-ref* pypi-package "info" "version"))))
     (or (find (lambda (release)
                 (string=? "sdist" (assoc-ref release "packagetype")))
-              releases)
+              (vector->list releases))
         (raise (condition (&missing-source-error
                            (package pypi-package)))))))
 
@@ -80,7 +80,7 @@ or #f if there isn't any."
                               (assoc-ref* pypi-package "info" "version"))))
     (or (find (lambda (release)
                 (string=? "bdist_wheel" (assoc-ref release "packagetype")))
-              releases)
+              (vector->list releases))
         #f)))
 
 (define (python->package-name name)
diff --git a/guix/import/stackage.scm b/guix/import/stackage.scm
index 1c1e73a723..194bea633e 100644
--- a/guix/import/stackage.scm
+++ b/guix/import/stackage.scm
@@ -60,7 +60,7 @@
      (let* ((url (if (string=? "" version)
                      (string-append %stackage-url "/lts")
                      (string-append %stackage-url "/lts-" version)))
-            (lts-info (json-fetch-alist url)))
+            (lts-info (json-fetch url)))
        (if lts-info
            (reverse lts-info)
            (leave-with-message "LTS release version not found: ~a" version))))))
@@ -74,7 +74,7 @@
 (define (lts-package-version pkgs-info name)
   "Return the version of the package with upstream NAME included in PKGS-INFO."
   (let ((pkg (find (lambda (pkg) (string=? (stackage-package-name pkg) name))
-                   pkgs-info)))
+                   (vector->list pkgs-info))))
     (stackage-package-version pkg)))
 
 
diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index 84503ab907..2a3b7341fb 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -45,7 +45,6 @@
   #:use-module (srfi srfi-41)
   #:export (factorize-uri
 
-            hash-table->alist
             flatten
             assoc-ref*
 
@@ -100,21 +99,6 @@ of the string VERSION is replaced by the symbol 'version."
                '()
                indices))))))
 
-(define (hash-table->alist table)
-  "Return an alist represenation of TABLE."
-  (map (match-lambda
-        ((key . (lst ...))
-         (cons key
-               (map (lambda (x)
-                      (if (hash-table? x)
-                          (hash-table->alist x)
-                          x))
-                    lst)))
-        ((key . (? hash-table? table))
-         (cons key (hash-table->alist table)))
-        (pair pair))
-       (hash-map->list cons table)))
-
 (define (flatten lst)
   "Return a list that recursively concatenates all sub-lists of LST."
   (fold-right
@@ -330,11 +314,14 @@ the expected fields of an <origin> object."
       (lookup-build-system-by-name
        (string->symbol (assoc-ref meta "build-system"))))
     (native-inputs
-     (specs->package-lists (or (assoc-ref meta "native-inputs") '())))
+     (specs->package-lists
+      (vector->list (or (assoc-ref meta "native-inputs") '#()))))
     (inputs
-     (specs->package-lists (or (assoc-ref meta "inputs") '())))
+     (specs->package-lists
+      (vector->list (or (assoc-ref meta "inputs") '#()))))
     (propagated-inputs
-     (specs->package-lists (or (assoc-ref meta "propagated-inputs") '())))
+     (specs->package-lists
+      (vector->list (or (assoc-ref meta "propagated-inputs") '#()))))
     (home-page
      (assoc-ref meta "home-page"))
     (synopsis
diff --git a/guix/scripts/import/json.scm b/guix/scripts/import/json.scm
index 8771e7b0eb..c9daf65479 100644
--- a/guix/scripts/import/json.scm
+++ b/guix/scripts/import/json.scm
@@ -93,7 +93,7 @@ Import and convert the JSON package definition in PACKAGE-FILE.\n"))
            (let ((json (json-string->scm
                         (with-input-from-file file-name read-string))))
              ;; TODO: also print define-module boilerplate
-             (package->code (alist->package (hash-table->alist json)))))
+             (package->code (alist->package json))))
          (lambda _
            (leave (G_ "invalid JSON in file '~a'~%") file-name))))
       (()
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index 01472d9768..fdb98983bf 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -479,7 +479,7 @@ the image."
 
   (define build
     ;; Guile-JSON and Guile-Gcrypt are required by (guix docker).
-    (with-extensions (list guile-json guile-gcrypt)
+    (with-extensions (list guile-json-3 guile-gcrypt)
       (with-imported-modules `(((guix config) => ,(make-config.scm))
                                ,@(source-module-closure
                                   `((guix docker)
diff --git a/guix/self.scm b/guix/self.scm
index 838ede7690..f03fe01d0c 100644
--- a/guix/self.scm
+++ b/guix/self.scm
@@ -50,7 +50,7 @@
                (module-ref (resolve-interface module) variable))))
     (match-lambda
       ("guile"      (ref '(gnu packages commencement) 'guile-final))
-      ("guile-json" (ref '(gnu packages guile) 'guile-json))
+      ("guile-json" (ref '(gnu packages guile) 'guile-json-3))
       ("guile-ssh"  (ref '(gnu packages ssh)   'guile-ssh))
       ("guile-git"  (ref '(gnu packages guile) 'guile-git))
       ("guile-sqlite3" (ref '(gnu packages guile) 'guile-sqlite3))
diff --git a/guix/swh.scm b/guix/swh.scm
index d692f81806..df2a138f04 100644
--- a/guix/swh.scm
+++ b/guix/swh.scm
@@ -138,16 +138,16 @@ following SPEC, a series of field specifications."
                         (json->scm input))
                        ((string? input)
                         (json-string->scm input))
-                       ((hash-table? input)
+                       ((or (null? input) (pair? input))
                         input))))
       (let-syntax ((extract-field (syntax-rules ()
                                     ((_ table (field key json->value))
-                                     (json->value (hash-ref table key)))
+                                     (json->value (assoc-ref table key)))
                                     ((_ table (field key))
-                                     (hash-ref table key))
+                                     (assoc-ref table key))
                                     ((_ table (field))
-                                     (hash-ref table
-                                               (symbol->string 'field))))))
+                                     (assoc-ref table
+                                                (symbol->string 'field))))))
         (ctor (extract-field table spec) ...)))))
 
 (define-syntax-rule (define-json-mapping rtd ctor pred json->record
@@ -257,12 +257,13 @@ FALSE-IF-404? is true, return #f upon 404 responses."
   (target-url   branch-target-url))
 
 (define (json->branches branches)
-  (hash-map->list (lambda (key value)
-                    (make-branch key
-                                 (string->symbol
-                                  (hash-ref value "target_type"))
-                                 (hash-ref value "target_url")))
-                  branches))
+  (map (match-lambda
+         ((key . value)
+          (make-branch key
+                       (string->symbol
+                        (assoc-ref value "target_type"))
+                       (assoc-ref value "target_url"))))
+       branches))
 
 ;; <https://archive.softwareheritage.org/api/1/release/1f44934fb6e2cefccbecd4fa347025349fa9ff76/>
 (define-json-mapping <release> make-release release?
@@ -292,9 +293,10 @@ FALSE-IF-404? is true, return #f upon 404 responses."
   (license-url   content-license-url "license_url"))
 
 (define (json->checksums checksums)
-  (hash-map->list (lambda (key value)
-                    (cons key (base16-string->bytevector value)))
-                  checksums))
+  (map (match-lambda
+         ((key . value)
+          (cons key (base16-string->bytevector value))))
+       checksums))
 
 ;; <https://archive.softwareheritage.org/api/1/directory/27c69c5d298a43096a53affbf881e7b13f17bdcd/>
 (define-json-mapping <directory-entry> make-directory-entry directory-entry?
@@ -365,14 +367,15 @@ FALSE-IF-404? is true, return #f upon 404 responses."
   json->directory-entries)
 
 (define (json->directory-entries port)
-  (map json->directory-entry (json->scm port)))
+  (map json->directory-entry
+       (vector->list (json->scm port))))
 
 (define (origin-visits origin)
   "Return the list of visits of ORIGIN, a record as returned by
 'lookup-origin'."
   (call (swh-url (origin-visits-url origin))
         (lambda (port)
-          (map json->visit (json->scm port)))))
+          (map json->visit (vector->list (json->scm port))))))
 
 (define (visit-snapshot visit)
   "Return the snapshot corresponding to VISIT."
diff --git a/m4/guix.m4 b/m4/guix.m4
index d0c5ec0f08..716bfb08ec 100644
--- a/m4/guix.m4
+++ b/m4/guix.m4
@@ -174,6 +174,27 @@ AC_DEFUN([GUIX_CHECK_GUILE_SQLITE3], [
      fi])
 ])
 
+dnl GUIX_CHECK_GUILE_JSON
+dnl
+dnl Check whether a recent-enough Guile-JSON is available.
+AC_DEFUN([GUIX_CHECK_GUILE_JSON], [
+  dnl Check whether we're using Guile-JSON 3.x, which uses a JSON-to-Scheme
+  dnl mapping different from that of earlier versions.
+  AC_CACHE_CHECK([whether Guile-JSON is available and recent enough],
+    [guix_cv_have_recent_guile_json],
+    [GUILE_CHECK([retval],
+      [(use-modules (json) (ice-9 match))
+       (match (json-string->scm \"[[] { \\\"a\\\": 42 } []]\")
+         (#(("a" . 42)) #t)
+	 (_ #f))])
+     if test "$retval" = 0; then
+       guix_cv_have_recent_guile_json="yes"
+     else
+       guix_cv_have_recent_guile_json="no"
+     fi])
+])
+
+
 dnl GUIX_TEST_ROOT_DIRECTORY
 AC_DEFUN([GUIX_TEST_ROOT_DIRECTORY], [
   AC_CACHE_CHECK([for unit test root directory],
diff --git a/tests/import-utils.scm b/tests/import-utils.scm
index 5c0c041360..c3ab25d788 100644
--- a/tests/import-utils.scm
+++ b/tests/import-utils.scm
@@ -23,6 +23,7 @@
   #:use-module ((guix licenses) #:prefix license:)
   #:use-module (guix packages)
   #:use-module (guix build-system)
+  #:use-module (gnu packages)
   #:use-module (srfi srfi-64))
 
 (test-begin "import-utils")
@@ -98,4 +99,25 @@
     (or (package-license (alist->package meta))
         'license-is-false)))
 
+(test-equal "alist->package with dependencies"
+  `(("gettext" ,(specification->package "gettext")))
+  (let* ((meta '(("name" . "hello")
+                 ("version" . "2.10")
+                 ("source" . (("method" . "url-fetch")
+                              ("uri"    . "mirror://gnu/hello/hello-2.10.tar.gz")
+                              ("sha256" .
+                               (("base32" .
+                                 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))
+                 ("build-system" . "gnu")
+                 ("home-page" . "https://gnu.org")
+                 ("synopsis" . "Say hi")
+                 ("description" . "This package says hi.")
+                                                  ;
+                 ;; Note: As with Guile-JSON 3.x, JSON arrays are represented
+                 ;; by vectors.
+                 ("native-inputs" . #("gettext"))
+
+                 ("license" . #f))))
+    (package-native-inputs (alist->package meta))))
+
 (test-end "import-utils")
-- 
2.22.0





Information forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Mon, 22 Jul 2019 10:20:02 GMT) Full text and rfc822 format available.

Message #11 received at 36760 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: 36760 <at> debbugs.gnu.org
Cc: Ludovic Courtès <ludo <at> gnu.org>
Subject: [PATCH 2/3] gnu: guile-json: Define 'guile-json-1'.
Date: Mon, 22 Jul 2019 12:18:42 +0200
* gnu/packages/guile.scm (guile-json-1): New variable.
---
 gnu/packages/guile.scm | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/gnu/packages/guile.scm b/gnu/packages/guile.scm
index 6e11a13c56..e871685f02 100644
--- a/gnu/packages/guile.scm
+++ b/gnu/packages/guile.scm
@@ -470,6 +470,10 @@ specification.  These are the main features:
     ;; Version 1.2.0 switched to GPLv3+ (from LGPLv3+).
     (license license:gpl3+)))
 
+(define-public guile-json-1
+  ;; This is the 1.x branch of Guile-JSON.
+  guile-json)
+
 (define-public guile2.2-json
   (deprecated-package "guile2.2-json" guile-json))
 
-- 
2.22.0





Information forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Mon, 22 Jul 2019 10:20:02 GMT) Full text and rfc822 format available.

Message #14 received at 36760 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: 36760 <at> debbugs.gnu.org
Cc: Ludovic Courtès <ludo <at> gnu.org>
Subject: [PATCH 3/3] gnu: Explicitly refer to 'guile-json-1' when needed.
Date: Mon, 22 Jul 2019 12:18:43 +0200
* gnu/packages/bioinformatics.scm (rcas-web)[inputs]: Change
'guile-json' to 'guile-json-1'.
* gnu/packages/ci.scm (cuirass)[inputs]: Likewise.
* gnu/packages/guile-xyz.scm (artanis)[inputs]: Likewise.
* gnu/packages/guile-xyz.scm (jupyter-guile-kernel)[inputs]: Likewise.
* gnu/packages/guile-xyz.scm (guile-mastodon)[inputs]: Likewise.
* gnu/packages/mail.scm (mumi)[inputs]: Likewise.
* gnu/packages/package-management.scm (guix)[inputs]: Likewise.
* gnu/packages/package-management.scm (guix-daemon)[inputs]: Likewise.
* gnu/packages/web.scm (hpcguix-web)[inputs]: Likewise.
---
 gnu/packages/bioinformatics.scm     | 2 +-
 gnu/packages/ci.scm                 | 2 +-
 gnu/packages/guile-xyz.scm          | 6 +++---
 gnu/packages/mail.scm               | 4 ++--
 gnu/packages/package-management.scm | 4 ++--
 gnu/packages/web.scm                | 2 +-
 6 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/gnu/packages/bioinformatics.scm b/gnu/packages/bioinformatics.scm
index d72fde00b4..5e2a38b591 100644
--- a/gnu/packages/bioinformatics.scm
+++ b/gnu/packages/bioinformatics.scm
@@ -8425,7 +8425,7 @@ library implementing most of the pipeline's features.")
      `(("r-minimal" ,r-minimal)
        ("r-rcas" ,r-rcas)
        ("guile-next" ,guile-2.2)
-       ("guile-json" ,guile-json)
+       ("guile-json" ,guile-json-1)
        ("guile-redis" ,guile-redis)))
     (native-inputs
      `(("pkg-config" ,pkg-config)))
diff --git a/gnu/packages/ci.scm b/gnu/packages/ci.scm
index eb5f665fc1..4af2cdc6ea 100644
--- a/gnu/packages/ci.scm
+++ b/gnu/packages/ci.scm
@@ -121,7 +121,7 @@
        `(("guile" ,guile-2.2)
          ("guile-fibers" ,guile-fibers)
          ("guile-gcrypt" ,guile-gcrypt)
-         ("guile-json" ,guile-json)
+         ("guile-json" ,guile-json-1)
          ("guile-sqlite3" ,guile-sqlite3)
          ("guile-git" ,guile-git)
          ;; FIXME: this is propagated by "guile-git", but it needs to be among
diff --git a/gnu/packages/guile-xyz.scm b/gnu/packages/guile-xyz.scm
index c16342deb0..6dcdcedccf 100644
--- a/gnu/packages/guile-xyz.scm
+++ b/gnu/packages/guile-xyz.scm
@@ -146,7 +146,7 @@
       ;; projects.
       ;; TODO: Add guile-dbi and guile-dbd optional dependencies.
       (inputs `(("guile" ,guile-2.2)
-                ("guile-json" ,guile-json)
+                ("guile-json" ,guile-json-1)
                 ("guile-redis" ,guile-redis)))
       (native-inputs `(("bash"       ,bash)         ;for the `source' builtin
                        ("pkgconfig"  ,pkg-config)
@@ -844,7 +844,7 @@ messaging library.")
       (inputs
        `(("openssl" ,openssl)
          ("guile" ,guile-2.2)
-         ("guile-json" ,guile-json)
+         ("guile-json" ,guile-json-1)
          ("guile-simple-zmq" ,guile-simple-zmq)))
       (synopsis "Guile kernel for the Jupyter Notebook")
       (description
@@ -1008,7 +1008,7 @@ Scheme by using Guile’s foreign function interface.")
     (inputs
      `(("guile" ,guile-2.2)
        ("gnutls" ,gnutls)
-       ("guile-json" ,guile-json)))
+       ("guile-json" ,guile-json-1)))
     (home-page "https://framagit.org/prouby/guile-mastodon")
     (synopsis "Guile Mastodon REST API module")
     (description "This package provides Guile modules to access the
diff --git a/gnu/packages/mail.scm b/gnu/packages/mail.scm
index b555578639..8a3f64b10d 100644
--- a/gnu/packages/mail.scm
+++ b/gnu/packages/mail.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018 Ludovic Courtès <ludo <at> gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo <at> gnu.org>
 ;;; Copyright © 2014, 2015, 2017 Mark H Weaver <mhw <at> netris.org>
 ;;; Copyright © 2014 Ian Denhardt <ian <at> zenhack.net>
 ;;; Copyright © 2014 Sou Bunnbu <iyzsong <at> gmail.com>
@@ -2848,7 +2848,7 @@ replacement for the @code{urlview} program.")
        `(("guile-debbugs" ,guile-debbugs-next)
          ("guile-email" ,guile-email)
          ("guile-fibers" ,guile-fibers)
-         ("guile-json" ,guile-json)
+         ("guile-json" ,guile-json-1)
          ("guile-syntax-highlight" ,guile-syntax-highlight)
          ("guile" ,guile-2.2)))
       (native-inputs
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm
index ab11065379..9b2cce0e8f 100644
--- a/gnu/packages/package-management.scm
+++ b/gnu/packages/package-management.scm
@@ -293,7 +293,7 @@
       (propagated-inputs
        `(("gnutls" ,gnutls)
          ("guile-gcrypt" ,guile-gcrypt)
-         ("guile-json" ,guile-json)
+         ("guile-json" ,guile-json-1)
          ("guile-sqlite3" ,guile-sqlite3)
          ("guile-ssh" ,guile-ssh)
          ("guile-git" ,guile-git)))
@@ -325,7 +325,7 @@ the Nix package manager.")
     (inputs
      `(("gnutls" ,gnutls)
        ("guile-git" ,guile-git)
-       ("guile-json" ,guile-json)
+       ("guile-json" ,guile-json-1)
        ("guile-gcrypt" ,guile-gcrypt)
        ,@(fold alist-delete (package-inputs guix)
                '("boot-guile" "boot-guile/i686" "util-linux"))))
diff --git a/gnu/packages/web.scm b/gnu/packages/web.scm
index f81d12c7ce..ac6403211c 100644
--- a/gnu/packages/web.scm
+++ b/gnu/packages/web.scm
@@ -6509,7 +6509,7 @@ compressed JSON header blocks.
       (propagated-inputs
        `(("guile" ,guile-2.2)
          ("guile-commonmark" ,guile-commonmark)
-         ("guile-json" ,guile-json)))
+         ("guile-json" ,guile-json-1)))
       (home-page "https://github.com/UMCUGenetics/hpcguix-web")
       (synopsis "Web interface for cluster deployments of Guix")
       (description "Hpcguix-web provides a web interface to the list of packages
-- 
2.22.0





Reply sent to Ludovic Courtès <ludo <at> gnu.org>:
You have taken responsibility. (Wed, 24 Jul 2019 22:40:01 GMT) Full text and rfc822 format available.

Notification sent to Ludovic Courtès <ludo <at> gnu.org>:
bug acknowledged by developer. (Wed, 24 Jul 2019 22:40:01 GMT) Full text and rfc822 format available.

Message #19 received at 36760-done <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: 36760-done <at> debbugs.gnu.org
Subject: Re: [bug#36760] [PATCH 0/3] Switch to Guile-JSON 3.x
Date: Thu, 25 Jul 2019 00:39:39 +0200
Hello!

Ludovic Courtès <ludo <at> gnu.org> skribis:

>   maint: Switch to Guile-JSON 3.x.
>   gnu: guile-json: Define 'guile-json-1'.
>   gnu: Explicitly refer to 'guile-json-1' when needed.

Pushed!

  91f55717ab gnu: Explicitly refer to 'guile-json-1' when needed.
  584a3ca3a4 gnu: guile-json: Define 'guile-json-1'.
  81c3dc3224 maint: Switch to Guile-JSON 3.x.

Compared to what I sent, I updated the ‘github’ and ‘launchpad’
updaters, which I had forgotten.

Now we need to adjust cuirass, hpcguix-web, and rcas-web.  I’m taking a
look at hpcguix-web.

Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Sat, 17 Aug 2019 17:30:03 GMT) Full text and rfc822 format available.

Message #22 received at 36760 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: 36760 <at> debbugs.gnu.org
Cc: Ricardo Wurmus <rekado <at> elephly.net>
Subject: Re: [bug#36760] [PATCH 0/3] Switch to Guile-JSON 3.x
Date: Sat, 17 Aug 2019 19:29:30 +0200
Hello,

Ludovic Courtès <ludo <at> gnu.org> skribis:

> When we update the ‘guix’ package, everything that depends on it will
> also have to be updated to a snapshot that uses Guile-JSON 3.x: cuirass,
> hpcguix-web, and rcas-web.  I count on you, dear reader, to help in
> those areas.  :-)

Commit 2eb0628a423a36bc21777d7439885baa9a9a8e6d updates the ‘guix’ and
‘cuirass’ packages to use Guile-JSON 3.x.  ‘hpcguix-web’ was updated
earlier, in commit 4b0356590a57bc27a61956b981f4a90efcf9c92d.

I haven’t checked rcas-web though; Ricardo?

Ludo’.




Information forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Sat, 17 Aug 2019 20:48:02 GMT) Full text and rfc822 format available.

Message #25 received at 36760 <at> debbugs.gnu.org (full text, mbox):

From: Ricardo Wurmus <rekado <at> elephly.net>
To: Ludovic Courtès <ludo <at> gnu.org>
Cc: 36760 <at> debbugs.gnu.org
Subject: Re: [bug#36760] [PATCH 0/3] Switch to Guile-JSON 3.x
Date: Sat, 17 Aug 2019 22:47:45 +0200
Ludovic Courtès <ludo <at> gnu.org> writes:

> Hello,
>
> Ludovic Courtès <ludo <at> gnu.org> skribis:
>
>> When we update the ‘guix’ package, everything that depends on it will
>> also have to be updated to a snapshot that uses Guile-JSON 3.x: cuirass,
>> hpcguix-web, and rcas-web.  I count on you, dear reader, to help in
>> those areas.  :-)
>
> Commit 2eb0628a423a36bc21777d7439885baa9a9a8e6d updates the ‘guix’ and
> ‘cuirass’ packages to use Guile-JSON 3.x.  ‘hpcguix-web’ was updated
> earlier, in commit 4b0356590a57bc27a61956b981f4a90efcf9c92d.

Thank you!

> I haven’t checked rcas-web though; Ricardo?

rcas-web doesn’t talk to Guix, so its use of an older Guile JSON is not
a problem.  If we want to let “guile-json” point to 3.x that’s fine;
we’d just let rcas-web use the 1.x variant.

(I’ll update it at some point in the future, but it doesn’t seem
critical.)

--
Ricardo





Information forwarded to guix-patches <at> gnu.org:
bug#36760; Package guix-patches. (Sat, 17 Aug 2019 21:18:02 GMT) Full text and rfc822 format available.

Message #28 received at 36760 <at> debbugs.gnu.org (full text, mbox):

From: Ludovic Courtès <ludo <at> gnu.org>
To: Ricardo Wurmus <rekado <at> elephly.net>
Cc: 36760 <at> debbugs.gnu.org
Subject: Re: [bug#36760] [PATCH 0/3] Switch to Guile-JSON 3.x
Date: Sat, 17 Aug 2019 23:17:31 +0200
Hello,

Ricardo Wurmus <rekado <at> elephly.net> skribis:

> Ludovic Courtès <ludo <at> gnu.org> writes:

[...]

>> Commit 2eb0628a423a36bc21777d7439885baa9a9a8e6d updates the ‘guix’ and
>> ‘cuirass’ packages to use Guile-JSON 3.x.  ‘hpcguix-web’ was updated
>> earlier, in commit 4b0356590a57bc27a61956b981f4a90efcf9c92d.
>
> Thank you!
>
>> I haven’t checked rcas-web though; Ricardo?
>
> rcas-web doesn’t talk to Guix, so its use of an older Guile JSON is not
> a problem.  If we want to let “guile-json” point to 3.x that’s fine;
> we’d just let rcas-web use the 1.x variant.

Perfect, in that case we’re all set.  Thanks!

Ludo’.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sun, 15 Sep 2019 11:24:07 GMT) Full text and rfc822 format available.

This bug report was last modified 4 years and 196 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.