From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id GDnDBKtJc18BHwAA0tVLHw (envelope-from ) for ; Tue, 29 Sep 2020 14:50:19 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1 with LMTPS id iEiJAKtJc1/SbwAAbx9fmQ (envelope-from ) for ; Tue, 29 Sep 2020 14:50:19 +0000 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 0E2589402A3 for ; Tue, 29 Sep 2020 14:50:17 +0000 (UTC) Received: from localhost ([::1]:46218 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kNGxL-0002Qh-TL for larch@yhetil.org; Tue, 29 Sep 2020 10:50:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:32896) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kNGx8-0002Pq-1y for guix-patches@gnu.org; Tue, 29 Sep 2020 10:50:02 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:45338) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kNGx7-00037J-O0 for guix-patches@gnu.org; Tue, 29 Sep 2020 10:50:01 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1kNGx7-00089I-Jv for guix-patches@gnu.org; Tue, 29 Sep 2020 10:50:01 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#42338] [PATCH 03/34] guix: Add composer-build-system. Resent-From: Julien Lepiller Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 29 Sep 2020 14:50:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 42338 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 42338@debbugs.gnu.org Received: via spool by 42338-submit@debbugs.gnu.org id=B42338.160139099131293 (code B ref 42338); Tue, 29 Sep 2020 14:50:01 +0000 Received: (at 42338) by debbugs.gnu.org; 29 Sep 2020 14:49:51 +0000 Received: from localhost ([127.0.0.1]:56881 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kNGwq-00088X-DV for submit@debbugs.gnu.org; Tue, 29 Sep 2020 10:49:51 -0400 Received: from lepiller.eu ([89.234.186.109]:50914) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1kNGwl-00088H-3K for 42338@debbugs.gnu.org; Tue, 29 Sep 2020 10:49:43 -0400 Received: from lepiller.eu (localhost [127.0.0.1]) by lepiller.eu (OpenSMTPD) with ESMTP id 404a0e97; Tue, 29 Sep 2020 14:49:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; d=lepiller.eu; h=date:from :to:cc:subject:message-id:in-reply-to:references:mime-version :content-type; s=dkim; bh=wcgz7dM5pytS2F368frIn8dmtK8Z2cfDrcDtOl QnJBI=; b=bIlnXpDp3q4J1FY0ixsQvM2pYKwjwwBslVDCljyrfn0hRifhqwEFkF 4aTtgdv5l3CGOMEEjPof77PH5uVZPszZ3fF/J5WhNeFE59WAjJgruRMJAZBqfVga /mZaWtuBkOjCko4z3LjDktiK0DNk0aL94TR56OPLGPddhLp4ljvserPBKlLTaF4H 6SfxAO7pZrjwDaKB58cC2jkuDBwSGpUuI+q4nMxZndgSkAE/PnP7L8BwWIxoO6io hdKMXL8KAFgDfGGAEmt2Hoz6VVOvqKfabGMlmcX5WyGr1AGvG1+M/Pax68hpTYlW 2HZ8se017GEM7zThNwG9zBhfxN2N+IhA== Received: by lepiller.eu (OpenSMTPD) with ESMTPSA id 3bf0a08d (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256:NO); Tue, 29 Sep 2020 14:49:36 +0000 (UTC) Date: Tue, 29 Sep 2020 16:49:20 +0200 From: Julien Lepiller Message-ID: <20200929164920.0684be42@tachikoma.lepiller.eu> In-Reply-To: <87eemq16y3.fsf@gnu.org> References: <20200713002055.1553f136@tachikoma.lepiller.eu> <20200712222538.18092-1-julien@lepiller.eu> <20200712222538.18092-3-julien@lepiller.eu> <87imcphe6a.fsf@gnu.org> <20200918004403.0d755d60@tachikoma.lepiller.eu> <87eemz1nib.fsf@gnu.org> <20200919012420.301201e8@tachikoma.lepiller.eu> <87eemq16y3.fsf@gnu.org> X-Mailer: Claws Mail 3.17.6 (GTK+ 2.24.32; x86_64-unknown-linux-gnu) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="MP_/wX.Yq./3HOZ_fNNuuCidCBh" X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-Spam-Score: -1.0 (-) X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+larch=yhetil.org@gnu.org Sender: "Guix-patches" X-Scanner: scn0 Authentication-Results: aspmx1.migadu.com; dkim=fail (rsa verify failed) header.d=lepiller.eu header.s=dkim header.b=bIlnXpDp; dmarc=fail reason="SPF not aligned (relaxed)" header.from=lepiller.eu (policy=none); spf=pass (aspmx1.migadu.com: domain of guix-patches-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=guix-patches-bounces@gnu.org X-Spam-Score: 0.09 X-TUID: m378q/zMyf0k --MP_/wX.Yq./3HOZ_fNNuuCidCBh Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Le Fri, 25 Sep 2020 12:33:56 +0200, Ludovic Court=C3=A8s a =C3=A9crit : > Hi, >=20 > As for Guile-JSON: perhaps you can post a draft that we can play with > to see if there=E2=80=99s anything wrong, but off the top of my head I do= n=E2=80=99t > see why it wouldn=E2=80=99t work. >=20 > Thanks, > Ludo=E2=80=99. 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? --MP_/wX.Yq./3HOZ_fNNuuCidCBh Content-Type: text/x-patch Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename=0003-guix-Add-composer-build-system.patch =46rom 432f57aeeb3b2e48591288e6491d66ab299661f0 Mon Sep 17 00:00:00 2001 From: Julien Lepiller 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 =3D \ 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 =3D \ 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 =3D \ 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 =20 # Templates, examples. EXAMPLES =3D \ 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 c= ode is compiled with @code{-O2 -g}, as is the case for Autoconf-based packages by default. @end defvr =20 +@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 t= he +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 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICEN= SE + * file that was distributed with this source code. + * + * This file is copied from the Symfony package. + * + * (c) Fabien Potencier + *=20 + * To the extent to wich it makes sense, as the author of the extract: + * Copyright =C2=A9 2020 Julien Lepiller + */ + +/** + * 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 =3D PHP_VERSION_ID < 50400 ? '' : '|trait'; + if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>= =3D')) { + $extraTypes .=3D '|enum'; + } + // Use @ here instead of Silencer to actively suppress 'unhelpful' out= put + // @link https://github.com/composer/composer/pull/4886 + $contents =3D @php_strip_whitespace($path); + if (!$contents) { + if (!file_exists($path)) { + $message =3D 'File at "%s" does not exist, check your classmap= definitions'; + } elseif (!is_readable($path)) { + $message =3D 'File at "%s" is not readable, check its permissi= ons'; + } elseif ('' =3D=3D=3D trim(file_get_contents($path))) { + // The input file was really empty and thus contains no classes + return array(); + } else { + $message =3D 'File at "%s" could not be parsed as PHP, it may = be binary or corrupted'; + } + $error =3D error_get_last(); + if (isset($error['message'])) { + $message .=3D 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 =3D preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?= :.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=3D\s+|[;,.)])}s', 'null', $contents); + // strip strings + $contents =3D preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\= \]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents); + // strip leading non-php code if needed + if (substr($contents, 0, 2) !=3D=3D '(?:[^<]++|<(?!\?))*+<\?}s', '?>'); + if (false !=3D=3D $pos && false =3D=3D=3D strpos(substr($contents, $po= s), '])(?Pclass|interface'.$extraTypes.') \s++ (?= P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+) + | \b(?])(?Pnamespace) (?P\s++[a-zA-Z_\x7f-\x= ff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-= \xff]*+)*+)? \s*+ [\{;] + ) + }ix', $contents, $matches); + $classes =3D array(); + $namespace =3D ''; + for ($i =3D 0, $len =3D count($matches['type']); $i < $len; $i++) { + if (!empty($matches['ns'][$i])) { + $namespace =3D str_replace(array(' ', "\t", "\r", "\n"), '', $= matches['nsname'][$i]) . '\\'; + } else { + $name =3D $matches['name'][$i]; + // skip anon classes extending/implementing + if ($name =3D=3D=3D 'extends' || $name =3D=3D=3D 'implements')= { + continue; + } + if ($name[0] =3D=3D=3D ':') { + // This is an XHP class, https://github.com/facebook/xhp + $name =3D 'xhp'.substr(str_replace(array('-', ':'), array(= '_', '__'), $name), 1); + } elseif ($matches['type'][$i] =3D=3D=3D 'enum') { + // In Hack, something like: + // enum Foo: int { HERP =3D '123'; } + // The regex above captures the colon, which isn't part of + // the class name. + $name =3D rtrim($name, ':'); + } + $classes[] =3D ltrim($namespace . $name, '\\'); + } + } + return $classes; +} + +$options =3D getopt('i:f:', []); +$file =3D $options["f"]; +$input =3D $options["i"]; + +$classes =3D findClasses($file); +foreach($classes as $class) { + echo '$classmap[\''.$class.'\'] =3D \''.$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 =C2=A9 2019 Julien Lepiller +;;; +;;; 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 . +(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 imple= mented +;; 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-compilati= on + (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 provi= des +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->se= xp + 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-bui= ld-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 =C2=A9 2019 Julien Lepiller +;;; +;;; 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 . + +(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 make-composer-autoload composer-a= utoload? + 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 make-composer-package composer-pac= kage? + json->composer-package + (name composer-package-name) + (autoload composer-package-autoload "autoload" json->composer-autolo= ad) + (autoload-dev composer-package-autoload-dev "autoload-dev" json->compose= r-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 #:al= low-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-dependenci= es?) + "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 + " $path) { + $loader->set($namespace, $path); +} +foreach ($psr4map as $namespace =3D> $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 "