Merge remote-tracking branch 'parent/master'
Conflicts: doc/04-schema.mdpull/1407/head
commit
7d63eb5718
|
@ -0,0 +1,8 @@
|
|||
# Auto-detect text files, ensure they use LF.
|
||||
* text=auto eol=lf
|
||||
|
||||
# These files are always considered text and should use LF.
|
||||
# See core.whitespace @ http://git-scm.com/docs/git-config for whitespace flags.
|
||||
*.php text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 diff=php
|
||||
*.json text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4
|
||||
*.test text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4
|
|
@ -8,3 +8,4 @@ phpunit.xml
|
|||
.vagrant
|
||||
Vagrantfile
|
||||
.idea
|
||||
.php_cs.cache
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$finder = Symfony\CS\Finder\DefaultFinder::create()
|
||||
->files()
|
||||
->name('*.php')
|
||||
->exclude('Fixtures')
|
||||
->in(__DIR__.'/src')
|
||||
->in(__DIR__.'/tests')
|
||||
;
|
||||
|
||||
return Symfony\CS\Config\Config::create()
|
||||
->setUsingCache(true)
|
||||
->level(Symfony\CS\FixerInterface::NONE_LEVEL)
|
||||
->fixers(array(
|
||||
'psr0', 'encoding', 'short_tag', 'braces', 'elseif', 'eof_ending', 'function_declaration', 'indentation', 'line_after_namespace', 'linefeed', 'lowercase_constants', 'lowercase_keywords', 'multiple_use', 'php_closing_tag', 'trailing_spaces', 'visibility', 'duplicate_semicolon', 'extra_empty_lines', 'include', 'namespace_no_leading_whitespace', 'object_operator', 'operators_spaces', 'phpdoc_params', 'return', 'single_array_no_trailing_comma', 'spaces_cast', 'standardize_not_equal', 'ternary_spaces', 'unused_use', 'whitespacy_lines', 'multiline_array_tailing_comma',
|
||||
))
|
||||
->finder($finder)
|
||||
;
|
24
.travis.yml
24
.travis.yml
|
@ -1,23 +1,39 @@
|
|||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
addons:
|
||||
apt_packages:
|
||||
- parallel
|
||||
|
||||
php:
|
||||
- 5.3.3
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
- hhvm-nightly
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- php: hhvm-nightly
|
||||
|
||||
before_script:
|
||||
- sudo apt-get install parallel
|
||||
- rm -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
|
||||
- composer install --prefer-source
|
||||
- bin/composer install --prefer-source
|
||||
- composer install
|
||||
- bin/composer install
|
||||
- git config --global user.name travis-ci
|
||||
- git config --global user.email travis@example.com
|
||||
|
||||
script:
|
||||
- ls -d tests/Composer/Test/* | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml {};'
|
||||
- ls -d tests/Composer/Test/* | parallel --gnu --keep-order 'echo "Running {} tests"; ./vendor/bin/phpunit -c tests/complete.phpunit.xml --colors=always {} || (echo -e "\e[41mFAILED\e[0m {}" && $(exit 1));'
|
||||
|
||||
git:
|
||||
depth: 5
|
||||
|
|
56
CHANGELOG.md
56
CHANGELOG.md
|
@ -1,4 +1,28 @@
|
|||
### 1.0.0-alpha9 (2014-12-07)
|
||||
### [1.0.0-alpha10] - 2015-04-14
|
||||
|
||||
* Break: The following event classes are deprecated and you should update your script handlers to use the new ones in type hints:
|
||||
- `Composer\Script\CommandEvent` is deprecated, use `Composer\Script\Event`
|
||||
- `Composer\Script\PackageEvent` is deprecated, use `Composer\Installer\PackageEvent`
|
||||
* Break: Output is now split between stdout and stderr. Any irrelevant output to each command is on stderr as per unix best practices.
|
||||
* Added support for npm-style semver operators (`^` and `-` ranges, ` ` = AND, `||` = OR)
|
||||
* Added --prefer-lowest to `update` command to allow testing a package with the lowest declared dependencies
|
||||
* Added support for parsing semver build metadata `+anything` at the end of versions
|
||||
* Added --sort-packages option to `require` command for sorting dependencies
|
||||
* Added --no-autoloader to `install` and `update` commands to skip autoload generation
|
||||
* Added --list to `run-script` command to see available scripts
|
||||
* Added --absolute to `config` command to get back absolute paths
|
||||
* Added `classmap-authoritative` config option, if enabled only the classmap info will be used by the composer autoloader
|
||||
* Added support for branch-alias on numeric branches
|
||||
* Added support for the `https_proxy`/`HTTPS_PROXY` env vars used only for https URLs
|
||||
* Added support for using real composer repos as local paths in `create-project` command
|
||||
* Added --no-dev to `licenses` command
|
||||
* Added support for PHP 7.0 nightly builds
|
||||
* Fixed detection of stability when parsing multiple constraints
|
||||
* Fixed installs from lock file containing updated composer.json requirement
|
||||
* Fixed the autoloader suffix in vendor/autoload.php changing in every build
|
||||
* Many minor fixes, documentation additions and UX improvements
|
||||
|
||||
### [1.0.0-alpha9] - 2014-12-07
|
||||
|
||||
* Added `remove` command to do the reverse of `require`
|
||||
* Added --ignore-platform-reqs to `install`/`update` commands to install even if you are missing a php extension or have an invalid php version
|
||||
|
@ -28,7 +52,7 @@
|
|||
* Improved SVN and Perforce support
|
||||
* A boatload of minor fixes, documentation additions and UX improvements
|
||||
|
||||
### 1.0.0-alpha8 (2014-01-06)
|
||||
### [1.0.0-alpha8] - 2014-01-06
|
||||
|
||||
* Break: The `install` command now has --dev enabled by default. --no-dev can be used to install without dev requirements
|
||||
* Added `composer-plugin` package type to allow extensibility, and deprecated `composer-installer`
|
||||
|
@ -59,7 +83,7 @@
|
|||
* Improved memory usage and performance of solving dependencies
|
||||
* Tons of minor bug fixes and improvements
|
||||
|
||||
### 1.0.0-alpha7 (2013-05-04)
|
||||
### [1.0.0-alpha7] - 2013-05-04
|
||||
|
||||
* Break: For forward compatibility, you should change your deployment scripts to run `composer install --no-dev`. The install command will install dev dependencies by default starting in the next release
|
||||
* Break: The `update` command now has --dev enabled by default. --no-dev can be used to update without dev requirements, but it will create an incomplete lock file and is discouraged
|
||||
|
@ -110,10 +134,10 @@
|
|||
* Improved the coverage of the `validate` command
|
||||
* Tons of minor bug fixes and improvements
|
||||
|
||||
### 1.0.0-alpha6 (2012-10-23)
|
||||
### [1.0.0-alpha6] - 2012-10-23
|
||||
|
||||
* Schema: Added ability to pass additional options to repositories (i.e. ssh keys/client certificates to secure private repos)
|
||||
* Schema: Added a new `~` operator that should be prefered over `>=`, see http://getcomposer.org/doc/01-basic-usage.md#package-versions
|
||||
* Schema: Added a new `~` operator that should be preferred over `>=`, see http://getcomposer.org/doc/01-basic-usage.md#package-versions
|
||||
* Schema: Version constraints `<x.y` are assumed to be `<x.y-dev` unless specified as `<x.y-stable` to reduce confusion
|
||||
* Added `config` command to edit/list config values, including --global switch for system config
|
||||
* Added OAuth token support for the GitHub API
|
||||
|
@ -121,7 +145,7 @@
|
|||
* Added --prefer-dist flag to force installs of dev packages from zip archives instead of clones
|
||||
* Added --working-dir (-d) flag to change the working directory
|
||||
* Added --profile flag to all commands to display execution time and memory usage
|
||||
* Added `github-protocols` config key to define the order of prefered protocols for github.com clones
|
||||
* Added `github-protocols` config key to define the order of preferred protocols for github.com clones
|
||||
* Added ability to interactively reset changes to vendor dirs while updating
|
||||
* Added support for hg bookmarks in the hg driver
|
||||
* Added support for svn repositories not following the standard trunk/branch/tags scheme
|
||||
|
@ -135,7 +159,7 @@
|
|||
* Improved performance of a few essential code paths
|
||||
* Many bug small fixes and docs improvements
|
||||
|
||||
### 1.0.0-alpha5 (2012-08-18)
|
||||
### [1.0.0-alpha5] - 2012-08-18
|
||||
|
||||
* Added `dump-autoload` command to only regenerate the autoloader
|
||||
* Added --optimize to `dump-autoload` to generate a more performant classmap-based autoloader for production
|
||||
|
@ -153,7 +177,7 @@
|
|||
* Improved error reporting on network failures and some other edge cases
|
||||
* Various minor bug fixes and docs improvements
|
||||
|
||||
### 1.0.0-alpha4 (2012-07-04)
|
||||
### [1.0.0-alpha4] - 2012-07-04
|
||||
|
||||
* Break: The default `minimum-stability` is now `stable`, [read more](https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion)
|
||||
* Break: Custom installers now receive the IO instance and a Composer instance in their constructor
|
||||
|
@ -181,7 +205,7 @@
|
|||
* Cleaned up / refactored the dependency solver code as well as the output for unsolvable requirements
|
||||
* Various bug fixes and docs improvements
|
||||
|
||||
### 1.0.0-alpha3 (2012-05-13)
|
||||
### [1.0.0-alpha3] - 2012-05-13
|
||||
|
||||
* Schema: Added `require-dev` for development-time requirements (tests, etc), install with --dev
|
||||
* Schema: Added author.role to list the author's role in the project
|
||||
|
@ -203,7 +227,7 @@
|
|||
* Fixed various bugs relating to package aliasing, proxy configuration, binaries
|
||||
* Various bug fixes and docs improvements
|
||||
|
||||
### 1.0.0-alpha2 (2012-04-03)
|
||||
### [1.0.0-alpha2] - 2012-04-03
|
||||
|
||||
* Added `create-project` command to install a project from scratch with composer
|
||||
* Added automated `classmap` autoloading support for non-PSR-0 compliant projects
|
||||
|
@ -218,6 +242,16 @@
|
|||
* Removed dependency on filter_var
|
||||
* Various robustness & error handling improvements, docs fixes and more bug fixes
|
||||
|
||||
### 1.0.0-alpha1 (2012-03-01)
|
||||
### 1.0.0-alpha1 - 2012-03-01
|
||||
|
||||
* Initial release
|
||||
|
||||
[1.0.0-alpha10]: https://github.com/composer/composer/compare/1.0.0-alpha9...1.0.0-alpha10
|
||||
[1.0.0-alpha9]: https://github.com/composer/composer/compare/1.0.0-alpha8...1.0.0-alpha9
|
||||
[1.0.0-alpha8]: https://github.com/composer/composer/compare/1.0.0-alpha7...1.0.0-alpha8
|
||||
[1.0.0-alpha7]: https://github.com/composer/composer/compare/1.0.0-alpha6...1.0.0-alpha7
|
||||
[1.0.0-alpha6]: https://github.com/composer/composer/compare/1.0.0-alpha5...1.0.0-alpha6
|
||||
[1.0.0-alpha5]: https://github.com/composer/composer/compare/1.0.0-alpha4...1.0.0-alpha5
|
||||
[1.0.0-alpha4]: https://github.com/composer/composer/compare/1.0.0-alpha3...1.0.0-alpha4
|
||||
[1.0.0-alpha3]: https://github.com/composer/composer/compare/1.0.0-alpha2...1.0.0-alpha3
|
||||
[1.0.0-alpha2]: https://github.com/composer/composer/compare/1.0.0-alpha1...1.0.0-alpha2
|
||||
|
|
|
@ -1,29 +1,47 @@
|
|||
Contributing to Composer
|
||||
========================
|
||||
|
||||
Please note that this project is released with a
|
||||
[Contributor Code of Conduct](http://contributor-covenant.org/version/1/0/0/).
|
||||
By participating in this project you agree to abide by its terms.
|
||||
|
||||
Reporting Issues
|
||||
----------------
|
||||
|
||||
When reporting issues, please try to be as descriptive as possible, and include
|
||||
as much relevant information as you can. A step by step guide on how to
|
||||
reproduce the issue will greatly increase the chances of your issue being
|
||||
resolved in a timely manner.
|
||||
|
||||
For example, if you are experiencing a problem while running one of the
|
||||
commands, please provide full output of said command in very very verbose mode
|
||||
(`-vvv`, e.g. `composer install -vvv`).
|
||||
|
||||
If your issue involves installing, updating or resolving dependencies, the
|
||||
chance of us being able to reproduce your issue will be much higher if you
|
||||
share your `composer.json` with us.
|
||||
|
||||
Installation from Source
|
||||
------------------------
|
||||
|
||||
Prior to contributing to Composer, you must use be able to run the tests.
|
||||
To achieve this, you must use the sources and not the phar file.
|
||||
Prior to contributing to Composer, you must be able to run the test suite.
|
||||
To achieve this, you need to acquire the Composer source code:
|
||||
|
||||
1. Run `git clone https://github.com/composer/composer.git`
|
||||
2. Download the [`composer.phar`](https://getcomposer.org/composer.phar) executable
|
||||
3. Run Composer to get the dependencies: `cd composer && php ../composer.phar install`
|
||||
|
||||
You can now run Composer by executing the `bin/composer` script: `php /path/to/composer/bin/composer`
|
||||
You can run the test suite by executing `vendor/bin/phpunit` when inside the
|
||||
composer directory, and run Composer by executing the `bin/composer`. To test
|
||||
your modified Composer code against another project, run `php
|
||||
/path/to/composer/bin/composer` inside that project's directory.
|
||||
|
||||
Contributing policy
|
||||
-------------------
|
||||
|
||||
All code contributions - including those of people having commit access -
|
||||
must go through a pull request and approved by a core developer before being
|
||||
merged. This is to ensure proper review of all the code.
|
||||
|
||||
Fork the project, create a feature branch, and send us a pull request.
|
||||
|
||||
To ensure a consistent code base, you should make sure the code follows
|
||||
the [Coding Standards](http://symfony.com/doc/current/contributing/code/standards.html)
|
||||
which we borrowed from Symfony.
|
||||
the [PSR-2 Coding Standards](http://www.php-fig.org/psr/psr-2/).
|
||||
|
||||
If you would like to help, take a look at the [list of issues](http://github.com/composer/composer/issues).
|
||||
If you would like to help, take a look at the [list of issues](https://github.com/composer/composer/issues).
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2011 Nils Adermann, Jordi Boggiano
|
||||
Copyright (c) 2015 Nils Adermann, Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
25
README.md
25
README.md
|
@ -6,6 +6,8 @@ Composer helps you declare, manage and install dependencies of PHP projects, ens
|
|||
See [https://getcomposer.org/](https://getcomposer.org/) for more information and documentation.
|
||||
|
||||
[![Build Status](https://travis-ci.org/composer/composer.svg?branch=master)](https://travis-ci.org/composer/composer)
|
||||
[![Dependency Status](https://www.versioneye.com/php/composer:composer/dev-master/badge.svg)](https://www.versioneye.com/php/composer:composer/dev-master)
|
||||
[![Reference Status](https://www.versioneye.com/php/composer:composer/reference_badge.svg?style=flat)](https://www.versioneye.com/php/composer:composer/references)
|
||||
|
||||
Installation / Usage
|
||||
--------------------
|
||||
|
@ -19,7 +21,7 @@ Installation / Usage
|
|||
2. Create a composer.json defining your dependencies. Note that this example is
|
||||
a short version for applications that are not meant to be published as packages
|
||||
themselves. To create libraries/packages please read the
|
||||
[documentation](http://getcomposer.org/doc/02-libraries.md).
|
||||
[documentation](https://getcomposer.org/doc/02-libraries.md).
|
||||
|
||||
``` json
|
||||
{
|
||||
|
@ -35,26 +37,27 @@ themselves. To create libraries/packages please read the
|
|||
Global installation of Composer (manual)
|
||||
----------------------------------------
|
||||
|
||||
Follow instructions [in the documentation](http://getcomposer.org/doc/00-intro.md#globally)
|
||||
Follow instructions [in the documentation](https://getcomposer.org/doc/00-intro.md#globally)
|
||||
|
||||
Updating Composer
|
||||
-----------------
|
||||
|
||||
Running `php composer.phar self-update` or equivalent will update a phar
|
||||
install with the latest version.
|
||||
install to the latest version.
|
||||
|
||||
|
||||
Community
|
||||
---------
|
||||
|
||||
Mailing lists for [user support](http://groups.google.com/group/composer-users) and
|
||||
[development](http://groups.google.com/group/composer-dev).
|
||||
|
||||
IRC channels are on irc.freenode.org: [#composer](irc://irc.freenode.org/composer)
|
||||
for users and [#composer-dev](irc://irc.freenode.org/composer-dev) for development.
|
||||
|
||||
Stack Overflow has a growing collection of
|
||||
[Composer related questions](http://stackoverflow.com/questions/tagged/composer-php).
|
||||
For support, Stack Overflow also offers a good collection of
|
||||
[Composer related questions](https://stackoverflow.com/questions/tagged/composer-php).
|
||||
|
||||
Please note that this project is released with a
|
||||
[Contributor Code of Conduct](http://contributor-covenant.org/version/1/0/0/).
|
||||
By participating in this project and its community you agree to abide by those terms.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
@ -64,8 +67,8 @@ PHP 5.3.2 or above (at least 5.3.4 recommended to avoid potential bugs)
|
|||
Authors
|
||||
-------
|
||||
|
||||
Nils Adermann - <naderman@naderman.de> - <http://twitter.com/naderman> - <http://www.naderman.de><br />
|
||||
Jordi Boggiano - <j.boggiano@seld.be> - <http://twitter.com/seldaek> - <http://seld.be><br />
|
||||
Nils Adermann - <naderman@naderman.de> - <https://twitter.com/naderman> - <http://www.naderman.de><br />
|
||||
Jordi Boggiano - <j.boggiano@seld.be> - <https://twitter.com/seldaek> - <http://seld.be><br />
|
||||
|
||||
See also the list of [contributors](https://github.com/composer/composer/contributors) who participated in this project.
|
||||
|
||||
|
@ -78,6 +81,6 @@ Acknowledgments
|
|||
---------------
|
||||
|
||||
- This project's Solver started out as a PHP port of openSUSE's
|
||||
[Libzypp satsolver](http://en.opensuse.org/openSUSE:Libzypp_satsolver).
|
||||
[Libzypp satsolver](https://en.opensuse.org/openSUSE:Libzypp_satsolver).
|
||||
- This project uses hiddeninput.exe to prompt for passwords on windows, sources
|
||||
and details can be found on the [github page of the project](https://github.com/Seldaek/hidden-input).
|
||||
|
|
16
bin/compile
16
bin/compile
|
@ -1,6 +1,20 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$cwd = getcwd();
|
||||
chdir(__DIR__.'/../');
|
||||
$ts = rtrim(shell_exec('git log -n1 --pretty=%ct HEAD'));
|
||||
if (!is_numeric($ts)) {
|
||||
echo 'Could not detect date using "git log -n1 --pretty=%ct HEAD"'.PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
// Install with the current version to force it having the right ClassLoader version
|
||||
// Install without dev packages to clean up the included classmap from phpunit classes
|
||||
shell_exec('php bin/composer config autoloader-suffix ComposerPhar' . $ts);
|
||||
shell_exec('php bin/composer install -q --no-dev');
|
||||
shell_exec('php bin/composer config autoloader-suffix --unset');
|
||||
chdir($cwd);
|
||||
|
||||
require __DIR__.'/../src/bootstrap.php';
|
||||
|
||||
use Composer\Compiler;
|
||||
|
@ -12,6 +26,6 @@ try {
|
|||
$compiler = new Compiler();
|
||||
$compiler->compile();
|
||||
} catch (\Exception $e) {
|
||||
echo 'Failed to compile phar: ['.get_class($e).'] '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine();
|
||||
echo 'Failed to compile phar: ['.get_class($e).'] '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ if (function_exists('ini_set')) {
|
|||
};
|
||||
|
||||
$memoryLimit = trim(ini_get('memory_limit'));
|
||||
// Increase memory_limit if it is lower than 512M
|
||||
if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 512 * 1024 * 1024) {
|
||||
@ini_set('memory_limit', '512M');
|
||||
// Increase memory_limit if it is lower than 1GB
|
||||
if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 1024 * 1024 * 1024) {
|
||||
@ini_set('memory_limit', '1G');
|
||||
}
|
||||
unset($memoryInBytes, $memoryLimit);
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$identifiers = new SPDXLicenseIdentifiersOnline;
|
||||
$printer = new JsonPrinter;
|
||||
$printer->printStringArray($identifiers->getStrings());
|
||||
|
||||
/**
|
||||
* SPDX Identifier List from the registry.
|
||||
*/
|
||||
class SPDXLicenseIdentifiersOnline
|
||||
{
|
||||
const REGISTRY = 'http://www.spdx.org/licenses/';
|
||||
const EXPRESSION = '//*[@typeof="spdx:License"]/code[@property="spdx:licenseId"]/text()';
|
||||
|
||||
private $identifiers;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getStrings()
|
||||
{
|
||||
if ($this->identifiers) {
|
||||
return $this->identifiers;
|
||||
}
|
||||
$this->identifiers = $this->importNodesFromURL(
|
||||
self::REGISTRY,
|
||||
self::EXPRESSION
|
||||
);
|
||||
|
||||
return $this->identifiers;
|
||||
}
|
||||
|
||||
private function importNodesFromURL($url, $expressionTextNodes)
|
||||
{
|
||||
$doc = new DOMDocument();
|
||||
$doc->loadHTMLFile($url);
|
||||
$xp = new DOMXPath($doc);
|
||||
$codes = $xp->query($expressionTextNodes);
|
||||
if (!$codes) {
|
||||
throw new \Exception(sprintf('XPath query failed: %s', $expressionTextNodes));
|
||||
}
|
||||
if ($codes->length < 20) {
|
||||
throw new \Exception('Obtaining the license table failed, there can not be less than 20 identifiers.');
|
||||
}
|
||||
$identifiers = array();
|
||||
foreach ($codes as $code) {
|
||||
$identifiers[] = $code->nodeValue;
|
||||
}
|
||||
|
||||
return $identifiers;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an array the way this script needs it.
|
||||
*/
|
||||
class JsonPrinter
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param array $array
|
||||
*/
|
||||
public function printStringArray(array $array)
|
||||
{
|
||||
$lines = array('');
|
||||
$line = &$lines[0];
|
||||
$last = count($array) - 1;
|
||||
foreach ($array as $item => $code) {
|
||||
$code = sprintf('"%s"%s', trim($code), $item === $last ? '' : ', ');
|
||||
$length = strlen($line) + strlen($code) - 1;
|
||||
if ($length > 76) {
|
||||
$line = rtrim($line);
|
||||
unset($line);
|
||||
$lines[] = $code;
|
||||
$line = &$lines[count($lines) - 1];
|
||||
} else {
|
||||
$line .= $code;
|
||||
}
|
||||
}
|
||||
$json = sprintf("[%s]", implode("\n ", $lines));
|
||||
$json = str_replace(array("[\"", "\"]"), array("[\n \"", "\"\n]"), $json);
|
||||
echo $json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require __DIR__ . '/../src/bootstrap.php';
|
||||
|
||||
use Composer\Util\SpdxLicensesUpdater;
|
||||
|
||||
$licenses = new SpdxLicensesUpdater;
|
||||
$licenses->update();
|
|
@ -2,7 +2,7 @@
|
|||
"name": "composer/composer",
|
||||
"description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.",
|
||||
"keywords": ["package", "dependency", "autoload"],
|
||||
"homepage": "http://getcomposer.org/",
|
||||
"homepage": "https://getcomposer.org/",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
|
@ -23,14 +23,23 @@
|
|||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"justinrainbow/json-schema": "~1.3",
|
||||
"justinrainbow/json-schema": "~1.4",
|
||||
"seld/jsonlint": "~1.0",
|
||||
"symfony/console": "~2.3",
|
||||
"symfony/console": "~2.5",
|
||||
"symfony/finder": "~2.2",
|
||||
"symfony/process": "~2.1"
|
||||
"symfony/process": "~2.1",
|
||||
"seld/phar-utils": "~1.0",
|
||||
"seld/cli-prompt": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"phpunit/phpunit": "~4.5",
|
||||
"phpunit/phpunit-mock-objects": "2.3.0"
|
||||
},
|
||||
"_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223",
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.3.3"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
"ext-zip": "Enabling the zip extension allows you to unzip archives, and allows gzip compression of all internet traffic",
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "2bc9cc8aa706b68d611d7058e4eb8de7",
|
||||
"hash": "556ac817fc0b456bddc48918ef09930d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "justinrainbow/json-schema",
|
||||
"version": "1.3.7",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/justinrainbow/json-schema.git",
|
||||
"reference": "87b54b460febed69726c781ab67462084e97a105"
|
||||
"reference": "2465fe486c864e30badaa4d005ebdf89dbc503f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/87b54b460febed69726c781ab67462084e97a105",
|
||||
"reference": "87b54b460febed69726c781ab67462084e97a105",
|
||||
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2465fe486c864e30badaa4d005ebdf89dbc503f3",
|
||||
"reference": "2465fe486c864e30badaa4d005ebdf89dbc503f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -70,20 +70,68 @@
|
|||
"json",
|
||||
"schema"
|
||||
],
|
||||
"time": "2014-08-25 02:48:14"
|
||||
"time": "2015-03-27 16:41:39"
|
||||
},
|
||||
{
|
||||
"name": "seld/jsonlint",
|
||||
"version": "1.3.0",
|
||||
"name": "seld/cli-prompt",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/jsonlint.git",
|
||||
"reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35"
|
||||
"url": "https://github.com/Seldaek/cli-prompt.git",
|
||||
"reference": "fe114c7a6ac5cb0ce76932ae4017024d9842a49c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/a7bc2ec9520ad15382292591b617c43bdb1fec35",
|
||||
"reference": "a7bc2ec9520ad15382292591b617c43bdb1fec35",
|
||||
"url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/fe114c7a6ac5cb0ce76932ae4017024d9842a49c",
|
||||
"reference": "fe114c7a6ac5cb0ce76932ae4017024d9842a49c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Seld\\CliPrompt\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type",
|
||||
"keywords": [
|
||||
"cli",
|
||||
"console",
|
||||
"hidden",
|
||||
"input",
|
||||
"prompt"
|
||||
],
|
||||
"time": "2015-04-30 20:24:49"
|
||||
},
|
||||
{
|
||||
"name": "seld/jsonlint",
|
||||
"version": "1.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/jsonlint.git",
|
||||
"reference": "863ae85c6d3ef60ca49cb12bd051c4a0648c40c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/863ae85c6d3ef60ca49cb12bd051c4a0648c40c4",
|
||||
"reference": "863ae85c6d3ef60ca49cb12bd051c4a0648c40c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -116,21 +164,65 @@
|
|||
"parser",
|
||||
"validator"
|
||||
],
|
||||
"time": "2014-09-05 15:36:20"
|
||||
"time": "2015-01-04 21:18:15"
|
||||
},
|
||||
{
|
||||
"name": "seld/phar-utils",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/phar-utils.git",
|
||||
"reference": "336bb5ee20de511f3c1a164222fcfd194afcab3a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/336bb5ee20de511f3c1a164222fcfd194afcab3a",
|
||||
"reference": "336bb5ee20de511f3c1a164222fcfd194afcab3a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Seld\\PharUtils\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be"
|
||||
}
|
||||
],
|
||||
"description": "PHAR file format utilities, for when PHP phars you up",
|
||||
"keywords": [
|
||||
"phra"
|
||||
],
|
||||
"time": "2015-05-01 12:45:48"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.6.1",
|
||||
"version": "v2.6.9",
|
||||
"target-dir": "Symfony/Component/Console",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Console.git",
|
||||
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8"
|
||||
"reference": "b5ec0c11a204718f2b656357f5505a8e578f30dd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Console/zipball/ef825fd9f809d275926547c9e57cbf14968793e8",
|
||||
"reference": "ef825fd9f809d275926547c9e57cbf14968793e8",
|
||||
"url": "https://api.github.com/repos/symfony/Console/zipball/b5ec0c11a204718f2b656357f5505a8e578f30dd",
|
||||
"reference": "b5ec0c11a204718f2b656357f5505a8e578f30dd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -139,6 +231,7 @@
|
|||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/event-dispatcher": "~2.1",
|
||||
"symfony/phpunit-bridge": "~2.7",
|
||||
"symfony/process": "~2.1"
|
||||
},
|
||||
"suggest": {
|
||||
|
@ -162,37 +255,40 @@
|
|||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-12-02 20:19:20"
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-05-29 14:42:58"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.6.1",
|
||||
"version": "v2.6.9",
|
||||
"target-dir": "Symfony/Component/Finder",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Finder.git",
|
||||
"reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721"
|
||||
"reference": "ffedd3e0ff8155188155e9322fe21b9ee012ac14"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Finder/zipball/0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721",
|
||||
"reference": "0d3ef7f6ec55a7af5eca7914eaa0dacc04ccc721",
|
||||
"url": "https://api.github.com/repos/symfony/Finder/zipball/ffedd3e0ff8155188155e9322fe21b9ee012ac14",
|
||||
"reference": "ffedd3e0ff8155188155e9322fe21b9ee012ac14",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -209,37 +305,40 @@
|
|||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-12-02 20:19:20"
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-05-15 13:32:45"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.6.1",
|
||||
"version": "v2.6.9",
|
||||
"target-dir": "Symfony/Component/Process",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Process.git",
|
||||
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a"
|
||||
"reference": "7856d78ab6cce6e59d02d9e1a873441f6bd21306"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Process/zipball/bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
|
||||
"reference": "bf0c9bd625f13b0b0bbe39919225cf145dfb935a",
|
||||
"url": "https://api.github.com/repos/symfony/Process/zipball/7856d78ab6cce6e59d02d9e1a873441f6bd21306",
|
||||
"reference": "7856d78ab6cce6e59d02d9e1a873441f6bd21306",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -256,18 +355,18 @@
|
|||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-12-02 20:19:20"
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-05-15 13:32:45"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -326,17 +425,126 @@
|
|||
"time": "2014-10-13 12:58:55"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "2.0.14",
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94"
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca158276c1200cc27f5409a5e338486bc0b4fc94",
|
||||
"reference": "ca158276c1200cc27f5409a5e338486bc0b4fc94",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
|
||||
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"dflydev/markdown": "~1.0",
|
||||
"erusev/parsedown": "~1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"phpDocumentor": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mike van Riel",
|
||||
"email": "mike.vanriel@naenius.com"
|
||||
}
|
||||
],
|
||||
"time": "2015-02-03 12:10:50"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
|
||||
"reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"phpdocumentor/reflection-docblock": "~2.0",
|
||||
"sebastian/comparator": "~1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "~2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Prophecy\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Konstantin Kudryashov",
|
||||
"email": "ever.zet@gmail.com",
|
||||
"homepage": "http://everzet.com"
|
||||
},
|
||||
{
|
||||
"name": "Marcello Duarte",
|
||||
"email": "marcello.duarte@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Highly opinionated mocking framework for PHP 5.3+",
|
||||
"homepage": "https://github.com/phpspec/prophecy",
|
||||
"keywords": [
|
||||
"Double",
|
||||
"Dummy",
|
||||
"fake",
|
||||
"mock",
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2015-04-27 22:15:08"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "2.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "be2286cb8c7e1773eded49d9719219e6f74f9e3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/be2286cb8c7e1773eded49d9719219e6f74f9e3e",
|
||||
"reference": "be2286cb8c7e1773eded49d9719219e6f74f9e3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -349,7 +557,7 @@
|
|||
},
|
||||
"require-dev": {
|
||||
"ext-xdebug": ">=2.1.4",
|
||||
"phpunit/phpunit": "~4.1"
|
||||
"phpunit/phpunit": "~4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "*",
|
||||
|
@ -359,7 +567,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -368,9 +576,6 @@
|
|||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
|
@ -388,35 +593,37 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2014-12-26 13:28:33"
|
||||
"time": "2015-06-09 13:05:42"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.3.4",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
|
||||
"reference": "a923bb15680d0089e2316f7a4af8f437046e96bb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
|
||||
"reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb",
|
||||
"reference": "a923bb15680d0089e2316f7a4af8f437046e96bb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"File/"
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
|
@ -433,7 +640,7 @@
|
|||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2013-10-10 15:34:57"
|
||||
"time": "2015-04-02 05:19:05"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
|
@ -525,16 +732,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "f8d5d08c56de5cfd592b3340424a81733259a876"
|
||||
"reference": "eab81d02569310739373308137284e0158424330"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876",
|
||||
"reference": "f8d5d08c56de5cfd592b3340424a81733259a876",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330",
|
||||
"reference": "eab81d02569310739373308137284e0158424330",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -547,7 +754,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3-dev"
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -570,20 +777,20 @@
|
|||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2014-08-31 06:12:13"
|
||||
"time": "2015-04-08 04:46:07"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.4.1",
|
||||
"version": "4.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "6a5e49a86ce5e33b8d0657abe145057fc513543a"
|
||||
"reference": "8e0c63329c8c4185296b8d357daa5c6bae43080f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6a5e49a86ce5e33b8d0657abe145057fc513543a",
|
||||
"reference": "6a5e49a86ce5e33b8d0657abe145057fc513543a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8e0c63329c8c4185296b8d357daa5c6bae43080f",
|
||||
"reference": "8e0c63329c8c4185296b8d357daa5c6bae43080f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -593,18 +800,19 @@
|
|||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-code-coverage": "~2.0",
|
||||
"phpunit/php-file-iterator": "~1.3.2",
|
||||
"phpspec/prophecy": "~1.3,>=1.3.1",
|
||||
"phpunit/php-code-coverage": "~2.1",
|
||||
"phpunit/php-file-iterator": "~1.4",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "~1.0.2",
|
||||
"phpunit/php-timer": "~1.0",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.0",
|
||||
"sebastian/diff": "~1.1",
|
||||
"sebastian/environment": "~1.1",
|
||||
"sebastian/exporter": "~1.0",
|
||||
"sebastian/comparator": "~1.1",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "~1.2",
|
||||
"sebastian/exporter": "~1.2",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/version": "~1.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
"symfony/yaml": "~2.1|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"phpunit/php-invoker": "~1.1"
|
||||
|
@ -615,7 +823,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.4.x-dev"
|
||||
"dev-master": "4.7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -641,7 +849,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2014-12-28 07:57:05"
|
||||
"time": "2015-06-06 08:36:08"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
|
@ -700,25 +908,25 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "c484a80f97573ab934e37826dba0135a3301b26a"
|
||||
"reference": "1dd8869519a225f7f2b9eb663e225298fade819e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/c484a80f97573ab934e37826dba0135a3301b26a",
|
||||
"reference": "c484a80f97573ab934e37826dba0135a3301b26a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e",
|
||||
"reference": "1dd8869519a225f7f2b9eb663e225298fade819e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/diff": "~1.1",
|
||||
"sebastian/exporter": "~1.0"
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/exporter": "~1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.1"
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -760,20 +968,20 @@
|
|||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2014-11-16 21:32:38"
|
||||
"time": "2015-01-29 16:28:08"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7"
|
||||
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7",
|
||||
"reference": "5843509fed39dee4b356a306401e9dd1a931fec7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3",
|
||||
"reference": "863df9687835c62aa423a22412d26fa2ebde3fd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -785,7 +993,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -812,32 +1020,32 @@
|
|||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"time": "2014-08-15 10:29:00"
|
||||
"time": "2015-02-22 15:13:53"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7"
|
||||
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7",
|
||||
"reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e",
|
||||
"reference": "5a8c7d31914337b69923db26c4221b81ff5a196e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.3"
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -862,32 +1070,33 @@
|
|||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2014-10-25 08:00:45"
|
||||
"time": "2015-01-01 10:01:08"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "1.0.2",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0"
|
||||
"reference": "84839970d05254c73cde183a721c7af13aede943"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
|
||||
"reference": "c7d59948d6e82818e1bdff7cadb6c34710eb7dc0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943",
|
||||
"reference": "84839970d05254c73cde183a721c7af13aede943",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/recursion-context": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -927,7 +1136,7 @@
|
|||
"export",
|
||||
"exporter"
|
||||
],
|
||||
"time": "2014-09-10 00:51:36"
|
||||
"time": "2015-01-27 07:23:06"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
|
@ -981,17 +1190,70 @@
|
|||
"time": "2014-10-06 09:23:50"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.4",
|
||||
"name": "sebastian/recursion-context",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "a77d9123f8e809db3fbdea15038c27a95da4058b"
|
||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||
"reference": "3989662bbb30a29d20d9faa04a846af79b276252"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b",
|
||||
"reference": "a77d9123f8e809db3fbdea15038c27a95da4058b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252",
|
||||
"reference": "3989662bbb30a29d20d9faa04a846af79b276252",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
},
|
||||
{
|
||||
"name": "Adam Harvey",
|
||||
"email": "aharvey@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"time": "2015-01-24 09:48:32"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
|
||||
"reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -1013,26 +1275,29 @@
|
|||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"time": "2014-12-15 14:25:24"
|
||||
"time": "2015-02-24 06:35:25"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.6.1",
|
||||
"version": "v2.6.9",
|
||||
"target-dir": "Symfony/Component/Yaml",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Yaml.git",
|
||||
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20"
|
||||
"reference": "f157ab074e453ecd4c0fa775f721f6e67a99d9e2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/3346fc090a3eb6b53d408db2903b241af51dcb20",
|
||||
"reference": "3346fc090a3eb6b53d408db2903b241af51dcb20",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/f157ab074e453ecd4c0fa775f721f6e67a99d9e2",
|
||||
"reference": "f157ab074e453ecd4c0fa775f721f6e67a99d9e2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "~2.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
|
@ -1049,18 +1314,18 @@
|
|||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-12-02 20:19:20"
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-05-02 15:18:45"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -1071,5 +1336,8 @@
|
|||
"platform": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"platform-dev": []
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "5.3.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ it manages them on a per-project basis, installing them in a directory (e.g. `ve
|
|||
inside your project. By default it will never install anything globally. Thus,
|
||||
it is a dependency manager.
|
||||
|
||||
This idea is not new and Composer is strongly inspired by node's [npm](http://npmjs.org/)
|
||||
and ruby's [bundler](http://gembundler.com/). But there has not been such a tool
|
||||
This idea is not new and Composer is strongly inspired by node's [npm](https://npmjs.org/)
|
||||
and ruby's [bundler](http://bundler.io/). But there has not been such a tool
|
||||
for PHP.
|
||||
|
||||
The problem that Composer solves is this:
|
||||
|
@ -142,6 +142,8 @@ Create a new `composer.bat` file alongside `composer.phar`:
|
|||
C:\bin>echo @php "%~dp0composer.phar" %*>composer.bat
|
||||
```
|
||||
|
||||
Add the directory to your PATH environment variable if it isn't already.
|
||||
|
||||
Close your current terminal. Test usage with a new terminal:
|
||||
|
||||
```sh
|
||||
|
@ -179,7 +181,7 @@ downloads. To use it, just add the following line to your code's bootstrap
|
|||
process:
|
||||
|
||||
```php
|
||||
require 'vendor/autoload.php';
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
```
|
||||
|
||||
Woah! Now start using monolog! To keep learning more about Composer, keep
|
||||
|
|
|
@ -45,7 +45,7 @@ smaller decoupled parts.
|
|||
|
||||
### Package Versions
|
||||
|
||||
In the previous example we were requiring version `1.0.*` of monolog. This
|
||||
In the previous example we were requiring version [`1.0.*`](http://semver.mwl.be/#?package=monolog%2Fmonolog&version=1.0.*) of monolog. This
|
||||
means any version in the `1.0` development branch. It would match `1.0.0`,
|
||||
`1.0.2` or `1.0.20`.
|
||||
|
||||
|
@ -94,6 +94,13 @@ so using [stability flags](04-schema.md#package-links). To change that for all
|
|||
packages instead of doing per dependency you can also use the
|
||||
[minimum-stability](04-schema.md#minimum-stability) setting.
|
||||
|
||||
### Test version constraints
|
||||
|
||||
You can test version constraints using [semver.mwl.be](http://semver.mwl.be). Fill in
|
||||
a package name and it will autofill the default version constraint which Composer would add
|
||||
to your `composer.json` file. You can adjust the version constraint and the tool will highlight
|
||||
all releases that match.
|
||||
|
||||
## Installing Dependencies
|
||||
|
||||
To fetch the defined dependencies into your local project, just run the
|
||||
|
@ -140,7 +147,7 @@ versions from `composer.json` and create the lock file after executing the `upd
|
|||
command.
|
||||
|
||||
This means that if any of the dependencies get a new version, you won't get the updates
|
||||
automatically. To update to the new version, use `update` command. This will fetch
|
||||
automatically. To update to the new version, use the `update` command. This will fetch
|
||||
the latest matching versions (according to your `composer.json` file) and also update
|
||||
the lock file with the new version.
|
||||
|
||||
|
|
|
@ -96,9 +96,9 @@ Here are a few examples of valid tag names:
|
|||
### Branches
|
||||
|
||||
For every branch, a package development version will be created. If the branch
|
||||
name looks like a version, the version will be `{branchname}-dev`. For example
|
||||
a branch `2.0` will get a version `2.0.x-dev` (the `.x` is added for technical
|
||||
reasons, to make sure it is recognized as a branch, a `2.0.x` branch would also
|
||||
name looks like a version, the version will be `{branchname}-dev`. For example,
|
||||
the branch `2.0` will get the `2.0.x-dev` version (the `.x` is added for technical
|
||||
reasons, to make sure it is recognized as a branch). The `2.0.x` branch would also
|
||||
be valid and be turned into `2.0.x-dev` as well. If the branch does not look
|
||||
like a version, it will be `dev-{branchname}`. `master` results in a
|
||||
`dev-master` version.
|
||||
|
@ -188,23 +188,23 @@ dependency in the `require` field.
|
|||
|
||||
## Publishing to packagist
|
||||
|
||||
Alright, so now you can publish packages. But specifying the vcs repository
|
||||
Alright, so now you can publish packages. But specifying the VCS repository
|
||||
every time is cumbersome. You don't want to force all your users to do that.
|
||||
|
||||
The other thing that you may have noticed is that we did not specify a package
|
||||
repository for `monolog/monolog`. How did that work? The answer is packagist.
|
||||
repository for `monolog/monolog`. How did that work? The answer is Packagist.
|
||||
|
||||
[Packagist](https://packagist.org/) is the main package repository for
|
||||
Composer, and it is enabled by default. Anything that is published on
|
||||
packagist is available automatically through Composer. Since monolog
|
||||
Packagist is available automatically through Composer. Since monolog
|
||||
[is on packagist](https://packagist.org/packages/monolog/monolog), we can depend
|
||||
on it without having to specify any additional repositories.
|
||||
|
||||
If we wanted to share `hello-world` with the world, we would publish it on
|
||||
packagist as well. Doing so is really easy.
|
||||
Packagist as well. Doing so is really easy.
|
||||
|
||||
You simply hit the big "Submit Package" button and sign up. Then you submit
|
||||
the URL to your VCS repository, at which point packagist will start crawling
|
||||
the URL to your VCS repository, at which point Packagist will start crawling
|
||||
it. Once it is done, your package will be available to anyone.
|
||||
|
||||
← [Basic usage](01-basic-usage.md) | [Command-line interface](03-cli.md) →
|
||||
|
|
|
@ -64,30 +64,31 @@ If there is a `composer.lock` file in the current directory, it will use the
|
|||
exact versions from there instead of resolving them. This ensures that
|
||||
everyone using the library will get the same versions of the dependencies.
|
||||
|
||||
If there is no `composer.lock` file, composer will create one after dependency
|
||||
If there is no `composer.lock` file, Composer will create one after dependency
|
||||
resolution.
|
||||
|
||||
### Options
|
||||
|
||||
* **--prefer-source:** There are two ways of downloading a package: `source`
|
||||
and `dist`. For stable versions composer will use the `dist` by default.
|
||||
and `dist`. For stable versions Composer will use the `dist` by default.
|
||||
The `source` is a version control repository. If `--prefer-source` is
|
||||
enabled, composer will install from `source` if there is one. This is
|
||||
enabled, Composer will install from `source` if there is one. This is
|
||||
useful if you want to make a bugfix to a project and get a local git
|
||||
clone of the dependency directly.
|
||||
* **--prefer-dist:** Reverse of `--prefer-source`, composer will install
|
||||
* **--prefer-dist:** Reverse of `--prefer-source`, Composer will install
|
||||
from `dist` if possible. This can speed up installs substantially on build
|
||||
servers and other use cases where you typically do not run updates of the
|
||||
vendors. It is also a way to circumvent problems with git if you do not
|
||||
have a proper setup.
|
||||
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
|
||||
requirements and force the installation even if the local machine does not
|
||||
fulfill these.
|
||||
fulfill these. See also the [`platform`](06-config.md#platform) config option.
|
||||
* **--dry-run:** If you want to run through an installation without actually
|
||||
installing a package, you can use `--dry-run`. This will simulate the
|
||||
installation and show you what would happen.
|
||||
* **--dev:** Install packages listed in `require-dev` (this is the default behavior).
|
||||
* **--no-dev:** Skip installing packages listed in `require-dev`. The autoloader generation skips the `autoload-dev` rules.
|
||||
* **--no-dev:** Skip installing packages listed in `require-dev`. The autoloader
|
||||
generation skips the `autoload-dev` rules.
|
||||
* **--no-autoloader:** Skips autoloader generation.
|
||||
* **--no-scripts:** Skips execution of scripts defined in `composer.json`.
|
||||
* **--no-plugins:** Disables plugins.
|
||||
|
@ -127,7 +128,7 @@ php composer.phar update vendor/*
|
|||
* **--prefer-dist:** Install packages from `dist` when available.
|
||||
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
|
||||
requirements and force the installation even if the local machine does not
|
||||
fulfill these.
|
||||
fulfill these. See also the [`platform`](06-config.md#platform) config option.
|
||||
* **--dry-run:** Simulate the command without actually doing anything.
|
||||
* **--dev:** Install packages listed in `require-dev` (this is the default behavior).
|
||||
* **--no-dev:** Skip installing packages listed in `require-dev`. The autoloader generation skips the `autoload-dev` rules.
|
||||
|
@ -171,7 +172,7 @@ php composer.phar require vendor/package:2.* vendor/package2:dev-master
|
|||
* **--prefer-dist:** Install packages from `dist` when available.
|
||||
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
|
||||
requirements and force the installation even if the local machine does not
|
||||
fulfill these.
|
||||
fulfill these. See also the [`platform`](06-config.md#platform) config option.
|
||||
* **--dev:** Add packages to `require-dev`.
|
||||
* **--no-update:** Disables the automatic update of the dependencies.
|
||||
* **--no-progress:** Removes the progress display that can mess with some
|
||||
|
@ -195,7 +196,7 @@ uninstalled.
|
|||
### Options
|
||||
* **--ignore-platform-reqs:** ignore `php`, `hhvm`, `lib-*` and `ext-*`
|
||||
requirements and force the installation even if the local machine does not
|
||||
fulfill these.
|
||||
fulfill these. See also the [`platform`](06-config.md#platform) config option.
|
||||
* **--dev:** Remove packages from `require-dev`.
|
||||
* **--no-update:** Disables the automatic update of the dependencies.
|
||||
* **--no-progress:** Removes the progress display that can mess with some
|
||||
|
@ -259,8 +260,8 @@ name : monolog/monolog
|
|||
versions : master-dev, 1.0.2, 1.0.1, 1.0.0, 1.0.0-RC1
|
||||
type : library
|
||||
names : monolog/monolog
|
||||
source : [git] http://github.com/Seldaek/monolog.git 3d4e60d0cbc4b888fe5ad223d77964428b1978da
|
||||
dist : [zip] http://github.com/Seldaek/monolog/zipball/3d4e60d0cbc4b888fe5ad223d77964428b1978da 3d4e60d0cbc4b888fe5ad223d77964428b1978da
|
||||
source : [git] https://github.com/Seldaek/monolog.git 3d4e60d0cbc4b888fe5ad223d77964428b1978da
|
||||
dist : [zip] https://github.com/Seldaek/monolog/zipball/3d4e60d0cbc4b888fe5ad223d77964428b1978da 3d4e60d0cbc4b888fe5ad223d77964428b1978da
|
||||
license : MIT
|
||||
|
||||
autoload
|
||||
|
@ -326,7 +327,7 @@ php composer.phar validate
|
|||
|
||||
### Options
|
||||
|
||||
* **--no-check-all:** Whether or not composer do a complete validation.
|
||||
* **--no-check-all:** Whether or not Composer does a complete validation.
|
||||
|
||||
## status
|
||||
|
||||
|
@ -351,7 +352,7 @@ vendor/seld/jsonlint:
|
|||
|
||||
## self-update
|
||||
|
||||
To update composer itself to the latest version, just run the `self-update`
|
||||
To update Composer itself to the latest version, just run the `self-update`
|
||||
command. It will replace your `composer.phar` with the latest version.
|
||||
|
||||
```sh
|
||||
|
@ -364,7 +365,7 @@ If you would like to instead update to a specific release simply specify it:
|
|||
php composer.phar self-update 1.0.0-alpha7
|
||||
```
|
||||
|
||||
If you have installed composer for your entire system (see [global installation](00-intro.md#globally)),
|
||||
If you have installed Composer for your entire system (see [global installation](00-intro.md#globally)),
|
||||
you may have to run the command with `root` privileges
|
||||
|
||||
```sh
|
||||
|
@ -374,11 +375,12 @@ sudo composer self-update
|
|||
### Options
|
||||
|
||||
* **--rollback (-r):** Rollback to the last version you had installed.
|
||||
* **--clean-backups:** Delete old backups during an update. This makes the current version of composer the only backup available after the update.
|
||||
* **--clean-backups:** Delete old backups during an update. This makes the
|
||||
current version of Composer the only backup available after the update.
|
||||
|
||||
## config
|
||||
|
||||
The `config` command allows you to edit some basic composer settings in either
|
||||
The `config` command allows you to edit some basic Composer settings in either
|
||||
the local composer.json file or the global config.json file.
|
||||
|
||||
```sh
|
||||
|
@ -393,8 +395,7 @@ php composer.phar config --list
|
|||
configuration value. For settings that can take an array of values (like
|
||||
`github-protocols`), more than one setting-value arguments are allowed.
|
||||
|
||||
See the [config schema section](04-schema.md#config) for valid configuration
|
||||
options.
|
||||
See the [Config](06-config.md) chapter for valid configuration options.
|
||||
|
||||
### Options
|
||||
|
||||
|
@ -418,13 +419,13 @@ In addition to modifying the config section, the `config` command also supports
|
|||
changes to the repositories section by using it the following way:
|
||||
|
||||
```sh
|
||||
php composer.phar config repositories.foo vcs http://github.com/foo/bar
|
||||
php composer.phar config repositories.foo vcs https://github.com/foo/bar
|
||||
```
|
||||
|
||||
## create-project
|
||||
|
||||
You can use Composer to create new projects from an existing package. This is
|
||||
the equivalent of doing a git clone/svn checkout followed by a composer install
|
||||
the equivalent of doing a git clone/svn checkout followed by a "composer install"
|
||||
of the vendors.
|
||||
|
||||
There are several applications for this:
|
||||
|
@ -434,7 +435,7 @@ There are several applications for this:
|
|||
3. Projects with multiple developers can use this feature to bootstrap the
|
||||
initial application for development.
|
||||
|
||||
To create a new project using composer you can use the "create-project" command.
|
||||
To create a new project using Composer you can use the "create-project" command.
|
||||
Pass it a package name, and the directory to create the project in. You can also
|
||||
provide a version as third argument, otherwise the latest version is used.
|
||||
|
||||
|
@ -507,8 +508,13 @@ Lists the name, version and license of every package installed. Use
|
|||
|
||||
## run-script
|
||||
|
||||
### Options
|
||||
|
||||
* **--no-dev:** Disable dev mode
|
||||
* **--list:** List user defined scripts
|
||||
|
||||
To run [scripts](articles/scripts.md) manually you can use this command,
|
||||
just give it the script name and optionally --no-dev to disable the dev mode.
|
||||
just give it the script name and optionally any required arguments.
|
||||
|
||||
## diagnose
|
||||
|
||||
|
@ -569,7 +575,7 @@ not be guessed from VCS info and is not present in `composer.json`.
|
|||
|
||||
### COMPOSER_VENDOR_DIR
|
||||
|
||||
By setting this var you can make composer install the dependencies into a
|
||||
By setting this var you can make Composer install the dependencies into a
|
||||
directory other than `vendor`.
|
||||
|
||||
### COMPOSER_BIN_DIR
|
||||
|
@ -579,7 +585,7 @@ directory to something other than `vendor/bin`.
|
|||
|
||||
### http_proxy or HTTP_PROXY
|
||||
|
||||
If you are using composer from behind an HTTP proxy, you can use the standard
|
||||
If you are using Composer from behind an HTTP proxy, you can use the standard
|
||||
`http_proxy` or `HTTP_PROXY` env vars. Simply set it to the URL of your proxy.
|
||||
Many operating systems already set this variable for you.
|
||||
|
||||
|
@ -601,18 +607,18 @@ can also set it to `*` to ignore the proxy for all HTTP requests.
|
|||
### HTTP_PROXY_REQUEST_FULLURI
|
||||
|
||||
If you use a proxy but it does not support the request_fulluri flag, then you
|
||||
should set this env var to `false` or `0` to prevent composer from setting the
|
||||
should set this env var to `false` or `0` to prevent Composer from setting the
|
||||
request_fulluri option.
|
||||
|
||||
### HTTPS_PROXY_REQUEST_FULLURI
|
||||
|
||||
If you use a proxy but it does not support the request_fulluri flag for HTTPS
|
||||
requests, then you should set this env var to `false` or `0` to prevent composer
|
||||
requests, then you should set this env var to `false` or `0` to prevent Composer
|
||||
from setting the request_fulluri option.
|
||||
|
||||
### COMPOSER_HOME
|
||||
|
||||
The `COMPOSER_HOME` var allows you to change the composer home directory. This
|
||||
The `COMPOSER_HOME` var allows you to change the Composer home directory. This
|
||||
is a hidden, global (per-user on the machine) directory that is shared between
|
||||
all projects.
|
||||
|
||||
|
@ -628,32 +634,32 @@ You may put a `config.json` file into the location which `COMPOSER_HOME` points
|
|||
to. Composer will merge this configuration with your project's `composer.json`
|
||||
when you run the `install` and `update` commands.
|
||||
|
||||
This file allows you to set [configuration](04-schema.md#config) and
|
||||
[repositories](05-repositories.md) for the user's projects.
|
||||
This file allows you to set [repositories](05-repositories.md) and
|
||||
[configuration](06-config.md) for the user's projects.
|
||||
|
||||
In case global configuration matches _local_ configuration, the _local_
|
||||
configuration in the project's `composer.json` always wins.
|
||||
|
||||
### COMPOSER_CACHE_DIR
|
||||
|
||||
The `COMPOSER_CACHE_DIR` var allows you to change the composer cache directory,
|
||||
which is also configurable via the [`cache-dir`](04-schema.md#config) option.
|
||||
The `COMPOSER_CACHE_DIR` var allows you to change the Composer cache directory,
|
||||
which is also configurable via the [`cache-dir`](06-config.md#cache-dir) option.
|
||||
|
||||
By default it points to $COMPOSER_HOME/cache on \*nix and OSX, and
|
||||
`C:\Users\<user>\AppData\Local\Composer` (or `%LOCALAPPDATA%/Composer`) on Windows.
|
||||
|
||||
### COMPOSER_PROCESS_TIMEOUT
|
||||
|
||||
This env var controls the time composer waits for commands (such as git
|
||||
This env var controls the time Composer waits for commands (such as git
|
||||
commands) to finish executing. The default value is 300 seconds (5 minutes).
|
||||
|
||||
### COMPOSER_DISCARD_CHANGES
|
||||
|
||||
This env var controls the discard-changes [config option](04-schema.md#config).
|
||||
This env var controls the [`discard-changes`](06-config.md#discard-changes) config option.
|
||||
|
||||
### COMPOSER_NO_INTERACTION
|
||||
|
||||
If set to 1, this env var will make composer behave as if you passed the
|
||||
If set to 1, this env var will make Composer behave as if you passed the
|
||||
`--no-interaction` flag to every command. This can be set on build boxes/CI.
|
||||
|
||||
← [Libraries](02-libraries.md) | [Schema](04-schema.md) →
|
||||
|
|
167
doc/04-schema.md
167
doc/04-schema.md
|
@ -20,9 +20,6 @@ this is the `config` field. Only the root package can define configuration.
|
|||
The config of dependencies is ignored. This makes the `config` field
|
||||
`root-only`.
|
||||
|
||||
If you clone one of those dependencies to work on it, then that package is the
|
||||
root package. The `composer.json` is identical, but the context is different.
|
||||
|
||||
> **Note:** A package can be the root package or not, depending on the context.
|
||||
> For example, if your project depends on the `monolog` library, your project
|
||||
> is the root package. However, if you clone `monolog` from GitHub in order to
|
||||
|
@ -87,7 +84,7 @@ that needs some special logic, you can define a custom type. This could be a
|
|||
all be specific to certain projects, and they will need to provide an
|
||||
installer capable of installing packages of that type.
|
||||
|
||||
Out of the box, composer supports four types:
|
||||
Out of the box, Composer supports four types:
|
||||
|
||||
- **library:** This is the default. It will simply copy the files to `vendor`.
|
||||
- **project:** This denotes a project rather than a library. For example
|
||||
|
@ -157,7 +154,7 @@ The recommended notation for the most common licenses is (alphabetical):
|
|||
- MIT
|
||||
|
||||
Optional, but it is highly recommended to supply this. More identifiers are
|
||||
listed at the [SPDX Open Source License Registry](http://www.spdx.org/licenses/).
|
||||
listed at the [SPDX Open Source License Registry](https://www.spdx.org/licenses/).
|
||||
|
||||
For closed-source software, you may use `"proprietary"` as the license identifier.
|
||||
|
||||
|
@ -235,11 +232,12 @@ Various information to get support about the project.
|
|||
Support information includes the following:
|
||||
|
||||
* **email:** Email address for support.
|
||||
* **issues:** URL to the Issue Tracker.
|
||||
* **forum:** URL to the Forum.
|
||||
* **wiki:** URL to the Wiki.
|
||||
* **issues:** URL to the issue tracker.
|
||||
* **forum:** URL to the forum.
|
||||
* **wiki:** URL to the wiki.
|
||||
* **irc:** IRC channel for support, as irc://server/channel.
|
||||
* **source:** URL to browse or download the sources.
|
||||
* **docs:** URL to the documentation.
|
||||
|
||||
An example:
|
||||
|
||||
|
@ -271,7 +269,7 @@ Example:
|
|||
|
||||
All links are optional fields.
|
||||
|
||||
`require` and `require-dev` additionally support stability flags (root-only).
|
||||
`require` and `require-dev` additionally support stability flags ([root-only](04-schema.md#root-package)).
|
||||
These allow you to further restrict or expand the stability of a package beyond
|
||||
the scope of the [minimum-stability](#minimum-stability) setting. You can apply
|
||||
them to a constraint, or just apply them to an empty constraint if you want to
|
||||
|
@ -334,7 +332,7 @@ aliases article](articles/aliases.md).
|
|||
Lists packages required by this package. The package will not be installed
|
||||
unless those requirements can be met.
|
||||
|
||||
#### require-dev <span>(root-only)</span>
|
||||
#### require-dev <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
Lists packages required for developing this package, or running
|
||||
tests, etc. The dev requirements of the root package are installed by default.
|
||||
|
@ -554,7 +552,7 @@ Example:
|
|||
}
|
||||
```
|
||||
|
||||
### autoload-dev <span>(root-only)</span>
|
||||
### autoload-dev <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
This section allows to define autoload rules for development purposes.
|
||||
|
||||
|
@ -627,7 +625,7 @@ To do that, `autoload` and `target-dir` are defined as follows:
|
|||
|
||||
Optional.
|
||||
|
||||
### minimum-stability <span>(root-only)</span>
|
||||
### minimum-stability <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
This defines the default behavior for filtering packages by stability. This
|
||||
defaults to `stable`, so if you rely on a `dev` package, you should specify
|
||||
|
@ -642,7 +640,7 @@ a given package can be done in `require` or `require-dev` (see
|
|||
Available options (in order of stability) are `dev`, `alpha`, `beta`, `RC`,
|
||||
and `stable`.
|
||||
|
||||
### prefer-stable <span>(root-only)</span>
|
||||
### prefer-stable <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
When this is enabled, Composer will prefer more stable packages over unstable
|
||||
ones when finding compatible stable packages is possible. If you require a
|
||||
|
@ -651,11 +649,11 @@ selected granted that the minimum-stability allows for it.
|
|||
|
||||
Use `"prefer-stable": true` to enable.
|
||||
|
||||
### repositories <span>(root-only)</span>
|
||||
### repositories <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
Custom package repositories to use.
|
||||
|
||||
By default composer just uses the packagist repository. By specifying
|
||||
By default Composer just uses the packagist repository. By specifying
|
||||
repositories you can get packages from elsewhere.
|
||||
|
||||
Repositories are not resolved recursively. You can only add them to your main
|
||||
|
@ -664,14 +662,14 @@ ignored.
|
|||
|
||||
The following repository types are supported:
|
||||
|
||||
* **composer:** A composer repository is simply a `packages.json` file served
|
||||
* **composer:** A Composer repository is simply a `packages.json` file served
|
||||
via the network (HTTP, FTP, SSH), that contains a list of `composer.json`
|
||||
objects with additional `dist` and/or `source` information. The `packages.json`
|
||||
file is loaded using a PHP stream. You can set extra options on that stream
|
||||
using the `options` parameter.
|
||||
* **vcs:** The version control system repository can fetch packages from git,
|
||||
svn and hg repositories.
|
||||
* **pear:** With this you can import any pear repository into your composer
|
||||
* **pear:** With this you can import any pear repository into your Composer
|
||||
project.
|
||||
* **package:** If you depend on a project that does not have any support for
|
||||
composer whatsoever you can define the package inline using a `package`
|
||||
|
@ -703,7 +701,7 @@ Example:
|
|||
},
|
||||
{
|
||||
"type": "pear",
|
||||
"url": "http://pear2.php.net"
|
||||
"url": "https://pear2.php.net"
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
|
@ -715,7 +713,7 @@ Example:
|
|||
"type": "zip"
|
||||
},
|
||||
"source": {
|
||||
"url": "http://smarty-php.googlecode.com/svn/",
|
||||
"url": "https://smarty-php.googlecode.com/svn/",
|
||||
"type": "svn",
|
||||
"reference": "tags/Smarty_3_1_7/distribution/"
|
||||
}
|
||||
|
@ -730,100 +728,12 @@ will look from the first to the last repository, and pick the first match.
|
|||
By default Packagist is added last which means that custom repositories can
|
||||
override packages from it.
|
||||
|
||||
### config <span>(root-only)</span>
|
||||
### config <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
A set of configuration options. It is only used for projects.
|
||||
A set of configuration options. It is only used for projects. See
|
||||
[Config](06-config.md) for a description of each individual option.
|
||||
|
||||
The following options are supported:
|
||||
|
||||
* **process-timeout:** Defaults to `300`. The duration processes like git clones
|
||||
can run before Composer assumes they died out. You may need to make this
|
||||
higher if you have a slow connection or huge vendors.
|
||||
* **use-include-path:** Defaults to `false`. If true, the Composer autoloader
|
||||
will also look for classes in the PHP include path.
|
||||
* **preferred-install:** Defaults to `auto` and can be any of `source`, `dist` or
|
||||
`auto`. This option allows you to set the install method Composer will prefer to
|
||||
use.
|
||||
* **store-auths:** What to do after prompting for authentication, one of:
|
||||
`true` (always store), `false` (do not store) and `"prompt"` (ask every
|
||||
time), defaults to `"prompt"`.
|
||||
* **github-protocols:** Defaults to `["git", "https", "ssh"]`. A list of protocols to
|
||||
use when cloning from github.com, in priority order. You can reconfigure it to
|
||||
for example prioritize the https protocol if you are behind a proxy or have somehow
|
||||
bad performances with the git protocol.
|
||||
* **github-oauth:** A list of domain names and oauth keys. For example using
|
||||
`{"github.com": "oauthtoken"}` as the value of this option will use `oauthtoken`
|
||||
to access private repositories on github and to circumvent the low IP-based
|
||||
rate limiting of their API.
|
||||
[Read more](articles/troubleshooting.md#api-rate-limit-and-oauth-tokens)
|
||||
on how to get an OAuth token for GitHub.
|
||||
* **http-basic:** A list of domain names and username/passwords to authenticate
|
||||
against them. For example using
|
||||
`{"example.org": {"username": "alice", "password": "foo"}` as the value of this
|
||||
option will let composer authenticate against example.org.
|
||||
* **vendor-dir:** Defaults to `vendor`. You can install dependencies into a
|
||||
different directory if you want to. `$HOME` and `~` will be replaced by your
|
||||
home directory's path in vendor-dir and all `*-dir` options below.
|
||||
* **bin-dir:** Defaults to `vendor/bin`. If a project includes binaries, they
|
||||
will be symlinked into this directory.
|
||||
* **cache-dir:** Defaults to `C:\Users\<user>\AppData\Local\Composer` on Windows,
|
||||
`$XDG_CACHE_HOME/composer` on unix systems that follow the XDG Base Directory
|
||||
Specifications, and `$home/cache` on other unix systems. Stores all the caches
|
||||
used by composer. See also [COMPOSER_HOME](03-cli.md#composer-home).
|
||||
* **cache-files-dir:** Defaults to `$cache-dir/files`. Stores the zip archives
|
||||
of packages.
|
||||
* **cache-repo-dir:** Defaults to `$cache-dir/repo`. Stores repository metadata
|
||||
for the `composer` type and the VCS repos of type `svn`, `github` and `bitbucket`.
|
||||
* **cache-vcs-dir:** Defaults to `$cache-dir/vcs`. Stores VCS clones for
|
||||
loading VCS repository metadata for the `git`/`hg` types and to speed up installs.
|
||||
* **cache-files-ttl:** Defaults to `15552000` (6 months). Composer caches all
|
||||
dist (zip, tar, ..) packages that it downloads. Those are purged after six
|
||||
months of being unused by default. This option allows you to tweak this
|
||||
duration (in seconds) or disable it completely by setting it to 0.
|
||||
* **cache-files-maxsize:** Defaults to `300MiB`. Composer caches all
|
||||
dist (zip, tar, ..) packages that it downloads. When the garbage collection
|
||||
is periodically ran, this is the maximum size the cache will be able to use.
|
||||
Older (less used) files will be removed first until the cache fits.
|
||||
* **prepend-autoloader:** Defaults to `true`. If false, the composer autoloader
|
||||
will not be prepended to existing autoloaders. This is sometimes required to fix
|
||||
interoperability issues with other autoloaders.
|
||||
* **autoloader-suffix:** Defaults to `null`. String to be used as a suffix for
|
||||
the generated Composer autoloader. When null a random one will be generated.
|
||||
* **optimize-autoloader** Defaults to `false`. Always optimize when dumping
|
||||
the autoloader.
|
||||
* **classmap-authoritative:** Defaults to `false`. If true, the composer
|
||||
autoloader will not scan the filesystem for classes that are not found in
|
||||
the class map. Implies 'optimize-autoloader'.
|
||||
* **github-domains:** Defaults to `["github.com"]`. A list of domains to use in
|
||||
github mode. This is used for GitHub Enterprise setups.
|
||||
* **github-expose-hostname:** Defaults to `true`. If set to false, the OAuth
|
||||
tokens created to access the github API will have a date instead of the
|
||||
machine hostname.
|
||||
* **notify-on-install:** Defaults to `true`. Composer allows repositories to
|
||||
define a notification URL, so that they get notified whenever a package from
|
||||
that repository is installed. This option allows you to disable that behaviour.
|
||||
* **discard-changes:** Defaults to `false` and can be any of `true`, `false` or
|
||||
`"stash"`. This option allows you to set the default style of handling dirty
|
||||
updates when in non-interactive mode. `true` will always discard changes in
|
||||
vendors, while `"stash"` will try to stash and reapply. Use this for CI
|
||||
servers or deploy scripts if you tend to have modified vendors.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"bin-dir": "bin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** Authentication-related config options like `http-basic` and
|
||||
> `github-oauth` can also be specified inside a `auth.json` file that goes
|
||||
> besides your `composer.json`. That way you can gitignore it and every
|
||||
> developer can place their own credentials in there.
|
||||
|
||||
### scripts <span>(root-only)</span>
|
||||
### scripts <span>([root-only](04-schema.md#root-package))</span>
|
||||
|
||||
Composer allows you to hook into various parts of the installation process
|
||||
through the use of scripts.
|
||||
|
@ -879,4 +789,39 @@ The example will include `/dir/foo/bar/file`, `/foo/bar/baz`, `/file.php`,
|
|||
|
||||
Optional.
|
||||
|
||||
### non-feature-branches
|
||||
|
||||
A list of regex patterns of branch names that are non-numeric (e.g. "latest" or something),
|
||||
that will NOT be handled as feature branches. This is an array of strings.
|
||||
|
||||
If you have non-numeric branch names, for example like "latest", "current", "latest-stable"
|
||||
or something, that do not look like a version number, then Composer handles such branches
|
||||
as feature branches. This means it searches for parent branches, that look like a version
|
||||
or ends at special branches (like master) and the root package version number becomes the
|
||||
version of the parent branch or at least master or something.
|
||||
|
||||
To handle non-numeric named branches as versions instead of searching for a parent branch
|
||||
with a valid version or special branch name like master, you can set patterns for branch
|
||||
names, that should be handled as dev version branches.
|
||||
|
||||
This is really helpful when you have dependencies using "self.version", so that not dev-master,
|
||||
but the same branch is installed (in the example: latest-testing).
|
||||
|
||||
An example:
|
||||
|
||||
If you have a testing branch, that is heavily maintained during a testing phase and is
|
||||
deployed to your staging environment, normally "composer show -s" will give you `versions : * dev-master`.
|
||||
|
||||
If you configure `latest-.*` as a pattern for non-feature-branches like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"non-feature-branches": ["latest-.*"]
|
||||
}
|
||||
```
|
||||
|
||||
Then "composer show -s" will give you `versions : * dev-latest-testing`.
|
||||
|
||||
Optional.
|
||||
|
||||
← [Command-line interface](03-cli.md) | [Repositories](05-repositories.md) →
|
||||
|
|
|
@ -6,7 +6,7 @@ of repositories are available, and how they work.
|
|||
## Concepts
|
||||
|
||||
Before we look at the different types of repositories that exist, we need to
|
||||
understand some of the basic concepts that composer is built on.
|
||||
understand some of the basic concepts that Composer is built on.
|
||||
|
||||
### Package
|
||||
|
||||
|
@ -16,8 +16,8 @@ code, but in theory it could be anything. And it contains a package
|
|||
description which has a name and a version. The name and the version are used
|
||||
to identify the package.
|
||||
|
||||
In fact, internally composer sees every version as a separate package. While
|
||||
this distinction does not matter when you are using composer, it's quite
|
||||
In fact, internally Composer sees every version as a separate package. While
|
||||
this distinction does not matter when you are using Composer, it's quite
|
||||
important when you want to change it.
|
||||
|
||||
In addition to the name and the version, there is useful metadata. The information
|
||||
|
@ -103,7 +103,7 @@ It may include any of the other fields specified in the [schema](04-schema.md).
|
|||
|
||||
#### notify-batch
|
||||
|
||||
The `notify-batch` field allows you to specify an URL that will be called
|
||||
The `notify-batch` field allows you to specify a URL that will be called
|
||||
every time a user installs a package. The URL can be either an absolute path
|
||||
(that will use the same domain as the repository) or a fully qualified URL.
|
||||
|
||||
|
@ -216,7 +216,7 @@ repository.
|
|||
|
||||
The `packages.json` file is loaded using a PHP stream. You can set extra options
|
||||
on that stream using the `options` parameter. You can set any valid PHP stream
|
||||
context option. See [Context options and parameters](http://php.net/manual/en/context.php)
|
||||
context option. See [Context options and parameters](https://php.net/manual/en/context.php)
|
||||
for more information.
|
||||
|
||||
### VCS
|
||||
|
@ -234,7 +234,7 @@ project to use the patched version. If the library is on GitHub (this is the
|
|||
case most of the time), you can simply fork it there and push your changes to
|
||||
your fork. After that you update the project's `composer.json`. All you have
|
||||
to do is add your fork as a repository and update the version constraint to
|
||||
point to your custom branch. For version constraint naming conventions see
|
||||
point to your custom branch. Your custom branch name must be prefixed with `"dev-"`. For version constraint naming conventions see
|
||||
[Libraries](02-libraries.md) for more information.
|
||||
|
||||
Example assuming you patched monolog to fix a bug in the `bugfix` branch:
|
||||
|
@ -293,8 +293,8 @@ The only requirement is the installation of SSH keys for a git client.
|
|||
Git is not the only version control system supported by the VCS repository.
|
||||
The following are supported:
|
||||
|
||||
* **Git:** [git-scm.com](http://git-scm.com)
|
||||
* **Subversion:** [subversion.apache.org](http://subversion.apache.org)
|
||||
* **Git:** [git-scm.com](https://git-scm.com)
|
||||
* **Subversion:** [subversion.apache.org](https://subversion.apache.org)
|
||||
* **Mercurial:** [mercurial.selenic.com](http://mercurial.selenic.com)
|
||||
|
||||
To get packages from these systems you need to have their respective clients
|
||||
|
@ -312,7 +312,7 @@ should you need to specify one for whatever reason, you can use `git`, `svn` or
|
|||
|
||||
If you set the `no-api` key to `true` on a github repository it will clone the
|
||||
repository as it would with any other git repository instead of using the
|
||||
GitHub API. But unlike using the `git` driver directly, composer will still
|
||||
GitHub API. But unlike using the `git` driver directly, Composer will still
|
||||
attempt to use github's zip files.
|
||||
|
||||
#### Subversion Options
|
||||
|
@ -341,7 +341,7 @@ If you have no branches or tags directory you can disable them entirely by
|
|||
setting the `branches-path` or `tags-path` to `false`.
|
||||
|
||||
If the package is in a sub-directory, e.g. `/trunk/foo/bar/composer.json` and
|
||||
`/tags/1.0/foo/bar/composer.json`, then you can make composer access it by
|
||||
`/tags/1.0/foo/bar/composer.json`, then you can make Composer access it by
|
||||
setting the `"package-path"` option to the sub-directory, in this example it
|
||||
would be `"package-path": "foo/bar/"`.
|
||||
|
||||
|
@ -389,7 +389,7 @@ Example using `pear2.php.net`:
|
|||
"repositories": [
|
||||
{
|
||||
"type": "pear",
|
||||
"url": "http://pear2.php.net"
|
||||
"url": "https://pear2.php.net"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
|
@ -462,7 +462,7 @@ and `IntermediatePackage` from a Github repository:
|
|||
|
||||
### Package
|
||||
|
||||
If you want to use a project that does not support composer through any of the
|
||||
If you want to use a project that does not support Composer through any of the
|
||||
means above, you still can define the package yourself by using a `package`
|
||||
repository.
|
||||
|
||||
|
@ -517,7 +517,7 @@ Typically you would leave the source part off, as you don't really need it.
|
|||
While you will probably want to put your packages on packagist most of the time,
|
||||
there are some use cases for hosting your own repository.
|
||||
|
||||
* **Private company packages:** If you are part of a company that uses composer
|
||||
* **Private company packages:** If you are part of a company that uses Composer
|
||||
for their packages internally, you might want to keep those packages private.
|
||||
|
||||
* **Separate ecosystem:** If you have a project which has its own ecosystem,
|
||||
|
@ -533,19 +533,22 @@ There are a few tools that can help you create a `composer` repository.
|
|||
### Packagist
|
||||
|
||||
The underlying application used by packagist is open source. This means that you
|
||||
can just install your own copy of packagist, re-brand, and use it. It's really
|
||||
quite straight-forward to do. However due to its size and complexity, for most
|
||||
small and medium sized companies willing to track a few packages will be better
|
||||
off using Satis.
|
||||
can technically install your own copy of packagist. However it is not a
|
||||
supported use case and changes will happen without caring for third parties
|
||||
using the code.
|
||||
|
||||
Packagist is a Symfony2 application, and it is [available on
|
||||
GitHub](https://github.com/composer/packagist). It uses composer internally and
|
||||
acts as a proxy between VCS repositories and the composer users. It holds a list
|
||||
of all VCS packages, periodically re-crawls them, and exposes them as a composer
|
||||
GitHub](https://github.com/composer/packagist). It uses Composer internally and
|
||||
acts as a proxy between VCS repositories and the Composer users. It holds a list
|
||||
of all VCS packages, periodically re-crawls them, and exposes them as a Composer
|
||||
repository.
|
||||
|
||||
To set your own copy, simply follow the instructions from the [packagist
|
||||
github repository](https://github.com/composer/packagist).
|
||||
### Toran Proxy
|
||||
|
||||
[Toran Proxy](https://toranproxy.com/) is a web app much like Packagist but
|
||||
providing private package hosting as well as mirroring/proxying of GitHub and
|
||||
packagist.org. Check its homepage and the [Satis/Toran Proxy article](articles/handling-private-packages-with-satis.md)
|
||||
for more information.
|
||||
|
||||
### Satis
|
||||
|
||||
|
@ -614,4 +617,4 @@ You can disable the default Packagist repository by adding this to your
|
|||
}
|
||||
```
|
||||
|
||||
← [Schema](04-schema.md) | [Community](06-community.md) →
|
||||
← [Schema](04-schema.md) | [Config](06-config.md) →
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
# Config
|
||||
|
||||
This chapter will describe the `config` section of the `composer.json`
|
||||
[schema](04-schema.md).
|
||||
|
||||
## process-timeout
|
||||
|
||||
Defaults to `300`. The duration processes like git clones can run before
|
||||
Composer assumes they died out. You may need to make this higher if you have a
|
||||
slow connection or huge vendors.
|
||||
|
||||
## use-include-path
|
||||
|
||||
Defaults to `false`. If `true`, the Composer autoloader will also look for classes
|
||||
in the PHP include path.
|
||||
|
||||
## preferred-install
|
||||
|
||||
Defaults to `auto` and can be any of `source`, `dist` or `auto`. This option
|
||||
allows you to set the install method Composer will prefer to use.
|
||||
|
||||
## store-auths
|
||||
|
||||
What to do after prompting for authentication, one of: `true` (always store),
|
||||
`false` (do not store) and `"prompt"` (ask every time), defaults to `"prompt"`.
|
||||
|
||||
## github-protocols
|
||||
|
||||
Defaults to `["git", "https", "ssh"]`. A list of protocols to use when cloning
|
||||
from github.com, in priority order. You can reconfigure it to for example
|
||||
prioritize the https protocol if you are behind a proxy or have somehow bad
|
||||
performances with the git protocol.
|
||||
|
||||
## github-oauth
|
||||
|
||||
A list of domain names and oauth keys. For example using `{"github.com":
|
||||
"oauthtoken"}` as the value of this option will use `oauthtoken` to access
|
||||
private repositories on github and to circumvent the low IP-based rate limiting
|
||||
of their API. [Read
|
||||
more](articles/troubleshooting.md#api-rate-limit-and-oauth-tokens) on how to get
|
||||
an OAuth token for GitHub.
|
||||
|
||||
## http-basic
|
||||
|
||||
A list of domain names and username/passwords to authenticate against them. For
|
||||
example using `{"example.org": {"username": "alice", "password": "foo"}` as the
|
||||
value of this option will let Composer authenticate against example.org.
|
||||
|
||||
## platform
|
||||
|
||||
Lets you fake platform packages (PHP and extensions) so that you can emulate a
|
||||
production env or define your target platform in the config. Example: `{"php":
|
||||
"5.4", "ext-something": "4.0"}`.
|
||||
|
||||
## vendor-dir
|
||||
|
||||
Defaults to `vendor`. You can install dependencies into a different directory if
|
||||
you want to. `$HOME` and `~` will be replaced by your home directory's path in
|
||||
vendor-dir and all `*-dir` options below.
|
||||
|
||||
## bin-dir
|
||||
|
||||
Defaults to `vendor/bin`. If a project includes binaries, they will be symlinked
|
||||
into this directory.
|
||||
|
||||
## cache-dir
|
||||
|
||||
Defaults `C:\Users\<user>\AppData\Local\Composer` on Windows,
|
||||
`$XDG_CACHE_HOME/composer` on unix systems that follow the XDG Base Directory
|
||||
Specifications, and `$home/cache` on other unix systems. Stores all the caches
|
||||
used by Composer. See also [COMPOSER_HOME](03-cli.md#composer-home).
|
||||
|
||||
## cache-files-dir
|
||||
|
||||
Defaults to `$cache-dir/files`. Stores the zip archives of packages.
|
||||
|
||||
## cache-repo-dir
|
||||
|
||||
Defaults to `$cache-dir/repo`. Stores repository metadata for the `composer`
|
||||
type and the VCS repos of type `svn`, `github` and `bitbucket`.
|
||||
|
||||
## cache-vcs-dir
|
||||
|
||||
Defaults to `$cache-dir/vcs`. Stores VCS clones for loading VCS repository
|
||||
metadata for the `git`/`hg` types and to speed up installs.
|
||||
|
||||
## cache-files-ttl
|
||||
|
||||
Defaults to `15552000` (6 months). Composer caches all dist (zip, tar, ..)
|
||||
packages that it downloads. Those are purged after six months of being unused by
|
||||
default. This option allows you to tweak this duration (in seconds) or disable
|
||||
it completely by setting it to 0.
|
||||
|
||||
## cache-files-maxsize
|
||||
|
||||
Defaults to `300MiB`. Composer caches all dist (zip, tar, ..) packages that it
|
||||
downloads. When the garbage collection is periodically ran, this is the maximum
|
||||
size the cache will be able to use. Older (less used) files will be removed
|
||||
first until the cache fits.
|
||||
|
||||
## prepend-autoloader
|
||||
|
||||
Defaults to `true`. If false, the Composer autoloader will not be prepended to
|
||||
existing autoloaders. This is sometimes required to fix interoperability issues
|
||||
with other autoloaders.
|
||||
|
||||
## autoloader-suffix
|
||||
|
||||
Defaults to `null`. String to be used as a suffix for the generated Composer
|
||||
autoloader. When null a random one will be generated.
|
||||
|
||||
## optimize-autoloader
|
||||
|
||||
Defaults to `false`. Always optimize when dumping the autoloader.
|
||||
|
||||
## classmap-authoritative
|
||||
|
||||
Defaults to `false`. If `true`, the Composer autoloader will not scan the
|
||||
filesystem for classes that are not found in the class map. Implies
|
||||
'optimize-autoloader'.
|
||||
|
||||
## github-domains
|
||||
|
||||
Defaults to `["github.com"]`. A list of domains to use in github mode. This is
|
||||
used for GitHub Enterprise setups.
|
||||
|
||||
## github-expose-hostname
|
||||
|
||||
Defaults to `true`. If set to `false`, the OAuth tokens created to access the
|
||||
github API will have a date instead of the machine hostname.
|
||||
|
||||
## notify-on-install
|
||||
|
||||
Defaults to `true`. Composer allows repositories to define a notification URL,
|
||||
so that they get notified whenever a package from that repository is installed.
|
||||
This option allows you to disable that behaviour.
|
||||
|
||||
## discard-changes
|
||||
|
||||
Defaults to `false` and can be any of `true`, `false` or `"stash"`. This option
|
||||
allows you to set the default style of handling dirty updates when in
|
||||
non-interactive mode. `true` will always discard changes in vendors, while
|
||||
`"stash"` will try to stash and reapply. Use this for CI servers or deploy
|
||||
scripts if you tend to have modified vendors.
|
||||
|
||||
## archive-format
|
||||
|
||||
Defaults to `tar`. Composer allows you to add a default archive format when the
|
||||
workflow needs to create a dedicated archiving format.
|
||||
|
||||
## archive-dir
|
||||
|
||||
Defaults to `.`. Composer allows you to add a default archive directory when the
|
||||
workflow needs to create a dedicated archiving format. Or for easier development
|
||||
between modules.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"bin-dir": "bin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** Authentication-related config options like `http-basic` and
|
||||
> `github-oauth` can also be specified inside a `auth.json` file that goes
|
||||
> besides your `composer.json`. That way you can gitignore it and every
|
||||
> developer can place their own credentials in there.
|
||||
|
||||
← [Repositories](05-repositories.md) | [Community](07-community.md) →
|
|
@ -1,12 +1,14 @@
|
|||
# Community
|
||||
|
||||
There are many people using composer already, and quite a few of them are
|
||||
There are many people using Composer already, and quite a few of them are
|
||||
contributing.
|
||||
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to composer, please read the
|
||||
[README](https://github.com/composer/composer).
|
||||
If you would like to contribute to Composer, please read the
|
||||
[README](https://github.com/composer/composer) and
|
||||
[CONTRIBUTING](https://github.com//composer/composer/blob/master/CONTRIBUTING.md)
|
||||
documents.
|
||||
|
||||
The most important guidelines are described as follows:
|
||||
|
||||
|
@ -17,18 +19,18 @@ The most important guidelines are described as follows:
|
|||
> Fork the project, create a feature branch, and send us a pull request.
|
||||
>
|
||||
> To ensure a consistent code base, you should make sure the code follows
|
||||
> the [Coding Standards](http://symfony.com/doc/2.0/contributing/code/standards.html)
|
||||
> the [Coding Standards](https://symfony.com/doc/2.0/contributing/code/standards.html)
|
||||
> which we borrowed from Symfony.
|
||||
|
||||
## IRC / mailing list
|
||||
|
||||
Mailing lists for [user support](http://groups.google.com/group/composer-users) and
|
||||
[development](http://groups.google.com/group/composer-dev).
|
||||
Mailing lists for [user support](https://groups.google.com/group/composer-users) and
|
||||
[development](https://groups.google.com/group/composer-dev).
|
||||
|
||||
IRC channels are on irc.freenode.org: [#composer](irc://irc.freenode.org/composer)
|
||||
for users and [#composer-dev](irc://irc.freenode.org/composer-dev) for development.
|
||||
|
||||
Stack Overflow has a growing collection of
|
||||
[Composer related questions](http://stackoverflow.com/questions/tagged/composer-php).
|
||||
[Composer related questions](https://stackoverflow.com/questions/tagged/composer-php).
|
||||
|
||||
← [Repositories](05-repositories.md)
|
||||
← [Config](06-config.md)
|
|
@ -38,8 +38,8 @@ specifying a `branch-alias` field under `extra` in `composer.json`:
|
|||
}
|
||||
```
|
||||
|
||||
If you alias a non-comparible version (such as dev-develop) `dev-` must prefix the
|
||||
branch name. You may also alias a comparible version (i.e. start with numbers,
|
||||
If you alias a non-comparable version (such as dev-develop) `dev-` must prefix the
|
||||
branch name. You may also alias a comparable version (i.e. start with numbers,
|
||||
and end with `.x-dev`), but only as a more specific version.
|
||||
For example, 1.x-dev could be aliased as 1.2.x-dev.
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ An example composer.json of such a template package would be:
|
|||
## Creating an Installer
|
||||
|
||||
A Custom Installer is defined as a class that implements the
|
||||
[`Composer\Installer\InstallerInterface`][3] and is usually distributed in a
|
||||
[`Composer\Installer\InstallerInterface`][4] and is usually distributed in a
|
||||
Composer Plugin.
|
||||
|
||||
A basic Installer Plugin would thus compose of three files:
|
||||
|
|
|
@ -6,16 +6,22 @@
|
|||
|
||||
# Toran Proxy
|
||||
|
||||
[Toran Proxy](https://toranproxy.com/) is a commercial alternative to Satis offering professional support as well as a web UI to manage everything and a better integration with Composer.
|
||||
[Toran Proxy](https://toranproxy.com/) is a commercial alternative to Satis
|
||||
offering professional support as well as a web UI to manage everything and a
|
||||
better integration with Composer. It also provides proxying/mirroring for git
|
||||
repos and package zip files which makes installs faster and independent from
|
||||
third party systems.
|
||||
|
||||
Toran's revenue is also used to pay for Composer and Packagist development and hosting so using it is a good way to support open source financially. You can find more information about how to set it up and use it on the [Toran Proxy](https://toranproxy.com/) website.
|
||||
Toran's revenue is also used to pay for Composer and Packagist development and
|
||||
hosting so using it is a good way to support open source financially. You can
|
||||
find more information about how to set it up and use it on the [Toran Proxy](https://toranproxy.com/) website.
|
||||
|
||||
# Satis
|
||||
|
||||
Satis on the other hand is open source but only a static `composer`
|
||||
repository generator. It is a bit like an ultra-lightweight, static file-based
|
||||
version of packagist and can be used to host the metadata of your company's
|
||||
private packages, or your own. You can get it from [GitHub](http://github.com/composer/satis)
|
||||
private packages, or your own. You can get it from [GitHub](https://github.com/composer/satis)
|
||||
or install via CLI:
|
||||
`php composer.phar create-project composer/satis --stability=dev --keep-vcs`.
|
||||
|
||||
|
@ -38,9 +44,9 @@ The default file Satis looks for is `satis.json` in the root of the repository.
|
|||
"name": "My Repository",
|
||||
"homepage": "http://packages.example.org",
|
||||
"repositories": [
|
||||
{ "type": "vcs", "url": "http://github.com/mycompany/privaterepo" },
|
||||
{ "type": "vcs", "url": "https://github.com/mycompany/privaterepo" },
|
||||
{ "type": "vcs", "url": "http://svn.example.org/private/repo" },
|
||||
{ "type": "vcs", "url": "http://github.com/mycompany/privaterepo2" }
|
||||
{ "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" }
|
||||
],
|
||||
"require-all": true
|
||||
}
|
||||
|
@ -54,9 +60,9 @@ constraint if you want really specific versions.
|
|||
```json
|
||||
{
|
||||
"repositories": [
|
||||
{ "type": "vcs", "url": "http://github.com/mycompany/privaterepo" },
|
||||
{ "type": "vcs", "url": "https://github.com/mycompany/privaterepo" },
|
||||
{ "type": "vcs", "url": "http://svn.example.org/private/repo" },
|
||||
{ "type": "vcs", "url": "http://github.com/mycompany/privaterepo2" }
|
||||
{ "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" }
|
||||
],
|
||||
"require": {
|
||||
"company/package": "*",
|
||||
|
@ -129,7 +135,7 @@ Example using a custom repository using SSH (requires the SSH2 PECL extension):
|
|||
}
|
||||
```
|
||||
|
||||
> **Tip:** See [ssh2 context options](http://www.php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-options) for more information.
|
||||
> **Tip:** See [ssh2 context options](https://www.php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-options) for more information.
|
||||
|
||||
Example using HTTP over SSL using a client certificate:
|
||||
|
||||
|
@ -149,7 +155,45 @@ Example using HTTP over SSL using a client certificate:
|
|||
}
|
||||
```
|
||||
|
||||
> **Tip:** See [ssl context options](http://www.php.net/manual/en/context.ssl.php) for more information.
|
||||
> **Tip:** See [ssl context options](https://www.php.net/manual/en/context.ssl.php) for more information.
|
||||
|
||||
Example using a custom HTTP Header field for token authentication:
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://example.org",
|
||||
"options": {
|
||||
"http": {
|
||||
"header": [
|
||||
"API-TOKEN: YOUR-API-TOKEN"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
When your private repositories are password protected, you can store the authentication details permanently.
|
||||
The first time Composer needs to authenticate against some domain it will prompt you for a username/password
|
||||
and then you will be asked whether you want to store it.
|
||||
|
||||
The storage can be done either globally in the `COMPOSER_HOME/auth.json` file (`COMPOSER_HOME` defaults to
|
||||
`~/.composer` or `%APPDATA%/Composer` on Windows) or also in the project directory directly sitting besides your
|
||||
composer.json.
|
||||
|
||||
You can also configure these by hand using the config command if you need to configure a production machine
|
||||
to be able to run non-interactive installs. For example to enter credentials for example.org one could type:
|
||||
|
||||
composer config http-basic.example.org username password
|
||||
|
||||
That will store it in the current directory's auth.json, but if you want it available globally you can use the
|
||||
`--global` (`-g`) flag.
|
||||
|
||||
### Downloads
|
||||
|
||||
|
@ -188,8 +232,8 @@ Once enabled, all downloads (include those from GitHub and BitBucket) will be re
|
|||
Prefixing the URL with another host is especially helpful if the downloads end up in a private Amazon S3
|
||||
bucket or on a CDN host. A CDN would drastically improve download times and therefore package installation.
|
||||
|
||||
Example: A `prefix-url` of `http://my-bucket.s3.amazonaws.com` (and `directory` set to `dist`) creates download URLs
|
||||
which look like the following: `http://my-bucket.s3.amazonaws.com/dist/vendor-package-version-ref.zip`.
|
||||
Example: A `prefix-url` of `https://my-bucket.s3.amazonaws.com` (and `directory` set to `dist`) creates download URLs
|
||||
which look like the following: `https://my-bucket.s3.amazonaws.com/dist/vendor-package-version-ref.zip`.
|
||||
|
||||
|
||||
### Resolving dependencies
|
||||
|
|
|
@ -17,7 +17,7 @@ of credentials inline with the repository specification such as:
|
|||
"repositories": [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "http://extremely:secret@repo.example.org"
|
||||
"url": "https://extremely:secret@repo.example.org"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ username/password pairs, for example:
|
|||
|
||||
```json
|
||||
{
|
||||
"basic-auth": {
|
||||
"http-basic": {
|
||||
"repo.example1.org": {
|
||||
"username": "my-username1",
|
||||
"password": "my-secret-password1"
|
||||
|
@ -55,5 +55,5 @@ username/password pairs, for example:
|
|||
|
||||
The main advantage of the auth.json file is that it can be gitignored so
|
||||
that every developer in your team can place their own credentials in there,
|
||||
which makes revokation of credentials much easier than if you all share the
|
||||
which makes revocation of credentials much easier than if you all share the
|
||||
same.
|
||||
|
|
|
@ -16,7 +16,7 @@ specific logic.
|
|||
|
||||
## Creating a Plugin
|
||||
|
||||
A plugin is a regular composer package which ships its code as part of the
|
||||
A plugin is a regular Composer package which ships its code as part of the
|
||||
package and may also depend on further packages.
|
||||
|
||||
### Plugin Package
|
||||
|
@ -24,23 +24,30 @@ package and may also depend on further packages.
|
|||
The package file is the same as any other package file but with the following
|
||||
requirements:
|
||||
|
||||
1. the [type][1] attribute must be `composer-plugin`.
|
||||
2. the [extra][2] attribute must contain an element `class` defining the
|
||||
1. The [type][1] attribute must be `composer-plugin`.
|
||||
2. The [extra][2] attribute must contain an element `class` defining the
|
||||
class name of the plugin (including namespace). If a package contains
|
||||
multiple plugins this can be array of class names.
|
||||
multiple plugins, this can be array of class names.
|
||||
3. You must require the special package called `composer-plugin-api`
|
||||
to define which Plugin API versions your plugin is compatible with.
|
||||
|
||||
Additionally you must require the special package called `composer-plugin-api`
|
||||
to define which composer API versions your plugin is compatible with. The
|
||||
current composer plugin API version is 1.0.0.
|
||||
The required version of the `composer-plugin-api` follows the same [rules][7]
|
||||
as a normal package's.
|
||||
|
||||
For example
|
||||
The current composer plugin API version is 1.0.0.
|
||||
|
||||
An example of a valid plugin `composer.json` file (with the autoloading
|
||||
part omitted):
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my/plugin-package",
|
||||
"type": "composer-plugin",
|
||||
"require": {
|
||||
"composer-plugin-api": "1.0.0"
|
||||
"composer-plugin-api": "^1.0"
|
||||
},
|
||||
"extra": {
|
||||
"class": "My\\Plugin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -82,15 +89,7 @@ Furthermore plugins may implement the
|
|||
event handlers automatically registered with the `EventDispatcher` when the
|
||||
plugin is loaded.
|
||||
|
||||
The events available for plugins are:
|
||||
|
||||
* **COMMAND**, is called at the beginning of all commands that load plugins.
|
||||
It provides you with access to the input and output objects of the program.
|
||||
* **PRE_FILE_DOWNLOAD**, is triggered before files are downloaded and allows
|
||||
you to manipulate the `RemoteFilesystem` object prior to downloading files
|
||||
based on the URL to be downloaded.
|
||||
|
||||
> A plugin can also subscribe to [script events][7].
|
||||
Plugin can subscribe to any of the available [script events](scripts.md#event-names).
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -148,7 +147,7 @@ list of installed packages. Additionally all plugin packages installed in the
|
|||
local project plugins are loaded.
|
||||
|
||||
> You may pass the `--no-plugins` option to composer commands to disable all
|
||||
> installed commands. This may be particularly helpful if any of the plugins
|
||||
> installed plugins. This may be particularly helpful if any of the plugins
|
||||
> causes errors and you wish to update or uninstall it.
|
||||
|
||||
[1]: ../04-schema.md#type
|
||||
|
@ -157,4 +156,4 @@ local project plugins are loaded.
|
|||
[4]: https://github.com/composer/composer/blob/master/src/Composer/Composer.php
|
||||
[5]: https://github.com/composer/composer/blob/master/src/Composer/IO/IOInterface.php
|
||||
[6]: https://github.com/composer/composer/blob/master/src/Composer/EventDispatcher/EventSubscriberInterface.php
|
||||
[7]: ./scripts.md#event-names
|
||||
[7]: ../01-basic-usage.md#package-versions
|
||||
|
|
|
@ -20,20 +20,16 @@ the Composer execution process.
|
|||
|
||||
Composer fires the following named events during its execution process:
|
||||
|
||||
### Command Events
|
||||
|
||||
- **pre-install-cmd**: occurs before the `install` command is executed.
|
||||
- **post-install-cmd**: occurs after the `install` command is executed.
|
||||
- **pre-update-cmd**: occurs before the `update` command is executed.
|
||||
- **post-update-cmd**: occurs after the `update` command is executed.
|
||||
- **pre-status-cmd**: occurs before the `status` command is executed.
|
||||
- **post-status-cmd**: occurs after the `status` command is executed.
|
||||
- **pre-dependencies-solving**: occurs before the dependencies are resolved.
|
||||
- **post-dependencies-solving**: occurs after the dependencies are resolved.
|
||||
- **pre-package-install**: occurs before a package is installed.
|
||||
- **post-package-install**: occurs after a package is installed.
|
||||
- **pre-package-update**: occurs before a package is updated.
|
||||
- **post-package-update**: occurs after a package is updated.
|
||||
- **pre-package-uninstall**: occurs before a package has been uninstalled.
|
||||
- **post-package-uninstall**: occurs after a package has been uninstalled.
|
||||
- **pre-archive-cmd**: occurs before the `archive` command is executed.
|
||||
- **post-archive-cmd**: occurs after the `archive` command is executed.
|
||||
- **pre-autoload-dump**: occurs before the autoloader is dumped, either
|
||||
during `install`/`update`, or via the `dump-autoload` command.
|
||||
- **post-autoload-dump**: occurs after the autoloader is dumped, either
|
||||
|
@ -42,8 +38,28 @@ Composer fires the following named events during its execution process:
|
|||
installed, during the `create-project` command.
|
||||
- **post-create-project-cmd**: occurs after the `create-project` command is
|
||||
executed.
|
||||
- **pre-archive-cmd**: occurs before the `archive` command is executed.
|
||||
- **post-archive-cmd**: occurs after the `archive` command is executed.
|
||||
|
||||
### Installer Events
|
||||
|
||||
- **pre-dependencies-solving**: occurs before the dependencies are resolved.
|
||||
- **post-dependencies-solving**: occurs after the dependencies are resolved.
|
||||
|
||||
### Package Events
|
||||
|
||||
- **pre-package-install**: occurs before a package is installed.
|
||||
- **post-package-install**: occurs after a package is installed.
|
||||
- **pre-package-update**: occurs before a package is updated.
|
||||
- **post-package-update**: occurs after a package is updated.
|
||||
- **pre-package-uninstall**: occurs before a package has been uninstalled.
|
||||
- **post-package-uninstall**: occurs after a package has been uninstalled.
|
||||
|
||||
### Plugin Events
|
||||
|
||||
- **command**: occurs before any Composer Command is executed on the CLI. It
|
||||
provides you with access to the input and output objects of the program.
|
||||
- **pre-file-download**: occurs before files are downloaded and allows
|
||||
you to manipulate the `RemoteFilesystem` object prior to downloading files
|
||||
based on the URL to be downloaded.
|
||||
|
||||
> **Note:** Composer makes no assumptions about the state of your dependencies
|
||||
> prior to `install` or `update`. Therefore, you should not specify scripts
|
||||
|
@ -96,6 +112,7 @@ that might be used to execute the PHP callbacks:
|
|||
namespace MyVendor;
|
||||
|
||||
use Composer\Script\Event;
|
||||
use Composer\Installer\PackageEvent;
|
||||
|
||||
class MyClass
|
||||
{
|
||||
|
@ -105,7 +122,7 @@ class MyClass
|
|||
// do stuff
|
||||
}
|
||||
|
||||
public static function postPackageInstall(Event $event)
|
||||
public static function postPackageInstall(PackageEvent $event)
|
||||
{
|
||||
$installedPackage = $event->getOperation()->getPackage();
|
||||
// do stuff
|
||||
|
@ -118,14 +135,21 @@ class MyClass
|
|||
}
|
||||
```
|
||||
|
||||
When an event is fired, Composer's internal event handler receives a
|
||||
`Composer\Script\Event` object, which is passed as the first argument to your
|
||||
PHP callback. This `Event` object has getters for other contextual objects:
|
||||
When an event is fired, your PHP callback receives as first argument an
|
||||
`Composer\EventDispatcher\Event` object. This object has a `getName()` method
|
||||
that lets you retrieve event name.
|
||||
|
||||
- `getComposer()`: returns the current instance of `Composer\Composer`
|
||||
- `getName()`: returns the name of the event being fired as a string
|
||||
- `getIO()`: returns the current input/output stream which implements
|
||||
`Composer\IO\IOInterface` for writing to the console
|
||||
Depending on the script types (see list above) you will get various event
|
||||
subclasses containing various getters with relevant data and associated
|
||||
objects:
|
||||
|
||||
- Base class: [`Composer\EventDispatcher\Event`](https://getcomposer.org/apidoc/master/Composer/EventDispatcher/Event.html)
|
||||
- Command Events: [`Composer\Script\Event`](https://getcomposer.org/apidoc/master/Composer/Script/Event.html)
|
||||
- Installer Events: [`Composer\Installer\InstallerEvent`](https://getcomposer.org/apidoc/master/Composer/Installer/InstallerEvent.html)
|
||||
- Package Events: [`Composer\Installer\PackageEvent`](https://getcomposer.org/apidoc/master/Composer/Installer/PackageEvent.html)
|
||||
- Plugin Events:
|
||||
- command: [`Composer\Plugin\CommandEvent`](https://getcomposer.org/apidoc/master/Composer/Plugin/CommandEvent.html)
|
||||
- pre-file-download: [`Composer\Plugin\PreFileDownloadEvent`](https://getcomposer.org/apidoc/master/Composer/Plugin/PreFileDownloadEvent.html)
|
||||
|
||||
## Running scripts manually
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ This is a list of common pitfalls on using Composer, and how to avoid them.
|
|||
1. Check the ["Package not found"](#package-not-found) item above.
|
||||
|
||||
2. If the package tested is a dependency of one of its dependencies (cyclic
|
||||
dependency), the problem might be that composer is not able to detect the version
|
||||
dependency), the problem might be that Composer is not able to detect the version
|
||||
of the package properly. If it is a git clone it is generally alright and Composer
|
||||
will detect the version of the current branch, but travis does shallow clones so
|
||||
that process can fail when testing pull requests and feature branches in general.
|
||||
|
@ -58,11 +58,22 @@ This is a list of common pitfalls on using Composer, and how to avoid them.
|
|||
Use: `before_script: COMPOSER_ROOT_VERSION=dev-master composer install` to export
|
||||
the variable for the call to composer.
|
||||
|
||||
## Package not found in a Jenkins-build
|
||||
|
||||
1. Check the ["Package not found"](#package-not-found) item above.
|
||||
2. Reason for failing is similar to the problem which can occur on travis-ci.org: The
|
||||
git-clone / checkout within Jenkins leaves the branch in a "detached HEAD"-state. As
|
||||
a result, Composer is not able to identify the version of the current checked out branch
|
||||
and may not be able to resolve a cyclic dependency. To solve this problem, you can use
|
||||
the "Additional Behaviours" -> "Check out to specific local branch" in your Git-settings
|
||||
for your Jenkins-job, where your "local branch" shall be the same branch as you are
|
||||
checking out. Using this, the checkout will not be in detached state any more and cyclic
|
||||
dependency is recognized correctly.
|
||||
|
||||
## Need to override a package version
|
||||
|
||||
Let say your project depends on package A which in turn depends on a specific
|
||||
version of package B (say 0.1) and you need a different version of that
|
||||
package - version 0.11.
|
||||
Let's say your project depends on package A, which in turn depends on a specific
|
||||
version of package B (say 0.1). But you need a different version of said package B (say 0.11).
|
||||
|
||||
You can fix this by aliasing version 0.11 to 0.1:
|
||||
|
||||
|
@ -87,7 +98,7 @@ If composer shows memory errors on some commands:
|
|||
|
||||
The PHP `memory_limit` should be increased.
|
||||
|
||||
> **Note:** Composer internally increases the `memory_limit` to `512M`.
|
||||
> **Note:** Composer internally increases the `memory_limit` to `1G`.
|
||||
> If you have memory issues when using composer, please consider [creating
|
||||
> an issue ticket](https://github.com/composer/composer/issues) so we can look into it.
|
||||
|
||||
|
@ -101,7 +112,7 @@ Try increasing the limit in your `php.ini` file (ex. `/etc/php5/cli/php.ini` for
|
|||
Debian-like systems):
|
||||
|
||||
```ini
|
||||
; Use -1 for unlimited or define an explicit value like 512M
|
||||
; Use -1 for unlimited or define an explicit value like 2G
|
||||
memory_limit = -1
|
||||
```
|
||||
|
||||
|
|
|
@ -12,6 +12,13 @@ resulting order in which the solver will try to install them.
|
|||
|
||||
The rules are to be applied in the order of these descriptions.
|
||||
|
||||
### Repository priorities
|
||||
|
||||
Packages Repo1.Av1, Repo2.Av1
|
||||
|
||||
* priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1)
|
||||
* priority(Repo1) < priority(Repo2) => (Repo2.Av1, Repo1.Av1)
|
||||
|
||||
### Package versions
|
||||
|
||||
Packages: Av1, Av2, Av3
|
||||
|
@ -22,13 +29,6 @@ Request: install A
|
|||
|
||||
* (Av3)
|
||||
|
||||
### Repository priorities
|
||||
|
||||
Packages Repo1.Av1, Repo2.Av1
|
||||
|
||||
* priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1)
|
||||
* priority(Repo1) < priority(Repo2) => (Repo2.Av1, Repo1.Av1)
|
||||
|
||||
### Virtual Packages (provides)
|
||||
|
||||
Packages Av1, Bv1
|
||||
|
|
|
@ -27,6 +27,6 @@ If you really feel like you must do this, you have a few options:
|
|||
in ZSH or `find vendor/ -type d -name ".git" -exec rm -rf {} \;` in Bash.
|
||||
but this means you will have to delete those dependencies from disk before
|
||||
running composer update.
|
||||
4. Add a .gitignore rule (`vendor/.git`) to ignore all the vendor `.git` folders.
|
||||
4. Add a .gitignore rule (`/vendor/**/.git`) to ignore all the vendor `.git` folders.
|
||||
This approach does not require that you delete dependencies from disk prior to
|
||||
running a composer update.
|
||||
|
|
|
@ -14,7 +14,7 @@ compatible with the new major version of your dependency.
|
|||
|
||||
For example instead of using `>=3.4` you should use `~3.4` which allows all
|
||||
versions up to `3.999` but does not include `4.0` and above. The `~` operator
|
||||
works very well with libraries follow [semantic versioning](http://semver.org).
|
||||
works very well with libraries following [semantic versioning](http://semver.org).
|
||||
|
||||
**Note:** As a package maintainer, you can make the life of your users easier
|
||||
by providing an [alias version](../articles/aliases.md) for your development
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Package version, see http://getcomposer.org/doc/04-schema.md#version for more info on valid schemes."
|
||||
"description": "Package version, see https://getcomposer.org/doc/04-schema.md#version for more info on valid schemes."
|
||||
},
|
||||
"time": {
|
||||
"type": "string",
|
||||
|
@ -145,6 +145,11 @@
|
|||
"type": ["string", "boolean"],
|
||||
"description": "What to do after prompting for authentication, one of: true (store), false (do not store) or \"prompt\" (ask every time), defaults to prompt."
|
||||
},
|
||||
"platform": {
|
||||
"type": "object",
|
||||
"description": "This is a hash of package name (keys) and version (values) that will be used to mock the platform packages on this machine.",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"vendor-dir": {
|
||||
"type": "string",
|
||||
"description": "The location where all packages are installed, defaults to \"vendor\"."
|
||||
|
@ -211,6 +216,14 @@
|
|||
"github-expose-hostname": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to true. If set to false, the OAuth tokens created to access the github API will have a date instead of the machine hostname."
|
||||
},
|
||||
"archive-format": {
|
||||
"type": "string",
|
||||
"description": "The default archiving format when not provided on cli, defaults to \"tar\"."
|
||||
},
|
||||
"archive-dir": {
|
||||
"type": "string",
|
||||
"description": "The default archive path when not provided on cli, defaults to \".\"."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -284,11 +297,12 @@
|
|||
},
|
||||
"minimum-stability": {
|
||||
"type": ["string"],
|
||||
"description": "The minimum stability the packages must have to be install-able. Possible values are: dev, alpha, beta, RC, stable."
|
||||
"description": "The minimum stability the packages must have to be install-able. Possible values are: dev, alpha, beta, RC, stable.",
|
||||
"pattern": "^dev|alpha|beta|rc|RC|stable$"
|
||||
},
|
||||
"prefer-stable": {
|
||||
"type": ["boolean"],
|
||||
"description": "If set to true, stable packages will be prefered to dev packages when possible, even if the minimum-stability allows unstable packages."
|
||||
"description": "If set to true, stable packages will be preferred to dev packages when possible, even if the minimum-stability allows unstable packages."
|
||||
},
|
||||
"bin": {
|
||||
"type": ["array"],
|
||||
|
@ -384,17 +398,17 @@
|
|||
},
|
||||
"issues": {
|
||||
"type": "string",
|
||||
"description": "URL to the Issue Tracker.",
|
||||
"description": "URL to the issue tracker.",
|
||||
"format": "uri"
|
||||
},
|
||||
"forum": {
|
||||
"type": "string",
|
||||
"description": "URL to the Forum.",
|
||||
"description": "URL to the forum.",
|
||||
"format": "uri"
|
||||
},
|
||||
"wiki": {
|
||||
"type": "string",
|
||||
"description": "URL to the Wiki.",
|
||||
"description": "URL to the wiki.",
|
||||
"format": "uri"
|
||||
},
|
||||
"irc": {
|
||||
|
@ -406,7 +420,19 @@
|
|||
"type": "string",
|
||||
"description": "URL to browse or download the sources.",
|
||||
"format": "uri"
|
||||
}
|
||||
},
|
||||
"docs": {
|
||||
"type": "string",
|
||||
"description": "URL to the documentation.",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
},
|
||||
"non-feature-branches": {
|
||||
"type": ["array"],
|
||||
"description": "A set of string or regex patterns for non-numeric branch names that will not be handled as feature branches.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
[
|
||||
"Glide", "Abstyles", "AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0",
|
||||
"AMPAS", "APL-1.0", "Adobe-Glyph", "APAFML", "Adobe-2006", "AGPL-1.0",
|
||||
"Afmparse", "Aladdin", "ADSL", "AMDPLPA", "ANTLR-PD", "Apache-1.0",
|
||||
"Apache-1.1", "Apache-2.0", "AML", "APSL-1.0", "APSL-1.1", "APSL-1.2",
|
||||
"APSL-2.0", "Artistic-1.0", "Artistic-1.0-Perl", "Artistic-1.0-cl8",
|
||||
"Artistic-2.0", "AAL", "Bahyph", "Barr", "Beerware", "BitTorrent-1.0",
|
||||
"BitTorrent-1.1", "BSL-1.0", "Borceux", "BSD-2-Clause",
|
||||
"BSD-2-Clause-FreeBSD", "BSD-2-Clause-NetBSD", "BSD-3-Clause",
|
||||
"BSD-3-Clause-Clear", "BSD-4-Clause", "BSD-Protection",
|
||||
"BSD-3-Clause-Attribution", "BSD-4-Clause-UC", "bzip2-1.0.5", "bzip2-1.0.6",
|
||||
"Caldera", "CECILL-1.0", "CECILL-1.1", "CECILL-2.0", "CECILL-B", "CECILL-C",
|
||||
"ClArtistic", "MIT-CMU", "CNRI-Python", "CNRI-Python-GPL-Compatible",
|
||||
"CPOL-1.02", "CDDL-1.0", "CDDL-1.1", "CPAL-1.0", "CPL-1.0", "CATOSL-1.1",
|
||||
"Condor-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5", "CC-BY-3.0",
|
||||
"CC-BY-4.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0",
|
||||
"CC-BY-ND-4.0", "CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5",
|
||||
"CC-BY-NC-3.0", "CC-BY-NC-4.0", "CC-BY-NC-ND-1.0", "CC-BY-NC-ND-2.0",
|
||||
"CC-BY-NC-ND-2.5", "CC-BY-NC-ND-3.0", "CC-BY-NC-ND-4.0", "CC-BY-NC-SA-1.0",
|
||||
"CC-BY-NC-SA-2.0", "CC-BY-NC-SA-2.5", "CC-BY-NC-SA-3.0", "CC-BY-NC-SA-4.0",
|
||||
"CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.5", "CC-BY-SA-3.0",
|
||||
"CC-BY-SA-4.0", "CC0-1.0", "Crossword", "CUA-OPL-1.0", "Cube", "D-FSL-1.0",
|
||||
"diffmark", "WTFPL", "DOC", "Dotseqn", "DSDP", "dvipdfm", "EPL-1.0",
|
||||
"eCos-2.0", "ECL-1.0", "ECL-2.0", "eGenix", "EFL-1.0", "EFL-2.0",
|
||||
"MIT-advertising", "MIT-enna", "Entessa", "ErlPL-1.1", "EUDatagrid",
|
||||
"EUPL-1.0", "EUPL-1.1", "Eurosym", "Fair", "MIT-feh", "Frameworx-1.0",
|
||||
"FTL", "FSFUL", "FSFULLR", "Giftware", "GL2PS", "Glulxe", "AGPL-3.0",
|
||||
"GFDL-1.1", "GFDL-1.2", "GFDL-1.3", "GPL-1.0", "GPL-1.0+", "GPL-2.0",
|
||||
"GPL-2.0+", "GPL-2.0-with-autoconf-exception",
|
||||
"GPL-2.0-with-bison-exception", "GPL-2.0-with-classpath-exception",
|
||||
"GPL-2.0-with-font-exception", "GPL-2.0-with-GCC-exception", "GPL-3.0",
|
||||
"GPL-3.0+", "GPL-3.0-with-autoconf-exception", "GPL-3.0-with-GCC-exception",
|
||||
"LGPL-2.1", "LGPL-2.1+", "LGPL-3.0", "LGPL-3.0+", "LGPL-2.0", "LGPL-2.0+",
|
||||
"gnuplot", "gSOAP-1.3b", "HaskellReport", "HPND", "IBM-pibs", "IPL-1.0",
|
||||
"ImageMagick", "iMatix", "Imlib2", "IJG", "Intel-ACPI", "Intel", "IPA",
|
||||
"ISC", "JasPer-2.0", "JSON", "LPPL-1.3a", "LPPL-1.0", "LPPL-1.1",
|
||||
"LPPL-1.2", "LPPL-1.3c", "Latex2e", "BSD-3-Clause-LBNL", "Leptonica",
|
||||
"Libpng", "libtiff", "LPL-1.02", "LPL-1.0", "MakeIndex", "MTLL", "MS-PL",
|
||||
"MS-RL", "MirOS", "MITNFA", "MIT", "Motosoto", "MPL-1.0", "MPL-1.1",
|
||||
"MPL-2.0", "MPL-2.0-no-copyleft-exception", "mpich2", "Multics", "Mup",
|
||||
"NASA-1.3", "Naumen", "NBPL-1.0", "NetCDF", "NGPL", "NOSL", "NPL-1.0",
|
||||
"NPL-1.1", "Newsletr", "NLPL", "Nokia", "NPOSL-3.0", "Noweb", "NRL", "NTP",
|
||||
"Nunit", "OCLC-2.0", "ODbL-1.0", "PDDL-1.0", "OGTSL", "OLDAP-2.2.2",
|
||||
"OLDAP-1.1", "OLDAP-1.2", "OLDAP-1.3", "OLDAP-1.4", "OLDAP-2.0",
|
||||
"OLDAP-2.0.1", "OLDAP-2.1", "OLDAP-2.2", "OLDAP-2.2.1", "OLDAP-2.3",
|
||||
"OLDAP-2.4", "OLDAP-2.5", "OLDAP-2.6", "OLDAP-2.7", "OML", "OPL-1.0",
|
||||
"OSL-1.0", "OSL-1.1", "OSL-2.0", "OSL-2.1", "OSL-3.0", "OLDAP-2.8",
|
||||
"OpenSSL", "PHP-3.0", "PHP-3.01", "Plexus", "PostgreSQL", "psfrag",
|
||||
"psutils", "Python-2.0", "QPL-1.0", "Qhull", "Rdisc", "RPSL-1.0", "RPL-1.1",
|
||||
"RPL-1.5", "RHeCos-1.1", "RSCPL", "Ruby", "SAX-PD", "Saxpath", "SCEA",
|
||||
"SWL", "SGI-B-1.0", "SGI-B-1.1", "SGI-B-2.0", "OFL-1.0", "OFL-1.1",
|
||||
"SimPL-2.0", "Sleepycat", "SNIA", "SMLNJ", "StandardML-NJ",
|
||||
"SugarCRM-1.1.3", "SISSL", "SISSL-1.2", "SPL-1.0", "Watcom-1.0", "TCL",
|
||||
"Unlicense", "TMate", "TORQUE-1.1", "TOSL", "Unicode-TOU", "NCSA", "Vim",
|
||||
"VOSTROM", "VSL-1.0", "W3C", "Wsuipa", "WXwindows", "Xnet", "X11", "Xerox",
|
||||
"XFree86-1.1", "xinetd", "xpp", "XSkat", "YPL-1.0", "YPL-1.1", "Zed",
|
||||
"Zend-2.0", "Zimbra-1.3", "Zlib", "zlib-acknowledgement", "ZPL-1.1",
|
||||
"ZPL-2.0", "ZPL-2.1"
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -183,7 +183,7 @@ EOF;
|
|||
continue;
|
||||
}
|
||||
$whitelist = sprintf(
|
||||
'{%s/%s.+(?<!(?<!/)Test\.php)$}',
|
||||
'{%s/%s.+$}',
|
||||
preg_quote($dir),
|
||||
($psrType === 'psr-0' && strpos($namespace, '_') === false) ? preg_quote(strtr($namespace, '\\', '/')) : ''
|
||||
);
|
||||
|
@ -213,9 +213,18 @@ EOF;
|
|||
}
|
||||
$classmapFile .= ");\n";
|
||||
|
||||
if (!$suffix) {
|
||||
if (!$config->get('autoloader-suffix') && is_readable($vendorPath.'/autoload.php')) {
|
||||
$content = file_get_contents($vendorPath.'/autoload.php');
|
||||
if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
|
||||
$suffix = $match[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$suffix) {
|
||||
$suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true));
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
|
||||
file_put_contents($targetDir.'/autoload_psr4.php', $psr4File);
|
||||
|
@ -383,7 +392,7 @@ EOF;
|
|||
}
|
||||
|
||||
if (!$filesCode) {
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return <<<EOF
|
||||
|
|
|
@ -351,7 +351,7 @@ class ClassLoader
|
|||
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
||||
if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ class ClassLoader
|
|||
|
||||
// PSR-4 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ class ClassLoader
|
|||
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||
if (0 === strpos($class, $prefix)) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ class ClassLoader
|
|||
|
||||
// PSR-0 fallback dirs
|
||||
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ class ClassMapGenerator
|
|||
if (!isset($map[$class])) {
|
||||
$map[$class] = $filePath;
|
||||
} elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
|
||||
$io->write(
|
||||
$io->writeError(
|
||||
'<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
|
||||
' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.</warning>'
|
||||
);
|
||||
|
@ -112,7 +112,10 @@ class ClassMapGenerator
|
|||
*/
|
||||
private static function findClasses($path)
|
||||
{
|
||||
$traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait';
|
||||
$extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait';
|
||||
if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) {
|
||||
$extraTypes .= '|enum';
|
||||
}
|
||||
|
||||
try {
|
||||
$contents = @php_strip_whitespace($path);
|
||||
|
@ -129,14 +132,14 @@ class ClassMapGenerator
|
|||
}
|
||||
|
||||
// return early if there is no chance of matching anything in this file
|
||||
if (!preg_match('{\b(?:class|interface'.$traits.')\s}i', $contents)) {
|
||||
if (!preg_match('{\b(?:class|interface'.$extraTypes.')\s}i', $contents)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// strip heredocs/nowdocs
|
||||
$contents = preg_replace('{<<<\s*(\'?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\2(?=\r\n|\n|\r|;)}s', 'null', $contents);
|
||||
// strip strings
|
||||
$contents = preg_replace('{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}s', 'null', $contents);
|
||||
$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);
|
||||
|
@ -154,8 +157,8 @@ class ClassMapGenerator
|
|||
|
||||
preg_match_all('{
|
||||
(?:
|
||||
\b(?<![\$:>])(?P<type>class|interface'.$traits.') \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*[\{;]
|
||||
\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);
|
||||
|
||||
|
@ -170,6 +173,12 @@ class ClassMapGenerator
|
|||
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, '\\');
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class Cache
|
|||
$file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
|
||||
if ($this->enabled && file_exists($this->root . $file)) {
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('Reading '.$this->root . $file.' from cache');
|
||||
$this->io->writeError('Reading '.$this->root . $file.' from cache');
|
||||
}
|
||||
|
||||
return file_get_contents($this->root . $file);
|
||||
|
@ -80,7 +80,7 @@ class Cache
|
|||
$file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
|
||||
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('Writing '.$this->root . $file.' into cache');
|
||||
$this->io->writeError('Writing '.$this->root . $file.' into cache');
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -98,7 +98,7 @@ class Cache
|
|||
@disk_free_space($this->root . dirname($file))
|
||||
);
|
||||
|
||||
$this->io->write($message);
|
||||
$this->io->writeError($message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ class Cache
|
|||
$this->filesystem->ensureDirectoryExists(dirname($this->root . $file));
|
||||
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('Writing '.$this->root . $file.' into cache');
|
||||
$this->io->writeError('Writing '.$this->root . $file.' into cache');
|
||||
}
|
||||
|
||||
return copy($source, $this->root . $file);
|
||||
|
@ -136,10 +136,16 @@ class Cache
|
|||
{
|
||||
$file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
|
||||
if ($this->enabled && file_exists($this->root . $file)) {
|
||||
try {
|
||||
touch($this->root . $file, filemtime($this->root . $file), time());
|
||||
} catch (\ErrorException $e) {
|
||||
// fallback in case the above failed due to incorrect ownership
|
||||
// see https://github.com/composer/composer/issues/4070
|
||||
touch($this->root . $file);
|
||||
}
|
||||
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('Reading '.$this->root . $file.' from cache');
|
||||
$this->io->writeError('Reading '.$this->root . $file.' from cache');
|
||||
}
|
||||
|
||||
return copy($this->root . $file, $target);
|
||||
|
|
|
@ -34,10 +34,10 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln(<<<EOT
|
||||
$this->getIO()->write(<<<EOT
|
||||
<info>Composer - Package Management for PHP</info>
|
||||
<comment>Composer is a dependency manager tracking local dependencies of your projects and libraries.
|
||||
See http://getcomposer.org/ for more information.</comment>
|
||||
See https://getcomposer.org/ for more information.</comment>
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,12 +14,11 @@ namespace Composer\Command;
|
|||
|
||||
use Composer\Factory;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\Config;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Script\ScriptEvents;
|
||||
use Composer\Plugin\CommandEvent;
|
||||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
@ -41,8 +40,8 @@ class ArchiveCommand extends Command
|
|||
->setDefinition(array(
|
||||
new InputArgument('package', InputArgument::OPTIONAL, 'The package to archive instead of the current project'),
|
||||
new InputArgument('version', InputArgument::OPTIONAL, 'A version constraint to find the package to archive'),
|
||||
new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the resulting archive: tar or zip', 'tar'),
|
||||
new InputOption('dir', false, InputOption::VALUE_REQUIRED, 'Write the archive to this directory', '.'),
|
||||
new InputOption('format', 'f', InputOption::VALUE_OPTIONAL, 'Format of the resulting archive: tar or zip'),
|
||||
new InputOption('dir', false, InputOption::VALUE_OPTIONAL, 'Write the archive to this directory'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>archive</info> command creates an archive of the specified format
|
||||
|
@ -58,6 +57,7 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
$composer = $this->getComposer(false);
|
||||
if ($composer) {
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'archive', $input, $output);
|
||||
|
@ -65,8 +65,16 @@ EOT
|
|||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_ARCHIVE_CMD);
|
||||
}
|
||||
|
||||
if (null === $input->getOption('format')) {
|
||||
$input->setOption('format', $config->get('archive-format'));
|
||||
}
|
||||
if (null === $input->getOption('dir')) {
|
||||
$input->setOption('dir', $config->get('archive-dir'));
|
||||
}
|
||||
|
||||
$returnCode = $this->archive(
|
||||
$this->getIO(),
|
||||
$config,
|
||||
$input->getArgument('package'),
|
||||
$input->getArgument('version'),
|
||||
$input->getOption('format'),
|
||||
|
@ -80,9 +88,8 @@ EOT
|
|||
return $returnCode;
|
||||
}
|
||||
|
||||
protected function archive(IOInterface $io, $packageName = null, $version = null, $format = 'tar', $dest = '.')
|
||||
protected function archive(IOInterface $io, Config $config, $packageName = null, $version = null, $format = 'tar', $dest = '.')
|
||||
{
|
||||
$config = Factory::createConfig();
|
||||
$factory = new Factory;
|
||||
$downloadManager = $factory->createDownloadManager($io, $config);
|
||||
$archiveManager = $factory->createArchiveManager($config, $downloadManager);
|
||||
|
@ -97,7 +104,7 @@ EOT
|
|||
$package = $this->getComposer()->getPackage();
|
||||
}
|
||||
|
||||
$io->write('<info>Creating the archive.</info>');
|
||||
$io->writeError('<info>Creating the archive into "'.$dest.'".</info>');
|
||||
$archiveManager->archive($package, $format, $dest);
|
||||
|
||||
return 0;
|
||||
|
@ -105,34 +112,29 @@ EOT
|
|||
|
||||
protected function selectPackage(IOInterface $io, $packageName, $version = null)
|
||||
{
|
||||
$io->write('<info>Searching for the specified package.</info>');
|
||||
$io->writeError('<info>Searching for the specified package.</info>');
|
||||
|
||||
if ($composer = $this->getComposer(false)) {
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
$repos = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||
$repo = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$io->write('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$repos = new CompositeRepository($defaultRepos);
|
||||
$io->writeError('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$repo = new CompositeRepository($defaultRepos);
|
||||
}
|
||||
|
||||
$pool = new Pool();
|
||||
$pool->addRepository($repos);
|
||||
|
||||
$parser = new VersionParser();
|
||||
$constraint = ($version) ? $parser->parseConstraints($version) : null;
|
||||
$packages = $pool->whatProvides($packageName, $constraint, true);
|
||||
$packages = $repo->findPackages($packageName, $version);
|
||||
|
||||
if (count($packages) > 1) {
|
||||
$package = reset($packages);
|
||||
$io->write('<info>Found multiple matches, selected '.$package->getPrettyString().'.</info>');
|
||||
$io->write('Alternatives were '.implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)).'.');
|
||||
$io->write('<comment>Please use a more specific constraint to pick a different package.</comment>');
|
||||
$io->writeError('<info>Found multiple matches, selected '.$package->getPrettyString().'.</info>');
|
||||
$io->writeError('Alternatives were '.implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)).'.');
|
||||
$io->writeError('<comment>Please use a more specific constraint to pick a different package.</comment>');
|
||||
} elseif ($packages) {
|
||||
$package = reset($packages);
|
||||
$io->write('<info>Found an exact match '.$package->getPrettyString().'.</info>');
|
||||
$io->writeError('<info>Found an exact match '.$package->getPrettyString().'.</info>');
|
||||
} else {
|
||||
$io->write('<error>Could not find a package matching '.$packageName.'.</error>');
|
||||
$io->writeError('<error>Could not find a package matching '.$packageName.'.</error>');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -51,21 +51,21 @@ EOT
|
|||
foreach ($cachePaths as $key => $cachePath) {
|
||||
$cachePath = realpath($cachePath);
|
||||
if (!$cachePath) {
|
||||
$io->write("<info>Cache directory does not exist ($key): $cachePath</info>");
|
||||
$io->writeError("<info>Cache directory does not exist ($key): $cachePath</info>");
|
||||
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
$cache = new Cache($io, $cachePath);
|
||||
if (!$cache->isEnabled()) {
|
||||
$io->write("<info>Cache is not enabled ($key): $cachePath</info>");
|
||||
$io->writeError("<info>Cache is not enabled ($key): $cachePath</info>");
|
||||
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
$io->write("<info>Clearing cache ($key): $cachePath</info>");
|
||||
$io->writeError("<info>Clearing cache ($key): $cachePath</info>");
|
||||
$cache->gc(0, 0);
|
||||
}
|
||||
|
||||
$io->write('<info>All caches cleared.</info>');
|
||||
$io->writeError('<info>All caches cleared.</info>');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,15 +33,25 @@ class ConfigCommand extends Command
|
|||
protected $config;
|
||||
|
||||
/**
|
||||
* @var Composer\Json\JsonFile
|
||||
* @var JsonFile
|
||||
*/
|
||||
protected $configFile;
|
||||
|
||||
/**
|
||||
* @var Composer\Config\JsonConfigSource
|
||||
* @var JsonConfigSource
|
||||
*/
|
||||
protected $configSource;
|
||||
|
||||
/**
|
||||
* @var JsonFile
|
||||
*/
|
||||
protected $authConfigFile;
|
||||
|
||||
/**
|
||||
* @var JsonConfigSource
|
||||
*/
|
||||
protected $authConfigSource;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -65,6 +75,15 @@ class ConfigCommand extends Command
|
|||
This command allows you to edit some basic composer settings in either the
|
||||
local composer.json file or the global config.json file.
|
||||
|
||||
To set a config setting:
|
||||
|
||||
<comment>%command.full_name% bin-dir bin/</comment>
|
||||
|
||||
To read a config setting:
|
||||
|
||||
<comment>%command.full_name% bin-dir</comment>
|
||||
Outputs: <info>bin</info>
|
||||
|
||||
To edit the global config.json file:
|
||||
|
||||
<comment>%command.full_name% --global</comment>
|
||||
|
@ -73,7 +92,15 @@ To add a repository:
|
|||
|
||||
<comment>%command.full_name% repositories.foo vcs http://bar.com</comment>
|
||||
|
||||
You can add a repository to the global config.json file by passing in the
|
||||
To remove a repository (repo is a short alias for repositories):
|
||||
|
||||
<comment>%command.full_name% --unset repo.foo</comment>
|
||||
|
||||
To disable packagist:
|
||||
|
||||
<comment>%command.full_name% repo.packagist false</comment>
|
||||
|
||||
You can alter repositories in the global config.json file by passing in the
|
||||
<info>--global</info> option.
|
||||
|
||||
To edit the file in an external editor:
|
||||
|
@ -114,6 +141,11 @@ EOT
|
|||
? ($this->config->get('home') . '/config.json')
|
||||
: $input->getOption('file');
|
||||
|
||||
// create global composer.json if this was invoked using `composer global config`
|
||||
if ($configFile === 'composer.json' && !file_exists($configFile) && realpath(getcwd()) === realpath($this->config->get('home'))) {
|
||||
file_put_contents($configFile, "{\n}\n");
|
||||
}
|
||||
|
||||
$this->configFile = new JsonFile($configFile);
|
||||
$this->configSource = new JsonConfigSource($this->configFile);
|
||||
|
||||
|
@ -230,55 +262,13 @@ EOT
|
|||
$value = json_encode($value);
|
||||
}
|
||||
|
||||
$output->writeln($value);
|
||||
$this->getIO()->write($value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$values = $input->getArgument('setting-value'); // what the user is trying to add/change
|
||||
|
||||
// handle repositories
|
||||
if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) {
|
||||
if ($input->getOption('unset')) {
|
||||
return $this->configSource->removeRepository($matches[1]);
|
||||
}
|
||||
|
||||
if (2 !== count($values)) {
|
||||
throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs http://bar.com');
|
||||
}
|
||||
|
||||
return $this->configSource->addRepository($matches[1], array(
|
||||
'type' => $values[0],
|
||||
'url' => $values[1],
|
||||
));
|
||||
}
|
||||
|
||||
// handle github-oauth
|
||||
if (preg_match('/^(github-oauth|http-basic)\.(.+)/', $settingKey, $matches)) {
|
||||
if ($input->getOption('unset')) {
|
||||
$this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($matches[1] === 'github-oauth') {
|
||||
if (1 !== count($values)) {
|
||||
throw new \RuntimeException('Too many arguments, expected only one token');
|
||||
}
|
||||
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
$this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], $values[0]);
|
||||
} elseif ($matches[1] === 'http-basic') {
|
||||
if (2 !== count($values)) {
|
||||
throw new \RuntimeException('Expected two arguments (username, password), got '.count($values));
|
||||
}
|
||||
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
$this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1]));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$booleanValidator = function ($val) { return in_array($val, array('true', 'false', '1', '0'), true); };
|
||||
$booleanNormalizer = function ($val) { return $val !== 'false' && (bool) $val; };
|
||||
|
||||
|
@ -402,6 +392,64 @@ EOT
|
|||
}
|
||||
}
|
||||
|
||||
// handle repositories
|
||||
if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) {
|
||||
if ($input->getOption('unset')) {
|
||||
return $this->configSource->removeRepository($matches[1]);
|
||||
}
|
||||
|
||||
if (2 === count($values)) {
|
||||
return $this->configSource->addRepository($matches[1], array(
|
||||
'type' => $values[0],
|
||||
'url' => $values[1],
|
||||
));
|
||||
}
|
||||
|
||||
if (1 === count($values)) {
|
||||
$bool = strtolower($values[0]);
|
||||
if (true === $booleanValidator($bool) && false === $booleanNormalizer($bool)) {
|
||||
return $this->configSource->addRepository($matches[1], false);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs http://bar.com');
|
||||
}
|
||||
|
||||
// handle platform
|
||||
if (preg_match('/^platform\.(.+)/', $settingKey, $matches)) {
|
||||
if ($input->getOption('unset')) {
|
||||
return $this->configSource->removeConfigSetting($settingKey);
|
||||
}
|
||||
|
||||
return $this->configSource->addConfigSetting($settingKey, $values[0]);
|
||||
}
|
||||
|
||||
// handle github-oauth
|
||||
if (preg_match('/^(github-oauth|http-basic)\.(.+)/', $settingKey, $matches)) {
|
||||
if ($input->getOption('unset')) {
|
||||
$this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($matches[1] === 'github-oauth') {
|
||||
if (1 !== count($values)) {
|
||||
throw new \RuntimeException('Too many arguments, expected only one token');
|
||||
}
|
||||
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
$this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], $values[0]);
|
||||
} elseif ($matches[1] === 'http-basic') {
|
||||
if (2 !== count($values)) {
|
||||
throw new \RuntimeException('Expected two arguments (username, password), got '.count($values));
|
||||
}
|
||||
$this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
|
||||
$this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1]));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command');
|
||||
}
|
||||
|
||||
|
@ -450,9 +498,9 @@ EOT
|
|||
}
|
||||
|
||||
if (is_string($rawVal) && $rawVal != $value) {
|
||||
$output->writeln('[<comment>' . $k . $key . '</comment>] <info>' . $rawVal . ' (' . $value . ')</info>');
|
||||
$this->getIO()->write('[<comment>' . $k . $key . '</comment>] <info>' . $rawVal . ' (' . $value . ')</info>');
|
||||
} else {
|
||||
$output->writeln('[<comment>' . $k . $key . '</comment>] <info>' . $value . '</info>');
|
||||
$this->getIO()->write('[<comment>' . $k . $key . '</comment>] <info>' . $value . '</info>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,12 +101,10 @@ EOT
|
|||
{
|
||||
$config = Factory::createConfig();
|
||||
|
||||
$preferSource = false;
|
||||
$preferDist = false;
|
||||
$this->updatePreferredOptions($config, $input, $preferSource, $preferDist);
|
||||
$this->updatePreferredOptions($config, $input, $preferSource, $preferDist, true);
|
||||
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$this->getIO()->writeError('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$input->setOption('no-plugins', true);
|
||||
}
|
||||
|
||||
|
@ -145,11 +143,13 @@ EOT
|
|||
}
|
||||
|
||||
$composer = Factory::create($io, null, $disablePlugins);
|
||||
$composer->getDownloadManager()->setOutputProgress(!$noProgress);
|
||||
|
||||
$fs = new Filesystem();
|
||||
|
||||
if ($noScripts === false) {
|
||||
// dispatch event
|
||||
$composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages);
|
||||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages);
|
||||
}
|
||||
|
||||
$rootPackageConfig = $composer->getConfig();
|
||||
|
@ -196,7 +196,7 @@ EOT
|
|||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$io->write('<error>An error occurred while removing the VCS metadata: '.$e->getMessage().'</error>');
|
||||
$io->writeError('<error>An error occurred while removing the VCS metadata: '.$e->getMessage().'</error>');
|
||||
}
|
||||
|
||||
$hasVcs = false;
|
||||
|
@ -217,7 +217,7 @@ EOT
|
|||
|
||||
if ($noScripts === false) {
|
||||
// dispatch event
|
||||
$composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages);
|
||||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages);
|
||||
}
|
||||
|
||||
chdir($oldCwd);
|
||||
|
@ -288,10 +288,20 @@ EOT
|
|||
$directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts);
|
||||
}
|
||||
|
||||
$io->write('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>');
|
||||
// handler Ctrl+C for unix-like systems
|
||||
if (function_exists('pcntl_signal')) {
|
||||
declare(ticks = 100);
|
||||
pcntl_signal(SIGINT, function() use ($directory) {
|
||||
$fs = new Filesystem();
|
||||
$fs->removeDirectory($directory);
|
||||
exit(130);
|
||||
});
|
||||
}
|
||||
|
||||
$io->writeError('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>');
|
||||
|
||||
if ($disablePlugins) {
|
||||
$io->write('<info>Plugins have been disabled.</info>');
|
||||
$io->writeError('<info>Plugins have been disabled.</info>');
|
||||
}
|
||||
|
||||
if (0 === strpos($package->getPrettyVersion(), 'dev-') && in_array($package->getSourceType(), array('git', 'hg'))) {
|
||||
|
@ -311,10 +321,11 @@ EOT
|
|||
|
||||
$installedFromVcs = 'source' === $package->getInstallationSource();
|
||||
|
||||
$io->write('<info>Created project in ' . $directory . '</info>');
|
||||
$io->writeError('<info>Created project in ' . $directory . '</info>');
|
||||
chdir($directory);
|
||||
|
||||
putenv('COMPOSER_ROOT_VERSION='.$package->getPrettyVersion());
|
||||
$_SERVER['COMPOSER_ROOT_VERSION'] = $package->getPrettyVersion();
|
||||
putenv('COMPOSER_ROOT_VERSION='.$_SERVER['COMPOSER_ROOT_VERSION']);
|
||||
|
||||
return $installedFromVcs;
|
||||
}
|
||||
|
@ -338,15 +349,16 @@ EOT
|
|||
* @param boolean $preferSource
|
||||
* @param boolean $preferDist
|
||||
*/
|
||||
protected function updatePreferredOptions(Config $config, InputInterface $input, &$preferSource, &$preferDist)
|
||||
protected function updatePreferredOptions(Config $config, InputInterface $input, &$preferSource, &$preferDist, $keepVcsRequiresPreferSource = false)
|
||||
{
|
||||
$preferSource = false;
|
||||
$preferDist = false;
|
||||
|
||||
switch ($config->get('preferred-install')) {
|
||||
case 'source':
|
||||
$preferSource = true;
|
||||
$preferDist = false;
|
||||
break;
|
||||
case 'dist':
|
||||
$preferSource = false;
|
||||
$preferDist = true;
|
||||
break;
|
||||
case 'auto':
|
||||
|
@ -355,8 +367,8 @@ EOT
|
|||
break;
|
||||
}
|
||||
|
||||
if ($input->getOption('prefer-source') || $input->getOption('prefer-dist')) {
|
||||
$preferSource = $input->getOption('prefer-source');
|
||||
if ($input->getOption('prefer-source') || $input->getOption('prefer-dist') || ($keepVcsRequiresPreferSource && $input->getOption('keep-vcs'))) {
|
||||
$preferSource = $input->getOption('prefer-source') || ($keepVcsRequiresPreferSource && $input->getOption('keep-vcs'));
|
||||
$preferDist = $input->getOption('prefer-dist');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,9 +96,9 @@ EOT
|
|||
|
||||
if ($messages) {
|
||||
sort($messages);
|
||||
$output->writeln($messages);
|
||||
$this->getIO()->write($messages);
|
||||
} else {
|
||||
$output->writeln('<info>There is no installed package depending on "'.$needle.'".</info>');
|
||||
$this->getIO()->writeError('<info>There is no installed package depending on "'.$needle.'".</info>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,13 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
*/
|
||||
class DiagnoseCommand extends Command
|
||||
{
|
||||
/** @var RemoteFileSystem */
|
||||
protected $rfs;
|
||||
|
||||
/** @var ProcessExecutor */
|
||||
protected $process;
|
||||
|
||||
/** @var int */
|
||||
protected $failures = 0;
|
||||
|
||||
protected function configure()
|
||||
|
@ -46,15 +51,19 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
|
||||
if ($composer) {
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
$output->write('Checking composer.json: ');
|
||||
$this->outputResult($output, $this->checkComposerSchema());
|
||||
$this->getIO()->write('Checking composer.json: ', false);
|
||||
$this->outputResult($this->checkComposerSchema());
|
||||
}
|
||||
|
||||
if ($composer) {
|
||||
|
@ -66,37 +75,64 @@ EOT
|
|||
$this->rfs = new RemoteFilesystem($this->getIO(), $config);
|
||||
$this->process = new ProcessExecutor($this->getIO());
|
||||
|
||||
$output->write('Checking platform settings: ');
|
||||
$this->outputResult($output, $this->checkPlatform());
|
||||
$this->getIO()->write('Checking platform settings: ', false);
|
||||
$this->outputResult($this->checkPlatform());
|
||||
|
||||
$output->write('Checking git settings: ');
|
||||
$this->outputResult($output, $this->checkGit());
|
||||
$this->getIO()->write('Checking git settings: ', false);
|
||||
$this->outputResult($this->checkGit());
|
||||
|
||||
$output->write('Checking http connectivity: ');
|
||||
$this->outputResult($output, $this->checkHttp());
|
||||
$this->getIO()->write('Checking http connectivity to packagist: ', false);
|
||||
$this->outputResult($this->checkHttp('http'));
|
||||
|
||||
$this->getIO()->write('Checking https connectivity to packagist: ', false);
|
||||
$this->outputResult($this->checkHttp('https'));
|
||||
|
||||
$opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org'));
|
||||
if (!empty($opts['http']['proxy'])) {
|
||||
$output->write('Checking HTTP proxy: ');
|
||||
$this->outputResult($output, $this->checkHttpProxy());
|
||||
$output->write('Checking HTTP proxy support for request_fulluri: ');
|
||||
$this->outputResult($output, $this->checkHttpProxyFullUriRequestParam());
|
||||
$output->write('Checking HTTPS proxy support for request_fulluri: ');
|
||||
$this->outputResult($output, $this->checkHttpsProxyFullUriRequestParam());
|
||||
$this->getIO()->write('Checking HTTP proxy: ', false);
|
||||
$this->outputResult($this->checkHttpProxy());
|
||||
$this->getIO()->write('Checking HTTP proxy support for request_fulluri: ', false);
|
||||
$this->outputResult($this->checkHttpProxyFullUriRequestParam());
|
||||
$this->getIO()->write('Checking HTTPS proxy support for request_fulluri: ', false);
|
||||
$this->outputResult($this->checkHttpsProxyFullUriRequestParam());
|
||||
}
|
||||
|
||||
if ($oauth = $config->get('github-oauth')) {
|
||||
foreach ($oauth as $domain => $token) {
|
||||
$output->write('Checking '.$domain.' oauth access: ');
|
||||
$this->outputResult($output, $this->checkGithubOauth($domain, $token));
|
||||
$this->getIO()->write('Checking '.$domain.' oauth access: ', false);
|
||||
$this->outputResult($this->checkGithubOauth($domain, $token));
|
||||
}
|
||||
} else {
|
||||
$this->getIO()->write('Checking github.com rate limit: ', false);
|
||||
try {
|
||||
$rate = $this->getGithubRateLimit('github.com');
|
||||
$this->outputResult(true);
|
||||
if (10 > $rate['remaining']) {
|
||||
$this->getIO()->write('<warning>WARNING</warning>');
|
||||
$this->getIO()->write(sprintf(
|
||||
'<comment>Github has a rate limit on their API. '
|
||||
. 'You currently have <options=bold>%u</options=bold> '
|
||||
. 'out of <options=bold>%u</options=bold> requests left.' . PHP_EOL
|
||||
. 'See https://developer.github.com/v3/#rate-limiting and also' . PHP_EOL
|
||||
. ' https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens</comment>',
|
||||
$rate['remaining'],
|
||||
$rate['limit']
|
||||
));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof TransportException && $e->getCode() === 401) {
|
||||
$this->outputResult('<comment>The oauth token for github.com seems invalid, run "composer config --global --unset github-oauth.github.com" to remove it</comment>');
|
||||
} else {
|
||||
$this->outputResult($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output->write('Checking disk free space: ');
|
||||
$this->outputResult($output, $this->checkDiskSpace($config));
|
||||
$this->getIO()->write('Checking disk free space: ', false);
|
||||
$this->outputResult($this->checkDiskSpace($config));
|
||||
|
||||
$output->write('Checking composer version: ');
|
||||
$this->outputResult($output, $this->checkVersion());
|
||||
$this->getIO()->write('Checking composer version: ', false);
|
||||
$this->outputResult($this->checkVersion());
|
||||
|
||||
return $this->failures;
|
||||
}
|
||||
|
@ -129,17 +165,16 @@ EOT
|
|||
{
|
||||
$this->process->execute('git config color.ui', $output);
|
||||
if (strtolower(trim($output)) === 'always') {
|
||||
return '<warning>Your git color.ui setting is set to always, this is known to create issues. Use "git config --global color.ui true" to set it correctly.</warning>';
|
||||
return '<comment>Your git color.ui setting is set to always, this is known to create issues. Use "git config --global color.ui true" to set it correctly.</comment>';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkHttp()
|
||||
private function checkHttp($proto)
|
||||
{
|
||||
$protocol = extension_loaded('openssl') ? 'https' : 'http';
|
||||
try {
|
||||
$json = $this->rfs->getContents('packagist.org', $protocol . '://packagist.org/packages.json', false);
|
||||
$this->rfs->getContents('packagist.org', $proto . '://packagist.org/packages.json', false);
|
||||
} catch (\Exception $e) {
|
||||
return $e;
|
||||
}
|
||||
|
@ -207,7 +242,7 @@ EOT
|
|||
|
||||
$url = 'https://api.github.com/repos/Seldaek/jsonlint/zipball/1.0.0';
|
||||
try {
|
||||
$rfcResult = $this->rfs->getContents('github.com', $url, false);
|
||||
$this->rfs->getContents('github.com', $url, false);
|
||||
} catch (TransportException $e) {
|
||||
try {
|
||||
$this->rfs->getContents('github.com', $url, false, array('http' => array('request_fulluri' => false)));
|
||||
|
@ -227,16 +262,37 @@ EOT
|
|||
try {
|
||||
$url = $domain === 'github.com' ? 'https://api.'.$domain.'/user/repos' : 'https://'.$domain.'/api/v3/user/repos';
|
||||
|
||||
return $this->rfs->getContents($domain, $url, false) ? true : 'Unexpected error';
|
||||
return $this->rfs->getContents($domain, $url, false, array(
|
||||
'retry-auth-failure' => false
|
||||
)) ? true : 'Unexpected error';
|
||||
} catch (\Exception $e) {
|
||||
if ($e instanceof TransportException && $e->getCode() === 401) {
|
||||
return '<warning>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</warning>';
|
||||
return '<comment>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</comment>';
|
||||
}
|
||||
|
||||
return $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $domain
|
||||
* @param string $token
|
||||
* @return array
|
||||
* @throws TransportException
|
||||
*/
|
||||
private function getGithubRateLimit($domain, $token = null)
|
||||
{
|
||||
if ($token) {
|
||||
$this->getIO()->setAuthentication($domain, $token, 'x-oauth-basic');
|
||||
}
|
||||
|
||||
$url = $domain === 'github.com' ? 'https://api.'.$domain.'/rate_limit' : 'https://'.$domain.'/api/rate_limit';
|
||||
$json = $this->rfs->getContents($domain, $url, false, array('retry-auth-failure' => false));
|
||||
$data = json_decode($json, true);
|
||||
|
||||
return $data['resources']['core'];
|
||||
}
|
||||
|
||||
private function checkDiskSpace($config)
|
||||
{
|
||||
$minSpaceFree = 1024*1024;
|
||||
|
@ -255,23 +311,26 @@ EOT
|
|||
$latest = trim($this->rfs->getContents('getcomposer.org', $protocol . '://getcomposer.org/version', false));
|
||||
|
||||
if (Composer::VERSION !== $latest && Composer::VERSION !== '@package_version@') {
|
||||
return '<warning>You are not running the latest version</warning>';
|
||||
return '<comment>You are not running the latest version</comment>';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function outputResult(OutputInterface $output, $result)
|
||||
/**
|
||||
* @param bool|string|\Exception $result
|
||||
*/
|
||||
private function outputResult($result)
|
||||
{
|
||||
if (true === $result) {
|
||||
$output->writeln('<info>OK</info>');
|
||||
$this->getIO()->write('<info>OK</info>');
|
||||
} else {
|
||||
$this->failures++;
|
||||
$output->writeln('<error>FAIL</error>');
|
||||
$this->getIO()->write('<error>FAIL</error>');
|
||||
if ($result instanceof \Exception) {
|
||||
$output->writeln('['.get_class($result).'] '.$result->getMessage());
|
||||
$this->getIO()->write('['.get_class($result).'] '.$result->getMessage());
|
||||
} elseif ($result) {
|
||||
$output->writeln($result);
|
||||
$this->getIO()->write(trim($result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +339,7 @@ EOT
|
|||
{
|
||||
$output = '';
|
||||
$out = function ($msg, $style) use (&$output) {
|
||||
$output .= '<'.$style.'>'.$msg.'</'.$style.'>';
|
||||
$output .= '<'.$style.'>'.$msg.'</'.$style.'>'.PHP_EOL;
|
||||
};
|
||||
|
||||
// code below taken from getcomposer.org/installer, any changes should be made there and replicated here
|
||||
|
@ -296,32 +355,46 @@ EOT
|
|||
}
|
||||
$iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.';
|
||||
|
||||
if (!function_exists('json_decode')) {
|
||||
$errors['json'] = true;
|
||||
}
|
||||
|
||||
if (!extension_loaded('Phar')) {
|
||||
$errors['phar'] = true;
|
||||
}
|
||||
|
||||
if (!extension_loaded('filter')) {
|
||||
$errors['filter'] = true;
|
||||
}
|
||||
|
||||
if (!extension_loaded('hash')) {
|
||||
$errors['hash'] = true;
|
||||
}
|
||||
|
||||
if (!ini_get('allow_url_fopen')) {
|
||||
$errors['allow_url_fopen'] = true;
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.2', '<')) {
|
||||
if (extension_loaded('ionCube Loader') && ioncube_loader_iversion() < 40009) {
|
||||
$errors['ioncube'] = ioncube_loader_version();
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID < 50302) {
|
||||
$errors['php'] = PHP_VERSION;
|
||||
}
|
||||
|
||||
if (!isset($errors['php']) && version_compare(PHP_VERSION, '5.3.4', '<')) {
|
||||
if (!isset($errors['php']) && PHP_VERSION_ID < 50304) {
|
||||
$warnings['php'] = PHP_VERSION;
|
||||
}
|
||||
|
||||
if (!extension_loaded('openssl')) {
|
||||
$warnings['openssl'] = true;
|
||||
$errors['openssl'] = true;
|
||||
}
|
||||
|
||||
if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) {
|
||||
$warnings['apc_cli'] = true;
|
||||
}
|
||||
|
||||
if (ini_get('xdebug.profiler_enabled')) {
|
||||
$warnings['xdebug_profile'] = true;
|
||||
} elseif (extension_loaded('xdebug')) {
|
||||
$warnings['xdebug_loaded'] = true;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
phpinfo(INFO_GENERAL);
|
||||
$phpinfo = ob_get_clean();
|
||||
|
@ -337,9 +410,49 @@ EOT
|
|||
}
|
||||
}
|
||||
|
||||
if (ini_get('xdebug.profiler_enabled')) {
|
||||
$warnings['xdebug_profile'] = true;
|
||||
} elseif (extension_loaded('xdebug')) {
|
||||
$warnings['xdebug_loaded'] = true;
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $error => $current) {
|
||||
switch ($error) {
|
||||
case 'json':
|
||||
$text = PHP_EOL."The json extension is missing.".PHP_EOL;
|
||||
$text .= "Install it or recompile php without --disable-json";
|
||||
break;
|
||||
|
||||
case 'phar':
|
||||
$text = PHP_EOL."The phar extension is missing.".PHP_EOL;
|
||||
$text .= "Install it or recompile php without --disable-phar";
|
||||
break;
|
||||
|
||||
case 'filter':
|
||||
$text = PHP_EOL."The filter extension is missing.".PHP_EOL;
|
||||
$text .= "Install it or recompile php without --disable-filter";
|
||||
break;
|
||||
|
||||
case 'hash':
|
||||
$text = PHP_EOL."The hash extension is missing.".PHP_EOL;
|
||||
$text .= "Install it or recompile php without --disable-hash";
|
||||
break;
|
||||
|
||||
case 'unicode':
|
||||
$text = PHP_EOL."The detect_unicode setting must be disabled.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
|
||||
$text .= " detect_unicode = Off";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'suhosin':
|
||||
$text = PHP_EOL."The suhosin.executor.include.whitelist setting is incorrect.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):".PHP_EOL;
|
||||
$text .= " suhosin.executor.include.whitelist = phar ".$current;
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'php':
|
||||
$text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher.";
|
||||
break;
|
||||
|
@ -350,6 +463,18 @@ EOT
|
|||
$text .= " allow_url_fopen = On";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'ioncube':
|
||||
$text = PHP_EOL."Your ionCube Loader extension ($current) is incompatible with Phar files.".PHP_EOL;
|
||||
$text .= "Upgrade to ionCube 4.0.9 or higher or remove this line (path may be different) from your `php.ini` to disable it:".PHP_EOL;
|
||||
$text .= " zend_extension = /usr/lib/php5/20090626+lfs/ioncube_loader_lin_5.3.so";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'openssl':
|
||||
$text = PHP_EOL."The openssl extension is missing, which means that secure HTTPS transfers are impossible.".PHP_EOL;
|
||||
$text .= "If possible you should enable it or recompile php with --with-openssl";
|
||||
break;
|
||||
}
|
||||
$out($text, 'error');
|
||||
}
|
||||
|
@ -361,51 +486,46 @@ EOT
|
|||
foreach ($warnings as $warning => $current) {
|
||||
switch ($warning) {
|
||||
case 'apc_cli':
|
||||
$text = PHP_EOL."The apc.enable_cli setting is incorrect.".PHP_EOL;
|
||||
$text = "The apc.enable_cli setting is incorrect.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
|
||||
$text .= " apc.enable_cli = Off";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
|
||||
case 'sigchild':
|
||||
$text = PHP_EOL."PHP was compiled with --enable-sigchild which can cause issues on some platforms.".PHP_EOL;
|
||||
$text = "PHP was compiled with --enable-sigchild which can cause issues on some platforms.".PHP_EOL;
|
||||
$text .= "Recompile it without this flag if possible, see also:".PHP_EOL;
|
||||
$text .= " https://bugs.php.net/bug.php?id=22999";
|
||||
break;
|
||||
|
||||
case 'curlwrappers':
|
||||
$text = PHP_EOL."PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.".PHP_EOL;
|
||||
$text = "PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.".PHP_EOL;
|
||||
$text .= " Recompile it without this flag if possible";
|
||||
break;
|
||||
|
||||
case 'openssl':
|
||||
$text = PHP_EOL."The openssl extension is missing, which will reduce the security and stability of Composer.".PHP_EOL;
|
||||
$text .= "If possible you should enable it or recompile php with --with-openssl";
|
||||
break;
|
||||
|
||||
case 'php':
|
||||
$text = PHP_EOL."Your PHP ({$current}) is quite old, upgrading to PHP 5.3.4 or higher is recommended.".PHP_EOL;
|
||||
$text = "Your PHP ({$current}) is quite old, upgrading to PHP 5.3.4 or higher is recommended.".PHP_EOL;
|
||||
$text .= " Composer works with 5.3.2+ for most people, but there might be edge case issues.";
|
||||
break;
|
||||
|
||||
case 'xdebug_loaded':
|
||||
$text = PHP_EOL."The xdebug extension is loaded, this can slow down Composer a little.".PHP_EOL;
|
||||
$text .= "Disabling it when using Composer is recommended, but should not cause issues beyond slowness.";
|
||||
$text = "The xdebug extension is loaded, this can slow down Composer a little.".PHP_EOL;
|
||||
$text .= " Disabling it when using Composer is recommended.";
|
||||
break;
|
||||
|
||||
case 'xdebug_profile':
|
||||
$text = PHP_EOL."The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.".PHP_EOL;
|
||||
$text = "The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.".PHP_EOL;
|
||||
$text .= "Add the following to the end of your `php.ini` to disable it:".PHP_EOL;
|
||||
$text .= " xdebug.profiler_enabled = 0";
|
||||
$displayIniMessage = true;
|
||||
break;
|
||||
}
|
||||
$out($text, 'warning');
|
||||
$out($text, 'comment');
|
||||
}
|
||||
}
|
||||
|
||||
if ($displayIniMessage) {
|
||||
$out($iniMessage, 'warning');
|
||||
$out($iniMessage, 'comment');
|
||||
}
|
||||
|
||||
return !$warnings && !$errors ? true : $output;
|
||||
|
|
|
@ -55,9 +55,9 @@ EOT
|
|||
$optimize = $input->getOption('optimize') || $config->get('optimize-autoloader') || $config->get('classmap-authoritative');
|
||||
|
||||
if ($optimize) {
|
||||
$output->writeln('<info>Generating optimized autoload files</info>');
|
||||
$this->getIO()->writeError('<info>Generating optimized autoload files</info>');
|
||||
} else {
|
||||
$output->writeln('<info>Generating autoload files</info>');
|
||||
$this->getIO()->writeError('<info>Generating autoload files</info>');
|
||||
}
|
||||
|
||||
$generator = $composer->getAutoloadGenerator();
|
||||
|
|
|
@ -72,7 +72,7 @@ EOT
|
|||
// change to global dir
|
||||
$config = Factory::createConfig();
|
||||
chdir($config->get('home'));
|
||||
$output->writeln('<info>Changed current directory to '.$config->get('home').'</info>');
|
||||
$this->getIO()->writeError('<info>Changed current directory to '.$config->get('home').'</info>');
|
||||
|
||||
// create new input without "global" command prefix
|
||||
$input = new StringInput(preg_replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1));
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace Composer\Command\Helper;
|
||||
|
||||
use Symfony\Component\Console\Helper\DialogHelper as BaseDialogHelper;
|
||||
|
||||
class DialogHelper extends BaseDialogHelper
|
||||
{
|
||||
/**
|
||||
* Build text for asking a question. For example:
|
||||
*
|
||||
* "Do you want to continue [yes]:"
|
||||
*
|
||||
* @param string $question The question you want to ask
|
||||
* @param mixed $default Default value to add to message, if false no default will be shown
|
||||
* @param string $sep Separation char for between message and user input
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQuestion($question, $default = null, $sep = ':')
|
||||
{
|
||||
return $default !== null ?
|
||||
sprintf('<info>%s</info> [<comment>%s</comment>]%s ', $question, $default, $sep) :
|
||||
sprintf('<info>%s</info>%s ', $question, $sep);
|
||||
}
|
||||
}
|
|
@ -12,11 +12,11 @@
|
|||
|
||||
namespace Composer\Command;
|
||||
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\Factory;
|
||||
use Composer\Package\CompletePackageInterface;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\ArrayRepository;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
@ -57,65 +57,55 @@ EOT
|
|||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$repo = $this->initializeRepo();
|
||||
$repos = $this->initializeRepos();
|
||||
$return = 0;
|
||||
|
||||
foreach ($input->getArgument('packages') as $packageName) {
|
||||
$package = $this->getPackage($repo, $packageName);
|
||||
$handled = false;
|
||||
$packageExists = false;
|
||||
foreach ($repos as $repo) {
|
||||
foreach ($repo->findPackages($packageName) as $package) {
|
||||
$packageExists = true;
|
||||
if ($this->handlePackage($package, $input->getOption('homepage'), $input->getOption('show'))) {
|
||||
$handled = true;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$package instanceof CompletePackageInterface) {
|
||||
if (!$packageExists) {
|
||||
$return = 1;
|
||||
$output->writeln('<warning>Package '.$packageName.' not found</warning>');
|
||||
|
||||
continue;
|
||||
$this->getIO()->writeError('<warning>Package '.$packageName.' not found</warning>');
|
||||
}
|
||||
|
||||
$support = $package->getSupport();
|
||||
$url = isset($support['source']) ? $support['source'] : $package->getSourceUrl();
|
||||
if (!$url || $input->getOption('homepage')) {
|
||||
$url = $package->getHomepage();
|
||||
}
|
||||
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
if (!$handled) {
|
||||
$return = 1;
|
||||
$output->writeln('<warning>'.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'</warning>');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($input->getOption('show')) {
|
||||
$output->writeln(sprintf('<info>%s</info>', $url));
|
||||
} else {
|
||||
$this->openBrowser($url);
|
||||
$this->getIO()->writeError('<warning>'.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'</warning>');
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds a package by name
|
||||
*
|
||||
* @param RepositoryInterface $repos
|
||||
* @param string $name
|
||||
* @return CompletePackageInterface
|
||||
*/
|
||||
protected function getPackage(RepositoryInterface $repos, $name)
|
||||
private function handlePackage(CompletePackageInterface $package, $showHomepage, $showOnly)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
$pool = new Pool('dev');
|
||||
$pool->addRepository($repos);
|
||||
$matches = $pool->whatProvides($name);
|
||||
|
||||
foreach ($matches as $index => $package) {
|
||||
// skip providers/replacers
|
||||
if ($package->getName() !== $name) {
|
||||
unset($matches[$index]);
|
||||
continue;
|
||||
$support = $package->getSupport();
|
||||
$url = isset($support['source']) ? $support['source'] : $package->getSourceUrl();
|
||||
if (!$url || $showHomepage) {
|
||||
$url = $package->getHomepage();
|
||||
}
|
||||
|
||||
return $package;
|
||||
if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($showOnly) {
|
||||
$this->getIO()->write(sprintf('<info>%s</info>', $url));
|
||||
} else {
|
||||
$this->openBrowser($url);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,26 +129,31 @@ EOT
|
|||
} elseif (0 === $osx) {
|
||||
passthru('open ' . $url);
|
||||
} else {
|
||||
$this->getIO()->write('no suitable browser opening command found, open yourself: ' . $url);
|
||||
$this->getIO()->writeError('no suitable browser opening command found, open yourself: ' . $url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the repo
|
||||
* Initializes repositories
|
||||
*
|
||||
* @return CompositeRepository
|
||||
* Returns an array of repos in order they should be checked in
|
||||
*
|
||||
* @return RepositoryInterface[]
|
||||
*/
|
||||
private function initializeRepo()
|
||||
private function initializeRepos()
|
||||
{
|
||||
$composer = $this->getComposer(false);
|
||||
|
||||
if ($composer) {
|
||||
$repo = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
|
||||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$repo = new CompositeRepository($defaultRepos);
|
||||
return array_merge(
|
||||
array(new ArrayRepository(array($composer->getPackage()))), // root package
|
||||
array($composer->getRepositoryManager()->getLocalRepository()), // installed packages
|
||||
$composer->getRepositoryManager()->getRepositories() // remotes
|
||||
);
|
||||
}
|
||||
|
||||
return $repo;
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
|
||||
return $defaultRepos;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,28 +33,18 @@ use Symfony\Component\Process\ExecutableFinder;
|
|||
*/
|
||||
class InitCommand extends Command
|
||||
{
|
||||
/** @var CompositeRepository */
|
||||
protected $repos;
|
||||
|
||||
/** @var array */
|
||||
private $gitConfig;
|
||||
|
||||
/** @var Pool */
|
||||
private $pool;
|
||||
|
||||
public function parseAuthorString($author)
|
||||
{
|
||||
if (preg_match('/^(?P<name>[- \.,\p{L}\'’]+) <(?P<email>.+?)>$/u', $author, $match)) {
|
||||
if ($this->isValidEmail($match['email'])) {
|
||||
return array(
|
||||
'name' => trim($match['name']),
|
||||
'email' => $match['email']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid author string. Must be in the format: '.
|
||||
'John Smith <john@example.com>'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
|
@ -65,6 +55,7 @@ class InitCommand extends Command
|
|||
new InputOption('description', null, InputOption::VALUE_REQUIRED, 'Description of package'),
|
||||
new InputOption('author', null, InputOption::VALUE_REQUIRED, 'Author name of package'),
|
||||
// new InputOption('version', null, InputOption::VALUE_NONE, 'Version of package'),
|
||||
new InputOption('type', null, InputOption::VALUE_OPTIONAL, 'Type of package'),
|
||||
new InputOption('homepage', null, InputOption::VALUE_REQUIRED, 'Homepage of package'),
|
||||
new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
|
||||
new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
|
||||
|
@ -82,11 +73,12 @@ EOT
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
|
||||
$whitelist = array('name', 'description', 'author', 'homepage', 'require', 'require-dev', 'stability', 'license');
|
||||
$whitelist = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license');
|
||||
|
||||
$options = array_filter(array_intersect_key($input->getOptions(), array_flip($whitelist)));
|
||||
|
||||
|
@ -113,17 +105,12 @@ EOT
|
|||
}
|
||||
|
||||
$file = new JsonFile('composer.json');
|
||||
|
||||
$json = $file->encode($options);
|
||||
|
||||
if ($input->isInteractive()) {
|
||||
$output->writeln(array(
|
||||
'',
|
||||
$json,
|
||||
''
|
||||
));
|
||||
if (!$dialog->askConfirmation($output, $dialog->getQuestion('Do you confirm generation', 'yes', '?'), true)) {
|
||||
$output->writeln('<error>Command aborted</error>');
|
||||
$this->getIO()->writeError(array('', $json, ''));
|
||||
if (!$this->getIO()->askConfirmation('Do you confirm generation [<comment>yes</comment>]? ', true)) {
|
||||
$this->getIO()->writeError('<error>Command aborted</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -141,27 +128,30 @@ EOT
|
|||
if (!$this->hasVendorIgnore($ignoreFile)) {
|
||||
$question = 'Would you like the <info>vendor</info> directory added to your <info>.gitignore</info> [<comment>yes</comment>]? ';
|
||||
|
||||
if ($dialog->askConfirmation($output, $question, true)) {
|
||||
if ($this->getIO()->askConfirmation($question, true)) {
|
||||
$this->addVendorIgnore($ignoreFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$git = $this->getGitConfig();
|
||||
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$formatter = $this->getHelperSet()->get('formatter');
|
||||
$output->writeln(array(
|
||||
|
||||
$this->getIO()->writeError(array(
|
||||
'',
|
||||
$formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
|
||||
''
|
||||
));
|
||||
|
||||
// namespace
|
||||
$output->writeln(array(
|
||||
$this->getIO()->writeError(array(
|
||||
'',
|
||||
'This command will guide you through creating your composer.json config.',
|
||||
'',
|
||||
|
@ -191,9 +181,8 @@ EOT
|
|||
}
|
||||
}
|
||||
|
||||
$name = $dialog->askAndValidate(
|
||||
$output,
|
||||
$dialog->getQuestion('Package name (<vendor>/<name>)', $name),
|
||||
$name = $this->getIO()->askAndValidate(
|
||||
'Package name (<vendor>/<name>) [<comment>'.$name.'</comment>]: ',
|
||||
function ($value) use ($name) {
|
||||
if (null === $value) {
|
||||
return $name;
|
||||
|
@ -206,14 +195,15 @@ EOT
|
|||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
},
|
||||
null,
|
||||
$name
|
||||
);
|
||||
$input->setOption('name', $name);
|
||||
|
||||
$description = $input->getOption('description') ?: false;
|
||||
$description = $dialog->ask(
|
||||
$output,
|
||||
$dialog->getQuestion('Description', $description),
|
||||
$description = $this->getIO()->ask(
|
||||
'Description [<comment>'.$description.'</comment>]: ',
|
||||
$description
|
||||
);
|
||||
$input->setOption('description', $description);
|
||||
|
@ -225,22 +215,22 @@ EOT
|
|||
}
|
||||
|
||||
$self = $this;
|
||||
$author = $dialog->askAndValidate(
|
||||
$output,
|
||||
$dialog->getQuestion('Author', $author),
|
||||
$author = $this->getIO()->askAndValidate(
|
||||
'Author [<comment>'.$author.'</comment>]: ',
|
||||
function ($value) use ($self, $author) {
|
||||
$value = $value ?: $author;
|
||||
$author = $self->parseAuthorString($value);
|
||||
|
||||
return sprintf('%s <%s>', $author['name'], $author['email']);
|
||||
}
|
||||
},
|
||||
null,
|
||||
$author
|
||||
);
|
||||
$input->setOption('author', $author);
|
||||
|
||||
$minimumStability = $input->getOption('stability') ?: '';
|
||||
$minimumStability = $dialog->askAndValidate(
|
||||
$output,
|
||||
$dialog->getQuestion('Minimum Stability', $minimumStability),
|
||||
$minimumStability = $input->getOption('stability') ?: null;
|
||||
$minimumStability = $this->getIO()->askAndValidate(
|
||||
'Minimum Stability [<comment>'.$minimumStability.'</comment>]: ',
|
||||
function ($value) use ($self, $minimumStability) {
|
||||
if (null === $value) {
|
||||
return $minimumStability;
|
||||
|
@ -254,36 +244,65 @@ EOT
|
|||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
},
|
||||
null,
|
||||
$minimumStability
|
||||
);
|
||||
$input->setOption('stability', $minimumStability);
|
||||
|
||||
$type = $input->getOption('type') ?: false;
|
||||
$type = $this->getIO()->ask(
|
||||
'Package Type [<comment>'.$type.'</comment>]: ',
|
||||
$type
|
||||
);
|
||||
$input->setOption('type', $type);
|
||||
|
||||
$license = $input->getOption('license') ?: false;
|
||||
$license = $dialog->ask(
|
||||
$output,
|
||||
$dialog->getQuestion('License', $license),
|
||||
$license = $this->getIO()->ask(
|
||||
'License [<comment>'.$license.'</comment>]: ',
|
||||
$license
|
||||
);
|
||||
$input->setOption('license', $license);
|
||||
|
||||
$output->writeln(array(
|
||||
'',
|
||||
'Define your dependencies.',
|
||||
''
|
||||
));
|
||||
$this->getIO()->writeError(array('', 'Define your dependencies.', ''));
|
||||
|
||||
$question = 'Would you like to define your dependencies (require) interactively [<comment>yes</comment>]? ';
|
||||
$requirements = array();
|
||||
if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dependencies (require) interactively', 'yes', '?'), true)) {
|
||||
if ($this->getIO()->askConfirmation($question, true)) {
|
||||
$requirements = $this->determineRequirements($input, $output, $input->getOption('require'));
|
||||
}
|
||||
$input->setOption('require', $requirements);
|
||||
|
||||
$question = 'Would you like to define your dev dependencies (require-dev) interactively [<comment>yes</comment>]? ';
|
||||
$devRequirements = array();
|
||||
if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dev dependencies (require-dev) interactively', 'yes', '?'), true)) {
|
||||
if ($this->getIO()->askConfirmation($question, true)) {
|
||||
$devRequirements = $this->determineRequirements($input, $output, $input->getOption('require-dev'));
|
||||
}
|
||||
$input->setOption('require-dev', $devRequirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param string $author
|
||||
* @return array
|
||||
*/
|
||||
public function parseAuthorString($author)
|
||||
{
|
||||
if (preg_match('/^(?P<name>[- \.,\p{L}\p{N}\'’]+) <(?P<email>.+?)>$/u', $author, $match)) {
|
||||
if ($this->isValidEmail($match['email'])) {
|
||||
return array(
|
||||
'name' => trim($match['name']),
|
||||
'email' => $match['email']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid author string. Must be in the format: '.
|
||||
'John Smith <john@example.com>'
|
||||
);
|
||||
}
|
||||
|
||||
protected function findPackages($name)
|
||||
{
|
||||
return $this->getRepos()->search($name);
|
||||
|
@ -303,9 +322,6 @@ EOT
|
|||
|
||||
protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array())
|
||||
{
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$prompt = $dialog->getQuestion('Search for a package', false, ':');
|
||||
|
||||
if ($requires) {
|
||||
$requires = $this->normalizeRequirements($requires);
|
||||
$result = array();
|
||||
|
@ -316,7 +332,7 @@ EOT
|
|||
$version = $this->findBestVersionForPackage($input, $requirement['name']);
|
||||
$requirement['version'] = $version;
|
||||
|
||||
$output->writeln(sprintf(
|
||||
$this->getIO()->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
$requirement['version'],
|
||||
$requirement['name']
|
||||
|
@ -329,7 +345,8 @@ EOT
|
|||
return $result;
|
||||
}
|
||||
|
||||
while (null !== $package = $dialog->ask($output, $prompt)) {
|
||||
$versionParser = new VersionParser();
|
||||
while (null !== $package = $this->getIO()->ask('Search for a package: ')) {
|
||||
$matches = $this->findPackages($package);
|
||||
|
||||
if (count($matches)) {
|
||||
|
@ -345,34 +362,49 @@ EOT
|
|||
|
||||
// no match, prompt which to pick
|
||||
if (!$exactMatch) {
|
||||
$output->writeln(array(
|
||||
$this->getIO()->writeError(array(
|
||||
'',
|
||||
sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
|
||||
''
|
||||
));
|
||||
|
||||
$output->writeln($choices);
|
||||
$output->writeln('');
|
||||
$this->getIO()->writeError($choices);
|
||||
$this->getIO()->writeError('');
|
||||
|
||||
$validator = function ($selection) use ($matches) {
|
||||
$validator = function ($selection) use ($matches, $versionParser) {
|
||||
if ('' === $selection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_numeric($selection) && preg_match('{^\s*(\S+)\s+(\S.*)\s*$}', $selection, $matches)) {
|
||||
return $matches[1].' '.$matches[2];
|
||||
}
|
||||
|
||||
if (!isset($matches[(int) $selection])) {
|
||||
throw new \Exception('Not a valid selection');
|
||||
}
|
||||
|
||||
if (is_numeric($selection) && isset($matches[(int) $selection])) {
|
||||
$package = $matches[(int) $selection];
|
||||
|
||||
return $package['name'];
|
||||
}
|
||||
|
||||
if (preg_match('{^\s*(?P<name>[\S/]+)(?:\s+(?P<version>\S+))?\s*$}', $selection, $packageMatches)) {
|
||||
if (isset($packageMatches['version'])) {
|
||||
// parsing `acme/example ~2.3`
|
||||
|
||||
// validate version constraint
|
||||
$versionParser->parseConstraints($packageMatches['version']);
|
||||
|
||||
return $packageMatches['name'].' '.$packageMatches['version'];
|
||||
}
|
||||
|
||||
// parsing `acme/example`
|
||||
return $packageMatches['name'];
|
||||
}
|
||||
|
||||
throw new \Exception('Not a valid selection');
|
||||
};
|
||||
|
||||
$package = $dialog->askAndValidate($output, $dialog->getQuestion('Enter package # to add, or the complete package name if it is not listed', false, ':'), $validator, 3);
|
||||
$package = $this->getIO()->askAndValidate(
|
||||
'Enter package # to add, or the complete package name if it is not listed: ',
|
||||
$validator,
|
||||
3,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// no constraint yet, determine the best version automatically
|
||||
|
@ -383,16 +415,17 @@ EOT
|
|||
return $input ?: false;
|
||||
};
|
||||
|
||||
$constraint = $dialog->askAndValidate(
|
||||
$output,
|
||||
$dialog->getQuestion('Enter the version constraint to require (or leave blank to use the latest version)', false, ':'),
|
||||
$constraint = $this->getIO()->askAndValidate(
|
||||
'Enter the version constraint to require (or leave blank to use the latest version): ',
|
||||
$validator,
|
||||
3)
|
||||
;
|
||||
3,
|
||||
false
|
||||
);
|
||||
|
||||
if (false === $constraint) {
|
||||
$constraint = $this->findBestVersionForPackage($input, $package);
|
||||
|
||||
$output->writeln(sprintf(
|
||||
$this->getIO()->writeError(sprintf(
|
||||
'Using version <info>%s</info> for <info>%s</info>',
|
||||
$constraint,
|
||||
$package
|
||||
|
@ -515,7 +548,7 @@ EOT
|
|||
}
|
||||
|
||||
// php <5.3.3 has a very broken email validator, so bypass checks
|
||||
if (version_compare(PHP_VERSION, '5.3.3', '<')) {
|
||||
if (PHP_VERSION_ID < 50303) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,18 +65,18 @@ EOT
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($args = $input->getArgument('packages')) {
|
||||
$output->writeln('<error>Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.</error>');
|
||||
$this->getIO()->writeError('<error>Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$this->getIO()->writeError('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$input->setOption('no-plugins', true);
|
||||
}
|
||||
|
||||
if ($input->getOption('dev')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
|
||||
$this->getIO()->writeError('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
|
|
|
@ -18,7 +18,7 @@ use Composer\Plugin\CommandEvent;
|
|||
use Composer\Plugin\PluginEvents;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Symfony\Component\Console\Helper\TableHelper;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
@ -68,14 +68,17 @@ EOT
|
|||
|
||||
switch ($format = $input->getOption('format')) {
|
||||
case 'text':
|
||||
$output->writeln('Name: <comment>'.$root->getPrettyName().'</comment>');
|
||||
$output->writeln('Version: <comment>'.$versionParser->formatVersion($root).'</comment>');
|
||||
$output->writeln('Licenses: <comment>'.(implode(', ', $root->getLicense()) ?: 'none').'</comment>');
|
||||
$output->writeln('Dependencies:');
|
||||
$this->getIO()->write('Name: <comment>'.$root->getPrettyName().'</comment>');
|
||||
$this->getIO()->write('Version: <comment>'.$versionParser->formatVersion($root).'</comment>');
|
||||
$this->getIO()->write('Licenses: <comment>'.(implode(', ', $root->getLicense()) ?: 'none').'</comment>');
|
||||
$this->getIO()->write('Dependencies:');
|
||||
$this->getIO()->write('');
|
||||
|
||||
$table = $this->getHelperSet()->get('table');
|
||||
$table->setLayout(TableHelper::LAYOUT_BORDERLESS);
|
||||
$table->setHorizontalBorderChar('');
|
||||
$table = new Table($output);
|
||||
$table->setStyle('compact');
|
||||
$table->getStyle()->setVerticalBorderChar('');
|
||||
$table->getStyle()->setCellRowContentFormat('%s ');
|
||||
$table->setHeaders(array('Name', 'Version', 'License'));
|
||||
foreach ($packages as $package) {
|
||||
$table->addRow(array(
|
||||
$package->getPrettyName(),
|
||||
|
@ -83,7 +86,7 @@ EOT
|
|||
implode(', ', $package->getLicense()) ?: 'none',
|
||||
));
|
||||
}
|
||||
$table->render($output);
|
||||
$table->render();
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
|
@ -94,7 +97,7 @@ EOT
|
|||
);
|
||||
}
|
||||
|
||||
$output->writeln(JsonFile::encode(array(
|
||||
$this->getIO()->write(JsonFile::encode(array(
|
||||
'name' => $root->getPrettyName(),
|
||||
'version' => $versionParser->formatVersion($root),
|
||||
'license' => $root->getLicense(),
|
||||
|
|
|
@ -73,15 +73,14 @@ EOT
|
|||
if (isset($composer[$type][$package])) {
|
||||
$json->removeLink($type, $package);
|
||||
} elseif (isset($composer[$altType][$package])) {
|
||||
$output->writeln('<warning>'.$package.' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$this->getIO()->writeError('<warning>'.$package.' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
|
||||
if ($this->getIO()->isInteractive()) {
|
||||
if ($dialog->askConfirmation($output, $dialog->getQuestion('Do you want to remove it from '.$altType, 'yes', '?'), true)) {
|
||||
if ($this->getIO()->askConfirmation('Do you want to remove it from '.$altType.' [<comment>yes</comment>]? ', true)) {
|
||||
$json->removeLink($altType, $package);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
|
||||
$this->getIO()->writeError('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +110,7 @@ EOT
|
|||
|
||||
$status = $install->run();
|
||||
if ($status !== 0) {
|
||||
$output->writeln("\n".'<error>Removal failed, reverting '.$file.' to its original content.</error>');
|
||||
$this->getIO()->writeError("\n".'<error>Removal failed, reverting '.$file.' to its original content.</error>');
|
||||
file_put_contents($jsonFile->getPath(), $composerBackup);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,21 +67,25 @@ EOT
|
|||
|
||||
$newlyCreated = !file_exists($file);
|
||||
if (!file_exists($file) && !file_put_contents($file, "{\n}\n")) {
|
||||
$output->writeln('<error>'.$file.' could not be created.</error>');
|
||||
$this->getIO()->writeError('<error>'.$file.' could not be created.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!is_readable($file)) {
|
||||
$output->writeln('<error>'.$file.' is not readable.</error>');
|
||||
$this->getIO()->writeError('<error>'.$file.' is not readable.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!is_writable($file)) {
|
||||
$output->writeln('<error>'.$file.' is not writable.</error>');
|
||||
$this->getIO()->writeError('<error>'.$file.' is not writable.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (filesize($file) === 0) {
|
||||
file_put_contents($file, "{\n}\n");
|
||||
}
|
||||
|
||||
$json = new JsonFile($file);
|
||||
$composerDefinition = $json->read();
|
||||
$composerBackup = file_get_contents($json->getPath());
|
||||
|
@ -122,7 +126,7 @@ EOT
|
|||
$json->write($composerDefinition);
|
||||
}
|
||||
|
||||
$output->writeln('<info>'.$file.' has been '.($newlyCreated ? 'created' : 'updated').'</info>');
|
||||
$this->getIO()->writeError('<info>'.$file.' has been '.($newlyCreated ? 'created' : 'updated').'</info>');
|
||||
|
||||
if ($input->getOption('no-update')) {
|
||||
return 0;
|
||||
|
@ -154,10 +158,10 @@ EOT
|
|||
$status = $install->run();
|
||||
if ($status !== 0) {
|
||||
if ($newlyCreated) {
|
||||
$output->writeln("\n".'<error>Installation failed, deleting '.$file.'.</error>');
|
||||
$this->getIO()->writeError("\n".'<error>Installation failed, deleting '.$file.'.</error>');
|
||||
unlink($json->getPath());
|
||||
} else {
|
||||
$output->writeln("\n".'<error>Installation failed, reverting '.$file.' to its original content.</error>');
|
||||
$this->getIO()->writeError("\n".'<error>Installation failed, reverting '.$file.' to its original content.</error>');
|
||||
file_put_contents($json->getPath(), $composerBackup);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class RunScriptCommand extends Command
|
|||
/**
|
||||
* @var array Array with command events
|
||||
*/
|
||||
protected $commandEvents = array(
|
||||
protected $scriptEvents = array(
|
||||
ScriptEvents::PRE_INSTALL_CMD,
|
||||
ScriptEvents::POST_INSTALL_CMD,
|
||||
ScriptEvents::PRE_UPDATE_CMD,
|
||||
|
@ -35,17 +35,11 @@ class RunScriptCommand extends Command
|
|||
ScriptEvents::PRE_STATUS_CMD,
|
||||
ScriptEvents::POST_STATUS_CMD,
|
||||
ScriptEvents::POST_ROOT_PACKAGE_INSTALL,
|
||||
ScriptEvents::POST_CREATE_PROJECT_CMD
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array Array with script events
|
||||
*/
|
||||
protected $scriptEvents = array(
|
||||
ScriptEvents::POST_CREATE_PROJECT_CMD,
|
||||
ScriptEvents::PRE_ARCHIVE_CMD,
|
||||
ScriptEvents::POST_ARCHIVE_CMD,
|
||||
ScriptEvents::PRE_AUTOLOAD_DUMP,
|
||||
ScriptEvents::POST_AUTOLOAD_DUMP
|
||||
ScriptEvents::POST_AUTOLOAD_DUMP,
|
||||
);
|
||||
|
||||
protected function configure()
|
||||
|
@ -54,10 +48,11 @@ class RunScriptCommand extends Command
|
|||
->setName('run-script')
|
||||
->setDescription('Run the scripts defined in composer.json.')
|
||||
->setDefinition(array(
|
||||
new InputArgument('script', InputArgument::REQUIRED, 'Script name to run.'),
|
||||
new InputArgument('script', InputArgument::OPTIONAL, 'Script name to run.'),
|
||||
new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
|
||||
new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
|
||||
new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
|
||||
new InputOption('list', 'l', InputOption::VALUE_NONE, 'List scripts.'),
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
The <info>run-script</info> command runs scripts defined in composer.json:
|
||||
|
@ -70,8 +65,14 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('list')) {
|
||||
return $this->listScripts();
|
||||
} elseif (!$input->getArgument('script')) {
|
||||
throw new \RunTimeException('Missing required argument "script"');
|
||||
}
|
||||
|
||||
$script = $input->getArgument('script');
|
||||
if (!in_array($script, $this->commandEvents) && !in_array($script, $this->scriptEvents)) {
|
||||
if (!in_array($script, $this->scriptEvents)) {
|
||||
if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
|
||||
throw new \InvalidArgumentException(sprintf('Script "%s" cannot be run with this command', $script));
|
||||
}
|
||||
|
@ -86,15 +87,28 @@ EOT
|
|||
// add the bin dir to the PATH to make local binaries of deps usable in scripts
|
||||
$binDir = $composer->getConfig()->get('bin-dir');
|
||||
if (is_dir($binDir)) {
|
||||
putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH'));
|
||||
$_SERVER['PATH'] = realpath($binDir).PATH_SEPARATOR.getenv('PATH');
|
||||
putenv('PATH='.$_SERVER['PATH']);
|
||||
}
|
||||
|
||||
$args = $input->getArgument('args');
|
||||
|
||||
if (in_array($script, $this->commandEvents)) {
|
||||
return $composer->getEventDispatcher()->dispatchCommandEvent($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args);
|
||||
}
|
||||
|
||||
return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args);
|
||||
}
|
||||
|
||||
protected function listScripts()
|
||||
{
|
||||
$scripts = $this->getComposer()->getPackage()->getScripts();
|
||||
|
||||
if (!count($scripts)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->getIO()->writeError('<info>scripts:</info>');
|
||||
foreach ($scripts as $name => $script) {
|
||||
$this->getIO()->write(' ' . $name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ EOT
|
|||
// add the bin dir to the PATH to make local binaries of deps usable in scripts
|
||||
$binDir = $composer->getConfig()->get('bin-dir');
|
||||
if (is_dir($binDir)) {
|
||||
putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH'));
|
||||
$_SERVER['PATH'] = realpath($binDir).PATH_SEPARATOR.getenv('PATH');
|
||||
putenv('PATH='.$_SERVER['PATH']);
|
||||
}
|
||||
|
||||
$args = $input->getArguments();
|
||||
|
|
|
@ -62,7 +62,7 @@ EOT
|
|||
$repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$output->writeln('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$this->getIO()->writeError('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$installedRepo = $platformRepo;
|
||||
$repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ EOT
|
|||
$results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags);
|
||||
|
||||
foreach ($results as $result) {
|
||||
$output->writeln($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
|
||||
$this->getIO()->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,13 +84,13 @@ EOT
|
|||
$updateVersion = $input->getArgument('version') ?: $latestVersion;
|
||||
|
||||
if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) {
|
||||
$output->writeln('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>');
|
||||
$this->getIO()->writeError('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Composer::VERSION === $updateVersion) {
|
||||
$output->writeln('<info>You are already using composer version '.$updateVersion.'.</info>');
|
||||
$this->getIO()->writeError('<info>You are already using composer version '.$updateVersion.'.</info>');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,11 +104,11 @@ EOT
|
|||
self::OLD_INSTALL_EXT
|
||||
);
|
||||
|
||||
$output->writeln(sprintf("Updating to version <info>%s</info>.", $updateVersion));
|
||||
$this->getIO()->writeError(sprintf("Updating to version <info>%s</info>.", $updateVersion));
|
||||
$remoteFilename = $baseUrl . (preg_match('{^[0-9a-f]{40}$}', $updateVersion) ? '/composer.phar' : "/download/{$updateVersion}/composer.phar");
|
||||
$remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename, !$input->getOption('no-progress'));
|
||||
if (!file_exists($tempFilename)) {
|
||||
$output->writeln('<error>The download of the new composer version failed for an unexpected reason</error>');
|
||||
$this->getIO()->writeError('<error>The download of the new composer version failed for an unexpected reason</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -120,22 +120,22 @@ EOT
|
|||
$fs = new Filesystem;
|
||||
foreach ($finder as $file) {
|
||||
$file = (string) $file;
|
||||
$output->writeln('<info>Removing: '.$file.'</info>');
|
||||
$this->getIO()->writeError('<info>Removing: '.$file.'</info>');
|
||||
$fs->remove($file);
|
||||
}
|
||||
}
|
||||
|
||||
if ($err = $this->setLocalPhar($localFilename, $tempFilename, $backupFile)) {
|
||||
$output->writeln('<error>The file is corrupted ('.$err->getMessage().').</error>');
|
||||
$output->writeln('<error>Please re-run the self-update command to try again.</error>');
|
||||
$this->getIO()->writeError('<error>The file is corrupted ('.$err->getMessage().').</error>');
|
||||
$this->getIO()->writeError('<error>Please re-run the self-update command to try again.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (file_exists($backupFile)) {
|
||||
$output->writeln('Use <info>composer self-update --rollback</info> to return to version '.Composer::VERSION);
|
||||
$this->getIO()->writeError('Use <info>composer self-update --rollback</info> to return to version '.Composer::VERSION);
|
||||
} else {
|
||||
$output->writeln('<warning>A backup of the current version could not be written to '.$backupFile.', no rollback possible</warning>');
|
||||
$this->getIO()->writeError('<warning>A backup of the current version could not be written to '.$backupFile.', no rollback possible</warning>');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,9 +160,9 @@ EOT
|
|||
}
|
||||
|
||||
$oldFile = $rollbackDir . "/{$rollbackVersion}" . self::OLD_INSTALL_EXT;
|
||||
$output->writeln(sprintf("Rolling back to version <info>%s</info>.", $rollbackVersion));
|
||||
$this->getIO()->writeError(sprintf("Rolling back to version <info>%s</info>.", $rollbackVersion));
|
||||
if ($err = $this->setLocalPhar($localFilename, $oldFile)) {
|
||||
$output->writeln('<error>The backup file was corrupted ('.$err->getMessage().') and has been removed.</error>');
|
||||
$this->getIO()->writeError('<error>The backup file was corrupted ('.$err->getMessage().') and has been removed.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ use Composer\Repository\CompositeRepository;
|
|||
use Composer\Repository\ComposerRepository;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Util\SpdxLicense;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
|
@ -84,7 +85,7 @@ EOT
|
|||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$repos = new CompositeRepository($defaultRepos);
|
||||
$output->writeln('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$this->getIO()->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
}
|
||||
} elseif ($composer) {
|
||||
$localRepo = $composer->getRepositoryManager()->getLocalRepository();
|
||||
|
@ -92,7 +93,7 @@ EOT
|
|||
$repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
|
||||
} else {
|
||||
$defaultRepos = Factory::createDefaultRepositories($this->getIO());
|
||||
$output->writeln('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$this->getIO()->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
|
||||
$installedRepo = $platformRepo;
|
||||
$repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
|
||||
}
|
||||
|
@ -115,18 +116,18 @@ EOT
|
|||
$versions = array($package->getPrettyVersion() => $package->getVersion());
|
||||
}
|
||||
|
||||
$this->printMeta($input, $output, $package, $versions, $installedRepo, $repos);
|
||||
$this->printLinks($input, $output, $package, 'requires');
|
||||
$this->printLinks($input, $output, $package, 'devRequires', 'requires (dev)');
|
||||
$this->printMeta($package, $versions, $installedRepo);
|
||||
$this->printLinks($package, 'requires');
|
||||
$this->printLinks($package, 'devRequires', 'requires (dev)');
|
||||
if ($package->getSuggests()) {
|
||||
$output->writeln("\n<info>suggests</info>");
|
||||
$this->getIO()->write("\n<info>suggests</info>");
|
||||
foreach ($package->getSuggests() as $suggested => $reason) {
|
||||
$output->writeln($suggested . ' <comment>' . $reason . '</comment>');
|
||||
$this->getIO()->write($suggested . ' <comment>' . $reason . '</comment>');
|
||||
}
|
||||
}
|
||||
$this->printLinks($input, $output, $package, 'provides');
|
||||
$this->printLinks($input, $output, $package, 'conflicts');
|
||||
$this->printLinks($input, $output, $package, 'replaces');
|
||||
$this->printLinks($package, 'provides');
|
||||
$this->printLinks($package, 'conflicts');
|
||||
$this->printLinks($package, 'replaces');
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ EOT
|
|||
foreach (array('<info>platform</info>:' => true, '<comment>available</comment>:' => false, '<info>installed</info>:' => true) as $type => $showVersion) {
|
||||
if (isset($packages[$type])) {
|
||||
if ($tree) {
|
||||
$output->writeln($type);
|
||||
$this->getIO()->write($type);
|
||||
}
|
||||
ksort($packages[$type]);
|
||||
|
||||
|
@ -195,6 +196,11 @@ EOT
|
|||
$width--;
|
||||
}
|
||||
|
||||
if ($input->getOption('path') && null === $composer) {
|
||||
$this->getIO()->writeError('No composer.json found in the current directory, disabling "path" option');
|
||||
$input->setOption('path', false);
|
||||
}
|
||||
|
||||
$writePath = !$input->getOption('name-only') && $input->getOption('path');
|
||||
$writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion && ($nameLength + $versionLength + 3 <= $width);
|
||||
$writeDescription = !$input->getOption('name-only') && !$input->getOption('path') && ($nameLength + ($showVersion ? $versionLength : 0) + 24 <= $width);
|
||||
|
@ -222,10 +228,10 @@ EOT
|
|||
} else {
|
||||
$output->write($indent . $package);
|
||||
}
|
||||
$output->writeln('');
|
||||
$this->getIO()->write('');
|
||||
}
|
||||
if ($tree) {
|
||||
$output->writeln('');
|
||||
$this->getIO()->write('');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,9 +278,9 @@ EOT
|
|||
$matches[$index] = $package->getId();
|
||||
}
|
||||
|
||||
// select prefered package according to policy rules
|
||||
if (!$matchedPackage && $matches && $prefered = $policy->selectPreferedPackages($pool, array(), $matches)) {
|
||||
$matchedPackage = $pool->literalToPackage($prefered[0]);
|
||||
// select preferred package according to policy rules
|
||||
if (!$matchedPackage && $matches && $preferred = $policy->selectPreferredPackages($pool, array(), $matches)) {
|
||||
$matchedPackage = $pool->literalToPackage($preferred[0]);
|
||||
}
|
||||
|
||||
return array($matchedPackage, $versions);
|
||||
|
@ -283,55 +289,55 @@ EOT
|
|||
/**
|
||||
* prints package meta data
|
||||
*/
|
||||
protected function printMeta(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos)
|
||||
protected function printMeta(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo)
|
||||
{
|
||||
$output->writeln('<info>name</info> : ' . $package->getPrettyName());
|
||||
$output->writeln('<info>descrip.</info> : ' . $package->getDescription());
|
||||
$output->writeln('<info>keywords</info> : ' . join(', ', $package->getKeywords() ?: array()));
|
||||
$this->printVersions($input, $output, $package, $versions, $installedRepo, $repos);
|
||||
$output->writeln('<info>type</info> : ' . $package->getType());
|
||||
$output->writeln('<info>license</info> : ' . implode(', ', $package->getLicense()));
|
||||
$output->writeln('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
|
||||
$output->writeln('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
|
||||
$output->writeln('<info>names</info> : ' . implode(', ', $package->getNames()));
|
||||
$this->getIO()->write('<info>name</info> : ' . $package->getPrettyName());
|
||||
$this->getIO()->write('<info>descrip.</info> : ' . $package->getDescription());
|
||||
$this->getIO()->write('<info>keywords</info> : ' . join(', ', $package->getKeywords() ?: array()));
|
||||
$this->printVersions($package, $versions, $installedRepo);
|
||||
$this->getIO()->write('<info>type</info> : ' . $package->getType());
|
||||
$this->printLicenses($package);
|
||||
$this->getIO()->write('<info>source</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
|
||||
$this->getIO()->write('<info>dist</info> : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
|
||||
$this->getIO()->write('<info>names</info> : ' . implode(', ', $package->getNames()));
|
||||
|
||||
if ($package->isAbandoned()) {
|
||||
$replacement = ($package->getReplacementPackage() !== null)
|
||||
? ' The author suggests using the ' . $package->getReplacementPackage(). ' package instead.'
|
||||
: null;
|
||||
|
||||
$output->writeln(
|
||||
sprintf('<error>Attention: This package is abandoned and no longer maintained.%s</error>', $replacement)
|
||||
$this->getIO()->writeError(
|
||||
sprintf('<warning>Attention: This package is abandoned and no longer maintained.%s</warning>', $replacement)
|
||||
);
|
||||
}
|
||||
|
||||
if ($package->getSupport()) {
|
||||
$output->writeln("\n<info>support</info>");
|
||||
$this->getIO()->write("\n<info>support</info>");
|
||||
foreach ($package->getSupport() as $type => $value) {
|
||||
$output->writeln('<comment>' . $type . '</comment> : '.$value);
|
||||
$this->getIO()->write('<comment>' . $type . '</comment> : '.$value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($package->getAutoload()) {
|
||||
$output->writeln("\n<info>autoload</info>");
|
||||
$this->getIO()->write("\n<info>autoload</info>");
|
||||
foreach ($package->getAutoload() as $type => $autoloads) {
|
||||
$output->writeln('<comment>' . $type . '</comment>');
|
||||
$this->getIO()->write('<comment>' . $type . '</comment>');
|
||||
|
||||
if ($type === 'psr-0') {
|
||||
foreach ($autoloads as $name => $path) {
|
||||
$output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
|
||||
$this->getIO()->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
|
||||
}
|
||||
} elseif ($type === 'psr-4') {
|
||||
foreach ($autoloads as $name => $path) {
|
||||
$output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
|
||||
$this->getIO()->write(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
|
||||
}
|
||||
} elseif ($type === 'classmap') {
|
||||
$output->writeln(implode(', ', $autoloads));
|
||||
$this->getIO()->write(implode(', ', $autoloads));
|
||||
}
|
||||
}
|
||||
if ($package->getIncludePaths()) {
|
||||
$output->writeln('<comment>include-path</comment>');
|
||||
$output->writeln(implode(', ', $package->getIncludePaths()));
|
||||
$this->getIO()->write('<comment>include-path</comment>');
|
||||
$this->getIO()->write(implode(', ', $package->getIncludePaths()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +345,7 @@ EOT
|
|||
/**
|
||||
* prints all available versions of this package and highlights the installed one if any
|
||||
*/
|
||||
protected function printVersions(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos)
|
||||
protected function printVersions(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo)
|
||||
{
|
||||
uasort($versions, 'version_compare');
|
||||
$versions = array_keys(array_reverse($versions));
|
||||
|
@ -355,27 +361,54 @@ EOT
|
|||
|
||||
$versions = implode(', ', $versions);
|
||||
|
||||
$output->writeln('<info>versions</info> : ' . $versions);
|
||||
$this->getIO()->write('<info>versions</info> : ' . $versions);
|
||||
}
|
||||
|
||||
/**
|
||||
* print link objects
|
||||
*
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @param CompletePackageInterface $package
|
||||
* @param string $linkType
|
||||
* @param string $title
|
||||
*/
|
||||
protected function printLinks(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, $linkType, $title = null)
|
||||
protected function printLinks(CompletePackageInterface $package, $linkType, $title = null)
|
||||
{
|
||||
$title = $title ?: $linkType;
|
||||
if ($links = $package->{'get'.ucfirst($linkType)}()) {
|
||||
$output->writeln("\n<info>" . $title . "</info>");
|
||||
$this->getIO()->write("\n<info>" . $title . "</info>");
|
||||
|
||||
foreach ($links as $link) {
|
||||
$output->writeln($link->getTarget() . ' <comment>' . $link->getPrettyConstraint() . '</comment>');
|
||||
$this->getIO()->write($link->getTarget() . ' <comment>' . $link->getPrettyConstraint() . '</comment>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the licenses of a package with metadata
|
||||
*
|
||||
* @param CompletePackageInterface $package
|
||||
*/
|
||||
protected function printLicenses(CompletePackageInterface $package)
|
||||
{
|
||||
$spdxLicense = new SpdxLicense;
|
||||
|
||||
$licenses = $package->getLicense();
|
||||
|
||||
foreach ($licenses as $licenseId) {
|
||||
$license = $spdxLicense->getLicenseByIdentifier($licenseId); // keys: 0 fullname, 1 osi, 2 url
|
||||
|
||||
if (!$license) {
|
||||
$out = $licenseId;
|
||||
} else {
|
||||
// is license OSI approved?
|
||||
if ($license[1] === true) {
|
||||
$out = sprintf('%s (%s) (OSI approved) %s', $license[0], $licenseId, $license[2]);
|
||||
} else {
|
||||
$out = sprintf('%s (%s) %s', $license[0], $licenseId, $license[2]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getIO()->write('<info>license</info> : ' . $out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ EOT
|
|||
$im = $composer->getInstallationManager();
|
||||
|
||||
// Dispatch pre-status-command
|
||||
$composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::PRE_STATUS_CMD, true);
|
||||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_STATUS_CMD, true);
|
||||
|
||||
$errors = array();
|
||||
|
||||
|
@ -76,9 +76,9 @@ EOT
|
|||
|
||||
// output errors/warnings
|
||||
if (!$errors) {
|
||||
$output->writeln('<info>No local changes</info>');
|
||||
$this->getIO()->writeError('<info>No local changes</info>');
|
||||
} else {
|
||||
$output->writeln('<error>You have changes in the following dependencies:</error>');
|
||||
$this->getIO()->writeError('<error>You have changes in the following dependencies:</error>');
|
||||
}
|
||||
|
||||
foreach ($errors as $path => $changes) {
|
||||
|
@ -86,19 +86,19 @@ EOT
|
|||
$indentedChanges = implode("\n", array_map(function ($line) {
|
||||
return ' ' . ltrim($line);
|
||||
}, explode("\n", $changes)));
|
||||
$output->writeln('<info>'.$path.'</info>:');
|
||||
$output->writeln($indentedChanges);
|
||||
$this->getIO()->write('<info>'.$path.'</info>:');
|
||||
$this->getIO()->write($indentedChanges);
|
||||
} else {
|
||||
$output->writeln($path);
|
||||
$this->getIO()->write($path);
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors && !$input->getOption('verbose')) {
|
||||
$output->writeln('Use --verbose (-v) to see modified files');
|
||||
$this->getIO()->writeError('Use --verbose (-v) to see modified files');
|
||||
}
|
||||
|
||||
// Dispatch post-status-command
|
||||
$composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_STATUS_CMD, true);
|
||||
$composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_STATUS_CMD, true);
|
||||
|
||||
return $errors ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -75,12 +75,12 @@ EOT
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
if ($input->getOption('no-custom-installers')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$this->getIO()->writeError('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
|
||||
$input->setOption('no-plugins', true);
|
||||
}
|
||||
|
||||
if ($input->getOption('dev')) {
|
||||
$output->writeln('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
|
||||
$this->getIO()->writeError('<warning>You are using the deprecated option "dev". Dev packages are installed by default now.</warning>');
|
||||
}
|
||||
|
||||
$composer = $this->getComposer(true, $input->getOption('no-plugins'));
|
||||
|
|
|
@ -37,6 +37,7 @@ class ValidateCommand extends Command
|
|||
->setDescription('Validates a composer.json')
|
||||
->setDefinition(array(
|
||||
new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not make a complete validation'),
|
||||
new InputOption('no-check-publish', null, InputOption::VALUE_NONE, 'Do not check for publish errors'),
|
||||
new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json')
|
||||
))
|
||||
->setHelp(<<<EOT
|
||||
|
@ -57,45 +58,53 @@ EOT
|
|||
$file = $input->getArgument('file');
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$output->writeln('<error>' . $file . ' not found.</error>');
|
||||
$this->getIO()->writeError('<error>' . $file . ' not found.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!is_readable($file)) {
|
||||
$output->writeln('<error>' . $file . ' is not readable.</error>');
|
||||
$this->getIO()->writeError('<error>' . $file . ' is not readable.</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$validator = new ConfigValidator($this->getIO());
|
||||
$checkAll = $input->getOption('no-check-all') ? 0 : ValidatingArrayLoader::CHECK_ALL;
|
||||
$checkPublish = !$input->getOption('no-check-publish');
|
||||
list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
|
||||
|
||||
// output errors/warnings
|
||||
if (!$errors && !$publishErrors && !$warnings) {
|
||||
$output->writeln('<info>' . $file . ' is valid</info>');
|
||||
$this->getIO()->write('<info>' . $file . ' is valid</info>');
|
||||
} elseif (!$errors && !$publishErrors) {
|
||||
$output->writeln('<info>' . $file . ' is valid, but with a few warnings</info>');
|
||||
$output->writeln('<warning>See http://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
|
||||
$this->getIO()->writeError('<info>' . $file . ' is valid, but with a few warnings</info>');
|
||||
$this->getIO()->writeError('<warning>See https://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
|
||||
} elseif (!$errors) {
|
||||
$output->writeln('<info>' . $file . ' is valid for simple usage with composer but has</info>');
|
||||
$output->writeln('<info>strict errors that make it unable to be published as a package:</info>');
|
||||
$output->writeln('<warning>See http://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
|
||||
$this->getIO()->writeError('<info>' . $file . ' is valid for simple usage with composer but has</info>');
|
||||
$this->getIO()->writeError('<info>strict errors that make it unable to be published as a package:</info>');
|
||||
$this->getIO()->writeError('<warning>See https://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
|
||||
} else {
|
||||
$output->writeln('<error>' . $file . ' is invalid, the following errors/warnings were found:</error>');
|
||||
$this->getIO()->writeError('<error>' . $file . ' is invalid, the following errors/warnings were found:</error>');
|
||||
}
|
||||
|
||||
$messages = array(
|
||||
'error' => array_merge($errors, $publishErrors),
|
||||
'error' => $errors,
|
||||
'warning' => $warnings,
|
||||
);
|
||||
|
||||
// If checking publish errors, display them errors, otherwise just show them as warnings
|
||||
if ($checkPublish) {
|
||||
$messages['error'] = array_merge($messages['error'], $publishErrors);
|
||||
} else {
|
||||
$messages['warning'] = array_merge($messages['warning'], $publishErrors);
|
||||
}
|
||||
|
||||
foreach ($messages as $style => $msgs) {
|
||||
foreach ($msgs as $msg) {
|
||||
$output->writeln('<' . $style . '>' . $msg . '</' . $style . '>');
|
||||
$this->getIO()->writeError('<' . $style . '>' . $msg . '</' . $style . '>');
|
||||
}
|
||||
}
|
||||
|
||||
return $errors || $publishErrors ? 1 : 0;
|
||||
return $errors || ($publishErrors && $checkPublish) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Composer;
|
|||
use Composer\Json\JsonFile;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Seld\PharUtils\Timestamps;
|
||||
|
||||
/**
|
||||
* The Compiler class compiles composer into a phar
|
||||
|
@ -51,9 +52,8 @@ class Compiler
|
|||
throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.');
|
||||
}
|
||||
|
||||
$date = new \DateTime(trim($process->getOutput()));
|
||||
$date->setTimezone(new \DateTimeZone('UTC'));
|
||||
$this->versionDate = $date->format('Y-m-d H:i:s');
|
||||
$this->versionDate = new \DateTime(trim($process->getOutput()));
|
||||
$this->versionDate->setTimezone(new \DateTimeZone('UTC'));
|
||||
|
||||
$process = new Process('git describe --tags --exact-match HEAD');
|
||||
if ($process->run() == 0) {
|
||||
|
@ -73,6 +73,10 @@ class Compiler
|
|||
|
||||
$phar->startBuffering();
|
||||
|
||||
$finderSort = function ($a, $b) {
|
||||
return strcmp(strtr($a->getRealPath(), '\\', '/'), strtr($b->getRealPath(), '\\', '/'));
|
||||
};
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->files()
|
||||
->ignoreVCS(true)
|
||||
|
@ -80,6 +84,7 @@ class Compiler
|
|||
->notName('Compiler.php')
|
||||
->notName('ClassLoader.php')
|
||||
->in(__DIR__.'/..')
|
||||
->sort($finderSort)
|
||||
;
|
||||
|
||||
foreach ($finder as $file) {
|
||||
|
@ -91,21 +96,27 @@ class Compiler
|
|||
$finder->files()
|
||||
->name('*.json')
|
||||
->in(__DIR__ . '/../../res')
|
||||
->sort($finderSort)
|
||||
;
|
||||
|
||||
foreach ($finder as $file) {
|
||||
$this->addFile($phar, $file, false);
|
||||
}
|
||||
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../src/Composer/IO/hiddeninput.exe'), false);
|
||||
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../vendor/seld/cli-prompt/res/hiddeninput.exe'), false);
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->files()
|
||||
->ignoreVCS(true)
|
||||
->name('*.php')
|
||||
->name('LICENSE')
|
||||
->exclude('Tests')
|
||||
->exclude('tests')
|
||||
->exclude('docs')
|
||||
->in(__DIR__.'/../../vendor/symfony/')
|
||||
->in(__DIR__.'/../../vendor/seld/jsonlint/src/')
|
||||
->in(__DIR__.'/../../vendor/justinrainbow/json-schema/src/')
|
||||
->in(__DIR__.'/../../vendor/seld/jsonlint/')
|
||||
->in(__DIR__.'/../../vendor/seld/cli-prompt/')
|
||||
->in(__DIR__.'/../../vendor/justinrainbow/json-schema/')
|
||||
->sort($finderSort)
|
||||
;
|
||||
|
||||
foreach ($finder as $file) {
|
||||
|
@ -134,6 +145,11 @@ class Compiler
|
|||
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../LICENSE'), false);
|
||||
|
||||
unset($phar);
|
||||
|
||||
// re-sign the phar with reproducible timestamp / signature
|
||||
$util = new Timestamps($pharFile);
|
||||
$util->updateTimestamps($this->versionDate);
|
||||
$util->save($pharFile, \Phar::SHA1);
|
||||
}
|
||||
|
||||
private function addFile($phar, $file, $strip = true)
|
||||
|
@ -150,7 +166,7 @@ class Compiler
|
|||
if ($path === 'src/Composer/Composer.php') {
|
||||
$content = str_replace('@package_version@', $this->version, $content);
|
||||
$content = str_replace('@package_branch_alias_version@', $this->branchAliasVersion, $content);
|
||||
$content = str_replace('@release_date@', $this->versionDate, $content);
|
||||
$content = str_replace('@release_date@', $this->versionDate->format('Y-m-d H:i:s'), $content);
|
||||
}
|
||||
|
||||
$phar->addFromString($path, $content);
|
||||
|
@ -226,9 +242,9 @@ Phar::mapPhar('composer.phar');
|
|||
|
||||
EOF;
|
||||
|
||||
// add warning once the phar is older than 30 days
|
||||
// add warning once the phar is older than 60 days
|
||||
if (preg_match('{^[a-f0-9]+$}', $this->version)) {
|
||||
$warningTime = time() + 30*86400;
|
||||
$warningTime = $this->versionDate->format('U') + 60 * 86400;
|
||||
$stub .= "define('COMPOSER_DEV_WARNING_TIME', $warningTime);\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
namespace Composer;
|
||||
|
||||
use Composer\Config\ConfigSourceInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
|
@ -45,6 +46,9 @@ class Config
|
|||
'github-domains' => array('github.com'),
|
||||
'github-expose-hostname' => true,
|
||||
'store-auths' => 'prompt',
|
||||
'platform' => array(),
|
||||
'archive-format' => 'tar',
|
||||
'archive-dir' => '.',
|
||||
// valid keys without defaults (auth config stuff):
|
||||
// github-oauth
|
||||
// http-basic
|
||||
|
|
|
@ -79,7 +79,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
public function addConfigSetting($name, $value)
|
||||
{
|
||||
$this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) {
|
||||
if ($key === 'github-oauth' || $key === 'http-basic') {
|
||||
if (preg_match('{^(github-oauth|http-basic|platform)\.}', $key)) {
|
||||
list($key, $host) = explode('.', $key, 2);
|
||||
if ($this->authConfig) {
|
||||
$config[$key][$host] = $val;
|
||||
|
@ -98,7 +98,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
|||
public function removeConfigSetting($name)
|
||||
{
|
||||
$this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) {
|
||||
if ($key === 'github-oauth' || $key === 'http-basic') {
|
||||
if (preg_match('{^(github-oauth|http-basic|platform)\.}', $key)) {
|
||||
list($key, $host) = explode('.', $key, 2);
|
||||
if ($this->authConfig) {
|
||||
unset($config[$key][$host]);
|
||||
|
|
|
@ -15,11 +15,11 @@ namespace Composer\Console;
|
|||
use Symfony\Component\Console\Application as BaseApplication;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Composer\Command;
|
||||
use Composer\Command\Helper\DialogHelper;
|
||||
use Composer\Composer;
|
||||
use Composer\Factory;
|
||||
use Composer\IO\IOInterface;
|
||||
|
@ -65,7 +65,6 @@ class Application extends BaseApplication
|
|||
date_default_timezone_set(@date_default_timezone_get());
|
||||
}
|
||||
|
||||
ErrorHandler::register();
|
||||
parent::__construct('Composer', Composer::VERSION);
|
||||
}
|
||||
|
||||
|
@ -89,9 +88,10 @@ class Application extends BaseApplication
|
|||
public function doRun(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->io = new ConsoleIO($input, $output, $this->getHelperSet());
|
||||
ErrorHandler::register($this->io);
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.3.2', '<')) {
|
||||
$output->writeln('<warning>Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.</warning>');
|
||||
if (PHP_VERSION_ID < 50302) {
|
||||
$this->getIO()->writeError('<warning>Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.', upgrading is strongly recommended.</warning>');
|
||||
}
|
||||
|
||||
if (defined('COMPOSER_DEV_WARNING_TIME')) {
|
||||
|
@ -104,7 +104,7 @@ class Application extends BaseApplication
|
|||
}
|
||||
if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
|
||||
if (time() > COMPOSER_DEV_WARNING_TIME) {
|
||||
$output->writeln(sprintf('<warning>Warning: This development build of composer is over 30 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF']));
|
||||
$this->getIO()->writeError(sprintf('<warning>Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,8 +117,8 @@ class Application extends BaseApplication
|
|||
if ($newWorkDir = $this->getNewWorkingDir($input)) {
|
||||
$oldWorkingDir = getcwd();
|
||||
chdir($newWorkDir);
|
||||
if ($output->getVerbosity() >= 4) {
|
||||
$output->writeln('Changed CWD to ' . getcwd());
|
||||
if ($this->getIO()->isDebug() >= 4) {
|
||||
$this->getIO()->writeError('Changed CWD to ' . getcwd());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ class Application extends BaseApplication
|
|||
foreach ($composer['scripts'] as $script => $dummy) {
|
||||
if (!defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
|
||||
if ($this->has($script)) {
|
||||
$output->writeln('<warning>A script named '.$script.' would override a native Composer function and has been skipped</warning>');
|
||||
$this->getIO()->writeError('<warning>A script named '.$script.' would override a native Composer function and has been skipped</warning>');
|
||||
} else {
|
||||
$this->add(new Command\ScriptAliasCommand($script));
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ class Application extends BaseApplication
|
|||
}
|
||||
|
||||
if (isset($startTime)) {
|
||||
$output->writeln('<info>Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s');
|
||||
$this->getIO()->writeError('<info>Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MB), time: '.round(microtime(true) - $startTime, 2).'s');
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -186,23 +186,27 @@ class Application extends BaseApplication
|
|||
|| (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
|
||||
|| (($df = @disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree)
|
||||
) {
|
||||
$output->writeln('<error>The disk hosting '.$dir.' is full, this may be the cause of the following exception</error>');
|
||||
$this->getIO()->writeError('<error>The disk hosting '.$dir.' is full, this may be the cause of the following exception</error>');
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
|
||||
$output->writeln('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>');
|
||||
$output->writeln('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>');
|
||||
$this->getIO()->writeError('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>');
|
||||
$this->getIO()->writeError('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>');
|
||||
}
|
||||
|
||||
if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) {
|
||||
$output->writeln('<error>The following exception is caused by a lack of memory and not having swap configured</error>');
|
||||
$output->writeln('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>');
|
||||
$this->getIO()->writeError('<error>The following exception is caused by a lack of memory and not having swap configured</error>');
|
||||
$this->getIO()->writeError('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>');
|
||||
}
|
||||
|
||||
return parent::renderException($exception, $output);
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
parent::renderException($exception, $output->getErrorOutput());
|
||||
} else {
|
||||
parent::renderException($exception, $output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,7 +222,7 @@ class Application extends BaseApplication
|
|||
$this->composer = Factory::create($this->io, null, $disablePlugins);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
if ($required) {
|
||||
$this->io->write($e->getMessage());
|
||||
$this->io->writeError($e->getMessage());
|
||||
exit(1);
|
||||
}
|
||||
} catch (JsonValidationException $e) {
|
||||
|
@ -316,16 +320,4 @@ class Application extends BaseApplication
|
|||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultHelperSet()
|
||||
{
|
||||
$helperSet = parent::getDefaultHelperSet();
|
||||
|
||||
$helperSet->set(new DialogHelper());
|
||||
|
||||
return $helperSet;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ class HtmlOutputFormatter extends OutputFormatter
|
|||
{
|
||||
$formatted = parent::format($message);
|
||||
|
||||
return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[0m}s", array($this, 'formatHtml'), $formatted);
|
||||
$clearEscapeCodes = '(?:39|49|0|22|24|25|27|28)';
|
||||
return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[(?:".$clearEscapeCodes.";)*?".$clearEscapeCodes."m}s", array($this, 'formatHtml'), $formatted);
|
||||
}
|
||||
|
||||
private function formatHtml($matches)
|
||||
|
|
|
@ -62,7 +62,15 @@ class DefaultPolicy implements PolicyInterface
|
|||
return $pool->getPriority($package->getRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Method has been renamed to selectPreferredPackages, you should update usages
|
||||
*/
|
||||
public function selectPreferedPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null)
|
||||
{
|
||||
return $this->selectPreferredPackages($pool, $installedMap, $literals, $requiredPackage);
|
||||
}
|
||||
|
||||
public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null)
|
||||
{
|
||||
$packages = $this->groupLiteralsByNamePreferInstalled($pool, $installedMap, $literals);
|
||||
|
||||
|
@ -74,10 +82,10 @@ class DefaultPolicy implements PolicyInterface
|
|||
}
|
||||
|
||||
foreach ($packages as &$literals) {
|
||||
$literals = $this->pruneToBestVersion($pool, $literals);
|
||||
|
||||
$literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals);
|
||||
|
||||
$literals = $this->pruneToBestVersion($pool, $literals);
|
||||
|
||||
$literals = $this->pruneRemoteAliases($pool, $literals);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,5 +21,5 @@ interface PolicyInterface
|
|||
{
|
||||
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
||||
public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package);
|
||||
public function selectPreferedPackages(Pool $pool, array $installedMap, array $literals);
|
||||
public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,6 @@ class Pool
|
|||
|
||||
public function __construct($minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array())
|
||||
{
|
||||
$stabilities = BasePackage::$stabilities;
|
||||
$this->versionParser = new VersionParser;
|
||||
$this->acceptableStabilities = array();
|
||||
foreach (BasePackage::$stabilities as $stability => $value) {
|
||||
|
@ -65,6 +64,11 @@ class Pool
|
|||
}
|
||||
$this->stabilityFlags = $stabilityFlags;
|
||||
$this->filterRequires = $filterRequires;
|
||||
foreach ($filterRequires as $name => $constraint) {
|
||||
if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name)) {
|
||||
unset($this->filterRequires[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setWhitelist($whitelist)
|
||||
|
|
|
@ -87,6 +87,19 @@ class Problem
|
|||
}
|
||||
|
||||
if ($job && $job['cmd'] === 'install' && empty($packages)) {
|
||||
// handle php/hhvm
|
||||
if ($job['packageName'] === 'php' || $job['packageName'] === 'php-64bit' || $job['packageName'] === 'hhvm') {
|
||||
$msg = "\n - This package requires ".$job['packageName'].$this->constraintToText($job['constraint']).' but ';
|
||||
|
||||
if (defined('HHVM_VERSION')) {
|
||||
return $msg . 'your HHVM version does not satisfy that requirement.';
|
||||
} elseif ($job['packageName'] === 'hhvm') {
|
||||
return $msg . 'you are running this with PHP and not HHVM.';
|
||||
}
|
||||
|
||||
return $msg . 'your PHP version ('. phpversion().') does not satisfy that requirement.';
|
||||
}
|
||||
|
||||
// handle php extensions
|
||||
if (0 === stripos($job['packageName'], 'ext-')) {
|
||||
$ext = substr($job['packageName'], 4);
|
||||
|
|
|
@ -20,11 +20,9 @@ use Composer\Package\LinkConstraint\LinkConstraintInterface;
|
|||
class Request
|
||||
{
|
||||
protected $jobs;
|
||||
protected $pool;
|
||||
|
||||
public function __construct(Pool $pool)
|
||||
public function __construct()
|
||||
{
|
||||
$this->pool = $pool;
|
||||
$this->jobs = array();
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,15 @@ class Rule
|
|||
$targetName = $this->reasonData->getTarget();
|
||||
|
||||
// handle php extensions
|
||||
if (0 === strpos($targetName, 'ext-')) {
|
||||
if ($targetName === 'php' || $targetName === 'php-64bit' || $targetName === 'hhvm') {
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$text .= ' -> your HHVM version does not satisfy that requirement.';
|
||||
} elseif ($targetName === 'hhvm') {
|
||||
$text .= ' -> you are running this with PHP and not HHVM.';
|
||||
} else {
|
||||
$text .= ' -> your PHP version ('. phpversion().') does not satisfy that requirement.';
|
||||
}
|
||||
} elseif (0 === strpos($targetName, 'ext-')) {
|
||||
$ext = substr($targetName, 4);
|
||||
$error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ class Solver
|
|||
protected $branches = array();
|
||||
protected $problems = array();
|
||||
protected $learnedPool = array();
|
||||
protected $learnedWhy = array();
|
||||
|
||||
public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed)
|
||||
{
|
||||
|
@ -328,7 +329,7 @@ class Solver
|
|||
private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule)
|
||||
{
|
||||
// choose best package to install from decisionQueue
|
||||
$literals = $this->policy->selectPreferedPackages($this->pool, $this->installedMap, $decisionQueue, $rule->getRequiredPackage());
|
||||
$literals = $this->policy->selectPreferredPackages($this->pool, $this->installedMap, $decisionQueue, $rule->getRequiredPackage());
|
||||
|
||||
$selectedLiteral = array_shift($literals);
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class SolverProblemsException extends \RuntimeException
|
|||
}
|
||||
|
||||
if (strpos($text, 'could not be found') || strpos($text, 'no matching package found')) {
|
||||
$text .= "\nPotential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.\n\nRead <http://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.";
|
||||
$text .= "\nPotential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.\n\nRead <https://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.";
|
||||
}
|
||||
|
||||
return $text;
|
||||
|
|
|
@ -35,7 +35,7 @@ abstract class ArchiveDownloader extends FileDownloader
|
|||
$fileName = parent::download($package, $path);
|
||||
|
||||
if ($this->io->isVerbose()) {
|
||||
$this->io->write(' Extracting archive');
|
||||
$this->io->writeError(' Extracting archive');
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -77,7 +77,7 @@ abstract class ArchiveDownloader extends FileDownloader
|
|||
|
||||
// retry downloading if we have an invalid zip file
|
||||
if ($retries && $e instanceof \UnexpectedValueException && class_exists('ZipArchive') && $e->getCode() === \ZipArchive::ER_NOZIP) {
|
||||
$this->io->write(' Invalid zip file, retrying...');
|
||||
$this->io->writeError(' Invalid zip file, retrying...');
|
||||
usleep(500000);
|
||||
continue;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ abstract class ArchiveDownloader extends FileDownloader
|
|||
break;
|
||||
}
|
||||
|
||||
$this->io->write('');
|
||||
$this->io->writeError('');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -115,10 +115,11 @@ abstract class ArchiveDownloader extends FileDownloader
|
|||
// update api archives to the proper reference
|
||||
$url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference();
|
||||
}
|
||||
} else if ($package->getDistReference() && strpos($url, 'bitbucket.org')) {
|
||||
if (preg_match('{^https?://(?:www\.)?bitbucket\.org/([^/]+)/([^/]+)/get/(.+)\.(zip|tar\.gz|tar\.bz2)$}i', $url, $match)) {
|
||||
// update Bitbucket archives to the proper reference
|
||||
$url = 'https://bitbucket.org/' . $match[1] . '/'. $match[2] . '/get/' . $package->getDistReference() . '.' . $match[4];
|
||||
}
|
||||
|
||||
if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) {
|
||||
throw new \RuntimeException('You must enable the openssl extension to download files via https');
|
||||
}
|
||||
|
||||
return parent::processUrl($package, $url);
|
||||
|
|
|
@ -192,7 +192,7 @@ class DownloadManager
|
|||
|
||||
foreach ($sources as $i => $source) {
|
||||
if (isset($e)) {
|
||||
$this->io->write(' <warning>Now trying to download from ' . $source . '</warning>');
|
||||
$this->io->writeError(' <warning>Now trying to download from ' . $source . '</warning>');
|
||||
}
|
||||
$package->setInstallationSource($source);
|
||||
try {
|
||||
|
@ -206,7 +206,7 @@ class DownloadManager
|
|||
throw $e;
|
||||
}
|
||||
|
||||
$this->io->write(
|
||||
$this->io->writeError(
|
||||
' <warning>Failed to download '.
|
||||
$package->getPrettyName().
|
||||
' from ' . $source . ': '.
|
||||
|
|
|
@ -81,7 +81,7 @@ class FileDownloader implements DownloaderInterface
|
|||
throw new \InvalidArgumentException('The given package is missing url information');
|
||||
}
|
||||
|
||||
$this->io->write(" - Installing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
|
||||
$this->io->writeError(" - Installing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
|
||||
|
||||
$urls = $package->getDistUrls();
|
||||
while ($url = array_shift($urls)) {
|
||||
|
@ -89,11 +89,11 @@ class FileDownloader implements DownloaderInterface
|
|||
return $this->doDownload($package, $path, $url);
|
||||
} catch (\Exception $e) {
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('');
|
||||
$this->io->write('Failed: ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage());
|
||||
$this->io->writeError('');
|
||||
$this->io->writeError('Failed: ['.get_class($e).'] '.$e->getCode().': '.$e->getMessage());
|
||||
} elseif (count($urls)) {
|
||||
$this->io->write('');
|
||||
$this->io->write(' Failed, trying the next URL ('.$e->getCode().': '.$e->getMessage().')');
|
||||
$this->io->writeError('');
|
||||
$this->io->writeError(' Failed, trying the next URL ('.$e->getCode().': '.$e->getMessage().')');
|
||||
}
|
||||
|
||||
if (!count($urls)) {
|
||||
|
@ -102,7 +102,7 @@ class FileDownloader implements DownloaderInterface
|
|||
}
|
||||
}
|
||||
|
||||
$this->io->write('');
|
||||
$this->io->writeError('');
|
||||
}
|
||||
|
||||
protected function doDownload(PackageInterface $package, $path, $url)
|
||||
|
@ -127,7 +127,7 @@ class FileDownloader implements DownloaderInterface
|
|||
// download if we don't have it in cache or the cache is invalidated
|
||||
if (!$this->cache || ($checksum && $checksum !== $this->cache->sha1($cacheKey)) || !$this->cache->copyTo($cacheKey, $fileName)) {
|
||||
if (!$this->outputProgress) {
|
||||
$this->io->write(' Downloading');
|
||||
$this->io->writeError(' Downloading');
|
||||
}
|
||||
|
||||
// try to download 3 times then fail hard
|
||||
|
@ -142,7 +142,7 @@ class FileDownloader implements DownloaderInterface
|
|||
throw $e;
|
||||
}
|
||||
if ($this->io->isVerbose()) {
|
||||
$this->io->write(' Download failed, retrying...');
|
||||
$this->io->writeError(' Download failed, retrying...');
|
||||
}
|
||||
usleep(500000);
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class FileDownloader implements DownloaderInterface
|
|||
$this->cache->copyFrom($cacheKey, $fileName);
|
||||
}
|
||||
} else {
|
||||
$this->io->write(' Loading from cache');
|
||||
$this->io->writeError(' Loading from cache');
|
||||
}
|
||||
|
||||
if (!file_exists($fileName)) {
|
||||
|
@ -205,7 +205,7 @@ class FileDownloader implements DownloaderInterface
|
|||
*/
|
||||
public function remove(PackageInterface $package, $path)
|
||||
{
|
||||
$this->io->write(" - Removing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
|
||||
$this->io->writeError(" - Removing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
|
||||
if (!$this->filesystem->removeDirectory($path)) {
|
||||
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ class GitDownloader extends VcsDownloader
|
|||
$ref = $package->getSourceReference();
|
||||
$flag = defined('PHP_WINDOWS_VERSION_MAJOR') ? '/D ' : '';
|
||||
$command = 'git clone --no-checkout %s %s && cd '.$flag.'%2$s && git remote add composer %1$s && git fetch composer';
|
||||
$this->io->write(" Cloning ".$ref);
|
||||
$this->io->writeError(" Cloning ".$ref);
|
||||
|
||||
$commandCallable = function ($url) use ($ref, $path, $command) {
|
||||
return sprintf($command, ProcessExecutor::escape($url), ProcessExecutor::escape($path), ProcessExecutor::escape($ref));
|
||||
|
@ -74,11 +74,11 @@ class GitDownloader extends VcsDownloader
|
|||
GitUtil::cleanEnv();
|
||||
$path = $this->normalizePath($path);
|
||||
if (!is_dir($path.'/.git')) {
|
||||
throw new \RuntimeException('The .git directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information');
|
||||
throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
|
||||
}
|
||||
|
||||
$ref = $target->getSourceReference();
|
||||
$this->io->write(" Checking out ".$ref);
|
||||
$this->io->writeError(" Checking out ".$ref);
|
||||
$command = 'git remote set-url composer %s && git fetch composer && git fetch --tags composer';
|
||||
|
||||
$commandCallable = function ($url) use ($command) {
|
||||
|
@ -143,10 +143,10 @@ class GitDownloader extends VcsDownloader
|
|||
$changes = array_map(function ($elem) {
|
||||
return ' '.$elem;
|
||||
}, preg_split('{\s*\r?\n\s*}', $changes));
|
||||
$this->io->write(' <error>The package has modified files:</error>');
|
||||
$this->io->write(array_slice($changes, 0, 10));
|
||||
$this->io->writeError(' <error>The package has modified files:</error>');
|
||||
$this->io->writeError(array_slice($changes, 0, 10));
|
||||
if (count($changes) > 10) {
|
||||
$this->io->write(' <info>'.count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>');
|
||||
$this->io->writeError(' <info>'.count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>');
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
@ -167,21 +167,21 @@ class GitDownloader extends VcsDownloader
|
|||
throw new \RuntimeException('Update aborted');
|
||||
|
||||
case 'v':
|
||||
$this->io->write($changes);
|
||||
$this->io->writeError($changes);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
help:
|
||||
$this->io->write(array(
|
||||
$this->io->writeError(array(
|
||||
' y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
|
||||
' n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
|
||||
' v - view modified files',
|
||||
));
|
||||
if ($update) {
|
||||
$this->io->write(' s - stash changes and try to reapply them after the update');
|
||||
$this->io->writeError(' s - stash changes and try to reapply them after the update');
|
||||
}
|
||||
$this->io->write(' ? - print help');
|
||||
$this->io->writeError(' ? - print help');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ class GitDownloader extends VcsDownloader
|
|||
$path = $this->normalizePath($path);
|
||||
if ($this->hasStashedChanges) {
|
||||
$this->hasStashedChanges = false;
|
||||
$this->io->write(' <info>Re-applying stashed changes</info>');
|
||||
$this->io->writeError(' <info>Re-applying stashed changes</info>');
|
||||
if (0 !== $this->process->execute('git stash pop', $output, $path)) {
|
||||
throw new \RuntimeException("Failed to apply stashed changes:\n\n".$this->process->getErrorOutput());
|
||||
}
|
||||
|
@ -215,7 +215,12 @@ class GitDownloader extends VcsDownloader
|
|||
*/
|
||||
protected function updateToCommit($path, $reference, $branch, $date)
|
||||
{
|
||||
$template = 'git checkout %s && git reset --hard %1$s';
|
||||
// This uses the "--" sequence to separate branch from file parameters.
|
||||
//
|
||||
// Otherwise git tries the branch name as well as file name.
|
||||
// If the non-existent branch is actually the name of a file, the file
|
||||
// is checked out.
|
||||
$template = 'git checkout %s -- && git reset --hard %1$s --';
|
||||
$branch = preg_replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $branch);
|
||||
|
||||
$branches = null;
|
||||
|
@ -229,7 +234,7 @@ class GitDownloader extends VcsDownloader
|
|||
&& $branches
|
||||
&& preg_match('{^\s+composer/'.preg_quote($reference).'$}m', $branches)
|
||||
) {
|
||||
$command = sprintf('git checkout -B %s %s && git reset --hard %2$s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference));
|
||||
$command = sprintf('git checkout -B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference));
|
||||
if (0 === $this->process->execute($command, $output, $path)) {
|
||||
return;
|
||||
}
|
||||
|
@ -242,12 +247,12 @@ class GitDownloader extends VcsDownloader
|
|||
$branch = 'v' . $branch;
|
||||
}
|
||||
|
||||
$command = sprintf('git checkout %s', ProcessExecutor::escape($branch));
|
||||
$fallbackCommand = sprintf('git checkout -B %s %s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch));
|
||||
$command = sprintf('git checkout %s --', ProcessExecutor::escape($branch));
|
||||
$fallbackCommand = sprintf('git checkout -B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch));
|
||||
if (0 === $this->process->execute($command, $output, $path)
|
||||
|| 0 === $this->process->execute($fallbackCommand, $output, $path)
|
||||
) {
|
||||
$command = sprintf('git reset --hard %s', ProcessExecutor::escape($reference));
|
||||
$command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference));
|
||||
if (0 === $this->process->execute($command, $output, $path)) {
|
||||
return;
|
||||
}
|
||||
|
@ -261,7 +266,7 @@ class GitDownloader extends VcsDownloader
|
|||
|
||||
// reference was not found (prints "fatal: reference is not a tree: $ref")
|
||||
if (false !== strpos($this->process->getErrorOutput(), $reference)) {
|
||||
$this->io->write(' <warning>'.$reference.' is gone (history was rewritten?)</warning>');
|
||||
$this->io->writeError(' <warning>'.$reference.' is gone (history was rewritten?)</warning>');
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput());
|
||||
|
|
|
@ -27,7 +27,7 @@ class HgDownloader extends VcsDownloader
|
|||
{
|
||||
$url = ProcessExecutor::escape($url);
|
||||
$ref = ProcessExecutor::escape($package->getSourceReference());
|
||||
$this->io->write(" Cloning ".$package->getSourceReference());
|
||||
$this->io->writeError(" Cloning ".$package->getSourceReference());
|
||||
$command = sprintf('hg clone %s %s', $url, ProcessExecutor::escape($path));
|
||||
if (0 !== $this->process->execute($command, $ignoredOutput)) {
|
||||
throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
|
||||
|
@ -45,10 +45,10 @@ class HgDownloader extends VcsDownloader
|
|||
{
|
||||
$url = ProcessExecutor::escape($url);
|
||||
$ref = ProcessExecutor::escape($target->getSourceReference());
|
||||
$this->io->write(" Updating to ".$target->getSourceReference());
|
||||
$this->io->writeError(" Updating to ".$target->getSourceReference());
|
||||
|
||||
if (!is_dir($path.'/.hg')) {
|
||||
throw new \RuntimeException('The .hg directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information');
|
||||
throw new \RuntimeException('The .hg directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
|
||||
}
|
||||
|
||||
$command = sprintf('hg pull %s && hg up %s', $url, $ref);
|
||||
|
|
|
@ -137,7 +137,7 @@ class PearPackageExtractor
|
|||
private function buildCopyActions($source, array $roles, $vars)
|
||||
{
|
||||
/** @var $package \SimpleXmlElement */
|
||||
$package = simplexml_load_file($this->combine($source, 'package.xml'));
|
||||
$package = simplexml_load_string(file_get_contents($this->combine($source, 'package.xml')));
|
||||
if (false === $package) {
|
||||
throw new \RuntimeException('Package definition file is not valid.');
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ class PerforceDownloader extends VcsDownloader
|
|||
$ref = $package->getSourceReference();
|
||||
$label = $this->getLabelFromSourceReference($ref);
|
||||
|
||||
$this->io->write(' Cloning ' . $ref);
|
||||
$this->io->writeError(' Cloning ' . $ref);
|
||||
$this->initPerforce($package, $path, $url);
|
||||
$this->perforce->setStream($ref);
|
||||
$this->perforce->p4Login($this->io);
|
||||
|
@ -85,7 +85,7 @@ class PerforceDownloader extends VcsDownloader
|
|||
*/
|
||||
public function getLocalChanges(PackageInterface $package, $path)
|
||||
{
|
||||
$this->io->write('Perforce driver does not check for local changes before overriding', true);
|
||||
$this->io->writeError('Perforce driver does not check for local changes before overriding', true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class SvnDownloader extends VcsDownloader
|
|||
SvnUtil::cleanEnv();
|
||||
$ref = $package->getSourceReference();
|
||||
|
||||
$this->io->write(" Checking out ".$package->getSourceReference());
|
||||
$this->io->writeError(" Checking out ".$package->getSourceReference());
|
||||
$this->execute($url, "svn co", sprintf("%s/%s", $url, $ref), null, $path);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ class SvnDownloader extends VcsDownloader
|
|||
$ref = $target->getSourceReference();
|
||||
|
||||
if (!is_dir($path.'/.svn')) {
|
||||
throw new \RuntimeException('The .svn directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information');
|
||||
throw new \RuntimeException('The .svn directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information');
|
||||
}
|
||||
|
||||
$flags = "";
|
||||
|
@ -52,7 +52,7 @@ class SvnDownloader extends VcsDownloader
|
|||
}
|
||||
}
|
||||
|
||||
$this->io->write(" Checking out " . $ref);
|
||||
$this->io->writeError(" Checking out " . $ref);
|
||||
$this->execute($url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path);
|
||||
}
|
||||
|
||||
|
@ -114,10 +114,10 @@ class SvnDownloader extends VcsDownloader
|
|||
$changes = array_map(function ($elem) {
|
||||
return ' '.$elem;
|
||||
}, preg_split('{\s*\r?\n\s*}', $changes));
|
||||
$this->io->write(' <error>The package has modified files:</error>');
|
||||
$this->io->write(array_slice($changes, 0, 10));
|
||||
$this->io->writeError(' <error>The package has modified files:</error>');
|
||||
$this->io->writeError(array_slice($changes, 0, 10));
|
||||
if (count($changes) > 10) {
|
||||
$this->io->write(' <info>'.count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>');
|
||||
$this->io->writeError(' <info>'.count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>');
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
@ -130,12 +130,12 @@ class SvnDownloader extends VcsDownloader
|
|||
throw new \RuntimeException('Update aborted');
|
||||
|
||||
case 'v':
|
||||
$this->io->write($changes);
|
||||
$this->io->writeError($changes);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
default:
|
||||
$this->io->write(array(
|
||||
$this->io->writeError(array(
|
||||
' y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
|
||||
' n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
|
||||
' v - view modified files',
|
||||
|
|
|
@ -54,7 +54,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
|
||||
}
|
||||
|
||||
$this->io->write(" - Installing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
|
||||
$this->io->writeError(" - Installing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
|
||||
$this->filesystem->emptyDirectory($path);
|
||||
|
||||
$urls = $package->getSourceUrls();
|
||||
|
@ -67,9 +67,9 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
break;
|
||||
} catch (\Exception $e) {
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage());
|
||||
$this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage());
|
||||
} elseif (count($urls)) {
|
||||
$this->io->write(' Failed, trying the next URL');
|
||||
$this->io->writeError(' Failed, trying the next URL');
|
||||
}
|
||||
if (!count($urls)) {
|
||||
throw $e;
|
||||
|
@ -77,7 +77,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
}
|
||||
}
|
||||
|
||||
$this->io->write('');
|
||||
$this->io->writeError('');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,7 +104,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
$to = VersionParser::formatVersion($target);
|
||||
}
|
||||
|
||||
$this->io->write(" - Updating <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>)");
|
||||
$this->io->writeError(" - Updating <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>)");
|
||||
|
||||
$this->cleanChanges($initial, $path, true);
|
||||
$urls = $target->getSourceUrls();
|
||||
|
@ -117,9 +117,9 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
break;
|
||||
} catch (\Exception $e) {
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage());
|
||||
$this->io->writeError('Failed: ['.get_class($e).'] '.$e->getMessage());
|
||||
} elseif (count($urls)) {
|
||||
$this->io->write(' Failed, trying the next URL');
|
||||
$this->io->writeError(' Failed, trying the next URL');
|
||||
} else {
|
||||
// in case of failed update, try to reapply the changes before aborting
|
||||
$this->reapplyChanges($path);
|
||||
|
@ -146,12 +146,12 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
return ' ' . $line;
|
||||
}, explode("\n", $logs)));
|
||||
|
||||
$this->io->write(' '.$message);
|
||||
$this->io->write($logs);
|
||||
$this->io->writeError(' '.$message);
|
||||
$this->io->writeError($logs);
|
||||
}
|
||||
}
|
||||
|
||||
$this->io->write('');
|
||||
$this->io->writeError('');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,7 +159,7 @@ abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterfa
|
|||
*/
|
||||
public function remove(PackageInterface $package, $path)
|
||||
{
|
||||
$this->io->write(" - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||
$this->io->writeError(" - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
|
||||
$this->cleanChanges($package, $path, false);
|
||||
if (!$this->filesystem->removeDirectory($path)) {
|
||||
throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
|
||||
|
|
|
@ -21,7 +21,6 @@ use Composer\Composer;
|
|||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Script;
|
||||
use Composer\Script\CommandEvent;
|
||||
use Composer\Script\PackageEvent;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
|
@ -95,36 +94,28 @@ class EventDispatcher
|
|||
/**
|
||||
* Dispatch a package event.
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param boolean $devMode Whether or not we are in dev mode
|
||||
* @param string $eventName The constant in PackageEvents
|
||||
* @param bool $devMode Whether or not we are in dev mode
|
||||
* @param PolicyInterface $policy The policy
|
||||
* @param Pool $pool The pool
|
||||
* @param CompositeRepository $installedRepo The installed repository
|
||||
* @param Request $request The request
|
||||
* @param array $operations The list of operations
|
||||
* @param OperationInterface $operation The package being installed/updated/removed
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchPackageEvent($eventName, $devMode, OperationInterface $operation)
|
||||
{
|
||||
return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a command event.
|
||||
*
|
||||
* @param string $eventName The constant in ScriptEvents
|
||||
* @param boolean $devMode Whether or not we are in dev mode
|
||||
* @param array $additionalArgs Arguments passed by the user
|
||||
* @param array $flags Optional flags to pass data not as argument
|
||||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchCommandEvent($eventName, $devMode, $additionalArgs = array(), $flags = array())
|
||||
public function dispatchPackageEvent($eventName, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation)
|
||||
{
|
||||
return $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
|
||||
return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $policy, $pool, $installedRepo, $request, $operations, $operation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a installer event.
|
||||
*
|
||||
* @param string $eventName The constant in InstallerEvents
|
||||
* @param bool $devMode Whether or not we are in dev mode
|
||||
* @param PolicyInterface $policy The policy
|
||||
* @param Pool $pool The pool
|
||||
* @param CompositeRepository $installedRepo The installed repository
|
||||
|
@ -134,9 +125,9 @@ class EventDispatcher
|
|||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchInstallerEvent($eventName, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
|
||||
public function dispatchInstallerEvent($eventName, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
|
||||
{
|
||||
return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $policy, $pool, $installedRepo, $request, $operations));
|
||||
return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $devMode, $policy, $pool, $installedRepo, $request, $operations));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,11 +154,11 @@ class EventDispatcher
|
|||
$methodName = substr($callable, strpos($callable, '::') + 2);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
$this->io->write('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
|
||||
$this->io->writeError('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
|
||||
continue;
|
||||
}
|
||||
if (!is_callable($callable)) {
|
||||
$this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
|
||||
$this->io->writeError('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -175,13 +166,13 @@ class EventDispatcher
|
|||
$return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0;
|
||||
} catch (\Exception $e) {
|
||||
$message = "Script %s handling the %s event terminated with an exception";
|
||||
$this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
|
||||
$this->io->writeError('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$args = implode(' ', array_map(array('Composer\Util\ProcessExecutor','escape'), $event->getArguments()));
|
||||
if (0 !== ($exitCode = $this->process->execute($callable . ($args === '' ? '' : ' '.$args)))) {
|
||||
$this->io->write(sprintf('<error>Script %s handling the %s event returned with an error</error>', $callable, $event->getName()));
|
||||
$this->io->writeError(sprintf('<error>Script %s handling the %s event returned with an error</error>', $callable, $event->getName()));
|
||||
|
||||
throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
|
||||
}
|
||||
|
@ -214,10 +205,6 @@ class EventDispatcher
|
|||
*/
|
||||
protected function checkListenerExpectedEvent($target, Event $event)
|
||||
{
|
||||
if (!$event instanceof Script\Event) {
|
||||
return $event;
|
||||
}
|
||||
|
||||
try {
|
||||
$reflected = new \ReflectionParameter($target, 0);
|
||||
} catch (\Exception $e) {
|
||||
|
@ -232,8 +219,24 @@ class EventDispatcher
|
|||
|
||||
$expected = $typehint->getName();
|
||||
|
||||
// BC support
|
||||
if (!$event instanceof $expected && $expected === 'Composer\Script\CommandEvent') {
|
||||
$event = new CommandEvent($event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), $event->getArguments());
|
||||
$event = new \Composer\Script\CommandEvent(
|
||||
$event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), $event->getArguments()
|
||||
);
|
||||
}
|
||||
if (!$event instanceof $expected && $expected === 'Composer\Script\PackageEvent') {
|
||||
$event = new \Composer\Script\PackageEvent(
|
||||
$event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(),
|
||||
$event->getPolicy(), $event->getPool(), $event->getInstalledRepo(), $event->getRequest(),
|
||||
$event->getOperations(), $event->getOperation()
|
||||
);
|
||||
}
|
||||
if (!$event instanceof $expected && $expected === 'Composer\Script\Event') {
|
||||
$event = new \Composer\Script\Event(
|
||||
$event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(),
|
||||
$event->getArguments(), $event->getFlags()
|
||||
);
|
||||
}
|
||||
|
||||
return $event;
|
||||
|
|
|
@ -194,10 +194,10 @@ class Factory
|
|||
$config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir, 'data-dir' => $dataDir)));
|
||||
|
||||
// load global config
|
||||
$file = new JsonFile($home.'/config.json');
|
||||
$file = new JsonFile($config->get('home').'/config.json');
|
||||
if ($file->exists()) {
|
||||
if ($io && $io->isDebug()) {
|
||||
$io->write('Loading config file ' . $file->getPath());
|
||||
$io->writeError('Loading config file ' . $file->getPath());
|
||||
}
|
||||
$config->merge($file->read());
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ class Factory
|
|||
$file = new JsonFile($config->get('home').'/auth.json');
|
||||
if ($file->exists()) {
|
||||
if ($io && $io->isDebug()) {
|
||||
$io->write('Loading config file ' . $file->getPath());
|
||||
$io->writeError('Loading config file ' . $file->getPath());
|
||||
}
|
||||
$config->merge(array('config' => $file->read()));
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ class Factory
|
|||
} else {
|
||||
$message = 'Composer could not find the config file: '.$localConfig;
|
||||
}
|
||||
$instructions = 'To initialize a project, please create a composer.json file as described in the http://getcomposer.org/ "Getting Started" section';
|
||||
$instructions = 'To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section';
|
||||
throw new \InvalidArgumentException($message.PHP_EOL.$instructions);
|
||||
}
|
||||
|
||||
|
@ -308,12 +308,12 @@ class Factory
|
|||
$config->merge($localConfig);
|
||||
if (isset($composerFile)) {
|
||||
if ($io && $io->isDebug()) {
|
||||
$io->write('Loading config file ' . $composerFile);
|
||||
$io->writeError('Loading config file ' . $composerFile);
|
||||
}
|
||||
$localAuthFile = new JsonFile(dirname(realpath($composerFile)) . '/auth.json');
|
||||
if ($localAuthFile->exists()) {
|
||||
if ($io && $io->isDebug()) {
|
||||
$io->write('Loading config file ' . $localAuthFile->getPath());
|
||||
$io->writeError('Loading config file ' . $localAuthFile->getPath());
|
||||
}
|
||||
$config->merge(array('config' => $localAuthFile->read()));
|
||||
$config->setAuthConfigSource(new JsonConfigSource($localAuthFile, true));
|
||||
|
@ -330,9 +330,6 @@ class Factory
|
|||
if ($fullLoad) {
|
||||
// load auth configs into the IO instance
|
||||
$io->loadConfiguration($config);
|
||||
|
||||
// setup process timeout
|
||||
ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
|
||||
}
|
||||
|
||||
// initialize event dispatcher
|
||||
|
@ -443,7 +440,7 @@ class Factory
|
|||
$composer = self::createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), false);
|
||||
} catch (\Exception $e) {
|
||||
if ($io->isDebug()) {
|
||||
$io->write('Failed to initialize global composer: '.$e->getMessage());
|
||||
$io->writeError('Failed to initialize global composer: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
namespace Composer\IO;
|
||||
|
||||
use Composer\Config;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
|
||||
abstract class BaseIO implements IOInterface
|
||||
{
|
||||
|
@ -75,5 +76,8 @@ abstract class BaseIO implements IOInterface
|
|||
$this->setAuthentication($domain, $cred['username'], $cred['password']);
|
||||
}
|
||||
}
|
||||
|
||||
// setup process timeout
|
||||
ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,12 +27,15 @@ class BufferIO extends ConsoleIO
|
|||
* @param int $verbosity
|
||||
* @param OutputFormatterInterface $formatter
|
||||
*/
|
||||
public function __construct($input = '', $verbosity = null, OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
public function __construct(
|
||||
$input = '',
|
||||
$verbosity = StreamOutput::VERBOSITY_NORMAL,
|
||||
OutputFormatterInterface $formatter = null
|
||||
) {
|
||||
$input = new StringInput($input);
|
||||
$input->setInteractive(false);
|
||||
|
||||
$output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity === null ? StreamOutput::VERBOSITY_NORMAL : $verbosity, !empty($formatter), $formatter);
|
||||
$output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity, !empty($formatter), $formatter);
|
||||
|
||||
parent::__construct($input, $output, new HelperSet(array()));
|
||||
}
|
||||
|
|
|
@ -13,8 +13,11 @@
|
|||
namespace Composer\IO;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Symfony\Component\Process\ExecutableFinder;
|
||||
|
||||
/**
|
||||
|
@ -29,6 +32,7 @@ class ConsoleIO extends BaseIO
|
|||
protected $output;
|
||||
protected $helperSet;
|
||||
protected $lastMessage;
|
||||
protected $lastMessageErr;
|
||||
private $startTime;
|
||||
|
||||
/**
|
||||
|
@ -79,7 +83,7 @@ class ConsoleIO extends BaseIO
|
|||
*/
|
||||
public function isVeryVerbose()
|
||||
{
|
||||
return $this->output->getVerbosity() >= 3; // OutputInterface::VERSOBITY_VERY_VERBOSE
|
||||
return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,13 +91,31 @@ class ConsoleIO extends BaseIO
|
|||
*/
|
||||
public function isDebug()
|
||||
{
|
||||
return $this->output->getVerbosity() >= 4; // OutputInterface::VERBOSITY_DEBUG
|
||||
return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function write($messages, $newline = true)
|
||||
{
|
||||
$this->doWrite($messages, $newline, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function writeError($messages, $newline = true)
|
||||
{
|
||||
$this->doWrite($messages, $newline, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $messages
|
||||
* @param boolean $newline
|
||||
* @param boolean $stderr
|
||||
*/
|
||||
private function doWrite($messages, $newline, $stderr)
|
||||
{
|
||||
if (null !== $this->startTime) {
|
||||
$memoryUsage = memory_get_usage() / 1024 / 1024;
|
||||
|
@ -102,6 +124,14 @@ class ConsoleIO extends BaseIO
|
|||
return sprintf('[%.1fMB/%.2fs] %s', $memoryUsage, $timeSpent, $message);
|
||||
}, (array) $messages);
|
||||
}
|
||||
|
||||
if (true === $stderr && $this->output instanceof ConsoleOutputInterface) {
|
||||
$this->output->getErrorOutput()->write($messages, $newline);
|
||||
$this->lastMessageErr = join($newline ? "\n" : '', (array) $messages);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->output->write($messages, $newline);
|
||||
$this->lastMessage = join($newline ? "\n" : '', (array) $messages);
|
||||
}
|
||||
|
@ -111,48 +141,74 @@ class ConsoleIO extends BaseIO
|
|||
*/
|
||||
public function overwrite($messages, $newline = true, $size = null)
|
||||
{
|
||||
if (!$this->output->isDecorated()) {
|
||||
if (!$messages) {
|
||||
return;
|
||||
$this->doOverwrite($messages, $newline, $size, false);
|
||||
}
|
||||
|
||||
return $this->write($messages, count($messages) === 1 || $newline);
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function overwriteError($messages, $newline = true, $size = null)
|
||||
{
|
||||
$this->doOverwrite($messages, $newline, $size, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $messages
|
||||
* @param boolean $newline
|
||||
* @param integer $size
|
||||
* @param boolean $stderr
|
||||
*/
|
||||
private function doOverwrite($messages, $newline, $size, $stderr)
|
||||
{
|
||||
// messages can be an array, let's convert it to string anyway
|
||||
$messages = join($newline ? "\n" : '', (array) $messages);
|
||||
|
||||
// since overwrite is supposed to overwrite last message...
|
||||
if (!isset($size)) {
|
||||
// removing possible formatting of lastMessage with strip_tags
|
||||
$size = strlen(strip_tags($this->lastMessage));
|
||||
$size = strlen(strip_tags($stderr ? $this->lastMessageErr : $this->lastMessage));
|
||||
}
|
||||
// ...let's fill its length with backspaces
|
||||
$this->write(str_repeat("\x08", $size), false);
|
||||
$this->doWrite(str_repeat("\x08", $size), false, $stderr);
|
||||
|
||||
// write the new message
|
||||
$this->write($messages, false);
|
||||
$this->doWrite($messages, false, $stderr);
|
||||
|
||||
$fill = $size - strlen(strip_tags($messages));
|
||||
if ($fill > 0) {
|
||||
// whitespace whatever has left
|
||||
$this->write(str_repeat(' ', $fill), false);
|
||||
$this->doWrite(str_repeat(' ', $fill), false, $stderr);
|
||||
// move the cursor back
|
||||
$this->write(str_repeat("\x08", $fill), false);
|
||||
$this->doWrite(str_repeat("\x08", $fill), false, $stderr);
|
||||
}
|
||||
|
||||
if ($newline) {
|
||||
$this->write('');
|
||||
$this->doWrite('', true, $stderr);
|
||||
}
|
||||
|
||||
if ($stderr) {
|
||||
$this->lastMessageErr = $messages;
|
||||
} else {
|
||||
$this->lastMessage = $messages;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function ask($question, $default = null)
|
||||
{
|
||||
return $this->helperSet->get('dialog')->ask($this->output, $question, $default);
|
||||
$output = $this->output;
|
||||
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
||||
$helper = $this->helperSet->get('question');
|
||||
$question = new Question($question, $default);
|
||||
|
||||
return $helper->ask($this->input, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,15 +216,37 @@ class ConsoleIO extends BaseIO
|
|||
*/
|
||||
public function askConfirmation($question, $default = true)
|
||||
{
|
||||
return $this->helperSet->get('dialog')->askConfirmation($this->output, $question, $default);
|
||||
$output = $this->output;
|
||||
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
||||
$helper = $this->helperSet->get('question');
|
||||
$question = new ConfirmationQuestion($question, $default);
|
||||
|
||||
return $helper->ask($this->input, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function askAndValidate($question, $validator, $attempts = false, $default = null)
|
||||
public function askAndValidate($question, $validator, $attempts = null, $default = null)
|
||||
{
|
||||
return $this->helperSet->get('dialog')->askAndValidate($this->output, $question, $validator, $attempts, $default);
|
||||
$output = $this->output;
|
||||
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
||||
$helper = $this->helperSet->get('question');
|
||||
$question = new Question($question, $default);
|
||||
$question->setValidator($validator);
|
||||
$question->setMaxAttempts($attempts);
|
||||
|
||||
return $helper->ask($this->input, $output, $question);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,71 +254,8 @@ class ConsoleIO extends BaseIO
|
|||
*/
|
||||
public function askAndHideAnswer($question)
|
||||
{
|
||||
// handle windows
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$finder = new ExecutableFinder();
|
||||
$this->writeError($question, false);
|
||||
|
||||
// use bash if it's present
|
||||
if ($finder->find('bash') && $finder->find('stty')) {
|
||||
$this->write($question, false);
|
||||
$value = rtrim(shell_exec('bash -c "stty -echo; read -n0 discard; read -r mypassword; stty echo; echo $mypassword"'));
|
||||
$this->write('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
// fallback to hiddeninput executable
|
||||
$exe = __DIR__.'\\hiddeninput.exe';
|
||||
|
||||
// handle code running from a phar
|
||||
if ('phar:' === substr(__FILE__, 0, 5)) {
|
||||
$tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
|
||||
|
||||
// use stream_copy_to_stream instead of copy
|
||||
// to work around https://bugs.php.net/bug.php?id=64634
|
||||
$source = fopen(__DIR__.'\\hiddeninput.exe', 'r');
|
||||
$target = fopen($tmpExe, 'w+');
|
||||
stream_copy_to_stream($source, $target);
|
||||
fclose($source);
|
||||
fclose($target);
|
||||
unset($source, $target);
|
||||
|
||||
$exe = $tmpExe;
|
||||
}
|
||||
|
||||
$this->write($question, false);
|
||||
$value = rtrim(shell_exec($exe));
|
||||
$this->write('');
|
||||
|
||||
// clean up
|
||||
if (isset($tmpExe)) {
|
||||
unlink($tmpExe);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (file_exists('/usr/bin/env')) {
|
||||
// handle other OSs with bash/zsh/ksh/csh if available to hide the answer
|
||||
$test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
|
||||
foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
|
||||
if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
|
||||
$shell = $sh;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($shell)) {
|
||||
$this->write($question, false);
|
||||
$readCmd = ($shell === 'csh') ? 'set mypassword = $<' : 'read -r mypassword';
|
||||
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
|
||||
$value = rtrim(shell_exec($command));
|
||||
$this->write('');
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
// not able to hide the answer, proceed with normal question handling
|
||||
return $this->ask($question);
|
||||
return \Seld\CliPrompt\CliPrompt::hiddenPrompt(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,14 @@ interface IOInterface
|
|||
*/
|
||||
public function write($messages, $newline = true);
|
||||
|
||||
/**
|
||||
* Writes a message to the error output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines or a single string
|
||||
* @param bool $newline Whether to add a newline or not
|
||||
*/
|
||||
public function writeError($messages, $newline = true);
|
||||
|
||||
/**
|
||||
* Overwrites a previous message to the output.
|
||||
*
|
||||
|
@ -73,6 +81,15 @@ interface IOInterface
|
|||
*/
|
||||
public function overwrite($messages, $newline = true, $size = null);
|
||||
|
||||
/**
|
||||
* Overwrites a previous message to the error output.
|
||||
*
|
||||
* @param string|array $messages The message as an array of lines or a single string
|
||||
* @param bool $newline Whether to add a newline or not
|
||||
* @param integer $size The size of line
|
||||
*/
|
||||
public function overwriteError($messages, $newline = true, $size = null);
|
||||
|
||||
/**
|
||||
* Asks a question to the user.
|
||||
*
|
||||
|
@ -106,14 +123,14 @@ interface IOInterface
|
|||
*
|
||||
* @param string|array $question The question to ask
|
||||
* @param callback $validator A PHP callback
|
||||
* @param bool|integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
* @param null|integer $attempts Max number of times to ask before giving up (default of null means infinite)
|
||||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception When any of the validators return an error
|
||||
*/
|
||||
public function askAndValidate($question, $validator, $attempts = false, $default = null);
|
||||
public function askAndValidate($question, $validator, $attempts = null, $default = null);
|
||||
|
||||
/**
|
||||
* Asks a question to the user and hide the answer.
|
||||
|
|
|
@ -66,6 +66,13 @@ class NullIO extends BaseIO
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function writeError($messages, $newline = true)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -73,6 +80,13 @@ class NullIO extends BaseIO
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function overwriteError($messages, $newline = true, $size = 80)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
|
Binary file not shown.
|
@ -177,7 +177,7 @@ class Installer
|
|||
// purge old require-dev packages to avoid conflicts with the new way of handling dev requirements
|
||||
$devRepo = new InstalledFilesystemRepository(new JsonFile($this->config->get('vendor-dir').'/composer/installed_dev.json'));
|
||||
if ($devRepo->getPackages()) {
|
||||
$this->io->write('<warning>BC Notice: Removing old dev packages to migrate to the new require-dev handling.</warning>');
|
||||
$this->io->writeError('<warning>BC Notice: Removing old dev packages to migrate to the new require-dev handling.</warning>');
|
||||
foreach ($devRepo->getPackages() as $package) {
|
||||
if ($this->installationManager->isPackageInstalled($devRepo, $package)) {
|
||||
$this->installationManager->uninstall($devRepo, new UninstallOperation($package));
|
||||
|
@ -191,7 +191,7 @@ class Installer
|
|||
if ($this->runScripts) {
|
||||
// dispatch pre event
|
||||
$eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
|
||||
$this->eventDispatcher->dispatchCommandEvent($eventName, $this->devMode);
|
||||
$this->eventDispatcher->dispatchScript($eventName, $this->devMode);
|
||||
}
|
||||
|
||||
$this->downloadManager->setPreferSource($this->preferSource);
|
||||
|
@ -206,7 +206,12 @@ class Installer
|
|||
|
||||
// create installed repo, this contains all local packages + platform packages (php & extensions)
|
||||
$localRepo = $this->repositoryManager->getLocalRepository();
|
||||
$platformRepo = new PlatformRepository();
|
||||
if (!$this->update && $this->locker->isLocked()) {
|
||||
$platformOverrides = $this->locker->getPlatformOverrides();
|
||||
} else {
|
||||
$platformOverrides = $this->config->get('platform') ?: array();
|
||||
}
|
||||
$platformRepo = new PlatformRepository(array(), $platformOverrides);
|
||||
$repos = array(
|
||||
$localRepo,
|
||||
new InstalledArrayRepository(array($installedRootPackage)),
|
||||
|
@ -243,7 +248,7 @@ class Installer
|
|||
}
|
||||
}
|
||||
|
||||
$this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')');
|
||||
$this->io->writeError($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,9 +262,9 @@ class Installer
|
|||
? 'Use ' . $package->getReplacementPackage() . ' instead'
|
||||
: 'No replacement was suggested';
|
||||
|
||||
$this->io->write(
|
||||
$this->io->writeError(
|
||||
sprintf(
|
||||
"<error>Package %s is abandoned, you should avoid using it. %s.</error>",
|
||||
"<warning>Package %s is abandoned, you should avoid using it. %s.</warning>",
|
||||
$package->getPrettyName(),
|
||||
$replacement
|
||||
)
|
||||
|
@ -282,16 +287,16 @@ class Installer
|
|||
$pool->addRepository($installedRepo, $aliases);
|
||||
|
||||
// creating requirements request
|
||||
$request = $this->createRequest($pool, $this->package, $platformRepo);
|
||||
$request = $this->createRequest($this->package, $platformRepo);
|
||||
$request->updateAll();
|
||||
foreach ($this->package->getRequires() as $link) {
|
||||
$request->install($link->getTarget(), $link->getConstraint());
|
||||
}
|
||||
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request);
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request);
|
||||
$solver = new Solver($policy, $pool, $installedRepo);
|
||||
$ops = $solver->solve($request, $this->ignorePlatformReqs);
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $ops);
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops);
|
||||
foreach ($ops as $op) {
|
||||
if ($op->getJobType() === 'uninstall') {
|
||||
$devPackages[] = $op->getPackage();
|
||||
|
@ -311,19 +316,20 @@ class Installer
|
|||
$this->package->getMinimumStability(),
|
||||
$this->package->getStabilityFlags(),
|
||||
$this->preferStable || $this->package->getPreferStable(),
|
||||
$this->preferLowest
|
||||
$this->preferLowest,
|
||||
$this->config->get('platform') ?: array()
|
||||
);
|
||||
if ($updatedLock) {
|
||||
$this->io->write('<info>Writing lock file</info>');
|
||||
$this->io->writeError('<info>Writing lock file</info>');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->dumpAutoloader) {
|
||||
// write autoloader
|
||||
if ($this->optimizeAutoloader) {
|
||||
$this->io->write('<info>Generating optimized autoload files</info>');
|
||||
$this->io->writeError('<info>Generating optimized autoload files</info>');
|
||||
} else {
|
||||
$this->io->write('<info>Generating autoload files</info>');
|
||||
$this->io->writeError('<info>Generating autoload files</info>');
|
||||
}
|
||||
|
||||
$this->autoloadGenerator->setDevMode($this->devMode);
|
||||
|
@ -333,7 +339,7 @@ class Installer
|
|||
if ($this->runScripts) {
|
||||
// dispatch post event
|
||||
$eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
|
||||
$this->eventDispatcher->dispatchCommandEvent($eventName, $this->devMode);
|
||||
$this->eventDispatcher->dispatchScript($eventName, $this->devMode);
|
||||
}
|
||||
|
||||
$vendorDir = $this->config->get('vendor-dir');
|
||||
|
@ -352,9 +358,12 @@ class Installer
|
|||
$repositories = null;
|
||||
|
||||
// initialize locker to create aliased packages
|
||||
$installFromLock = false;
|
||||
if (!$this->update && $this->locker->isLocked()) {
|
||||
$installFromLock = true;
|
||||
$installFromLock = !$this->update && $this->locker->isLocked();
|
||||
|
||||
// initialize locked repo if we are installing from lock or in a partial update
|
||||
// and a lock file is present as we need to force install non-whitelisted lock file
|
||||
// packages in that case
|
||||
if ($installFromLock || (!empty($this->updateWhitelist) && $this->locker->isLocked())) {
|
||||
try {
|
||||
$lockedRepository = $this->locker->getLockedRepository($withDevReqs);
|
||||
} catch (\RuntimeException $e) {
|
||||
|
@ -374,25 +383,27 @@ class Installer
|
|||
$this->package->getDevRequires()
|
||||
);
|
||||
|
||||
$this->io->write('<info>Loading composer repositories with package information</info>');
|
||||
$this->io->writeError('<info>Loading composer repositories with package information</info>');
|
||||
|
||||
// creating repository pool
|
||||
$policy = $this->createPolicy();
|
||||
$pool = $this->createPool($withDevReqs);
|
||||
$pool = $this->createPool($withDevReqs, $installFromLock ? $lockedRepository : null);
|
||||
$pool->addRepository($installedRepo, $aliases);
|
||||
if ($installFromLock) {
|
||||
$pool->addRepository($lockedRepository, $aliases);
|
||||
}
|
||||
|
||||
if (!$installFromLock) {
|
||||
$repositories = $this->repositoryManager->getRepositories();
|
||||
foreach ($repositories as $repository) {
|
||||
$pool->addRepository($repository, $aliases);
|
||||
}
|
||||
}
|
||||
// Add the locked repository after the others in case we are doing a
|
||||
// partial update so missing packages can be found there still.
|
||||
// For installs from lock it's the only one added so it is first
|
||||
if ($lockedRepository) {
|
||||
$pool->addRepository($lockedRepository, $aliases);
|
||||
}
|
||||
|
||||
// creating requirements request
|
||||
$request = $this->createRequest($pool, $this->package, $platformRepo);
|
||||
$request = $this->createRequest($this->package, $platformRepo);
|
||||
|
||||
if (!$installFromLock) {
|
||||
// remove unstable packages from the localRepo if they don't match the current stability settings
|
||||
|
@ -409,7 +420,7 @@ class Installer
|
|||
}
|
||||
|
||||
if ($this->update) {
|
||||
$this->io->write('<info>Updating dependencies'.($withDevReqs ? ' (including require-dev)' : '').'</info>');
|
||||
$this->io->writeError('<info>Updating dependencies'.($withDevReqs ? ' (including require-dev)' : '').'</info>');
|
||||
|
||||
$request->updateAll();
|
||||
|
||||
|
@ -426,16 +437,7 @@ class Installer
|
|||
// if the updateWhitelist is enabled, packages not in it are also fixed
|
||||
// to the version specified in the lock, or their currently installed version
|
||||
if ($this->updateWhitelist) {
|
||||
if ($this->locker->isLocked()) {
|
||||
try {
|
||||
$currentPackages = $this->locker->getLockedRepository($withDevReqs)->getPackages();
|
||||
} catch (\RuntimeException $e) {
|
||||
// fetch only non-dev packages from lock if doing a dev update fails due to a previously incomplete lock file
|
||||
$currentPackages = $this->locker->getLockedRepository()->getPackages();
|
||||
}
|
||||
} else {
|
||||
$currentPackages = $installedRepo->getPackages();
|
||||
}
|
||||
$currentPackages = $this->getCurrentPackages($withDevReqs, $installedRepo);
|
||||
|
||||
// collect packages to fixate from root requirements as well as installed packages
|
||||
$candidates = array();
|
||||
|
@ -460,10 +462,10 @@ class Installer
|
|||
}
|
||||
}
|
||||
} elseif ($installFromLock) {
|
||||
$this->io->write('<info>Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').' from lock file</info>');
|
||||
$this->io->writeError('<info>Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').' from lock file</info>');
|
||||
|
||||
if (!$this->locker->isFresh()) {
|
||||
$this->io->write('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.</warning>');
|
||||
$this->io->writeError('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.</warning>');
|
||||
}
|
||||
|
||||
foreach ($lockedRepository->getPackages() as $package) {
|
||||
|
@ -480,7 +482,7 @@ class Installer
|
|||
$request->install($link->getTarget(), $link->getConstraint());
|
||||
}
|
||||
} else {
|
||||
$this->io->write('<info>Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').'</info>');
|
||||
$this->io->writeError('<info>Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').'</info>');
|
||||
|
||||
if ($withDevReqs) {
|
||||
$links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
|
||||
|
@ -494,27 +496,27 @@ class Installer
|
|||
}
|
||||
|
||||
// force dev packages to have the latest links if we update or install from a (potentially new) lock
|
||||
$this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links');
|
||||
$this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $installFromLock, $withDevReqs, 'force-links');
|
||||
|
||||
// solve dependencies
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request);
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request);
|
||||
$solver = new Solver($policy, $pool, $installedRepo);
|
||||
try {
|
||||
$operations = $solver->solve($request, $this->ignorePlatformReqs);
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $operations);
|
||||
$this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations);
|
||||
} catch (SolverProblemsException $e) {
|
||||
$this->io->write('<error>Your requirements could not be resolved to an installable set of packages.</error>');
|
||||
$this->io->write($e->getMessage());
|
||||
$this->io->writeError('<error>Your requirements could not be resolved to an installable set of packages.</error>');
|
||||
$this->io->writeError($e->getMessage());
|
||||
|
||||
return max(1, $e->getCode());
|
||||
}
|
||||
|
||||
// force dev packages to be updated if we update or install from a (potentially new) lock
|
||||
$operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-updates', $operations);
|
||||
$operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $installFromLock, $withDevReqs, 'force-updates', $operations);
|
||||
|
||||
// execute operations
|
||||
if (!$operations) {
|
||||
$this->io->write('Nothing to install or update');
|
||||
$this->io->writeError('Nothing to install or update');
|
||||
}
|
||||
|
||||
$operations = $this->movePluginsToFront($operations);
|
||||
|
@ -553,26 +555,26 @@ class Installer
|
|||
&& $operation->getTargetPackage()->getSourceReference() === $operation->getInitialPackage()->getSourceReference()
|
||||
) {
|
||||
if ($this->io->isDebug()) {
|
||||
$this->io->write(' - Skipping update of '. $operation->getTargetPackage()->getPrettyName().' to the same reference-locked version');
|
||||
$this->io->write('');
|
||||
$this->io->writeError(' - Skipping update of '. $operation->getTargetPackage()->getPrettyName().' to the same reference-locked version');
|
||||
$this->io->writeError('');
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$event = 'Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType());
|
||||
$event = 'Composer\Installer\PackageEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType());
|
||||
if (defined($event) && $this->runScripts) {
|
||||
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
|
||||
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation);
|
||||
}
|
||||
|
||||
// output non-alias ops in dry run, output alias ops in debug verbosity
|
||||
if ($this->dryRun && false === strpos($operation->getJobType(), 'Alias')) {
|
||||
$this->io->write(' - ' . $operation);
|
||||
$this->io->write('');
|
||||
$this->io->writeError(' - ' . $operation);
|
||||
$this->io->writeError('');
|
||||
} elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) {
|
||||
$this->io->write(' - ' . $operation);
|
||||
$this->io->write('');
|
||||
$this->io->writeError(' - ' . $operation);
|
||||
$this->io->writeError('');
|
||||
}
|
||||
|
||||
$this->installationManager->execute($localRepo, $operation);
|
||||
|
@ -583,20 +585,20 @@ class Installer
|
|||
if ($reason instanceof Rule) {
|
||||
switch ($reason->getReason()) {
|
||||
case Rule::RULE_JOB_INSTALL:
|
||||
$this->io->write(' REASON: Required by root: '.$reason->getPrettyString($pool));
|
||||
$this->io->write('');
|
||||
$this->io->writeError(' REASON: Required by root: '.$reason->getPrettyString($pool));
|
||||
$this->io->writeError('');
|
||||
break;
|
||||
case Rule::RULE_PACKAGE_REQUIRES:
|
||||
$this->io->write(' REASON: '.$reason->getPrettyString($pool));
|
||||
$this->io->write('');
|
||||
$this->io->writeError(' REASON: '.$reason->getPrettyString($pool));
|
||||
$this->io->writeError('');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$event = 'Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType());
|
||||
$event = 'Composer\Installer\PackageEvents::POST_PACKAGE_'.strtoupper($operation->getJobType());
|
||||
if (defined($event) && $this->runScripts) {
|
||||
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
|
||||
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation);
|
||||
}
|
||||
|
||||
if (!$this->dryRun) {
|
||||
|
@ -604,6 +606,12 @@ class Installer
|
|||
}
|
||||
}
|
||||
|
||||
if (!$this->dryRun) {
|
||||
// force source/dist urls to be updated for all packages
|
||||
$operations = $this->processPackageUrls($pool, $policy, $localRepo, $repositories);
|
||||
$localRepo->write();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -671,27 +679,39 @@ class Installer
|
|||
return array_merge($uninstOps, $operations);
|
||||
}
|
||||
|
||||
private function createPool($withDevReqs)
|
||||
private function createPool($withDevReqs, RepositoryInterface $lockedRepository = null)
|
||||
{
|
||||
$minimumStability = $this->package->getMinimumStability();
|
||||
$stabilityFlags = $this->package->getStabilityFlags();
|
||||
|
||||
if (!$this->update && $this->locker->isLocked()) {
|
||||
if (!$this->update && $this->locker->isLocked()) { // install from lock
|
||||
$minimumStability = $this->locker->getMinimumStability();
|
||||
$stabilityFlags = $this->locker->getStabilityFlags();
|
||||
|
||||
$requires = array();
|
||||
foreach ($lockedRepository->getPackages() as $package) {
|
||||
$constraint = new VersionConstraint('=', $package->getVersion());
|
||||
$constraint->setPrettyString($package->getPrettyVersion());
|
||||
$requires[$package->getName()] = $constraint;
|
||||
}
|
||||
} else {
|
||||
$minimumStability = $this->package->getMinimumStability();
|
||||
$stabilityFlags = $this->package->getStabilityFlags();
|
||||
|
||||
$requires = $this->package->getRequires();
|
||||
if ($withDevReqs) {
|
||||
$requires = array_merge($requires, $this->package->getDevRequires());
|
||||
}
|
||||
}
|
||||
|
||||
$rootConstraints = array();
|
||||
foreach ($requires as $req => $constraint) {
|
||||
// skip platform requirements from the root package to avoid filtering out existing platform packages
|
||||
if ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) {
|
||||
continue;
|
||||
}
|
||||
if ($constraint instanceof Link) {
|
||||
$rootConstraints[$req] = $constraint->getConstraint();
|
||||
} else {
|
||||
$rootConstraints[$req] = $constraint;
|
||||
}
|
||||
}
|
||||
|
||||
return new Pool($minimumStability, $stabilityFlags, $rootConstraints);
|
||||
|
@ -717,9 +737,9 @@ class Installer
|
|||
return new DefaultPolicy($preferStable, $preferLowest);
|
||||
}
|
||||
|
||||
private function createRequest(Pool $pool, RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
|
||||
private function createRequest(RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
|
||||
{
|
||||
$request = new Request($pool);
|
||||
$request = new Request();
|
||||
|
||||
$constraint = new VersionConstraint('=', $rootPackage->getVersion());
|
||||
$constraint->setPrettyString($rootPackage->getPrettyVersion());
|
||||
|
@ -750,7 +770,7 @@ class Installer
|
|||
return $request;
|
||||
}
|
||||
|
||||
private function processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, $task, array $operations = null)
|
||||
private function processDevPackages($localRepo, $pool, $policy, $repositories, $installedRepo, $lockedRepository, $installFromLock, $withDevReqs, $task, array $operations = null)
|
||||
{
|
||||
if ($task === 'force-updates' && null === $operations) {
|
||||
throw new \InvalidArgumentException('Missing operations argument');
|
||||
|
@ -759,6 +779,10 @@ class Installer
|
|||
$operations = array();
|
||||
}
|
||||
|
||||
if (!$installFromLock && $this->updateWhitelist) {
|
||||
$currentPackages = $this->getCurrentPackages($withDevReqs, $installedRepo);
|
||||
}
|
||||
|
||||
foreach ($localRepo->getCanonicalPackages() as $package) {
|
||||
// skip non-dev packages
|
||||
if (!$package->isDev()) {
|
||||
|
@ -799,6 +823,26 @@ class Installer
|
|||
if ($this->update) {
|
||||
// skip package if the whitelist is enabled and it is not in it
|
||||
if ($this->updateWhitelist && !$this->isUpdateable($package)) {
|
||||
// check if non-updateable packages are out of date compared to the lock file to ensure we don't corrupt it
|
||||
foreach ($currentPackages as $curPackage) {
|
||||
if ($curPackage->isDev() && $curPackage->getName() === $package->getName() && $curPackage->getVersion() === $package->getVersion()) {
|
||||
if ($task === 'force-links') {
|
||||
$package->setRequires($curPackage->getRequires());
|
||||
$package->setConflicts($curPackage->getConflicts());
|
||||
$package->setProvides($curPackage->getProvides());
|
||||
$package->setReplaces($curPackage->getReplaces());
|
||||
} elseif ($task === 'force-updates') {
|
||||
if (($curPackage->getSourceReference() && $curPackage->getSourceReference() !== $package->getSourceReference())
|
||||
|| ($curPackage->getDistReference() && $curPackage->getDistReference() !== $package->getDistReference())
|
||||
) {
|
||||
$operations[] = new UpdateOperation($package, $curPackage);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -820,8 +864,8 @@ class Installer
|
|||
$matches[$index] = $match->getId();
|
||||
}
|
||||
|
||||
// select prefered package according to policy rules
|
||||
if ($matches && $matches = $policy->selectPreferedPackages($pool, array(), $matches)) {
|
||||
// select preferred package according to policy rules
|
||||
if ($matches && $matches = $policy->selectPreferredPackages($pool, array(), $matches)) {
|
||||
$newPackage = $pool->literalToPackage($matches[0]);
|
||||
|
||||
if ($task === 'force-links' && $newPackage) {
|
||||
|
@ -842,7 +886,7 @@ class Installer
|
|||
}
|
||||
|
||||
if ($task === 'force-updates') {
|
||||
// force installed package to update to referenced version if it does not match the installed version
|
||||
// force installed package to update to referenced version in root package if it does not match the installed version
|
||||
$references = $this->package->getReferences();
|
||||
|
||||
if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) {
|
||||
|
@ -856,6 +900,23 @@ class Installer
|
|||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the most "current" list of packages that are installed meaning from lock ideally or from installed repo as fallback
|
||||
*/
|
||||
private function getCurrentPackages($withDevReqs, $installedRepo)
|
||||
{
|
||||
if ($this->locker->isLocked()) {
|
||||
try {
|
||||
return $this->locker->getLockedRepository($withDevReqs)->getPackages();
|
||||
} catch (\RuntimeException $e) {
|
||||
// fetch only non-dev packages from lock if doing a dev update fails due to a previously incomplete lock file
|
||||
return $this->locker->getLockedRepository()->getPackages();
|
||||
}
|
||||
}
|
||||
|
||||
return $installedRepo->getPackages();
|
||||
}
|
||||
|
||||
private function getRootAliases()
|
||||
{
|
||||
if (!$this->update && $this->locker->isLocked()) {
|
||||
|
@ -876,6 +937,46 @@ class Installer
|
|||
return $normalizedAliases;
|
||||
}
|
||||
|
||||
private function processPackageUrls($pool, $policy, $localRepo, $repositories)
|
||||
{
|
||||
if (!$this->update) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($localRepo->getCanonicalPackages() as $package) {
|
||||
// find similar packages (name/version) in all repositories
|
||||
$matches = $pool->whatProvides($package->getName(), new VersionConstraint('=', $package->getVersion()));
|
||||
foreach ($matches as $index => $match) {
|
||||
// skip local packages
|
||||
if (!in_array($match->getRepository(), $repositories, true)) {
|
||||
unset($matches[$index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip providers/replacers
|
||||
if ($match->getName() !== $package->getName()) {
|
||||
unset($matches[$index]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$matches[$index] = $match->getId();
|
||||
}
|
||||
|
||||
// select preferred package according to policy rules
|
||||
if ($matches && $matches = $policy->selectPreferredPackages($pool, array(), $matches)) {
|
||||
$newPackage = $pool->literalToPackage($matches[0]);
|
||||
|
||||
// update the dist and source URLs
|
||||
$package->setSourceUrl($newPackage->getSourceUrl());
|
||||
// only update dist url for github/bitbucket dists as they use a combination of dist url + dist reference to install
|
||||
// but for other urls this is ambiguous and could result in bad outcomes
|
||||
if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com)/}', $newPackage->getDistUrl())) {
|
||||
$package->setDistUrl($newPackage->getDistUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function aliasPlatformPackages(PlatformRepository $platformRepo, $aliases)
|
||||
{
|
||||
foreach ($aliases as $package => $versions) {
|
||||
|
@ -989,7 +1090,7 @@ class Installer
|
|||
}
|
||||
|
||||
if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock'))) {
|
||||
$this->io->write('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
|
||||
$this->io->writeError('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
|
||||
}
|
||||
|
||||
foreach ($depPackages as $depPackage) {
|
||||
|
@ -1166,7 +1267,6 @@ class Installer
|
|||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set whether to run autoloader or not
|
||||
*
|
||||
|
@ -1180,7 +1280,6 @@ class Installer
|
|||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set whether to run scripts or not
|
||||
*
|
||||
|
@ -1271,7 +1370,7 @@ class Installer
|
|||
}
|
||||
|
||||
/**
|
||||
* Should packages be prefered in a stable version when updating?
|
||||
* Should packages be preferred in a stable version when updating?
|
||||
*
|
||||
* @param boolean $preferStable
|
||||
* @return Installer
|
||||
|
@ -1284,7 +1383,7 @@ class Installer
|
|||
}
|
||||
|
||||
/**
|
||||
* Should packages be prefered in a lowest version when updating?
|
||||
* Should packages be preferred in a lowest version when updating?
|
||||
*
|
||||
* @param boolean $preferLowest
|
||||
* @return Installer
|
||||
|
|
|
@ -38,6 +38,11 @@ class InstallerEvent extends Event
|
|||
*/
|
||||
private $io;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $devMode;
|
||||
|
||||
/**
|
||||
* @var PolicyInterface
|
||||
*/
|
||||
|
@ -69,18 +74,20 @@ class InstallerEvent extends Event
|
|||
* @param string $eventName
|
||||
* @param Composer $composer
|
||||
* @param IOInterface $io
|
||||
* @param bool $devMode
|
||||
* @param PolicyInterface $policy
|
||||
* @param Pool $pool
|
||||
* @param CompositeRepository $installedRepo
|
||||
* @param Request $request
|
||||
* @param OperationInterface[] $operations
|
||||
*/
|
||||
public function __construct($eventName, Composer $composer, IOInterface $io, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
|
||||
public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
|
||||
{
|
||||
parent::__construct($eventName);
|
||||
|
||||
$this->composer = $composer;
|
||||
$this->io = $io;
|
||||
$this->devMode = $devMode;
|
||||
$this->policy = $policy;
|
||||
$this->pool = $pool;
|
||||
$this->installedRepo = $installedRepo;
|
||||
|
@ -104,6 +111,14 @@ class InstallerEvent extends Event
|
|||
return $this->io;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDevMode()
|
||||
{
|
||||
return $this->devMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PolicyInterface
|
||||
*/
|
||||
|
|
|
@ -197,7 +197,7 @@ class LibraryInstaller implements InstallerInterface
|
|||
foreach ($binaries as $bin) {
|
||||
$binPath = $this->getInstallPath($package).'/'.$bin;
|
||||
if (!file_exists($binPath)) {
|
||||
$this->io->write(' <warning>Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package</warning>');
|
||||
$this->io->writeError(' <warning>Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package</warning>');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ class LibraryInstaller implements InstallerInterface
|
|||
// is a fresh install of the vendor.
|
||||
@chmod($link, 0777 & ~umask());
|
||||
}
|
||||
$this->io->write(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
|
||||
$this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
|
||||
continue;
|
||||
}
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
|
@ -226,7 +226,7 @@ class LibraryInstaller implements InstallerInterface
|
|||
@chmod($link, 0777 & ~umask());
|
||||
$link .= '.bat';
|
||||
if (file_exists($link)) {
|
||||
$this->io->write(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed');
|
||||
$this->io->writeError(' Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed');
|
||||
}
|
||||
}
|
||||
if (!file_exists($link)) {
|
||||
|
@ -239,7 +239,7 @@ class LibraryInstaller implements InstallerInterface
|
|||
// when using it in smbfs mounted folder
|
||||
$relativeBin = $this->filesystem->findShortestPath($link, $binPath);
|
||||
chdir(dirname($link));
|
||||
if (false === symlink($relativeBin, $link)) {
|
||||
if (false === @symlink($relativeBin, $link)) {
|
||||
throw new \ErrorException();
|
||||
}
|
||||
} catch (\ErrorException $e) {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace Composer\Installer;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
use Composer\DependencyResolver\PolicyInterface;
|
||||
use Composer\DependencyResolver\Pool;
|
||||
use Composer\DependencyResolver\Request;
|
||||
use Composer\EventDispatcher\Event;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
|
||||
/**
|
||||
* The Package Event.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class PackageEvent extends InstallerEvent
|
||||
{
|
||||
/**
|
||||
* @var OperationInterface The package instance
|
||||
*/
|
||||
private $operation;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $eventName
|
||||
* @param Composer $composer
|
||||
* @param IOInterface $io
|
||||
* @param bool $devMode
|
||||
* @param PolicyInterface $policy
|
||||
* @param Pool $pool
|
||||
* @param CompositeRepository $installedRepo
|
||||
* @param Request $request
|
||||
* @param OperationInterface[] $operations
|
||||
* @param OperationInterface $operation
|
||||
*/
|
||||
public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations, OperationInterface $operation)
|
||||
{
|
||||
parent::__construct($eventName, $composer, $io, $devMode, $policy, $pool, $installedRepo, $request, $operations);
|
||||
|
||||
$this->operation = $operation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package instance.
|
||||
*
|
||||
* @return OperationInterface
|
||||
*/
|
||||
public function getOperation()
|
||||
{
|
||||
return $this->operation;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace Composer\Installer;
|
||||
|
||||
/**
|
||||
* Package Events.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class PackageEvents
|
||||
{
|
||||
/**
|
||||
* The PRE_PACKAGE_INSTALL event occurs before a package is installed.
|
||||
*
|
||||
* The event listener method receives a Composer\Script\PackageEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_PACKAGE_INSTALL = 'pre-package-install';
|
||||
|
||||
/**
|
||||
* The POST_PACKAGE_INSTALL event occurs after a package is installed.
|
||||
*
|
||||
* The event listener method receives a Composer\Script\PackageEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_PACKAGE_INSTALL = 'post-package-install';
|
||||
|
||||
/**
|
||||
* The PRE_PACKAGE_UPDATE event occurs before a package is updated.
|
||||
*
|
||||
* The event listener method receives a Composer\Script\PackageEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_PACKAGE_UPDATE = 'pre-package-update';
|
||||
|
||||
/**
|
||||
* The POST_PACKAGE_UPDATE event occurs after a package is updated.
|
||||
*
|
||||
* The event listener method receives a Composer\Script\PackageEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_PACKAGE_UPDATE = 'post-package-update';
|
||||
|
||||
/**
|
||||
* The PRE_PACKAGE_UNINSTALL event occurs before a package has been uninstalled.
|
||||
*
|
||||
* The event listener method receives a Composer\Script\PackageEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
|
||||
|
||||
/**
|
||||
* The POST_PACKAGE_UNINSTALL event occurs after a package has been uninstalled.
|
||||
*
|
||||
* The event listener method receives a Composer\Script\PackageEvent instance.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
|
||||
}
|
|
@ -76,7 +76,7 @@ class PearInstaller extends LibraryInstaller
|
|||
$pearExtractor->extractTo($this->getInstallPath($package), array('php' => '/', 'script' => '/bin', 'data' => '/data'), $vars);
|
||||
|
||||
if ($this->io->isVerbose()) {
|
||||
$this->io->write(' Cleaning up');
|
||||
$this->io->writeError(' Cleaning up');
|
||||
}
|
||||
$this->filesystem->unlink($packageArchive);
|
||||
}
|
||||
|
|
|
@ -182,8 +182,11 @@ class JsonFile
|
|||
*/
|
||||
public static function encode($data, $options = 448)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
||||
if (PHP_VERSION_ID >= 50400) {
|
||||
$json = json_encode($data, $options);
|
||||
if (false === $json) {
|
||||
self::throwEncodeError(json_last_error());
|
||||
}
|
||||
|
||||
// compact brackets to follow recent php versions
|
||||
if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
|
||||
|
@ -195,6 +198,9 @@ class JsonFile
|
|||
}
|
||||
|
||||
$json = json_encode($data);
|
||||
if (false === $json) {
|
||||
self::throwEncodeError(json_last_error());
|
||||
}
|
||||
|
||||
$prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT);
|
||||
$unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE);
|
||||
|
@ -209,6 +215,34 @@ class JsonFile
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception according to a given code with a customized message
|
||||
*
|
||||
* @param int $code return code of json_last_error function
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
private static function throwEncodeError($code)
|
||||
{
|
||||
switch ($code) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
$msg = 'Maximum stack depth exceeded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
$msg = 'Underflow or the modes mismatch';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
$msg = 'Unexpected control character found';
|
||||
break;
|
||||
case JSON_ERROR_UTF8:
|
||||
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
break;
|
||||
default:
|
||||
$msg = 'Unknown error';
|
||||
}
|
||||
|
||||
throw new \RuntimeException('JSON encoding failed: '.$msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses json string and returns hash.
|
||||
*
|
||||
|
@ -219,6 +253,9 @@ class JsonFile
|
|||
*/
|
||||
public static function parseJson($json, $file = null)
|
||||
{
|
||||
if (null === $json) {
|
||||
return;
|
||||
}
|
||||
$data = json_decode($json, true);
|
||||
if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
|
||||
self::validateSyntax($json, $file);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue