all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* [PATCH 2/2] import: Add stackage importer and updater.
@ 2017-02-07  7:36 Federico Beffa
  2017-02-08 13:19 ` Federico Beffa
  2017-02-08 15:30 ` Ludovic Courtès
  0 siblings, 2 replies; 5+ messages in thread
From: Federico Beffa @ 2017-02-07  7:36 UTC (permalink / raw)
  To: Guix-devel

[-- Attachment #1: Type: text/plain, Size: 81 bytes --]

An importer/updater for Stackage built on top of the Hackage one.

Regards,
Fede

[-- Attachment #2: 0002-import-Add-stackage-importer-and-updater.patch --]
[-- Type: text/x-patch, Size: 16414 bytes --]

From 50891dc929a21327405c6a3b58638126456deeed Mon Sep 17 00:00:00 2001
From: Federico Beffa <beffa@fbengineering.ch>
Date: Mon, 6 Feb 2017 18:19:26 +0100
Subject: [PATCH 2/2] import: Add stackage importer and updater.

* guix/import/stackage.scm: New file.
* guix/scripts/import/stackage.scm: New file.
* Makefile.am (MODULES): Add new files.
* guix/scripts/import.scm (importers): Add "stackage".
* guix/scripts/refresh.scm (%updaters): Add %stackage-updater.
* doc/guix.texi (Invoking 'guix import'): Document the importer.
  (Invoking 'guix refresh'): Add stackage to option --type valid values.
---
 Makefile.am                      |   2 +
 doc/guix.texi                    |  33 +++++++-
 guix/import/stackage.scm         | 178 +++++++++++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   3 +-
 guix/scripts/import/stackage.scm | 115 +++++++++++++++++++++++++
 guix/scripts/refresh.scm         |   2 +
 6 files changed, 331 insertions(+), 2 deletions(-)
 create mode 100644 guix/import/stackage.scm
 create mode 100644 guix/scripts/import/stackage.scm

diff --git a/Makefile.am b/Makefile.am
index 360c356f1..18501bddf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,6 +126,7 @@ MODULES =					\
   guix/import/cabal.scm				\
   guix/import/cran.scm				\
   guix/import/hackage.scm			\
+  guix/import/stackage.scm			\
   guix/import/elpa.scm   			\
   guix/scripts.scm				\
   guix/scripts/download.scm			\
@@ -147,6 +148,7 @@ MODULES =					\
   guix/scripts/import/gnu.scm			\
   guix/scripts/import/nix.scm			\
   guix/scripts/import/hackage.scm		\
+  guix/scripts/import/stackage.scm		\
   guix/scripts/import/elpa.scm  		\
   guix/scripts/environment.scm			\
   guix/scripts/publish.scm			\
diff --git a/doc/guix.texi b/doc/guix.texi
index 6acde6621..8caf1d68d 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -31,7 +31,8 @@ Copyright @copyright{} 2016 Jan Nieuwenhuizen@*
 Copyright @copyright{} 2016 Julien Lepiller@*
 Copyright @copyright{} 2016 Alex ter Weele@*
 Copyright @copyright{} 2017 Clément Lassieur@*
-Copyright @copyright{} 2017 Mathieu Othacehe
+Copyright @copyright{} 2017 Mathieu Othacehe@*
+Copyright @copyright{} 2017 Federico Beffa
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -5340,6 +5341,34 @@ package name by an at-sign and a version number as in the following example:
 guix import hackage mtl@@2.1.3.1
 @end example
 
+@item stackage
+@cindex stackage
+The @code{stackage} importer is a wrapper around the @code{hackage} one.
+It takes a package name, looks up the package version included in an LTS
+@uref{https://www.stackage.org/, Stackage} release and uses the
+@code{hackage} importer to retrieve its metadata.  Note that it is up to
+you to select an LTS release compatible with the GHC compiler used by
+Guix.
+
+Specific command-line options are:
+
+@table @code
+@item --no-test-dependencies
+@itemx -t
+Do not include dependencies required only by the test suites.
+@item --lts-version=@var{version}
+@itemx -r @var{version}
+@var{version} is the desired LTS release version.  If omitted the latest
+release is used.
+@end table
+
+The command below imports metadata for the @code{HTTP} Haskell package
+included in the LTS Stackage release version 7.18:
+
+@example
+guix import stackage --lts-version=7.18 HTTP
+@end example
+
 @item elpa
 @cindex elpa
 Import metadata from an Emacs Lisp Package Archive (ELPA) package
@@ -5504,6 +5533,8 @@ the updater for @uref{https://rubygems.org, RubyGems} packages.
 the updater for @uref{https://github.com, GitHub} packages.
 @item hackage
 the updater for @uref{https://hackage.haskell.org, Hackage} packages.
+@item stackage
+the updater for @uref{https://www.stackage.org, Stackage} packages.
 @item crate
 the updater for @uref{https://crates.io, Crates} packages.
 @end table
diff --git a/guix/import/stackage.scm b/guix/import/stackage.scm
new file mode 100644
index 000000000..1e536debb
--- /dev/null
+++ b/guix/import/stackage.scm
@@ -0,0 +1,178 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2017 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 stackage)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 regex)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix import json)
+  #:use-module (guix import hackage)
+  #:use-module (guix memoization)
+  #:use-module (guix packages)
+  #:use-module (guix upstream)
+  #:export (stackage->guix-package
+            stackage-lts->guix-packages
+            %stackage-updater))
+
+\f
+;;;
+;;; Stackage info fetcher and access functions
+;;;
+
+
+(define %stackage-url "http://www.stackage.org")
+
+(define (lts-info-ghc-version lts-info)
+  "Retruns the version of the GHC compiler contained in LTS-INFO."
+  (match lts-info
+    ((("snapshot" ("ghc" . version) _ _) _)  version)
+    (_ #f)))
+
+(define (lts-info-packages lts-info)
+  "Retruns the alist of packages contained in LTS-INFO."
+  (match lts-info
+    ((_ ("packages" pkg ...)) pkg)
+    (_ '())))
+
+(define stackage-lts-info-fetch
+  ;; "Retrieve the information about the LTS Stackage release VERSION."
+  (memoize
+   (lambda* (#:optional (version ""))
+     (let* ((url (if (string=? "" version)
+                     (string-append %stackage-url "/lts")
+                     (string-append %stackage-url "/lts-" version)))
+            (lts-info (json-fetch url)))
+       (if lts-info
+           (reverse lts-info)
+           (begin
+             (format (current-error-port)
+                     "guix import stackage: LTS release version not found: ~a~%"
+                     version)
+             #f))))))
+
+(define (stackage-package-name pkg-info)
+  (assoc-ref pkg-info "name"))
+
+(define (stackage-package-version pkg-info)
+  (assoc-ref pkg-info "version"))
+
+(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)))
+    (stackage-package-version pkg)))
+
+\f
+;;;
+;;; Hackage importer low-level help functions
+;;;
+
+(define guix-package->hackage-name
+  (@@ (guix import hackage) guix-package->hackage-name))
+
+(define hackage-fetch
+  (@@ (guix import hackage) hackage-fetch))
+
+(define hackage-source-url
+  (@@ (guix import hackage) hackage-source-url))
+
+(define hackage-cabal-url
+  (@@ (guix import hackage) hackage-cabal-url))
+
+\f
+;;;
+;;; Importer entry point
+;;;
+
+(define (hackage-name-version name version)
+  (and version (string-append  name "@" version)))
+
+(define* (stackage->guix-package package-name ; upstream name
+                                 #:key
+                                 (include-test-dependencies? #t)
+                                 (lts-version "")
+                                 (packages-info
+                                  (lts-info-packages
+                                   (stackage-lts-info-fetch lts-version))))
+  "Fetch Cabal file for PACKAGE-NAME from hackage.haskell.org.  The retrieved
+vesion corresponds to the version of PACKAGE-NAME specified in the LTS-VERSION
+release at stackage.org.  Return the `package' S-expression corresponding to
+that package, or #f on failure.  PACKAGES-INFO is the alist with the packages
+included in the Stackage LTS release."
+  (let* ((version (lts-package-version packages-info package-name))
+         (name-version (hackage-name-version package-name version)))
+    (if name-version
+        (hackage->guix-package name-version
+                               #:include-test-dependencies?
+                               include-test-dependencies?)
+        (begin
+          (format (current-error-port)
+                  "guix import stackage: package not found: ~a~%" package-name)
+          #f))))
+
+(define* (stackage-lts->guix-packages #:key
+                                      (include-test-dependencies? #t)
+                                      (lts-version ""))
+  "Fetch the Cabal files of all packages included in the Stackage LTS release
+LTS-VERSION and produce a list with a Guix package S-expression for each of
+them.  If we fail to parse the Cabal file we omit that package from the result."
+  (let* ((pkgs-info (lts-info-packages (stackage-lts-info-fetch lts-version)))
+         (hackage-names (map stackage-package-name pkgs-info)))
+    (filter (cut stackage->guix-package <>
+                 #:include-test-dependencies? include-test-dependencies?
+                 #:lts-version lts-version
+                 #:packages-info pkgs-info)
+            hackage-names)))
+
+\f
+;;;
+;;; Updater
+;;;
+
+(define* (latest-lts-release package
+                             #:optional
+                             (packages-info (lts-info-packages
+                                             (stackage-lts-info-fetch))))
+  "Return an <upstream-source> for the latest Stackage LTS release of PACKAGE
+or #f it the package is not inlucded in the Stackage LTS release."
+  (let* ((hackage-name (guix-package->hackage-name package))
+         (version (lts-package-version packages-info hackage-name))
+         (name-version (hackage-name-version hackage-name version))
+         (cabal-meta (and=> name-version hackage-fetch)))
+    (match cabal-meta
+      (#f
+       (format (current-error-port)
+               "warning: failed to parse ~a~%"
+               (hackage-cabal-url hackage-name))
+       #f)
+      (_
+       (let ((url (hackage-source-url hackage-name version)))
+         (upstream-source
+          (package (package-name package))
+          (version version)
+          (urls (list url))))))))
+
+(define %stackage-updater
+  (upstream-updater
+   (name 'stackage)
+   (description "Updater for Stackage LTS packages")
+   (pred (@@ (guix import hackage) hackage-package?))
+   (latest latest-lts-release)))
+
+;;; stackage.scm ends here
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 4d07e0fd6..8c2f70573 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -73,7 +73,8 @@ rather than \\n."
 ;;; Entry point.
 ;;;
 
-(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "elpa" "gem" "cran" "crate"))
+(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem"
+                    "cran" "crate"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/stackage.scm b/guix/scripts/import/stackage.scm
new file mode 100644
index 000000000..cf47bff25
--- /dev/null
+++ b/guix/scripts/import/stackage.scm
@@ -0,0 +1,115 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2017 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 scripts import stackage)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix packages)
+  #:use-module (guix scripts)
+  #:use-module (guix import stackage)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-stackage))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  `((lts-version . "")
+    (include-test-dependencies? . #t)))
+
+(define (show-help)
+  (display (_ "Usage: guix import stackage PACKAGE-NAME
+Import and convert the LTS Stackage package for PACKAGE-NAME.\n"))
+  (display (_ "
+  -r VERSION, --lts-version=VERSION
+                               specify the LTS version to use"))
+  (display (_ "
+  -h, --help                   display this help and exit"))
+  (display (_ "
+  -t, --no-test-dependencies   don't include test-only dependencies"))
+  (display (_ "
+  -V, --version                display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import stackage")))
+         (option '(#\t "no-test-dependencies") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'include-test-dependencies? #f
+                               (alist-delete 'include-test-dependencies?
+                                             result))))
+         (option '(#\r "lts-version") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'lts-version arg
+                               (alist-delete 'lts-version
+                                             result))))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-stackage . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((package-name)
+       (let ((sexp (stackage->guix-package
+                    package-name
+                    #:include-test-dependencies?
+                    (assoc-ref opts 'include-test-dependencies?)
+                    #:lts-version (assoc-ref opts 'lts-version))))
+         (unless sexp
+           (leave (_ "failed to download cabal file for package '~a'~%")
+                  package-name))
+         sexp))
+      (()
+       (leave (_ "too few arguments~%")))
+      ((many ...)
+       (leave (_ "too many arguments~%"))))))
+
+;;; stackage.scm ends here
diff --git a/guix/scripts/refresh.scm b/guix/scripts/refresh.scm
index 0dd7eee97..94dea4ebc 100644
--- a/guix/scripts/refresh.scm
+++ b/guix/scripts/refresh.scm
@@ -40,6 +40,7 @@
   #:use-module (guix import elpa)
   #:use-module (guix import cran)
   #:use-module (guix import hackage)
+  #:use-module (guix import stackage)
   #:use-module (guix gnupg)
   #:use-module (gnu packages)
   #:use-module ((gnu packages commencement) #:select (%final-inputs))
@@ -205,6 +206,7 @@ unavailable optional dependencies such as Guile-JSON."
                  %elpa-updater
                  %cran-updater
                  %bioconductor-updater
+                 %stackage-updater
                  %hackage-updater
                  ((guix import cpan) => %cpan-updater)
                  ((guix import pypi) => %pypi-updater)
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] import: Add stackage importer and updater.
  2017-02-07  7:36 [PATCH 2/2] import: Add stackage importer and updater Federico Beffa
@ 2017-02-08 13:19 ` Federico Beffa
  2017-02-08 15:30 ` Ludovic Courtès
  1 sibling, 0 replies; 5+ messages in thread
From: Federico Beffa @ 2017-02-08 13:19 UTC (permalink / raw)
  To: Guix-devel

[-- Attachment #1: Type: text/plain, Size: 166 bytes --]

On Tue, Feb 7, 2017 at 8:36 AM, Federico Beffa <beffa@ieee.org> wrote:
> An importer/updater for Stackage built on top of the Hackage one.

I've cleaned it up a bit.

[-- Attachment #2: 0002-import-Add-stackage-importer-and-updater.patch --]
[-- Type: text/x-patch, Size: 15332 bytes --]

From 168ce15a10ed0b76bb339e31ae5b8998564d7d43 Mon Sep 17 00:00:00 2001
From: Federico Beffa <beffa@fbengineering.ch>
Date: Mon, 6 Feb 2017 18:19:26 +0100
Subject: [PATCH 2/2] import: Add stackage importer and updater.

* guix/import/stackage.scm: New file.
* guix/scripts/import/stackage.scm: New file.
* Makefile.am (MODULES): Add new files.
* guix/scripts/import.scm (importers): Add "stackage".
* guix/scripts/refresh.scm (%updaters): Add %stackage-updater.
* doc/guix.texi (Invoking 'guix import'): Document the importer.
  (Invoking 'guix refresh'): Add stackage to option --type valid values.
---
 Makefile.am                      |   2 +
 doc/guix.texi                    |  33 ++++++++-
 guix/import/stackage.scm         | 153 +++++++++++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   3 +-
 guix/scripts/import/stackage.scm | 115 +++++++++++++++++++++++++++++
 guix/scripts/refresh.scm         |   2 +
 6 files changed, 306 insertions(+), 2 deletions(-)
 create mode 100644 guix/import/stackage.scm
 create mode 100644 guix/scripts/import/stackage.scm

diff --git a/Makefile.am b/Makefile.am
index 360c356f1..18501bddf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,6 +126,7 @@ MODULES =					\
   guix/import/cabal.scm				\
   guix/import/cran.scm				\
   guix/import/hackage.scm			\
+  guix/import/stackage.scm			\
   guix/import/elpa.scm   			\
   guix/scripts.scm				\
   guix/scripts/download.scm			\
@@ -147,6 +148,7 @@ MODULES =					\
   guix/scripts/import/gnu.scm			\
   guix/scripts/import/nix.scm			\
   guix/scripts/import/hackage.scm		\
+  guix/scripts/import/stackage.scm		\
   guix/scripts/import/elpa.scm  		\
   guix/scripts/environment.scm			\
   guix/scripts/publish.scm			\
diff --git a/doc/guix.texi b/doc/guix.texi
index 6acde6621..8caf1d68d 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -31,7 +31,8 @@ Copyright @copyright{} 2016 Jan Nieuwenhuizen@*
 Copyright @copyright{} 2016 Julien Lepiller@*
 Copyright @copyright{} 2016 Alex ter Weele@*
 Copyright @copyright{} 2017 Clément Lassieur@*
-Copyright @copyright{} 2017 Mathieu Othacehe
+Copyright @copyright{} 2017 Mathieu Othacehe@*
+Copyright @copyright{} 2017 Federico Beffa
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -5340,6 +5341,34 @@ package name by an at-sign and a version number as in the following example:
 guix import hackage mtl@@2.1.3.1
 @end example
 
+@item stackage
+@cindex stackage
+The @code{stackage} importer is a wrapper around the @code{hackage} one.
+It takes a package name, looks up the package version included in an LTS
+@uref{https://www.stackage.org/, Stackage} release and uses the
+@code{hackage} importer to retrieve its metadata.  Note that it is up to
+you to select an LTS release compatible with the GHC compiler used by
+Guix.
+
+Specific command-line options are:
+
+@table @code
+@item --no-test-dependencies
+@itemx -t
+Do not include dependencies required only by the test suites.
+@item --lts-version=@var{version}
+@itemx -r @var{version}
+@var{version} is the desired LTS release version.  If omitted the latest
+release is used.
+@end table
+
+The command below imports metadata for the @code{HTTP} Haskell package
+included in the LTS Stackage release version 7.18:
+
+@example
+guix import stackage --lts-version=7.18 HTTP
+@end example
+
 @item elpa
 @cindex elpa
 Import metadata from an Emacs Lisp Package Archive (ELPA) package
@@ -5504,6 +5533,8 @@ the updater for @uref{https://rubygems.org, RubyGems} packages.
 the updater for @uref{https://github.com, GitHub} packages.
 @item hackage
 the updater for @uref{https://hackage.haskell.org, Hackage} packages.
+@item stackage
+the updater for @uref{https://www.stackage.org, Stackage} packages.
 @item crate
 the updater for @uref{https://crates.io, Crates} packages.
 @end table
diff --git a/guix/import/stackage.scm b/guix/import/stackage.scm
new file mode 100644
index 000000000..57b07f24e
--- /dev/null
+++ b/guix/import/stackage.scm
@@ -0,0 +1,153 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2017 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 stackage)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 regex)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (guix import json)
+  #:use-module (guix import hackage)
+  #:use-module (guix memoization)
+  #:use-module (guix packages)
+  #:use-module (guix upstream)
+  #:use-module (guix ui)
+  #:export (stackage->guix-package
+            %stackage-updater))
+
+\f
+;;;
+;;; Stackage info fetcher and access functions
+;;;
+
+
+(define %stackage-url "http://www.stackage.org")
+
+(define (lts-info-ghc-version lts-info)
+  "Retruns the version of the GHC compiler contained in LTS-INFO."
+  (match lts-info
+    ((("snapshot" ("ghc" . version) _ _) _)  version)
+    (_ #f)))
+
+(define (lts-info-packages lts-info)
+  "Retruns the alist of packages contained in LTS-INFO."
+  (match lts-info
+    ((_ ("packages" pkg ...)) pkg)
+    (_ '())))
+
+(define stackage-lts-info-fetch
+  ;; "Retrieve the information about the LTS Stackage release VERSION."
+  (memoize
+   (lambda* (#:optional (version ""))
+     (let* ((url (if (string=? "" version)
+                     (string-append %stackage-url "/lts")
+                     (string-append %stackage-url "/lts-" version)))
+            (lts-info (json-fetch url)))
+       (if lts-info
+           (reverse lts-info)
+           (leave (_ "LTS release version not found: ~A~%") version))))))
+
+(define (stackage-package-name pkg-info)
+  (assoc-ref pkg-info "name"))
+
+(define (stackage-package-version pkg-info)
+  (assoc-ref pkg-info "version"))
+
+(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)))
+    (stackage-package-version pkg)))
+
+\f
+;;;
+;;; Hackage importer low-level help functions
+;;;
+
+(define guix-package->hackage-name
+  (@@ (guix import hackage) guix-package->hackage-name))
+
+(define hackage-fetch
+  (@@ (guix import hackage) hackage-fetch))
+
+(define hackage-source-url
+  (@@ (guix import hackage) hackage-source-url))
+
+(define hackage-cabal-url
+  (@@ (guix import hackage) hackage-cabal-url))
+
+\f
+;;;
+;;; Importer entry point
+;;;
+
+(define (hackage-name-version name version)
+  (and version (string-append  name "@" version)))
+
+(define* (stackage->guix-package package-name ; upstream name
+                                 #:key
+                                 (include-test-dependencies? #t)
+                                 (lts-version "")
+                                 (packages-info
+                                  (lts-info-packages
+                                   (stackage-lts-info-fetch lts-version))))
+  "Fetch Cabal file for PACKAGE-NAME from hackage.haskell.org.  The retrieved
+vesion corresponds to the version of PACKAGE-NAME specified in the LTS-VERSION
+release at stackage.org.  Return the `package' S-expression corresponding to
+that package, or #f on failure.  PACKAGES-INFO is the alist with the packages
+included in the Stackage LTS release."
+  (let* ((version (lts-package-version packages-info package-name))
+         (name-version (hackage-name-version package-name version)))
+    (if name-version
+        (hackage->guix-package name-version
+                               #:include-test-dependencies?
+                               include-test-dependencies?)
+        (leave (_ "package not found: ~A~%") package-name))))
+
+\f
+;;;
+;;; Updater
+;;;
+
+(define latest-lts-release
+  (let ((pkgs-info (mlambda () (lts-info-packages (stackage-lts-info-fetch)))))
+    (lambda* (package)
+      "Return an <upstream-source> for the latest Stackage LTS release of
+PACKAGE or #f it the package is not inlucded in the Stackage LTS release."
+      (let* ((hackage-name (guix-package->hackage-name package))
+             (version (lts-package-version (pkgs-info) hackage-name))
+             (name-version (hackage-name-version hackage-name version)))
+        (match (and=> name-version hackage-fetch)
+          (#f (format (current-error-port)
+                      "warning: failed to parse ~a~%"
+                      (hackage-cabal-url hackage-name))
+              #f)
+          (_ (let ((url (hackage-source-url hackage-name version)))
+               (upstream-source
+                (package (package-name package))
+                (version version)
+                (urls (list url))))))))))
+
+(define %stackage-updater
+  (upstream-updater
+   (name 'stackage)
+   (description "Updater for Stackage LTS packages")
+   (pred (@@ (guix import hackage) hackage-package?))
+   (latest latest-lts-release)))
+
+;;; stackage.scm ends here
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 4d07e0fd6..8c2f70573 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -73,7 +73,8 @@ rather than \\n."
 ;;; Entry point.
 ;;;
 
-(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "elpa" "gem" "cran" "crate"))
+(define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem"
+                    "cran" "crate"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/stackage.scm b/guix/scripts/import/stackage.scm
new file mode 100644
index 000000000..cf47bff25
--- /dev/null
+++ b/guix/scripts/import/stackage.scm
@@ -0,0 +1,115 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2017 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 scripts import stackage)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix packages)
+  #:use-module (guix scripts)
+  #:use-module (guix import stackage)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-stackage))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  `((lts-version . "")
+    (include-test-dependencies? . #t)))
+
+(define (show-help)
+  (display (_ "Usage: guix import stackage PACKAGE-NAME
+Import and convert the LTS Stackage package for PACKAGE-NAME.\n"))
+  (display (_ "
+  -r VERSION, --lts-version=VERSION
+                               specify the LTS version to use"))
+  (display (_ "
+  -h, --help                   display this help and exit"))
+  (display (_ "
+  -t, --no-test-dependencies   don't include test-only dependencies"))
+  (display (_ "
+  -V, --version                display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (cons* (option '(#\h "help") #f #f
+                 (lambda args
+                   (show-help)
+                   (exit 0)))
+         (option '(#\V "version") #f #f
+                 (lambda args
+                   (show-version-and-exit "guix import stackage")))
+         (option '(#\t "no-test-dependencies") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'include-test-dependencies? #f
+                               (alist-delete 'include-test-dependencies?
+                                             result))))
+         (option '(#\r "lts-version") #t #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'lts-version arg
+                               (alist-delete 'lts-version
+                                             result))))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-stackage . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (_ "~A: unrecognized option~%") name))
+                (lambda (arg result)
+                  (alist-cons 'argument arg result))
+                %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((package-name)
+       (let ((sexp (stackage->guix-package
+                    package-name
+                    #:include-test-dependencies?
+                    (assoc-ref opts 'include-test-dependencies?)
+                    #:lts-version (assoc-ref opts 'lts-version))))
+         (unless sexp
+           (leave (_ "failed to download cabal file for package '~a'~%")
+                  package-name))
+         sexp))
+      (()
+       (leave (_ "too few arguments~%")))
+      ((many ...)
+       (leave (_ "too many arguments~%"))))))
+
+;;; stackage.scm ends here
diff --git a/guix/scripts/refresh.scm b/guix/scripts/refresh.scm
index 0dd7eee97..94dea4ebc 100644
--- a/guix/scripts/refresh.scm
+++ b/guix/scripts/refresh.scm
@@ -40,6 +40,7 @@
   #:use-module (guix import elpa)
   #:use-module (guix import cran)
   #:use-module (guix import hackage)
+  #:use-module (guix import stackage)
   #:use-module (guix gnupg)
   #:use-module (gnu packages)
   #:use-module ((gnu packages commencement) #:select (%final-inputs))
@@ -205,6 +206,7 @@ unavailable optional dependencies such as Guile-JSON."
                  %elpa-updater
                  %cran-updater
                  %bioconductor-updater
+                 %stackage-updater
                  %hackage-updater
                  ((guix import cpan) => %cpan-updater)
                  ((guix import pypi) => %pypi-updater)
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] import: Add stackage importer and updater.
  2017-02-07  7:36 [PATCH 2/2] import: Add stackage importer and updater Federico Beffa
  2017-02-08 13:19 ` Federico Beffa
@ 2017-02-08 15:30 ` Ludovic Courtès
  2017-02-09 18:39   ` Federico Beffa
  1 sibling, 1 reply; 5+ messages in thread
From: Ludovic Courtès @ 2017-02-08 15:30 UTC (permalink / raw)
  To: Federico Beffa; +Cc: Guix-devel

Hello Federico,

Federico Beffa <beffa@ieee.org> skribis:

> From 50891dc929a21327405c6a3b58638126456deeed Mon Sep 17 00:00:00 2001
> From: Federico Beffa <beffa@fbengineering.ch>
> Date: Mon, 6 Feb 2017 18:19:26 +0100
> Subject: [PATCH 2/2] import: Add stackage importer and updater.
>
> * guix/import/stackage.scm: New file.
> * guix/scripts/import/stackage.scm: New file.
> * Makefile.am (MODULES): Add new files.
> * guix/scripts/import.scm (importers): Add "stackage".
> * guix/scripts/refresh.scm (%updaters): Add %stackage-updater.
> * doc/guix.texi (Invoking 'guix import'): Document the importer.
>   (Invoking 'guix refresh'): Add stackage to option --type valid values.

Neat!

[...]

> +@item stackage
> +@cindex stackage
> +The @code{stackage} importer is a wrapper around the @code{hackage} one.
> +It takes a package name, looks up the package version included in an LTS

For the first occurrence of “LTS”:
s/LTS/long-term support (LTS)/

> +;;;
> +;;; Hackage importer low-level help functions
> +;;;
> +
> +(define guix-package->hackage-name
> +  (@@ (guix import hackage) guix-package->hackage-name))
> +
> +(define hackage-fetch
> +  (@@ (guix import hackage) hackage-fetch))
> +
> +(define hackage-source-url
> +  (@@ (guix import hackage) hackage-source-url))
> +
> +(define hackage-cabal-url
> +  (@@ (guix import hackage) hackage-cabal-url))

I’d suggest exporting these procedures from (guix import hackage) rather
than using ‘@@’, which should really be a last resort.

> +(define %stackage-updater
> +  (upstream-updater
> +   (name 'stackage)
> +   (description "Updater for Stackage LTS packages")
> +   (pred (@@ (guix import hackage) hackage-package?))

Likewise here, or use (upstream-updater-predicate hackage-updater).

> +    (if name-version
> +        (hackage->guix-package name-version
> +                               #:include-test-dependencies?
> +                               include-test-dependencies?)
> +        (begin
> +          (format (current-error-port)
> +                  "guix import stackage: package not found: ~a~%" package-name)
> +          #f))))

The ‘if’ is unnecessary here: (guix scripts import) produces an error
message when an importer returns something other than a ‘package’ sexp.

> --- a/guix/scripts/refresh.scm
> +++ b/guix/scripts/refresh.scm
> @@ -40,6 +40,7 @@
>    #:use-module (guix import elpa)
>    #:use-module (guix import cran)
>    #:use-module (guix import hackage)
> +  #:use-module (guix import stackage)
>    #:use-module (guix gnupg)
>    #:use-module (gnu packages)
>    #:use-module ((gnu packages commencement) #:select (%final-inputs))
> @@ -205,6 +206,7 @@ unavailable optional dependencies such as Guile-JSON."
>                   %elpa-updater
>                   %cran-updater
>                   %bioconductor-updater
> +                 %stackage-updater

Because the dependency on Guile-JSON is still optional, you should
remove the #:use-module above and this line and write:

  ((guix import stackage) => %stackage-updater)

I haven’t tested it, but this LGTM.

Thank you!

Ludo’.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] import: Add stackage importer and updater.
  2017-02-08 15:30 ` Ludovic Courtès
@ 2017-02-09 18:39   ` Federico Beffa
  2017-02-09 22:48     ` Ludovic Courtès
  0 siblings, 1 reply; 5+ messages in thread
From: Federico Beffa @ 2017-02-09 18:39 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Guix-devel

On Wed, Feb 8, 2017 at 4:30 PM, Ludovic Courtès <ludo@gnu.org> wrote:
> Hello Federico,
>
> Federico Beffa <beffa@ieee.org> skribis:

> [...]

>> +    (if name-version
>> +        (hackage->guix-package name-version
>> +                               #:include-test-dependencies?
>> +                               include-test-dependencies?)
>> +        (begin
>> +          (format (current-error-port)
>> +                  "guix import stackage: package not found: ~a~%" package-name)
>> +          #f))))
>
> The ‘if’ is unnecessary here: (guix scripts import) produces an error
> message when an importer returns something other than a ‘package’ sexp.

I've implemented all suggested changes apart from this one for two reasons:

* If the package is not included in an LTS release then the procedure
generating name-version returns #f. If I remove the 'if' then
hackage->guix-package will be called with a boolean instead of a
string as the first parameter and that will throw an exception.

* Here we can give a more accurate error message: we can say that the
package was not found in the LTS release, while, by returning, the
error would be "failed to download cabal file" which is somewhat
misleading.

Thanks for the review.
Fede

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] import: Add stackage importer and updater.
  2017-02-09 18:39   ` Federico Beffa
@ 2017-02-09 22:48     ` Ludovic Courtès
  0 siblings, 0 replies; 5+ messages in thread
From: Ludovic Courtès @ 2017-02-09 22:48 UTC (permalink / raw)
  To: Federico Beffa; +Cc: Guix-devel

Federico Beffa <beffa@ieee.org> skribis:

> On Wed, Feb 8, 2017 at 4:30 PM, Ludovic Courtès <ludo@gnu.org> wrote:
>> Hello Federico,
>>
>> Federico Beffa <beffa@ieee.org> skribis:
>
>> [...]
>
>>> +    (if name-version
>>> +        (hackage->guix-package name-version
>>> +                               #:include-test-dependencies?
>>> +                               include-test-dependencies?)
>>> +        (begin
>>> +          (format (current-error-port)
>>> +                  "guix import stackage: package not found: ~a~%" package-name)
>>> +          #f))))
>>
>> The ‘if’ is unnecessary here: (guix scripts import) produces an error
>> message when an importer returns something other than a ‘package’ sexp.
>
> I've implemented all suggested changes apart from this one for two reasons:
>
> * If the package is not included in an LTS release then the procedure
> generating name-version returns #f. If I remove the 'if' then
> hackage->guix-package will be called with a boolean instead of a
> string as the first parameter and that will throw an exception.
>
> * Here we can give a more accurate error message: we can say that the
> package was not found in the LTS release, while, by returning, the
> error would be "failed to download cabal file" which is somewhat
> misleading.

Good points!

In that case it’s better to either use ‘warning’ from (guix ui), but
that may not be appropriate here because this module is not supposed to
contain UI code, or to use:

  (raise (condition
            (&message
             (message (format #f (_ "~a: Stackage package not found")
                                 package-name)))))

That way, error messages are always reported in a consistent manner.

Ludo’.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-02-09 22:48 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-07  7:36 [PATCH 2/2] import: Add stackage importer and updater Federico Beffa
2017-02-08 13:19 ` Federico Beffa
2017-02-08 15:30 ` Ludovic Courtès
2017-02-09 18:39   ` Federico Beffa
2017-02-09 22:48     ` Ludovic Courtès

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.