unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#42338] [PATCH] Add composer build system (PHP)
@ 2020-07-12 22:20 Julien Lepiller
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                   ` (11 more replies)
  0 siblings, 12 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:20 UTC (permalink / raw)
  To: 42338

Hi Guix!

This patch series adds the composer-build-system, along with an
importer and an updater (first 3 patches).

The patch series also adds some php packages for phpunit and its
dependencies.

The patches are available in my composer branch at
https://framagit.org/tyreunom/guix/-/tree/composer




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

* [bug#42338] [PATCH 01/34] guix: import: Add composer importer.
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
@ 2020-07-12 22:25 ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 02/34] gnu: Add composer-classloader Julien Lepiller
                     ` (33 more replies)
  2021-08-23  9:46 ` [bug#42338] db
                   ` (10 subsequent siblings)
  11 siblings, 34 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
---
 Makefile.am                      |   2 +
 guix/import/composer.scm         | 252 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 +++++++++++++
 4 files changed, 362 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 20d43cd130..623ddf32b2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -219,6 +219,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -265,6 +266,7 @@ MODULES =					\
   guix/scripts/system/reconfigure.scm		\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cran.scm			\
   guix/scripts/import/elpa.scm  		\
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..0e17eb0487
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,252 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? a b) a b)) (car versions) versions))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append "https://repo.packagist.org/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (assoc-ref packages name))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (versions (map
+                           (lambda (version)
+                             (cons (fix-version version) version))
+                           versions))
+               (version (or (if (null? version) #f version)
+                            (latest-version (map car versions)))))
+          (assoc-ref package (assoc-ref versions version)))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp name version home-page description dependencies
+                       dev-dependencies licenses source)
+  "Return the `package' s-expression for a PHP package with the given NAME,
+VERSION, HOME-PAGE, DESCRIPTION, DEPENDENCIES, LICENSES and SOURCE."
+  (let ((git? (equal? (assoc-ref source "type") "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (assoc-ref source "url")
+                             (assoc-ref source "reference")
+                             temp))
+                (url-fetch (assoc-ref source "url") temp))
+            `(package
+               (name ,(php-package-name name))
+               (version ,version)
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(assoc-ref source "url"))
+                                        (commit ,(assoc-ref source "reference"))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(assoc-ref source "url"))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,description)
+               (home-page ,home-page)
+               (license ,(match licenses
+                           (() #f)
+                           ((license) (license->symbol license))
+                           (_ `(list ,@(map license->symbol licenses)))))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((name         (assoc-ref package "name"))
+                (version      (fix-version (assoc-ref package "version")))
+                (description  (beautify-description
+                               (assoc-ref package "description")))
+                (home-page    (assoc-ref package "homepage"))
+                (dependencies-names (filter
+                                      (lambda (dep)
+                                        (string-contains dep "/"))
+                                      (map car (assoc-ref package "require"))))
+                (dependencies (map php-package-name dependencies-names))
+                (require-dev (assoc-ref package "require-dev"))
+                (dev-dependencies-names
+                  (if require-dev
+                      (filter
+                        (lambda (dep)
+                          (string-contains dep "/"))
+                        (map car require-dev))
+                      '()))
+                (dev-dependencies (map php-package-name dev-dependencies-names))
+                (licenses     (map string->license
+                                   (vector->list
+                                    (assoc-ref package "license")))))
+           (values (make-php-sexp name version home-page description dependencies
+                                  dev-dependencies licenses (assoc-ref package "source"))
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" license:lgpl2.0)
+    ("GPL" license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") license:expat)
+    ("Public domain" license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (version (fix-version (assoc-ref metadata "version")))
+         (url (assoc-ref (assoc-ref metadata "source") "url")))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (latest latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index c6cc93fad8..4c91627283 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -76,7 +76,7 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem"
-                    "cran" "crate" "texlive" "json" "opam"))
+                    "cran" "crate" "texlive" "json" "opam" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
-- 
2.27.0





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

* [bug#42338] [PATCH 02/34] gnu: Add composer-classloader.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 03/34] guix: Add composer-build-system Julien Lepiller
                     ` (32 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk             |  1 +
 gnu/packages/php-xyz.scm | 61 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 gnu/packages/php-xyz.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index 3046a840c9..90d1b1302b 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -424,6 +424,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/photo.scm			\
   %D%/packages/phabricator.scm 			\
   %D%/packages/php.scm				\
+  %D%/packages/php-xyz.scm			\
   %D%/packages/pkg-config.scm			\
   %D%/packages/plotutils.scm			\
   %D%/packages/poedit.scm				\
diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
new file mode 100644
index 0000000000..dab660f84f
--- /dev/null
+++ b/gnu/packages/php-xyz.scm
@@ -0,0 +1,61 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (gnu packages php-xyz)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages php)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system composer)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix utils)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public composer-classloader
+  (package
+    (name "composer-classloader")
+    (version "1.9.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/composer/composer.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0127zmmg3yx84ljngfs86q7kjhyypybkf4d1ihfrfnzgynzxfxdf"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (delete 'build)
+         (delete 'check)
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (install (string-append out "/share/web/composer/ClassLoader.php")))
+               (mkdir-p (dirname install))
+               (copy-file "src/Composer/Autoload/ClassLoader.php" install)))))))
+    (home-page "https://getcomposer.org")
+    (synopsis "PHP class loader extracted from the composer package")
+    (description "This package contains the class loader class used by Composer to
+build its autoloading feature.  This package is used by the composer-build-system
+to build its own store-aware autoloading feature.")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 02/34] gnu: Add composer-classloader Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-09-07 14:09     ` Ludovic Courtès
  2020-07-12 22:25   ` [bug#42338] [PATCH 04/34] gnu: Add php-doctrine-instantiator Julien Lepiller
                     ` (31 subsequent siblings)
  33 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* guix/build-system/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   2 +
 doc/guix.texi                        |  14 ++
 guix/build-system/composer.scm       | 169 ++++++++++++++++++++
 guix/build-system/findclass.php      | 102 ++++++++++++
 guix/build/composer-build-system.scm | 224 +++++++++++++++++++++++++++
 5 files changed, 511 insertions(+)
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build-system/findclass.php
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index 623ddf32b2..363af872fa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -117,6 +117,7 @@ MODULES =					\
   guix/build-system/cargo.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/emacs.scm			\
@@ -164,6 +165,7 @@ MODULES =					\
   guix/build/cargo-build-system.scm		\
   guix/build/cargo-utils.scm			\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/emacs-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index 17338ed764..0613f669a0 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -6687,6 +6687,20 @@ debugging information''), which roughly means that code is compiled with
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvr
 
+@defvr {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvr
+
 @defvr {Scheme Variable} dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..19455b1920
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,169 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (local-file (string-append (current-source-directory) "/findclass.php")))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build json)
+    (guix build union)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:source #:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build store name inputs
+                         #:key (guile #f)
+                         (outputs '("out")) (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags ''("--strip-debug"))
+                         (strip-directories ''("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build json)
+                                    (guix build utils))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    `(begin
+       (use-modules ,@modules)
+       (composer-build #:source ,(match (assoc-ref inputs "source")
+                                   (((? derivation? source))
+                                    (derivation->output-path source))
+                                   ((source)
+                                    source)
+                                   (source
+                                    source))
+                       #:system ,system
+                       #:outputs %outputs
+                       #:inputs %build-inputs
+                       #:search-paths ',(map search-path-specification->sexp
+                                             search-paths)
+                       #:phases ,phases
+                       #:out-of-source? ,out-of-source?
+                       #:composer-file ,composer-file
+                       #:tests? ,tests?
+                       #:test-target ,test-target
+                       #:install-target ,install-target
+                       #:validate-runpath? ,validate-runpath?
+                       #:patch-shebangs? ,patch-shebangs?
+                       #:strip-binaries? ,strip-binaries?
+                       #:strip-flags ,strip-flags
+                       #:strip-directories ,strip-directories)))
+
+  (define guile-for-build
+    (match guile
+      ((? package?)
+       (package-derivation store guile system #:graft? #f))
+      (#f                                         ; the default
+       (let* ((distro (resolve-interface '(gnu packages commencement)))
+              (guile  (module-ref distro 'guile-final)))
+         (package-derivation store guile system #:graft? #f)))))
+
+  (build-expression->derivation store name builder
+                                #:system system
+                                #:inputs inputs
+                                #:modules imported-modules
+                                #:outputs outputs
+                                #:guile-for-build guile-for-build))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build-system/findclass.php b/guix/build-system/findclass.php
new file mode 100644
index 0000000000..a9704f809c
--- /dev/null
+++ b/guix/build-system/findclass.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..3578b91954
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,224 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build json)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (read-json port))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Install the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (match (assoc-ref package-data "scripts")
+                      (('@ script ...) script)
+                      (#f '())))
+           (test-script
+             (assoc-ref scripts test-target))
+           (dependencies (filter (lambda (dep) (string-contains dep "/"))
+                                 (map car
+                                      (match (assoc-ref package-data "require")
+                                        (('@ dependency ...) dependency)
+                                        (#f '())))))
+           (dependencies-dev
+             (filter (lambda (dep) (string-contains dep "/"))
+                     (map car
+                          (match (assoc-ref package-data "require-dev")
+                            (('@ dependency ...) dependency)
+                            (#f '())))))
+           (name (assoc-ref package-data "name")))
+      (for-each
+        (lambda (input)
+          (let ((bin (find-php-bin (cdr input))))
+            (when bin
+              (copy-recursively bin "vendor/bin"))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (equal? (system command) 0)
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (equal? (system c) 0)
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit")))))
+  #t)
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs (map cdr inputs)))
+    (if (null? inputs)
+        (throw 'unsatisfied-dependency "Unsatisfied dependency: required " dependency)
+        (let ((autoload (string-append (car inputs) "/share/web/" dependency "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop (cdr inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (format #t "<?php~%")
+      (format #t "// autoload.php @generated by Guix~%")
+      (format #t "$map = $psr4map = $classmap = array();~%")
+      (format #t "require_once '~a/autoload_conf.php';~%" vendor)
+      (format #t "require_once '~a/share/web/composer/ClassLoader.php';~%"
+                 (assoc-ref inputs "composer-classloader"))
+      (format #t "$loader = new \\Composer\\Autoload\\ClassLoader();~%")
+      (format #t "foreach ($map as $namespace => $path) {~%")
+      (format #t "  $loader->set($namespace, $path);~%")
+      (format #t "}~%")
+      (format #t "foreach ($psr4map as $namespace => $path) {~%")
+      (format #t "  $loader->setPsr4($namespace, $path);~%")
+      (format #t "}~%")
+      (format #t "$loader->addClassMap($classmap);~%")
+      (format #t "$loader->register();~%")))
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload
+           (match (assoc-ref package-data "autoload")
+             (('@ autoload ...) autoload)
+             (#f '())))
+         (autoload-dev
+           (match (assoc-ref package-data "autoload-dev")
+             (('@ autoload-dev ...) autoload-dev)
+             (#f '())))
+         (dependencies (filter (lambda (dep) (string-contains dep "/"))
+                               (map car
+                                    (match (assoc-ref package-data "require")
+                                      (('@ dependency ...) dependency)
+                                      (#f '())))))
+         (dependencies-dev
+           (filter (lambda (dep) (string-contains dep "/"))
+                   (map car
+                        (match (assoc-ref package-data "require-dev")
+                          (('@ dependency ...) dependency)
+                          (#f '()))))))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (match (assoc-ref autoload "psr-4")
+              (('@ psr4 ...) psr4)
+              (#f '()))
+            (if dev-dependencies?
+                (match (assoc-ref autoload-dev "psr-4")
+                  (('@ psr4 ...) psr4)
+                  (#f '()))
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (or (assoc-ref autoload "classmap") '())
+            (if dev-dependencies?
+                (or (assoc-ref autoload-dev "classmap") '())
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (assoc-ref package-data "name"))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (assoc-ref package-data "bin")))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs))
+  #t)
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
-- 
2.27.0





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

* [bug#42338] [PATCH 04/34] gnu: Add php-doctrine-instantiator.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 02/34] gnu: Add composer-classloader Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 03/34] guix: Add composer-build-system Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 05/34] gnu: Add php-sebastian-recursion-context Julien Lepiller
                     ` (30 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-doctrine-instantiator): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index dab660f84f..28d8909dad 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -59,3 +59,26 @@
 build its autoloading feature.  This package is used by the composer-build-system
 to build its own store-aware autoloading feature.")
     (license license:expat)))
+
+(define-public php-doctrine-instantiator
+  (package
+    (name "php-doctrine-instantiator")
+    (version "1.3.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/doctrine/instantiator.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "17c72j29p77gdgh06b9qc0nivmav0k5yc22z4ryygj7dhr1h65nq"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Utility for instantiating PHP objects")
+    (description "This package provides a small, lightweight utility to
+instantiate objects in PHP without invoking their constructors")
+    (home-page "https://www.doctrine-project.org/projects/instantiator.html")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 05/34] gnu: Add php-sebastian-recursion-context.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (2 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 04/34] gnu: Add php-doctrine-instantiator Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 06/34] gnu: Add php-sebastian-exporter Julien Lepiller
                     ` (29 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-recursion-context): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 28d8909dad..b04b8e0859 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -82,3 +82,26 @@ to build its own store-aware autoloading feature.")
 instantiate objects in PHP without invoking their constructors")
     (home-page "https://www.doctrine-project.org/projects/instantiator.html")
     (license license:expat)))
+
+(define-public php-sebastian-recursion-context
+  (package
+    (name "php-sebastian-recursion-context")
+    (version "4.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/recursion-context.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0glpydmvr95f9xbmh76vgid2nz7rf6lxwfz1j7ksvgmf4m1dniyz"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Process PHP variables recursively")
+    (description "This package provides functionality to recursively process
+PHP variables")
+    (home-page "http://www.github.com/sebastianbergmann/recursion-context")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 06/34] gnu: Add php-sebastian-exporter.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (3 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 05/34] gnu: Add php-sebastian-recursion-context Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 07/34] gnu: Add php-myclabs-deep-copy Julien Lepiller
                     ` (28 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-exporter): New variable.
---
 gnu/packages/php-xyz.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index b04b8e0859..ae7d7ff6b2 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -105,3 +105,28 @@ instantiate objects in PHP without invoking their constructors")
 PHP variables")
     (home-page "http://www.github.com/sebastianbergmann/recursion-context")
     (license license:bsd-3)))
+
+(define-public php-sebastian-exporter
+  (package
+    (name "php-sebastian-exporter")
+    (version "4.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/exporter.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "03xj9gbi8ifnbj5n72gfpwyg65l71gg1r8yvzpbg6d3yxbqaa8f6"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-sebastian-recursion-context" ,php-sebastian-recursion-context)))
+    (synopsis "Visualize PHP variables")
+    (description "This package provides the functionality to export PHP
+variables for visualization")
+    (home-page "http://www.github.com/sebastianbergmann/exporter")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 07/34] gnu: Add php-myclabs-deep-copy.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (4 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 06/34] gnu: Add php-sebastian-exporter Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 08/34] gnu: Add php-phar-io-version Julien Lepiller
                     ` (27 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-myclabs-deep-copy): New variable.
---
 gnu/packages/php-xyz.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index ae7d7ff6b2..a45726a484 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -130,3 +130,28 @@ PHP variables")
 variables for visualization")
     (home-page "http://www.github.com/sebastianbergmann/exporter")
     (license license:bsd-3)))
+
+(define-public php-myclabs-deep-copy
+  (package
+    (name "php-myclabs-deep-copy")
+    (version "1.10.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/myclabs/DeepCopy.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1ms4qhx5cf19ggdicnd7qjrigwam206py6mj6nw8bz71mafq9nbi"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Create copies of PHP objects")
+    (description "This package contains a facility to create deep copies (clones)
+of PHP objects.  This package not only creates a new copy of an object, it
+recursively create new copies of any object referenced by the object.  It is
+designed to work even in the presence of cycles in the association graph.")
+    (home-page "https://github.com/myclabs/DeepCopy.git")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 08/34] gnu: Add php-phar-io-version.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (5 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 07/34] gnu: Add php-myclabs-deep-copy Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 09/34] gnu: Add php-phar-io-manifest Julien Lepiller
                     ` (26 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phar-io-version): New variable.
---
 gnu/packages/php-xyz.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index a45726a484..0b64efe6ca 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -155,3 +155,28 @@ recursively create new copies of any object referenced by the object.  It is
 designed to work even in the presence of cycles in the association graph.")
     (home-page "https://github.com/myclabs/DeepCopy.git")
     (license license:expat)))
+
+(define-public php-phar-io-version
+  (package
+    (name "php-phar-io-version")
+    (version "3.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/phar-io/version.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0r9470p0azw7l0x2wbn7kh0zhpswvjnm32vc8vml5v5nskmnqz4c"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (properties
+     `((upstream-name . "phar-io/version")))
+    (synopsis "Library for handling version information and constraints")
+    (description "This package contains a library for handling version information
+and constraints.")
+    (home-page "https://phar.io")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 09/34] gnu: Add php-phar-io-manifest.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (6 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 08/34] gnu: Add php-phar-io-version Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 10/34] gnu: Add php-symfony-polyfill-ctype Julien Lepiller
                     ` (25 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* qnu/packages/php-xyz.scm (php-phar-io-manifest): New variable.
---
 gnu/packages/php-xyz.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 0b64efe6ca..f0f4fe650a 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -180,3 +180,30 @@ designed to work even in the presence of cycles in the association graph.")
 and constraints.")
     (home-page "https://phar.io")
     (license license:bsd-3)))
+
+(define-public php-phar-io-manifest
+  (package
+    (name "php-phar-io-manifest")
+    (version "2.0.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/phar-io/manifest.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0r2s1qdkhn7782g1y6skxvp5w397vmwb496fymsnik2818w0q469"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-phar-io-version" ,php-phar-io-version)))
+    (properties
+     `((upstream-name . "phar-io/manifest")))
+    (synopsis "PHP Archive information reader")
+    (description "This package contains a component for reading phar.io manifest
+information from a PHP Archive (PHAR)")
+    (home-page "https://phar.io")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 10/34] gnu: Add php-symfony-polyfill-ctype.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (7 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 09/34] gnu: Add php-phar-io-manifest Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 11/34] gnu: Add php-webmozart-assert Julien Lepiller
                     ` (24 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php.scm (php-symfony-polyfill-ctype): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index f0f4fe650a..51e51ac51b 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -207,3 +207,26 @@ and constraints.")
 information from a PHP Archive (PHAR)")
     (home-page "https://phar.io")
     (license license:bsd-3)))
+
+(define-public php-symfony-polyfill-ctype
+  (package
+    (name "php-symfony-polyfill-ctype")
+    (version "1.17.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/symfony/polyfill-ctype.git")
+                     (commit (string-append "v" version))))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0bh22vwq2idy7fi8ajm6aggjdvds64s98y9854b5gl9s84dk9pz8"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Ctype functions for older PHP versions")
+    (description "This component provides @code{ctype_*} functions to users
+who run php versions without the ctype extension.")
+    (home-page "https://symfony.com")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 11/34] gnu: Add php-webmozart-assert.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (8 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 10/34] gnu: Add php-symfony-polyfill-ctype Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 12/34] gnu: Add php-phpdocumentor-reflection-common Julien Lepiller
                     ` (23 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-webmozart-assert): New variable.
---
 gnu/packages/php-xyz.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 51e51ac51b..ffc2eb7b11 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -230,3 +230,28 @@ information from a PHP Archive (PHAR)")
 who run php versions without the ctype extension.")
     (home-page "https://symfony.com")
     (license license:expat)))
+
+(define-public php-webmozart-assert
+  (package
+    (name "php-webmozart-assert")
+    (version "1.9.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/webmozart/assert.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1q9bp4sp11r8ghdzr0qswdf1k5bf9b5s525im3kspar6y8019sh9"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-symfony-polyfill-ctype" ,php-symfony-polyfill-ctype)))
+    (synopsis "Assertions to validate method input/output with nice error messages.")
+    (description "This library contains efficient assertions to test the input
+and output of PHP methods.")
+    (home-page "https://github.com/webmozart/assert")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 12/34] gnu: Add php-phpdocumentor-reflection-common.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (9 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 11/34] gnu: Add php-webmozart-assert Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 13/34] gnu: Add php-phpdocumentor-type-resolver Julien Lepiller
                     ` (22 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpdocumentor-reflection-common): New
variable.
---
 gnu/packages/php-xyz.scm | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index ffc2eb7b11..9b604c46f0 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -255,3 +255,27 @@ who run php versions without the ctype extension.")
 and output of PHP methods.")
     (home-page "https://github.com/webmozart/assert")
     (license license:expat)))
+
+(define-public php-phpdocumentor-reflection-common
+  (package
+    (name "php-phpdocumentor-reflection-common")
+    (version "2.2.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/phpDocumentor/ReflectionCommon.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1q685cpwbfxqy42iz61xxv6zbcc1qskn07nkipflj6c5s935l8jy"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Common reflection classes used by phpdocumentor to reflect
+the code structure")
+    (description "This package contains common classes used by phpdocumentor
+to analyze the code structure.")
+    (home-page "http://www.phpdoc.org")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 13/34] gnu: Add php-phpdocumentor-type-resolver.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (10 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 12/34] gnu: Add php-phpdocumentor-reflection-common Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 14/34] gnu: Add php-phpdocumentor-reflection-docblock Julien Lepiller
                     ` (21 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpdocumentor-type-resolver): New
variable.
---
 gnu/packages/php-xyz.scm | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 9b604c46f0..93d8649bee 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -279,3 +279,28 @@ the code structure")
 to analyze the code structure.")
     (home-page "http://www.phpdoc.org")
     (license license:expat)))
+
+(define-public php-phpdocumentor-type-resolver
+  (package
+    (name "php-phpdocumentor-type-resolver")
+    (version "1.3.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/phpDocumentor/TypeResolver.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0wshv49z4hxraygg2vhzn0s9ih2y9ymzpcnyjfk14vcfq5yx53l9"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-phpdocumentor-reflection-common" ,php-phpdocumentor-reflection-common)))
+    (synopsis "Resolver of class names, types and structural element names")
+    (description "This package provides a PSR-5 based resolver of class names,
+types and structural element names.")
+    (home-page "http://www.phpdoc.org")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 14/34] gnu: Add php-phpdocumentor-reflection-docblock.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (11 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 13/34] gnu: Add php-phpdocumentor-type-resolver Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 15/34] gnu: Add php-theseer-tokenizer Julien Lepiller
                     ` (20 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpdocumentor-reflection-docblock): New
variable.
---
 gnu/packages/php-xyz.scm | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 93d8649bee..df9c490bbf 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -304,3 +304,31 @@ to analyze the code structure.")
 types and structural element names.")
     (home-page "http://www.phpdoc.org")
     (license license:expat)))
+
+(define-public php-phpdocumentor-reflection-docblock
+  (package
+    (name "php-phpdocumentor-reflection-docblock")
+    (version "5.1.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/phpDocumentor/ReflectionDocBlock.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1bsqwcq5ix7f5p56kc92pl1nqpjdpfc92pjvwyshp1syrrspa3rr"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-webmozart-assert" ,php-webmozart-assert)
+       ("php-phpdocumentor-reflection-common" ,php-phpdocumentor-reflection-common)
+       ("php-phpdocumentor-type-resolver" ,php-phpdocumentor-type-resolver)))
+    (synopsis "Library for retrieving documentation in code fro the code")
+    (description "With this component, a library can provide support for
+annotations via DocBlocks or otherwise retrieve information that is embedded
+in a DocBlock.")
+    (home-page "https://github.com/phpDocumentor/ReflectionDocBlock")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 15/34] gnu: Add php-theseer-tokenizer.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (12 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 14/34] gnu: Add php-phpdocumentor-reflection-docblock Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 16/34] gnu: Add php-sebastian-code-unit-reverse-lookup Julien Lepiller
                     ` (19 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-theseer-tokenizer): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index df9c490bbf..f54b875d92 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -332,3 +332,26 @@ annotations via DocBlocks or otherwise retrieve information that is embedded
 in a DocBlock.")
     (home-page "https://github.com/phpDocumentor/ReflectionDocBlock")
     (license license:expat)))
+
+(define-public php-theseer-tokenizer
+  (package
+    (name "php-theseer-tokenizer")
+    (version "1.1.3")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/theseer/tokenizer.git")
+                     (commit "11336f6f84e16a720dae9d8e6ed5019efa85a0f9")))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0j436a3jpynnlqrvd7la7a7smj78aklkragwa9l8p91973xra18l"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Convert PHP to XML")
+    (description "This package provides a small library for converting tokenized
+PHP source code into XML and potentially other formats.")
+    (home-page "https://github.com/theseer/tokenizer")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 16/34] gnu: Add php-sebastian-code-unit-reverse-lookup.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (13 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 15/34] gnu: Add php-theseer-tokenizer Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 17/34] gnu: Add php-phpunit-php-token-stream Julien Lepiller
                     ` (18 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-code-unit-reverse-lookup): New
variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index f54b875d92..13584273f9 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -355,3 +355,26 @@ in a DocBlock.")
 PHP source code into XML and potentially other formats.")
     (home-page "https://github.com/theseer/tokenizer")
     (license license:bsd-3)))
+
+(define-public php-sebastian-code-unit-reverse-lookup
+  (package
+    (name "php-sebastian-code-unit-reverse-lookup")
+    (version "2.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0lppni3qcd6gx50jf16y3n71ldj12xjd06kl9ml78zd5p2s6z4qc"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Look up function name from location")
+    (description "This package provides a facility to look up which function or
+method a line of code belongs to.")
+    (home-page "https://github.com/sebastianbergmann/code-unit-reverse-lookup/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 17/34] gnu: Add php-phpunit-php-token-stream.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (14 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 16/34] gnu: Add php-sebastian-code-unit-reverse-lookup Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 18/34] gnu: Add php-sebastian-version Julien Lepiller
                     ` (17 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-php-token-stream): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 13584273f9..344c413d2c 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -378,3 +378,26 @@ PHP source code into XML and potentially other formats.")
 method a line of code belongs to.")
     (home-page "https://github.com/sebastianbergmann/code-unit-reverse-lookup/")
     (license license:bsd-3)))
+
+(define-public php-phpunit-php-token-stream
+  (package
+    (name "php-phpunit-php-token-stream")
+    (version "4.0.3")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/php-token-stream.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0iv8ssvyjhgxa1qpp5s8i0j409w49s2kc9qwv1c27qgdhv7yhf7h"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Wrapper around PHP's tokenizer extension")
+    (description "This library provides a wrapper around PHP's tokenizer
+extension.")
+    (home-page "https://github.com/sebastianbergmann/php-token-stream/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 18/34] gnu: Add php-sebastian-version.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (15 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 17/34] gnu: Add php-phpunit-php-token-stream Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 19/34] gnu: Add php-phpunit-php-file-iterator Julien Lepiller
                     ` (16 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-version): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 344c413d2c..906a88d49e 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -401,3 +401,26 @@ method a line of code belongs to.")
 extension.")
     (home-page "https://github.com/sebastianbergmann/php-token-stream/")
     (license license:bsd-3)))
+
+(define-public php-sebastian-version
+  (package
+    (name "php-sebastian-version")
+    (version "3.0.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/version.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1kr2i6s7y4k18bz09cqj4pc4bqzph9n6ncgpqq4p4fg790h5i5ym"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "PHP versionning library")
+    (description "This package is a library that helps with managing the version
+number of Git-hosted PHP projects.")
+    (home-page "https://github.com/sebastianbergmann/version")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 19/34] gnu: Add php-phpunit-php-file-iterator.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (16 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 18/34] gnu: Add php-sebastian-version Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 20/34] gnu: Add php-phpunit-php-text-template Julien Lepiller
                     ` (15 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-php-file-iterator): New
variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 906a88d49e..5d06bea0cb 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -424,3 +424,26 @@ extension.")
 number of Git-hosted PHP projects.")
     (home-page "https://github.com/sebastianbergmann/version")
     (license license:bsd-3)))
+
+(define-public php-phpunit-php-file-iterator
+  (package
+    (name "php-phpunit-php-file-iterator")
+    (version "3.0.4")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/php-file-iterator.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1pglbp8m4iv5w16gshlp49k4ngpsx28mhwip761kyvvd5w27ysr2"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Filter file by extension")
+    (description "This package contains a @code{FilterIterator} implementation
+that filters files based on a list of suffixes.")
+    (home-page "https://github.com/sebastianbergmann/php-file-iterator/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 20/34] gnu: Add php-phpunit-php-text-template.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (17 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 19/34] gnu: Add php-phpunit-php-file-iterator Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 21/34] gnu: Add php-sebastian-diff Julien Lepiller
                     ` (14 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-php-text-template): New
variable.
---
 gnu/packages/php-xyz.scm | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 5d06bea0cb..b5abcaae36 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -447,3 +447,25 @@ number of Git-hosted PHP projects.")
 that filters files based on a list of suffixes.")
     (home-page "https://github.com/sebastianbergmann/php-file-iterator/")
     (license license:bsd-3)))
+
+(define-public php-phpunit-php-text-template
+  (package
+    (name "php-phpunit-php-text-template")
+    (version "2.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/php-text-template.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0x38kj1xlnysg9xgad560k361l93vh32mvkyfn7rss3p2r319jhx"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Simple template engine")
+    (description "This package contains a library for a simple templating engine.")
+    (home-page "https://github.com/sebastianbergmann/php-text-template/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 21/34] gnu: Add php-sebastian-diff.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (18 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 20/34] gnu: Add php-phpunit-php-text-template Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 22/34] gnu: Add php-sebastian-comparator Julien Lepiller
                     ` (13 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-diff): New variable.
---
 gnu/packages/php-xyz.scm | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index b5abcaae36..ccc613baaf 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -469,3 +469,25 @@ that filters files based on a list of suffixes.")
     (description "This package contains a library for a simple templating engine.")
     (home-page "https://github.com/sebastianbergmann/php-text-template/")
     (license license:bsd-3)))
+
+(define-public php-sebastian-diff
+  (package
+    (name "php-sebastian-diff")
+    (version "4.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/diff.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0fr5vrmz3d1wwpf59y16fin5lgi55sjd7dqfkx0zqmsqadbjrjxq"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Diff implementation")
+    (description "This package contains a PHP implementation of a diff function.")
+    (home-page "https://github.com/sebastianbergmann/diff")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 22/34] gnu: Add php-sebastian-comparator.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (19 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 21/34] gnu: Add php-sebastian-diff Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 23/34] gnu: Add php-sebastian-environment Julien Lepiller
                     ` (12 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-comparator): New variable.
---
 gnu/packages/php-xyz.scm | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index ccc613baaf..aff2ed79a7 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -491,3 +491,29 @@ that filters files based on a list of suffixes.")
     (description "This package contains a PHP implementation of a diff function.")
     (home-page "https://github.com/sebastianbergmann/diff")
     (license license:bsd-3)))
+
+(define-public php-sebastian-comparator
+  (package
+    (name "php-sebastian-comparator")
+    (version "4.0.3")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/comparator.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1scw7vm26layqh5mzvdhjiil520fj6ipixkjnmwm036xr925iww0"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-sebastian-exporter" ,php-sebastian-exporter)
+       ("php-sebastian-diff" ,php-sebastian-diff)))
+    (synopsis "PHP value comparison")
+    (description "This package provides the functionality to compare PHP values
+for equality.")
+    (home-page "https://github.com/sebastianbergmann/comparator")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 23/34] gnu: Add php-sebastian-environment.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (20 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 22/34] gnu: Add php-sebastian-comparator Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 24/34] gnu: Add php-phpspec-prophecy Julien Lepiller
                     ` (11 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-environment): New variable.
---
 gnu/packages/php-xyz.scm | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index aff2ed79a7..9ee823bcda 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -517,3 +517,25 @@ that filters files based on a list of suffixes.")
 for equality.")
     (home-page "https://github.com/sebastianbergmann/comparator")
     (license license:bsd-3)))
+
+(define-public php-sebastian-environment
+  (package
+    (name "php-sebastian-environment")
+    (version "5.1.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/environment.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0lhaiwk6dbwii9kmjaq3gjl2x5s1rikmxkvmy4mjvjcbi7imp38s"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Handle HHVM and PHP environments")
+    (description "This package provides functionality to handle HHVM/PHP environments")
+    (home-page "http://www.github.com/sebastianbergmann/environment")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 24/34] gnu: Add php-phpspec-prophecy.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (21 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 23/34] gnu: Add php-sebastian-environment Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 25/34] gnu: Add php-sebastian-object-reflector Julien Lepiller
                     ` (10 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpspec-prophecy): New variable.
---
 gnu/packages/php-xyz.scm | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 9ee823bcda..8c96d9aabc 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -539,3 +539,32 @@ for equality.")
     (description "This package provides functionality to handle HHVM/PHP environments")
     (home-page "http://www.github.com/sebastianbergmann/environment")
     (license license:bsd-3)))
+
+(define-public php-phpspec-prophecy
+  (package
+    (name "php-phpspec-prophecy")
+    (version "1.11.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/phpspec/prophecy.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1pd6iz6pbfpaz5rqa36q01l569zgiqpjgqmzw3rra2qdh1jrwdy1"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-sebastian-recursion-context" ,php-sebastian-recursion-context)
+       ("php-doctrine-instantiator" ,php-doctrine-instantiator)
+       ("php-sebastian-comparator" ,php-sebastian-comparator)
+       ("php-phpdocumentor-reflection-docblock"
+	,php-phpdocumentor-reflection-docblock)))
+    (synopsis "Mocking framework for PHP 5.3+")
+    (description "This package contains a mocking framework for testing PHP
+5.3+ projects.")
+    (home-page "https://github.com/phpspec/prophecy")
+    (license license:expat)))
-- 
2.27.0





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

* [bug#42338] [PATCH 25/34] gnu: Add php-sebastian-object-reflector.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (22 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 24/34] gnu: Add php-phpspec-prophecy Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 26/34] gnu: Add php-sebastian-global-state Julien Lepiller
                     ` (9 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-object-reflector): New
variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 8c96d9aabc..899f6a3f69 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -568,3 +568,26 @@ for equality.")
 5.3+ projects.")
     (home-page "https://github.com/phpspec/prophecy")
     (license license:expat)))
+
+(define-public php-sebastian-object-reflector
+  (package
+    (name "php-sebastian-object-reflector")
+    (version "2.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/object-reflector.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1qkvp2s932h53f161l30qlnxicw4fklirmnds173wgmavms1b5yb"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "PHP reflexion library")
+    (description "This package allows reflection of object attributes, including
+inherited and non-public ones.")
+    (home-page "https://github.com/sebastianbergmann/object-reflector/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 26/34] gnu: Add php-sebastian-global-state.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (23 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 25/34] gnu: Add php-sebastian-object-reflector Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 27/34] gnu: Add php-sebastian-object-enumerator Julien Lepiller
                     ` (8 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-global-state): New variable.
---
 gnu/packages/php-xyz.scm | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 899f6a3f69..4872523b31 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -591,3 +591,30 @@ for equality.")
 inherited and non-public ones.")
     (home-page "https://github.com/sebastianbergmann/object-reflector/")
     (license license:bsd-3)))
+
+(define-public php-sebastian-global-state
+  (package
+    (name "php-sebastian-global-state")
+    (version "4.0.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/global-state.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0x6sfw353px5y7azipn2mb15w7w7zxbbpbv3dbhhkryrhad8w064"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-sebastian-recursion-context" ,php-sebastian-recursion-context)
+       ("php-sebastian-object-reflector" ,php-sebastian-object-reflector)))
+    (synopsis "Snapshotting of global state")
+    (description "This package contains a stand-alone component originally part
+of PHPUnit.  It provides support for creating a snapshot of the global state
+of a PHP program.")
+    (home-page "http://www.github.com/sebastianbergmann/global-state")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 27/34] gnu: Add php-sebastian-object-enumerator.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (24 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 26/34] gnu: Add php-sebastian-global-state Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 28/34] gnu: Add php-sebastian-resource-operations Julien Lepiller
                     ` (7 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-object-enumerator): New
variable.
---
 gnu/packages/php-xyz.scm | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 4872523b31..8cf5668030 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -618,3 +618,29 @@ of PHPUnit.  It provides support for creating a snapshot of the global state
 of a PHP program.")
     (home-page "http://www.github.com/sebastianbergmann/global-state")
     (license license:bsd-3)))
+
+(define-public php-sebastian-object-enumerator
+  (package
+    (name "php-sebastian-object-enumerator")
+    (version "4.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/object-enumerator.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1qx28r0ncbh0x9i0jplyg870paxxsy7g1ibgbdqq11176101aj6q"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-sebastian-recursion-context" ,php-sebastian-recursion-context)
+       ("php-sebastian-object-reflector" ,php-sebastian-object-reflector)))
+    (synopsis "Enumerate PHP objects")
+    (description "This package allows PHP programs to traverse array structures
+and object graphs to enumerate all referenced objects.")
+    (home-page "https://github.com/sebastianbergmann/object-enumerator/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 28/34] gnu: Add php-sebastian-resource-operations.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (25 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 27/34] gnu: Add php-sebastian-object-enumerator Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 29/34] gnu: Add php-sebastian-type Julien Lepiller
                     ` (6 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-resource-operations): New
variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 8cf5668030..aee08c0878 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -644,3 +644,26 @@ of a PHP program.")
 and object graphs to enumerate all referenced objects.")
     (home-page "https://github.com/sebastianbergmann/object-enumerator/")
     (license license:bsd-3)))
+
+(define-public php-sebastian-resource-operations
+  (package
+    (name "php-sebastian-resource-operations")
+    (version "3.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/resource-operations.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "09s2gsmx6fg8sx64yyz2dszy22dcsspazlhskv3d9mflpmrk0d9y"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "List built-in PHP functions")
+    (description "This package provides a list of PHP built-in functions that
+operate on resources.")
+    (home-page "https://www.github.com/sebastianbergmann/resource-operations")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 29/34] gnu: Add php-sebastian-type.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (26 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 28/34] gnu: Add php-sebastian-resource-operations Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 30/34] gnu: Add php-phpunit-php-code-coverage Julien Lepiller
                     ` (5 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-type): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index aee08c0878..9a50c431b7 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -667,3 +667,26 @@ and object graphs to enumerate all referenced objects.")
 operate on resources.")
     (home-page "https://www.github.com/sebastianbergmann/resource-operations")
     (license license:bsd-3)))
+
+(define-public php-sebastian-type
+  (package
+    (name "php-sebastian-type")
+    (version "2.2.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/type.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0gvdb9188a4903q0dnhhdcm9qd67is5pns8jbccxr7hxv8w7d7h3"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "PHP type system representation")
+    (description "This package is a collection of value objects that represent
+the types of the PHP type system.")
+    (home-page "https://github.com/sebastianbergmann/type")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 30/34] gnu: Add php-phpunit-php-code-coverage.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (27 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 29/34] gnu: Add php-sebastian-type Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 31/34] gnu: Add php-phpunit-php-timer Julien Lepiller
                     ` (4 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-php-code-coverage): New
variable.
---
 gnu/packages/php-xyz.scm | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 9a50c431b7..2d186c5190 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -690,3 +690,35 @@ operate on resources.")
 the types of the PHP type system.")
     (home-page "https://github.com/sebastianbergmann/type")
     (license license:bsd-3)))
+
+(define-public php-phpunit-php-code-coverage
+  (package
+    (name "php-phpunit-php-code-coverage")
+    (version "8.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/php-code-coverage.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1qr7x9y8636bvv0fk8hl0kl9d2y8fy6qw65kpi4yb1yyqhfddkgh"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (inputs
+     `(("php-theseer-tokenizer" ,php-theseer-tokenizer)
+       ("php-sebastian-version" ,php-sebastian-version)
+       ("php-sebastian-environment" ,php-sebastian-environment)
+       ("php-sebastian-code-unit-reverse-lookup"
+	,php-sebastian-code-unit-reverse-lookup)
+       ("php-phpunit-php-text-template" ,php-phpunit-php-text-template)
+       ("php-phpunit-php-token-stream" ,php-phpunit-php-token-stream)
+       ("php-phpunit-php-file-iterator" ,php-phpunit-php-file-iterator)))
+    (synopsis "Code coverage information library")
+    (description "This package is a library that provides collection,
+processing, and rendering functionality for PHP code coverage information.")
+    (home-page "https://github.com/sebastianbergmann/php-code-coverage")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 31/34] gnu: Add php-phpunit-php-timer.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (28 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 30/34] gnu: Add php-phpunit-php-code-coverage Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 32/34] gnu: Add php-phpunit-php-invoker Julien Lepiller
                     ` (3 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-php-timer): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 2d186c5190..1b6669abcc 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -722,3 +722,26 @@ the types of the PHP type system.")
 processing, and rendering functionality for PHP code coverage information.")
     (home-page "https://github.com/sebastianbergmann/php-code-coverage")
     (license license:bsd-3)))
+
+(define-public php-phpunit-php-timer
+  (package
+    (name "php-phpunit-php-timer")
+    (version "5.0.1")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/php-timer.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0hyy5c8b22zki6836a7fhzr3s6dpvga33r2rzfrsbv1arh19ay60"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "Utility class for timing")
+    (description "This package contains a stand-alone component originally part
+of PHPUnit.  It provides a utility class for timing.")
+    (home-page "https://github.com/sebastianbergmann/php-timer/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 32/34] gnu: Add php-phpunit-php-invoker.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (29 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 31/34] gnu: Add php-phpunit-php-timer Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 33/34] gnu: Add php-sebastian-code-unit Julien Lepiller
                     ` (2 subsequent siblings)
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-php-invoker): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 1b6669abcc..484fb17790 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -745,3 +745,26 @@ processing, and rendering functionality for PHP code coverage information.")
 of PHPUnit.  It provides a utility class for timing.")
     (home-page "https://github.com/sebastianbergmann/php-timer/")
     (license license:bsd-3)))
+
+(define-public php-phpunit-php-invoker
+  (package
+    (name "php-phpunit-php-invoker")
+    (version "3.0.2")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/php-invoker.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1xs7m0wiminnhkd400glmixyhrx1ir710j6fds9i03dhicfcj7db"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "PHP library for invoking functions")
+    (description "This package contains a library to invoke callables with a
+timeout.")
+    (home-page "https://github.com/sebastianbergmann/php-invoker/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 33/34] gnu: Add php-sebastian-code-unit.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (30 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 32/34] gnu: Add php-phpunit-php-invoker Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-07-12 22:25   ` [bug#42338] [PATCH 34/34] gnu: Add phpunit Julien Lepiller
  2020-09-07 14:06   ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Ludovic Courtès
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-sebastian-code-unit): New variable.
---
 gnu/packages/php-xyz.scm | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 484fb17790..0ae92c4600 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -768,3 +768,26 @@ of PHPUnit.  It provides a utility class for timing.")
 timeout.")
     (home-page "https://github.com/sebastianbergmann/php-invoker/")
     (license license:bsd-3)))
+
+(define-public php-sebastian-code-unit
+  (package
+    (name "php-sebastian-code-unit")
+    (version "1.0.5")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/code-unit.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "058ykqcmzm900c513j2qvi189bgn0scxsrhbrik5xycrr620krxc"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; We do not have phpunit yet
+     `(#:tests? #f))
+    (synopsis "PHP collection of value objects for code units")
+    (description "This package contains a collection of value objects that
+represent the PHP code units.")
+    (home-page "https://github.com/sebastianbergmann/code-unit")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 34/34] gnu: Add phpunit.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (31 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 33/34] gnu: Add php-sebastian-code-unit Julien Lepiller
@ 2020-07-12 22:25   ` Julien Lepiller
  2020-09-07 14:06   ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Ludovic Courtès
  33 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2020-07-12 22:25 UTC (permalink / raw)
  To: 42338

* gnu/packages/php-xyz.scm (php-phpunit-phpunit): New variable.
---
 gnu/packages/php-xyz.scm | 45 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
index 0ae92c4600..eebf64c1a3 100644
--- a/gnu/packages/php-xyz.scm
+++ b/gnu/packages/php-xyz.scm
@@ -791,3 +791,48 @@ timeout.")
 represent the PHP code units.")
     (home-page "https://github.com/sebastianbergmann/code-unit")
     (license license:bsd-3)))
+
+(define-public php-phpunit-phpunit
+  (package
+    (name "phpunit")
+    (version "9.2.5")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/sebastianbergmann/phpunit.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "1ck41faxkqr6painsqirklzsl08k8biadi2ksnpsmpjf3dp5p5gl"))))
+    (build-system composer-build-system)
+    (arguments
+     ;; Requires phpspec/prophecy-phpunit, which in turns requires phpunit.
+     `(#:tests? #f))
+    (inputs
+     `(("php-sebastian-version" ,php-sebastian-version)
+       ("php-sebastian-type" ,php-sebastian-type)
+       ("php-sebastian-resource-operations" ,php-sebastian-resource-operations)
+       ("php-sebastian-object-enumerator" ,php-sebastian-object-enumerator)
+       ("php-sebastian-global-state" ,php-sebastian-global-state)
+       ("php-sebastian-exporter" ,php-sebastian-exporter)
+       ("php-sebastian-environment" ,php-sebastian-environment)
+       ("php-sebastian-diff" ,php-sebastian-diff)
+       ("php-sebastian-comparator" ,php-sebastian-comparator)
+       ("php-sebastian-code-unit" ,php-sebastian-code-unit)
+       ("php-phpunit-php-timer" ,php-phpunit-php-timer)
+       ("php-phpunit-php-text-template" ,php-phpunit-php-text-template)
+       ("php-phpunit-php-invoker" ,php-phpunit-php-invoker)
+       ("php-phpunit-php-file-iterator" ,php-phpunit-php-file-iterator)
+       ("php-phpunit-php-code-coverage" ,php-phpunit-php-code-coverage)
+       ("php-phpspec-prophecy" ,php-phpspec-prophecy)
+       ("php-phar-io-version" ,php-phar-io-version)
+       ("php-phar-io-manifest" ,php-phar-io-manifest)
+       ("php-myclabs-deep-copy" ,php-myclabs-deep-copy)
+       ("php-doctrine-instantiator" ,php-doctrine-instantiator)))
+    (properties `((upstream-name . "phpunit/phpunit")))
+    (synopsis "PHP Unit Testing framework")
+    (description "PHPUnit is a testing framework for PHP.  It is an instance of
+the xUnit architecture for unit testing frameworks.")
+    (home-page "https://phpunit.de/")
+    (license license:bsd-3)))
-- 
2.27.0





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

* [bug#42338] [PATCH 01/34] guix: import: Add composer importer.
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
                     ` (32 preceding siblings ...)
  2020-07-12 22:25   ` [bug#42338] [PATCH 34/34] gnu: Add phpunit Julien Lepiller
@ 2020-09-07 14:06   ` Ludovic Courtès
  2020-09-17 22:43     ` Julien Lepiller
  33 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-07 14:06 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi Julien,

There’s a lot of interesting work in here!  I’m not familiar with PHP;
I’ll just make a bird’s eye review.

Julien Lepiller <julien@lepiller.eu> skribis:

> * guix/import/composer.scm: New file.
> * guix/scripts/import/composer.scm: New file.
> * Makefile.am: Add them.
> * guix/scripts/import.scm: Add composer importer.

Please add tests and a mention in “Invoking guix import” in the manual.

For tests, a strategy that I think works well is that used in
tests/cpan.scm, where we spawn an HTTP server to mock the real one.

> +(define* (composer-fetch name #:optional version)
> +  "Return an alist representation of the Composer metadata for the package NAME,
> +or #f on failure."
> +  (let ((package (json-fetch
> +                   (string-append "https://repo.packagist.org/p/" name ".json"))))
> +    (if package
> +        (let* ((packages (assoc-ref package "packages"))
> +               (package (assoc-ref packages name))
> +               (versions (filter
> +                           (lambda (version)
> +                             (and (not (string-contains version "dev"))
> +                                  (not (string-contains version "beta"))))
> +                           (map car package)))
> +               (versions (map
> +                           (lambda (version)
> +                             (cons (fix-version version) version))
> +                           versions))
> +               (version (or (if (null? version) #f version)
> +                            (latest-version (map car versions)))))
> +          (assoc-ref package (assoc-ref versions version)))
> +        #f)))

I recommend using ‘define-json-mapping’ instead of browsing alists: it’s
less error-prone, hides the JSON details away, and leads to more
readable code.  The pypi, crates, cpan importers use it.

Thanks!

Ludo’.




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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-07-12 22:25   ` [bug#42338] [PATCH 03/34] guix: Add composer-build-system Julien Lepiller
@ 2020-09-07 14:09     ` Ludovic Courtès
  2020-09-17 22:44       ` Julien Lepiller
  0 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-07 14:09 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Julien Lepiller <julien@lepiller.eu> skribis:

> * guix/build-system/composer.scm: New file.
> * guix/build/composer-build-system.scm: New file.
> * guix/build-system/findclass.php: New file.
> * Makefile.am: Add them.
> * doc/guix.texi (Build Systems): Document it.

[...]

> +++ b/guix/build-system/findclass.php
> @@ -0,0 +1,102 @@
> +<?php
> +/**
> + * Extract the classes in the given file
> + *
> + * @param  string            $path The file to check
> + * @throws \RuntimeException
> + * @return array             The found classes
> + */

This should rather be under gnu/packages/aux-files IMO.  Also, could you
add a copyright header and possibly info as to where it originates?

> +(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
> +  (with-output-to-file (string-append vendor "/autoload.php")
> +    (lambda _
> +      (format #t "<?php~%")
> +      (format #t "// autoload.php @generated by Guix~%")
> +      (format #t "$map = $psr4map = $classmap = array();~%")
> +      (format #t "require_once '~a/autoload_conf.php';~%" vendor)
> +      (format #t "require_once '~a/share/web/composer/ClassLoader.php';~%"
> +                 (assoc-ref inputs "composer-classloader"))
> +      (format #t "$loader = new \\Composer\\Autoload\\ClassLoader();~%")
> +      (format #t "foreach ($map as $namespace => $path) {~%")
> +      (format #t "  $loader->set($namespace, $path);~%")
> +      (format #t "}~%")
> +      (format #t "foreach ($psr4map as $namespace => $path) {~%")
> +      (format #t "  $loader->setPsr4($namespace, $path);~%")
> +      (format #t "}~%")
> +      (format #t "$loader->addClassMap($classmap);~%")
> +      (format #t "$loader->register();~%")))

I think it’d be clearer as a single string:

  (display "\
<?php
// autoload.php …")

Ludo’.




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

* [bug#42338] [PATCH 01/34] guix: import: Add composer importer.
  2020-09-07 14:06   ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Ludovic Courtès
@ 2020-09-17 22:43     ` Julien Lepiller
  2020-09-18  8:31       ` Ludovic Courtès
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-09-17 22:43 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 42338

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

Le Mon, 07 Sep 2020 16:06:13 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

> Hi Julien,
> 
> There’s a lot of interesting work in here!  I’m not familiar with PHP;
> I’ll just make a bird’s eye review.
> 
> Julien Lepiller <julien@lepiller.eu> skribis:
> 
> > * guix/import/composer.scm: New file.
> > * guix/scripts/import/composer.scm: New file.
> > * Makefile.am: Add them.
> > * guix/scripts/import.scm: Add composer importer.  
> 
> Please add tests and a mention in “Invoking guix import” in the
> manual.
> 
> For tests, a strategy that I think works well is that used in
> tests/cpan.scm, where we spawn an HTTP server to mock the real one.
> 
> > +(define* (composer-fetch name #:optional version)
> > +  "Return an alist representation of the Composer metadata for the
> > package NAME, +or #f on failure."
> > +  (let ((package (json-fetch
> > +                   (string-append "https://repo.packagist.org/p/"
> > name ".json"))))
> > +    (if package
> > +        (let* ((packages (assoc-ref package "packages"))
> > +               (package (assoc-ref packages name))
> > +               (versions (filter
> > +                           (lambda (version)
> > +                             (and (not (string-contains version
> > "dev"))
> > +                                  (not (string-contains version
> > "beta"))))
> > +                           (map car package)))
> > +               (versions (map
> > +                           (lambda (version)
> > +                             (cons (fix-version version) version))
> > +                           versions))
> > +               (version (or (if (null? version) #f version)
> > +                            (latest-version (map car versions)))))
> > +          (assoc-ref package (assoc-ref versions version)))
> > +        #f)))  
> 
> I recommend using ‘define-json-mapping’ instead of browsing alists:
> it’s less error-prone, hides the JSON details away, and leads to more
> readable code.  The pypi, crates, cpan importers use it.
> 
> Thanks!
> 
> Ludo’.

Thanks, here's a new version

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-guix-import-Add-composer-importer.patch --]
[-- Type: text/x-patch, Size: 21868 bytes --]

From 6d521ca9f066f82488abefd5d3630e38305c0fd1 Mon Sep 17 00:00:00 2001
From: Julien Lepiller <julien@lepiller.eu>
Date: Tue, 29 Oct 2019 08:07:38 +0100
Subject: [PATCH 01/34] guix: import: Add composer importer.

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |   6 +
 guix/import/composer.scm         | 257 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 +++++++++++++
 tests/composer.scm               |  92 +++++++++++
 6 files changed, 466 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 8e91e1e558..6ce1430ea6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -223,6 +223,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -269,6 +270,7 @@ MODULES =					\
   guix/scripts/system/reconfigure.scm		\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cran.scm			\
   guix/scripts/import/elpa.scm  		\
@@ -402,6 +404,7 @@ SCM_TESTS =					\
   tests/challenge.scm				\
   tests/channels.scm				\
   tests/combinators.scm			\
+  tests/composer.scm				\
   tests/containers.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 88128a4b3a..ca4eb347c7 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -10164,6 +10164,12 @@ in Guix.
 @cindex OCaml
 Import metadata from the @uref{https://opam.ocaml.org/, OPAM} package
 repository used by the OCaml community.
+
+@item composer
+@cindex COMPOSER
+@cindex PHP
+Import metadat from the @uref{https://getcomposer.org/, Composer} package
+archive used by the PHP community.
 @end table
 
 The structure of the @command{guix import} code is modular.  It would be
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..db8075edb2
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,257 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import
+
+            %composer-base-url))
+
+(define %composer-base-url
+  (make-parameter "https://repo.packagist.org"))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? a b) a b)) (car versions) versions))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append (%composer-base-url) "/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (assoc-ref packages name))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (versions (map
+                           (lambda (version)
+                             (cons (fix-version version) version))
+                           versions))
+               (version (or (if (null? version) #f version)
+                            (latest-version (map car versions)))))
+          (assoc-ref package (assoc-ref versions version)))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp name version home-page description dependencies
+                       dev-dependencies licenses source)
+  "Return the `package' s-expression for a PHP package with the given NAME,
+VERSION, HOME-PAGE, DESCRIPTION, DEPENDENCIES, LICENSES and SOURCE."
+  (let ((git? (equal? (assoc-ref source "type") "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (assoc-ref source "url")
+                             (assoc-ref source "reference")
+                             temp))
+                (url-fetch (assoc-ref source "url") temp))
+            `(package
+               (name ,(php-package-name name))
+               (version ,version)
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(assoc-ref source "url"))
+                                        (commit ,(assoc-ref source "reference"))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(assoc-ref source "url"))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,description)
+               (home-page ,home-page)
+               (license ,(match licenses
+                           (() #f)
+                           ((license) (license->symbol license))
+                           (_ `(list ,@(map license->symbol licenses)))))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((name         (assoc-ref package "name"))
+                (version      (fix-version (assoc-ref package "version")))
+                (description  (beautify-description
+                               (assoc-ref package "description")))
+                (home-page    (assoc-ref package "homepage"))
+                (dependencies-names (filter
+                                      (lambda (dep)
+                                        (string-contains dep "/"))
+                                      (map car (assoc-ref package "require"))))
+                (dependencies (map php-package-name dependencies-names))
+                (require-dev (assoc-ref package "require-dev"))
+                (dev-dependencies-names
+                  (if require-dev
+                      (filter
+                        (lambda (dep)
+                          (string-contains dep "/"))
+                        (map car require-dev))
+                      '()))
+                (dev-dependencies (map php-package-name dev-dependencies-names))
+                (licenses     (map string->license
+                                   (vector->list
+                                    (assoc-ref package "license")))))
+           (values (make-php-sexp name version home-page description dependencies
+                                  dev-dependencies licenses (assoc-ref package "source"))
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" license:lgpl2.0)
+    ("GPL" license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") license:expat)
+    ("Public domain" license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (version (fix-version (assoc-ref metadata "version")))
+         (url (assoc-ref (assoc-ref metadata "source") "url")))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (latest latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 0a3863f965..23da295e48 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,7 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem"
-                    "cran" "crate" "texlive" "json" "opam"))
+                    "cran" "crate" "texlive" "json" "opam" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/tests/composer.scm b/tests/composer.scm
new file mode 100644
index 0000000000..cefaf9f434
--- /dev/null
+++ b/tests/composer.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (test-composer)
+  #:use-module (guix import composer)
+  #:use-module (guix base32)
+  #:use-module (gcrypt hash)
+  #:use-module (guix tests http)
+  #:use-module (guix grafts)
+  #:use-module (srfi srfi-64)
+  #:use-module (web client)
+  #:use-module (ice-9 match))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define test-json
+  "{
+  \"packages\": {
+    \"foo/bar\": {
+      \"0.1\": {
+        \"name\": \"foo/bar\",
+        \"description\": \"description\",
+        \"keywords\": [\"testing\"],
+        \"homepage\": \"http://example.com\",
+        \"version\": \"0.1\",
+        \"license\": [\"BSD-3-Clause\"],
+        \"source\": {
+          \"type\": \"url\",
+          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
+        },
+        \"require\": {},
+        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
+      }
+    }
+  }
+}")
+
+(define test-source
+  "foobar")
+
+;; Avoid collisions with other tests.
+(%http-server-port 10450)
+
+(test-begin "composer")
+
+(test-assert "composer->guix-package"
+  ;; Replace network resources with sample data.
+  (with-http-server `((200 ,test-json)
+                      (200 ,test-source))
+    (parameterize ((%composer-base-url (%local-url))
+                   (current-http-proxy (%local-url)))
+      (match (composer->guix-package "foo/bar")
+        (('package
+           ('name "php-foo-bar")
+           ('version "0.1")
+           ('source ('origin
+                      ('method 'url-fetch)
+                      ('uri "http://example.com/Bar-0.1.tar.gz")
+                      ('sha256
+                       ('base32
+                        (? string? hash)))))
+           ('build-system 'composer-build-system)
+           ('native-inputs
+            ('quasiquote
+             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
+           ('synopsis "")
+           ('description "description")
+           ('home-page "http://example.com")
+           ('license 'license:bsd-3))
+         (string=? (bytevector->nix-base32-string
+                    (call-with-input-string test-source port-sha256))
+                   hash))
+        (x
+         (pk 'fail x #f))))))
+
+(test-end "composer")
-- 
2.28.0


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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-07 14:09     ` Ludovic Courtès
@ 2020-09-17 22:44       ` Julien Lepiller
  2020-09-18  8:45         ` Ludovic Courtès
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-09-17 22:44 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 42338

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

Le Mon, 07 Sep 2020 16:09:01 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

> Julien Lepiller <julien@lepiller.eu> skribis:
> 
> > * guix/build-system/composer.scm: New file.
> > * guix/build/composer-build-system.scm: New file.
> > * guix/build-system/findclass.php: New file.
> > * Makefile.am: Add them.
> > * doc/guix.texi (Build Systems): Document it.  
> 
> [...]
> 
> > +++ b/guix/build-system/findclass.php
> > @@ -0,0 +1,102 @@
> > +<?php
> > +/**
> > + * Extract the classes in the given file
> > + *
> > + * @param  string            $path The file to check
> > + * @throws \RuntimeException
> > + * @return array             The found classes
> > + */  
> 
> This should rather be under gnu/packages/aux-files IMO.  Also, could
> you add a copyright header and possibly info as to where it
> originates?
> 
> > +(define* (create-autoload vendor composer-file inputs #:key
> > dev-dependencies?)
> > +  (with-output-to-file (string-append vendor "/autoload.php")
> > +    (lambda _
> > +      (format #t "<?php~%")
> > +      (format #t "// autoload.php @generated by Guix~%")
> > +      (format #t "$map = $psr4map = $classmap = array();~%")
> > +      (format #t "require_once '~a/autoload_conf.php';~%" vendor)
> > +      (format #t "require_once
> > '~a/share/web/composer/ClassLoader.php';~%"
> > +                 (assoc-ref inputs "composer-classloader"))
> > +      (format #t "$loader = new
> > \\Composer\\Autoload\\ClassLoader();~%")
> > +      (format #t "foreach ($map as $namespace => $path) {~%")
> > +      (format #t "  $loader->set($namespace, $path);~%")
> > +      (format #t "}~%")
> > +      (format #t "foreach ($psr4map as $namespace => $path) {~%")
> > +      (format #t "  $loader->setPsr4($namespace, $path);~%")
> > +      (format #t "}~%")
> > +      (format #t "$loader->addClassMap($classmap);~%")
> > +      (format #t "$loader->register();~%")))  
> 
> I think it’d be clearer as a single string:
> 
>   (display "\
> <?php
> // autoload.php …")
> 
> Ludo’.

Thanks, here's a new version

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0003-guix-Add-composer-build-system.patch --]
[-- Type: text/x-patch, Size: 25980 bytes --]

From bb5d102b6ea5e6b5c06bbf90a58927c6180e23bc Mon Sep 17 00:00:00 2001
From: Julien Lepiller <julien@lepiller.eu>
Date: Tue, 29 Oct 2019 20:58:51 +0100
Subject: [PATCH 03/34] guix: Add composer-build-system.

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* gnu/packages/aux-files/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   5 +-
 doc/guix.texi                        |  14 ++
 gnu/packages/aux-files/findclass.php | 125 +++++++++++++++
 guix/build-system/composer.scm       | 170 ++++++++++++++++++++
 guix/build/composer-build-system.scm | 226 +++++++++++++++++++++++++++
 5 files changed, 539 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index 6ce1430ea6..5af964b0e9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -115,6 +115,7 @@ MODULES =					\
   guix/build-system/cargo.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/emacs.scm			\
@@ -163,6 +164,7 @@ MODULES =					\
   guix/build/cargo-build-system.scm		\
   guix/build/cargo-utils.scm			\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/emacs-build-system.scm		\
@@ -354,7 +356,8 @@ AUX_FILES =						\
   gnu/packages/aux-files/linux-libre/4.4-i686.conf	\
   gnu/packages/aux-files/linux-libre/4.4-x86_64.conf	\
   gnu/packages/aux-files/pack-audit.c			\
-  gnu/packages/aux-files/run-in-namespace.c
+  gnu/packages/aux-files/run-in-namespace.c		\
+  gnu/packages/aux-files/findclass.php
 
 # Templates, examples.
 EXAMPLES =					\
diff --git a/doc/guix.texi b/doc/guix.texi
index ca4eb347c7..6ee4d7e5f0 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -6941,6 +6941,20 @@ debugging information''), which roughly means that code is compiled with
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvr
 
+@defvr {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvr
+
 @defvr {Scheme Variable} dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
diff --git a/gnu/packages/aux-files/findclass.php b/gnu/packages/aux-files/findclass.php
new file mode 100644
index 0000000000..d0b250c8e1
--- /dev/null
+++ b/gnu/packages/aux-files/findclass.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * The content of this file is copied from composer's src/Composer/Autoload/ClassMapGenerator.php
+ * the findClasses method was extracted, to prevent using any dependency.
+ *
+ * Composer (and thus this file) is distributed under the expat license, and
+ * ClassMapGenerator.php also contains this notice:
+ *
+ *   This file is part of Composer.
+ *
+ *   (c) Nils Adermann <naderman@naderman.de>
+ *       Jordi Boggiano <j.boggiano@seld.be>
+ *
+ *   For the full copyright and license information, please view the LICENSE
+ *   file that was distributed with this source code.
+ *
+ *   This file is copied from the Symfony package.
+ *
+ *   (c) Fabien Potencier <fabien@symfony.com>
+ * 
+ * To the extent to wich it makes sense, as the author of the extract:
+ * Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+ */
+
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..ebc472c717
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,170 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build json)
+    (guix build union)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:source #:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build store name inputs
+                         #:key (guile #f)
+                         (outputs '("out")) (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags ''("--strip-debug"))
+                         (strip-directories ''("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build json)
+                                    (guix build utils))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    `(begin
+       (use-modules ,@modules)
+       (composer-build #:source ,(match (assoc-ref inputs "source")
+                                   (((? derivation? source))
+                                    (derivation->output-path source))
+                                   ((source)
+                                    source)
+                                   (source
+                                    source))
+                       #:system ,system
+                       #:outputs %outputs
+                       #:inputs %build-inputs
+                       #:search-paths ',(map search-path-specification->sexp
+                                             search-paths)
+                       #:phases ,phases
+                       #:out-of-source? ,out-of-source?
+                       #:composer-file ,composer-file
+                       #:tests? ,tests?
+                       #:test-target ,test-target
+                       #:install-target ,install-target
+                       #:validate-runpath? ,validate-runpath?
+                       #:patch-shebangs? ,patch-shebangs?
+                       #:strip-binaries? ,strip-binaries?
+                       #:strip-flags ,strip-flags
+                       #:strip-directories ,strip-directories)))
+
+  (define guile-for-build
+    (match guile
+      ((? package?)
+       (package-derivation store guile system #:graft? #f))
+      (#f                                         ; the default
+       (let* ((distro (resolve-interface '(gnu packages commencement)))
+              (guile  (module-ref distro 'guile-final)))
+         (package-derivation store guile system #:graft? #f)))))
+
+  (build-expression->derivation store name builder
+                                #:system system
+                                #:inputs inputs
+                                #:modules imported-modules
+                                #:outputs outputs
+                                #:guile-for-build guile-for-build))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..f73684f8d5
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,226 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build json)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (read-json port))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Install the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (match (assoc-ref package-data "scripts")
+                      (('@ script ...) script)
+                      (#f '())))
+           (test-script
+             (assoc-ref scripts test-target))
+           (dependencies (filter (lambda (dep) (string-contains dep "/"))
+                                 (map car
+                                      (match (assoc-ref package-data "require")
+                                        (('@ dependency ...) dependency)
+                                        (#f '())))))
+           (dependencies-dev
+             (filter (lambda (dep) (string-contains dep "/"))
+                     (map car
+                          (match (assoc-ref package-data "require-dev")
+                            (('@ dependency ...) dependency)
+                            (#f '())))))
+           (name (assoc-ref package-data "name")))
+      (for-each
+        (lambda (input)
+          (let ((bin (find-php-bin (cdr input))))
+            (when bin
+              (copy-recursively bin "vendor/bin"))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (equal? (system command) 0)
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (equal? (system c) 0)
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit")))))
+  #t)
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs (map cdr inputs)))
+    (if (null? inputs)
+        (throw 'unsatisfied-dependency "Unsatisfied dependency: required " dependency)
+        (let ((autoload (string-append (car inputs) "/share/web/" dependency "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop (cdr inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (display "<?php
+// autoload.php @generated by Guix
+$map = $psr4map = $classmap = array();
+")
+      (format #t "require_once '~a/autoload_conf.php'~%" vendor)
+      (format #t "require_once '~a/share/web/composer/ClassLoader.php'~%"
+              (assoc-ref inputs "composer-classloader"))
+      (display "$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($map as $namespace => $path) {
+  $loader->set($namespace, $path);
+}
+foreach ($psr4map as $namespace => $path) {
+  $loader->setPsr4($namespace, $path);
+}
+$loader->addClassMap($classmap);
+$loader->register();
+")))
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload
+           (match (assoc-ref package-data "autoload")
+             (('@ autoload ...) autoload)
+             (#f '())))
+         (autoload-dev
+           (match (assoc-ref package-data "autoload-dev")
+             (('@ autoload-dev ...) autoload-dev)
+             (#f '())))
+         (dependencies (filter (lambda (dep) (string-contains dep "/"))
+                               (map car
+                                    (match (assoc-ref package-data "require")
+                                      (('@ dependency ...) dependency)
+                                      (#f '())))))
+         (dependencies-dev
+           (filter (lambda (dep) (string-contains dep "/"))
+                   (map car
+                        (match (assoc-ref package-data "require-dev")
+                          (('@ dependency ...) dependency)
+                          (#f '()))))))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (match (assoc-ref autoload "psr-4")
+              (('@ psr4 ...) psr4)
+              (#f '()))
+            (if dev-dependencies?
+                (match (assoc-ref autoload-dev "psr-4")
+                  (('@ psr4 ...) psr4)
+                  (#f '()))
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (or (assoc-ref autoload "classmap") '())
+            (if dev-dependencies?
+                (or (assoc-ref autoload-dev "classmap") '())
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (assoc-ref package-data "name"))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (assoc-ref package-data "bin")))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs))
+  #t)
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
-- 
2.28.0


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

* [bug#42338] [PATCH 01/34] guix: import: Add composer importer.
  2020-09-17 22:43     ` Julien Lepiller
@ 2020-09-18  8:31       ` Ludovic Courtès
  2020-09-18 23:20         ` Julien Lepiller
  0 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-18  8:31 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi!

Julien Lepiller <julien@lepiller.eu> skribis:

> From 6d521ca9f066f82488abefd5d3630e38305c0fd1 Mon Sep 17 00:00:00 2001
> From: Julien Lepiller <julien@lepiller.eu>
> Date: Tue, 29 Oct 2019 08:07:38 +0100
> Subject: [PATCH 01/34] guix: import: Add composer importer.
>
> * guix/import/composer.scm: New file.
> * guix/scripts/import/composer.scm: New file.
> * guix/tests/composer.scm: New file.
> * Makefile.am: Add them.
> * guix/scripts/import.scm: Add composer importer.
> * doc/guix.texi (Invoking guix import): Mention it.

[...]

> +@item composer
> +@cindex COMPOSER

s/COMPOSER/Composer/ ?

> +Import metadat from the @uref{https://getcomposer.org/, Composer} package
                ^
metadata

> +archive used by the PHP community.

Could you add an example command line like we have for some of the other
importers?  (It’s also useful for us as a test against the actual servers…)

> +  (let ((package (json-fetch
> +                   (string-append (%composer-base-url) "/p/" name ".json"))))
> +    (if package
> +        (let* ((packages (assoc-ref package "packages"))
> +               (package (assoc-ref packages name))
> +               (versions (filter
> +                           (lambda (version)
> +                             (and (not (string-contains version "dev"))
> +                                  (not (string-contains version "beta"))))
> +                           (map car package)))

Like I wrote before, I recommend ‘define-json-mapping’.  If you prefer
you can make that change later on once you’ve pushed this first version,
but I really think it’ll help maintainability.

This should also help avoid (map car …), which is frowned upon in Guix.
:-)

> +               (versions (map
> +                           (lambda (version)

Rather indent as: (map (lambda (version)

Otherwise LGTM!  

Ludo’.




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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-17 22:44       ` Julien Lepiller
@ 2020-09-18  8:45         ` Ludovic Courtès
  2020-09-18 23:24           ` Julien Lepiller
  0 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-18  8:45 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi,

Julien Lepiller <julien@lepiller.eu> skribis:

> From bb5d102b6ea5e6b5c06bbf90a58927c6180e23bc Mon Sep 17 00:00:00 2001
> From: Julien Lepiller <julien@lepiller.eu>
> Date: Tue, 29 Oct 2019 20:58:51 +0100
> Subject: [PATCH 03/34] guix: Add composer-build-system.
>
> * guix/build-system/composer.scm: New file.
> * guix/build/composer-build-system.scm: New file.
> * gnu/packages/aux-files/findclass.php: New file.
> * Makefile.am: Add them.
> * doc/guix.texi (Build Systems): Document it.

[...]

> --- /dev/null
> +++ b/gnu/packages/aux-files/findclass.php

I can’t believe we’ll have PHP in our code base.  :-)

> +;;; 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 build-system composer)

Missing newline.

> +    (let* ((package-data (read-package-data #:filename composer-file))
> +           (scripts (match (assoc-ref package-data "scripts")
> +                      (('@ script ...) script)
> +                      (#f '())))
> +           (test-script
> +             (assoc-ref scripts test-target))
> +           (dependencies (filter (lambda (dep) (string-contains dep "/"))
> +                                 (map car
> +                                      (match (assoc-ref package-data "require")
> +                                        (('@ dependency ...) dependency)
> +                                        (#f '())))))
> +           (dependencies-dev
> +             (filter (lambda (dep) (string-contains dep "/"))
> +                     (map car
> +                          (match (assoc-ref package-data "require-dev")
> +                            (('@ dependency ...) dependency)
> +                            (#f '())))))
> +           (name (assoc-ref package-data "name")))

This is also a case for ‘define-json-mapping’.  I suppose we could use
Guile-JSON instead of (guix build json), no?

I think this code and similar occurrences would be less intimidating if
we used ‘define-json-mapping’; it would make the data structures
clearer, unlike here where one has to keep in mind what the list/tree
looks like so they can map car/cdr around.

> +      (for-each
> +        (lambda (input)

Like for ‘map’, please indent on the same line:

  (for-each (lambda (input)

> +      (match test-script
> +        ((? string? command)
> +         (unless (equal? (system command) 0)
> +           (throw 'failed-command command)))
> +        (('@ (? string? command) ...)
> +         (for-each
> +           (lambda (c)
> +             (unless (equal? (system c) 0)
> +               (throw 'failed-command c)))
> +           command))

Use (zero? x) instead of (equal? 0 x).

Also, why not use ‘invoke’?  I this because these commands are really
shell commands and expect things like glob patterns and tilde expansion?
If these are not shell commands, I recommend ‘invoke’, which will report
failures more nicely.

> +(define (find-php-dep inputs dependency)
> +  (let loop ((inputs (map cdr inputs)))
> +    (if (null? inputs)
> +        (throw 'unsatisfied-dependency "Unsatisfied dependency: required " dependency)
> +        (let ((autoload (string-append (car inputs) "/share/web/" dependency "/vendor/autoload_conf.php")))
> +          (if (file-exists? autoload)
> +              autoload
> +              (loop (cdr inputs)))))))

Please use ‘match’ instead of car/cdr.

> +(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
> +  (with-output-to-file (string-append vendor "/autoload.php")
> +    (lambda _
> +      (display "<?php
> +// autoload.php @generated by Guix
> +$map = $psr4map = $classmap = array();
> +")
> +      (format #t "require_once '~a/autoload_conf.php'~%" vendor)
> +      (format #t "require_once '~a/share/web/composer/ClassLoader.php'~%"
> +              (assoc-ref inputs "composer-classloader"))
> +      (display "$loader = new \\Composer\\Autoload\\ClassLoader();
> +foreach ($map as $namespace => $path) {
> +  $loader->set($namespace, $path);
> +}
> +foreach ($psr4map as $namespace => $path) {
> +  $loader->setPsr4($namespace, $path);
> +}
> +$loader->addClassMap($classmap);
> +$loader->register();
> +")))

Please add a docstring explaining what’s happening here.  Also, perhaps
use ‘string-append’ instead of ‘format’ so we don’t end up generating
things like:

  require_once '#f/autoload_conf.php'

:-)

In short, I think we must pay attention to the style to facilitate
maintainability.

Could you send an updated patch?

Thanks!

Ludo’.




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

* [bug#42338] [PATCH 01/34] guix: import: Add composer importer.
  2020-09-18  8:31       ` Ludovic Courtès
@ 2020-09-18 23:20         ` Julien Lepiller
  2020-09-25 10:27           ` Ludovic Courtès
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-09-18 23:20 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 42338

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

Le Fri, 18 Sep 2020 10:31:39 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

> Hi!
> 
> Julien Lepiller <julien@lepiller.eu> skribis:
> 
> > From 6d521ca9f066f82488abefd5d3630e38305c0fd1 Mon Sep 17 00:00:00
> > 2001 From: Julien Lepiller <julien@lepiller.eu>
> > Date: Tue, 29 Oct 2019 08:07:38 +0100
> > Subject: [PATCH 01/34] guix: import: Add composer importer.
> >
> > * guix/import/composer.scm: New file.
> > * guix/scripts/import/composer.scm: New file.
> > * guix/tests/composer.scm: New file.
> > * Makefile.am: Add them.
> > * guix/scripts/import.scm: Add composer importer.
> > * doc/guix.texi (Invoking guix import): Mention it.  
> 
> [...]
> 
> > +@item composer
> > +@cindex COMPOSER  
> 
> s/COMPOSER/Composer/ ?
> 
> > +Import metadat from the @uref{https://getcomposer.org/, Composer}
> > package  
>                 ^
> metadata
> 
> > +archive used by the PHP community.  
> 
> Could you add an example command line like we have for some of the
> other importers?  (It’s also useful for us as a test against the
> actual servers…)
> 
> > +  (let ((package (json-fetch
> > +                   (string-append (%composer-base-url) "/p/" name
> > ".json"))))
> > +    (if package
> > +        (let* ((packages (assoc-ref package "packages"))
> > +               (package (assoc-ref packages name))
> > +               (versions (filter
> > +                           (lambda (version)
> > +                             (and (not (string-contains version
> > "dev"))
> > +                                  (not (string-contains version
> > "beta"))))
> > +                           (map car package)))  
> 
> Like I wrote before, I recommend ‘define-json-mapping’.  If you prefer
> you can make that change later on once you’ve pushed this first
> version, but I really think it’ll help maintainability.
> 
> This should also help avoid (map car …), which is frowned upon in
> Guix. :-)
> 
> > +               (versions (map
> > +                           (lambda (version)  
> 
> Rather indent as: (map (lambda (version)
> 
> Otherwise LGTM!  
> 
> Ludo’.

Thanks, here's a new version

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-guix-import-Add-composer-importer.patch --]
[-- Type: text/x-patch, Size: 22291 bytes --]

From 70b9cb2bb389f3e5f9dcc75a44d7d60c28f997bc Mon Sep 17 00:00:00 2001
From: Julien Lepiller <julien@lepiller.eu>
Date: Tue, 29 Oct 2019 08:07:38 +0100
Subject: [PATCH 01/34] guix: import: Add composer importer.

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  11 ++
 guix/import/composer.scm         | 270 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 ++++++++++++
 tests/composer.scm               |  92 +++++++++++
 6 files changed, 484 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 8e91e1e558..6ce1430ea6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -223,6 +223,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -269,6 +270,7 @@ MODULES =					\
   guix/scripts/system/reconfigure.scm		\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cran.scm			\
   guix/scripts/import/elpa.scm  		\
@@ -402,6 +404,7 @@ SCM_TESTS =					\
   tests/challenge.scm				\
   tests/channels.scm				\
   tests/combinators.scm			\
+  tests/composer.scm				\
   tests/containers.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 88128a4b3a..5d29567153 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -10164,6 +10164,17 @@ in Guix.
 @cindex OCaml
 Import metadata from the @uref{https://opam.ocaml.org/, OPAM} package
 repository used by the OCaml community.
+
+@item composer
+@cindex Composer
+@cindex PHP
+Import metadat from the @uref{https://getcomposer.org/, Composer} package
+archive used by the PHP community, as in this example:
+
+@example
+guix import composer phpunit/phpunit
+@end example
+
 @end table
 
 The structure of the @command{guix import} code is modular.  It would be
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..9b284d0dd2
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,270 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import
+
+            %composer-base-url))
+
+(define %composer-base-url
+  (make-parameter "https://repo.packagist.org"))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b))
+        (car versions) versions))
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-source> make-composer-source composer-source?
+  json->composer-source
+  (type      composer-source-type)
+  (url       composer-source-url)
+  (reference composer-source-reference))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (description composer-package-description)
+  (homepage    composer-package-homepage)
+  (source      composer-package-source "source" json->composer-source)
+  (name        composer-package-name "name" php-package-name)
+  (version     composer-package-version "version" fix-version)
+  (require     composer-package-require "require" json->require)
+  (dev-require composer-package-dev-require "require-dev" json->require)
+  (license     composer-package-license "license"
+               (lambda (vector)
+                 (map string->license (vector->list vector)))))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append (%composer-base-url) "/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (or (assoc-ref packages name) package))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (version (or (if (null? version) #f version)
+                            (latest-version versions))))
+          (assoc-ref package version))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp composer-package)
+  "Return the `package' s-expression for a PHP package for the given
+COMPOSER-PACKAGE."
+  (let* ((source (composer-package-source composer-package))
+         (dependencies (map php-package-name
+                            (composer-package-require composer-package)))
+         (dev-dependencies (map php-package-name
+                                (composer-package-dev-require composer-package)))
+         (git? (equal? (composer-source-type source) "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (composer-source-url source)
+                             (composer-source-reference source)
+                             temp))
+                (url-fetch (composer-source-url source) temp))
+            `(package
+               (name ,(composer-package-name composer-package))
+               (version ,(composer-package-version composer-package))
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(composer-source-url source))
+                                        (commit ,(composer-source-reference source))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(composer-source-url source))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,(composer-package-description composer-package))
+               (home-page ,(composer-package-homepage composer-package))
+               (license ,(match (composer-package-license composer-package)
+                           (() #f)
+                           ((license) license)
+                           (_ license)))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((package (json->composer-package package))
+                (dependencies-names (composer-package-require package))
+                (dev-dependencies-names (composer-package-dev-require package)))
+           (values (make-php-sexp package)
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" 'license:lgpl2.0)
+    ("GPL" 'license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") 'license:expat)
+    ("Public domain" 'license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (package (json->composer-package metadata))
+         (version (composer-package-version package))
+         (url (composer-source-url (composer-package-source package))))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (latest latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 0a3863f965..23da295e48 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -77,7 +77,7 @@ rather than \\n."
 ;;;
 
 (define importers '("gnu" "nix" "pypi" "cpan" "hackage" "stackage" "elpa" "gem"
-                    "cran" "crate" "texlive" "json" "opam"))
+                    "cran" "crate" "texlive" "json" "opam" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/tests/composer.scm b/tests/composer.scm
new file mode 100644
index 0000000000..cefaf9f434
--- /dev/null
+++ b/tests/composer.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (test-composer)
+  #:use-module (guix import composer)
+  #:use-module (guix base32)
+  #:use-module (gcrypt hash)
+  #:use-module (guix tests http)
+  #:use-module (guix grafts)
+  #:use-module (srfi srfi-64)
+  #:use-module (web client)
+  #:use-module (ice-9 match))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define test-json
+  "{
+  \"packages\": {
+    \"foo/bar\": {
+      \"0.1\": {
+        \"name\": \"foo/bar\",
+        \"description\": \"description\",
+        \"keywords\": [\"testing\"],
+        \"homepage\": \"http://example.com\",
+        \"version\": \"0.1\",
+        \"license\": [\"BSD-3-Clause\"],
+        \"source\": {
+          \"type\": \"url\",
+          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
+        },
+        \"require\": {},
+        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
+      }
+    }
+  }
+}")
+
+(define test-source
+  "foobar")
+
+;; Avoid collisions with other tests.
+(%http-server-port 10450)
+
+(test-begin "composer")
+
+(test-assert "composer->guix-package"
+  ;; Replace network resources with sample data.
+  (with-http-server `((200 ,test-json)
+                      (200 ,test-source))
+    (parameterize ((%composer-base-url (%local-url))
+                   (current-http-proxy (%local-url)))
+      (match (composer->guix-package "foo/bar")
+        (('package
+           ('name "php-foo-bar")
+           ('version "0.1")
+           ('source ('origin
+                      ('method 'url-fetch)
+                      ('uri "http://example.com/Bar-0.1.tar.gz")
+                      ('sha256
+                       ('base32
+                        (? string? hash)))))
+           ('build-system 'composer-build-system)
+           ('native-inputs
+            ('quasiquote
+             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
+           ('synopsis "")
+           ('description "description")
+           ('home-page "http://example.com")
+           ('license 'license:bsd-3))
+         (string=? (bytevector->nix-base32-string
+                    (call-with-input-string test-source port-sha256))
+                   hash))
+        (x
+         (pk 'fail x #f))))))
+
+(test-end "composer")
-- 
2.28.0


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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-18  8:45         ` Ludovic Courtès
@ 2020-09-18 23:24           ` Julien Lepiller
  2020-09-25 10:33             ` Ludovic Courtès
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-09-18 23:24 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 42338

Le Fri, 18 Sep 2020 10:45:48 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

> Hi,
> 
> Julien Lepiller <julien@lepiller.eu> skribis:
> 
> > +    (let* ((package-data (read-package-data #:filename
> > composer-file))
> > +           (scripts (match (assoc-ref package-data "scripts")
> > +                      (('@ script ...) script)
> > +                      (#f '())))
> > +           (test-script
> > +             (assoc-ref scripts test-target))
> > +           (dependencies (filter (lambda (dep) (string-contains
> > dep "/"))
> > +                                 (map car
> > +                                      (match (assoc-ref
> > package-data "require")
> > +                                        (('@ dependency ...)
> > dependency)
> > +                                        (#f '())))))
> > +           (dependencies-dev
> > +             (filter (lambda (dep) (string-contains dep "/"))
> > +                     (map car
> > +                          (match (assoc-ref package-data
> > "require-dev")
> > +                            (('@ dependency ...) dependency)
> > +                            (#f '())))))
> > +           (name (assoc-ref package-data "name")))  
> 
> This is also a case for ‘define-json-mapping’.  I suppose we could use
> Guile-JSON instead of (guix build json), no?
> 
> I think this code and similar occurrences would be less intimidating
> if we used ‘define-json-mapping’; it would make the data structures
> clearer, unlike here where one has to keep in mind what the list/tree
> looks like so they can map car/cdr around.

I think we already tried that with the node build system, but we had to
revert, because we were importing guile-json from the host side. I
don't remember the details though, so if you think it's OK now, I'll
gladly make the code look nicer :)

> 
> > +      (for-each
> > +        (lambda (input)  
> 
> Like for ‘map’, please indent on the same line:
> 
>   (for-each (lambda (input)
> 
> > +      (match test-script
> > +        ((? string? command)
> > +         (unless (equal? (system command) 0)
> > +           (throw 'failed-command command)))
> > +        (('@ (? string? command) ...)
> > +         (for-each
> > +           (lambda (c)
> > +             (unless (equal? (system c) 0)
> > +               (throw 'failed-command c)))
> > +           command))  
> 
> Use (zero? x) instead of (equal? 0 x).
> 
> Also, why not use ‘invoke’?  I this because these commands are really
> shell commands and expect things like glob patterns and tilde
> expansion? If these are not shell commands, I recommend ‘invoke’,
> which will report failures more nicely.

Here I have a single string that contains shell commands, so I don't
think I can use invoke.




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

* [bug#42338] [PATCH 01/34] guix: import: Add composer importer.
  2020-09-18 23:20         ` Julien Lepiller
@ 2020-09-25 10:27           ` Ludovic Courtès
  2021-10-16  4:15             ` [bug#42338] [PATCH] Add composer build system (PHP) Maxim Cournoyer
  0 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-25 10:27 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi Julien,

Julien Lepiller <julien@lepiller.eu> skribis:

> From 70b9cb2bb389f3e5f9dcc75a44d7d60c28f997bc Mon Sep 17 00:00:00 2001
> From: Julien Lepiller <julien@lepiller.eu>
> Date: Tue, 29 Oct 2019 08:07:38 +0100
> Subject: [PATCH 01/34] guix: import: Add composer importer.
>
> * guix/import/composer.scm: New file.
> * guix/scripts/import/composer.scm: New file.
> * guix/tests/composer.scm: New file.
> * Makefile.am: Add them.
> * guix/scripts/import.scm: Add composer importer.
> * doc/guix.texi (Invoking guix import): Mention it.

[...]

> +@cindex PHP
> +Import metadat from the @uref{https://getcomposer.org/, Composer} package
                ^
Typo.

> +(define* (composer-fetch name #:optional version)
> +  "Return an alist representation of the Composer metadata for the package NAME,
> +or #f on failure."
> +  (let ((package (json-fetch
> +                   (string-append (%composer-base-url) "/p/" name ".json"))))
> +    (if package
> +        (let* ((packages (assoc-ref package "packages"))
> +               (package (or (assoc-ref packages name) package))
> +               (versions (filter
> +                           (lambda (version)
> +                             (and (not (string-contains version "dev"))
> +                                  (not (string-contains version "beta"))))
> +                           (map car package)))
> +               (version (or (if (null? version) #f version)
> +                            (latest-version versions))))
> +          (assoc-ref package version))
> +        #f)))

I think this should directly return a <composer-package> since the all
the callers pass the alist through ‘json->composer-package’.  The idea
is that alists should be converted to records as soon as they enter the
process.

Also it’s weird that ‘package’ above has a “packages” (plural) entry.
Perhaps we’re missing another JSON mapping?

[...]

> +++ b/guix/scripts/import/composer.scm
> @@ -0,0 +1,107 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2015 David Thompson <davet@gnu.org>
> +;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>

You can preserve these two lines if you think it’s relevant, but I’d
suggest adding one for yourself.

OK to push with changes along these lines.

Thanks for taking the time to convert to ‘define-json-mapping’ and all!

Ludo’.




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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-18 23:24           ` Julien Lepiller
@ 2020-09-25 10:33             ` Ludovic Courtès
  2020-09-29 14:49               ` Julien Lepiller
  0 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-25 10:33 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi,

Julien Lepiller <julien@lepiller.eu> skribis:

> Le Fri, 18 Sep 2020 10:45:48 +0200,
> Ludovic Courtès <ludo@gnu.org> a écrit :
>
>> Hi,
>> 
>> Julien Lepiller <julien@lepiller.eu> skribis:
>> 
>> > +    (let* ((package-data (read-package-data #:filename
>> > composer-file))
>> > +           (scripts (match (assoc-ref package-data "scripts")
>> > +                      (('@ script ...) script)
>> > +                      (#f '())))
>> > +           (test-script
>> > +             (assoc-ref scripts test-target))
>> > +           (dependencies (filter (lambda (dep) (string-contains
>> > dep "/"))
>> > +                                 (map car
>> > +                                      (match (assoc-ref
>> > package-data "require")
>> > +                                        (('@ dependency ...)
>> > dependency)
>> > +                                        (#f '())))))
>> > +           (dependencies-dev
>> > +             (filter (lambda (dep) (string-contains dep "/"))
>> > +                     (map car
>> > +                          (match (assoc-ref package-data
>> > "require-dev")
>> > +                            (('@ dependency ...) dependency)
>> > +                            (#f '())))))
>> > +           (name (assoc-ref package-data "name")))  
>> 
>> This is also a case for ‘define-json-mapping’.  I suppose we could use
>> Guile-JSON instead of (guix build json), no?
>> 
>> I think this code and similar occurrences would be less intimidating
>> if we used ‘define-json-mapping’; it would make the data structures
>> clearer, unlike here where one has to keep in mind what the list/tree
>> looks like so they can map car/cdr around.
>
> I think we already tried that with the node build system, but we had to
> revert, because we were importing guile-json from the host side. I
> don't remember the details though, so if you think it's OK now, I'll
> gladly make the code look nicer :)

Yes please. :-)  I think code full of alists/dictionaries would be hard
to read and to maintain since mistakes could end up being silently
ignored or lead to a wrong-type-#f error far down the road.

Also please remember to avoid car/cdr:

  https://guix.gnu.org/manual/en/html_node/Data-Types-and-Pattern-Matching.html

As for Guile-JSON: perhaps you can post a draft that we can play with to
see if there’s anything wrong, but off the top of my head I don’t see
why it wouldn’t work.

>> > +      (match test-script
>> > +        ((? string? command)
>> > +         (unless (equal? (system command) 0)
>> > +           (throw 'failed-command command)))
>> > +        (('@ (? string? command) ...)
>> > +         (for-each
>> > +           (lambda (c)
>> > +             (unless (equal? (system c) 0)
>> > +               (throw 'failed-command c)))
>> > +           command))  
>> 
>> Use (zero? x) instead of (equal? 0 x).
>> 
>> Also, why not use ‘invoke’?  I this because these commands are really
>> shell commands and expect things like glob patterns and tilde
>> expansion? If these are not shell commands, I recommend ‘invoke’,
>> which will report failures more nicely.
>
> Here I have a single string that contains shell commands, so I don't
> think I can use invoke.

‘system’ passes the string to “sh -c”, which means the string is subject
to shelly things: glob expansion, semicolon interpretation, string
quotation, etc.

If those strings are meant to be shell-interpreted, then passing them to
‘system’ is the right thing.  Otherwise, it should be avoided IMO.

Thanks,
Ludo’.




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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-25 10:33             ` Ludovic Courtès
@ 2020-09-29 14:49               ` Julien Lepiller
  2020-09-30  9:24                 ` Ludovic Courtès
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-09-29 14:49 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 42338

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

Le Fri, 25 Sep 2020 12:33:56 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :

> Hi,
> 
> As for Guile-JSON: perhaps you can post a draft that we can play with
> to see if there’s anything wrong, but off the top of my head I don’t
> see why it wouldn’t work.
> 
> Thanks,
> Ludo’.

Here's a new version, hopefully this addresses all your remarks. I'm
still not sure how (json) is pulled in to the build side though... How
does guix know it needs to use guile-json-3 instead of guile-json-1 for
instance? How does it work with inferiors?

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0003-guix-Add-composer-build-system.patch --]
[-- Type: text/x-patch, Size: 26503 bytes --]

From 432f57aeeb3b2e48591288e6491d66ab299661f0 Mon Sep 17 00:00:00 2001
From: Julien Lepiller <julien@lepiller.eu>
Date: Tue, 29 Oct 2019 20:58:51 +0100
Subject: [PATCH 03/34] guix: Add composer-build-system.

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* gnu/packages/aux-files/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   5 +-
 doc/guix.texi                        |  14 ++
 gnu/packages/aux-files/findclass.php | 125 ++++++++++++++
 guix/build-system/composer.scm       | 173 +++++++++++++++++++
 guix/build/composer-build-system.scm | 241 +++++++++++++++++++++++++++
 5 files changed, 557 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index 6ce1430ea6..5af964b0e9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -115,6 +115,7 @@ MODULES =					\
   guix/build-system/cargo.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/emacs.scm			\
@@ -163,6 +164,7 @@ MODULES =					\
   guix/build/cargo-build-system.scm		\
   guix/build/cargo-utils.scm			\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/emacs-build-system.scm		\
@@ -354,7 +356,8 @@ AUX_FILES =						\
   gnu/packages/aux-files/linux-libre/4.4-i686.conf	\
   gnu/packages/aux-files/linux-libre/4.4-x86_64.conf	\
   gnu/packages/aux-files/pack-audit.c			\
-  gnu/packages/aux-files/run-in-namespace.c
+  gnu/packages/aux-files/run-in-namespace.c		\
+  gnu/packages/aux-files/findclass.php
 
 # Templates, examples.
 EXAMPLES =					\
diff --git a/doc/guix.texi b/doc/guix.texi
index 626915fd39..6870163c23 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -6941,6 +6941,20 @@ debugging information''), which roughly means that code is compiled with
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvr
 
+@defvr {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvr
+
 @defvr {Scheme Variable} dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
diff --git a/gnu/packages/aux-files/findclass.php b/gnu/packages/aux-files/findclass.php
new file mode 100644
index 0000000000..d0b250c8e1
--- /dev/null
+++ b/gnu/packages/aux-files/findclass.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * The content of this file is copied from composer's src/Composer/Autoload/ClassMapGenerator.php
+ * the findClasses method was extracted, to prevent using any dependency.
+ *
+ * Composer (and thus this file) is distributed under the expat license, and
+ * ClassMapGenerator.php also contains this notice:
+ *
+ *   This file is part of Composer.
+ *
+ *   (c) Nils Adermann <naderman@naderman.de>
+ *       Jordi Boggiano <j.boggiano@seld.be>
+ *
+ *   For the full copyright and license information, please view the LICENSE
+ *   file that was distributed with this source code.
+ *
+ *   This file is copied from the Symfony package.
+ *
+ *   (c) Fabien Potencier <fabien@symfony.com>
+ * 
+ * To the extent to wich it makes sense, as the author of the extract:
+ * Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+ */
+
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..0299f11906
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,173 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build union)
+    (json)
+    (json builder)
+    (json parser)
+    (json record)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:source #:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build store name inputs
+                         #:key (guile #f)
+                         (outputs '("out")) (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags ''("--strip-debug"))
+                         (strip-directories ''("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build utils)
+                                    (json))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    `(begin
+       (use-modules ,@modules)
+       (composer-build #:source ,(match (assoc-ref inputs "source")
+                                   (((? derivation? source))
+                                    (derivation->output-path source))
+                                   ((source)
+                                    source)
+                                   (source
+                                    source))
+                       #:system ,system
+                       #:outputs %outputs
+                       #:inputs %build-inputs
+                       #:search-paths ',(map search-path-specification->sexp
+                                             search-paths)
+                       #:phases ,phases
+                       #:out-of-source? ,out-of-source?
+                       #:composer-file ,composer-file
+                       #:tests? ,tests?
+                       #:test-target ,test-target
+                       #:install-target ,install-target
+                       #:validate-runpath? ,validate-runpath?
+                       #:patch-shebangs? ,patch-shebangs?
+                       #:strip-binaries? ,strip-binaries?
+                       #:strip-flags ,strip-flags
+                       #:strip-directories ,strip-directories)))
+
+  (define guile-for-build
+    (match guile
+      ((? package?)
+       (package-derivation store guile system #:graft? #f))
+      (#f                                         ; the default
+       (let* ((distro (resolve-interface '(gnu packages commencement)))
+              (guile  (module-ref distro 'guile-final)))
+         (package-derivation store guile system #:graft? #f)))))
+
+  (build-expression->derivation store name builder
+                                #:system system
+                                #:inputs inputs
+                                #:modules imported-modules
+                                #:outputs outputs
+                                #:guile-for-build guile-for-build))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..1af5e59b81
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,241 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (srfi srfi-26)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-autoload> make-composer-autoload composer-autoload?
+  json->composer-autoload
+  (psr-4 composer-autoload-psr-4 "psr-4"
+                (match-lambda
+                  (#f '())
+                  (psr-4 psr-4)))
+  (classmap composer-autoload-classmap "classmap"
+            (match-lambda
+              (#f '())
+              (#(lst ...) lst))))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (name         composer-package-name)
+  (autoload     composer-package-autoload "autoload" json->composer-autoload)
+  (autoload-dev composer-package-autoload-dev "autoload-dev" json->composer-autoload)
+  (require      composer-package-require "require" json->require)
+  (dev-require  composer-package-dev-require "require-dev" json->require)
+  (scripts      composer-package-scripts "scripts"
+                (match-lambda
+                  (#f '())
+                  ((scripts ...) scripts)))
+  (binaries     composer-package-binaries "bin"
+                (match-lambda
+                  (#f '())
+                  (#(lst ...) lst))))
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (json->composer-package (json->scm port)))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Install the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (composer-package-scripts package-data))
+           (test-script (assoc-ref scripts test-target))
+           (dependencies (composer-package-require package-data))
+           (dependencies-dev (composer-package-dev-require package-data))
+           (name (composer-package-name package-data)))
+      (for-each
+        (match-lambda
+          ((_ . input)
+           (let ((bin (find-php-bin input)))
+             (when bin
+               (copy-recursively bin "vendor/bin")))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (zero? (system command))
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (zero? (system c))
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit")))))
+  #t)
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs inputs))
+    (match inputs
+      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
+                 dependency))
+      (((_ . input) inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  "creates an autoload.php file that sets up the class locations for this package,
+so it can be autoloaded by PHP when the package classes are required."
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (display (string-append
+                 "<?php
+// autoload.php @generated by Guix
+$map = $psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php'
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($map as $namespace => $path) {
+  $loader->set($namespace, $path);
+}
+foreach ($psr4map as $namespace => $path) {
+  $loader->setPsr4($namespace, $path);
+}
+$loader->addClassMap($classmap);
+$loader->register();
+"))))
+  ;; Now, create autoload_conf.php that contains the actual data, as a set
+  ;; of arrays
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload (composer-package-autoload package-data))
+         (autoload-dev (composer-package-autoload-dev package-data))
+         (dependencies (composer-package-require package-data))
+         (dependencies-dev (composer-package-dev-require package-data)))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (composer-autoload-psr-4 autoload)
+            (if dev-dependencies?
+                (composer-autoload-psr-4 autoload-dev)
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (composer-autoload-classmap autoload)
+            (if dev-dependencies?
+                (composer-autoload-classmap autoload-dev)
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (composer-package-name package-data))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (composer-package-binaries package-data)))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs))
+  #t)
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
-- 
2.28.0


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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-29 14:49               ` Julien Lepiller
@ 2020-09-30  9:24                 ` Ludovic Courtès
  2020-12-18 23:43                   ` Julien Lepiller
  0 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2020-09-30  9:24 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi,

Julien Lepiller <julien@lepiller.eu> skribis:

> Here's a new version, hopefully this addresses all your remarks. I'm
> still not sure how (json) is pulled in to the build side though... How
> does guix know it needs to use guile-json-3 instead of guile-json-1 for
> instance?

Ah, see below.

> How does it work with inferiors?

I think inferiors have nothing to do with it.

> From 432f57aeeb3b2e48591288e6491d66ab299661f0 Mon Sep 17 00:00:00 2001
> From: Julien Lepiller <julien@lepiller.eu>
> Date: Tue, 29 Oct 2019 20:58:51 +0100
> Subject: [PATCH 03/34] guix: Add composer-build-system.
>
> * guix/build-system/composer.scm: New file.
> * guix/build/composer-build-system.scm: New file.
> * gnu/packages/aux-files/findclass.php: New file.
> * Makefile.am: Add them.
> * doc/guix.texi (Build Systems): Document it.

[...]

> +(define %composer-build-system-modules
> +  ;; Build-side modules imported by default.
> +  `((guix build composer-build-system)
> +    (guix build union)
> +    (json)
> +    (json builder)
> +    (json parser)
> +    (json record)

Here, as the comment says, you’re importing (json …) from the host side
to the build side.  That’s why it works.

The problem is that it’s just picking whatever (json …) modules are on
your load path on the host side: if you have Guile-JSON 3.x, it’ll use
that, if you have 4.x, that’ll be 4.x, and if you have nothing, it’ll
fail to build.

So the fix is to remove those modules from this list.  You should only
ever import Guix modules.

Now you need to bring Guile-JSON into the environment.  When using gexp,
we do that with ‘with-extensions’, but here it’s a bit clunky…

> +                         (modules '((guix build composer-build-system)
> +                                    (guix build utils)
> +                                    (json))))

I think you don’t need (json) here.  (This is the list of modules in
scope.)

> +  (define builder
> +    `(begin
> +       (use-modules ,@modules)
> +       (composer-build #:source ,(match (assoc-ref inputs "source")
> +                                   (((? derivation? source))
> +                                    (derivation->output-path source))
> +                                   ((source)
> +                                    source)
> +                                   (source
> +                                    source))
> +                       #:system ,system
> +                       #:outputs %outputs
> +                       #:inputs %build-inputs
> +                       #:search-paths ',(map search-path-specification->sexp
> +                                             search-paths)
> +                       #:phases ,phases
> +                       #:out-of-source? ,out-of-source?
> +                       #:composer-file ,composer-file
> +                       #:tests? ,tests?
> +                       #:test-target ,test-target
> +                       #:install-target ,install-target
> +                       #:validate-runpath? ,validate-runpath?
> +                       #:patch-shebangs? ,patch-shebangs?
> +                       #:strip-binaries? ,strip-binaries?
> +                       #:strip-flags ,strip-flags
> +                       #:strip-directories ,strip-directories)))

To bring in Guile-JSON, you need to do something similar to what
‘gexp->file’ does with ‘load-path-expression’, along these lines
(untested):

  (define guile-json-drv
    (package-derivation store
                        (module-ref (resolve-interface '(gnu packages guile))
                                    'guile-json)
                        system))

  (define builder
    `(begin
       (add-to-load-path (string-append ,(derivation->output-path guile-json-drv)
                                        "/share/guile/site/"
                                        (effective-version)))
       (use-modules ,@modules)
       …))

   ;; …

   (build-expression->derivation store name builder
                                 ;; …
                                 #:inputs (append inputs
                                                  `(("guile-json" ,guile-json-drv))))

I guess clunkiness is the reason why we didn’t do it last time…

HTH!

Ludo’.




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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-09-30  9:24                 ` Ludovic Courtès
@ 2020-12-18 23:43                   ` Julien Lepiller
  2020-12-21 14:51                     ` Ludovic Courtès
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2020-12-18 23:43 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: 42338

Le Wed, 30 Sep 2020 11:24:08 +0200,
Ludovic Courtès <ludo@gnu.org> a écrit :
> 
> To bring in Guile-JSON, you need to do something similar to what
> ‘gexp->file’ does with ‘load-path-expression’, along these lines
> (untested):
> 
>   (define guile-json-drv
>     (package-derivation store
>                         (module-ref (resolve-interface '(gnu packages
> guile)) 'guile-json)
>                         system))
> 
>   (define builder
>     `(begin
>        (add-to-load-path (string-append ,(derivation->output-path
> guile-json-drv) "/share/guile/site/"
>                                         (effective-version)))
>        (use-modules ,@modules)
>        …))
> 
>    ;; …
> 
>    (build-expression->derivation store name builder
>                                  ;; …
>                                  #:inputs (append inputs
>                                                   `(("guile-json"
> ,guile-json-drv))))
> 
> I guess clunkiness is the reason why we didn’t do it last time…
> 
> HTH!
> 
> Ludo’.

Hi Ludo, sorry for the delay!

I tried that (replacing 'guile-json with 'guile-json-4), but it doesn't
work: when building the package, guix first builds a modules-compiled
that fails because it can't find (json). It seems to be related to the
compilation of (guix build composer-build-system) which uses the (json)
module: when removing the import, it's modules-compiled works (with a
lot of warnings), but obviously guix can't build the php package.




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

* [bug#42338] [PATCH 03/34] guix: Add composer-build-system.
  2020-12-18 23:43                   ` Julien Lepiller
@ 2020-12-21 14:51                     ` Ludovic Courtès
  0 siblings, 0 replies; 95+ messages in thread
From: Ludovic Courtès @ 2020-12-21 14:51 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: 42338

Hi,

Julien Lepiller <julien@lepiller.eu> skribis:

> I tried that (replacing 'guile-json with 'guile-json-4), but it doesn't
> work: when building the package, guix first builds a modules-compiled
> that fails because it can't find (json). It seems to be related to the
> compilation of (guix build composer-build-system) which uses the (json)
> module: when removing the import, it's modules-compiled works (with a
> lot of warnings), but obviously guix can't build the php package.

Ah OK.  Well, maybe you can sidestep the issue and use a custom JSON
module instead.  Sorry for the broken piece of advice!

Ludo’.




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

* [bug#42338]
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
@ 2021-08-23  9:46 ` db
  2022-08-13 20:30 ` [bug#42338] Ping about php composer guix-patches--- via
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 95+ messages in thread
From: db @ 2021-08-23  9:46 UTC (permalink / raw)
  To: 42338

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

Hello. Is this feature still being worked on? I'd love to make use of it!

Cheers,

Demis.


[-- Attachment #2: Type: text/html, Size: 1620 bytes --]

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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2020-09-25 10:27           ` Ludovic Courtès
@ 2021-10-16  4:15             ` Maxim Cournoyer
  0 siblings, 0 replies; 95+ messages in thread
From: Maxim Cournoyer @ 2021-10-16  4:15 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Julien Lepiller, 42338

Hey Julien,

That's a pretty interesting series you have there.

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

> Hi Julien,
>
> Julien Lepiller <julien@lepiller.eu> skribis:
>
>> From 70b9cb2bb389f3e5f9dcc75a44d7d60c28f997bc Mon Sep 17 00:00:00 2001
>> From: Julien Lepiller <julien@lepiller.eu>
>> Date: Tue, 29 Oct 2019 08:07:38 +0100
>> Subject: [PATCH 01/34] guix: import: Add composer importer.
>>
>> * guix/import/composer.scm: New file.
>> * guix/scripts/import/composer.scm: New file.
>> * guix/tests/composer.scm: New file.
>> * Makefile.am: Add them.
>> * guix/scripts/import.scm: Add composer importer.
>> * doc/guix.texi (Invoking guix import): Mention it.
>
> [...]
>
>> +@cindex PHP
>> +Import metadat from the @uref{https://getcomposer.org/, Composer} package
>                 ^
> Typo.
>
>> +(define* (composer-fetch name #:optional version)
>> +  "Return an alist representation of the Composer metadata for the package NAME,
>> +or #f on failure."
>> +  (let ((package (json-fetch
>> +                   (string-append (%composer-base-url) "/p/" name ".json"))))
>> +    (if package
>> +        (let* ((packages (assoc-ref package "packages"))
>> +               (package (or (assoc-ref packages name) package))
>> +               (versions (filter
>> +                           (lambda (version)
>> +                             (and (not (string-contains version "dev"))
>> +                                  (not (string-contains version "beta"))))
>> +                           (map car package)))
>> +               (version (or (if (null? version) #f version)
>> +                            (latest-version versions))))
>> +          (assoc-ref package version))
>> +        #f)))
>
> I think this should directly return a <composer-package> since the all
> the callers pass the alist through ‘json->composer-package’.  The idea
> is that alists should be converted to records as soon as they enter the
> process.
>
> Also it’s weird that ‘package’ above has a “packages” (plural) entry.
> Perhaps we’re missing another JSON mapping?
>
> [...]
>
>> +++ b/guix/scripts/import/composer.scm
>> @@ -0,0 +1,107 @@
>> +;;; GNU Guix --- Functional package management for GNU
>> +;;; Copyright © 2015 David Thompson <davet@gnu.org>
>> +;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
>
> You can preserve these two lines if you think it’s relevant, but I’d
> suggest adding one for yourself.
>
> OK to push with changes along these lines.

Seems you were almost ready to roll.  Consider this a very gentle ping
:-).

Maxim




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

* [bug#42338] Ping about php composer
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
  2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
  2021-08-23  9:46 ` [bug#42338] db
@ 2022-08-13 20:30 ` guix-patches--- via
  2022-08-13 20:38   ` Julien Lepiller
  2022-10-06 16:27 ` [bug#42338] [PATCH] Add composer build system (PHP) Maxime Devos
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 95+ messages in thread
From: guix-patches--- via @ 2022-08-13 20:30 UTC (permalink / raw)
  To: 42338, julien

Hi,

I wanted to ask, would you be interested in finishing your php composer
patch to get it pushed? Or if not, can I take you code to the finish
line appyling those last few requests?

Regards,

Maya




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

* [bug#42338] Ping about php composer
  2022-08-13 20:30 ` [bug#42338] Ping about php composer guix-patches--- via
@ 2022-08-13 20:38   ` Julien Lepiller
  0 siblings, 0 replies; 95+ messages in thread
From: Julien Lepiller @ 2022-08-13 20:38 UTC (permalink / raw)
  To: Mája Tomášek, 42338

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

Hi Mája

You're more than welcome to take the patch series to the finish line! I don't think I'm able to work on it, but I can answer questions if you have any.

Le 13 août 2022 22:30:47 GMT+02:00, "Mája Tomášek" <maya.tomasek@disroot.org> a écrit :
>Hi,
>
>I wanted to ask, would you be interested in finishing your php composer
>patch to get it pushed? Or if not, can I take you code to the finish
>line appyling those last few requests?
>
>Regards,
>
>Maya

[-- Attachment #2: Type: text/html, Size: 753 bytes --]

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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (2 preceding siblings ...)
  2022-08-13 20:30 ` [bug#42338] Ping about php composer guix-patches--- via
@ 2022-10-06 16:27 ` Maxime Devos
  2022-10-11 18:07   ` guix-patches--- via
  2023-04-21  0:23 ` Adam Faiz via Guix-patches via
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 95+ messages in thread
From: Maxime Devos @ 2022-10-06 16:27 UTC (permalink / raw)
  To: 42338, Mája Tomášek


[-- Attachment #1.1.1: Type: text/plain, Size: 158 bytes --]

Hi,

I think I'll have some time to finish this, but first I'd like to ask if 
someone else had taken / is taking  a stab at this.

Greetings,
Maxime.

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2022-10-06 16:27 ` [bug#42338] [PATCH] Add composer build system (PHP) Maxime Devos
@ 2022-10-11 18:07   ` guix-patches--- via
  0 siblings, 0 replies; 95+ messages in thread
From: guix-patches--- via @ 2022-10-11 18:07 UTC (permalink / raw)
  To: Maxime Devos, 42338

Maxime Devos <maximedevos@telenet.be> writes:

> Hi,
>
> I think I'll have some time to finish this, but first I'd like to ask if 
> someone else had taken / is taking  a stab at this.
>
> Greetings,
> Maxime.

Hi,

I have not managed to rebase these patches and sadly I don't have the time
for this right now. :/

Maya




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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (3 preceding siblings ...)
  2022-10-06 16:27 ` [bug#42338] [PATCH] Add composer build system (PHP) Maxime Devos
@ 2023-04-21  0:23 ` Adam Faiz via Guix-patches via
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 95+ messages in thread
From: Adam Faiz via Guix-patches via @ 2023-04-21  0:23 UTC (permalink / raw)
  To: 42338; +Cc: julien, maximedevos, maya.tomasek

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

Hi,

I'm interested in this composer build system so that I can start packaging the NextCloud server and its dependencies.
I've rebased the patches and modified them a bit:

1. The composer importer now uses the new inputs style for importing
2. The composer build system uses gexps

However, there are a few bugs that I don't know how to fix.

The --recursive option of the importer doesn't work:

===
In guix/scripts/import.scm:
     89:11  4 (guix-import . _)
In guix/scripts/import/composer.scm:ice-9/boot-9.scm:1685:16: In procedure raise-exception:
Throw to key `match-error' with args `("match" "no matching pattern" #<unspecified>)'.

     98:17  3 (guix-import-composer . _)
In guix/import/utils.scm:
    638:27  2 (recursive-import "psr/http-client" # _ #:guix-name _ . #)
    630:33  1 (lookup-node "psr/http-client" #f)
In ice-9/eval.scm:
    423:17  0 (_ . _)

ice-9/eval.scm:423:17: In procedure eval: Wrong number of arguments
===


I think there's something wrong with (define-json-mapping <composer-autoload>:

===
error: in phase 'install': uncaught exception:
match-error "match" "no matching pattern" #<unspecified>

In guix/build/gnu-build-system.scm:
    927:23  6 (_)
In guix/build/composer-build-system.scm:
    200:23  5 (install #:inputs _ #:outputs _ #:composer-file _)
In ice-9/ports.scm:
    433:17  4 (call-with-input-file _ _ #:binary _ #:encoding _ # _)
In guix/build/composer-build-system.scm:
      56:0  3 (json->composer-package (("config" ("allow-plug…" …)) …))
     52:12  2 (json->composer-autoload (("psr-4" ("Doctrine\\…" . #))))
In ice-9/boot-9.scm:
   1685:16  1 (raise-exception _ #:continuable? _)
   1685:16  0 (raise-exception _ #:continuable? _)

ice-9/boot-9.scm:1685:16: In procedure raise-exception:
Throw to key `match-error' with args `("match" "no matching pattern" #<unspecified>)'.
===

[-- Attachment #2: 0001-guix-import-Add-composer-importer.patch --]
[-- Type: text/x-patch, Size: 21171 bytes --]

From 0d44f8f1e66c4141d0c97aa2b633091a0bb753e5 Mon Sep 17 00:00:00 2001
Message-Id: <0d44f8f1e66c4141d0c97aa2b633091a0bb753e5.1682034340.git.adam.faiz@disroot.org>
From: Julien Lepiller <julien@lepiller.eu>
Date: Thu, 20 Apr 2023 07:18:18 +0800
Subject: [PATCH 1/3] guix: import: Add composer importer.

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  12 ++
 guix/import/composer.scm         | 248 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 +++++++++++++
 tests/composer.scm               |  92 ++++++++++++
 6 files changed, 463 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 23b939b674..f9de4a967a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -270,6 +270,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -327,6 +328,7 @@ MODULES =					\
   guix/scripts/home/import.scm			\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cran.scm			\
   guix/scripts/import/egg.scm   		\
@@ -492,6 +494,7 @@ SCM_TESTS =					\
   tests/challenge.scm				\
   tests/channels.scm				\
   tests/combinators.scm			\
+  tests/composer.scm				\
   tests/containers.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index adb1975935..9c9e567120 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -14009,6 +14009,18 @@ Invoking guix import
 
 @end table
 
+@item composer
+@cindex Composer
+@cindex PHP
+Import metadata from the @uref{https://getcomposer.org/, Composer} package
+archive used by the PHP community, as in this example:
+
+@example
+guix import composer phpunit/phpunit
+@end example
+
+@end table
+
 @item go
 @cindex go
 Import metadata for a Go module using
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..75c79209ee
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,248 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? a b) a b)) (car versions) versions))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append "https://repo.packagist.org/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (assoc-ref packages name))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (versions (map
+                           (lambda (version)
+                             (cons (fix-version version) version))
+                           versions))
+               (version (or (if (null? version) #f version)
+                            (latest-version (map car versions)))))
+          (assoc-ref package (assoc-ref versions version)))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp name version home-page description dependencies
+                       dev-dependencies licenses source)
+  "Return the `package' s-expression for a PHP package with the given NAME,
+VERSION, HOME-PAGE, DESCRIPTION, DEPENDENCIES, LICENSES and SOURCE."
+  (let ((git? (equal? (assoc-ref source "type") "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (assoc-ref source "url")
+                             (assoc-ref source "reference")
+                             temp))
+                (url-fetch (assoc-ref source "url") temp))
+            `(package
+               (name ,(php-package-name name))
+               (version ,version)
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(assoc-ref source "url"))
+                                        (commit ,(assoc-ref source "reference"))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(assoc-ref source "url"))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'list
+                         ,@(map (lambda (name)
+                                 `,(string->symbol name))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'list
+                         ,@(map (lambda (name)
+                                 `,(string->symbol name))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,description)
+               (home-page ,home-page)
+               (license ,(match licenses
+                           (() #f)
+                           ((license) (license->symbol license))
+                           (_ `(list ,@(map license->symbol licenses)))))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((name         (assoc-ref package "name"))
+                (version      (fix-version (assoc-ref package "version")))
+                (description  (beautify-description
+                               (assoc-ref package "description")))
+                (home-page    (assoc-ref package "homepage"))
+                (dependencies-names (filter
+                                      (lambda (dep)
+                                        (string-contains dep "/"))
+                                      (map car (assoc-ref package "require"))))
+                (dependencies (map php-package-name dependencies-names))
+                (require-dev (assoc-ref package "require-dev"))
+                (dev-dependencies-names
+                  (if require-dev
+                      (filter
+                        (lambda (dep)
+                          (string-contains dep "/"))
+                        (map car require-dev))
+                      '()))
+                (dev-dependencies (map php-package-name dev-dependencies-names))
+                (licenses     (map string->license
+                                   (vector->list
+                                    (assoc-ref package "license")))))
+           (values (make-php-sexp name version home-page description dependencies
+                                  dev-dependencies licenses (assoc-ref package "source"))
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" license:lgpl2.0)
+    ("GPL" license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") license:expat)
+    ("Public domain" license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (version (fix-version (assoc-ref metadata "version")))
+         (url (assoc-ref (assoc-ref metadata "source") "url")))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (import latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index f84a964a53..fa1f96df9c 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -47,7 +47,7 @@ (define %standard-import-options '())
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
                     "gem" "go" "cran" "crate" "texlive" "json" "opam"
-                    "minetest" "elm" "hexpm"))
+                    "minetest" "elm" "hexpm" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/tests/composer.scm b/tests/composer.scm
new file mode 100644
index 0000000000..cefaf9f434
--- /dev/null
+++ b/tests/composer.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (test-composer)
+  #:use-module (guix import composer)
+  #:use-module (guix base32)
+  #:use-module (gcrypt hash)
+  #:use-module (guix tests http)
+  #:use-module (guix grafts)
+  #:use-module (srfi srfi-64)
+  #:use-module (web client)
+  #:use-module (ice-9 match))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define test-json
+  "{
+  \"packages\": {
+    \"foo/bar\": {
+      \"0.1\": {
+        \"name\": \"foo/bar\",
+        \"description\": \"description\",
+        \"keywords\": [\"testing\"],
+        \"homepage\": \"http://example.com\",
+        \"version\": \"0.1\",
+        \"license\": [\"BSD-3-Clause\"],
+        \"source\": {
+          \"type\": \"url\",
+          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
+        },
+        \"require\": {},
+        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
+      }
+    }
+  }
+}")
+
+(define test-source
+  "foobar")
+
+;; Avoid collisions with other tests.
+(%http-server-port 10450)
+
+(test-begin "composer")
+
+(test-assert "composer->guix-package"
+  ;; Replace network resources with sample data.
+  (with-http-server `((200 ,test-json)
+                      (200 ,test-source))
+    (parameterize ((%composer-base-url (%local-url))
+                   (current-http-proxy (%local-url)))
+      (match (composer->guix-package "foo/bar")
+        (('package
+           ('name "php-foo-bar")
+           ('version "0.1")
+           ('source ('origin
+                      ('method 'url-fetch)
+                      ('uri "http://example.com/Bar-0.1.tar.gz")
+                      ('sha256
+                       ('base32
+                        (? string? hash)))))
+           ('build-system 'composer-build-system)
+           ('native-inputs
+            ('quasiquote
+             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
+           ('synopsis "")
+           ('description "description")
+           ('home-page "http://example.com")
+           ('license 'license:bsd-3))
+         (string=? (bytevector->nix-base32-string
+                    (call-with-input-string test-source port-sha256))
+                   hash))
+        (x
+         (pk 'fail x #f))))))
+
+(test-end "composer")

base-commit: a9f4b6ecd00112ae4fb04dfbe0f9cc86b042dbc5
-- 
2.39.2


[-- Attachment #3: 0002-gnu-Add-composer-classloader.patch --]
[-- Type: text/x-patch, Size: 3922 bytes --]

From d8814cc803f26c63c1c1ac55c45132324b1446a4 Mon Sep 17 00:00:00 2001
Message-Id: <d8814cc803f26c63c1c1ac55c45132324b1446a4.1682034341.git.adam.faiz@disroot.org>
In-Reply-To: <0d44f8f1e66c4141d0c97aa2b633091a0bb753e5.1682034340.git.adam.faiz@disroot.org>
References: <0d44f8f1e66c4141d0c97aa2b633091a0bb753e5.1682034340.git.adam.faiz@disroot.org>
From: Julien Lepiller <julien@lepiller.eu>
Date: Thu, 20 Apr 2023 07:22:37 +0800
Subject: [PATCH 2/3] gnu: Add composer-classloader.

* gnu/packages/php-xyz.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk             |  1 +
 gnu/packages/php-xyz.scm | 61 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 gnu/packages/php-xyz.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index 7f6ea08b93..025fd5e09b 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -495,6 +495,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/photo.scm			\
   %D%/packages/phabricator.scm 			\
   %D%/packages/php.scm				\
+  %D%/packages/php-xyz.scm			\
   %D%/packages/piet.scm			\
   %D%/packages/pikchr.scm			\
   %D%/packages/pkg-config.scm			\
diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
new file mode 100644
index 0000000000..dab660f84f
--- /dev/null
+++ b/gnu/packages/php-xyz.scm
@@ -0,0 +1,61 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (gnu packages php-xyz)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages php)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system composer)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix utils)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public composer-classloader
+  (package
+    (name "composer-classloader")
+    (version "1.9.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/composer/composer.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0127zmmg3yx84ljngfs86q7kjhyypybkf4d1ihfrfnzgynzxfxdf"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (delete 'build)
+         (delete 'check)
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (install (string-append out "/share/web/composer/ClassLoader.php")))
+               (mkdir-p (dirname install))
+               (copy-file "src/Composer/Autoload/ClassLoader.php" install)))))))
+    (home-page "https://getcomposer.org")
+    (synopsis "PHP class loader extracted from the composer package")
+    (description "This package contains the class loader class used by Composer to
+build its autoloading feature.  This package is used by the composer-build-system
+to build its own store-aware autoloading feature.")
+    (license license:expat)))
-- 
2.39.2


[-- Attachment #4: 0003-guix-Add-composer-build-system.patch --]
[-- Type: text/x-patch, Size: 25235 bytes --]

From 575967e5a34b397495e8e18fee8ba322cb62321a Mon Sep 17 00:00:00 2001
Message-Id: <575967e5a34b397495e8e18fee8ba322cb62321a.1682034341.git.adam.faiz@disroot.org>
In-Reply-To: <0d44f8f1e66c4141d0c97aa2b633091a0bb753e5.1682034340.git.adam.faiz@disroot.org>
References: <0d44f8f1e66c4141d0c97aa2b633091a0bb753e5.1682034340.git.adam.faiz@disroot.org>
From: Julien Lepiller <julien@lepiller.eu>
Date: Thu, 20 Apr 2023 07:32:48 +0800
Subject: [PATCH 3/3] guix: Add composer-build-system.

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* gnu/packages/aux-files/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   6 +-
 doc/guix.texi                        |  14 ++
 gnu/packages/aux-files/findclass.php | 125 ++++++++++++++
 guix/build-system/composer.scm       | 162 ++++++++++++++++++
 guix/build/composer-build-system.scm | 239 +++++++++++++++++++++++++++
 5 files changed, 545 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index f9de4a967a..dbf2336025 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -147,6 +147,7 @@ MODULES =					\
   guix/build-system/chicken.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/elm.scm			\
@@ -202,6 +203,7 @@ MODULES =					\
   guix/build/cargo-utils.scm			\
   guix/build/chicken-build-system.scm		\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/elm-build-system.scm		\
@@ -438,7 +440,9 @@ AUX_FILES =						\
   gnu/packages/aux-files/python/sanity-check-next.py	\
   gnu/packages/aux-files/python/sitecustomize.py	\
   gnu/packages/aux-files/renpy/renpy.in	\
-  gnu/packages/aux-files/run-in-namespace.c
+  gnu/packages/aux-files/run-in-namespace.c	\
+  gnu/packages/aux-files/findclass.php
+
 
 # Templates, examples.
 EXAMPLES =					\
diff --git a/doc/guix.texi b/doc/guix.texi
index 9c9e567120..13f4f7401c 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9173,6 +9173,20 @@ Build Systems
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvar
 
+@defvar {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvar
+
 @defvar dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
diff --git a/gnu/packages/aux-files/findclass.php b/gnu/packages/aux-files/findclass.php
new file mode 100644
index 0000000000..d0b250c8e1
--- /dev/null
+++ b/gnu/packages/aux-files/findclass.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * The content of this file is copied from composer's src/Composer/Autoload/ClassMapGenerator.php
+ * the findClasses method was extracted, to prevent using any dependency.
+ *
+ * Composer (and thus this file) is distributed under the expat license, and
+ * ClassMapGenerator.php also contains this notice:
+ *
+ *   This file is part of Composer.
+ *
+ *   (c) Nils Adermann <naderman@naderman.de>
+ *       Jordi Boggiano <j.boggiano@seld.be>
+ *
+ *   For the full copyright and license information, please view the LICENSE
+ *   file that was distributed with this source code.
+ *
+ *   This file is copied from the Symfony package.
+ *
+ *   (c) Fabien Potencier <fabien@symfony.com>
+ * 
+ * To the extent to wich it makes sense, as the author of the extract:
+ * Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+ */
+
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..8bf99ff9c5
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,162 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build union)
+    (json)
+    (json builder)
+    (json parser)
+    (json record)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build name inputs
+                         #:key
+                         guile source
+                         (outputs '("out"))
+                         (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags #~'("--strip-debug"))
+                         (strip-directories #~'("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build utils))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@(sexp->gexp modules))
+
+          #$(with-build-variables inputs outputs
+              #~(composer-build
+                 #:source #$source
+                 #:system #$system
+                 #:outputs %outputs
+                 #:inputs %build-inputs
+                 #:search-paths '#$(map search-path-specification->sexp
+                                        search-paths)
+                 #:phases #$phases
+                 #:out-of-source? #$out-of-source?
+                 #:composer-file #$composer-file
+                 #:tests? #$tests?
+                 #:test-target #$test-target
+                 #:install-target #$install-target
+                 #:validate-runpath? #$validate-runpath?
+                 #:patch-shebangs? #$patch-shebangs?
+                 #:strip-binaries? #$strip-binaries?
+                 #:strip-flags #$strip-flags
+                 #:strip-directories #$strip-directories)))))
+
+  (gexp->derivation name builder
+                    #:system system
+                    #:target #f
+                    #:graft? #f
+                    #:guile-for-build guile))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..7df2b7c400
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,239 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (srfi srfi-26)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-autoload> make-composer-autoload composer-autoload?
+  json->composer-autoload
+  (psr-4 composer-autoload-psr-4 "psr-4"
+                (match-lambda
+                  (#f '())
+                  (psr-4 psr-4)))
+  (classmap composer-autoload-classmap "classmap"
+            (match-lambda
+              (#f '())
+              (#(lst ...) lst))))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (name         composer-package-name)
+  (autoload     composer-package-autoload "autoload" json->composer-autoload)
+  (autoload-dev composer-package-autoload-dev "autoload-dev" json->composer-autoload)
+  (require      composer-package-require "require" json->require)
+  (dev-require  composer-package-dev-require "require-dev" json->require)
+  (scripts      composer-package-scripts "scripts"
+                (match-lambda
+                  (#f '())
+                  ((scripts ...) scripts)))
+  (binaries     composer-package-binaries "bin"
+                (match-lambda
+                  (#f '())
+                  (#(lst ...) lst))))
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (json->composer-package (json->scm port)))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Test the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (composer-package-scripts package-data))
+           (test-script (assoc-ref scripts test-target))
+           (dependencies (composer-package-require package-data))
+           (dependencies-dev (composer-package-dev-require package-data))
+           (name (composer-package-name package-data)))
+      (for-each
+        (match-lambda
+          ((_ . input)
+           (let ((bin (find-php-bin input)))
+             (when bin
+               (copy-recursively bin "vendor/bin")))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (zero? (system command))
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (zero? (system c))
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit"))))))
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs inputs))
+    (match inputs
+      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
+                 dependency))
+      (((_ . input) inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  "creates an autoload.php file that sets up the class locations for this package,
+so it can be autoloaded by PHP when the package classes are required."
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (display (string-append
+                 "<?php
+// autoload.php @generated by Guix
+$map = $psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php'
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($map as $namespace => $path) {
+  $loader->set($namespace, $path);
+}
+foreach ($psr4map as $namespace => $path) {
+  $loader->setPsr4($namespace, $path);
+}
+$loader->addClassMap($classmap);
+$loader->register();
+"))))
+  ;; Now, create autoload_conf.php that contains the actual data, as a set
+  ;; of arrays
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload (composer-package-autoload package-data))
+         (autoload-dev (composer-package-autoload-dev package-data))
+         (dependencies (composer-package-require package-data))
+         (dependencies-dev (composer-package-dev-require package-data)))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (composer-autoload-psr-4 autoload)
+            (if dev-dependencies?
+                (composer-autoload-psr-4 autoload-dev)
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (composer-autoload-classmap autoload)
+            (if dev-dependencies?
+                (composer-autoload-classmap autoload-dev)
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (composer-package-name package-data))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (composer-package-binaries package-data)))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs)))
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
-- 
2.39.2


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

* [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer.
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (4 preceding siblings ...)
  2023-04-21  0:23 ` Adam Faiz via Guix-patches via
@ 2023-09-26 10:31 ` Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 2/7] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
                     ` (7 more replies)
  2023-09-26 11:25 ` [bug#42338] [PATCH v3] guix: import: composer: Fix match-lambda with a default fallback Nicolas Graves via Guix-patches via
                   ` (5 subsequent siblings)
  11 siblings, 8 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338
  Cc: ngraves, Christopher Baines, Josselin Poiret,
	Ludovic Courtès, Mathieu Othacehe, Ricardo Wurmus,
	Simon Tournier, Tobias Geerinckx-Rice

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  20 +++
 guix/import/composer.scm         | 270 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 ++++++++++++
 tests/composer.scm               |  92 +++++++++++
 6 files changed, 493 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 8924974e8a..3ce7ee832e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -274,6 +274,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -332,6 +333,7 @@ MODULES =					\
   guix/scripts/home/import.scm			\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cpan.scm			\
   guix/scripts/import/cran.scm			\
@@ -500,6 +502,7 @@ SCM_TESTS =					\
   tests/challenge.scm				\
   tests/channels.scm				\
   tests/combinators.scm			\
+  tests/composer.scm				\
   tests/containers.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 46591b2f64..4d2fc11cd7 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -14530,6 +14530,26 @@ Invoking guix import
 
 Additional options include:
 
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
+@item composer
+@cindex Composer
+@cindex PHP
+Import metadat from the @uref{https://getcomposer.org/, Composer} package
+archive used by the PHP community, as in this example:
+
+@example
+guix import composer phpunit/phpunit
+@end example
+
+Additional options include:
+
 @table @code
 @item --recursive
 @itemx -r
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..c152f402bb
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,270 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import
+
+            %composer-base-url))
+
+(define %composer-base-url
+  (make-parameter "https://repo.packagist.org"))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b))
+        (car versions) versions))
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-source> make-composer-source composer-source?
+  json->composer-source
+  (type      composer-source-type)
+  (url       composer-source-url)
+  (reference composer-source-reference))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (description composer-package-description)
+  (homepage    composer-package-homepage)
+  (source      composer-package-source "source" json->composer-source)
+  (name        composer-package-name "name" php-package-name)
+  (version     composer-package-version "version" fix-version)
+  (require     composer-package-require "require" json->require)
+  (dev-require composer-package-dev-require "require-dev" json->require)
+  (license     composer-package-license "license"
+               (lambda (vector)
+                 (map string->license (vector->list vector)))))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append (%composer-base-url) "/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (or (assoc-ref packages name) package))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (version (or (if (null? version) #f version)
+                            (latest-version versions))))
+          (assoc-ref package version))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp composer-package)
+  "Return the `package' s-expression for a PHP package for the given
+COMPOSER-PACKAGE."
+  (let* ((source (composer-package-source composer-package))
+         (dependencies (map php-package-name
+                            (composer-package-require composer-package)))
+         (dev-dependencies (map php-package-name
+                                (composer-package-dev-require composer-package)))
+         (git? (equal? (composer-source-type source) "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (composer-source-url source)
+                             (composer-source-reference source)
+                             temp))
+                (url-fetch (composer-source-url source) temp))
+            `(package
+               (name ,(composer-package-name composer-package))
+               (version ,(composer-package-version composer-package))
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(composer-source-url source))
+                                        (commit ,(composer-source-reference source))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(composer-source-url source))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,(composer-package-description composer-package))
+               (home-page ,(composer-package-homepage composer-package))
+               (license ,(match (composer-package-license composer-package)
+                           (() #f)
+                           ((license) license)
+                           (_ license)))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((package (json->composer-package package))
+                (dependencies-names (composer-package-require package))
+                (dev-dependencies-names (composer-package-dev-require package)))
+           (values (make-php-sexp package)
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" 'license:lgpl2.0)
+    ("GPL" 'license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") 'license:expat)
+    ("Public domain" 'license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (package (json->composer-package metadata))
+         (version (composer-package-version package))
+         (url (composer-source-url (composer-package-source package))))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (import latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 4ddd8d46a1..8c58dd35e2 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -47,7 +47,7 @@ (define %standard-import-options '())
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
                     "gem" "go" "cran" "crate" "texlive" "json" "opam"
-                    "minetest" "elm" "hexpm"))
+                    "minetest" "elm" "hexpm" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/tests/composer.scm b/tests/composer.scm
new file mode 100644
index 0000000000..cefaf9f434
--- /dev/null
+++ b/tests/composer.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (test-composer)
+  #:use-module (guix import composer)
+  #:use-module (guix base32)
+  #:use-module (gcrypt hash)
+  #:use-module (guix tests http)
+  #:use-module (guix grafts)
+  #:use-module (srfi srfi-64)
+  #:use-module (web client)
+  #:use-module (ice-9 match))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define test-json
+  "{
+  \"packages\": {
+    \"foo/bar\": {
+      \"0.1\": {
+        \"name\": \"foo/bar\",
+        \"description\": \"description\",
+        \"keywords\": [\"testing\"],
+        \"homepage\": \"http://example.com\",
+        \"version\": \"0.1\",
+        \"license\": [\"BSD-3-Clause\"],
+        \"source\": {
+          \"type\": \"url\",
+          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
+        },
+        \"require\": {},
+        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
+      }
+    }
+  }
+}")
+
+(define test-source
+  "foobar")
+
+;; Avoid collisions with other tests.
+(%http-server-port 10450)
+
+(test-begin "composer")
+
+(test-assert "composer->guix-package"
+  ;; Replace network resources with sample data.
+  (with-http-server `((200 ,test-json)
+                      (200 ,test-source))
+    (parameterize ((%composer-base-url (%local-url))
+                   (current-http-proxy (%local-url)))
+      (match (composer->guix-package "foo/bar")
+        (('package
+           ('name "php-foo-bar")
+           ('version "0.1")
+           ('source ('origin
+                      ('method 'url-fetch)
+                      ('uri "http://example.com/Bar-0.1.tar.gz")
+                      ('sha256
+                       ('base32
+                        (? string? hash)))))
+           ('build-system 'composer-build-system)
+           ('native-inputs
+            ('quasiquote
+             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
+           ('synopsis "")
+           ('description "description")
+           ('home-page "http://example.com")
+           ('license 'license:bsd-3))
+         (string=? (bytevector->nix-base32-string
+                    (call-with-input-string test-source port-sha256))
+                   hash))
+        (x
+         (pk 'fail x #f))))))
+
+(test-end "composer")

base-commit: fafd3caef0d51811a5da81d6061789e2908b0dac
prerequisite-patch-id: eb618ab7b10483d917c308a38792af98baa517e2
prerequisite-patch-id: c12968d02d99c253f858586a86b16fa32d41f1c1
prerequisite-patch-id: 09d995d48139f8e61183d5634cda13a01cdb50f7
prerequisite-patch-id: 86baa45ec2aad977c8c8135f7613aa391155de6d
prerequisite-patch-id: 3425fbbff6a603d60b4e143ea2141aabf4ddc92c
prerequisite-patch-id: c373c01aab5dcba3503a97d51c62a595147a041c
prerequisite-patch-id: cda857c790b88c681c4e713c5f71e40291970daf
prerequisite-patch-id: 8e234d0f4d93d2aad499eec8842be3d28da98707
prerequisite-patch-id: 5f664cb2fd995a53765c5ffc19a708ac795cc0c4
prerequisite-patch-id: ed447cba9cf9b7e1a1b47aa27acb14f8f2da0a8e
prerequisite-patch-id: 9f80c5bbbfb8cd3347951c4d57634e93ffa79924
prerequisite-patch-id: 1aaa9f0d466e2d6837f75844df48a98beb70ff24
prerequisite-patch-id: 34502820d8c0355b3ed2638c457084edeaba029d
prerequisite-patch-id: a96258da9e78cfb9ac9893cdcdeb38b69b75f134
prerequisite-patch-id: 4a2da4ee89dbbdb2244845149ce6da967ddd5268
prerequisite-patch-id: 9f9c4205781d1f0e2bb7af2d21875de08ee3ecd5
prerequisite-patch-id: 9697db9b50cab8f7974c32383e0a9a786ecbd8f9
prerequisite-patch-id: ebbd089a3313232347273c723d3deb1bf8c9bf81
prerequisite-patch-id: e93360d66936b9efd70a6ffd41f6ecda177ad7b8
prerequisite-patch-id: 19d76f45db1c59bd9ccd2e4e1125ffd698e9d6ce
prerequisite-patch-id: 929b39ded7ad095e9f768f7d484bbd3b7a486a3c
prerequisite-patch-id: 5e1262f77d55c91eadca113223faa84935bffd60
prerequisite-patch-id: ad370d41983418fa704215aa3458f97c75d5d128
prerequisite-patch-id: f179c922613390d249a365625c2ee545a908029d
prerequisite-patch-id: 03b0aaa382ddda0819ddb62479cd1885c930ddea
prerequisite-patch-id: 83b8b3a072520705dcba4b67712a29553bea1548
prerequisite-patch-id: 9308fa06526d9bacdbcdd347cc225f6f3f87811a
prerequisite-patch-id: a017243a1a4b406caed9cec048d194cdc33d1a25
prerequisite-patch-id: e8d5b2e787904b0dd1a650d7a0012b91a430cb03
prerequisite-patch-id: 1cc872245864ace22db43cf2d268a87190b333b6
prerequisite-patch-id: c277dcca77f3acde51bdffe932b9250e454086ad
prerequisite-patch-id: ea926073e68d5af7f6c76a6333520cc5f42c9789
prerequisite-patch-id: 10008b9b34ccc8f87f2fcd8391075fe57244ac72
prerequisite-patch-id: 443d7e3eb85f36848c2120979f9f1d3a78f8bf38
prerequisite-patch-id: 6414c2d65c1806942d7f834e9300a8ecf8fd743f
prerequisite-patch-id: 8c6dec06b716c39ca7fada0f2872078612917779
prerequisite-patch-id: 62e28252e9b7ab11edb03609b68369feb499f883
prerequisite-patch-id: 84c9361c4c6d7662cfb3235cc4a6640a53e00622
prerequisite-patch-id: 0f27045bc50089a9a88da7818448a50cd28dd295
prerequisite-patch-id: 500413da3a81e75c5fbca62a21d9457d7b1ad8a8
prerequisite-patch-id: 6f48169f4d69da277bcdecb8f40d2f608941d9f9
prerequisite-patch-id: fc8b43573cc6b90033769de63ca235b16159190d
prerequisite-patch-id: ae749fc3fa0ab1768841ffb4633847b5b2233881
prerequisite-patch-id: 46b8490d2b338229a2f3c5e39427275cf46982ba
prerequisite-patch-id: b1bb7dfb35069a2b30f5b2714bc19a249be3e1b5
prerequisite-patch-id: 94848222eb08beb53530ba6ce626e9d8bcffecd4
prerequisite-patch-id: f8181365677e68d8628013c7636e9ff56214ac9e
prerequisite-patch-id: aebc0f8156c409599cc7aced4b708bb5ea08a2b2
prerequisite-patch-id: 4ce416249f6d3176a51d7e4cbbd2c6bf2982bab6
prerequisite-patch-id: 5e14463dcc090e497bb1d29c1b4c822b43d5fdca
prerequisite-patch-id: 89306b41386cb29db7c147e8c4468a3b4d8d292d
prerequisite-patch-id: 29e414b1ede9108047ff224e1e24a3adb2c44c52
prerequisite-patch-id: 7e15edfd04cd291f54284d13dcdbebcfb456b752
prerequisite-patch-id: b8c18091929e58b49847ab510d3d75a8a934cad0
prerequisite-patch-id: 7a607a1659b22afb0c21dec3d8eb1e2ed51e47a9
prerequisite-patch-id: 89fbd04f11e5bef5703ba7ea4c2064d5ba63c4d4
prerequisite-patch-id: b421048677352ea536dd93a61d6de987fb95d60b
prerequisite-patch-id: 25a03298bdfd6a691bb8cf68690009f8e46447e0
prerequisite-patch-id: 3924163576eafdac47ac06de311ac317730e6631
prerequisite-patch-id: 69b1d81677b507242f556c3e2fcf5290aeca445c
prerequisite-patch-id: a378fa79002001da51ae91eb026769eddb8a593b
prerequisite-patch-id: 86bb35c89ec3cc1b6ec47f238c84a154d5e9a1aa
prerequisite-patch-id: f8d0709d94ed99b1530bad1908ca27b1b56ea84e
prerequisite-patch-id: dcb65983aa914b8f1d1a8fbdfba34714ddb7f6fa
prerequisite-patch-id: 89752146a063d0706885819e244b4179196538b8
prerequisite-patch-id: 1f9e7627d0b23302159cdab3d939fcec52f7ca70
prerequisite-patch-id: f706bfa95ba0e5e72c206537ed207feb95daa888
prerequisite-patch-id: 9b60c519b0df65eeacd5779808e0d75b011ebf7f
prerequisite-patch-id: cd6cd74eca502ebce581c223cd0d2ac4278912e8
prerequisite-patch-id: b86e08404ef83877dfa3b76a80a12b02c61b1326
prerequisite-patch-id: 9417f8d92995cf417bb3c4afa0786b05a756d48a
prerequisite-patch-id: 59dda13243375b013396981a4f9e17abd694d734
prerequisite-patch-id: 89be058d0605cb8278d5d3384bb44911b188dd90
prerequisite-patch-id: 70c26fde2fde34c031a95ef74a3321710dc4961e
prerequisite-patch-id: 38a27cdf8cbe03fdf5f9bafa5ba53f3ba644a5ad
prerequisite-patch-id: 40a6d2e51dff2531c40a38087a8aea1be7108792
prerequisite-patch-id: 024d1bba9bcd449d2b8196b2f1a64a197cafaed8
prerequisite-patch-id: e83d54aa767ebab267530fca74d60366160a5253
prerequisite-patch-id: c34734661161c27224316dc519609db5c6d87a1e
prerequisite-patch-id: a58d739146fe46f6c7f203e5d2e0f114bd3f7834
prerequisite-patch-id: 1ff8499f5ec69b737d77053e6809ec3a0b599ebc
prerequisite-patch-id: 498e5608bca9b5ebcb3592a556e75f5dcc2b7076
prerequisite-patch-id: df6dfdea7c3d9db4649d857ce55fbeb99d4febca
prerequisite-patch-id: 453b66b1faaaebaa1666954185de327298aa0578
prerequisite-patch-id: f98da1de781c203a53cae73c5bb707240d21cb0a
prerequisite-patch-id: 14b1718dbc4fb9cd94e1094a4d44ebfcfe6ad869
prerequisite-patch-id: 3b68944fa8fb2fab0c21d6ff73f649f53dd6f551
prerequisite-patch-id: 82d1e6bcd221f982b6ab1ed0e9a90d46a39562c4
prerequisite-patch-id: c9cce20b146f955b715d15c0c384c9acc6176493
prerequisite-patch-id: c204491c1db4f5056711768265f101e881e4e415
prerequisite-patch-id: e66e13fbde027e99552fc6d80ff8d48c110a18f2
prerequisite-patch-id: 3c313f0a20730c653c8f5ec4f318e2485a8ef60f
prerequisite-patch-id: 925c466172c01c4b5976ac019961cbe240f0cddd
prerequisite-patch-id: e81e0aded80adf18c861f67624a179a15ef68906
prerequisite-patch-id: 001675f7da57d25731c7c71f6f2dcaa7409e5664
prerequisite-patch-id: d65bf6ef5f51da0acba72d332d60167b34e193e1
prerequisite-patch-id: fc7c9a5024037363319b58520480a6c4a8a5dcff
prerequisite-patch-id: 5aae8c77d028459d944021f4943558411deb0662
prerequisite-patch-id: 71fa80813ad36528e8a737249424d90827933c16
prerequisite-patch-id: 65dc75b8e1ddb45542480a8867ecd7a63ab3112e
prerequisite-patch-id: 8619aa1dec17409d9b5ecb6ed0a2cc7d1563c174
prerequisite-patch-id: 6473142746dc5b448ec9698d577f47b4da6cd1d5
prerequisite-patch-id: eb6689695d5d1b6c650de0c86a805a45b80ab88d
prerequisite-patch-id: 7d50679dad38c9f859ec231da2db78919818b40e
prerequisite-patch-id: faeb97c5f9c07754bd0bf0be59254091470978c2
prerequisite-patch-id: 56e31c3ab9ed9ff19aca25d5ffb9655c6515b692
prerequisite-patch-id: 8d7418e017eec3c6e56b55f9ff6181cc3dcc1a17
prerequisite-patch-id: 84f58e5a274c980ae6905e764d479e1c960149ca
prerequisite-patch-id: ada6a2d9427bff9dd7fd115a91300a1f7379995c
prerequisite-patch-id: 108161d5500b39b3ac55d202b5b9af817d829724
prerequisite-patch-id: c89b0fc7dadc53facc45ccf9991503430b7e7799
prerequisite-patch-id: d62e2be8f9fd6a1d9ac8dfa2cdc4db6d4a4327ac
prerequisite-patch-id: f8f4375b2b16ffae596d416607c00b374f485299
prerequisite-patch-id: 36b1a9c3e0e9f91b7172e1211231759a6cb81473
prerequisite-patch-id: 8cb6ac6a5188c817bb3a6a86920001de75bb7225
prerequisite-patch-id: 17ef87336a8c664e0109a7466c9f7d37f5901167
-- 
2.41.0





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

* [bug#42338] [PATCH v3 2/7] gnu: Add composer-classloader.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
@ 2023-09-26 10:31   ` Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 3/7] guix: Add composer-build-system Nicolas Graves via Guix-patches via
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* gnu/packages/php-xyz.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk             |  1 +
 gnu/packages/php-xyz.scm | 61 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 gnu/packages/php-xyz.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index bfa816d717..8cd0e0537b 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -501,6 +501,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/photo.scm			\
   %D%/packages/phabricator.scm 			\
   %D%/packages/php.scm				\
+  %D%/packages/php-xyz.scm			\
   %D%/packages/piet.scm			\
   %D%/packages/pikchr.scm			\
   %D%/packages/pkg-config.scm			\
diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
new file mode 100644
index 0000000000..dab660f84f
--- /dev/null
+++ b/gnu/packages/php-xyz.scm
@@ -0,0 +1,61 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (gnu packages php-xyz)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages php)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system composer)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix utils)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public composer-classloader
+  (package
+    (name "composer-classloader")
+    (version "1.9.0")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                     (url "https://github.com/composer/composer.git")
+                     (commit version)))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0127zmmg3yx84ljngfs86q7kjhyypybkf4d1ihfrfnzgynzxfxdf"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (delete 'build)
+         (delete 'check)
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out"))
+                    (install (string-append out "/share/web/composer/ClassLoader.php")))
+               (mkdir-p (dirname install))
+               (copy-file "src/Composer/Autoload/ClassLoader.php" install)))))))
+    (home-page "https://getcomposer.org")
+    (synopsis "PHP class loader extracted from the composer package")
+    (description "This package contains the class loader class used by Composer to
+build its autoloading feature.  This package is used by the composer-build-system
+to build its own store-aware autoloading feature.")
+    (license license:expat)))
-- 
2.41.0





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

* [bug#42338] [PATCH v3 3/7] guix: Add composer-build-system.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 2/7] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
@ 2023-09-26 10:31   ` Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 4/7] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* gnu/packages/aux-files/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   3 +
 doc/guix.texi                        |  14 ++
 gnu/packages/aux-files/findclass.php | 125 ++++++++++++++
 guix/build-system/composer.scm       | 162 ++++++++++++++++++
 guix/build/composer-build-system.scm | 239 +++++++++++++++++++++++++++
 5 files changed, 543 insertions(+)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index 3ce7ee832e..903fc42afa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -149,6 +149,7 @@ MODULES =					\
   guix/build-system/chicken.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/elm.scm			\
@@ -206,6 +207,7 @@ MODULES =					\
   guix/build/cargo-utils.scm			\
   guix/build/chicken-build-system.scm		\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/elm-build-system.scm		\
@@ -411,6 +413,7 @@ dist_noinst_DATA =				\
 AUX_FILES =						\
   gnu/packages/aux-files/chromium/master-preferences.json		\
   gnu/packages/aux-files/emacs/guix-emacs.el		\
+  gnu/packages/aux-files/findclass.php			\
   gnu/packages/aux-files/guix.vim			\
   gnu/packages/aux-files/linux-libre/6.4-arm.conf	\
   gnu/packages/aux-files/linux-libre/6.4-arm64.conf	\
diff --git a/doc/guix.texi b/doc/guix.texi
index 4d2fc11cd7..d133e43773 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9545,6 +9545,20 @@ Build Systems
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvar
 
+@defvar {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvar
+
 @defvar dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
diff --git a/gnu/packages/aux-files/findclass.php b/gnu/packages/aux-files/findclass.php
new file mode 100644
index 0000000000..d0b250c8e1
--- /dev/null
+++ b/gnu/packages/aux-files/findclass.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * The content of this file is copied from composer's src/Composer/Autoload/ClassMapGenerator.php
+ * the findClasses method was extracted, to prevent using any dependency.
+ *
+ * Composer (and thus this file) is distributed under the expat license, and
+ * ClassMapGenerator.php also contains this notice:
+ *
+ *   This file is part of Composer.
+ *
+ *   (c) Nils Adermann <naderman@naderman.de>
+ *       Jordi Boggiano <j.boggiano@seld.be>
+ *
+ *   For the full copyright and license information, please view the LICENSE
+ *   file that was distributed with this source code.
+ *
+ *   This file is copied from the Symfony package.
+ *
+ *   (c) Fabien Potencier <fabien@symfony.com>
+ * 
+ * To the extent to wich it makes sense, as the author of the extract:
+ * Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+ */
+
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..8bf99ff9c5
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,162 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build union)
+    (json)
+    (json builder)
+    (json parser)
+    (json record)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build name inputs
+                         #:key
+                         guile source
+                         (outputs '("out"))
+                         (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags #~'("--strip-debug"))
+                         (strip-directories #~'("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build utils))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@(sexp->gexp modules))
+
+          #$(with-build-variables inputs outputs
+              #~(composer-build
+                 #:source #$source
+                 #:system #$system
+                 #:outputs %outputs
+                 #:inputs %build-inputs
+                 #:search-paths '#$(map search-path-specification->sexp
+                                        search-paths)
+                 #:phases #$phases
+                 #:out-of-source? #$out-of-source?
+                 #:composer-file #$composer-file
+                 #:tests? #$tests?
+                 #:test-target #$test-target
+                 #:install-target #$install-target
+                 #:validate-runpath? #$validate-runpath?
+                 #:patch-shebangs? #$patch-shebangs?
+                 #:strip-binaries? #$strip-binaries?
+                 #:strip-flags #$strip-flags
+                 #:strip-directories #$strip-directories)))))
+
+  (gexp->derivation name builder
+                    #:system system
+                    #:target #f
+                    #:graft? #f
+                    #:guile-for-build guile))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..7df2b7c400
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,239 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (srfi srfi-26)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-autoload> make-composer-autoload composer-autoload?
+  json->composer-autoload
+  (psr-4 composer-autoload-psr-4 "psr-4"
+                (match-lambda
+                  (#f '())
+                  (psr-4 psr-4)))
+  (classmap composer-autoload-classmap "classmap"
+            (match-lambda
+              (#f '())
+              (#(lst ...) lst))))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (name         composer-package-name)
+  (autoload     composer-package-autoload "autoload" json->composer-autoload)
+  (autoload-dev composer-package-autoload-dev "autoload-dev" json->composer-autoload)
+  (require      composer-package-require "require" json->require)
+  (dev-require  composer-package-dev-require "require-dev" json->require)
+  (scripts      composer-package-scripts "scripts"
+                (match-lambda
+                  (#f '())
+                  ((scripts ...) scripts)))
+  (binaries     composer-package-binaries "bin"
+                (match-lambda
+                  (#f '())
+                  (#(lst ...) lst))))
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (json->composer-package (json->scm port)))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Test the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (composer-package-scripts package-data))
+           (test-script (assoc-ref scripts test-target))
+           (dependencies (composer-package-require package-data))
+           (dependencies-dev (composer-package-dev-require package-data))
+           (name (composer-package-name package-data)))
+      (for-each
+        (match-lambda
+          ((_ . input)
+           (let ((bin (find-php-bin input)))
+             (when bin
+               (copy-recursively bin "vendor/bin")))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (zero? (system command))
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (zero? (system c))
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit"))))))
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs inputs))
+    (match inputs
+      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
+                 dependency))
+      (((_ . input) inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  "creates an autoload.php file that sets up the class locations for this package,
+so it can be autoloaded by PHP when the package classes are required."
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (display (string-append
+                 "<?php
+// autoload.php @generated by Guix
+$map = $psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php'
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($map as $namespace => $path) {
+  $loader->set($namespace, $path);
+}
+foreach ($psr4map as $namespace => $path) {
+  $loader->setPsr4($namespace, $path);
+}
+$loader->addClassMap($classmap);
+$loader->register();
+"))))
+  ;; Now, create autoload_conf.php that contains the actual data, as a set
+  ;; of arrays
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload (composer-package-autoload package-data))
+         (autoload-dev (composer-package-autoload-dev package-data))
+         (dependencies (composer-package-require package-data))
+         (dependencies-dev (composer-package-dev-require package-data)))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (composer-autoload-psr-4 autoload)
+            (if dev-dependencies?
+                (composer-autoload-psr-4 autoload-dev)
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (composer-autoload-classmap autoload)
+            (if dev-dependencies?
+                (composer-autoload-classmap autoload-dev)
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (composer-package-name package-data))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (composer-package-binaries package-data)))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs)))
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
-- 
2.41.0





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

* [bug#42338] [PATCH v3 4/7] guix: import: composer: Use memoization.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 2/7] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 3/7] guix: Add composer-build-system Nicolas Graves via Guix-patches via
@ 2023-09-26 10:31   ` Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 5/7] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

---
 guix/import/composer.scm | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index c152f402bb..177dc63092 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -27,6 +27,7 @@ (define-module (guix import composer)
   #:use-module (guix import json)
   #:use-module (guix import utils)
   #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix memoization)
   #:use-module (guix packages)
   #:use-module (guix serialization)
   #:use-module (guix upstream)
@@ -197,16 +198,18 @@ (define (make-php-sexp composer-package)
                            ((license) license)
                            (_ license)))))))))
 
-(define* (composer->guix-package package-name #:optional version)
-  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+(define composer->guix-package
+  (memoize
+   (lambda* (package-name #:key version #:allow-other-keys)
+     "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
 `package' s-expression corresponding to that package, or #f on failure."
-  (let ((package (composer-fetch package-name version)))
-    (and package
-         (let* ((package (json->composer-package package))
-                (dependencies-names (composer-package-require package))
-                (dev-dependencies-names (composer-package-dev-require package)))
-           (values (make-php-sexp package)
-                   (append dependencies-names dev-dependencies-names))))))
+     (let ((package (composer-fetch package-name version)))
+       (and package
+            (let* ((package (json->composer-package package))
+                   (dependencies-names (composer-package-require package))
+                   (dev-dependencies-names (composer-package-dev-require package)))
+              (values (make-php-sexp package)
+                      (append dependencies-names dev-dependencies-names))))))))
 
 (define (guix-name->composer-name name)
   "Given a guix package name, return the name of the package in Packagist."
@@ -265,6 +268,7 @@ (define %composer-updater
    (import latest-release)))
 
 (define* (composer-recursive-import package-name #:optional version)
-  (recursive-import package-name '()
+  (recursive-import package-name
+                    #:version version
                     #:repo->guix-package composer->guix-package
                     #:guix-name php-package-name))
-- 
2.41.0





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

* [bug#42338] [PATCH v3 5/7] guix: import: composer: Fix json->require.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (2 preceding siblings ...)
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 4/7] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
@ 2023-09-26 10:31   ` Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 6/7] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

---
 guix/import/composer.scm | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 177dc63092..3acbbecf82 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -88,7 +88,8 @@ (define (json->require dict)
           ((((? (cut string-contains <> "/") name) . _)
              require ...)
            (loop (cons name result) require))
-          ((_ require ...) (loop result require))))
+          ((_ require ...) (loop result require))
+          (_ result)))
       '()))
 
 (define-json-mapping <composer-source> make-composer-source composer-source?
-- 
2.41.0





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

* [bug#42338] [PATCH v3 6/7] guix: import: composer: More robust string->license.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (3 preceding siblings ...)
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 5/7] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
@ 2023-09-26 10:31   ` Nicolas Graves via Guix-patches via
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 7/7] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm (string->license): Use spdx-string->license. Fall
back to unknown-license!.
---
 guix/import/composer.scm | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 3acbbecf82..2ce7206ef9 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -194,10 +194,8 @@ (define (make-php-sexp composer-package)
                (synopsis "")
                (description ,(composer-package-description composer-package))
                (home-page ,(composer-package-homepage composer-package))
-               (license ,(match (composer-package-license composer-package)
-                           (() #f)
-                           ((license) license)
-                           (_ license)))))))))
+               (license ,(or (composer-package-license composer-package)
+                             'unknown-license!))))))))
 
 (define composer->guix-package
   (memoize
@@ -234,14 +232,15 @@ (define (guix-package->composer-name package)
 
 (define (string->license str)
   "Convert the string STR into a license object."
-  (match str
-    ("GNU LGPL" 'license:lgpl2.0)
-    ("GPL" 'license:gpl3)
-    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
-    ((or "MIT" "MIT license" "Expat license") 'license:expat)
-    ("Public domain" 'license:public-domain)
-    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
-    (_ #f)))
+  (or (spdx-string->license str)
+      (match str
+        ("GNU LGPL" 'license:lgpl2.0)
+        ("GPL" 'license:gpl3)
+        ((or "BSD" "BSD License") 'license:bsd-3)
+        ((or "MIT" "MIT license" "Expat license") 'license:expat)
+        ("Public domain" 'license:public-domain)
+        ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+        (_ 'unknown-license!))))
 
 (define (php-package? package)
   "Return true if PACKAGE is a PHP package from Packagist."
-- 
2.41.0





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

* [bug#42338] [PATCH v3 7/7] guix: import: composer: Modern inputs formatting.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (4 preceding siblings ...)
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 6/7] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
@ 2023-09-26 10:31   ` Nicolas Graves via Guix-patches via
  2023-09-26 10:43   ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
  2023-10-14 15:48   ` Ludovic Courtès
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:31 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm (make-php-sexp): Update inputs formatting.
---
 guix/import/composer.scm | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 2ce7206ef9..b4710c6fb9 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -176,21 +176,11 @@ (define (make-php-sexp composer-package)
                ,@(if (null? dependencies)
                      '()
                      `((inputs
-                        (,'quasiquote
-                         ,(map (lambda (name)
-                                 `(,name
-                                   (,'unquote
-                                    ,(string->symbol name))))
-                               dependencies)))))
+                        (list ,(map string->symbol dependencies)))))
                ,@(if (null? dev-dependencies)
                      '()
                      `((native-inputs
-                        (,'quasiquote
-                         ,(map (lambda (name)
-                                 `(,name
-                                   (,'unquote
-                                    ,(string->symbol name))))
-                               dev-dependencies)))))
+                        (list ,(map string->symbol dev-dependencies)))))
                (synopsis "")
                (description ,(composer-package-description composer-package))
                (home-page ,(composer-package-homepage composer-package))
-- 
2.41.0





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

* [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (5 preceding siblings ...)
  2023-09-26 10:31   ` [bug#42338] [PATCH v3 7/7] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
@ 2023-09-26 10:43   ` Nicolas Graves via Guix-patches via
  2023-10-14 15:48   ` Ludovic Courtès
  7 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 10:43 UTC (permalink / raw)
  To: 42338; +Cc: adam.faiz5990, Ludovic Courtès, julien


I've just added some modernizations and fixes ontop of the :
- first patch which is the latest provided in the discussion between
Ludo' and Julien, with minimal fixes.
- second and third patch which are the versions from Adam Faiz.

The recursive import should work with these patches but often fails,
probably because it loops and we eventually get a gnu-tls error probably
from when github refuses to serve, because it doesn't stop on a specific
package. This probably will stop looping so much one phpunit is added,
with the later patches from Julien adding phpunit. In any case, it's
definitely a more robust recursive import, and the error Adam
experienced has been solved in the fifth patch. The sixth patch also
avoids some licensing-related failures.

On 2023-09-26 12:31, Nicolas Graves wrote:

> * guix/import/composer.scm: New file.
> * guix/scripts/import/composer.scm: New file.
> * guix/tests/composer.scm: New file.
> * Makefile.am: Add them.
> * guix/scripts/import.scm: Add composer importer.
> * doc/guix.texi (Invoking guix import): Mention it.
> ---
>  Makefile.am                      |   3 +
>  doc/guix.texi                    |  20 +++
>  guix/import/composer.scm         | 270 +++++++++++++++++++++++++++++++
>  guix/scripts/import.scm          |   2 +-
>  guix/scripts/import/composer.scm | 107 ++++++++++++
>  tests/composer.scm               |  92 +++++++++++
>  6 files changed, 493 insertions(+), 1 deletion(-)
>  create mode 100644 guix/import/composer.scm
>  create mode 100644 guix/scripts/import/composer.scm
>  create mode 100644 tests/composer.scm
>
> diff --git a/Makefile.am b/Makefile.am
> index 8924974e8a..3ce7ee832e 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -274,6 +274,7 @@ MODULES =					\
>    guix/search-paths.scm				\
>    guix/packages.scm				\
>    guix/import/cabal.scm				\
> +  guix/import/composer.scm			\
>    guix/import/cpan.scm				\
>    guix/import/cran.scm				\
>    guix/import/crate.scm				\
> @@ -332,6 +333,7 @@ MODULES =					\
>    guix/scripts/home/import.scm			\
>    guix/scripts/lint.scm				\
>    guix/scripts/challenge.scm			\
> +  guix/scripts/import/composer.scm		\
>    guix/scripts/import/crate.scm			\
>    guix/scripts/import/cpan.scm			\
>    guix/scripts/import/cran.scm			\
> @@ -500,6 +502,7 @@ SCM_TESTS =					\
>    tests/challenge.scm				\
>    tests/channels.scm				\
>    tests/combinators.scm			\
> +  tests/composer.scm				\
>    tests/containers.scm				\
>    tests/cpan.scm				\
>    tests/cpio.scm				\
> diff --git a/doc/guix.texi b/doc/guix.texi
> index 46591b2f64..4d2fc11cd7 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -14530,6 +14530,26 @@ Invoking guix import
>
>  Additional options include:
>
> +@table @code
> +@item --recursive
> +@itemx -r
> +Traverse the dependency graph of the given upstream package recursively
> +and generate package expressions for all those packages that are not yet
> +in Guix.
> +@end table
> +
> +@item composer
> +@cindex Composer
> +@cindex PHP
> +Import metadat from the @uref{https://getcomposer.org/, Composer} package
> +archive used by the PHP community, as in this example:
> +
> +@example
> +guix import composer phpunit/phpunit
> +@end example
> +
> +Additional options include:
> +
>  @table @code
>  @item --recursive
>  @itemx -r
> diff --git a/guix/import/composer.scm b/guix/import/composer.scm
> new file mode 100644
> index 0000000000..c152f402bb
> --- /dev/null
> +++ b/guix/import/composer.scm
> @@ -0,0 +1,270 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
> +;;;
> +;;; 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 composer)
> +  #:use-module (ice-9 match)
> +  #:use-module (json)
> +  #:use-module (gcrypt hash)
> +  #:use-module (guix base32)
> +  #:use-module (guix build git)
> +  #:use-module (guix build utils)
> +  #:use-module (guix build-system)
> +  #:use-module (guix import json)
> +  #:use-module (guix import utils)
> +  #:use-module ((guix licenses) #:prefix license:)
> +  #:use-module (guix packages)
> +  #:use-module (guix serialization)
> +  #:use-module (guix upstream)
> +  #:use-module (guix utils)
> +  #:use-module (srfi srfi-1)
> +  #:use-module (srfi srfi-11)
> +  #:use-module (srfi srfi-26)
> +  #:export (composer->guix-package
> +            %composer-updater
> +            composer-recursive-import
> +
> +            %composer-base-url))
> +
> +(define %composer-base-url
> +  (make-parameter "https://repo.packagist.org"))
> +
> +;; XXX adapted from (guix scripts hash)
> +(define (file-hash file select? recursive?)
> +  ;; Compute the hash of FILE.
> +  (if recursive?
> +      (let-values (((port get-hash) (open-sha256-port)))
> +        (write-file file port #:select? select?)
> +        (force-output port)
> +        (get-hash))
> +      (call-with-input-file file port-sha256)))
> +
> +;; XXX taken from (guix scripts hash)
> +(define (vcs-file? file stat)
> +  (case (stat:type stat)
> +    ((directory)
> +     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
> +    ((regular)
> +     ;; Git sub-modules have a '.git' file that is a regular text file.
> +     (string=? (basename file) ".git"))
> +    (else
> +     #f)))
> +
> +(define (fix-version version)
> +  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
> +  (cond
> +    ((string-prefix? "version" version)
> +     (if (char-set-contains? char-set:digit (string-ref version 7))
> +         (substring version 7)
> +         (substring version 8)))
> +    ((string-prefix? "v" version)
> +     (substring version 1))
> +    (else version)))
> +
> +(define (latest-version versions)
> +  (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b))
> +        (car versions) versions))
> +
> +(define (json->require dict)
> +  (if dict
> +      (let loop ((result '()) (require dict))
> +        (match require
> +          (() result)
> +          ((((? (cut string-contains <> "/") name) . _)
> +             require ...)
> +           (loop (cons name result) require))
> +          ((_ require ...) (loop result require))))
> +      '()))
> +
> +(define-json-mapping <composer-source> make-composer-source composer-source?
> +  json->composer-source
> +  (type      composer-source-type)
> +  (url       composer-source-url)
> +  (reference composer-source-reference))
> +
> +(define-json-mapping <composer-package> make-composer-package composer-package?
> +  json->composer-package
> +  (description composer-package-description)
> +  (homepage    composer-package-homepage)
> +  (source      composer-package-source "source" json->composer-source)
> +  (name        composer-package-name "name" php-package-name)
> +  (version     composer-package-version "version" fix-version)
> +  (require     composer-package-require "require" json->require)
> +  (dev-require composer-package-dev-require "require-dev" json->require)
> +  (license     composer-package-license "license"
> +               (lambda (vector)
> +                 (map string->license (vector->list vector)))))
> +
> +(define* (composer-fetch name #:optional version)
> +  "Return an alist representation of the Composer metadata for the package NAME,
> +or #f on failure."
> +  (let ((package (json-fetch
> +                   (string-append (%composer-base-url) "/p/" name ".json"))))
> +    (if package
> +        (let* ((packages (assoc-ref package "packages"))
> +               (package (or (assoc-ref packages name) package))
> +               (versions (filter
> +                           (lambda (version)
> +                             (and (not (string-contains version "dev"))
> +                                  (not (string-contains version "beta"))))
> +                           (map car package)))
> +               (version (or (if (null? version) #f version)
> +                            (latest-version versions))))
> +          (assoc-ref package version))
> +        #f)))
> +
> +(define (php-package-name name)
> +  "Given the NAME of a package on Packagist, return a Guix-compliant name for
> +the package."
> +  (let ((name (string-join (string-split name #\/) "-")))
> +    (if (string-prefix? "php-" name)
> +        (snake-case name)
> +        (string-append "php-" (snake-case name)))))
> +
> +(define (make-php-sexp composer-package)
> +  "Return the `package' s-expression for a PHP package for the given
> +COMPOSER-PACKAGE."
> +  (let* ((source (composer-package-source composer-package))
> +         (dependencies (map php-package-name
> +                            (composer-package-require composer-package)))
> +         (dev-dependencies (map php-package-name
> +                                (composer-package-dev-require composer-package)))
> +         (git? (equal? (composer-source-type source) "git")))
> +    ((if git? call-with-temporary-directory call-with-temporary-output-file)
> +     (lambda* (temp #:optional port)
> +       (and (if git?
> +                (begin
> +                  (mkdir-p temp)
> +                  (git-fetch (composer-source-url source)
> +                             (composer-source-reference source)
> +                             temp))
> +                (url-fetch (composer-source-url source) temp))
> +            `(package
> +               (name ,(composer-package-name composer-package))
> +               (version ,(composer-package-version composer-package))
> +               (source (origin
> +                         ,@(if git?
> +                               `((method git-fetch)
> +                                 (uri (git-reference
> +                                        (url ,(composer-source-url source))
> +                                        (commit ,(composer-source-reference source))))
> +                                 (file-name (git-file-name name version))
> +                                 (sha256
> +                                   (base32
> +                                     ,(bytevector->nix-base32-string
> +                                       (file-hash temp (negate vcs-file?) #t)))))
> +                               `((method url-fetch)
> +                                 (uri ,(composer-source-url source))
> +                                 (sha256 (base32 ,(guix-hash-url temp)))))))
> +               (build-system composer-build-system)
> +               ,@(if (null? dependencies)
> +                     '()
> +                     `((inputs
> +                        (,'quasiquote
> +                         ,(map (lambda (name)
> +                                 `(,name
> +                                   (,'unquote
> +                                    ,(string->symbol name))))
> +                               dependencies)))))
> +               ,@(if (null? dev-dependencies)
> +                     '()
> +                     `((native-inputs
> +                        (,'quasiquote
> +                         ,(map (lambda (name)
> +                                 `(,name
> +                                   (,'unquote
> +                                    ,(string->symbol name))))
> +                               dev-dependencies)))))
> +               (synopsis "")
> +               (description ,(composer-package-description composer-package))
> +               (home-page ,(composer-package-homepage composer-package))
> +               (license ,(match (composer-package-license composer-package)
> +                           (() #f)
> +                           ((license) license)
> +                           (_ license)))))))))
> +
> +(define* (composer->guix-package package-name #:optional version)
> +  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
> +`package' s-expression corresponding to that package, or #f on failure."
> +  (let ((package (composer-fetch package-name version)))
> +    (and package
> +         (let* ((package (json->composer-package package))
> +                (dependencies-names (composer-package-require package))
> +                (dev-dependencies-names (composer-package-dev-require package)))
> +           (values (make-php-sexp package)
> +                   (append dependencies-names dev-dependencies-names))))))
> +
> +(define (guix-name->composer-name name)
> +  "Given a guix package name, return the name of the package in Packagist."
> +  (if (string-prefix? "php-" name)
> +      (let ((components (string-split (substring name 4) #\-)))
> +        (match components
> +          ((namespace name ...)
> +           (string-append namespace "/" (string-join name "-")))))
> +      name))
> +
> +(define (guix-package->composer-name package)
> +  "Given a Composer PACKAGE built from Packagist, return the name of the
> +package in Packagist."
> +  (let ((upstream-name (assoc-ref
> +                         (package-properties package)
> +                         'upstream-name))
> +        (name (package-name package)))
> +    (if upstream-name
> +      upstream-name
> +      (guix-name->composer-name name))))
> +
> +(define (string->license str)
> +  "Convert the string STR into a license object."
> +  (match str
> +    ("GNU LGPL" 'license:lgpl2.0)
> +    ("GPL" 'license:gpl3)
> +    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
> +    ((or "MIT" "MIT license" "Expat license") 'license:expat)
> +    ("Public domain" 'license:public-domain)
> +    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
> +    (_ #f)))
> +
> +(define (php-package? package)
> +  "Return true if PACKAGE is a PHP package from Packagist."
> +  (and
> +    (eq? (build-system-name (package-build-system package)) 'composer)
> +    (string-prefix? "php-" (package-name package))))
> +
> +(define (latest-release package)
> +  "Return an <upstream-source> for the latest release of PACKAGE."
> +  (let* ((php-name (guix-package->composer-name package))
> +         (metadata (composer-fetch php-name))
> +         (package (json->composer-package metadata))
> +         (version (composer-package-version package))
> +         (url (composer-source-url (composer-package-source package))))
> +    (upstream-source
> +     (package (package-name package))
> +     (version version)
> +     (urls (list url)))))
> +
> +(define %composer-updater
> +  (upstream-updater
> +   (name 'composer)
> +   (description "Updater for Composer packages")
> +   (pred php-package?)
> +   (import latest-release)))
> +
> +(define* (composer-recursive-import package-name #:optional version)
> +  (recursive-import package-name '()
> +                    #:repo->guix-package composer->guix-package
> +                    #:guix-name php-package-name))
> diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
> index 4ddd8d46a1..8c58dd35e2 100644
> --- a/guix/scripts/import.scm
> +++ b/guix/scripts/import.scm
> @@ -47,7 +47,7 @@ (define %standard-import-options '())
>
>  (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
>                      "gem" "go" "cran" "crate" "texlive" "json" "opam"
> -                    "minetest" "elm" "hexpm"))
> +                    "minetest" "elm" "hexpm" "composer"))
>
>  (define (resolve-importer name)
>    (let ((module (resolve-interface
> diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
> new file mode 100644
> index 0000000000..412bae6318
> --- /dev/null
> +++ b/guix/scripts/import/composer.scm
> @@ -0,0 +1,107 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2015 David Thompson <davet@gnu.org>
> +;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
> +;;;
> +;;; 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 composer)
> +  #:use-module (guix ui)
> +  #:use-module (guix utils)
> +  #:use-module (guix scripts)
> +  #:use-module (guix import composer)
> +  #:use-module (guix scripts import)
> +  #:use-module (srfi srfi-1)
> +  #:use-module (srfi srfi-11)
> +  #:use-module (srfi srfi-37)
> +  #:use-module (srfi srfi-41)
> +  #:use-module (ice-9 match)
> +  #:use-module (ice-9 format)
> +  #:export (guix-import-composer))
> +
> +\f
> +;;;
> +;;; Command-line options.
> +;;;
> +
> +(define %default-options
> +  '())
> +
> +(define (show-help)
> +  (display (G_ "Usage: guix import composer PACKAGE-NAME
> +Import and convert the Composer package for PACKAGE-NAME.\n"))
> +  (display (G_ "
> +  -h, --help             display this help and exit"))
> +  (display (G_ "
> +  -V, --version          display version information and exit"))
> +  (display (G_ "
> +  -r, --recursive        generate package expressions for all Composer packages\
> + that are not yet in Guix"))
> +  (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 composer")))
> +         (option '(#\r "recursive") #f #f
> +                 (lambda (opt name arg result)
> +                   (alist-cons 'recursive #t result)))
> +         %standard-import-options))
> +
> +\f
> +;;;
> +;;; Entry point.
> +;;;
> +
> +(define (guix-import-composer . args)
> +  (define (parse-options)
> +    ;; Return the alist of option values.
> +    (args-fold* args %options
> +                (lambda (opt name arg result)
> +                  (leave (G_ "~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)
> +       (if (assoc-ref opts 'recursive)
> +           (map (match-lambda
> +                  ((and ('package ('name name) . rest) pkg)
> +                   `(define-public ,(string->symbol name)
> +                      ,pkg))
> +                  (_ #f))
> +                (composer-recursive-import package-name))
> +           (let ((sexp (composer->guix-package package-name)))
> +             (unless sexp
> +               (leave (G_ "failed to download meta-data for package '~a'~%")
> +                      package-name))
> +             sexp)))
> +      (()
> +       (leave (G_ "too few arguments~%")))
> +      ((many ...)
> +       (leave (G_ "too many arguments~%"))))))
> diff --git a/tests/composer.scm b/tests/composer.scm
> new file mode 100644
> index 0000000000..cefaf9f434
> --- /dev/null
> +++ b/tests/composer.scm
> @@ -0,0 +1,92 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
> +;;;
> +;;; 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 (test-composer)
> +  #:use-module (guix import composer)
> +  #:use-module (guix base32)
> +  #:use-module (gcrypt hash)
> +  #:use-module (guix tests http)
> +  #:use-module (guix grafts)
> +  #:use-module (srfi srfi-64)
> +  #:use-module (web client)
> +  #:use-module (ice-9 match))
> +
> +;; Globally disable grafts because they can trigger early builds.
> +(%graft? #f)
> +
> +(define test-json
> +  "{
> +  \"packages\": {
> +    \"foo/bar\": {
> +      \"0.1\": {
> +        \"name\": \"foo/bar\",
> +        \"description\": \"description\",
> +        \"keywords\": [\"testing\"],
> +        \"homepage\": \"http://example.com\",
> +        \"version\": \"0.1\",
> +        \"license\": [\"BSD-3-Clause\"],
> +        \"source\": {
> +          \"type\": \"url\",
> +          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
> +        },
> +        \"require\": {},
> +        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
> +      }
> +    }
> +  }
> +}")
> +
> +(define test-source
> +  "foobar")
> +
> +;; Avoid collisions with other tests.
> +(%http-server-port 10450)
> +
> +(test-begin "composer")
> +
> +(test-assert "composer->guix-package"
> +  ;; Replace network resources with sample data.
> +  (with-http-server `((200 ,test-json)
> +                      (200 ,test-source))
> +    (parameterize ((%composer-base-url (%local-url))
> +                   (current-http-proxy (%local-url)))
> +      (match (composer->guix-package "foo/bar")
> +        (('package
> +           ('name "php-foo-bar")
> +           ('version "0.1")
> +           ('source ('origin
> +                      ('method 'url-fetch)
> +                      ('uri "http://example.com/Bar-0.1.tar.gz")
> +                      ('sha256
> +                       ('base32
> +                        (? string? hash)))))
> +           ('build-system 'composer-build-system)
> +           ('native-inputs
> +            ('quasiquote
> +             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
> +           ('synopsis "")
> +           ('description "description")
> +           ('home-page "http://example.com")
> +           ('license 'license:bsd-3))
> +         (string=? (bytevector->nix-base32-string
> +                    (call-with-input-string test-source port-sha256))
> +                   hash))
> +        (x
> +         (pk 'fail x #f))))))
> +
> +(test-end "composer")
>
> base-commit: fafd3caef0d51811a5da81d6061789e2908b0dac
> prerequisite-patch-id: eb618ab7b10483d917c308a38792af98baa517e2
> prerequisite-patch-id: c12968d02d99c253f858586a86b16fa32d41f1c1
> prerequisite-patch-id: 09d995d48139f8e61183d5634cda13a01cdb50f7
> prerequisite-patch-id: 86baa45ec2aad977c8c8135f7613aa391155de6d
> prerequisite-patch-id: 3425fbbff6a603d60b4e143ea2141aabf4ddc92c
> prerequisite-patch-id: c373c01aab5dcba3503a97d51c62a595147a041c
> prerequisite-patch-id: cda857c790b88c681c4e713c5f71e40291970daf
> prerequisite-patch-id: 8e234d0f4d93d2aad499eec8842be3d28da98707
> prerequisite-patch-id: 5f664cb2fd995a53765c5ffc19a708ac795cc0c4
> prerequisite-patch-id: ed447cba9cf9b7e1a1b47aa27acb14f8f2da0a8e
> prerequisite-patch-id: 9f80c5bbbfb8cd3347951c4d57634e93ffa79924
> prerequisite-patch-id: 1aaa9f0d466e2d6837f75844df48a98beb70ff24
> prerequisite-patch-id: 34502820d8c0355b3ed2638c457084edeaba029d
> prerequisite-patch-id: a96258da9e78cfb9ac9893cdcdeb38b69b75f134
> prerequisite-patch-id: 4a2da4ee89dbbdb2244845149ce6da967ddd5268
> prerequisite-patch-id: 9f9c4205781d1f0e2bb7af2d21875de08ee3ecd5
> prerequisite-patch-id: 9697db9b50cab8f7974c32383e0a9a786ecbd8f9
> prerequisite-patch-id: ebbd089a3313232347273c723d3deb1bf8c9bf81
> prerequisite-patch-id: e93360d66936b9efd70a6ffd41f6ecda177ad7b8
> prerequisite-patch-id: 19d76f45db1c59bd9ccd2e4e1125ffd698e9d6ce
> prerequisite-patch-id: 929b39ded7ad095e9f768f7d484bbd3b7a486a3c
> prerequisite-patch-id: 5e1262f77d55c91eadca113223faa84935bffd60
> prerequisite-patch-id: ad370d41983418fa704215aa3458f97c75d5d128
> prerequisite-patch-id: f179c922613390d249a365625c2ee545a908029d
> prerequisite-patch-id: 03b0aaa382ddda0819ddb62479cd1885c930ddea
> prerequisite-patch-id: 83b8b3a072520705dcba4b67712a29553bea1548
> prerequisite-patch-id: 9308fa06526d9bacdbcdd347cc225f6f3f87811a
> prerequisite-patch-id: a017243a1a4b406caed9cec048d194cdc33d1a25
> prerequisite-patch-id: e8d5b2e787904b0dd1a650d7a0012b91a430cb03
> prerequisite-patch-id: 1cc872245864ace22db43cf2d268a87190b333b6
> prerequisite-patch-id: c277dcca77f3acde51bdffe932b9250e454086ad
> prerequisite-patch-id: ea926073e68d5af7f6c76a6333520cc5f42c9789
> prerequisite-patch-id: 10008b9b34ccc8f87f2fcd8391075fe57244ac72
> prerequisite-patch-id: 443d7e3eb85f36848c2120979f9f1d3a78f8bf38
> prerequisite-patch-id: 6414c2d65c1806942d7f834e9300a8ecf8fd743f
> prerequisite-patch-id: 8c6dec06b716c39ca7fada0f2872078612917779
> prerequisite-patch-id: 62e28252e9b7ab11edb03609b68369feb499f883
> prerequisite-patch-id: 84c9361c4c6d7662cfb3235cc4a6640a53e00622
> prerequisite-patch-id: 0f27045bc50089a9a88da7818448a50cd28dd295
> prerequisite-patch-id: 500413da3a81e75c5fbca62a21d9457d7b1ad8a8
> prerequisite-patch-id: 6f48169f4d69da277bcdecb8f40d2f608941d9f9
> prerequisite-patch-id: fc8b43573cc6b90033769de63ca235b16159190d
> prerequisite-patch-id: ae749fc3fa0ab1768841ffb4633847b5b2233881
> prerequisite-patch-id: 46b8490d2b338229a2f3c5e39427275cf46982ba
> prerequisite-patch-id: b1bb7dfb35069a2b30f5b2714bc19a249be3e1b5
> prerequisite-patch-id: 94848222eb08beb53530ba6ce626e9d8bcffecd4
> prerequisite-patch-id: f8181365677e68d8628013c7636e9ff56214ac9e
> prerequisite-patch-id: aebc0f8156c409599cc7aced4b708bb5ea08a2b2
> prerequisite-patch-id: 4ce416249f6d3176a51d7e4cbbd2c6bf2982bab6
> prerequisite-patch-id: 5e14463dcc090e497bb1d29c1b4c822b43d5fdca
> prerequisite-patch-id: 89306b41386cb29db7c147e8c4468a3b4d8d292d
> prerequisite-patch-id: 29e414b1ede9108047ff224e1e24a3adb2c44c52
> prerequisite-patch-id: 7e15edfd04cd291f54284d13dcdbebcfb456b752
> prerequisite-patch-id: b8c18091929e58b49847ab510d3d75a8a934cad0
> prerequisite-patch-id: 7a607a1659b22afb0c21dec3d8eb1e2ed51e47a9
> prerequisite-patch-id: 89fbd04f11e5bef5703ba7ea4c2064d5ba63c4d4
> prerequisite-patch-id: b421048677352ea536dd93a61d6de987fb95d60b
> prerequisite-patch-id: 25a03298bdfd6a691bb8cf68690009f8e46447e0
> prerequisite-patch-id: 3924163576eafdac47ac06de311ac317730e6631
> prerequisite-patch-id: 69b1d81677b507242f556c3e2fcf5290aeca445c
> prerequisite-patch-id: a378fa79002001da51ae91eb026769eddb8a593b
> prerequisite-patch-id: 86bb35c89ec3cc1b6ec47f238c84a154d5e9a1aa
> prerequisite-patch-id: f8d0709d94ed99b1530bad1908ca27b1b56ea84e
> prerequisite-patch-id: dcb65983aa914b8f1d1a8fbdfba34714ddb7f6fa
> prerequisite-patch-id: 89752146a063d0706885819e244b4179196538b8
> prerequisite-patch-id: 1f9e7627d0b23302159cdab3d939fcec52f7ca70
> prerequisite-patch-id: f706bfa95ba0e5e72c206537ed207feb95daa888
> prerequisite-patch-id: 9b60c519b0df65eeacd5779808e0d75b011ebf7f
> prerequisite-patch-id: cd6cd74eca502ebce581c223cd0d2ac4278912e8
> prerequisite-patch-id: b86e08404ef83877dfa3b76a80a12b02c61b1326
> prerequisite-patch-id: 9417f8d92995cf417bb3c4afa0786b05a756d48a
> prerequisite-patch-id: 59dda13243375b013396981a4f9e17abd694d734
> prerequisite-patch-id: 89be058d0605cb8278d5d3384bb44911b188dd90
> prerequisite-patch-id: 70c26fde2fde34c031a95ef74a3321710dc4961e
> prerequisite-patch-id: 38a27cdf8cbe03fdf5f9bafa5ba53f3ba644a5ad
> prerequisite-patch-id: 40a6d2e51dff2531c40a38087a8aea1be7108792
> prerequisite-patch-id: 024d1bba9bcd449d2b8196b2f1a64a197cafaed8
> prerequisite-patch-id: e83d54aa767ebab267530fca74d60366160a5253
> prerequisite-patch-id: c34734661161c27224316dc519609db5c6d87a1e
> prerequisite-patch-id: a58d739146fe46f6c7f203e5d2e0f114bd3f7834
> prerequisite-patch-id: 1ff8499f5ec69b737d77053e6809ec3a0b599ebc
> prerequisite-patch-id: 498e5608bca9b5ebcb3592a556e75f5dcc2b7076
> prerequisite-patch-id: df6dfdea7c3d9db4649d857ce55fbeb99d4febca
> prerequisite-patch-id: 453b66b1faaaebaa1666954185de327298aa0578
> prerequisite-patch-id: f98da1de781c203a53cae73c5bb707240d21cb0a
> prerequisite-patch-id: 14b1718dbc4fb9cd94e1094a4d44ebfcfe6ad869
> prerequisite-patch-id: 3b68944fa8fb2fab0c21d6ff73f649f53dd6f551
> prerequisite-patch-id: 82d1e6bcd221f982b6ab1ed0e9a90d46a39562c4
> prerequisite-patch-id: c9cce20b146f955b715d15c0c384c9acc6176493
> prerequisite-patch-id: c204491c1db4f5056711768265f101e881e4e415
> prerequisite-patch-id: e66e13fbde027e99552fc6d80ff8d48c110a18f2
> prerequisite-patch-id: 3c313f0a20730c653c8f5ec4f318e2485a8ef60f
> prerequisite-patch-id: 925c466172c01c4b5976ac019961cbe240f0cddd
> prerequisite-patch-id: e81e0aded80adf18c861f67624a179a15ef68906
> prerequisite-patch-id: 001675f7da57d25731c7c71f6f2dcaa7409e5664
> prerequisite-patch-id: d65bf6ef5f51da0acba72d332d60167b34e193e1
> prerequisite-patch-id: fc7c9a5024037363319b58520480a6c4a8a5dcff
> prerequisite-patch-id: 5aae8c77d028459d944021f4943558411deb0662
> prerequisite-patch-id: 71fa80813ad36528e8a737249424d90827933c16
> prerequisite-patch-id: 65dc75b8e1ddb45542480a8867ecd7a63ab3112e
> prerequisite-patch-id: 8619aa1dec17409d9b5ecb6ed0a2cc7d1563c174
> prerequisite-patch-id: 6473142746dc5b448ec9698d577f47b4da6cd1d5
> prerequisite-patch-id: eb6689695d5d1b6c650de0c86a805a45b80ab88d
> prerequisite-patch-id: 7d50679dad38c9f859ec231da2db78919818b40e
> prerequisite-patch-id: faeb97c5f9c07754bd0bf0be59254091470978c2
> prerequisite-patch-id: 56e31c3ab9ed9ff19aca25d5ffb9655c6515b692
> prerequisite-patch-id: 8d7418e017eec3c6e56b55f9ff6181cc3dcc1a17
> prerequisite-patch-id: 84f58e5a274c980ae6905e764d479e1c960149ca
> prerequisite-patch-id: ada6a2d9427bff9dd7fd115a91300a1f7379995c
> prerequisite-patch-id: 108161d5500b39b3ac55d202b5b9af817d829724
> prerequisite-patch-id: c89b0fc7dadc53facc45ccf9991503430b7e7799
> prerequisite-patch-id: d62e2be8f9fd6a1d9ac8dfa2cdc4db6d4a4327ac
> prerequisite-patch-id: f8f4375b2b16ffae596d416607c00b374f485299
> prerequisite-patch-id: 36b1a9c3e0e9f91b7172e1211231759a6cb81473
> prerequisite-patch-id: 8cb6ac6a5188c817bb3a6a86920001de75bb7225
> prerequisite-patch-id: 17ef87336a8c664e0109a7466c9f7d37f5901167

-- 
Best regards,
Nicolas Graves




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

* [bug#42338] [PATCH v3] guix: import: composer: Fix match-lambda with a default fallback.
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (5 preceding siblings ...)
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
@ 2023-09-26 11:25 ` Nicolas Graves via Guix-patches via
  2023-09-26 11:27   ` Nicolas Graves via Guix-patches via
  2023-09-26 11:29 ` [bug#42338] [PATCH v4] guix: composer-build-system: Fix match-lambda with a fallback Nicolas Graves via Guix-patches via
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 11:25 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm:
(composer-package): Fix match-lambda with a default fallback.
(composer-autoload): Fix match-lambda with a default fallback.
---
 guix/build/composer-build-system.scm | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
index 7df2b7c400..d891ea3a6d 100644
--- a/guix/build/composer-build-system.scm
+++ b/guix/build/composer-build-system.scm
@@ -46,12 +46,12 @@ (define-json-mapping <composer-autoload> make-composer-autoload composer-autoloa
   json->composer-autoload
   (psr-4 composer-autoload-psr-4 "psr-4"
                 (match-lambda
-                  (#f '())
-                  (psr-4 psr-4)))
+                  (psr-4 psr-4)
+                  (_ '())))
   (classmap composer-autoload-classmap "classmap"
             (match-lambda
-              (#f '())
-              (#(lst ...) lst))))
+              (#(lst ...) lst)
+              (_ '()))))
 
 (define-json-mapping <composer-package> make-composer-package composer-package?
   json->composer-package
@@ -62,12 +62,12 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
   (dev-require  composer-package-dev-require "require-dev" json->require)
   (scripts      composer-package-scripts "scripts"
                 (match-lambda
-                  (#f '())
-                  ((scripts ...) scripts)))
+                  ((scripts ...) scripts)
+                  (_ '())))
   (binaries     composer-package-binaries "bin"
                 (match-lambda
-                  (#f '())
-                  (#(lst ...) lst))))
+                  (#(lst ...) lst)
+                  (_ '()))))
 
 (define* (read-package-data #:key (filename "composer.json"))
   (call-with-input-file filename

base-commit: fafd3caef0d51811a5da81d6061789e2908b0dac
prerequisite-patch-id: eb618ab7b10483d917c308a38792af98baa517e2
prerequisite-patch-id: c12968d02d99c253f858586a86b16fa32d41f1c1
prerequisite-patch-id: 09d995d48139f8e61183d5634cda13a01cdb50f7
prerequisite-patch-id: 86baa45ec2aad977c8c8135f7613aa391155de6d
prerequisite-patch-id: 3425fbbff6a603d60b4e143ea2141aabf4ddc92c
prerequisite-patch-id: c373c01aab5dcba3503a97d51c62a595147a041c
prerequisite-patch-id: cda857c790b88c681c4e713c5f71e40291970daf
prerequisite-patch-id: 8e234d0f4d93d2aad499eec8842be3d28da98707
prerequisite-patch-id: 5f664cb2fd995a53765c5ffc19a708ac795cc0c4
prerequisite-patch-id: ed447cba9cf9b7e1a1b47aa27acb14f8f2da0a8e
prerequisite-patch-id: 9f80c5bbbfb8cd3347951c4d57634e93ffa79924
prerequisite-patch-id: 1aaa9f0d466e2d6837f75844df48a98beb70ff24
prerequisite-patch-id: 34502820d8c0355b3ed2638c457084edeaba029d
prerequisite-patch-id: a96258da9e78cfb9ac9893cdcdeb38b69b75f134
prerequisite-patch-id: 4a2da4ee89dbbdb2244845149ce6da967ddd5268
prerequisite-patch-id: 9f9c4205781d1f0e2bb7af2d21875de08ee3ecd5
prerequisite-patch-id: 9697db9b50cab8f7974c32383e0a9a786ecbd8f9
prerequisite-patch-id: ebbd089a3313232347273c723d3deb1bf8c9bf81
prerequisite-patch-id: e93360d66936b9efd70a6ffd41f6ecda177ad7b8
prerequisite-patch-id: 19d76f45db1c59bd9ccd2e4e1125ffd698e9d6ce
prerequisite-patch-id: 929b39ded7ad095e9f768f7d484bbd3b7a486a3c
prerequisite-patch-id: 5e1262f77d55c91eadca113223faa84935bffd60
prerequisite-patch-id: ad370d41983418fa704215aa3458f97c75d5d128
prerequisite-patch-id: f179c922613390d249a365625c2ee545a908029d
prerequisite-patch-id: 03b0aaa382ddda0819ddb62479cd1885c930ddea
prerequisite-patch-id: 83b8b3a072520705dcba4b67712a29553bea1548
prerequisite-patch-id: 9308fa06526d9bacdbcdd347cc225f6f3f87811a
prerequisite-patch-id: a017243a1a4b406caed9cec048d194cdc33d1a25
prerequisite-patch-id: e8d5b2e787904b0dd1a650d7a0012b91a430cb03
prerequisite-patch-id: 1cc872245864ace22db43cf2d268a87190b333b6
prerequisite-patch-id: c277dcca77f3acde51bdffe932b9250e454086ad
prerequisite-patch-id: ea926073e68d5af7f6c76a6333520cc5f42c9789
prerequisite-patch-id: 10008b9b34ccc8f87f2fcd8391075fe57244ac72
prerequisite-patch-id: 443d7e3eb85f36848c2120979f9f1d3a78f8bf38
prerequisite-patch-id: 6414c2d65c1806942d7f834e9300a8ecf8fd743f
prerequisite-patch-id: 8c6dec06b716c39ca7fada0f2872078612917779
prerequisite-patch-id: 62e28252e9b7ab11edb03609b68369feb499f883
prerequisite-patch-id: 84c9361c4c6d7662cfb3235cc4a6640a53e00622
prerequisite-patch-id: 0f27045bc50089a9a88da7818448a50cd28dd295
prerequisite-patch-id: 500413da3a81e75c5fbca62a21d9457d7b1ad8a8
prerequisite-patch-id: 6f48169f4d69da277bcdecb8f40d2f608941d9f9
prerequisite-patch-id: fc8b43573cc6b90033769de63ca235b16159190d
prerequisite-patch-id: ae749fc3fa0ab1768841ffb4633847b5b2233881
prerequisite-patch-id: 46b8490d2b338229a2f3c5e39427275cf46982ba
prerequisite-patch-id: b1bb7dfb35069a2b30f5b2714bc19a249be3e1b5
prerequisite-patch-id: 94848222eb08beb53530ba6ce626e9d8bcffecd4
prerequisite-patch-id: f8181365677e68d8628013c7636e9ff56214ac9e
prerequisite-patch-id: aebc0f8156c409599cc7aced4b708bb5ea08a2b2
prerequisite-patch-id: 4ce416249f6d3176a51d7e4cbbd2c6bf2982bab6
prerequisite-patch-id: 5e14463dcc090e497bb1d29c1b4c822b43d5fdca
prerequisite-patch-id: 89306b41386cb29db7c147e8c4468a3b4d8d292d
prerequisite-patch-id: 29e414b1ede9108047ff224e1e24a3adb2c44c52
prerequisite-patch-id: 7e15edfd04cd291f54284d13dcdbebcfb456b752
prerequisite-patch-id: b8c18091929e58b49847ab510d3d75a8a934cad0
prerequisite-patch-id: 7a607a1659b22afb0c21dec3d8eb1e2ed51e47a9
prerequisite-patch-id: 89fbd04f11e5bef5703ba7ea4c2064d5ba63c4d4
prerequisite-patch-id: b421048677352ea536dd93a61d6de987fb95d60b
prerequisite-patch-id: 25a03298bdfd6a691bb8cf68690009f8e46447e0
prerequisite-patch-id: 3924163576eafdac47ac06de311ac317730e6631
prerequisite-patch-id: 69b1d81677b507242f556c3e2fcf5290aeca445c
prerequisite-patch-id: a378fa79002001da51ae91eb026769eddb8a593b
prerequisite-patch-id: 86bb35c89ec3cc1b6ec47f238c84a154d5e9a1aa
prerequisite-patch-id: f8d0709d94ed99b1530bad1908ca27b1b56ea84e
prerequisite-patch-id: dcb65983aa914b8f1d1a8fbdfba34714ddb7f6fa
prerequisite-patch-id: 89752146a063d0706885819e244b4179196538b8
prerequisite-patch-id: 1f9e7627d0b23302159cdab3d939fcec52f7ca70
prerequisite-patch-id: f706bfa95ba0e5e72c206537ed207feb95daa888
prerequisite-patch-id: 9b60c519b0df65eeacd5779808e0d75b011ebf7f
prerequisite-patch-id: cd6cd74eca502ebce581c223cd0d2ac4278912e8
prerequisite-patch-id: b86e08404ef83877dfa3b76a80a12b02c61b1326
prerequisite-patch-id: 9417f8d92995cf417bb3c4afa0786b05a756d48a
prerequisite-patch-id: 59dda13243375b013396981a4f9e17abd694d734
prerequisite-patch-id: 89be058d0605cb8278d5d3384bb44911b188dd90
prerequisite-patch-id: 70c26fde2fde34c031a95ef74a3321710dc4961e
prerequisite-patch-id: 38a27cdf8cbe03fdf5f9bafa5ba53f3ba644a5ad
prerequisite-patch-id: 40a6d2e51dff2531c40a38087a8aea1be7108792
prerequisite-patch-id: 024d1bba9bcd449d2b8196b2f1a64a197cafaed8
prerequisite-patch-id: e83d54aa767ebab267530fca74d60366160a5253
prerequisite-patch-id: c34734661161c27224316dc519609db5c6d87a1e
prerequisite-patch-id: a58d739146fe46f6c7f203e5d2e0f114bd3f7834
prerequisite-patch-id: 1ff8499f5ec69b737d77053e6809ec3a0b599ebc
prerequisite-patch-id: 498e5608bca9b5ebcb3592a556e75f5dcc2b7076
prerequisite-patch-id: df6dfdea7c3d9db4649d857ce55fbeb99d4febca
prerequisite-patch-id: 453b66b1faaaebaa1666954185de327298aa0578
prerequisite-patch-id: f98da1de781c203a53cae73c5bb707240d21cb0a
prerequisite-patch-id: 14b1718dbc4fb9cd94e1094a4d44ebfcfe6ad869
prerequisite-patch-id: 3b68944fa8fb2fab0c21d6ff73f649f53dd6f551
prerequisite-patch-id: 82d1e6bcd221f982b6ab1ed0e9a90d46a39562c4
prerequisite-patch-id: c9cce20b146f955b715d15c0c384c9acc6176493
prerequisite-patch-id: c204491c1db4f5056711768265f101e881e4e415
prerequisite-patch-id: e66e13fbde027e99552fc6d80ff8d48c110a18f2
prerequisite-patch-id: 3c313f0a20730c653c8f5ec4f318e2485a8ef60f
prerequisite-patch-id: 925c466172c01c4b5976ac019961cbe240f0cddd
prerequisite-patch-id: e81e0aded80adf18c861f67624a179a15ef68906
prerequisite-patch-id: 001675f7da57d25731c7c71f6f2dcaa7409e5664
prerequisite-patch-id: d65bf6ef5f51da0acba72d332d60167b34e193e1
prerequisite-patch-id: fc7c9a5024037363319b58520480a6c4a8a5dcff
prerequisite-patch-id: 5aae8c77d028459d944021f4943558411deb0662
prerequisite-patch-id: 71fa80813ad36528e8a737249424d90827933c16
prerequisite-patch-id: 65dc75b8e1ddb45542480a8867ecd7a63ab3112e
prerequisite-patch-id: 8619aa1dec17409d9b5ecb6ed0a2cc7d1563c174
prerequisite-patch-id: 6473142746dc5b448ec9698d577f47b4da6cd1d5
prerequisite-patch-id: eb6689695d5d1b6c650de0c86a805a45b80ab88d
prerequisite-patch-id: 7d50679dad38c9f859ec231da2db78919818b40e
prerequisite-patch-id: faeb97c5f9c07754bd0bf0be59254091470978c2
prerequisite-patch-id: 56e31c3ab9ed9ff19aca25d5ffb9655c6515b692
prerequisite-patch-id: 8d7418e017eec3c6e56b55f9ff6181cc3dcc1a17
prerequisite-patch-id: 84f58e5a274c980ae6905e764d479e1c960149ca
prerequisite-patch-id: ada6a2d9427bff9dd7fd115a91300a1f7379995c
prerequisite-patch-id: 108161d5500b39b3ac55d202b5b9af817d829724
prerequisite-patch-id: c89b0fc7dadc53facc45ccf9991503430b7e7799
prerequisite-patch-id: d62e2be8f9fd6a1d9ac8dfa2cdc4db6d4a4327ac
prerequisite-patch-id: f8f4375b2b16ffae596d416607c00b374f485299
prerequisite-patch-id: 36b1a9c3e0e9f91b7172e1211231759a6cb81473
prerequisite-patch-id: 8cb6ac6a5188c817bb3a6a86920001de75bb7225
prerequisite-patch-id: 17ef87336a8c664e0109a7466c9f7d37f5901167
prerequisite-patch-id: a2c72266baec1b3eb5706d43157d93ae8db5e42d
prerequisite-patch-id: 27503579f8bdfadb95847b8dd5bf3732f5149cfb
prerequisite-patch-id: 50d6d9c6ff0734705ae384ede694b547f4973249
prerequisite-patch-id: 81cd72752ab376d459dceff93f71715e55a55846
prerequisite-patch-id: 922cec7ef3d21275f5933968f5b704e0bed64ce5
prerequisite-patch-id: 1f0903e8846cd59d0d5a3dcbf9a5a82ad4dcb5cd
prerequisite-patch-id: 69d839b9d5b794ef1b7dee9c592ed20300f8539f
-- 
2.41.0





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

* [bug#42338] [PATCH v3] guix: import: composer: Fix match-lambda with a default fallback.
  2023-09-26 11:25 ` [bug#42338] [PATCH v3] guix: import: composer: Fix match-lambda with a default fallback Nicolas Graves via Guix-patches via
@ 2023-09-26 11:27   ` Nicolas Graves via Guix-patches via
  0 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 11:27 UTC (permalink / raw)
  To: 42338


I haven't tested building packages, and it seemed that there still was
the same issue as the importer (no fallback for a match). With this
additional patch, packages seem to build well. 


On 2023-09-26 13:25, Nicolas Graves wrote:

> * guix/import/composer.scm:
> (composer-package): Fix match-lambda with a default fallback.
> (composer-autoload): Fix match-lambda with a default fallback.
> ---
>  guix/build/composer-build-system.scm | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
> index 7df2b7c400..d891ea3a6d 100644
> --- a/guix/build/composer-build-system.scm
> +++ b/guix/build/composer-build-system.scm
> @@ -46,12 +46,12 @@ (define-json-mapping <composer-autoload> make-composer-autoload composer-autoloa
>    json->composer-autoload
>    (psr-4 composer-autoload-psr-4 "psr-4"
>                  (match-lambda
> -                  (#f '())
> -                  (psr-4 psr-4)))
> +                  (psr-4 psr-4)
> +                  (_ '())))
>    (classmap composer-autoload-classmap "classmap"
>              (match-lambda
> -              (#f '())
> -              (#(lst ...) lst))))
> +              (#(lst ...) lst)
> +              (_ '()))))
>  
>  (define-json-mapping <composer-package> make-composer-package composer-package?
>    json->composer-package
> @@ -62,12 +62,12 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
>    (dev-require  composer-package-dev-require "require-dev" json->require)
>    (scripts      composer-package-scripts "scripts"
>                  (match-lambda
> -                  (#f '())
> -                  ((scripts ...) scripts)))
> +                  ((scripts ...) scripts)
> +                  (_ '())))
>    (binaries     composer-package-binaries "bin"
>                  (match-lambda
> -                  (#f '())
> -                  (#(lst ...) lst))))
> +                  (#(lst ...) lst)
> +                  (_ '()))))
>  
>  (define* (read-package-data #:key (filename "composer.json"))
>    (call-with-input-file filename
>
> base-commit: fafd3caef0d51811a5da81d6061789e2908b0dac
> prerequisite-patch-id: eb618ab7b10483d917c308a38792af98baa517e2
> prerequisite-patch-id: c12968d02d99c253f858586a86b16fa32d41f1c1
> prerequisite-patch-id: 09d995d48139f8e61183d5634cda13a01cdb50f7
> prerequisite-patch-id: 86baa45ec2aad977c8c8135f7613aa391155de6d
> prerequisite-patch-id: 3425fbbff6a603d60b4e143ea2141aabf4ddc92c
> prerequisite-patch-id: c373c01aab5dcba3503a97d51c62a595147a041c
> prerequisite-patch-id: cda857c790b88c681c4e713c5f71e40291970daf
> prerequisite-patch-id: 8e234d0f4d93d2aad499eec8842be3d28da98707
> prerequisite-patch-id: 5f664cb2fd995a53765c5ffc19a708ac795cc0c4
> prerequisite-patch-id: ed447cba9cf9b7e1a1b47aa27acb14f8f2da0a8e
> prerequisite-patch-id: 9f80c5bbbfb8cd3347951c4d57634e93ffa79924
> prerequisite-patch-id: 1aaa9f0d466e2d6837f75844df48a98beb70ff24
> prerequisite-patch-id: 34502820d8c0355b3ed2638c457084edeaba029d
> prerequisite-patch-id: a96258da9e78cfb9ac9893cdcdeb38b69b75f134
> prerequisite-patch-id: 4a2da4ee89dbbdb2244845149ce6da967ddd5268
> prerequisite-patch-id: 9f9c4205781d1f0e2bb7af2d21875de08ee3ecd5
> prerequisite-patch-id: 9697db9b50cab8f7974c32383e0a9a786ecbd8f9
> prerequisite-patch-id: ebbd089a3313232347273c723d3deb1bf8c9bf81
> prerequisite-patch-id: e93360d66936b9efd70a6ffd41f6ecda177ad7b8
> prerequisite-patch-id: 19d76f45db1c59bd9ccd2e4e1125ffd698e9d6ce
> prerequisite-patch-id: 929b39ded7ad095e9f768f7d484bbd3b7a486a3c
> prerequisite-patch-id: 5e1262f77d55c91eadca113223faa84935bffd60
> prerequisite-patch-id: ad370d41983418fa704215aa3458f97c75d5d128
> prerequisite-patch-id: f179c922613390d249a365625c2ee545a908029d
> prerequisite-patch-id: 03b0aaa382ddda0819ddb62479cd1885c930ddea
> prerequisite-patch-id: 83b8b3a072520705dcba4b67712a29553bea1548
> prerequisite-patch-id: 9308fa06526d9bacdbcdd347cc225f6f3f87811a
> prerequisite-patch-id: a017243a1a4b406caed9cec048d194cdc33d1a25
> prerequisite-patch-id: e8d5b2e787904b0dd1a650d7a0012b91a430cb03
> prerequisite-patch-id: 1cc872245864ace22db43cf2d268a87190b333b6
> prerequisite-patch-id: c277dcca77f3acde51bdffe932b9250e454086ad
> prerequisite-patch-id: ea926073e68d5af7f6c76a6333520cc5f42c9789
> prerequisite-patch-id: 10008b9b34ccc8f87f2fcd8391075fe57244ac72
> prerequisite-patch-id: 443d7e3eb85f36848c2120979f9f1d3a78f8bf38
> prerequisite-patch-id: 6414c2d65c1806942d7f834e9300a8ecf8fd743f
> prerequisite-patch-id: 8c6dec06b716c39ca7fada0f2872078612917779
> prerequisite-patch-id: 62e28252e9b7ab11edb03609b68369feb499f883
> prerequisite-patch-id: 84c9361c4c6d7662cfb3235cc4a6640a53e00622
> prerequisite-patch-id: 0f27045bc50089a9a88da7818448a50cd28dd295
> prerequisite-patch-id: 500413da3a81e75c5fbca62a21d9457d7b1ad8a8
> prerequisite-patch-id: 6f48169f4d69da277bcdecb8f40d2f608941d9f9
> prerequisite-patch-id: fc8b43573cc6b90033769de63ca235b16159190d
> prerequisite-patch-id: ae749fc3fa0ab1768841ffb4633847b5b2233881
> prerequisite-patch-id: 46b8490d2b338229a2f3c5e39427275cf46982ba
> prerequisite-patch-id: b1bb7dfb35069a2b30f5b2714bc19a249be3e1b5
> prerequisite-patch-id: 94848222eb08beb53530ba6ce626e9d8bcffecd4
> prerequisite-patch-id: f8181365677e68d8628013c7636e9ff56214ac9e
> prerequisite-patch-id: aebc0f8156c409599cc7aced4b708bb5ea08a2b2
> prerequisite-patch-id: 4ce416249f6d3176a51d7e4cbbd2c6bf2982bab6
> prerequisite-patch-id: 5e14463dcc090e497bb1d29c1b4c822b43d5fdca
> prerequisite-patch-id: 89306b41386cb29db7c147e8c4468a3b4d8d292d
> prerequisite-patch-id: 29e414b1ede9108047ff224e1e24a3adb2c44c52
> prerequisite-patch-id: 7e15edfd04cd291f54284d13dcdbebcfb456b752
> prerequisite-patch-id: b8c18091929e58b49847ab510d3d75a8a934cad0
> prerequisite-patch-id: 7a607a1659b22afb0c21dec3d8eb1e2ed51e47a9
> prerequisite-patch-id: 89fbd04f11e5bef5703ba7ea4c2064d5ba63c4d4
> prerequisite-patch-id: b421048677352ea536dd93a61d6de987fb95d60b
> prerequisite-patch-id: 25a03298bdfd6a691bb8cf68690009f8e46447e0
> prerequisite-patch-id: 3924163576eafdac47ac06de311ac317730e6631
> prerequisite-patch-id: 69b1d81677b507242f556c3e2fcf5290aeca445c
> prerequisite-patch-id: a378fa79002001da51ae91eb026769eddb8a593b
> prerequisite-patch-id: 86bb35c89ec3cc1b6ec47f238c84a154d5e9a1aa
> prerequisite-patch-id: f8d0709d94ed99b1530bad1908ca27b1b56ea84e
> prerequisite-patch-id: dcb65983aa914b8f1d1a8fbdfba34714ddb7f6fa
> prerequisite-patch-id: 89752146a063d0706885819e244b4179196538b8
> prerequisite-patch-id: 1f9e7627d0b23302159cdab3d939fcec52f7ca70
> prerequisite-patch-id: f706bfa95ba0e5e72c206537ed207feb95daa888
> prerequisite-patch-id: 9b60c519b0df65eeacd5779808e0d75b011ebf7f
> prerequisite-patch-id: cd6cd74eca502ebce581c223cd0d2ac4278912e8
> prerequisite-patch-id: b86e08404ef83877dfa3b76a80a12b02c61b1326
> prerequisite-patch-id: 9417f8d92995cf417bb3c4afa0786b05a756d48a
> prerequisite-patch-id: 59dda13243375b013396981a4f9e17abd694d734
> prerequisite-patch-id: 89be058d0605cb8278d5d3384bb44911b188dd90
> prerequisite-patch-id: 70c26fde2fde34c031a95ef74a3321710dc4961e
> prerequisite-patch-id: 38a27cdf8cbe03fdf5f9bafa5ba53f3ba644a5ad
> prerequisite-patch-id: 40a6d2e51dff2531c40a38087a8aea1be7108792
> prerequisite-patch-id: 024d1bba9bcd449d2b8196b2f1a64a197cafaed8
> prerequisite-patch-id: e83d54aa767ebab267530fca74d60366160a5253
> prerequisite-patch-id: c34734661161c27224316dc519609db5c6d87a1e
> prerequisite-patch-id: a58d739146fe46f6c7f203e5d2e0f114bd3f7834
> prerequisite-patch-id: 1ff8499f5ec69b737d77053e6809ec3a0b599ebc
> prerequisite-patch-id: 498e5608bca9b5ebcb3592a556e75f5dcc2b7076
> prerequisite-patch-id: df6dfdea7c3d9db4649d857ce55fbeb99d4febca
> prerequisite-patch-id: 453b66b1faaaebaa1666954185de327298aa0578
> prerequisite-patch-id: f98da1de781c203a53cae73c5bb707240d21cb0a
> prerequisite-patch-id: 14b1718dbc4fb9cd94e1094a4d44ebfcfe6ad869
> prerequisite-patch-id: 3b68944fa8fb2fab0c21d6ff73f649f53dd6f551
> prerequisite-patch-id: 82d1e6bcd221f982b6ab1ed0e9a90d46a39562c4
> prerequisite-patch-id: c9cce20b146f955b715d15c0c384c9acc6176493
> prerequisite-patch-id: c204491c1db4f5056711768265f101e881e4e415
> prerequisite-patch-id: e66e13fbde027e99552fc6d80ff8d48c110a18f2
> prerequisite-patch-id: 3c313f0a20730c653c8f5ec4f318e2485a8ef60f
> prerequisite-patch-id: 925c466172c01c4b5976ac019961cbe240f0cddd
> prerequisite-patch-id: e81e0aded80adf18c861f67624a179a15ef68906
> prerequisite-patch-id: 001675f7da57d25731c7c71f6f2dcaa7409e5664
> prerequisite-patch-id: d65bf6ef5f51da0acba72d332d60167b34e193e1
> prerequisite-patch-id: fc7c9a5024037363319b58520480a6c4a8a5dcff
> prerequisite-patch-id: 5aae8c77d028459d944021f4943558411deb0662
> prerequisite-patch-id: 71fa80813ad36528e8a737249424d90827933c16
> prerequisite-patch-id: 65dc75b8e1ddb45542480a8867ecd7a63ab3112e
> prerequisite-patch-id: 8619aa1dec17409d9b5ecb6ed0a2cc7d1563c174
> prerequisite-patch-id: 6473142746dc5b448ec9698d577f47b4da6cd1d5
> prerequisite-patch-id: eb6689695d5d1b6c650de0c86a805a45b80ab88d
> prerequisite-patch-id: 7d50679dad38c9f859ec231da2db78919818b40e
> prerequisite-patch-id: faeb97c5f9c07754bd0bf0be59254091470978c2
> prerequisite-patch-id: 56e31c3ab9ed9ff19aca25d5ffb9655c6515b692
> prerequisite-patch-id: 8d7418e017eec3c6e56b55f9ff6181cc3dcc1a17
> prerequisite-patch-id: 84f58e5a274c980ae6905e764d479e1c960149ca
> prerequisite-patch-id: ada6a2d9427bff9dd7fd115a91300a1f7379995c
> prerequisite-patch-id: 108161d5500b39b3ac55d202b5b9af817d829724
> prerequisite-patch-id: c89b0fc7dadc53facc45ccf9991503430b7e7799
> prerequisite-patch-id: d62e2be8f9fd6a1d9ac8dfa2cdc4db6d4a4327ac
> prerequisite-patch-id: f8f4375b2b16ffae596d416607c00b374f485299
> prerequisite-patch-id: 36b1a9c3e0e9f91b7172e1211231759a6cb81473
> prerequisite-patch-id: 8cb6ac6a5188c817bb3a6a86920001de75bb7225
> prerequisite-patch-id: 17ef87336a8c664e0109a7466c9f7d37f5901167
> prerequisite-patch-id: a2c72266baec1b3eb5706d43157d93ae8db5e42d
> prerequisite-patch-id: 27503579f8bdfadb95847b8dd5bf3732f5149cfb
> prerequisite-patch-id: 50d6d9c6ff0734705ae384ede694b547f4973249
> prerequisite-patch-id: 81cd72752ab376d459dceff93f71715e55a55846
> prerequisite-patch-id: 922cec7ef3d21275f5933968f5b704e0bed64ce5
> prerequisite-patch-id: 1f0903e8846cd59d0d5a3dcbf9a5a82ad4dcb5cd
> prerequisite-patch-id: 69d839b9d5b794ef1b7dee9c592ed20300f8539f

-- 
Best regards,
Nicolas Graves




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

* [bug#42338] [PATCH v4] guix: composer-build-system: Fix match-lambda with a fallback.
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (6 preceding siblings ...)
  2023-09-26 11:25 ` [bug#42338] [PATCH v3] guix: import: composer: Fix match-lambda with a default fallback Nicolas Graves via Guix-patches via
@ 2023-09-26 11:29 ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-09-26 11:29 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/build/composer-build-system.scm:
(composer-package): Fix match-lambda with a default fallback.
(composer-autoload): Fix match-lambda with a default fallback.
---
 guix/build/composer-build-system.scm | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
index 7df2b7c400..d891ea3a6d 100644
--- a/guix/build/composer-build-system.scm
+++ b/guix/build/composer-build-system.scm
@@ -46,12 +46,12 @@ (define-json-mapping <composer-autoload> make-composer-autoload composer-autoloa
   json->composer-autoload
   (psr-4 composer-autoload-psr-4 "psr-4"
                 (match-lambda
-                  (#f '())
-                  (psr-4 psr-4)))
+                  (psr-4 psr-4)
+                  (_ '())))
   (classmap composer-autoload-classmap "classmap"
             (match-lambda
-              (#f '())
-              (#(lst ...) lst))))
+              (#(lst ...) lst)
+              (_ '()))))
 
 (define-json-mapping <composer-package> make-composer-package composer-package?
   json->composer-package
@@ -62,12 +62,12 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
   (dev-require  composer-package-dev-require "require-dev" json->require)
   (scripts      composer-package-scripts "scripts"
                 (match-lambda
-                  (#f '())
-                  ((scripts ...) scripts)))
+                  ((scripts ...) scripts)
+                  (_ '())))
   (binaries     composer-package-binaries "bin"
                 (match-lambda
-                  (#f '())
-                  (#(lst ...) lst))))
+                  (#(lst ...) lst)
+                  (_ '()))))
 
 (define* (read-package-data #:key (filename "composer.json"))
   (call-with-input-file filename

base-commit: fafd3caef0d51811a5da81d6061789e2908b0dac
prerequisite-patch-id: eb618ab7b10483d917c308a38792af98baa517e2
prerequisite-patch-id: c12968d02d99c253f858586a86b16fa32d41f1c1
prerequisite-patch-id: 09d995d48139f8e61183d5634cda13a01cdb50f7
prerequisite-patch-id: 86baa45ec2aad977c8c8135f7613aa391155de6d
prerequisite-patch-id: 3425fbbff6a603d60b4e143ea2141aabf4ddc92c
prerequisite-patch-id: c373c01aab5dcba3503a97d51c62a595147a041c
prerequisite-patch-id: cda857c790b88c681c4e713c5f71e40291970daf
prerequisite-patch-id: 8e234d0f4d93d2aad499eec8842be3d28da98707
prerequisite-patch-id: 5f664cb2fd995a53765c5ffc19a708ac795cc0c4
prerequisite-patch-id: ed447cba9cf9b7e1a1b47aa27acb14f8f2da0a8e
prerequisite-patch-id: 9f80c5bbbfb8cd3347951c4d57634e93ffa79924
prerequisite-patch-id: 1aaa9f0d466e2d6837f75844df48a98beb70ff24
prerequisite-patch-id: 34502820d8c0355b3ed2638c457084edeaba029d
prerequisite-patch-id: a96258da9e78cfb9ac9893cdcdeb38b69b75f134
prerequisite-patch-id: 4a2da4ee89dbbdb2244845149ce6da967ddd5268
prerequisite-patch-id: 9f9c4205781d1f0e2bb7af2d21875de08ee3ecd5
prerequisite-patch-id: 9697db9b50cab8f7974c32383e0a9a786ecbd8f9
prerequisite-patch-id: ebbd089a3313232347273c723d3deb1bf8c9bf81
prerequisite-patch-id: e93360d66936b9efd70a6ffd41f6ecda177ad7b8
prerequisite-patch-id: 19d76f45db1c59bd9ccd2e4e1125ffd698e9d6ce
prerequisite-patch-id: 929b39ded7ad095e9f768f7d484bbd3b7a486a3c
prerequisite-patch-id: 5e1262f77d55c91eadca113223faa84935bffd60
prerequisite-patch-id: ad370d41983418fa704215aa3458f97c75d5d128
prerequisite-patch-id: f179c922613390d249a365625c2ee545a908029d
prerequisite-patch-id: 03b0aaa382ddda0819ddb62479cd1885c930ddea
prerequisite-patch-id: 83b8b3a072520705dcba4b67712a29553bea1548
prerequisite-patch-id: 9308fa06526d9bacdbcdd347cc225f6f3f87811a
prerequisite-patch-id: a017243a1a4b406caed9cec048d194cdc33d1a25
prerequisite-patch-id: e8d5b2e787904b0dd1a650d7a0012b91a430cb03
prerequisite-patch-id: 1cc872245864ace22db43cf2d268a87190b333b6
prerequisite-patch-id: c277dcca77f3acde51bdffe932b9250e454086ad
prerequisite-patch-id: ea926073e68d5af7f6c76a6333520cc5f42c9789
prerequisite-patch-id: 10008b9b34ccc8f87f2fcd8391075fe57244ac72
prerequisite-patch-id: 443d7e3eb85f36848c2120979f9f1d3a78f8bf38
prerequisite-patch-id: 6414c2d65c1806942d7f834e9300a8ecf8fd743f
prerequisite-patch-id: 8c6dec06b716c39ca7fada0f2872078612917779
prerequisite-patch-id: 62e28252e9b7ab11edb03609b68369feb499f883
prerequisite-patch-id: 84c9361c4c6d7662cfb3235cc4a6640a53e00622
prerequisite-patch-id: 0f27045bc50089a9a88da7818448a50cd28dd295
prerequisite-patch-id: 500413da3a81e75c5fbca62a21d9457d7b1ad8a8
prerequisite-patch-id: 6f48169f4d69da277bcdecb8f40d2f608941d9f9
prerequisite-patch-id: fc8b43573cc6b90033769de63ca235b16159190d
prerequisite-patch-id: ae749fc3fa0ab1768841ffb4633847b5b2233881
prerequisite-patch-id: 46b8490d2b338229a2f3c5e39427275cf46982ba
prerequisite-patch-id: b1bb7dfb35069a2b30f5b2714bc19a249be3e1b5
prerequisite-patch-id: 94848222eb08beb53530ba6ce626e9d8bcffecd4
prerequisite-patch-id: f8181365677e68d8628013c7636e9ff56214ac9e
prerequisite-patch-id: aebc0f8156c409599cc7aced4b708bb5ea08a2b2
prerequisite-patch-id: 4ce416249f6d3176a51d7e4cbbd2c6bf2982bab6
prerequisite-patch-id: 5e14463dcc090e497bb1d29c1b4c822b43d5fdca
prerequisite-patch-id: 89306b41386cb29db7c147e8c4468a3b4d8d292d
prerequisite-patch-id: 29e414b1ede9108047ff224e1e24a3adb2c44c52
prerequisite-patch-id: 7e15edfd04cd291f54284d13dcdbebcfb456b752
prerequisite-patch-id: b8c18091929e58b49847ab510d3d75a8a934cad0
prerequisite-patch-id: 7a607a1659b22afb0c21dec3d8eb1e2ed51e47a9
prerequisite-patch-id: 89fbd04f11e5bef5703ba7ea4c2064d5ba63c4d4
prerequisite-patch-id: b421048677352ea536dd93a61d6de987fb95d60b
prerequisite-patch-id: 25a03298bdfd6a691bb8cf68690009f8e46447e0
prerequisite-patch-id: 3924163576eafdac47ac06de311ac317730e6631
prerequisite-patch-id: 69b1d81677b507242f556c3e2fcf5290aeca445c
prerequisite-patch-id: a378fa79002001da51ae91eb026769eddb8a593b
prerequisite-patch-id: 86bb35c89ec3cc1b6ec47f238c84a154d5e9a1aa
prerequisite-patch-id: f8d0709d94ed99b1530bad1908ca27b1b56ea84e
prerequisite-patch-id: dcb65983aa914b8f1d1a8fbdfba34714ddb7f6fa
prerequisite-patch-id: 89752146a063d0706885819e244b4179196538b8
prerequisite-patch-id: 1f9e7627d0b23302159cdab3d939fcec52f7ca70
prerequisite-patch-id: f706bfa95ba0e5e72c206537ed207feb95daa888
prerequisite-patch-id: 9b60c519b0df65eeacd5779808e0d75b011ebf7f
prerequisite-patch-id: cd6cd74eca502ebce581c223cd0d2ac4278912e8
prerequisite-patch-id: b86e08404ef83877dfa3b76a80a12b02c61b1326
prerequisite-patch-id: 9417f8d92995cf417bb3c4afa0786b05a756d48a
prerequisite-patch-id: 59dda13243375b013396981a4f9e17abd694d734
prerequisite-patch-id: 89be058d0605cb8278d5d3384bb44911b188dd90
prerequisite-patch-id: 70c26fde2fde34c031a95ef74a3321710dc4961e
prerequisite-patch-id: 38a27cdf8cbe03fdf5f9bafa5ba53f3ba644a5ad
prerequisite-patch-id: 40a6d2e51dff2531c40a38087a8aea1be7108792
prerequisite-patch-id: 024d1bba9bcd449d2b8196b2f1a64a197cafaed8
prerequisite-patch-id: e83d54aa767ebab267530fca74d60366160a5253
prerequisite-patch-id: c34734661161c27224316dc519609db5c6d87a1e
prerequisite-patch-id: a58d739146fe46f6c7f203e5d2e0f114bd3f7834
prerequisite-patch-id: 1ff8499f5ec69b737d77053e6809ec3a0b599ebc
prerequisite-patch-id: 498e5608bca9b5ebcb3592a556e75f5dcc2b7076
prerequisite-patch-id: df6dfdea7c3d9db4649d857ce55fbeb99d4febca
prerequisite-patch-id: 453b66b1faaaebaa1666954185de327298aa0578
prerequisite-patch-id: f98da1de781c203a53cae73c5bb707240d21cb0a
prerequisite-patch-id: 14b1718dbc4fb9cd94e1094a4d44ebfcfe6ad869
prerequisite-patch-id: 3b68944fa8fb2fab0c21d6ff73f649f53dd6f551
prerequisite-patch-id: 82d1e6bcd221f982b6ab1ed0e9a90d46a39562c4
prerequisite-patch-id: c9cce20b146f955b715d15c0c384c9acc6176493
prerequisite-patch-id: c204491c1db4f5056711768265f101e881e4e415
prerequisite-patch-id: e66e13fbde027e99552fc6d80ff8d48c110a18f2
prerequisite-patch-id: 3c313f0a20730c653c8f5ec4f318e2485a8ef60f
prerequisite-patch-id: 925c466172c01c4b5976ac019961cbe240f0cddd
prerequisite-patch-id: e81e0aded80adf18c861f67624a179a15ef68906
prerequisite-patch-id: 001675f7da57d25731c7c71f6f2dcaa7409e5664
prerequisite-patch-id: d65bf6ef5f51da0acba72d332d60167b34e193e1
prerequisite-patch-id: fc7c9a5024037363319b58520480a6c4a8a5dcff
prerequisite-patch-id: 5aae8c77d028459d944021f4943558411deb0662
prerequisite-patch-id: 71fa80813ad36528e8a737249424d90827933c16
prerequisite-patch-id: 65dc75b8e1ddb45542480a8867ecd7a63ab3112e
prerequisite-patch-id: 8619aa1dec17409d9b5ecb6ed0a2cc7d1563c174
prerequisite-patch-id: 6473142746dc5b448ec9698d577f47b4da6cd1d5
prerequisite-patch-id: eb6689695d5d1b6c650de0c86a805a45b80ab88d
prerequisite-patch-id: 7d50679dad38c9f859ec231da2db78919818b40e
prerequisite-patch-id: faeb97c5f9c07754bd0bf0be59254091470978c2
prerequisite-patch-id: 56e31c3ab9ed9ff19aca25d5ffb9655c6515b692
prerequisite-patch-id: 8d7418e017eec3c6e56b55f9ff6181cc3dcc1a17
prerequisite-patch-id: 84f58e5a274c980ae6905e764d479e1c960149ca
prerequisite-patch-id: ada6a2d9427bff9dd7fd115a91300a1f7379995c
prerequisite-patch-id: 108161d5500b39b3ac55d202b5b9af817d829724
prerequisite-patch-id: c89b0fc7dadc53facc45ccf9991503430b7e7799
prerequisite-patch-id: d62e2be8f9fd6a1d9ac8dfa2cdc4db6d4a4327ac
prerequisite-patch-id: f8f4375b2b16ffae596d416607c00b374f485299
prerequisite-patch-id: 36b1a9c3e0e9f91b7172e1211231759a6cb81473
prerequisite-patch-id: 8cb6ac6a5188c817bb3a6a86920001de75bb7225
prerequisite-patch-id: 17ef87336a8c664e0109a7466c9f7d37f5901167
prerequisite-patch-id: a2c72266baec1b3eb5706d43157d93ae8db5e42d
prerequisite-patch-id: 27503579f8bdfadb95847b8dd5bf3732f5149cfb
prerequisite-patch-id: 50d6d9c6ff0734705ae384ede694b547f4973249
prerequisite-patch-id: 81cd72752ab376d459dceff93f71715e55a55846
prerequisite-patch-id: 922cec7ef3d21275f5933968f5b704e0bed64ce5
prerequisite-patch-id: 1f0903e8846cd59d0d5a3dcbf9a5a82ad4dcb5cd
prerequisite-patch-id: 69d839b9d5b794ef1b7dee9c592ed20300f8539f
-- 
2.41.0





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

* [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer.
  2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (6 preceding siblings ...)
  2023-09-26 10:43   ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
@ 2023-10-14 15:48   ` Ludovic Courtès
  7 siblings, 0 replies; 95+ messages in thread
From: Ludovic Courtès @ 2023-10-14 15:48 UTC (permalink / raw)
  To: Nicolas Graves
  Cc: Josselin Poiret, Tobias Geerinckx-Rice, Simon Tournier,
	Mathieu Othacehe, 42338, Ricardo Wurmus, Christopher Baines

Hi Nicolas,

Nicolas Graves <ngraves@ngraves.fr> skribis:

> * guix/import/composer.scm: New file.
> * guix/scripts/import/composer.scm: New file.
> * guix/tests/composer.scm: New file.
> * Makefile.am: Add them.
> * guix/scripts/import.scm: Add composer importer.
> * doc/guix.texi (Invoking guix import): Mention it.

I’m a bit at loss with this patch series because there are two v3
threads, one v4 thread that contains a single patch, and the original
versions contained many more patches.

I think it’s OK to separate out the “gnu: Add php-*” patches, it’s
probably clearer.  However, could you come up with a v5 that includes
all the ‘guix import composer’ changes that we would need to apply?
How does that sound?

I have a couple of comments:

> +@item composer
> +@cindex Composer
> +@cindex PHP
> +Import metadat from the @uref{https://getcomposer.org/, Composer} package
                ^
Typo.

> +++ b/guix/import/composer.scm
> @@ -0,0 +1,270 @@
> +;;; GNU Guix --- Functional package management for GNU
> +;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>

Maybe add yourself too?

> +;; XXX adapted from (guix scripts hash)
> +(define (file-hash file select? recursive?)
> +  ;; Compute the hash of FILE.
> +  (if recursive?
> +      (let-values (((port get-hash) (open-sha256-port)))
> +        (write-file file port #:select? select?)
> +        (force-output port)
> +        (get-hash))
> +      (call-with-input-file file port-sha256)))
> +
> +;; XXX taken from (guix scripts hash)
> +(define (vcs-file? file stat)

These two procedures are now exported from (guix hash), so you can
remove them and #:use-module (guix hash) instead.

> +(define* (composer-fetch name #:optional version)
> +  "Return an alist representation of the Composer metadata for the package NAME,
> +or #f on failure."
> +  (let ((package (json-fetch
> +                   (string-append (%composer-base-url) "/p/" name ".json"))))
> +    (if package
> +        (let* ((packages (assoc-ref package "packages"))
> +               (package (or (assoc-ref packages name) package))
> +               (versions (filter
> +                           (lambda (version)
> +                             (and (not (string-contains version "dev"))
> +                                  (not (string-contains version "beta"))))
> +                           (map car package)))
> +               (version (or (if (null? version) #f version)
> +                            (latest-version versions))))
> +          (assoc-ref package version))

Instead of returning an alist, directly return a <composer-package>
record.

> +(define (php-package? package)
> +  "Return true if PACKAGE is a PHP package from Packagist."
> +  (and
> +    (eq? (build-system-name (package-build-system package)) 'composer)

Rather: (eq? (package-build-system package) composer-build-system).

(The ‘name’ field is for debugging purposes only.)

> +(define (latest-release package)
> +  "Return an <upstream-source> for the latest release of PACKAGE."
> +  (let* ((php-name (guix-package->composer-name package))
> +         (metadata (composer-fetch php-name))
> +         (package (json->composer-package metadata))
> +         (version (composer-package-version package))
> +         (url (composer-source-url (composer-package-source package))))
> +    (upstream-source
> +     (package (package-name package))
> +     (version version)
> +     (urls (list url)))))

Maybe we can do that later, but note that <upstream-source> has an
‘inputs’ field nowadays; if you feel it in, ‘guix refresh -u’ is able to
update dependencies in addition to version/hash.

(If you leave it for later, please add a TODO.)

> +;; Avoid collisions with other tests.
> +(%http-server-port 10450)

This is now unnecessary: by default a random unused port is chosen and
everything’s fine.

> +(test-begin "composer")
> +
> +(test-assert "composer->guix-package"
> +  ;; Replace network resources with sample data.
> +  (with-http-server `((200 ,test-json)
> +                      (200 ,test-source))
> +    (parameterize ((%composer-base-url (%local-url))
> +                   (current-http-proxy (%local-url)))
> +      (match (composer->guix-package "foo/bar")
> +        (('package
> +           ('name "php-foo-bar")
> +           ('version "0.1")

For clarity, you can write:

  (match …
    (`(package
        (name "php-foo-bar")
        (version "0.1")
        …) …))

See commit 654fcf9971bb01389d577be07c6ec0f68940c743.

> +           ('native-inputs
> +            ('quasiquote
> +             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))

Please change the importer so that it emits inputs without labels:

  (native-inputs (list php-phpunit-phpunit))

One last thing: consider adding an ‘etc/news.scm’ entry so people can
learn about the new importer.

Thanks in advance!

Ludo’.




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

* [bug#42338] [PATCH 0/9] Composer build system
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (7 preceding siblings ...)
  2023-09-26 11:29 ` [bug#42338] [PATCH v4] guix: composer-build-system: Fix match-lambda with a fallback Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04 ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (8 more replies)
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                   ` (2 subsequent siblings)
  11 siblings, 9 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

This is the result of my further rework of the composer import and
build-system. The `guix: import: composer` commits can be squashed
easily.

This is now tested on 94 php packages with all testing enabled except
for 3 packages. I will submit these packages as a whole in the
alphabetical order (the bootstrap order is not worth it IMO) in a new
guix issue.

Before accepting it, I also would like to propose a change of
names. If me make an analogy with python:
tool: pip <-> composer
package hub: pypi <-> packagist
build-system: python/pyproject <-> php

Since we only take about 90 lines of real composer code, I would
rather call the build-system php-build-system. 
Same thing: instead of `guix import composer` we should rather call
`guix import packagist`.

If that's OK, I'll change it with the next (and hopefully last!)
version of this build system.

Nicolas Graves (9):
  guix: import: Add composer importer.
  gnu: Add composer-classloader.
  guix: Add composer-build-system.
  guix: import: composer: Use memoization.
  guix: import: composer: Fix json->require.
  guix: import: composer: More robust string->license.
  guix: import: composer: Modern inputs formatting.
  guix: import: composer: Full rewrite composer-fetch.
  gnu: composer-build-system: Full check phase rewrite.

 Makefile.am                          |   6 +
 doc/guix.texi                        |  34 +++
 gnu/local.mk                         |   1 +
 gnu/packages/aux-files/findclass.php | 125 +++++++++++
 gnu/packages/php-xyz.scm             |  60 ++++++
 guix/build-system/composer.scm       | 164 +++++++++++++++
 guix/build/composer-build-system.scm | 300 +++++++++++++++++++++++++++
 guix/import/composer.scm             | 267 ++++++++++++++++++++++++
 guix/scripts/import.scm              |   2 +-
 guix/scripts/import/composer.scm     | 107 ++++++++++
 tests/composer.scm                   |  88 ++++++++
 11 files changed, 1153 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 gnu/packages/php-xyz.scm
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

-- 
2.41.0





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

* [bug#42338] [PATCH 1/9] guix: import: Add composer importer.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 2/9] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  20 +++
 guix/import/composer.scm         | 270 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 ++++++++++++
 tests/composer.scm               |  92 +++++++++++
 6 files changed, 493 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 310a231259..3fec98f064 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -274,6 +274,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -332,6 +333,7 @@ MODULES =					\
   guix/scripts/home/import.scm			\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cpan.scm			\
   guix/scripts/import/cran.scm			\
@@ -504,6 +506,7 @@ SCM_TESTS =					\
   tests/challenge.scm				\
   tests/channels.scm				\
   tests/combinators.scm			\
+  tests/composer.scm				\
   tests/containers.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 8c5697589f..0e64654715 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -14539,6 +14539,26 @@ guix import hexpm cf@@0.3.0
 
 Additional options include:
 
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
+@item composer
+@cindex Composer
+@cindex PHP
+Import metadat from the @uref{https://getcomposer.org/, Composer} package
+archive used by the PHP community, as in this example:
+
+@example
+guix import composer phpunit/phpunit
+@end example
+
+Additional options include:
+
 @table @code
 @item --recursive
 @itemx -r
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..c152f402bb
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,270 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import
+
+            %composer-base-url))
+
+(define %composer-base-url
+  (make-parameter "https://repo.packagist.org"))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b))
+        (car versions) versions))
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-source> make-composer-source composer-source?
+  json->composer-source
+  (type      composer-source-type)
+  (url       composer-source-url)
+  (reference composer-source-reference))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (description composer-package-description)
+  (homepage    composer-package-homepage)
+  (source      composer-package-source "source" json->composer-source)
+  (name        composer-package-name "name" php-package-name)
+  (version     composer-package-version "version" fix-version)
+  (require     composer-package-require "require" json->require)
+  (dev-require composer-package-dev-require "require-dev" json->require)
+  (license     composer-package-license "license"
+               (lambda (vector)
+                 (map string->license (vector->list vector)))))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append (%composer-base-url) "/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (or (assoc-ref packages name) package))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (version (or (if (null? version) #f version)
+                            (latest-version versions))))
+          (assoc-ref package version))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp composer-package)
+  "Return the `package' s-expression for a PHP package for the given
+COMPOSER-PACKAGE."
+  (let* ((source (composer-package-source composer-package))
+         (dependencies (map php-package-name
+                            (composer-package-require composer-package)))
+         (dev-dependencies (map php-package-name
+                                (composer-package-dev-require composer-package)))
+         (git? (equal? (composer-source-type source) "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (composer-source-url source)
+                             (composer-source-reference source)
+                             temp))
+                (url-fetch (composer-source-url source) temp))
+            `(package
+               (name ,(composer-package-name composer-package))
+               (version ,(composer-package-version composer-package))
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(composer-source-url source))
+                                        (commit ,(composer-source-reference source))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(composer-source-url source))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,(composer-package-description composer-package))
+               (home-page ,(composer-package-homepage composer-package))
+               (license ,(match (composer-package-license composer-package)
+                           (() #f)
+                           ((license) license)
+                           (_ license)))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((package (json->composer-package package))
+                (dependencies-names (composer-package-require package))
+                (dev-dependencies-names (composer-package-dev-require package)))
+           (values (make-php-sexp package)
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" 'license:lgpl2.0)
+    ("GPL" 'license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") 'license:expat)
+    ("Public domain" 'license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (package (json->composer-package metadata))
+         (version (composer-package-version package))
+         (url (composer-source-url (composer-package-source package))))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (import latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 4ddd8d46a1..8c58dd35e2 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -47,7 +47,7 @@ (define %standard-import-options '())
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
                     "gem" "go" "cran" "crate" "texlive" "json" "opam"
-                    "minetest" "elm" "hexpm"))
+                    "minetest" "elm" "hexpm" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/tests/composer.scm b/tests/composer.scm
new file mode 100644
index 0000000000..cefaf9f434
--- /dev/null
+++ b/tests/composer.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (test-composer)
+  #:use-module (guix import composer)
+  #:use-module (guix base32)
+  #:use-module (gcrypt hash)
+  #:use-module (guix tests http)
+  #:use-module (guix grafts)
+  #:use-module (srfi srfi-64)
+  #:use-module (web client)
+  #:use-module (ice-9 match))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define test-json
+  "{
+  \"packages\": {
+    \"foo/bar\": {
+      \"0.1\": {
+        \"name\": \"foo/bar\",
+        \"description\": \"description\",
+        \"keywords\": [\"testing\"],
+        \"homepage\": \"http://example.com\",
+        \"version\": \"0.1\",
+        \"license\": [\"BSD-3-Clause\"],
+        \"source\": {
+          \"type\": \"url\",
+          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
+        },
+        \"require\": {},
+        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
+      }
+    }
+  }
+}")
+
+(define test-source
+  "foobar")
+
+;; Avoid collisions with other tests.
+(%http-server-port 10450)
+
+(test-begin "composer")
+
+(test-assert "composer->guix-package"
+  ;; Replace network resources with sample data.
+  (with-http-server `((200 ,test-json)
+                      (200 ,test-source))
+    (parameterize ((%composer-base-url (%local-url))
+                   (current-http-proxy (%local-url)))
+      (match (composer->guix-package "foo/bar")
+        (('package
+           ('name "php-foo-bar")
+           ('version "0.1")
+           ('source ('origin
+                      ('method 'url-fetch)
+                      ('uri "http://example.com/Bar-0.1.tar.gz")
+                      ('sha256
+                       ('base32
+                        (? string? hash)))))
+           ('build-system 'composer-build-system)
+           ('native-inputs
+            ('quasiquote
+             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
+           ('synopsis "")
+           ('description "description")
+           ('home-page "http://example.com")
+           ('license 'license:bsd-3))
+         (string=? (bytevector->nix-base32-string
+                    (call-with-input-string test-source port-sha256))
+                   hash))
+        (x
+         (pk 'fail x #f))))))
+
+(test-end "composer")
-- 
2.41.0





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

* [bug#42338] [PATCH 2/9] gnu: Add composer-classloader.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 3/9] guix: Add composer-build-system Nicolas Graves via Guix-patches via
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* gnu/packages/php-xyz.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk             |  1 +
 gnu/packages/php-xyz.scm | 60 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 gnu/packages/php-xyz.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index 83b5268c7e..f1d16f873c 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -502,6 +502,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/photo.scm			\
   %D%/packages/phabricator.scm 			\
   %D%/packages/php.scm				\
+  %D%/packages/php-xyz.scm			\
   %D%/packages/piet.scm			\
   %D%/packages/pikchr.scm			\
   %D%/packages/pkg-config.scm			\
diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
new file mode 100644
index 0000000000..ac90ee3c25
--- /dev/null
+++ b/gnu/packages/php-xyz.scm
@@ -0,0 +1,60 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (gnu packages php-xyz)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages php)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system composer)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix utils)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public composer-classloader
+  (package
+    (name "composer-classloader")
+    (version "1.9.0")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/composer/composer")
+             (commit version)))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "0127zmmg3yx84ljngfs86q7kjhyypybkf4d1ihfrfnzgynzxfxdf"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (delete 'build)
+         (delete 'check)
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out")))
+               (install-file "src/Composer/Autoload/ClassLoader.php"
+                             (string-append out "/share/web/composer/"))))))))
+    (home-page "https://getcomposer.org")
+    (synopsis "PHP class loader extracted from the composer package")
+    (description "This package contains the class loader class used by Composer to
+build its autoloading feature.  This package is used by the composer-build-system
+to build its own store-aware autoloading feature.")
+    (license license:expat)))
-- 
2.41.0





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

* [bug#42338] [PATCH 3/9] guix: Add composer-build-system.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 2/9] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 4/9] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* gnu/packages/aux-files/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   3 +
 doc/guix.texi                        |  16 +-
 gnu/packages/aux-files/findclass.php | 125 ++++++++++++++
 guix/build-system/composer.scm       | 162 ++++++++++++++++++
 guix/build/composer-build-system.scm | 247 +++++++++++++++++++++++++++
 tests/composer.scm                   |  36 ++--
 6 files changed, 568 insertions(+), 21 deletions(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index 3fec98f064..47d1cb19ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -149,6 +149,7 @@ MODULES =					\
   guix/build-system/chicken.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/elm.scm			\
@@ -206,6 +207,7 @@ MODULES =					\
   guix/build/cargo-utils.scm			\
   guix/build/chicken-build-system.scm		\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/elm-build-system.scm		\
@@ -411,6 +413,7 @@ dist_noinst_DATA =				\
 AUX_FILES =						\
   gnu/packages/aux-files/chromium/master-preferences.json		\
   gnu/packages/aux-files/emacs/guix-emacs.el		\
+  gnu/packages/aux-files/findclass.php			\
   gnu/packages/aux-files/guix.vim			\
   gnu/packages/aux-files/linux-libre/6.5-arm.conf	\
   gnu/packages/aux-files/linux-libre/6.5-arm64.conf	\
diff --git a/doc/guix.texi b/doc/guix.texi
index 0e64654715..6a1c0aeaa5 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9554,6 +9554,20 @@ debugging information''), which roughly means that code is compiled with
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvar
 
+@defvar {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvar
+
 @defvar dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
@@ -14550,7 +14564,7 @@ in Guix.
 @item composer
 @cindex Composer
 @cindex PHP
-Import metadat from the @uref{https://getcomposer.org/, Composer} package
+Import metadata from the @uref{https://getcomposer.org/, Composer} package
 archive used by the PHP community, as in this example:
 
 @example
diff --git a/gnu/packages/aux-files/findclass.php b/gnu/packages/aux-files/findclass.php
new file mode 100644
index 0000000000..d0b250c8e1
--- /dev/null
+++ b/gnu/packages/aux-files/findclass.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * The content of this file is copied from composer's src/Composer/Autoload/ClassMapGenerator.php
+ * the findClasses method was extracted, to prevent using any dependency.
+ *
+ * Composer (and thus this file) is distributed under the expat license, and
+ * ClassMapGenerator.php also contains this notice:
+ *
+ *   This file is part of Composer.
+ *
+ *   (c) Nils Adermann <naderman@naderman.de>
+ *       Jordi Boggiano <j.boggiano@seld.be>
+ *
+ *   For the full copyright and license information, please view the LICENSE
+ *   file that was distributed with this source code.
+ *
+ *   This file is copied from the Symfony package.
+ *
+ *   (c) Fabien Potencier <fabien@symfony.com>
+ * 
+ * To the extent to wich it makes sense, as the author of the extract:
+ * Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+ */
+
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..8bf99ff9c5
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,162 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build union)
+    (json)
+    (json builder)
+    (json parser)
+    (json record)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build name inputs
+                         #:key
+                         guile source
+                         (outputs '("out"))
+                         (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags #~'("--strip-debug"))
+                         (strip-directories #~'("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build utils))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@(sexp->gexp modules))
+
+          #$(with-build-variables inputs outputs
+              #~(composer-build
+                 #:source #$source
+                 #:system #$system
+                 #:outputs %outputs
+                 #:inputs %build-inputs
+                 #:search-paths '#$(map search-path-specification->sexp
+                                        search-paths)
+                 #:phases #$phases
+                 #:out-of-source? #$out-of-source?
+                 #:composer-file #$composer-file
+                 #:tests? #$tests?
+                 #:test-target #$test-target
+                 #:install-target #$install-target
+                 #:validate-runpath? #$validate-runpath?
+                 #:patch-shebangs? #$patch-shebangs?
+                 #:strip-binaries? #$strip-binaries?
+                 #:strip-flags #$strip-flags
+                 #:strip-directories #$strip-directories)))))
+
+  (gexp->derivation name builder
+                    #:system system
+                    #:target #f
+                    #:graft? #f
+                    #:guile-for-build guile))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..bcbae27021
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,247 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (srfi srfi-26)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))
+          (_ result)))
+      '()))
+
+(define (if-specified-to-list fn)
+  (match-lambda
+    ((? unspecified?) '())
+    (arg (fn arg))
+    (_ '())))
+
+(define-json-mapping <composer-autoload> make-composer-autoload
+  composer-autoload?
+  json->composer-autoload
+  (psr-4 composer-autoload-psr-4 "psr-4" (if-specified-to-list identity))
+  (classmap composer-autoload-classmap "classmap"
+            (if-specified-to-list vector->list)))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (name         composer-package-name)
+  (autoload     composer-package-autoload "autoload"
+                (if-specified-to-list json->composer-autoload))
+  (autoload-dev composer-package-autoload-dev "autoload-dev"
+                (if-specified-to-list json->composer-autoload))
+  (require      composer-package-require "require" json->require)
+  (dev-require  composer-package-dev-require "require-dev" json->require)
+  (scripts      composer-package-scripts "scripts"
+                (if-specified-to-list identity))
+  (binaries     composer-package-binaries "bin"
+                (if-specified-to-list vector->list)))
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (json->composer-package (json->scm port)))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Test the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (composer-package-scripts package-data))
+           (test-script (assoc-ref scripts test-target))
+           (dependencies (composer-package-require package-data))
+           (dependencies-dev (composer-package-dev-require package-data))
+           (name (composer-package-name package-data)))
+      (for-each
+        (match-lambda
+          ((_ . input)
+           (let ((bin (find-php-bin input)))
+             (when bin
+               (copy-recursively bin "vendor/bin")))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (zero? (system command))
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (zero? (system c))
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit"))))))
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs inputs))
+    (match inputs
+      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
+                 dependency))
+      (((_ . input) inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop inputs))))
+      ((input inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+         (if (file-exists? autoload)
+             autoload
+             (loop inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  "creates an autoload.php file that sets up the class locations for this package,
+so it can be autoloaded by PHP when the package classes are required."
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (display (string-append
+                 "<?php
+// autoload.php @generated by Guix
+$map = $psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php'
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($map as $namespace => $path) {
+  $loader->set($namespace, $path);
+}
+foreach ($psr4map as $namespace => $path) {
+  $loader->setPsr4($namespace, $path);
+}
+$loader->addClassMap($classmap);
+$loader->register();
+"))))
+  ;; Now, create autoload_conf.php that contains the actual data, as a set
+  ;; of arrays
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload (composer-package-autoload package-data))
+         (autoload-dev (composer-package-autoload-dev package-data))
+         (dependencies (composer-package-require package-data))
+         (dependencies-dev (composer-package-dev-require package-data)))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (composer-autoload-psr-4 autoload)
+            (if dev-dependencies?
+                (composer-autoload-psr-4 autoload-dev)
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (composer-autoload-classmap autoload)
+            (if dev-dependencies?
+                (composer-autoload-classmap autoload-dev)
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (composer-package-name package-data))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (composer-package-binaries package-data)))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs)))
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
diff --git a/tests/composer.scm b/tests/composer.scm
index cefaf9f434..9114fef19e 100644
--- a/tests/composer.scm
+++ b/tests/composer.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -54,9 +55,6 @@ (define test-json
 (define test-source
   "foobar")
 
-;; Avoid collisions with other tests.
-(%http-server-port 10450)
-
 (test-begin "composer")
 
 (test-assert "composer->guix-package"
@@ -66,23 +64,21 @@ (define test-source
     (parameterize ((%composer-base-url (%local-url))
                    (current-http-proxy (%local-url)))
       (match (composer->guix-package "foo/bar")
-        (('package
-           ('name "php-foo-bar")
-           ('version "0.1")
-           ('source ('origin
-                      ('method 'url-fetch)
-                      ('uri "http://example.com/Bar-0.1.tar.gz")
-                      ('sha256
-                       ('base32
-                        (? string? hash)))))
-           ('build-system 'composer-build-system)
-           ('native-inputs
-            ('quasiquote
-             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
-           ('synopsis "")
-           ('description "description")
-           ('home-page "http://example.com")
-           ('license 'license:bsd-3))
+        (`(package
+            (name "php-foo-bar")
+            (version "0.1")
+            (source (origin
+                      (method url-fetch)
+                      (uri "http://example.com/Bar-0.1.tar.gz")
+                      (sha256
+                       (base32
+                        ,(? string? hash)))))
+            (build-system composer-build-system)
+            (native-inputs (list php-phpunit-phpunit))
+            (synopsis "")
+            (description "description")
+            (home-page "http://example.com")
+            (license license:bsd-3))
          (string=? (bytevector->nix-base32-string
                     (call-with-input-string test-source port-sha256))
                    hash))
-- 
2.41.0





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

* [bug#42338] [PATCH 4/9] guix: import: composer: Use memoization.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                     ` (2 preceding siblings ...)
  2023-11-02 15:04   ` [bug#42338] [PATCH 3/9] guix: Add composer-build-system Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 5/9] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

---
 guix/import/composer.scm | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index c152f402bb..177dc63092 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -27,6 +27,7 @@ (define-module (guix import composer)
   #:use-module (guix import json)
   #:use-module (guix import utils)
   #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix memoization)
   #:use-module (guix packages)
   #:use-module (guix serialization)
   #:use-module (guix upstream)
@@ -197,16 +198,18 @@ (define (make-php-sexp composer-package)
                            ((license) license)
                            (_ license)))))))))
 
-(define* (composer->guix-package package-name #:optional version)
-  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+(define composer->guix-package
+  (memoize
+   (lambda* (package-name #:key version #:allow-other-keys)
+     "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
 `package' s-expression corresponding to that package, or #f on failure."
-  (let ((package (composer-fetch package-name version)))
-    (and package
-         (let* ((package (json->composer-package package))
-                (dependencies-names (composer-package-require package))
-                (dev-dependencies-names (composer-package-dev-require package)))
-           (values (make-php-sexp package)
-                   (append dependencies-names dev-dependencies-names))))))
+     (let ((package (composer-fetch package-name version)))
+       (and package
+            (let* ((package (json->composer-package package))
+                   (dependencies-names (composer-package-require package))
+                   (dev-dependencies-names (composer-package-dev-require package)))
+              (values (make-php-sexp package)
+                      (append dependencies-names dev-dependencies-names))))))))
 
 (define (guix-name->composer-name name)
   "Given a guix package name, return the name of the package in Packagist."
@@ -265,6 +268,7 @@ (define %composer-updater
    (import latest-release)))
 
 (define* (composer-recursive-import package-name #:optional version)
-  (recursive-import package-name '()
+  (recursive-import package-name
+                    #:version version
                     #:repo->guix-package composer->guix-package
                     #:guix-name php-package-name))
-- 
2.41.0





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

* [bug#42338] [PATCH 5/9] guix: import: composer: Fix json->require.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                     ` (3 preceding siblings ...)
  2023-11-02 15:04   ` [bug#42338] [PATCH 4/9] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 6/9] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

---
 guix/import/composer.scm | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 177dc63092..3acbbecf82 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -88,7 +88,8 @@ (define (json->require dict)
           ((((? (cut string-contains <> "/") name) . _)
              require ...)
            (loop (cons name result) require))
-          ((_ require ...) (loop result require))))
+          ((_ require ...) (loop result require))
+          (_ result)))
       '()))
 
 (define-json-mapping <composer-source> make-composer-source composer-source?
-- 
2.41.0





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

* [bug#42338] [PATCH 6/9] guix: import: composer: More robust string->license.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                     ` (4 preceding siblings ...)
  2023-11-02 15:04   ` [bug#42338] [PATCH 5/9] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 7/9] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm (string->license): Use spdx-string->license. Fall
back to unknown-license!.
---
 guix/import/composer.scm | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 3acbbecf82..49f16caedf 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -109,7 +109,10 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
   (dev-require composer-package-dev-require "require-dev" json->require)
   (license     composer-package-license "license"
                (lambda (vector)
-                 (map string->license (vector->list vector)))))
+                 (let ((l (map string->license (vector->list vector))))
+                   (if (eq? (length l) 1)
+                       (car l)
+                       `(list ,@l))))))
 
 (define* (composer-fetch name #:optional version)
   "Return an alist representation of the Composer metadata for the package NAME,
@@ -194,10 +197,8 @@ (define (make-php-sexp composer-package)
                (synopsis "")
                (description ,(composer-package-description composer-package))
                (home-page ,(composer-package-homepage composer-package))
-               (license ,(match (composer-package-license composer-package)
-                           (() #f)
-                           ((license) license)
-                           (_ license)))))))))
+               (license ,(or (composer-package-license composer-package)
+                             'unknown-license!))))))))
 
 (define composer->guix-package
   (memoize
@@ -234,14 +235,15 @@ (define (guix-package->composer-name package)
 
 (define (string->license str)
   "Convert the string STR into a license object."
-  (match str
-    ("GNU LGPL" 'license:lgpl2.0)
-    ("GPL" 'license:gpl3)
-    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
-    ((or "MIT" "MIT license" "Expat license") 'license:expat)
-    ("Public domain" 'license:public-domain)
-    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
-    (_ #f)))
+  (or (spdx-string->license str)
+      (match str
+        ("GNU LGPL" 'license:lgpl2.0)
+        ("GPL" 'license:gpl3)
+        ((or "BSD" "BSD License") 'license:bsd-3)
+        ((or "MIT" "MIT license" "Expat license") 'license:expat)
+        ("Public domain" 'license:public-domain)
+        ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+        (_ 'unknown-license!))))
 
 (define (php-package? package)
   "Return true if PACKAGE is a PHP package from Packagist."
-- 
2.41.0





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

* [bug#42338] [PATCH 7/9] guix: import: composer: Modern inputs formatting.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                     ` (5 preceding siblings ...)
  2023-11-02 15:04   ` [bug#42338] [PATCH 6/9] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 8/9] guix: import: composer: Full rewrite composer-fetch Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 9/9] gnu: composer-build-system: Full check phase rewrite Nicolas Graves via Guix-patches via
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm (make-php-sexp): Update inputs formatting.
---
 guix/import/composer.scm | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 49f16caedf..89c8ea9113 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -179,21 +179,11 @@ (define (make-php-sexp composer-package)
                ,@(if (null? dependencies)
                      '()
                      `((inputs
-                        (,'quasiquote
-                         ,(map (lambda (name)
-                                 `(,name
-                                   (,'unquote
-                                    ,(string->symbol name))))
-                               dependencies)))))
+                        (list ,@(map string->symbol dependencies)))))
                ,@(if (null? dev-dependencies)
                      '()
                      `((native-inputs
-                        (,'quasiquote
-                         ,(map (lambda (name)
-                                 `(,name
-                                   (,'unquote
-                                    ,(string->symbol name))))
-                               dev-dependencies)))))
+                        (list ,@(map string->symbol dev-dependencies)))))
                (synopsis "")
                (description ,(composer-package-description composer-package))
                (home-page ,(composer-package-homepage composer-package))
-- 
2.41.0





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

* [bug#42338] [PATCH 8/9] guix: import: composer: Full rewrite composer-fetch.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                     ` (6 preceding siblings ...)
  2023-11-02 15:04   ` [bug#42338] [PATCH 7/9] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:04   ` [bug#42338] [PATCH 9/9] gnu: composer-build-system: Full check phase rewrite Nicolas Graves via Guix-patches via
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

Change-Id: I1c01c242cefe0bc4cfc9bd9a5717d10a61dd575e
---
 guix/import/composer.scm | 154 +++++++++++++++++++--------------------
 1 file changed, 77 insertions(+), 77 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 89c8ea9113..2cc8861bdd 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -19,7 +19,7 @@
 (define-module (guix import composer)
   #:use-module (ice-9 match)
   #:use-module (json)
-  #:use-module (gcrypt hash)
+  #:use-module (guix hash)
   #:use-module (guix base32)
   #:use-module (guix build git)
   #:use-module (guix build utils)
@@ -44,27 +44,6 @@ (define-module (guix import composer)
 (define %composer-base-url
   (make-parameter "https://repo.packagist.org"))
 
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file select? recursive?)
-  ;; Compute the hash of FILE.
-  (if recursive?
-      (let-values (((port get-hash) (open-sha256-port)))
-        (write-file file port #:select? select?)
-        (force-output port)
-        (get-hash))
-      (call-with-input-file file port-sha256)))
-
-;; XXX taken from (guix scripts hash)
-(define (vcs-file? file stat)
-  (case (stat:type stat)
-    ((directory)
-     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
-    ((regular)
-     ;; Git sub-modules have a '.git' file that is a regular text file.
-     (string=? (basename file) ".git"))
-    (else
-     #f)))
-
 (define (fix-version version)
   "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
   (cond
@@ -114,22 +93,36 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
                        (car l)
                        `(list ,@l))))))
 
-(define* (composer-fetch name #:optional version)
-  "Return an alist representation of the Composer metadata for the package NAME,
-or #f on failure."
-  (let ((package (json-fetch
-                   (string-append (%composer-base-url) "/p/" name ".json"))))
-    (if package
-        (let* ((packages (assoc-ref package "packages"))
-               (package (or (assoc-ref packages name) package))
-               (versions (filter
-                           (lambda (version)
-                             (and (not (string-contains version "dev"))
-                                  (not (string-contains version "beta"))))
-                           (map car package)))
-               (version (or (if (null? version) #f version)
-                            (latest-version versions))))
-          (assoc-ref package version))
+(define (valid-version? v)
+  (let ((d (string-downcase v)))
+    (and (not (string-contains d "dev"))
+         (not (string-contains d "beta"))
+         (not (string-contains d "rc")))))
+
+(define* (composer-fetch name #:key (version #f))
+  "Return a composer-package representation of the Composer metadata for the
+package NAME with optional VERSION, or #f on failure."
+  (let* ((url (string-append (%composer-base-url) "/p/" name ".json"))
+         (packages (and=> (json-fetch url)
+                          (lambda (pkg)
+                            (let ((pkgs (assoc-ref pkg "packages")))
+                              (or (assoc-ref pkgs name) pkg))))))
+    (if packages
+        (json->composer-package
+         (if version
+             (assoc-ref packages version)
+             (cdr
+              (reduce
+               (lambda (new cur-max)
+                 (match new
+                   (((? valid-version? version) . tail)
+                    (if (version>? (fix-version version)
+                                   (fix-version (car cur-max)))
+                        (cons* version tail)
+                        cur-max))
+                   (_ cur-max)))
+               (cons* "0.0.0" #f)
+               packages))))
         #f)))
 
 (define (php-package-name name)
@@ -158,47 +151,55 @@ (define (make-php-sexp composer-package)
                              (composer-source-reference source)
                              temp))
                 (url-fetch (composer-source-url source) temp))
-            `(package
-               (name ,(composer-package-name composer-package))
-               (version ,(composer-package-version composer-package))
-               (source (origin
-                         ,@(if git?
-                               `((method git-fetch)
-                                 (uri (git-reference
-                                        (url ,(composer-source-url source))
-                                        (commit ,(composer-source-reference source))))
-                                 (file-name (git-file-name name version))
-                                 (sha256
-                                   (base32
-                                     ,(bytevector->nix-base32-string
-                                       (file-hash temp (negate vcs-file?) #t)))))
-                               `((method url-fetch)
-                                 (uri ,(composer-source-url source))
-                                 (sha256 (base32 ,(guix-hash-url temp)))))))
-               (build-system composer-build-system)
-               ,@(if (null? dependencies)
-                     '()
-                     `((inputs
-                        (list ,@(map string->symbol dependencies)))))
-               ,@(if (null? dev-dependencies)
-                     '()
-                     `((native-inputs
-                        (list ,@(map string->symbol dev-dependencies)))))
-               (synopsis "")
-               (description ,(composer-package-description composer-package))
-               (home-page ,(composer-package-homepage composer-package))
-               (license ,(or (composer-package-license composer-package)
-                             'unknown-license!))))))))
+            `(define-public ,(string->symbol
+                              (composer-package-name composer-package))
+               (package
+                 (name ,(composer-package-name composer-package))
+                 (version ,(composer-package-version composer-package))
+                 (source
+                  (origin
+                    ,@(if git?
+                          `((method git-fetch)
+                            (uri (git-reference
+                                  (url ,(if (string-suffix?
+                                             ".git"
+                                             (composer-source-url source))
+                                            (string-drop-right
+                                             (composer-source-url source)
+                                             (string-length ".git"))
+                                            (composer-source-url source)))
+                                  (commit ,(composer-source-reference source))))
+                            (file-name (git-file-name name version))
+                            (sha256
+                             (base32
+                              ,(bytevector->nix-base32-string
+                                (file-hash* temp)))))
+                          `((method url-fetch)
+                            (uri ,(composer-source-url source))
+                            (sha256 (base32 ,(guix-hash-url temp)))))))
+                 (build-system composer-build-system)
+                 ,@(if (null? dependencies)
+                       '()
+                       `((inputs
+                          (list ,@(map string->symbol dependencies)))))
+                 ,@(if (null? dev-dependencies)
+                       '()
+                       `((native-inputs
+                          (list ,@(map string->symbol dev-dependencies)))))
+                 (synopsis "")
+                 (description ,(composer-package-description composer-package))
+                 (home-page ,(composer-package-homepage composer-package))
+                 (license ,(or (composer-package-license composer-package)
+                               'unknown-license!)))))))))
 
 (define composer->guix-package
   (memoize
-   (lambda* (package-name #:key version #:allow-other-keys)
+   (lambda* (package-name #:key (version #f) #:allow-other-keys)
      "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
 `package' s-expression corresponding to that package, or #f on failure."
-     (let ((package (composer-fetch package-name version)))
+     (let ((package (composer-fetch package-name #:version version)))
        (and package
-            (let* ((package (json->composer-package package))
-                   (dependencies-names (composer-package-require package))
+            (let* ((dependencies-names (composer-package-require package))
                    (dev-dependencies-names (composer-package-dev-require package)))
               (values (make-php-sexp package)
                       (append dependencies-names dev-dependencies-names))))))))
@@ -238,14 +239,13 @@ (define (string->license str)
 (define (php-package? package)
   "Return true if PACKAGE is a PHP package from Packagist."
   (and
-    (eq? (build-system-name (package-build-system package)) 'composer)
-    (string-prefix? "php-" (package-name package))))
+   (eq? (package-build-system package) composer-build-system)
+   (string-prefix? "php-" (package-name package))))
 
 (define (latest-release package)
   "Return an <upstream-source> for the latest release of PACKAGE."
   (let* ((php-name (guix-package->composer-name package))
-         (metadata (composer-fetch php-name))
-         (package (json->composer-package metadata))
+         (package (composer-fetch php-name))
          (version (composer-package-version package))
          (url (composer-source-url (composer-package-source package))))
     (upstream-source
-- 
2.41.0





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

* [bug#42338] [PATCH 9/9] gnu: composer-build-system: Full check phase rewrite.
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
                     ` (7 preceding siblings ...)
  2023-11-02 15:04   ` [bug#42338] [PATCH 8/9] guix: import: composer: Full rewrite composer-fetch Nicolas Graves via Guix-patches via
@ 2023-11-02 15:04   ` Nicolas Graves via Guix-patches via
  8 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:04 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

Change-Id: I824b27b925cd718ee83ef6b2ee4a8a1e69455de6
---
 guix/build-system/composer.scm       |   2 +
 guix/build/composer-build-system.scm | 239 ++++++++++++++++-----------
 2 files changed, 148 insertions(+), 93 deletions(-)

diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
index 8bf99ff9c5..7d2ad2b398 100644
--- a/guix/build-system/composer.scm
+++ b/guix/build-system/composer.scm
@@ -107,6 +107,7 @@ (define* (composer-build name inputs
                          (composer-file "composer.json")
                          (tests? #t)
                          (test-target "test")
+                         (test-flags ''())
                          (install-target "install")
                          (validate-runpath? #t)
                          (patch-shebangs? #t)
@@ -140,6 +141,7 @@ (define builder
                  #:composer-file #$composer-file
                  #:tests? #$tests?
                  #:test-target #$test-target
+                 #:test-flags #$test-flags
                  #:install-target #$install-target
                  #:validate-runpath? #$validate-runpath?
                  #:patch-shebangs? #$patch-shebangs?
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
index bcbae27021..6f05801ad1 100644
--- a/guix/build/composer-build-system.scm
+++ b/guix/build/composer-build-system.scm
@@ -53,9 +53,22 @@ (define (if-specified-to-list fn)
 (define-json-mapping <composer-autoload> make-composer-autoload
   composer-autoload?
   json->composer-autoload
-  (psr-4 composer-autoload-psr-4 "psr-4" (if-specified-to-list identity))
+  (psr-4 composer-autoload-psr-4 "psr-4"
+         (match-lambda
+           ((? unspecified?) '())
+           ((? (lambda (al)
+                 (and (list? al) (pair? (car al)) (vector? (cdar al)))) al)
+            (append-map
+             (lambda (vect-el)
+               (list (cons (caar al) vect-el)))
+             (vector->list (cdar al))))
+           ((? list? l)                  l)
+           (_                           '())))
+  (psr-0 composer-autoload-psr-0 "psr-0" (if-specified-to-list identity))
   (classmap composer-autoload-classmap "classmap"
-            (if-specified-to-list vector->list)))
+            (if-specified-to-list vector->list))
+  (files composer-autoload-files "files"
+         (if-specified-to-list vector->list)))
 
 (define-json-mapping <composer-package> make-composer-package composer-package?
   json->composer-package
@@ -76,65 +89,57 @@ (define* (read-package-data #:key (filename "composer.json"))
     (lambda (port)
       (json->composer-package (json->scm port)))))
 
-(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
-  "Test the given package."
+(define* (create-test-autoload #:key composer-file inputs outputs tests?
+                               #:allow-other-keys)
+  "Create the autoload.php file for tests.  This is a standalone phase so that
+the autoload.php file can be edited before the check phase."
   (when tests?
     (mkdir-p "vendor")
     (create-autoload (string-append (getcwd) "/vendor") composer-file
-                     (append inputs outputs) #:dev-dependencies? #t)
-    (let* ((package-data (read-package-data #:filename composer-file))
-           (scripts (composer-package-scripts package-data))
-           (test-script (assoc-ref scripts test-target))
-           (dependencies (composer-package-require package-data))
-           (dependencies-dev (composer-package-dev-require package-data))
-           (name (composer-package-name package-data)))
-      (for-each
-        (match-lambda
-          ((_ . input)
-           (let ((bin (find-php-bin input)))
-             (when bin
-               (copy-recursively bin "vendor/bin")))))
-        inputs)
-      (match test-script
-        ((? string? command)
-         (unless (zero? (system command))
-           (throw 'failed-command command)))
-        (('@ (? string? command) ...)
-         (for-each
-           (lambda (c)
-             (unless (zero? (system c))
-               (throw 'failed-command c)))
-           command))
-        (#f (invoke "vendor/bin/phpunit"))))))
+                     inputs #:dev-dependencies? #t)))
 
-(define (find-php-bin input)
-  (let* ((web-dir (string-append input "/share/web"))
-         (vendors (if (file-exists? web-dir)
-                      (find-files web-dir "^vendor$" #:directories? #t)
-                      #f)))
-    (match vendors
-      ((vendor)
-       (let ((bin (string-append vendor "/bin")))
-         (and (file-exists? bin) bin)))
-      (_ #f))))
+(define (find-bin script inputs)
+  (search-input-file inputs
+                     (string-append
+                      "bin/"
+                      (string-drop script (string-length "vendor/bin/")))))
 
-(define (find-php-dep inputs dependency)
-  (let loop ((inputs inputs))
-    (match inputs
-      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
-                 dependency))
-      (((_ . input) inputs ...)
-       (let ((autoload (string-append input "/share/web/" dependency
-                                      "/vendor/autoload_conf.php")))
-          (if (file-exists? autoload)
-              autoload
-              (loop inputs))))
-      ((input inputs ...)
-       (let ((autoload (string-append input "/share/web/" dependency
-                                      "/vendor/autoload_conf.php")))
-         (if (file-exists? autoload)
-             autoload
-             (loop inputs)))))))
+(define* (check #:key composer-file inputs
+                tests? test-target test-flags #:allow-other-keys)
+  "Test the given package.
+Please note that none of the PHP packages at the time of the rewrite of the
+build-system did use the test-script field.  This means that the @code{match
+test-script} part is not tested on a real example and relies on the original
+implementation."
+  (if tests?
+      (let* ((package-data (read-package-data #:filename composer-file))
+             (scripts (composer-package-scripts package-data))
+             (test-script (assoc-ref scripts test-target)))
+        (match test-script
+          ((? string? bin)
+           (let ((command (find-bin bin inputs)))
+             (unless (zero? (apply system command test-flags))
+               (throw 'failed-command command))))
+          (('@ (? string? bins) ...)
+           (for-each
+            (lambda (c)
+              (let ((command (find-bin bin inputs)))
+                (unless (zero? (apply system command test-flags))
+                  (throw 'failed-command command))))
+            bins))
+          (_ (if (file-exists? "phpunit.xml.dist")
+                 (apply invoke
+                        (with-exception-handler
+                            (lambda (exn)
+                              (if (search-error? exn)
+                                  (error "\
+Missing php-phpunit-phpunit native input.~%")
+                                  (raise exn)))
+                          (lambda ()
+                            (search-input-file (or inputs '()) "bin/phpunit")))
+                        test-flags))
+             (format #t "No test suite found.~%"))))
+      (format #t "Test suite not run.~%")))
 
 (define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
   "creates an autoload.php file that sets up the class locations for this package,
@@ -144,15 +149,14 @@ (define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
       (display (string-append
                  "<?php
 // autoload.php @generated by Guix
-$map = $psr4map = $classmap = array();
-require_once '" vendor "/autoload_conf.php'
-require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php';
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php';
 $loader = new \\Composer\\Autoload\\ClassLoader();
-foreach ($map as $namespace => $path) {
-  $loader->set($namespace, $path);
-}
-foreach ($psr4map as $namespace => $path) {
-  $loader->setPsr4($namespace, $path);
+foreach ($psr4map as $namespace => $paths) {
+    foreach ($paths as $path) {
+        $loader->addPsr4($namespace, $path);
+    }
 }
 $loader->addClassMap($classmap);
 $loader->register();
@@ -170,37 +174,85 @@ (define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
         (format #t "// autoload_conf.php @generated by Guix~%")
         (force-output)
         (for-each
-          (lambda (psr4)
-            (match psr4
-              ((key . value)
-               (format #t "$psr4map['~a'] = '~a/../~a';~%"
-                       (string-join (string-split key #\\) "\\\\")
-                       vendor value))))
+         (match-lambda
+           ((key . value)
+            (let ((vals (if (list? value)
+                            (reverse value)
+                            (list value))))
+              (apply
+               format
+               #t
+               (string-append
+                "$psr4map['~a'][] = ["
+                (string-join
+                 (make-list (length vals) "'~a/../~a'") ",")
+                "];~%")
+               (cons* (string-join (string-split key #\\) "\\\\")
+                      (append-map (lambda (v) (list vendor v)) vals)))))
+           (_ (format #t "")))
+         (merge-duplicates
           (append
-            (composer-autoload-psr-4 autoload)
-            (if dev-dependencies?
-                (composer-autoload-psr-4 autoload-dev)
-                '())))
+           (composer-autoload-psr-4 autoload)
+           (if (and dev-dependencies? (not (null? autoload-dev)))
+               (composer-autoload-psr-4 autoload-dev)
+               '()))
+          '()))
         (for-each
-          (lambda (classmap)
-            (for-each
-              (lambda (file)
-                (invoke "php" (assoc-ref inputs "findclass.php")
-                        "-i" (string-append vendor "/..") "-f" file))
-              (find-files classmap ".(php|hh|inc)$")))
-          (append
-            (composer-autoload-classmap autoload)
-            (if dev-dependencies?
-                (composer-autoload-classmap autoload-dev)
-                '())))
+         (lambda (psr0)
+           (match psr0
+             ((key . value)
+              (format #t "$psr4map['~a'][] = ['~a/../~a/~a'];~%"
+                      (string-join (string-split key #\\) "\\\\")
+                      vendor
+                      value
+                      (string-join (string-split key #\\) "/")))
+             (_ (format #t ""))))
+         (append
+          (composer-autoload-psr-0 autoload)
+          (if (and dev-dependencies? (not (null? autoload-dev)))
+              (composer-autoload-psr-0 autoload-dev)
+              '())))
         (for-each
-          (lambda (dep)
-            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
-          (append
-            dependencies
-            (if dev-dependencies?
-                dependencies-dev
-                '())))))))
+         (lambda (classmap)
+           (for-each
+            (lambda (file)
+              (invoke "php" (assoc-ref inputs "findclass.php")
+                      "-i" (string-append vendor "/..") "-f" file))
+            (find-files classmap ".(php|hh|inc)$")))
+         (append
+          (composer-autoload-classmap autoload)
+          (if (and dev-dependencies? (not (null? autoload-dev)))
+              (composer-autoload-classmap autoload-dev)
+              '())))
+        (for-each
+         (lambda (file)
+           (format #t "require_once '~a/../~a';~%" vendor file))
+         (append
+          (composer-autoload-files autoload)
+          (if (and dev-dependencies? (not (null? autoload-dev)))
+              (composer-autoload-files autoload-dev)
+              '())))
+        (for-each
+         (lambda (dep)
+           (format
+            #t "require_once '~a';~%"
+            (search-input-file
+             inputs
+             (string-append "/share/web/" dep "/vendor/autoload_conf.php"))))
+          dependencies)
+        ;; Also add native-inputs that are not necessarily given in the
+        ;; composer.json. This allows to simply add a package in tests by
+        ;; adding it in native-inputs, without the need to patch composer.json.
+        (for-each
+         (match-lambda
+           ((name . loc)
+            (match (find-files loc "autoload_conf\\.php$")
+              (() #t)
+              (((? string? conf) . ())
+               (format #t "require_once '~a';~%" conf))
+              (_ #t)))
+           (_ #t))
+         (or inputs '()))))))
 
 (define* (install #:key inputs outputs composer-file #:allow-other-keys)
   "Install the given package."
@@ -237,7 +289,8 @@ (define %standard-phases
     (delete 'build)
     (delete 'check)
     (replace 'install install)
-    (add-after 'install 'check check)))
+    (add-after 'install 'check check)
+    (add-after 'install 'create-test-autoload create-test-autoload)))
 
 (define* (composer-build #:key inputs (phases %standard-phases)
                          #:allow-other-keys #:rest args)
-- 
2.41.0





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

* [bug#42338] [PATCH v5 0/9] Composer build-system
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (8 preceding siblings ...)
  2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16 ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
                     ` (10 more replies)
  2023-12-09 22:00 ` [bug#42338] [PATCH] Add composer build system (PHP) Charlie McMackin
  2023-12-20 10:41 ` Wilko Meyer
  11 siblings, 11 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

This is the result of my further rework of the composer import and
build-system. The `guix: import: composer` commits can be squashed
easily.

This is now tested on 94 php packages with all testing enabled except
for 3 packages. I will submit these packages as a whole in the
alphabetical order (the bootstrap order is not worth it IMO) in a new
guix issue.

Before accepting it, I also would like to propose a change of
names. If me make an analogy with python:
tool: pip <-> composer
package hub: pypi <-> packagist
build-system: python/pyproject <-> php

Since we only take about 90 lines of real composer code, I would
rather call the build-system php-build-system. 
Same thing: instead of `guix import composer` we should rather call
`guix import packagist`.

If that's OK, I'll change it with the next (and hopefully last!)
version of this build system.

Nicolas Graves (9):
  guix: import: Add composer importer.
  gnu: Add composer-classloader.
  guix: Add composer-build-system.
  guix: import: composer: Use memoization.
  guix: import: composer: Fix json->require.
  guix: import: composer: More robust string->license.
  guix: import: composer: Modern inputs formatting.
  guix: import: composer: Full rewrite composer-fetch.
  gnu: composer-build-system: Full check phase rewrite.

 Makefile.am                          |   6 +
 doc/guix.texi                        |  34 +++
 gnu/local.mk                         |   1 +
 gnu/packages/aux-files/findclass.php | 125 +++++++++++
 gnu/packages/php-xyz.scm             |  60 ++++++
 guix/build-system/composer.scm       | 164 +++++++++++++++
 guix/build/composer-build-system.scm | 300 +++++++++++++++++++++++++++
 guix/import/composer.scm             | 267 ++++++++++++++++++++++++
 guix/scripts/import.scm              |   2 +-
 guix/scripts/import/composer.scm     | 107 ++++++++++
 tests/composer.scm                   |  88 ++++++++
 11 files changed, 1153 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 gnu/packages/php-xyz.scm
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

-- 
2.41.0





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

* [bug#42338] [PATCH v5 1/9] guix: import: Add composer importer.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 2/9] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm: New file.
* guix/scripts/import/composer.scm: New file.
* guix/tests/composer.scm: New file.
* Makefile.am: Add them.
* guix/scripts/import.scm: Add composer importer.
* doc/guix.texi (Invoking guix import): Mention it.
---
 Makefile.am                      |   3 +
 doc/guix.texi                    |  20 +++
 guix/import/composer.scm         | 270 +++++++++++++++++++++++++++++++
 guix/scripts/import.scm          |   2 +-
 guix/scripts/import/composer.scm | 107 ++++++++++++
 tests/composer.scm               |  92 +++++++++++
 6 files changed, 493 insertions(+), 1 deletion(-)
 create mode 100644 guix/import/composer.scm
 create mode 100644 guix/scripts/import/composer.scm
 create mode 100644 tests/composer.scm

diff --git a/Makefile.am b/Makefile.am
index 310a231259..3fec98f064 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -274,6 +274,7 @@ MODULES =					\
   guix/search-paths.scm				\
   guix/packages.scm				\
   guix/import/cabal.scm				\
+  guix/import/composer.scm			\
   guix/import/cpan.scm				\
   guix/import/cran.scm				\
   guix/import/crate.scm				\
@@ -332,6 +333,7 @@ MODULES =					\
   guix/scripts/home/import.scm			\
   guix/scripts/lint.scm				\
   guix/scripts/challenge.scm			\
+  guix/scripts/import/composer.scm		\
   guix/scripts/import/crate.scm			\
   guix/scripts/import/cpan.scm			\
   guix/scripts/import/cran.scm			\
@@ -504,6 +506,7 @@ SCM_TESTS =					\
   tests/challenge.scm				\
   tests/channels.scm				\
   tests/combinators.scm			\
+  tests/composer.scm				\
   tests/containers.scm				\
   tests/cpan.scm				\
   tests/cpio.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 8c5697589f..0e64654715 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -14539,6 +14539,26 @@ guix import hexpm cf@@0.3.0
 
 Additional options include:
 
+@table @code
+@item --recursive
+@itemx -r
+Traverse the dependency graph of the given upstream package recursively
+and generate package expressions for all those packages that are not yet
+in Guix.
+@end table
+
+@item composer
+@cindex Composer
+@cindex PHP
+Import metadat from the @uref{https://getcomposer.org/, Composer} package
+archive used by the PHP community, as in this example:
+
+@example
+guix import composer phpunit/phpunit
+@end example
+
+Additional options include:
+
 @table @code
 @item --recursive
 @itemx -r
diff --git a/guix/import/composer.scm b/guix/import/composer.scm
new file mode 100644
index 0000000000..c152f402bb
--- /dev/null
+++ b/guix/import/composer.scm
@@ -0,0 +1,270 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 composer)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (gcrypt hash)
+  #:use-module (guix base32)
+  #:use-module (guix build git)
+  #:use-module (guix build utils)
+  #:use-module (guix build-system)
+  #:use-module (guix import json)
+  #:use-module (guix import utils)
+  #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix packages)
+  #:use-module (guix serialization)
+  #:use-module (guix upstream)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-26)
+  #:export (composer->guix-package
+            %composer-updater
+            composer-recursive-import
+
+            %composer-base-url))
+
+(define %composer-base-url
+  (make-parameter "https://repo.packagist.org"))
+
+;; XXX adapted from (guix scripts hash)
+(define (file-hash file select? recursive?)
+  ;; Compute the hash of FILE.
+  (if recursive?
+      (let-values (((port get-hash) (open-sha256-port)))
+        (write-file file port #:select? select?)
+        (force-output port)
+        (get-hash))
+      (call-with-input-file file port-sha256)))
+
+;; XXX taken from (guix scripts hash)
+(define (vcs-file? file stat)
+  (case (stat:type stat)
+    ((directory)
+     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
+    ((regular)
+     ;; Git sub-modules have a '.git' file that is a regular text file.
+     (string=? (basename file) ".git"))
+    (else
+     #f)))
+
+(define (fix-version version)
+  "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
+  (cond
+    ((string-prefix? "version" version)
+     (if (char-set-contains? char-set:digit (string-ref version 7))
+         (substring version 7)
+         (substring version 8)))
+    ((string-prefix? "v" version)
+     (substring version 1))
+    (else version)))
+
+(define (latest-version versions)
+  (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b))
+        (car versions) versions))
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))))
+      '()))
+
+(define-json-mapping <composer-source> make-composer-source composer-source?
+  json->composer-source
+  (type      composer-source-type)
+  (url       composer-source-url)
+  (reference composer-source-reference))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (description composer-package-description)
+  (homepage    composer-package-homepage)
+  (source      composer-package-source "source" json->composer-source)
+  (name        composer-package-name "name" php-package-name)
+  (version     composer-package-version "version" fix-version)
+  (require     composer-package-require "require" json->require)
+  (dev-require composer-package-dev-require "require-dev" json->require)
+  (license     composer-package-license "license"
+               (lambda (vector)
+                 (map string->license (vector->list vector)))))
+
+(define* (composer-fetch name #:optional version)
+  "Return an alist representation of the Composer metadata for the package NAME,
+or #f on failure."
+  (let ((package (json-fetch
+                   (string-append (%composer-base-url) "/p/" name ".json"))))
+    (if package
+        (let* ((packages (assoc-ref package "packages"))
+               (package (or (assoc-ref packages name) package))
+               (versions (filter
+                           (lambda (version)
+                             (and (not (string-contains version "dev"))
+                                  (not (string-contains version "beta"))))
+                           (map car package)))
+               (version (or (if (null? version) #f version)
+                            (latest-version versions))))
+          (assoc-ref package version))
+        #f)))
+
+(define (php-package-name name)
+  "Given the NAME of a package on Packagist, return a Guix-compliant name for
+the package."
+  (let ((name (string-join (string-split name #\/) "-")))
+    (if (string-prefix? "php-" name)
+        (snake-case name)
+        (string-append "php-" (snake-case name)))))
+
+(define (make-php-sexp composer-package)
+  "Return the `package' s-expression for a PHP package for the given
+COMPOSER-PACKAGE."
+  (let* ((source (composer-package-source composer-package))
+         (dependencies (map php-package-name
+                            (composer-package-require composer-package)))
+         (dev-dependencies (map php-package-name
+                                (composer-package-dev-require composer-package)))
+         (git? (equal? (composer-source-type source) "git")))
+    ((if git? call-with-temporary-directory call-with-temporary-output-file)
+     (lambda* (temp #:optional port)
+       (and (if git?
+                (begin
+                  (mkdir-p temp)
+                  (git-fetch (composer-source-url source)
+                             (composer-source-reference source)
+                             temp))
+                (url-fetch (composer-source-url source) temp))
+            `(package
+               (name ,(composer-package-name composer-package))
+               (version ,(composer-package-version composer-package))
+               (source (origin
+                         ,@(if git?
+                               `((method git-fetch)
+                                 (uri (git-reference
+                                        (url ,(composer-source-url source))
+                                        (commit ,(composer-source-reference source))))
+                                 (file-name (git-file-name name version))
+                                 (sha256
+                                   (base32
+                                     ,(bytevector->nix-base32-string
+                                       (file-hash temp (negate vcs-file?) #t)))))
+                               `((method url-fetch)
+                                 (uri ,(composer-source-url source))
+                                 (sha256 (base32 ,(guix-hash-url temp)))))))
+               (build-system composer-build-system)
+               ,@(if (null? dependencies)
+                     '()
+                     `((inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dependencies)))))
+               ,@(if (null? dev-dependencies)
+                     '()
+                     `((native-inputs
+                        (,'quasiquote
+                         ,(map (lambda (name)
+                                 `(,name
+                                   (,'unquote
+                                    ,(string->symbol name))))
+                               dev-dependencies)))))
+               (synopsis "")
+               (description ,(composer-package-description composer-package))
+               (home-page ,(composer-package-homepage composer-package))
+               (license ,(match (composer-package-license composer-package)
+                           (() #f)
+                           ((license) license)
+                           (_ license)))))))))
+
+(define* (composer->guix-package package-name #:optional version)
+  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+`package' s-expression corresponding to that package, or #f on failure."
+  (let ((package (composer-fetch package-name version)))
+    (and package
+         (let* ((package (json->composer-package package))
+                (dependencies-names (composer-package-require package))
+                (dev-dependencies-names (composer-package-dev-require package)))
+           (values (make-php-sexp package)
+                   (append dependencies-names dev-dependencies-names))))))
+
+(define (guix-name->composer-name name)
+  "Given a guix package name, return the name of the package in Packagist."
+  (if (string-prefix? "php-" name)
+      (let ((components (string-split (substring name 4) #\-)))
+        (match components
+          ((namespace name ...)
+           (string-append namespace "/" (string-join name "-")))))
+      name))
+
+(define (guix-package->composer-name package)
+  "Given a Composer PACKAGE built from Packagist, return the name of the
+package in Packagist."
+  (let ((upstream-name (assoc-ref
+                         (package-properties package)
+                         'upstream-name))
+        (name (package-name package)))
+    (if upstream-name
+      upstream-name
+      (guix-name->composer-name name))))
+
+(define (string->license str)
+  "Convert the string STR into a license object."
+  (match str
+    ("GNU LGPL" 'license:lgpl2.0)
+    ("GPL" 'license:gpl3)
+    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
+    ((or "MIT" "MIT license" "Expat license") 'license:expat)
+    ("Public domain" 'license:public-domain)
+    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+    (_ #f)))
+
+(define (php-package? package)
+  "Return true if PACKAGE is a PHP package from Packagist."
+  (and
+    (eq? (build-system-name (package-build-system package)) 'composer)
+    (string-prefix? "php-" (package-name package))))
+
+(define (latest-release package)
+  "Return an <upstream-source> for the latest release of PACKAGE."
+  (let* ((php-name (guix-package->composer-name package))
+         (metadata (composer-fetch php-name))
+         (package (json->composer-package metadata))
+         (version (composer-package-version package))
+         (url (composer-source-url (composer-package-source package))))
+    (upstream-source
+     (package (package-name package))
+     (version version)
+     (urls (list url)))))
+
+(define %composer-updater
+  (upstream-updater
+   (name 'composer)
+   (description "Updater for Composer packages")
+   (pred php-package?)
+   (import latest-release)))
+
+(define* (composer-recursive-import package-name #:optional version)
+  (recursive-import package-name '()
+                    #:repo->guix-package composer->guix-package
+                    #:guix-name php-package-name))
diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm
index 4ddd8d46a1..8c58dd35e2 100644
--- a/guix/scripts/import.scm
+++ b/guix/scripts/import.scm
@@ -47,7 +47,7 @@ (define %standard-import-options '())
 
 (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa"
                     "gem" "go" "cran" "crate" "texlive" "json" "opam"
-                    "minetest" "elm" "hexpm"))
+                    "minetest" "elm" "hexpm" "composer"))
 
 (define (resolve-importer name)
   (let ((module (resolve-interface
diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm
new file mode 100644
index 0000000000..412bae6318
--- /dev/null
+++ b/guix/scripts/import/composer.scm
@@ -0,0 +1,107 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 David Thompson <davet@gnu.org>
+;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
+;;;
+;;; 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 composer)
+  #:use-module (guix ui)
+  #:use-module (guix utils)
+  #:use-module (guix scripts)
+  #:use-module (guix import composer)
+  #:use-module (guix scripts import)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11)
+  #:use-module (srfi srfi-37)
+  #:use-module (srfi srfi-41)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 format)
+  #:export (guix-import-composer))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (G_ "Usage: guix import composer PACKAGE-NAME
+Import and convert the Composer package for PACKAGE-NAME.\n"))
+  (display (G_ "
+  -h, --help             display this help and exit"))
+  (display (G_ "
+  -V, --version          display version information and exit"))
+  (display (G_ "
+  -r, --recursive        generate package expressions for all Composer packages\
+ that are not yet in Guix"))
+  (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 composer")))
+         (option '(#\r "recursive") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'recursive #t result)))
+         %standard-import-options))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-import-composer . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold* args %options
+                (lambda (opt name arg result)
+                  (leave (G_ "~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)
+       (if (assoc-ref opts 'recursive)
+           (map (match-lambda
+                  ((and ('package ('name name) . rest) pkg)
+                   `(define-public ,(string->symbol name)
+                      ,pkg))
+                  (_ #f))
+                (composer-recursive-import package-name))
+           (let ((sexp (composer->guix-package package-name)))
+             (unless sexp
+               (leave (G_ "failed to download meta-data for package '~a'~%")
+                      package-name))
+             sexp)))
+      (()
+       (leave (G_ "too few arguments~%")))
+      ((many ...)
+       (leave (G_ "too many arguments~%"))))))
diff --git a/tests/composer.scm b/tests/composer.scm
new file mode 100644
index 0000000000..cefaf9f434
--- /dev/null
+++ b/tests/composer.scm
@@ -0,0 +1,92 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (test-composer)
+  #:use-module (guix import composer)
+  #:use-module (guix base32)
+  #:use-module (gcrypt hash)
+  #:use-module (guix tests http)
+  #:use-module (guix grafts)
+  #:use-module (srfi srfi-64)
+  #:use-module (web client)
+  #:use-module (ice-9 match))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define test-json
+  "{
+  \"packages\": {
+    \"foo/bar\": {
+      \"0.1\": {
+        \"name\": \"foo/bar\",
+        \"description\": \"description\",
+        \"keywords\": [\"testing\"],
+        \"homepage\": \"http://example.com\",
+        \"version\": \"0.1\",
+        \"license\": [\"BSD-3-Clause\"],
+        \"source\": {
+          \"type\": \"url\",
+          \"url\": \"http://example.com/Bar-0.1.tar.gz\"
+        },
+        \"require\": {},
+        \"require-dev\": {\"phpunit/phpunit\": \"1.0.0\"}
+      }
+    }
+  }
+}")
+
+(define test-source
+  "foobar")
+
+;; Avoid collisions with other tests.
+(%http-server-port 10450)
+
+(test-begin "composer")
+
+(test-assert "composer->guix-package"
+  ;; Replace network resources with sample data.
+  (with-http-server `((200 ,test-json)
+                      (200 ,test-source))
+    (parameterize ((%composer-base-url (%local-url))
+                   (current-http-proxy (%local-url)))
+      (match (composer->guix-package "foo/bar")
+        (('package
+           ('name "php-foo-bar")
+           ('version "0.1")
+           ('source ('origin
+                      ('method 'url-fetch)
+                      ('uri "http://example.com/Bar-0.1.tar.gz")
+                      ('sha256
+                       ('base32
+                        (? string? hash)))))
+           ('build-system 'composer-build-system)
+           ('native-inputs
+            ('quasiquote
+             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
+           ('synopsis "")
+           ('description "description")
+           ('home-page "http://example.com")
+           ('license 'license:bsd-3))
+         (string=? (bytevector->nix-base32-string
+                    (call-with-input-string test-source port-sha256))
+                   hash))
+        (x
+         (pk 'fail x #f))))))
+
+(test-end "composer")
-- 
2.41.0





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

* [bug#42338] [PATCH v5 2/9] gnu: Add composer-classloader.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 3/9] guix: Add composer-build-system Nicolas Graves via Guix-patches via
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* gnu/packages/php-xyz.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk             |  1 +
 gnu/packages/php-xyz.scm | 60 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 gnu/packages/php-xyz.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index 83b5268c7e..f1d16f873c 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -502,6 +502,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/photo.scm			\
   %D%/packages/phabricator.scm 			\
   %D%/packages/php.scm				\
+  %D%/packages/php-xyz.scm			\
   %D%/packages/piet.scm			\
   %D%/packages/pikchr.scm			\
   %D%/packages/pkg-config.scm			\
diff --git a/gnu/packages/php-xyz.scm b/gnu/packages/php-xyz.scm
new file mode 100644
index 0000000000..ac90ee3c25
--- /dev/null
+++ b/gnu/packages/php-xyz.scm
@@ -0,0 +1,60 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 (gnu packages php-xyz)
+  #:use-module (gnu packages)
+  #:use-module (gnu packages php)
+  #:use-module (guix packages)
+  #:use-module (guix download)
+  #:use-module (guix git-download)
+  #:use-module (guix build-system composer)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix utils)
+  #:use-module ((guix licenses) #:prefix license:))
+
+(define-public composer-classloader
+  (package
+    (name "composer-classloader")
+    (version "1.9.0")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/composer/composer")
+             (commit version)))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32 "0127zmmg3yx84ljngfs86q7kjhyypybkf4d1ihfrfnzgynzxfxdf"))))
+    (build-system gnu-build-system)
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (delete 'configure)
+         (delete 'build)
+         (delete 'check)
+         (replace 'install
+           (lambda* (#:key outputs #:allow-other-keys)
+             (let* ((out (assoc-ref outputs "out")))
+               (install-file "src/Composer/Autoload/ClassLoader.php"
+                             (string-append out "/share/web/composer/"))))))))
+    (home-page "https://getcomposer.org")
+    (synopsis "PHP class loader extracted from the composer package")
+    (description "This package contains the class loader class used by Composer to
+build its autoloading feature.  This package is used by the composer-build-system
+to build its own store-aware autoloading feature.")
+    (license license:expat)))
-- 
2.41.0





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

* [bug#42338] [PATCH v5 3/9] guix: Add composer-build-system.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 2/9] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 4/9] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/build-system/composer.scm: New file.
* guix/build/composer-build-system.scm: New file.
* gnu/packages/aux-files/findclass.php: New file.
* Makefile.am: Add them.
* doc/guix.texi (Build Systems): Document it.
---
 Makefile.am                          |   3 +
 doc/guix.texi                        |  16 +-
 gnu/packages/aux-files/findclass.php | 125 ++++++++++++++
 guix/build-system/composer.scm       | 162 ++++++++++++++++++
 guix/build/composer-build-system.scm | 247 +++++++++++++++++++++++++++
 tests/composer.scm                   |  36 ++--
 6 files changed, 568 insertions(+), 21 deletions(-)
 create mode 100644 gnu/packages/aux-files/findclass.php
 create mode 100644 guix/build-system/composer.scm
 create mode 100644 guix/build/composer-build-system.scm

diff --git a/Makefile.am b/Makefile.am
index 3fec98f064..47d1cb19ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -149,6 +149,7 @@ MODULES =					\
   guix/build-system/chicken.scm			\
   guix/build-system/clojure.scm			\
   guix/build-system/cmake.scm			\
+  guix/build-system/composer.scm		\
   guix/build-system/dub.scm			\
   guix/build-system/dune.scm			\
   guix/build-system/elm.scm			\
@@ -206,6 +207,7 @@ MODULES =					\
   guix/build/cargo-utils.scm			\
   guix/build/chicken-build-system.scm		\
   guix/build/cmake-build-system.scm		\
+  guix/build/composer-build-system.scm		\
   guix/build/dub-build-system.scm		\
   guix/build/dune-build-system.scm		\
   guix/build/elm-build-system.scm		\
@@ -411,6 +413,7 @@ dist_noinst_DATA =				\
 AUX_FILES =						\
   gnu/packages/aux-files/chromium/master-preferences.json		\
   gnu/packages/aux-files/emacs/guix-emacs.el		\
+  gnu/packages/aux-files/findclass.php			\
   gnu/packages/aux-files/guix.vim			\
   gnu/packages/aux-files/linux-libre/6.5-arm.conf	\
   gnu/packages/aux-files/linux-libre/6.5-arm64.conf	\
diff --git a/doc/guix.texi b/doc/guix.texi
index 0e64654715..6a1c0aeaa5 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9554,6 +9554,20 @@ debugging information''), which roughly means that code is compiled with
 @code{-O2 -g}, as is the case for Autoconf-based packages by default.
 @end defvar
 
+@defvar {Scheme Variable} composer-build-system
+This variable is exported by @code{(guix build-system composer)}.  It
+implements the build procedure for packages using
+@url{https://getcomposer.org/, Composer}, the PHP package manager.
+
+It automatically adds the @code{php} package to the set of inputs.  Which
+package is used can be specified with the @code{#:php} parameter.
+
+The @code{#:test-target} parameter is used to control which script is run
+for the tests.  By default, the @code{test} script is run if it exists.  If
+the script does not exist, the build system will run @code{phpunit} from the
+source directory, assuming there is a @file{phpunit.xml} file.
+@end defvar
+
 @defvar dune-build-system
 This variable is exported by @code{(guix build-system dune)}.  It
 supports builds of packages using @uref{https://dune.build/, Dune}, a build
@@ -14550,7 +14564,7 @@ in Guix.
 @item composer
 @cindex Composer
 @cindex PHP
-Import metadat from the @uref{https://getcomposer.org/, Composer} package
+Import metadata from the @uref{https://getcomposer.org/, Composer} package
 archive used by the PHP community, as in this example:
 
 @example
diff --git a/gnu/packages/aux-files/findclass.php b/gnu/packages/aux-files/findclass.php
new file mode 100644
index 0000000000..d0b250c8e1
--- /dev/null
+++ b/gnu/packages/aux-files/findclass.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * The content of this file is copied from composer's src/Composer/Autoload/ClassMapGenerator.php
+ * the findClasses method was extracted, to prevent using any dependency.
+ *
+ * Composer (and thus this file) is distributed under the expat license, and
+ * ClassMapGenerator.php also contains this notice:
+ *
+ *   This file is part of Composer.
+ *
+ *   (c) Nils Adermann <naderman@naderman.de>
+ *       Jordi Boggiano <j.boggiano@seld.be>
+ *
+ *   For the full copyright and license information, please view the LICENSE
+ *   file that was distributed with this source code.
+ *
+ *   This file is copied from the Symfony package.
+ *
+ *   (c) Fabien Potencier <fabien@symfony.com>
+ * 
+ * To the extent to wich it makes sense, as the author of the extract:
+ * Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+ */
+
+/**
+ * Extract the classes in the given file
+ *
+ * @param  string            $path The file to check
+ * @throws \RuntimeException
+ * @return array             The found classes
+ */
+function findClasses($path)
+{
+    $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
+    if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
+        $extraTypes .= '|enum';
+    }
+    // Use @ here instead of Silencer to actively suppress 'unhelpful' output
+    // @link https://github.com/composer/composer/pull/4886
+    $contents = @php_strip_whitespace($path);
+    if (!$contents) {
+        if (!file_exists($path)) {
+            $message = 'File at "%s" does not exist, check your classmap definitions';
+        } elseif (!is_readable($path)) {
+            $message = 'File at "%s" is not readable, check its permissions';
+        } elseif ('' === trim(file_get_contents($path))) {
+            // The input file was really empty and thus contains no classes
+            return array();
+        } else {
+            $message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
+        }
+        $error = error_get_last();
+        if (isset($error['message'])) {
+            $message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
+        }
+        throw new \RuntimeException(sprintf($message, $path));
+    }
+    // return early if there is no chance of matching anything in this file
+    if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
+        return array();
+    }
+    // strip heredocs/nowdocs
+    $contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
+    // strip strings
+    $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
+    // strip leading non-php code if needed
+    if (substr($contents, 0, 2) !== '<?') {
+        $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
+        if ($replacements === 0) {
+            return array();
+        }
+    }
+    // strip non-php blocks in the file
+    $contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
+    // strip trailing non-php code if needed
+    $pos = strrpos($contents, '?>');
+    if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
+        $contents = substr($contents, 0, $pos);
+    }
+    // strip comments if short open tags are in the file
+    if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
+        $contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
+    }
+    preg_match_all('{
+        (?:
+             \b(?<![\$:>])(?P<type>class|interface'.$extraTypes.') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
+           | \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
+        )
+    }ix', $contents, $matches);
+    $classes = array();
+    $namespace = '';
+    for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
+        if (!empty($matches['ns'][$i])) {
+            $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
+        } else {
+            $name = $matches['name'][$i];
+            // skip anon classes extending/implementing
+            if ($name === 'extends' || $name === 'implements') {
+                continue;
+            }
+            if ($name[0] === ':') {
+                // This is an XHP class, https://github.com/facebook/xhp
+                $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
+            } elseif ($matches['type'][$i] === 'enum') {
+                // In Hack, something like:
+                //   enum Foo: int { HERP = '123'; }
+                // The regex above captures the colon, which isn't part of
+                // the class name.
+                $name = rtrim($name, ':');
+            }
+            $classes[] = ltrim($namespace . $name, '\\');
+        }
+    }
+    return $classes;
+}
+
+$options = getopt('i:f:', []);
+$file = $options["f"];
+$input = $options["i"];
+
+$classes = findClasses($file);
+foreach($classes as $class) {
+  echo '$classmap[\''.$class.'\'] = \''.$input.'/'.$file.'\';';
+  echo "\n";
+}
diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
new file mode 100644
index 0000000000..8bf99ff9c5
--- /dev/null
+++ b/guix/build-system/composer.scm
@@ -0,0 +1,162 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;;
+;;; 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 build-system composer)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix derivations)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-1)
+  #:export (%composer-build-system-modules
+            lower
+            composer-build
+            composer-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for PHP packages using Composer. This is implemented
+;; as an extension of `gnu-build-system'.
+;;
+;; Code:
+
+(define (default-php)
+  "Return the default PHP package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php))))
+    (module-ref module 'php)))
+
+(define (default-findclass)
+  "Return the default findclass script."
+  (search-auxiliary-file "findclass.php"))
+
+(define (default-composer-classloader)
+  "Return the default composer-classloader package."
+
+  ;; Do not use `@' to avoid introducing circular dependencies.
+  (let ((module (resolve-interface '(gnu packages php-xyz))))
+    (module-ref module 'composer-classloader)))
+
+(define %composer-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build composer-build-system)
+    (guix build union)
+    (json)
+    (json builder)
+    (json parser)
+    (json record)
+    ,@%gnu-build-system-modules))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (php (default-php))
+                (composer-classloader (default-composer-classloader))
+                (findclass (default-findclass))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs))
+
+  (and (not target)                               ;XXX: no cross-compilation
+       (bag
+         (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '())
+                        ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(("php" ,php)
+                         ("findclass.php" ,findclass)
+			 ("composer-classloader" ,composer-classloader)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build composer-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (composer-build name inputs
+                         #:key
+                         guile source
+                         (outputs '("out"))
+                         (configure-flags ''())
+                         (search-paths '())
+                         (out-of-source? #t)
+                         (composer-file "composer.json")
+                         (tests? #t)
+                         (test-target "test")
+                         (install-target "install")
+                         (validate-runpath? #t)
+                         (patch-shebangs? #t)
+                         (strip-binaries? #t)
+                         (strip-flags #~'("--strip-debug"))
+                         (strip-directories #~'("lib" "lib64" "libexec"
+                                               "bin" "sbin"))
+                         (phases '(@ (guix build composer-build-system)
+                                     %standard-phases))
+                         (system (%current-system))
+                         (imported-modules %composer-build-system-modules)
+                         (modules '((guix build composer-build-system)
+                                    (guix build utils))))
+  "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides
+a 'composer.json' file as its build system."
+  (define builder
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@(sexp->gexp modules))
+
+          #$(with-build-variables inputs outputs
+              #~(composer-build
+                 #:source #$source
+                 #:system #$system
+                 #:outputs %outputs
+                 #:inputs %build-inputs
+                 #:search-paths '#$(map search-path-specification->sexp
+                                        search-paths)
+                 #:phases #$phases
+                 #:out-of-source? #$out-of-source?
+                 #:composer-file #$composer-file
+                 #:tests? #$tests?
+                 #:test-target #$test-target
+                 #:install-target #$install-target
+                 #:validate-runpath? #$validate-runpath?
+                 #:patch-shebangs? #$patch-shebangs?
+                 #:strip-binaries? #$strip-binaries?
+                 #:strip-flags #$strip-flags
+                 #:strip-directories #$strip-directories)))))
+
+  (gexp->derivation name builder
+                    #:system system
+                    #:target #f
+                    #:graft? #f
+                    #:guile-for-build guile))
+
+(define composer-build-system
+  (build-system
+    (name 'composer)
+    (description "The standard Composer build system")
+    (lower lower)))
+
+;;; composer.scm ends here
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
new file mode 100644
index 0000000000..bcbae27021
--- /dev/null
+++ b/guix/build/composer-build-system.scm
@@ -0,0 +1,247 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu>
+;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
+;;;
+;;; 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 build composer-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:use-module (json)
+  #:use-module (srfi srfi-26)
+  #:export (%standard-phases
+            composer-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard composer build procedure.
+;;
+;; Code:
+
+(define (json->require dict)
+  (if dict
+      (let loop ((result '()) (require dict))
+        (match require
+          (() result)
+          ((((? (cut string-contains <> "/") name) . _)
+             require ...)
+           (loop (cons name result) require))
+          ((_ require ...) (loop result require))
+          (_ result)))
+      '()))
+
+(define (if-specified-to-list fn)
+  (match-lambda
+    ((? unspecified?) '())
+    (arg (fn arg))
+    (_ '())))
+
+(define-json-mapping <composer-autoload> make-composer-autoload
+  composer-autoload?
+  json->composer-autoload
+  (psr-4 composer-autoload-psr-4 "psr-4" (if-specified-to-list identity))
+  (classmap composer-autoload-classmap "classmap"
+            (if-specified-to-list vector->list)))
+
+(define-json-mapping <composer-package> make-composer-package composer-package?
+  json->composer-package
+  (name         composer-package-name)
+  (autoload     composer-package-autoload "autoload"
+                (if-specified-to-list json->composer-autoload))
+  (autoload-dev composer-package-autoload-dev "autoload-dev"
+                (if-specified-to-list json->composer-autoload))
+  (require      composer-package-require "require" json->require)
+  (dev-require  composer-package-dev-require "require-dev" json->require)
+  (scripts      composer-package-scripts "scripts"
+                (if-specified-to-list identity))
+  (binaries     composer-package-binaries "bin"
+                (if-specified-to-list vector->list)))
+
+(define* (read-package-data #:key (filename "composer.json"))
+  (call-with-input-file filename
+    (lambda (port)
+      (json->composer-package (json->scm port)))))
+
+(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
+  "Test the given package."
+  (when tests?
+    (mkdir-p "vendor")
+    (create-autoload (string-append (getcwd) "/vendor") composer-file
+                     (append inputs outputs) #:dev-dependencies? #t)
+    (let* ((package-data (read-package-data #:filename composer-file))
+           (scripts (composer-package-scripts package-data))
+           (test-script (assoc-ref scripts test-target))
+           (dependencies (composer-package-require package-data))
+           (dependencies-dev (composer-package-dev-require package-data))
+           (name (composer-package-name package-data)))
+      (for-each
+        (match-lambda
+          ((_ . input)
+           (let ((bin (find-php-bin input)))
+             (when bin
+               (copy-recursively bin "vendor/bin")))))
+        inputs)
+      (match test-script
+        ((? string? command)
+         (unless (zero? (system command))
+           (throw 'failed-command command)))
+        (('@ (? string? command) ...)
+         (for-each
+           (lambda (c)
+             (unless (zero? (system c))
+               (throw 'failed-command c)))
+           command))
+        (#f (invoke "vendor/bin/phpunit"))))))
+
+(define (find-php-bin input)
+  (let* ((web-dir (string-append input "/share/web"))
+         (vendors (if (file-exists? web-dir)
+                      (find-files web-dir "^vendor$" #:directories? #t)
+                      #f)))
+    (match vendors
+      ((vendor)
+       (let ((bin (string-append vendor "/bin")))
+         (and (file-exists? bin) bin)))
+      (_ #f))))
+
+(define (find-php-dep inputs dependency)
+  (let loop ((inputs inputs))
+    (match inputs
+      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
+                 dependency))
+      (((_ . input) inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+          (if (file-exists? autoload)
+              autoload
+              (loop inputs))))
+      ((input inputs ...)
+       (let ((autoload (string-append input "/share/web/" dependency
+                                      "/vendor/autoload_conf.php")))
+         (if (file-exists? autoload)
+             autoload
+             (loop inputs)))))))
+
+(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
+  "creates an autoload.php file that sets up the class locations for this package,
+so it can be autoloaded by PHP when the package classes are required."
+  (with-output-to-file (string-append vendor "/autoload.php")
+    (lambda _
+      (display (string-append
+                 "<?php
+// autoload.php @generated by Guix
+$map = $psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php'
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$loader = new \\Composer\\Autoload\\ClassLoader();
+foreach ($map as $namespace => $path) {
+  $loader->set($namespace, $path);
+}
+foreach ($psr4map as $namespace => $path) {
+  $loader->setPsr4($namespace, $path);
+}
+$loader->addClassMap($classmap);
+$loader->register();
+"))))
+  ;; Now, create autoload_conf.php that contains the actual data, as a set
+  ;; of arrays
+  (let* ((package-data (read-package-data #:filename composer-file))
+         (autoload (composer-package-autoload package-data))
+         (autoload-dev (composer-package-autoload-dev package-data))
+         (dependencies (composer-package-require package-data))
+         (dependencies-dev (composer-package-dev-require package-data)))
+    (with-output-to-file (string-append vendor "/autoload_conf.php")
+      (lambda _
+        (format #t "<?php~%")
+        (format #t "// autoload_conf.php @generated by Guix~%")
+        (force-output)
+        (for-each
+          (lambda (psr4)
+            (match psr4
+              ((key . value)
+               (format #t "$psr4map['~a'] = '~a/../~a';~%"
+                       (string-join (string-split key #\\) "\\\\")
+                       vendor value))))
+          (append
+            (composer-autoload-psr-4 autoload)
+            (if dev-dependencies?
+                (composer-autoload-psr-4 autoload-dev)
+                '())))
+        (for-each
+          (lambda (classmap)
+            (for-each
+              (lambda (file)
+                (invoke "php" (assoc-ref inputs "findclass.php")
+                        "-i" (string-append vendor "/..") "-f" file))
+              (find-files classmap ".(php|hh|inc)$")))
+          (append
+            (composer-autoload-classmap autoload)
+            (if dev-dependencies?
+                (composer-autoload-classmap autoload-dev)
+                '())))
+        (for-each
+          (lambda (dep)
+            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
+          (append
+            dependencies
+            (if dev-dependencies?
+                dependencies-dev
+                '())))))))
+
+(define* (install #:key inputs outputs composer-file #:allow-other-keys)
+  "Install the given package."
+  (let* ((out (assoc-ref outputs "out"))
+         (package-data (read-package-data #:filename composer-file))
+         (name (composer-package-name package-data))
+         (php-dir (string-append out "/share/web/" name))
+         (bin-dir (string-append php-dir "/vendor/bin"))
+         (bin (string-append out "/bin"))
+         (binaries (composer-package-binaries package-data)))
+      (mkdir-p php-dir)
+      (copy-recursively "." php-dir)
+      (mkdir-p (string-append php-dir "/vendor"))
+      (when binaries
+        (mkdir-p bin-dir)
+        (mkdir-p bin)
+        (for-each
+          (lambda (file)
+            (let ((installed-file (string-append bin-dir "/" (basename file)))
+                  (bin-file (string-append bin "/" (basename file)))
+                  (original-file (string-append php-dir "/" file)))
+              (symlink original-file installed-file)
+              (symlink original-file bin-file)))
+          binaries))
+      (create-autoload (string-append php-dir "/vendor")
+                       composer-file inputs)))
+
+(define %standard-phases
+  ;; Everything is as with the GNU Build System except for the `configure'
+  ;; , `build', `check' and `install' phases.
+  (modify-phases gnu:%standard-phases
+    (delete 'bootstrap)
+    (delete 'configure)
+    (delete 'build)
+    (delete 'check)
+    (replace 'install install)
+    (add-after 'install 'check check)))
+
+(define* (composer-build #:key inputs (phases %standard-phases)
+                         #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply gnu:gnu-build #:inputs inputs #:phases phases args))
+
+;;; composer-build-system.scm ends here
diff --git a/tests/composer.scm b/tests/composer.scm
index cefaf9f434..9114fef19e 100644
--- a/tests/composer.scm
+++ b/tests/composer.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2020 Julien Lepiller <julien@lepiller.eu>
+;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -54,9 +55,6 @@ (define test-json
 (define test-source
   "foobar")
 
-;; Avoid collisions with other tests.
-(%http-server-port 10450)
-
 (test-begin "composer")
 
 (test-assert "composer->guix-package"
@@ -66,23 +64,21 @@ (define test-source
     (parameterize ((%composer-base-url (%local-url))
                    (current-http-proxy (%local-url)))
       (match (composer->guix-package "foo/bar")
-        (('package
-           ('name "php-foo-bar")
-           ('version "0.1")
-           ('source ('origin
-                      ('method 'url-fetch)
-                      ('uri "http://example.com/Bar-0.1.tar.gz")
-                      ('sha256
-                       ('base32
-                        (? string? hash)))))
-           ('build-system 'composer-build-system)
-           ('native-inputs
-            ('quasiquote
-             (("php-phpunit-phpunit" ('unquote 'php-phpunit-phpunit)))))
-           ('synopsis "")
-           ('description "description")
-           ('home-page "http://example.com")
-           ('license 'license:bsd-3))
+        (`(package
+            (name "php-foo-bar")
+            (version "0.1")
+            (source (origin
+                      (method url-fetch)
+                      (uri "http://example.com/Bar-0.1.tar.gz")
+                      (sha256
+                       (base32
+                        ,(? string? hash)))))
+            (build-system composer-build-system)
+            (native-inputs (list php-phpunit-phpunit))
+            (synopsis "")
+            (description "description")
+            (home-page "http://example.com")
+            (license license:bsd-3))
          (string=? (bytevector->nix-base32-string
                     (call-with-input-string test-source port-sha256))
                    hash))
-- 
2.41.0





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

* [bug#42338] [PATCH v5 4/9] guix: import: composer: Use memoization.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (2 preceding siblings ...)
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 3/9] guix: Add composer-build-system Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 5/9] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

---
 guix/import/composer.scm | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index c152f402bb..177dc63092 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -27,6 +27,7 @@ (define-module (guix import composer)
   #:use-module (guix import json)
   #:use-module (guix import utils)
   #:use-module ((guix licenses) #:prefix license:)
+  #:use-module (guix memoization)
   #:use-module (guix packages)
   #:use-module (guix serialization)
   #:use-module (guix upstream)
@@ -197,16 +198,18 @@ (define (make-php-sexp composer-package)
                            ((license) license)
                            (_ license)))))))))
 
-(define* (composer->guix-package package-name #:optional version)
-  "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
+(define composer->guix-package
+  (memoize
+   (lambda* (package-name #:key version #:allow-other-keys)
+     "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
 `package' s-expression corresponding to that package, or #f on failure."
-  (let ((package (composer-fetch package-name version)))
-    (and package
-         (let* ((package (json->composer-package package))
-                (dependencies-names (composer-package-require package))
-                (dev-dependencies-names (composer-package-dev-require package)))
-           (values (make-php-sexp package)
-                   (append dependencies-names dev-dependencies-names))))))
+     (let ((package (composer-fetch package-name version)))
+       (and package
+            (let* ((package (json->composer-package package))
+                   (dependencies-names (composer-package-require package))
+                   (dev-dependencies-names (composer-package-dev-require package)))
+              (values (make-php-sexp package)
+                      (append dependencies-names dev-dependencies-names))))))))
 
 (define (guix-name->composer-name name)
   "Given a guix package name, return the name of the package in Packagist."
@@ -265,6 +268,7 @@ (define %composer-updater
    (import latest-release)))
 
 (define* (composer-recursive-import package-name #:optional version)
-  (recursive-import package-name '()
+  (recursive-import package-name
+                    #:version version
                     #:repo->guix-package composer->guix-package
                     #:guix-name php-package-name))
-- 
2.41.0





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

* [bug#42338] [PATCH v5 5/9] guix: import: composer: Fix json->require.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (3 preceding siblings ...)
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 4/9] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 6/9] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

---
 guix/import/composer.scm | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 177dc63092..3acbbecf82 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -88,7 +88,8 @@ (define (json->require dict)
           ((((? (cut string-contains <> "/") name) . _)
              require ...)
            (loop (cons name result) require))
-          ((_ require ...) (loop result require))))
+          ((_ require ...) (loop result require))
+          (_ result)))
       '()))
 
 (define-json-mapping <composer-source> make-composer-source composer-source?
-- 
2.41.0





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

* [bug#42338] [PATCH v5 6/9] guix: import: composer: More robust string->license.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (4 preceding siblings ...)
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 5/9] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 7/9] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm (string->license): Use spdx-string->license. Fall
back to unknown-license!.
---
 guix/import/composer.scm | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 3acbbecf82..49f16caedf 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -109,7 +109,10 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
   (dev-require composer-package-dev-require "require-dev" json->require)
   (license     composer-package-license "license"
                (lambda (vector)
-                 (map string->license (vector->list vector)))))
+                 (let ((l (map string->license (vector->list vector))))
+                   (if (eq? (length l) 1)
+                       (car l)
+                       `(list ,@l))))))
 
 (define* (composer-fetch name #:optional version)
   "Return an alist representation of the Composer metadata for the package NAME,
@@ -194,10 +197,8 @@ (define (make-php-sexp composer-package)
                (synopsis "")
                (description ,(composer-package-description composer-package))
                (home-page ,(composer-package-homepage composer-package))
-               (license ,(match (composer-package-license composer-package)
-                           (() #f)
-                           ((license) license)
-                           (_ license)))))))))
+               (license ,(or (composer-package-license composer-package)
+                             'unknown-license!))))))))
 
 (define composer->guix-package
   (memoize
@@ -234,14 +235,15 @@ (define (guix-package->composer-name package)
 
 (define (string->license str)
   "Convert the string STR into a license object."
-  (match str
-    ("GNU LGPL" 'license:lgpl2.0)
-    ("GPL" 'license:gpl3)
-    ((or "BSD" "BSD License" "BSD-3-Clause") 'license:bsd-3)
-    ((or "MIT" "MIT license" "Expat license") 'license:expat)
-    ("Public domain" 'license:public-domain)
-    ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
-    (_ #f)))
+  (or (spdx-string->license str)
+      (match str
+        ("GNU LGPL" 'license:lgpl2.0)
+        ("GPL" 'license:gpl3)
+        ((or "BSD" "BSD License") 'license:bsd-3)
+        ((or "MIT" "MIT license" "Expat license") 'license:expat)
+        ("Public domain" 'license:public-domain)
+        ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0)
+        (_ 'unknown-license!))))
 
 (define (php-package? package)
   "Return true if PACKAGE is a PHP package from Packagist."
-- 
2.41.0





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

* [bug#42338] [PATCH v5 7/9] guix: import: composer: Modern inputs formatting.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (5 preceding siblings ...)
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 6/9] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 8/9] guix: import: composer: Full rewrite composer-fetch Nicolas Graves via Guix-patches via
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

* guix/import/composer.scm (make-php-sexp): Update inputs formatting.
---
 guix/import/composer.scm | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 49f16caedf..89c8ea9113 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -179,21 +179,11 @@ (define (make-php-sexp composer-package)
                ,@(if (null? dependencies)
                      '()
                      `((inputs
-                        (,'quasiquote
-                         ,(map (lambda (name)
-                                 `(,name
-                                   (,'unquote
-                                    ,(string->symbol name))))
-                               dependencies)))))
+                        (list ,@(map string->symbol dependencies)))))
                ,@(if (null? dev-dependencies)
                      '()
                      `((native-inputs
-                        (,'quasiquote
-                         ,(map (lambda (name)
-                                 `(,name
-                                   (,'unquote
-                                    ,(string->symbol name))))
-                               dev-dependencies)))))
+                        (list ,@(map string->symbol dev-dependencies)))))
                (synopsis "")
                (description ,(composer-package-description composer-package))
                (home-page ,(composer-package-homepage composer-package))
-- 
2.41.0





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

* [bug#42338] [PATCH v5 8/9] guix: import: composer: Full rewrite composer-fetch.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (6 preceding siblings ...)
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 7/9] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 9/9] gnu: composer-build-system: Full check phase rewrite Nicolas Graves via Guix-patches via
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

Change-Id: I1c01c242cefe0bc4cfc9bd9a5717d10a61dd575e
---
 guix/import/composer.scm | 154 +++++++++++++++++++--------------------
 1 file changed, 77 insertions(+), 77 deletions(-)

diff --git a/guix/import/composer.scm b/guix/import/composer.scm
index 89c8ea9113..2cc8861bdd 100644
--- a/guix/import/composer.scm
+++ b/guix/import/composer.scm
@@ -19,7 +19,7 @@
 (define-module (guix import composer)
   #:use-module (ice-9 match)
   #:use-module (json)
-  #:use-module (gcrypt hash)
+  #:use-module (guix hash)
   #:use-module (guix base32)
   #:use-module (guix build git)
   #:use-module (guix build utils)
@@ -44,27 +44,6 @@ (define-module (guix import composer)
 (define %composer-base-url
   (make-parameter "https://repo.packagist.org"))
 
-;; XXX adapted from (guix scripts hash)
-(define (file-hash file select? recursive?)
-  ;; Compute the hash of FILE.
-  (if recursive?
-      (let-values (((port get-hash) (open-sha256-port)))
-        (write-file file port #:select? select?)
-        (force-output port)
-        (get-hash))
-      (call-with-input-file file port-sha256)))
-
-;; XXX taken from (guix scripts hash)
-(define (vcs-file? file stat)
-  (case (stat:type stat)
-    ((directory)
-     (member (basename file) '(".bzr" ".git" ".hg" ".svn" "CVS")))
-    ((regular)
-     ;; Git sub-modules have a '.git' file that is a regular text file.
-     (string=? (basename file) ".git"))
-    (else
-     #f)))
-
 (define (fix-version version)
   "Return a fixed version from a version string.  For instance, v10.1 -> 10.1"
   (cond
@@ -114,22 +93,36 @@ (define-json-mapping <composer-package> make-composer-package composer-package?
                        (car l)
                        `(list ,@l))))))
 
-(define* (composer-fetch name #:optional version)
-  "Return an alist representation of the Composer metadata for the package NAME,
-or #f on failure."
-  (let ((package (json-fetch
-                   (string-append (%composer-base-url) "/p/" name ".json"))))
-    (if package
-        (let* ((packages (assoc-ref package "packages"))
-               (package (or (assoc-ref packages name) package))
-               (versions (filter
-                           (lambda (version)
-                             (and (not (string-contains version "dev"))
-                                  (not (string-contains version "beta"))))
-                           (map car package)))
-               (version (or (if (null? version) #f version)
-                            (latest-version versions))))
-          (assoc-ref package version))
+(define (valid-version? v)
+  (let ((d (string-downcase v)))
+    (and (not (string-contains d "dev"))
+         (not (string-contains d "beta"))
+         (not (string-contains d "rc")))))
+
+(define* (composer-fetch name #:key (version #f))
+  "Return a composer-package representation of the Composer metadata for the
+package NAME with optional VERSION, or #f on failure."
+  (let* ((url (string-append (%composer-base-url) "/p/" name ".json"))
+         (packages (and=> (json-fetch url)
+                          (lambda (pkg)
+                            (let ((pkgs (assoc-ref pkg "packages")))
+                              (or (assoc-ref pkgs name) pkg))))))
+    (if packages
+        (json->composer-package
+         (if version
+             (assoc-ref packages version)
+             (cdr
+              (reduce
+               (lambda (new cur-max)
+                 (match new
+                   (((? valid-version? version) . tail)
+                    (if (version>? (fix-version version)
+                                   (fix-version (car cur-max)))
+                        (cons* version tail)
+                        cur-max))
+                   (_ cur-max)))
+               (cons* "0.0.0" #f)
+               packages))))
         #f)))
 
 (define (php-package-name name)
@@ -158,47 +151,55 @@ (define (make-php-sexp composer-package)
                              (composer-source-reference source)
                              temp))
                 (url-fetch (composer-source-url source) temp))
-            `(package
-               (name ,(composer-package-name composer-package))
-               (version ,(composer-package-version composer-package))
-               (source (origin
-                         ,@(if git?
-                               `((method git-fetch)
-                                 (uri (git-reference
-                                        (url ,(composer-source-url source))
-                                        (commit ,(composer-source-reference source))))
-                                 (file-name (git-file-name name version))
-                                 (sha256
-                                   (base32
-                                     ,(bytevector->nix-base32-string
-                                       (file-hash temp (negate vcs-file?) #t)))))
-                               `((method url-fetch)
-                                 (uri ,(composer-source-url source))
-                                 (sha256 (base32 ,(guix-hash-url temp)))))))
-               (build-system composer-build-system)
-               ,@(if (null? dependencies)
-                     '()
-                     `((inputs
-                        (list ,@(map string->symbol dependencies)))))
-               ,@(if (null? dev-dependencies)
-                     '()
-                     `((native-inputs
-                        (list ,@(map string->symbol dev-dependencies)))))
-               (synopsis "")
-               (description ,(composer-package-description composer-package))
-               (home-page ,(composer-package-homepage composer-package))
-               (license ,(or (composer-package-license composer-package)
-                             'unknown-license!))))))))
+            `(define-public ,(string->symbol
+                              (composer-package-name composer-package))
+               (package
+                 (name ,(composer-package-name composer-package))
+                 (version ,(composer-package-version composer-package))
+                 (source
+                  (origin
+                    ,@(if git?
+                          `((method git-fetch)
+                            (uri (git-reference
+                                  (url ,(if (string-suffix?
+                                             ".git"
+                                             (composer-source-url source))
+                                            (string-drop-right
+                                             (composer-source-url source)
+                                             (string-length ".git"))
+                                            (composer-source-url source)))
+                                  (commit ,(composer-source-reference source))))
+                            (file-name (git-file-name name version))
+                            (sha256
+                             (base32
+                              ,(bytevector->nix-base32-string
+                                (file-hash* temp)))))
+                          `((method url-fetch)
+                            (uri ,(composer-source-url source))
+                            (sha256 (base32 ,(guix-hash-url temp)))))))
+                 (build-system composer-build-system)
+                 ,@(if (null? dependencies)
+                       '()
+                       `((inputs
+                          (list ,@(map string->symbol dependencies)))))
+                 ,@(if (null? dev-dependencies)
+                       '()
+                       `((native-inputs
+                          (list ,@(map string->symbol dev-dependencies)))))
+                 (synopsis "")
+                 (description ,(composer-package-description composer-package))
+                 (home-page ,(composer-package-homepage composer-package))
+                 (license ,(or (composer-package-license composer-package)
+                               'unknown-license!)))))))))
 
 (define composer->guix-package
   (memoize
-   (lambda* (package-name #:key version #:allow-other-keys)
+   (lambda* (package-name #:key (version #f) #:allow-other-keys)
      "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the
 `package' s-expression corresponding to that package, or #f on failure."
-     (let ((package (composer-fetch package-name version)))
+     (let ((package (composer-fetch package-name #:version version)))
        (and package
-            (let* ((package (json->composer-package package))
-                   (dependencies-names (composer-package-require package))
+            (let* ((dependencies-names (composer-package-require package))
                    (dev-dependencies-names (composer-package-dev-require package)))
               (values (make-php-sexp package)
                       (append dependencies-names dev-dependencies-names))))))))
@@ -238,14 +239,13 @@ (define (string->license str)
 (define (php-package? package)
   "Return true if PACKAGE is a PHP package from Packagist."
   (and
-    (eq? (build-system-name (package-build-system package)) 'composer)
-    (string-prefix? "php-" (package-name package))))
+   (eq? (package-build-system package) composer-build-system)
+   (string-prefix? "php-" (package-name package))))
 
 (define (latest-release package)
   "Return an <upstream-source> for the latest release of PACKAGE."
   (let* ((php-name (guix-package->composer-name package))
-         (metadata (composer-fetch php-name))
-         (package (json->composer-package metadata))
+         (package (composer-fetch php-name))
          (version (composer-package-version package))
          (url (composer-source-url (composer-package-source package))))
     (upstream-source
-- 
2.41.0





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

* [bug#42338] [PATCH v5 9/9] gnu: composer-build-system: Full check phase rewrite.
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (7 preceding siblings ...)
  2023-11-02 15:16   ` [bug#42338] [PATCH v5 8/9] guix: import: composer: Full rewrite composer-fetch Nicolas Graves via Guix-patches via
@ 2023-11-02 15:16   ` Nicolas Graves via Guix-patches via
       [not found]   ` <87ttq3u8m4.fsf@ngraves.fr>
  2023-12-18 22:33   ` Ludovic Courtès
  10 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-11-02 15:16 UTC (permalink / raw)
  To: 42338; +Cc: ngraves

Change-Id: I824b27b925cd718ee83ef6b2ee4a8a1e69455de6
---
 guix/build-system/composer.scm       |   2 +
 guix/build/composer-build-system.scm | 239 ++++++++++++++++-----------
 2 files changed, 148 insertions(+), 93 deletions(-)

diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm
index 8bf99ff9c5..7d2ad2b398 100644
--- a/guix/build-system/composer.scm
+++ b/guix/build-system/composer.scm
@@ -107,6 +107,7 @@ (define* (composer-build name inputs
                          (composer-file "composer.json")
                          (tests? #t)
                          (test-target "test")
+                         (test-flags ''())
                          (install-target "install")
                          (validate-runpath? #t)
                          (patch-shebangs? #t)
@@ -140,6 +141,7 @@ (define builder
                  #:composer-file #$composer-file
                  #:tests? #$tests?
                  #:test-target #$test-target
+                 #:test-flags #$test-flags
                  #:install-target #$install-target
                  #:validate-runpath? #$validate-runpath?
                  #:patch-shebangs? #$patch-shebangs?
diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm
index bcbae27021..6f05801ad1 100644
--- a/guix/build/composer-build-system.scm
+++ b/guix/build/composer-build-system.scm
@@ -53,9 +53,22 @@ (define (if-specified-to-list fn)
 (define-json-mapping <composer-autoload> make-composer-autoload
   composer-autoload?
   json->composer-autoload
-  (psr-4 composer-autoload-psr-4 "psr-4" (if-specified-to-list identity))
+  (psr-4 composer-autoload-psr-4 "psr-4"
+         (match-lambda
+           ((? unspecified?) '())
+           ((? (lambda (al)
+                 (and (list? al) (pair? (car al)) (vector? (cdar al)))) al)
+            (append-map
+             (lambda (vect-el)
+               (list (cons (caar al) vect-el)))
+             (vector->list (cdar al))))
+           ((? list? l)                  l)
+           (_                           '())))
+  (psr-0 composer-autoload-psr-0 "psr-0" (if-specified-to-list identity))
   (classmap composer-autoload-classmap "classmap"
-            (if-specified-to-list vector->list)))
+            (if-specified-to-list vector->list))
+  (files composer-autoload-files "files"
+         (if-specified-to-list vector->list)))
 
 (define-json-mapping <composer-package> make-composer-package composer-package?
   json->composer-package
@@ -76,65 +89,57 @@ (define* (read-package-data #:key (filename "composer.json"))
     (lambda (port)
       (json->composer-package (json->scm port)))))
 
-(define* (check #:key composer-file inputs outputs tests? test-target #:allow-other-keys)
-  "Test the given package."
+(define* (create-test-autoload #:key composer-file inputs outputs tests?
+                               #:allow-other-keys)
+  "Create the autoload.php file for tests.  This is a standalone phase so that
+the autoload.php file can be edited before the check phase."
   (when tests?
     (mkdir-p "vendor")
     (create-autoload (string-append (getcwd) "/vendor") composer-file
-                     (append inputs outputs) #:dev-dependencies? #t)
-    (let* ((package-data (read-package-data #:filename composer-file))
-           (scripts (composer-package-scripts package-data))
-           (test-script (assoc-ref scripts test-target))
-           (dependencies (composer-package-require package-data))
-           (dependencies-dev (composer-package-dev-require package-data))
-           (name (composer-package-name package-data)))
-      (for-each
-        (match-lambda
-          ((_ . input)
-           (let ((bin (find-php-bin input)))
-             (when bin
-               (copy-recursively bin "vendor/bin")))))
-        inputs)
-      (match test-script
-        ((? string? command)
-         (unless (zero? (system command))
-           (throw 'failed-command command)))
-        (('@ (? string? command) ...)
-         (for-each
-           (lambda (c)
-             (unless (zero? (system c))
-               (throw 'failed-command c)))
-           command))
-        (#f (invoke "vendor/bin/phpunit"))))))
+                     inputs #:dev-dependencies? #t)))
 
-(define (find-php-bin input)
-  (let* ((web-dir (string-append input "/share/web"))
-         (vendors (if (file-exists? web-dir)
-                      (find-files web-dir "^vendor$" #:directories? #t)
-                      #f)))
-    (match vendors
-      ((vendor)
-       (let ((bin (string-append vendor "/bin")))
-         (and (file-exists? bin) bin)))
-      (_ #f))))
+(define (find-bin script inputs)
+  (search-input-file inputs
+                     (string-append
+                      "bin/"
+                      (string-drop script (string-length "vendor/bin/")))))
 
-(define (find-php-dep inputs dependency)
-  (let loop ((inputs inputs))
-    (match inputs
-      (() (throw 'unsatisfied-dependency "Unsatisfied dependency: required "
-                 dependency))
-      (((_ . input) inputs ...)
-       (let ((autoload (string-append input "/share/web/" dependency
-                                      "/vendor/autoload_conf.php")))
-          (if (file-exists? autoload)
-              autoload
-              (loop inputs))))
-      ((input inputs ...)
-       (let ((autoload (string-append input "/share/web/" dependency
-                                      "/vendor/autoload_conf.php")))
-         (if (file-exists? autoload)
-             autoload
-             (loop inputs)))))))
+(define* (check #:key composer-file inputs
+                tests? test-target test-flags #:allow-other-keys)
+  "Test the given package.
+Please note that none of the PHP packages at the time of the rewrite of the
+build-system did use the test-script field.  This means that the @code{match
+test-script} part is not tested on a real example and relies on the original
+implementation."
+  (if tests?
+      (let* ((package-data (read-package-data #:filename composer-file))
+             (scripts (composer-package-scripts package-data))
+             (test-script (assoc-ref scripts test-target)))
+        (match test-script
+          ((? string? bin)
+           (let ((command (find-bin bin inputs)))
+             (unless (zero? (apply system command test-flags))
+               (throw 'failed-command command))))
+          (('@ (? string? bins) ...)
+           (for-each
+            (lambda (c)
+              (let ((command (find-bin bin inputs)))
+                (unless (zero? (apply system command test-flags))
+                  (throw 'failed-command command))))
+            bins))
+          (_ (if (file-exists? "phpunit.xml.dist")
+                 (apply invoke
+                        (with-exception-handler
+                            (lambda (exn)
+                              (if (search-error? exn)
+                                  (error "\
+Missing php-phpunit-phpunit native input.~%")
+                                  (raise exn)))
+                          (lambda ()
+                            (search-input-file (or inputs '()) "bin/phpunit")))
+                        test-flags))
+             (format #t "No test suite found.~%"))))
+      (format #t "Test suite not run.~%")))
 
 (define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
   "creates an autoload.php file that sets up the class locations for this package,
@@ -144,15 +149,14 @@ (define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
       (display (string-append
                  "<?php
 // autoload.php @generated by Guix
-$map = $psr4map = $classmap = array();
-require_once '" vendor "/autoload_conf.php'
-require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'
+$psr4map = $classmap = array();
+require_once '" vendor "/autoload_conf.php';
+require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php';
 $loader = new \\Composer\\Autoload\\ClassLoader();
-foreach ($map as $namespace => $path) {
-  $loader->set($namespace, $path);
-}
-foreach ($psr4map as $namespace => $path) {
-  $loader->setPsr4($namespace, $path);
+foreach ($psr4map as $namespace => $paths) {
+    foreach ($paths as $path) {
+        $loader->addPsr4($namespace, $path);
+    }
 }
 $loader->addClassMap($classmap);
 $loader->register();
@@ -170,37 +174,85 @@ (define* (create-autoload vendor composer-file inputs #:key dev-dependencies?)
         (format #t "// autoload_conf.php @generated by Guix~%")
         (force-output)
         (for-each
-          (lambda (psr4)
-            (match psr4
-              ((key . value)
-               (format #t "$psr4map['~a'] = '~a/../~a';~%"
-                       (string-join (string-split key #\\) "\\\\")
-                       vendor value))))
+         (match-lambda
+           ((key . value)
+            (let ((vals (if (list? value)
+                            (reverse value)
+                            (list value))))
+              (apply
+               format
+               #t
+               (string-append
+                "$psr4map['~a'][] = ["
+                (string-join
+                 (make-list (length vals) "'~a/../~a'") ",")
+                "];~%")
+               (cons* (string-join (string-split key #\\) "\\\\")
+                      (append-map (lambda (v) (list vendor v)) vals)))))
+           (_ (format #t "")))
+         (merge-duplicates
           (append
-            (composer-autoload-psr-4 autoload)
-            (if dev-dependencies?
-                (composer-autoload-psr-4 autoload-dev)
-                '())))
+           (composer-autoload-psr-4 autoload)
+           (if (and dev-dependencies? (not (null? autoload-dev)))
+               (composer-autoload-psr-4 autoload-dev)
+               '()))
+          '()))
         (for-each
-          (lambda (classmap)
-            (for-each
-              (lambda (file)
-                (invoke "php" (assoc-ref inputs "findclass.php")
-                        "-i" (string-append vendor "/..") "-f" file))
-              (find-files classmap ".(php|hh|inc)$")))
-          (append
-            (composer-autoload-classmap autoload)
-            (if dev-dependencies?
-                (composer-autoload-classmap autoload-dev)
-                '())))
+         (lambda (psr0)
+           (match psr0
+             ((key . value)
+              (format #t "$psr4map['~a'][] = ['~a/../~a/~a'];~%"
+                      (string-join (string-split key #\\) "\\\\")
+                      vendor
+                      value
+                      (string-join (string-split key #\\) "/")))
+             (_ (format #t ""))))
+         (append
+          (composer-autoload-psr-0 autoload)
+          (if (and dev-dependencies? (not (null? autoload-dev)))
+              (composer-autoload-psr-0 autoload-dev)
+              '())))
         (for-each
-          (lambda (dep)
-            (format #t "require_once '~a';~%" (find-php-dep inputs dep)))
-          (append
-            dependencies
-            (if dev-dependencies?
-                dependencies-dev
-                '())))))))
+         (lambda (classmap)
+           (for-each
+            (lambda (file)
+              (invoke "php" (assoc-ref inputs "findclass.php")
+                      "-i" (string-append vendor "/..") "-f" file))
+            (find-files classmap ".(php|hh|inc)$")))
+         (append
+          (composer-autoload-classmap autoload)
+          (if (and dev-dependencies? (not (null? autoload-dev)))
+              (composer-autoload-classmap autoload-dev)
+              '())))
+        (for-each
+         (lambda (file)
+           (format #t "require_once '~a/../~a';~%" vendor file))
+         (append
+          (composer-autoload-files autoload)
+          (if (and dev-dependencies? (not (null? autoload-dev)))
+              (composer-autoload-files autoload-dev)
+              '())))
+        (for-each
+         (lambda (dep)
+           (format
+            #t "require_once '~a';~%"
+            (search-input-file
+             inputs
+             (string-append "/share/web/" dep "/vendor/autoload_conf.php"))))
+          dependencies)
+        ;; Also add native-inputs that are not necessarily given in the
+        ;; composer.json. This allows to simply add a package in tests by
+        ;; adding it in native-inputs, without the need to patch composer.json.
+        (for-each
+         (match-lambda
+           ((name . loc)
+            (match (find-files loc "autoload_conf\\.php$")
+              (() #t)
+              (((? string? conf) . ())
+               (format #t "require_once '~a';~%" conf))
+              (_ #t)))
+           (_ #t))
+         (or inputs '()))))))
 
 (define* (install #:key inputs outputs composer-file #:allow-other-keys)
   "Install the given package."
@@ -237,7 +289,8 @@ (define %standard-phases
     (delete 'build)
     (delete 'check)
     (replace 'install install)
-    (add-after 'install 'check check)))
+    (add-after 'install 'check check)
+    (add-after 'install 'create-test-autoload create-test-autoload)))
 
 (define* (composer-build #:key inputs (phases %standard-phases)
                          #:allow-other-keys #:rest args)
-- 
2.41.0





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

* [bug#42338] [Nicolas Graves via Guix-patches via] [bug#42338] [PATCH v5 0/9] Composer build-system
       [not found]   ` <87ttq3u8m4.fsf@ngraves.fr>
@ 2023-12-07 12:36     ` Nicolas Graves via Guix-patches via
  0 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-12-07 12:36 UTC (permalink / raw)
  To: Ludovic Courtès
  Cc: Josselin Poiret, 42338, Mathieu Othacehe, Tobias Geerinckx-Rice,
	Ricardo Wurmus, Christopher Baines, Simon Tournier


Just a quick reminder for this patch series. ;)

The right version is the v5 now, and I was asking for opinions on a
change of names too ;) 

Cheers,

Nicolas 


On 2023-11-02 22:51, Nicolas Graves wrote:

> Sorry I did send the patch series twice because I forgot the v5 in the
> first.
>
> You can find the packages attached if useful for testing, but I will
> commit only after we agree on the proper renaming of the import and
> build-system, so that I can do it in a sole patch series.
>
>
>
> -------------------- Start of forwarded message --------------------
> Subject: [bug#42338] [PATCH v5 0/9] Composer build-system
> To: 42338@debbugs.gnu.org
> Cc: ngraves@ngraves.fr
> Date: Thu,  2 Nov 2023 16:16:47 +0100
> From:  Nicolas Graves via Guix-patches via <guix-patches@gnu.org>
>
> This is the result of my further rework of the composer import and
> build-system. The `guix: import: composer` commits can be squashed
> easily.
>
> This is now tested on 94 php packages with all testing enabled except
> for 3 packages. I will submit these packages as a whole in the
> alphabetical order (the bootstrap order is not worth it IMO) in a new
> guix issue.
>
> Before accepting it, I also would like to propose a change of
> names. If me make an analogy with python:
> tool: pip <-> composer
> package hub: pypi <-> packagist
> build-system: python/pyproject <-> php
>
> Since we only take about 90 lines of real composer code, I would
> rather call the build-system php-build-system.
> Same thing: instead of `guix import composer` we should rather call
> `guix import packagist`.
>
> If that's OK, I'll change it with the next (and hopefully last!)
> version of this build system.
>
> Nicolas Graves (9):
>   guix: import: Add composer importer.
>   gnu: Add composer-classloader.
>   guix: Add composer-build-system.
>   guix: import: composer: Use memoization.
>   guix: import: composer: Fix json->require.
>   guix: import: composer: More robust string->license.
>   guix: import: composer: Modern inputs formatting.
>   guix: import: composer: Full rewrite composer-fetch.
>   gnu: composer-build-system: Full check phase rewrite.
>
>  Makefile.am                          |   6 +
>  doc/guix.texi                        |  34 +++
>  gnu/local.mk                         |   1 +
>  gnu/packages/aux-files/findclass.php | 125 +++++++++++
>  gnu/packages/php-xyz.scm             |  60 ++++++
>  guix/build-system/composer.scm       | 164 +++++++++++++++
>  guix/build/composer-build-system.scm | 300 +++++++++++++++++++++++++++
>  guix/import/composer.scm             | 267 ++++++++++++++++++++++++
>  guix/scripts/import.scm              |   2 +-
>  guix/scripts/import/composer.scm     | 107 ++++++++++
>  tests/composer.scm                   |  88 ++++++++
>  11 files changed, 1153 insertions(+), 1 deletion(-)
>  create mode 100644 gnu/packages/aux-files/findclass.php
>  create mode 100644 gnu/packages/php-xyz.scm
>  create mode 100644 guix/build-system/composer.scm
>  create mode 100644 guix/build/composer-build-system.scm
>  create mode 100644 guix/import/composer.scm
>  create mode 100644 guix/scripts/import/composer.scm
>  create mode 100644 tests/composer.scm
>
> --
> 2.41.0
>
>
>
>
> -------------------- End of forwarded message --------------------
>
> --
> Best regards,
> Nicolas Graves

--
Best regards,
Nicolas Graves




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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (9 preceding siblings ...)
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
@ 2023-12-09 22:00 ` Charlie McMackin
  2023-12-20 10:41 ` Wilko Meyer
  11 siblings, 0 replies; 95+ messages in thread
From: Charlie McMackin @ 2023-12-09 22:00 UTC (permalink / raw)
  To: 42338

Hello,

I'm another user interested in this patch series. Thanks for carrying
it forward. I thought I would try it out myself and give feedback if I
discovered anything but I'm running into issues with the v5 patch
series:

1. When I run `git am -3` on the archive mbox for this patch series, I
have to skip patch 0 (empty) and then it fails on patch 0004 with;

Applying: guix: Add composer-build-system.
error: sha1 information is lacking or useless (Makefile.am).
error: could not build fake ancestor
Patch failed at 0004 guix: Add composer-build-system.

I'm trying to apply to a branch with HEAD at 61f2d84e75.

2. I am a bit new to applying patches from mail but I thought I could
resolve the problem if I knew where the branch began and applied
there. However, I am not able to find where this patch series branches
from. Should that information (the ancestor SHA1) be in the PATCH 0?
Is there something I'm missing with `git am` style patches?

3. Without any authority, making it `guix import packagist` sounds
reasonable to me given the existing patterns with other importers like
pypi and crate.

4. Do you plan to add a news.scm entry in the next patch series as
suggested by Ludovic?

I look forward to testing this out! Thanks,
Charlie




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

* [bug#42338] [PATCH v5 0/9] Composer build-system
  2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
                     ` (9 preceding siblings ...)
       [not found]   ` <87ttq3u8m4.fsf@ngraves.fr>
@ 2023-12-18 22:33   ` Ludovic Courtès
  2023-12-19  7:43     ` Nicolas Graves via Guix-patches via
  10 siblings, 1 reply; 95+ messages in thread
From: Ludovic Courtès @ 2023-12-18 22:33 UTC (permalink / raw)
  To: Nicolas Graves; +Cc: Julien Lepiller, 42338

Hi,

Nicolas Graves <ngraves@ngraves.fr> skribis:

> This is the result of my further rework of the composer import and
> build-system. The `guix: import: composer` commits can be squashed
> easily.
>
> This is now tested on 94 php packages with all testing enabled except
> for 3 packages. I will submit these packages as a whole in the
> alphabetical order (the bootstrap order is not worth it IMO) in a new
> guix issue.
>
> Before accepting it, I also would like to propose a change of
> names. If me make an analogy with python:
> tool: pip <-> composer
> package hub: pypi <-> packagist
> build-system: python/pyproject <-> php
>
> Since we only take about 90 lines of real composer code, I would
> rather call the build-system php-build-system. 
> Same thing: instead of `guix import composer` we should rather call
> `guix import packagist`.
>
> If that's OK, I'll change it with the next (and hopefully last!)
> version of this build system.
>
> Nicolas Graves (9):
>   guix: import: Add composer importer.
>   gnu: Add composer-classloader.
>   guix: Add composer-build-system.
>   guix: import: composer: Use memoization.
>   guix: import: composer: Fix json->require.
>   guix: import: composer: More robust string->license.
>   guix: import: composer: Modern inputs formatting.
>   guix: import: composer: Full rewrite composer-fetch.
>   gnu: composer-build-system: Full check phase rewrite.

In the interest of moving forward, I pushed this:

  6454788a5c build-system/composer: Do not import host-side Guile-JSON modules.
  9dab758791 build-system: Add ‘composer-build-system’.
  e8fd78d54e gnu: Add composer-classloader.
  b7e3945283 guix: import: Add composer importer.

I squashed the importer commits.

However, I also add to make way too many fixes to my taste: adding
missing #:use-module, fixing unbound variables (guessing…), fixing
typos, untangling and build system commit that was fixing things in the
importer, fixing ‘tests/composer.scm’ which wouldn’t pass, fixing a case
where the importer would return a single value instead of two (breaking
recursive imports), and probably others that I forgot.  Not great.

Could you please take a closer look and see whether anything is amiss at
this point?

Next, which PHP packages do we add?  Julien initially submitted 30ish of
them, should we take those?  Or are you planning to submit a separate
set?

It would also be nice if the updater would fill in the ‘inputs’ fields
of <upstream-source>: that would allow ‘guix refresh -u’ to
automatically update inputs.

Thanks in advance!

Ludo’.




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

* [bug#42338] [PATCH v5 0/9] Composer build-system
  2023-12-18 22:33   ` Ludovic Courtès
@ 2023-12-19  7:43     ` Nicolas Graves via Guix-patches via
  0 siblings, 0 replies; 95+ messages in thread
From: Nicolas Graves via Guix-patches via @ 2023-12-19  7:43 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Julien Lepiller, 42338

On 2023-12-18 23:33, Ludovic Courtès wrote:

> Hi,
>
> Nicolas Graves <ngraves@ngraves.fr> skribis:
>
>> This is the result of my further rework of the composer import and
>> build-system. The `guix: import: composer` commits can be squashed
>> easily.
>>
>> This is now tested on 94 php packages with all testing enabled except
>> for 3 packages. I will submit these packages as a whole in the
>> alphabetical order (the bootstrap order is not worth it IMO) in a new
>> guix issue.
>>
>> Before accepting it, I also would like to propose a change of
>> names. If me make an analogy with python:
>> tool: pip <-> composer
>> package hub: pypi <-> packagist
>> build-system: python/pyproject <-> php

>>
>> Since we only take about 90 lines of real composer code, I would
>> rather call the build-system php-build-system. 
>> Same thing: instead of `guix import composer` we should rather call
>> `guix import packagist`.

Do you have an opinion on this? I guess now that's in the code, we can
keep it as is, but that's sad we didn't get to discuss on this. 

>>
>> If that's OK, I'll change it with the next (and hopefully last!)
>> version of this build system.
>>
>> Nicolas Graves (9):
>>   guix: import: Add composer importer.
>>   gnu: Add composer-classloader.
>>   guix: Add composer-build-system.
>>   guix: import: composer: Use memoization.
>>   guix: import: composer: Fix json->require.
>>   guix: import: composer: More robust string->license.
>>   guix: import: composer: Modern inputs formatting.
>>   guix: import: composer: Full rewrite composer-fetch.
>>   gnu: composer-build-system: Full check phase rewrite.
>
> In the interest of moving forward, I pushed this:
>
>   6454788a5c build-system/composer: Do not import host-side Guile-JSON modules.
>   9dab758791 build-system: Add ‘composer-build-system’.
>   e8fd78d54e gnu: Add composer-classloader.
>   b7e3945283 guix: import: Add composer importer.
>
> I squashed the importer commits.
>
> However, I also add to make way too many fixes to my taste: adding
> missing #:use-module, fixing unbound variables (guessing…), fixing
> typos, untangling and build system commit that was fixing things in the
> importer, fixing ‘tests/composer.scm’ which wouldn’t pass, fixing a case
> where the importer would return a single value instead of two (breaking
> recursive imports), and probably others that I forgot.  Not great.
>
> Could you please take a closer look and see whether anything is amiss at
> this point?

Not great indeed, seemed to work fine on my end, will take a look. I
hope I didn't send a different patch series than intended. 

>
> Next, which PHP packages do we add?  Julien initially submitted 30ish of
> them, should we take those?  Or are you planning to submit a separate
> set?

I have a set of 94-97 packages, I've sent them in an email to you and
Julien (an email from ngraves@ngraves.fr on november 2nd), these should
work with this set of commits. Will cut that in commits and submit them
quickly. 

>
> It would also be nice if the updater would fill in the ‘inputs’ fields
> of <upstream-source>: that would allow ‘guix refresh -u’ to
> automatically update inputs.

I will first focus on fixes and packages.

>
> Thanks in advance!
>
> Ludo’.

-- 
Best regards,
Nicolas Graves




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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
                   ` (10 preceding siblings ...)
  2023-12-09 22:00 ` [bug#42338] [PATCH] Add composer build system (PHP) Charlie McMackin
@ 2023-12-20 10:41 ` Wilko Meyer
  2023-12-20 11:31   ` Julien Lepiller
  11 siblings, 1 reply; 95+ messages in thread
From: Wilko Meyer @ 2023-12-20 10:41 UTC (permalink / raw)
  To: 42338

Hi,

Just wanted to say thanks for all this work, was really surprised to see
a composer-build-system in Guix and a handy packagist importer!

As far as I'm aware, there's not a structure in gnu/packages yet for
composer packages. Hope this is the right place to ask, I'm considering
packaging my more used dependencies for Guix, do they go into
php.scm/php-xyz.scm? a yet-to-be-created packagist.scm? Should there be
a more thematic grouping (e.g. how python*.scm is currently structured)?

Thanks for this great work!

-- 
Kind regards,

Wilko Meyer
w@wmeyer.eu




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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2023-12-20 10:41 ` Wilko Meyer
@ 2023-12-20 11:31   ` Julien Lepiller
  2023-12-20 11:40     ` Wilko Meyer
  0 siblings, 1 reply; 95+ messages in thread
From: Julien Lepiller @ 2023-12-20 11:31 UTC (permalink / raw)
  To: 42338, w

Hi,

I would put them in php-xyz.scm. php.scm would be for the compiler and language tools. If we start having a lot of php packages, we could start creating more modules.

I don't think packagist.scm would work, similar to how we have python.scm, not pypi.scm :)

Le 20 décembre 2023 11:41:55 GMT+01:00, Wilko Meyer <w@wmeyer.eu> a écrit :
>Hi,
>
>Just wanted to say thanks for all this work, was really surprised to see
>a composer-build-system in Guix and a handy packagist importer!
>
>As far as I'm aware, there's not a structure in gnu/packages yet for
>composer packages. Hope this is the right place to ask, I'm considering
>packaging my more used dependencies for Guix, do they go into
>php.scm/php-xyz.scm? a yet-to-be-created packagist.scm? Should there be
>a more thematic grouping (e.g. how python*.scm is currently structured)?
>
>Thanks for this great work!
>




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

* [bug#42338] [PATCH] Add composer build system (PHP)
  2023-12-20 11:31   ` Julien Lepiller
@ 2023-12-20 11:40     ` Wilko Meyer
  0 siblings, 0 replies; 95+ messages in thread
From: Wilko Meyer @ 2023-12-20 11:40 UTC (permalink / raw)
  To: Julien Lepiller; +Cc: w, 42338


Hi Julien,

Julien Lepiller <julien@lepiller.eu> writes:

> I would put them in php-xyz.scm. php.scm would be for the compiler and language tools. If we start having a lot of php packages, we could start creating more modules.

Sounds good!

> I don't think packagist.scm would work, similar to how we have
> python.scm, not pypi.scm :)

We do have crates-io.scm and rust{,-apps}.scm for rust, which is why I
was asking (though I don't know the background of why crates-io.scm was
chosen for rust crates). But that may be more of an outlier then in the
structure of gnu/packages.

-- 
Kind regards,

Wilko Meyer
w@wmeyer.eu




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

end of thread, other threads:[~2023-12-20 11:48 UTC | newest]

Thread overview: 95+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-12 22:20 [bug#42338] [PATCH] Add composer build system (PHP) Julien Lepiller
2020-07-12 22:25 ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 02/34] gnu: Add composer-classloader Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 03/34] guix: Add composer-build-system Julien Lepiller
2020-09-07 14:09     ` Ludovic Courtès
2020-09-17 22:44       ` Julien Lepiller
2020-09-18  8:45         ` Ludovic Courtès
2020-09-18 23:24           ` Julien Lepiller
2020-09-25 10:33             ` Ludovic Courtès
2020-09-29 14:49               ` Julien Lepiller
2020-09-30  9:24                 ` Ludovic Courtès
2020-12-18 23:43                   ` Julien Lepiller
2020-12-21 14:51                     ` Ludovic Courtès
2020-07-12 22:25   ` [bug#42338] [PATCH 04/34] gnu: Add php-doctrine-instantiator Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 05/34] gnu: Add php-sebastian-recursion-context Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 06/34] gnu: Add php-sebastian-exporter Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 07/34] gnu: Add php-myclabs-deep-copy Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 08/34] gnu: Add php-phar-io-version Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 09/34] gnu: Add php-phar-io-manifest Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 10/34] gnu: Add php-symfony-polyfill-ctype Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 11/34] gnu: Add php-webmozart-assert Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 12/34] gnu: Add php-phpdocumentor-reflection-common Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 13/34] gnu: Add php-phpdocumentor-type-resolver Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 14/34] gnu: Add php-phpdocumentor-reflection-docblock Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 15/34] gnu: Add php-theseer-tokenizer Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 16/34] gnu: Add php-sebastian-code-unit-reverse-lookup Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 17/34] gnu: Add php-phpunit-php-token-stream Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 18/34] gnu: Add php-sebastian-version Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 19/34] gnu: Add php-phpunit-php-file-iterator Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 20/34] gnu: Add php-phpunit-php-text-template Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 21/34] gnu: Add php-sebastian-diff Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 22/34] gnu: Add php-sebastian-comparator Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 23/34] gnu: Add php-sebastian-environment Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 24/34] gnu: Add php-phpspec-prophecy Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 25/34] gnu: Add php-sebastian-object-reflector Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 26/34] gnu: Add php-sebastian-global-state Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 27/34] gnu: Add php-sebastian-object-enumerator Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 28/34] gnu: Add php-sebastian-resource-operations Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 29/34] gnu: Add php-sebastian-type Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 30/34] gnu: Add php-phpunit-php-code-coverage Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 31/34] gnu: Add php-phpunit-php-timer Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 32/34] gnu: Add php-phpunit-php-invoker Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 33/34] gnu: Add php-sebastian-code-unit Julien Lepiller
2020-07-12 22:25   ` [bug#42338] [PATCH 34/34] gnu: Add phpunit Julien Lepiller
2020-09-07 14:06   ` [bug#42338] [PATCH 01/34] guix: import: Add composer importer Ludovic Courtès
2020-09-17 22:43     ` Julien Lepiller
2020-09-18  8:31       ` Ludovic Courtès
2020-09-18 23:20         ` Julien Lepiller
2020-09-25 10:27           ` Ludovic Courtès
2021-10-16  4:15             ` [bug#42338] [PATCH] Add composer build system (PHP) Maxim Cournoyer
2021-08-23  9:46 ` [bug#42338] db
2022-08-13 20:30 ` [bug#42338] Ping about php composer guix-patches--- via
2022-08-13 20:38   ` Julien Lepiller
2022-10-06 16:27 ` [bug#42338] [PATCH] Add composer build system (PHP) Maxime Devos
2022-10-11 18:07   ` guix-patches--- via
2023-04-21  0:23 ` Adam Faiz via Guix-patches via
2023-09-26 10:31 ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
2023-09-26 10:31   ` [bug#42338] [PATCH v3 2/7] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
2023-09-26 10:31   ` [bug#42338] [PATCH v3 3/7] guix: Add composer-build-system Nicolas Graves via Guix-patches via
2023-09-26 10:31   ` [bug#42338] [PATCH v3 4/7] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
2023-09-26 10:31   ` [bug#42338] [PATCH v3 5/7] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
2023-09-26 10:31   ` [bug#42338] [PATCH v3 6/7] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
2023-09-26 10:31   ` [bug#42338] [PATCH v3 7/7] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
2023-09-26 10:43   ` [bug#42338] [PATCH v3 1/7] guix: import: Add composer importer Nicolas Graves via Guix-patches via
2023-10-14 15:48   ` Ludovic Courtès
2023-09-26 11:25 ` [bug#42338] [PATCH v3] guix: import: composer: Fix match-lambda with a default fallback Nicolas Graves via Guix-patches via
2023-09-26 11:27   ` Nicolas Graves via Guix-patches via
2023-09-26 11:29 ` [bug#42338] [PATCH v4] guix: composer-build-system: Fix match-lambda with a fallback Nicolas Graves via Guix-patches via
2023-11-02 15:04 ` [bug#42338] [PATCH 0/9] Composer build system Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 2/9] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 3/9] guix: Add composer-build-system Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 4/9] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 5/9] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 6/9] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 7/9] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 8/9] guix: import: composer: Full rewrite composer-fetch Nicolas Graves via Guix-patches via
2023-11-02 15:04   ` [bug#42338] [PATCH 9/9] gnu: composer-build-system: Full check phase rewrite Nicolas Graves via Guix-patches via
2023-11-02 15:16 ` [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 1/9] guix: import: Add composer importer Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 2/9] gnu: Add composer-classloader Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 3/9] guix: Add composer-build-system Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 4/9] guix: import: composer: Use memoization Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 5/9] guix: import: composer: Fix json->require Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 6/9] guix: import: composer: More robust string->license Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 7/9] guix: import: composer: Modern inputs formatting Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 8/9] guix: import: composer: Full rewrite composer-fetch Nicolas Graves via Guix-patches via
2023-11-02 15:16   ` [bug#42338] [PATCH v5 9/9] gnu: composer-build-system: Full check phase rewrite Nicolas Graves via Guix-patches via
     [not found]   ` <87ttq3u8m4.fsf@ngraves.fr>
2023-12-07 12:36     ` [bug#42338] [Nicolas Graves via Guix-patches via] [bug#42338] [PATCH v5 0/9] Composer build-system Nicolas Graves via Guix-patches via
2023-12-18 22:33   ` Ludovic Courtès
2023-12-19  7:43     ` Nicolas Graves via Guix-patches via
2023-12-09 22:00 ` [bug#42338] [PATCH] Add composer build system (PHP) Charlie McMackin
2023-12-20 10:41 ` Wilko Meyer
2023-12-20 11:31   ` Julien Lepiller
2023-12-20 11:40     ` Wilko Meyer

Code repositories for project(s) associated with this public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).