* 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
[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)
"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,8 +420,20 @@
"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.",
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>';
// 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;
$output->writeln('<warning>'.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'</warning>');
continue;
$this->getIO()->writeError('<warning>Package '.$packageName.' not found</warning>');
$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)
@ -33,28 +33,18 @@ use Symfony\Component\Process\ExecutableFinder;
*/
class InitCommand extends Command
{
/** @var CompositeRepository */
protected $repos;
/** @var array */
private $gitConfig;
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>'
);
}
/** @var Pool */
private $pool;
/**
* {@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)
$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)) {
$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): ',
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>');
$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)));
$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));
* 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()));
@ -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>');
$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>');
@ -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.";
* @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())
$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) {