build-system: 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. Co-authored-by: Julien Lepiller <julien@lepiller.eu> Signed-off-by: Ludovic Courtès <ludo@gnu.org> Change-Id: Ie6a05b42ff04d3ad774a0a20278a77e4820bb8f6master
parent
e8fd78d54e
commit
9dab758791
|
@ -154,6 +154,7 @@ MODULES = \
|
|||
guix/build-system/clojure.scm \
|
||||
guix/build-system/cmake.scm \
|
||||
guix/build-system/copy.scm \
|
||||
guix/build-system/composer.scm \
|
||||
guix/build-system/dub.scm \
|
||||
guix/build-system/dune.scm \
|
||||
guix/build-system/elm.scm \
|
||||
|
@ -212,6 +213,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 \
|
||||
|
@ -420,6 +422,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.6-arm.conf \
|
||||
gnu/packages/aux-files/linux-libre/6.6-arm64.conf \
|
||||
|
|
|
@ -9598,6 +9598,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 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
|
||||
|
|
|
@ -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";
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
;;; 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")
|
||||
(test-flags ''())
|
||||
(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
|
||||
#:test-flags #$test-flags
|
||||
#: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
|
|
@ -0,0 +1,301 @@
|
|||
;;; 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-1)
|
||||
#: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"
|
||||
(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))
|
||||
(files composer-autoload-files "files"
|
||||
(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* (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
|
||||
inputs #:dev-dependencies? #t)))
|
||||
|
||||
(define (find-bin script inputs)
|
||||
(search-input-file inputs
|
||||
(string-append
|
||||
"bin/"
|
||||
(string-drop script (string-length "vendor/bin/")))))
|
||||
|
||||
(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 c 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,
|
||||
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
|
||||
$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 ($psr4map as $namespace => $paths) {
|
||||
foreach ($paths as $path) {
|
||||
$loader->addPsr4($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
|
||||
(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 "")))
|
||||
(delete-duplicates
|
||||
(append
|
||||
(composer-autoload-psr-4 autoload)
|
||||
(if (and dev-dependencies? (not (null? autoload-dev)))
|
||||
(composer-autoload-psr-4 autoload-dev)
|
||||
'()))
|
||||
'()))
|
||||
(for-each
|
||||
(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 (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."
|
||||
(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)
|
||||
(add-after 'install 'create-test-autoload create-test-autoload)))
|
||||
|
||||
(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
|
Reference in New Issue