sms functions testing
[namibia] / composer.phar
1 #!/usr/bin/env php
2 <?php
3 /*
4  * This file is part of Composer.
5  *
6  * (c) Nils Adermann <naderman@naderman.de>
7  *     Jordi Boggiano <j.boggiano@seld.be>
8  *
9  * For the full copyright and license information, please view
10  * the license that is located at the bottom of this file.
11  */
12
13 // Avoid APC causing random fatal errors per https://github.com/composer/composer/issues/264
14 if (extension_loaded('apc') && ini_get('apc.enable_cli') && ini_get('apc.cache_by_default')) {
15     if (version_compare(phpversion('apc'), '3.0.12', '>=')) {
16         ini_set('apc.cache_by_default', 0);
17     } else {
18         fwrite(STDERR, 'Warning: APC <= 3.0.12 may cause fatal errors when running composer commands.'.PHP_EOL);
19         fwrite(STDERR, 'Update APC, or set apc.enable_cli or apc.cache_by_default to 0 in your php.ini.'.PHP_EOL);
20     }
21 }
22
23 Phar::mapPhar('composer.phar');
24 define('COMPOSER_DEV_WARNING_TIME', 1423113606);
25 require 'phar://composer.phar/bin/composer';
26
27 __HALT_COMPILER(); ?>\r
28 jr\0\0_\ 1\0\0\11\0\0\0\ 1\0\r\0\0\0composer.phar\0\0\0\0\11\0\0\0src/bootstrap.phpÅ\ 1\0\0\86p«TÅ\ 1\0\0¨¯2\90\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/IO/ConsoleIO.phpâ\ f\0\0\86p«Tâ\ f\0\0\ 4Ú N¶\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/IO/NullIO.php%\ 3\0\0\86p«T%\ 3\0\0~`\9f\ 4\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/IO/IOInterface.phpö\ 3\0\0\86p«Tö\ 3\0\0Gj¯:¶\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/IO/BaseIO.php\ 6\ 5\0\0\86p«T\ 6\ 5\0\0#\ e°.¶\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/IO/BufferIO.php+\ 4\0\0\86p«T+\ 4\0\0]\v\12í¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Command/RunScriptCommand.phpg
29 \0\0\86p«Tg
30 \0\0|̲D¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/DiagnoseCommand.phpÕ,\0\0\86p«TÕ,\0\0SÛD\r\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/ArchiveCommand.phpà\10\0\0\86p«Tà\10\0\0\8c-zG¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Command/ClearCacheCommand.phpB\ 5\0\0\86p«TB\ 5\0\0´\13Oã¶\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Command/Command.php\89\ 6\0\0\86p«T\89\ 6\0\0µ\fvJ¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Command/CreateProjectCommand.php+1\0\0\86p«T+1\0\0³\90~(¶\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Command/AboutCommand.php¶\ 2\0\0\86p«T¶\ 2\0\0\89²E\8f\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Command/ScriptAliasCommand.php\8d\ 5\0\0\86p«T\8d\ 5\0\0¢ò9J¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/ShowCommand.php~/\0\0\86p«T~/\0\0\83\8f­J¶\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/UpdateCommand.phpK\15\0\0\86p«TK\15\0\0x\v\91\1d\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/ConfigCommand.phpõ0\0\0\86p«Tõ0\0\0ÈBÂk¶\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/InstallCommand.php:\12\0\0\86p«T:\12\0\0]aI\94\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/ValidateCommand.phpq    \0\0\86p«Tq \0\0>Ù:\99\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/DependsCommand.phpu
31 \0\0\86p«Tu
32 \0\0¢\84°\99\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/SearchCommand.php]       \0\0\86p«T] \0\0\8bÔke¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Command/SelfUpdateCommand.php«\19\0\0\86p«T«\19\0\0Nºý'¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Command/LicensesCommand.php&\ e\0\0\86p«T&\ e\0\0¾D橶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/HomeCommand.php2\f\0\0\86p«T2\f\0\0yT\1e\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Command/RequireCommand.php§\17\0\0\86p«T§\17\0\0©ÿwÿ¶\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Command/DumpAutoloadCommand.phpÁ\ 6\0\0\86p«TÁ\ 6\0\0\807µh¶\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/GlobalCommand.php   \a\0\0\86p«T \a\0\0\16ƶ\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/RemoveCommand.phpv\ e\0\0\86p«Tv\ e\0\0B  «É¶\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Command/Helper/DialogHelper.php\9e\ 1\0\0\86p«T\9e\ 1\0\0\95\82\8c\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Command/StatusCommand.phpN   \0\0\86p«TN \0\0\1d\97ö$¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Command/InitCommand.php¥6\0\0\86p«T¥6\0\0szÌ@¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/VcsDownloader.phpÀ\11\0\0\86p«TÀ\11\0\0bûíL¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/RarDownloader.phpß\a\0\0\86p«Tß\a\0\0\15¾¼\7f\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/FileDownloader.php7\15\0\0\86p«T7\15\0\0¼À\90þ¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/SvnDownloader.php9\ f\0\0\86p«T9\ f\0\0]Òë\16\ 1\0\0\0\0\0\00\0\0\0src/Composer/Downloader/PearPackageExtractor.phpa\e\0\0\86p«Ta\e\0\0@ÔØ#¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Downloader/DownloadManager.php\87\11\0\0\86p«T\87\11\0\0\7f=
33\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Downloader/DownloaderInterface.phpÊ\ 1\0\0\86p«TÊ\ 1\0\0gs!l¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Downloader/TransportException.php\96\ 1\0\0\86p«T\96\ 1\0\0h"Br¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/PharDownloader.phpå\0\0\0\86p«Tå\0\0\0ÞÉ\1fç¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/TarDownloader.phpã\0\0\0\86p«Tã\0\0\0Í\92X?¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Downloader/HgDownloader.phpY\b\0\0\86p«TY\b\0\0\8bS¡Ù¶\ 1\0\0\0\0\0\01\0\0\0src/Composer/Downloader/ChangeReportInterface.phpÌ\0\0\0\86p«TÌ\0\0\0¯à¨¿¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Downloader/ArchiveDownloader.php\91\r\0\0\86p«T\91\r\0\0H\1c\9cö¶\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Downloader/FilesystemException.php\ f\ 1\0\0\86p«T\ f\ 1\0\0]T½\88\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Downloader/PerforceDownloader.phpn\a\0\0\86p«Tn\a\0\0E¹:¾¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/ZipDownloader.phpC\v\0\0\86p«TC\v\0\0\ 2]^+¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Downloader/GzipDownloader.phpÈ\ 5\0\0\86p«TÈ\ 5\0\0­äßж\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Downloader/GitDownloader.php/#\0\0\86p«T/#\0\0\rM(L¶\ 1\0\0\0\0\0\06\0\0\0src/Composer/Repository/InvalidRepositoryException.phpn\0\0\0\86p«Tn\0\0\0à\93ë\98\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Repository/ArrayRepository.php\15\f\0\0\86p«T\15\f\0\0´¯Þ/¶\ 1\0\0\0\0\0\00\0\0\0src/Composer/Repository/FilesystemRepository.phpÀ\ 4\0\0\86p«TÀ\ 4\0\0&xb£¶\ 1\0\0\0\0\0\07\0\0\0src/Composer/Repository/WritableRepositoryInterface.php\89\ 1\0\0\86p«T\89\ 1\0\0\91/sï¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Repository/PearRepository.php¡\15\0\0\86p«T¡\15\0\0O¬¶r¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/RepositoryManager.php³\a\0\0\86p«T³\a\0\033¸ï¶\ 1\0\0\0\0\0\03\0\0\0src/Composer/Repository/WritableArrayRepository.php\ f\ 3\0\0\86p«T\ f\ 3\0\0¾G\17\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Vcs/GitHubDriver.php^'\0\0\86p«T^'\0\0k\º<¶\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Vcs/GitBitbucketDriver.phpå\f\0\0\86p«Tå\f\0\0ìQ,L¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/GitDriver.phpg\15\0\0\86p«Tg\15\0\0×,»Ê¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/Vcs/PerforceDriver.php!
34 \0\0\86p«T!
35 \0\0\8d\80Ùk¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/SvnDriver.php²\19\0\0\86p«T²\19\0\0Ë W¶\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Vcs/VcsDriverInterface.php\89\ 2\0\0\86p«T\89\ 2\0\0pO㤶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Repository/Vcs/HgDriver.phpÛ\12\0\0\86p«TÛ\12\0\0\1e\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/Vcs/VcsDriver.phpÑ\ 5\0\0\86p«TÑ\ 5\0\0å%\ 6\ 1\0\0\0\0\0\01\0\0\0src/Composer/Repository/Vcs/HgBitbucketDriver.phpí\r\0\0\86p«Tí\r\0\0Ü8)׶\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/InstalledArrayRepository.php£\0\0\0\86p«T£\0\0\0/ö~>¶\ 1\0\0\0\0\0\07\0\0\0src/Composer/Repository/RepositorySecurityException.phpo\0\0\0\86p«To\0\0\0pÕ«ª¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Repository/VcsRepository.phpá\1c\0\0\86p«Tá\1c\0\0\17à¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/PlatformRepository.php\9d\ e\0\0\86p«T\9d\ e\0\0µáÇض\ 1\0\0\0\0\0\09\0\0\0src/Composer/Repository/InstalledFilesystemRepository.php£\0\0\0\86p«T£\0\0\0V
36 \95\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/CompositeRepository.php\b  \0\0\86p«T\b \0\0\ 3\ 1\0\0\0\0\0\08\0\0\0src/Composer/Repository/InstalledRepositoryInterface.php\87\0\0\0\86p«T\87\0\0\0\18£9p¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/ComposerRepository.phpa>\0\0\86p«Ta>\0\0\1c_\93ï¶\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/Pear/DependencyInfo.phpq\ 1\0\0\86p«Tq\ 1\0\0fºTò¶\ 1\0\0\0\0\0\08\0\0\0src/Composer/Repository/Pear/PackageDependencyParser.php%\16\0\0\86p«T%\16\0\0\ 6j?\93\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/ChannelInfo.phpÄ\ 1\0\0\86p«TÄ\ 1\0\0:T*ɶ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/Pear/ChannelReader.phpn\ 6\0\0\86p«Tn\ 6\0\0\1c\9a8\15\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/PackageInfo.php°\ 3\0\0\86p«T°\ 3\0\0\9f\r¸\f\ 1\0\0\0\0\0\05\0\0\0src/Composer/Repository/Pear/DependencyConstraint.phpq\ 2\0\0\86p«Tq\ 2\0\09\ e\17\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/Pear/ChannelRest11Reader.php& \0\0\86p«T& \0\0òUb\b\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Repository/Pear/ReleaseInfo.php\92\ 1\0\0\86p«T\92\ 1\0\0o\93\8aö\ 1\0\0\0\0\0\02\0\0\0src/Composer/Repository/Pear/BaseChannelReader.php6\ 5\0\0\86p«T6\ 5\0\0.fi!¶\ 1\0\0\0\0\0\04\0\0\0src/Composer/Repository/Pear/ChannelRest10Reader.phpÁ   \0\0\86p«TÁ \0\0\ 4O\80ë¶\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Repository/RepositoryInterface.phpÔ\ 1\0\0\86p«TÔ\ 1\0\0ò\90\9fɶ\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Repository/ArtifactRepository.phpá
37 \0\0\86p«Tá
38 \0\0xQoP¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Repository/PackageRepository.phpG\ 3\0\0\86p«TG\ 3\0\0í\ 4:k¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Package/CompletePackage.phpÿ\ 6\0\0\86p«Tÿ\ 6\0\0o+ã      ¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Package/Dumper/ArrayDumper.phpì\v\0\0\86p«Tì\v\0\0ª\96\7fæ¶\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Loader/InvalidPackageException.phpE\ 2\0\0\86p«TE\ 2\0\0xb\13¾¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Package/Loader/JsonLoader.phpù\ 1\0\0\86p«Tù\ 1\0\0!~\88\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Package/Loader/LoaderInterface.php²\0\0\0\86p«T²\0\0\0¦}úζ\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Package/Loader/ArrayLoader.phpð\19\0\0\86p«Tð\19\0\0\9f\1cak¶\ 1\0\0\0\0\0\05\0\0\0src/Composer/Package/Loader/ValidatingArrayLoader.php\1f.\0\0\86p«T\1f.\0\0n\ 4{Z¶\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/Loader/RootPackageLoader.phpN!\0\0\86p«TN!\0\0\91-^À¶\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/Package/Locker.php¢\1c\0\0\86p«T¢\1c\0\0\8bÝ:â¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Package/PackageInterface.php_\a\0\0\86p«T_\a\0\0æ\88¹\82\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Package/BasePackage.phpM\v\0\0\86p«TM\v\0\0·\v%þ¶\ 1\0\0\0\0\0\00\0\0\0src/Composer/Package/Version/VersionSelector.phpü\b\0\0\86p«Tü\b\0\0í\aM¬¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Package/Version/VersionParser.phpK-\0\0\86p«TK-\0\0·Ò\9a\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/CompletePackageInterface.phpõ\ 1\0\0\86p«Tõ\ 1\0\0¦Ê\81ò¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Package/RootPackageInterface.php´\ 1\0\0\86p«T´\ 1\0\0êqKж\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Package/RootPackage.phpn\ 4\0\0\86p«Tn\ 4\0\0áACO¶\ 1\0\0\0\0\0\03\0\0\0src/Composer/Package/Archiver/ArchiverInterface.phpï\0\0\0\86p«Tï\0\0\0\a<ʸ¶\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ComposerExcludeFilter.php\1f\ 1\0\0\86p«T\1f\ 1\0\0\8bSZ0¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Package/Archiver/PharArchiver.php[\ 3\0\0\86p«T[\ 3\0\0Ê5Íø¶\ 1\0\0\0\0\0\03\0\0\0src/Composer/Package/Archiver/BaseExcludeFilter.php\91\ 6\0\0\86p«T\91\ 6\0\0\11\ 4Mù¶\ 1\0\0\0\0\0\02\0\0\0src/Composer/Package/Archiver/GitExcludeFilter.phpw\ 3\0\0\86p«Tw\ 3\0\0LgU»¶\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/Archiver/ArchivableFilesFinder.php¿\ 4\0\0\86p«T¿\ 4\0\0\8ecEl¶\ 1\0\0\0\0\0\00\0\0\0src/Composer/Package/Archiver/ArchiveManager.php'\f\0\0\86p«T'\f\0\0é\e\89ô¶\ 1\0\0\0\0\0\01\0\0\0src/Composer/Package/Archiver/HgExcludeFilter.php\13\ 5\0\0\86p«T\13\ 5\0\0~\94\ e¸¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Package/RootAliasPackage.phpÞ\ 3\0\0\86p«TÞ\ 3\0\0Õ\12>\ 5\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Package/Package.phpÄ\1a\0\0\86p«TÄ\1a\0\0\84ô\13\11\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Package/AliasPackage.phpW\16\0\0\86p«TW\16\0\0T/YÁ¶\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/Package/Link.php*\ 5\0\0\86p«T*\ 5\0\0\1d_\92\85\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/LinkConstraint/EmptyConstraint.phpê\ 1\0\0\86p«Tê\ 1\0\0\0ì\e¾¶\ 1\0\0\0\0\0\07\0\0\0src/Composer/Package/LinkConstraint/MultiConstraint.phpg\ 4\0\0\86p«Tg\ 4\0\0s\153\ 6\ 1\0\0\0\0\0\09\0\0\0src/Composer/Package/LinkConstraint/VersionConstraint.phpÉ\b\0\0\86p«TÉ\b\0\0y?³Ø¶\ 1\0\0\0\0\0\0:\0\0\0src/Composer/Package/LinkConstraint/SpecificConstraint.phpp\ 2\0\0\86p«Tp\ 2\0\0_\84\88\ 1\0\0\0\0\0\0?\0\0\0src/Composer/Package/LinkConstraint/LinkConstraintInterface.php\15\ 1\0\0\86p«T\15\ 1\0\0åþ\87¢¶\ 1\0\0\0\0\0\0\16\0\0\0src/Composer/Cache.php\11\10\0\0\86p«T\11\10\0\0§û\99«¶\ 1\0\0\0\0\0\03\0\0\0src/Composer/DependencyResolver/PolicyInterface.php\91\ 1\0\0\86p«T\91\ 1\0\0B\18\9f¶¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/RuleSet.php%
39 \0\0\86p«T%
40 \0\09z    \ e\ 1\0\0\0\0\0\06\0\0\0src/Composer/DependencyResolver/SolverBugException.php\98\ 1\0\0\86p«T\98\ 1\0\0\7f"qN¶\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/DefaultPolicy.php\e\17\0\0\86p«T\e\17\0\0\89\16&\97\ 1\0\0\0\0\0\0-\0\0\0src/Composer/DependencyResolver/Decisions.phpQ\ f\0\0\86p«TQ\ f\0\0?\98¬$¶\ 1\0\0\0\0\0\01\0\0\0src/Composer/DependencyResolver/RuleWatchNode.phpç\ 3\0\0\86p«Tç\ 3\0\0\97Þ\12ȶ\ 1\0\0\0\0\0\0;\0\0\0src/Composer/DependencyResolver/SolverProblemsException.php%\ 4\0\0\86p«T%\ 4\0\0T\1aíP¶\ 1\0\0\0\0\0\0/\0\0\0src/Composer/DependencyResolver/Transaction.phpÔ\13\0\0\86p«TÔ\13\0\0 3ô\e\ 1\0\0\0\0\0\0@\0\0\0src/Composer/DependencyResolver/Operation/UninstallOperation.phpI\ 2\0\0\86p«TI\ 2\0\0FûÂɶ\ 1\0\0\0\0\0\0=\0\0\0src/Composer/DependencyResolver/Operation/UpdateOperation.phph\ 3\0\0\86p«Th\ 3\0\0öSÕ]¶\ 1\0\0\0\0\0\0I\0\0\0src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.phpÐ\ 2\0\0\86p«TÐ\ 2\0\0xUZa¶\ 1\0\0\0\0\0\0>\0\0\0src/Composer/DependencyResolver/Operation/InstallOperation.phpC\ 2\0\0\86p«TC\ 2\0\0´\õ*¶\ 1\0\0\0\0\0\0=\0\0\0src/Composer/DependencyResolver/Operation/SolverOperation.phpë\ 1\0\0\86p«Të\ 1\0\0ħÝ\94\ 1\0\0\0\0\0\0K\0\0\0src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.phpÖ\ 2\0\0\86p«TÖ\ 2\0\0_iÇ«¶\ 1\0\0\0\0\0\0@\0\0\0src/Composer/DependencyResolver/Operation/OperationInterface.phpÓ\0\0\0\86p«TÓ\0\0\0Ùâ&ä¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/DependencyResolver/Pool.php\85!\0\0\86p«T\85!\0\0~8ð6¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/DependencyResolver/Rule.php¡\14\0\0\86p«T¡\14\0\0z#¢Û¶\ 1\0\0\0\0\0\04\0\0\0src/Composer/DependencyResolver/RuleSetGenerator.php]\e\0\0\86p«T]\e\0\04\93Ñ9¶\ 1\0\0\0\0\0\0/\0\0\0src/Composer/DependencyResolver/DebugSolver.php\89\ 6\0\0\86p«T\89\ 6\0\0£Ò­\85\ 1\0\0\0\0\0\03\0\0\0src/Composer/DependencyResolver/RuleSetIterator.php\14\ 6\0\0\86p«T\14\ 6\0\0}õÇù¶\ 1\0\0\0\0\0\02\0\0\0src/Composer/DependencyResolver/RuleWatchChain.phpi\ 1\0\0\86p«Ti\ 1\0\0\9a\ 1\0\0\0\0\0\0*\0\0\0src/Composer/DependencyResolver/Solver.phpè6\0\0\86p«Tè6\0\0|£w0¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/Request.phpÌ\ 4\0\0\86p«TÌ\ 4\0\0\99¦òä¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/DependencyResolver/Problem.php\1c\12\0\0\86p«T\1c\12\0\0õüùÀ¶\ 1\0\0\0\0\0\02\0\0\0src/Composer/DependencyResolver/RuleWatchGraph.phpÜ\ 6\0\0\86p«TÜ\ 6\0\0\89\ 3\ f\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Config/ConfigSourceInterface.php®\ 1\0\0\86p«T®\ 1\0\06J[ª¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Config/JsonConfigSource.php}\f\0\0\86p«T}\f\0\0\ fèÇ ¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Plugin/PluginEvents.php¤\0\0\0\86p«T¤\0\0\00ïÞX¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Plugin/CommandEvent.phpâ\ 2\0\0\86p«Tâ\ 2\0\0³ÆÇW¶\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Plugin/PreFileDownloadEvent.php`\ 2\0\0\86p«T`\ 2\0\0\09-ζ\ 1\0\0\0\0\0\0'\0\0\0src/Composer/Plugin/PluginInterface.phpô\0\0\0\86p«Tô\0\0\0\f1\89\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Plugin/PluginManager.php\16\17\0\0\86p«T\16\17\0\0²$VU¶\ 1\0\0\0\0\0\0\18\0\0\0src/Composer/Factory.phpÔ,\0\0\86p«TÔ,\0\08ÈÍõ¶\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Util/Filesystem.php4&\0\0\86p«T4&\0\0Rl\97\87\ 1\0\0\0\0\0\0\1c\0\0\0src/Composer/Util/GitHub.php*\11\0\0\86p«T*\11\0\0³\8f?ȶ\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Util/ComposerMirror.php±\ 4\0\0\86p«T±\ 4\0\0­½øض\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Util/Perforce.php\b3\0\0\86p«T\b3\0\0\82=e.¶\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Util/ProcessExecutor.phpé\ 6\0\0\86p«Té\ 6\0\0{kßã¶\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Git.phpM\16\0\0\86p«TM\16\0\0L¢äã¶\ 1\0\0\0\0\0\0&\0\0\0src/Composer/Util/RemoteFilesystem.phpA%\0\0\86p«TA%\0\0\10?\v¨¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Util/StreamContextFactory.phpâ\f\0\0\86p«Tâ\f\0\0\eÐ\v\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Util/ConfigValidator.php2\ e\0\0\86p«T2\ e\0\0ö\137.¶\ 1\0\0\0\0\0\0"\0\0\0src/Composer/Util/ErrorHandler.php\14\ 2\0\0\86p«T\14\ 2\0\0´@\85æ¶\ 1\0\0\0\0\0\0 \0\0\0src/Composer/Util/AuthHelper.phpÌ\ 3\0\0\86p«TÌ\ 3\0\0\9c¼\8dÀ¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Util/SpdxLicenseIdentifier.php6
41 \0\0\86p«T6
42 \0\0Ä6»o¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Util/NoProxyPattern.php¾\ 6\0\0\86p«T¾\ 6\0\0Z+°m¶\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Util/Svn.php\17\11\0\0\86p«T\17\11\0\0^îÕ\12\ 1\0\0\0\0\0\0\19\0\0\0src/Composer/Composer.php)       \0\0\86p«T) \0\0\1a\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Json/JsonManipulator.php\12%\0\0\86p«T\12%\0\0\17¬¥ô¶\ 1\0\0\0\0\0\0\1e\0\0\0src/Composer/Json/JsonFile.phpy\10\0\0\86p«Ty\10\0\0¼è\7fî¶\ 1\0\0\0\0\0\0#\0\0\0src/Composer/Json/JsonFormatter.php\a\ 6\0\0\86p«T\a\ 6\0\0c\96]Y¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Json/JsonValidationException.php]\ 1\0\0\86p«T]\ 1\0\0\10\91#\97\ 1\0\0\0\0\0\0\17\0\0\0src/Composer/Config.php\9a\17\0\0\86p«T\9a\17\0\0¡Ú\90¥¶\ 1\0\0\0\0\0\09\0\0\0src/Composer/EventDispatcher/EventSubscriberInterface.php©\0\0\0\86p«T©\0\0\0\ 1\ 1\0\0\0\0\0\0&\0\0\0src/Composer/EventDispatcher/Event.php \ 2\0\0\86p«T \ 2\0\0±\99jï¶\ 1\0\0\0\0\0\00\0\0\0src/Composer/EventDispatcher/EventDispatcher.php\93\19\0\0\86p«T\93\19\0\0ê®Ñ\93\ 1\0\0\0\0\0\0\1d\0\0\0src/Composer/Script/Event.phpµ\ 2\0\0\86p«Tµ\ 2\0\0lt¦M¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/ScriptEvents.phpH\ 4\0\0\86p«TH\ 4\0\0¯ðܲ¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/CommandEvent.phpW\0\0\0\86p«TW\0\0\0£VZt¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Script/PackageEvent.php÷\ 1\0\0\86p«T÷\ 1\0\0a\16± ¶\ 1\0\0\0\0\0\0)\0\0\0src/Composer/Installer/InstallerEvent.php\97\ 5\0\0\86p«T\97\ 5\0\0üa\18\1f\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/NoopInstaller.php+\ 5\0\0\86p«T+\ 5\0\0À·M}¶\ 1\0\0\0\0\0\0/\0\0\0src/Composer/Installer/MetapackageInstaller.php\9c\ 4\0\0\86p«T\9c\ 4\0\0Æ\12Å!¶\ 1\0\0\0\0\0\0(\0\0\0src/Composer/Installer/PearInstaller.phpQ\11\0\0\86p«TQ\11\0\0@W\89\8a\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Installer/ProjectInstaller.php\1d\ 6\0\0\86p«T\1d\ 6\0\0*0@P¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Installer/LibraryInstaller.phpy\1c\0\0\86p«Ty\1c\0\0
43 M\r°¶\ 1\0\0\0\0\0\0.\0\0\0src/Composer/Installer/InstallationManager.php@\14\0\0\86p«T@\14\0\0\9bö«\ 3\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/InstallerEvents.phpÞ\0\0\0\86p«TÞ\0\0\0ì\9f@G¶\ 1\0\0\0\0\0\0*\0\0\0src/Composer/Installer/PluginInstaller.phpJ\ 6\0\0\86p«TJ\ 6\0\0«\10èV¶\ 1\0\0\0\0\0\0-\0\0\0src/Composer/Installer/InstallerInterface.phpÅ\ 2\0\0\86p«TÅ\ 2\0\0HS\93¡¶\ 1\0\0\0\0\0\0$\0\0\0src/Composer/Console/Application.phpü \0\0\86p«Tü \0\0Çd\13Û¶\ 1\0\0\0\0\0\0,\0\0\0src/Composer/Console/HtmlOutputFormatter.phpÐ\ 5\0\0\86p«TÐ\ 5\0\0ÝF×ê¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Autoload/AutoloadGenerator.phpyC\0\0\86p«TyC\0\0Ln¿g¶\ 1\0\0\0\0\0\0+\0\0\0src/Composer/Autoload/ClassMapGenerator.phpE\ e\0\0\86p«TE\ e\0\0Dd\85\ 1\0\0\0\0\0\0\1a\0\0\0src/Composer/Installer.phpÕr\0\0\86p«TÕr\0\0\9a\89_µ¶\ 1\0\0\0\0\0\0%\0\0\0src/Composer/Autoload/ClassLoader.phpç-\0\0\86p«Tç-\0\0\ 5ï0Ú¶\ 1\0\0\0\0\0\0\18\0\0\0res/spdx-identifier.jsonD\10\0\0\86p«TD\10\0\0*Oiò¶\ 1\0\0\0\0\0\0\18\0\0\0res/composer-schema.json_O\0\0\86p«T_O\0\0\87}ÖT¶\ 1\0\0\0\0\0\0\1f\0\0\0src/Composer/IO/hiddeninput.exe\0$\0\0\86p«T\0$\0\0\95\8d¥v¶\ 1\0\0\0\0\0\0?\0\0\0vendor/symfony/process/Symfony/Component/Process/PhpProcess.php\ f\ 3\0\0\86p«T\ f\ 3\0\08ZÔ·¶\ 1\0\0\0\0\0\0E\0\0\0vendor/symfony/process/Symfony/Component/Process/ExecutableFinder.php\8e\ 4\0\0\86p«T\8e\ 4\0\0ëËXʶ\ 1\0\0\0\0\0\0<\0\0\0vendor/symfony/process/Symfony/Component/Process/Process.phpuN\0\0\86p«TuN\0\0@íÃ\81\ 1\0\0\0\0\0\0C\0\0\0vendor/symfony/process/Symfony/Component/Process/ProcessBuilder.php\ 3\v\0\0\86p«T\ 3\v\0\0\848<²¶\ 1\0\0\0\0\0\0A\0\0\0vendor/symfony/process/Symfony/Component/Process/ProcessUtils.php\94\ 5\0\0\86p«T\94\ 5\0\00]ä/¶\ 1\0\0\0\0\0\0W\0\0\0vendor/symfony/process/Symfony/Component/Process/Exception/ProcessTimedOutException.php\1f\ 4\0\0\86p«T\1f\ 4\0\0.      Ãá¶\ 1\0\0\0\0\0\0Q\0\0\0vendor/symfony/process/Symfony/Component/Process/Exception/ExceptionInterface.phpf\0\0\0\86p«Tf\0\0\0]ö>T¶\ 1\0\0\0\0\0\0O\0\0\0vendor/symfony/process/Symfony/Component/Process/Exception/RuntimeException.php\98\0\0\0\86p«T\98\0\0\0¢\eØ:¶\ 1\0\0\0\0\0\0M\0\0\0vendor/symfony/process/Symfony/Component/Process/Exception/LogicException.php\94\0\0\0\86p«T\94\0\0\0 ³ãñ¶\ 1\0\0\0\0\0\0U\0\0\0vendor/symfony/process/Symfony/Component/Process/Exception/ProcessFailedException.php<\ 3\0\0\86p«T<\ 3\0\0"wÛn¶\ 1\0\0\0\0\0\0W\0\0\0vendor/symfony/process/Symfony/Component/Process/Exception/InvalidArgumentException.php¨\0\0\0\86p«T¨\0\0\0ÐÀ+_¶\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/process/Symfony/Component/Process/PhpExecutableFinder.php\1c\ 4\0\0\86p«T\1c\ 4\0\0¦Fж\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/process/Symfony/Component/Process/Pipes/PipesInterface.phpD\ 1\0\0\86p«TD\ 1\0\0vØ\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/process/Symfony/Component/Process/Pipes/AbstractPipes.php\0\ 3\0\0\86p«T\0\ 3\0\0\98|¥¾¶\ 1\0\0\0\0\0\0G\0\0\0vendor/symfony/process/Symfony/Component/Process/Pipes/WindowsPipes.phpÄ\ e\0\0\86p«TÄ\ e\0\0{침¶\ 1\0\0\0\0\0\0D\0\0\0vendor/symfony/process/Symfony/Component/Process/Pipes/UnixPipes.php¬\v\0\0\86p«T¬\v\0\0i\14੶\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/console/Symfony/Component/Console/Command/HelpCommand.php1\a\0\0\86p«T1\a\0\0ý\1d\80\94\ 1\0\0\0\0\0\0D\0\0\0vendor/symfony/console/Symfony/Component/Console/Command/Command.phpë\e\0\0\86p«Të\e\0\0\ eض\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/console/Symfony/Component/Console/Command/ListCommand.php³\a\0\0\86p«T³\a\0\0V\ 3Óé¶\ 1\0\0\0\0\0\0M\0\0\0vendor/symfony/console/Symfony/Component/Console/Tester/ApplicationTester.phpÔ\ 5\0\0\86p«TÔ\ 5\0\0¬ì¤d¶\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/console/Symfony/Component/Console/Tester/CommandTester.php\90\ 6\0\0\86p«T\90\ 6\0\0H»â`¶\ 1\0\0\0\0\0\0X\0\0\0vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php\b\ 5\0\0\86p«T\b\ 5\0\0y\bI'¶\ 1\0\0\0\0\0\0S\0\0\0vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyle.phpÅ\ f\0\0\86p«TÅ\ f\0\0ÂÚ³\15\ 1\0\0\0\0\0\0\\0\0\0vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php\8e\ 1\0\0\86p«T\8e\ 1\0\0öëÄ=¶\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatter.php\88\f\0\0\86p«T\88\f\0\0+ÂF5¶\ 1\0\0\0\0\0\0W\0\0\0vendor/symfony/console/Symfony/Component/Console/Formatter/OutputFormatterInterface.php\98\ 1\0\0\86p«T\98\ 1\0\03l~´¶\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/console/Symfony/Component/Console/Application.php{Q\0\0\86p«T{Q\0\0W\1f\võ¶\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/InputArgument.php\9e\ 5\0\0\86p«T\9e\ 5\0\0K]ìi¶\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/Input.php\12
44 \0\0\86p«T\12
45 \0\0ÇýT\ 5\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/StringInput.php\8b\ 5\0\0\86p«T\8b\ 5\0\0\86uný¶\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/InputOption.php«\v\0\0\86p«T«\v\0\0ê\86®½¶\ 1\0\0\0\0\0\0D\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/ArgvInput.phpÄ\13\0\0\86p«TÄ\13\0\0ÌSGd¶\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/InputInterface.php \ 3\0\0\86p«T \ 3\0\09\94øǶ\ 1\0\0\0\0\0\0E\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/ArrayInput.phpõ       \0\0\86p«Tõ \0\0É×\81\99\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/InputAwareInterface.php\9a\0\0\0\86p«T\9a\0\0\0\87jT\9f\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/console/Symfony/Component/Console/Input/InputDefinition.php\v\17\0\0\86p«T\v\17\0\0\98£JM¶\ 1\0\0\0\0\0\0:\0\0\0vendor/symfony/console/Symfony/Component/Console/Shell.php.\ f\0\0\86p«T.\ f\0\0þÉ\8e\87\ 1\0\0\0\0\0\0L\0\0\0vendor/symfony/console/Symfony/Component/Console/Question/ChoiceQuestion.phpZ\a\0\0\86p«TZ\a\0\0C8\17\ 1\0\0\0\0\0\0R\0\0\0vendor/symfony/console/Symfony/Component/Console/Question/ConfirmationQuestion.php@\ 2\0\0\86p«T@\ 2\0\0Y\93B;¶\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/console/Symfony/Component/Console/Question/Question.php®\b\0\0\86p«T®\b\0\0.e8Ö¶\ 1\0\0\0\0\0\0B\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/Output.php§\b\0\0\86p«T§\b\0\0\1cÚ _¶\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/NullOutput.php¿\ 3\0\0\86p«T¿\ 3\0\0`5E˶\ 1\0\0\0\0\0\0R\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutputInterface.phpå\0\0\0\86p«Tå\0\0\0rNô\0\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/StreamOutput.php¢\ 4\0\0\86p«T¢\ 4\0\0\1a\ 6ü0¶\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/BufferedOutput.php_\ 1\0\0\86p«T_\ 1\0\0ûBÍ·¶\ 1\0\0\0\0\0\0K\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/OutputInterface.phpI\ 3\0\0\86p«TI\ 3\0\0ÈâãB¶\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/console/Symfony/Component/Console/Output/ConsoleOutput.php\14\ 5\0\0\86p«T\14\ 5\0\0jå¬\ 6\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/console/Symfony/Component/Console/Logger/ConsoleLogger.php9  \0\0\86p«T9 \0\0ã\ 3\99ç¶\ 1\0\0\0\0\0\0S\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/DescriptorInterface.phpü\0\0\0\86p«Tü\0\0\0±Q\aµ¶\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/TextDescriptor.php4\1a\0\0\86p«T4\1a\0\0Ô±\96\ 1\0\0\0\0\0\0M\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/XmlDescriptor.php\9e\1c\0\0\86p«T\9e\1c\0\0Ò\91¦j¶\ 1\0\0\0\0\0\0R\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php\16\ e\0\0\86p«T\16\ e\0\0ìC/\83\ 1\0\0\0\0\0\0V\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/ApplicationDescription.php÷\a\0\0\86p«T÷\a\0\0)Ißð¶\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/Descriptor.phpZ\a\0\0\86p«TZ\a\0\0v;\83ö¶\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/console/Symfony/Component/Console/Descriptor/JsonDescriptor.php0\r\0\0\86p«T0\r\0\0\vFÄ`¶\ 1\0\0\0\0\0\0K\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/HelperInterface.phpï\0\0\0\86p«Tï\0\0\0=e\e\f\ 1\0\0\0\0\0\0G\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/TableHelper.phpß
46 \0\0\86p«Tß
47 \0\0\85kzζ\ 1\0\0\0\0\0\0A\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/Table.php\ 6\17\0\0\86p«T\ 6\17\0\0µlk\98\ 1\0\0\0\0\0\0G\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/ProgressBar.php\15$\0\0\86p«T\15$\0\02\8c5J¶\ 1\0\0\0\0\0\0L\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/DescriptorHelper.php9\ 5\0\0\86p«T9\ 5\0\0ûùäð¶\ 1\0\0\0\0\0\0K\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/FormatterHelper.php\1e\ 4\0\0\86p«T\1e\ 4\0\0\9eI\82\81\ 1\0\0\0\0\0\0P\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/DebugFormatterHelper.phpm\b\0\0\86p«Tm\b\0\0ò¯s>¶\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/ProcessHelper.phpâ\b\0\0\86p«Tâ\b\0\0|\7f̼¶\ 1\0\0\0\0\0\0E\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/HelperSet.php/\ 4\0\0\86p«T/\ 4\0\0âw\0\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/DialogHelper.phpÓ\e\0\0\86p«TÓ\e\0\0jWð\90\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/QuestionHelper.phpp\18\0\0\86p«Tp\18\0\0¿7(ݶ\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/TableSeparator.php[\0\0\0\86p«T[\0\0\0LV\16¡¶\ 1\0\0\0\0\0\0B\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/Helper.phpß\ 6\0\0\86p«Tß\ 6\0\0\ 1ã¶\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/ProgressHelper.php\83\19\0\0\86p«T\83\19\0\0ê\ 5ëä¶\ 1\0\0\0\0\0\0L\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/InputAwareHelper.phpc\ 1\0\0\86p«Tc\ 1\0\0ñø\90\ 1\0\0\0\0\0\0F\0\0\0vendor/symfony/console/Symfony/Component/Console/Helper/TableStyle.phpÕ\b\0\0\86p«TÕ\b\0\0æ"ðù¶\ 1\0\0\0\0\0\0G\0\0\0vendor/symfony/console/Symfony/Component/Console/Event/ConsoleEvent.phpÅ\ 2\0\0\86p«TÅ\ 2\0\0ÒxÛ\¶\ 1\0\0\0\0\0\0P\0\0\0vendor/symfony/console/Symfony/Component/Console/Event/ConsoleTerminateEvent.phpz\ 2\0\0\86p«Tz\ 2\0\0³,îL¶\ 1\0\0\0\0\0\0P\0\0\0vendor/symfony/console/Symfony/Component/Console/Event/ConsoleExceptionEvent.php\12\ 3\0\0\86p«T\12\ 3\0\0á\162é¶\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/console/Symfony/Component/Console/Event/ConsoleCommandEvent.php²\ 1\0\0\86p«T²\ 1\0\0Zk\89\ 1\0\0\0\0\0\0B\0\0\0vendor/symfony/console/Symfony/Component/Console/ConsoleEvents.phpï\0\0\0\86p«Tï\0\0\0\rÕH¸¶\ 1\0\0\0\0\0\09\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Finder.phpÍ \0\0\86p«TÍ \0\0ÿÛ¹1¶\ 1\0\0\0\0\0\0@\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Shell/Command.php©
48 \0\0\86p«T©
49 \0\0V\82\84\ 1\0\0\0\0\0\0>\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Shell/Shell.phpé\ 3\0\0\86p«Té\ 3\0\0¿ëÛ\95\ 1\0\0\0\0\0\0C\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Expression/Regex.php\81\ e\0\0\86p«T\81\ e\0\0S7Pæ¶\ 1\0\0\0\0\0\0B\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Expression/Glob.php¡\a\0\0\86p«T¡\a\0\0  V¿¶\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Expression/Expression.php}\ 5\0\0\86p«T}\ 5\0\0/·cð¶\ 1\0\0\0\0\0\0L\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Expression/ValueInterface.php;\ 1\0\0\86p«T;\ 1\0\0\vîãÓ¶\ 1\0\0\0\0\0\0K\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Adapter/AdapterInterface.php¯\ 3\0\0\86p«T¯\ 3\0\0\8b\béȶ\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Adapter/BsdFindAdapter.php{\ 6\0\0\86p«T{\ 6\0\0Q,D2¶\ 1\0\0\0\0\0\0I\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Adapter/GnuFindAdapter.php^\ 6\0\0\86p«T^\ 6\0\0ßz\98\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractAdapter.php¤
50 \0\0\86p«T¤
51 \0\0¢)z9¶\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Adapter/AbstractFindAdapter.phpÛ\18\0\0\86p«TÛ\18\0\0SõT´¶\ 1\0\0\0\0\0\0E\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Adapter/PhpAdapter.php+\a\0\0\86p«T+\a\0\0&\98îÒ¶\ 1\0\0\0\0\0\07\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Glob.php\r\ 5\0\0\86p«T\r\ 5\0\0z\9dø
52\ 1\0\0\0\0\0\0T\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/DepthRangeFilterIterator.phpð\ 1\0\0\86p«Tð\ 1\0\0ß0\99\ 4\ 1\0\0\0\0\0\0L\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/SortableIterator.phpÞ\ 5\0\0\86p«TÞ\ 5\0\0ö³\ 6\ 1\0\0\0\0\0\0U\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilecontentFilterIterator.php#\ 3\0\0\86p«T#\ 3\0\0Ú_VǶ\ 1\0\0\0\0\0\0M\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilePathsIterator.php\8d\ 5\0\0\86p«T\8d\ 5\0\0ýòäQ¶\ 1\0\0\0\0\0\0S\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/SizeRangeFilterIterator.phpg\ 2\0\0\86p«Tg\ 2\0\0\97é¶\ 1\0\0\0\0\0\0Z\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php\94\ 2\0\0\86p«T\94\ 2\0\0"ÖóÁ¶\ 1\0\0\0\0\0\0J\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilterIterator.php\86\ 2\0\0\86p«T\86\ 2\0\00£¾Ô¶\ 1\0\0\0\0\0\0V\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/MultiplePcreFilterIterator.phpØ\ 2\0\0\86p«TØ\ 2\0\0\ 4Òù\93\ 1\0\0\0\0\0\0P\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/CustomFilterIterator.php]\ 2\0\0\86p«T]\ 2\0\0tà±µ¶\ 1\0\0\0\0\0\0R\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/FilenameFilterIterator.php\87\ 2\0\0\86p«T\87\ 2\0\0\92\v\ 1\0\0\0\0\0\0S\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.phpz\ 2\0\0\86p«Tz\ 2\0\0\7f}\17¢¶\ 1\0\0\0\0\0\0R\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/FileTypeFilterIterator.php\\ 2\0\0\86p«T\\ 2\0\0p\91'\98\ 1\0\0\0\0\0\0V\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/RecursiveDirectoryIterator.phpY\ 6\0\0\86p«TY\ 6\0\0êÓÊܶ\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Iterator/PathFilterIterator.phpÀ\ 2\0\0\86p«TÀ\ 2\0\0Í"dÕ¶\ 1\0\0\0\0\0\0L\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Comparator/DateComparator.php%\ 3\0\0\86p«T%\ 3\0\0L¿EǶ\ 1\0\0\0\0\0\0N\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Comparator/NumberComparator.phpy\ 3\0\0\86p«Ty\ 3\0\0"`\14Û¶\ 1\0\0\0\0\0\0H\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Comparator/Comparator.php\8c\ 3\0\0\86p«T\8c\ 3\0\0\16wþT¶\ 1\0\0\0\0\0\0R\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Exception/AccessDeniedException.php\84\0\0\0\86p«T\84\0\0\0½¾s\9c\ 1\0\0\0\0\0\0O\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Exception/ExceptionInterface.php\84\0\0\0\86p«T\84\0\0\0\1cGz-¶\ 1\0\0\0\0\0\0Z\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Exception/OperationNotPermitedException.php\8a\0\0\0\86p«T\8a\0\0\0U\1288¶\ 1\0\0\0\0\0\0T\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Exception/AdapterFailureException.php\16\ 2\0\0\86p«T\16\ 2\0\0m\8c_,¶\ 1\0\0\0\0\0\0Y\0\0\0vendor/symfony/finder/Symfony/Component/Finder/Exception/ShellCommandFailureException.php$\ 2\0\0\86p«T$\ 2\0\0C\94sÓ¶\ 1\0\0\0\0\0\0>\0\0\0vendor/symfony/finder/Symfony/Component/Finder/SplFileInfo.phpû\ 2\0\0\86p«Tû\ 2\0\0\91\ 5\86\ 1\0\0\0\0\0\04\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/Undefined.php>\0\0\0\86p«T>\0\0\0ÿq\9f\9f\ 1\0\0\0\0\0\05\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php)1\0\0\86p«T)1\0\0?5R3¶\ 1\0\0\0\0\0\00\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/Lexer.php\ 4\ f\0\0\86p«T\ 4\ f\0\0ÒÅ~\97\ 1\0\0\0\0\0\0;\0\0\0vendor/seld/jsonlint/src/Seld/JsonLint/ParsingException.php\1e\ 1\0\0\86p«T\1e\ 1\0\0\89²\10ñ¶\ 1\0\0\0\0\0\0?\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/RefResolver.php|
53 \0\0\86p«T|
54 \0\0\99&\r\ 1\0\0\0\0\0\0I\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Undefined.phpl\17\0\0\86p«Tl\17\0\0\83\rÎ\89\ 1\0\0\0\0\0\0D\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Type.phph\b\0\0\86p«Th\b\0\0õ\1cd϶\ 1\0\0\0\0\0\0F\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Schema.php\16\ 2\0\0\86p«T\16\ 2\0\0]\12ÜÙ¶\ 1\0\0\0\0\0\0F\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Number.php«\b\0\0\86p«T«\b\0\0\9bçI)¶\ 1\0\0\0\0\0\0F\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Object.php¾
55 \0\0\86p«T¾
56 \0\0|Ò\F¶\ 1\0\0\0\0\0\0S\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.phpN\ 1\0\0\86p«TN\ 1\0\0øÆMy¶\ 1\0\0\0\0\0\0J\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php9\ e\0\0\86p«T9\ e\0\0éð°#¶\ 1\0\0\0\0\0\0J\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Collection.phpý\b\0\0\86p«Tý\b\0\0Ç\f;ÿ¶\ 1\0\0\0\0\0\0D\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Enum.phpè\ 1\0\0\86p«Tè\ 1\0\0ê\10vĶ\ 1\0\0\0\0\0\0F\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Format.phpí\r\0\0\86p«Tí\r\0\0á\94\18\r\ 1\0\0\0\0\0\0F\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/String.php\9f\ 3\0\0\86p«T\9f\ 3\0\0\8d\88på¶\ 1\0\0\0\0\0\0R\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/UriResolverException.phpj\0\0\0\86p«Tj\0\0\0SÓdz¶\ 1\0\0\0\0\0\0W\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/ResourceNotFoundException.phpo\0\0\0\86p«To\0\0\0Æ$"Ŷ\ 1\0\0\0\0\0\0]\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSchemaMediaTypeException.phpv\0\0\0\86p«Tv\0\0\0\ 2\8aCÓ¶\ 1\0\0\0\0\0\0W\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidSourceUriException.phpw\0\0\0\86p«Tw\0\0\0N-ò[¶\ 1\0\0\0\0\0\0S\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/JsonDecodingException.phpÞ\ 2\0\0\86p«TÞ\ 2\0\0\86¾©\91\ 1\0\0\0\0\0\0V\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Exception/InvalidArgumentException.phpv\0\0\0\86p«Tv\0\0\0¬ «"¶\ 1\0\0\0\0\0\0C\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriResolver.php®     \0\0\86p«T® \0\0àP¾¡¶\ 1\0\0\0\0\0\0D\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php\96\13\0\0\86p«T\96\13\0\0ªÿ¨Ü¶\ 1\0\0\0\0\0\0T\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.phpÜ\0\0\0\86p«TÜ\0\0\0\e]j\1c\ 1\0\0\0\0\0\0R\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/FileGetContents.phpÑ\ 4\0\0\86p«TÑ\ 4\0\0æ\87¨\12\ 1\0\0\0\0\0\0X\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/UriRetrieverInterface.php©\0\0\0\86p«T©\0\0\0\ 6\ 3CO¶\ 1\0\0\0\0\0\0G\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/Curl.phpt\ 4\0\0\86p«Tt\ 4\0\0I·ý\0\ 1\0\0\0\0\0\0R\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php^\ 2\0\0\86p«T^\ 2\0\0"ß6o¶\ 1\0\0\0\0\0\0=\0\0\0vendor/justinrainbow/json-schema/src/JsonSchema/Validator.phps\ 2\0\0\86p«Ts\ 2\0\0ô\84\7f\ 1\0\0\0\0\0\0\13\0\0\0vendor/autoload.php\91\0\0\0\86p«T\91\0\0\0ï4\9f\8d\ 1\0\0\0\0\0\0'\0\0\0vendor/composer/autoload_namespaces.php±\ 1\0\0\86p«T±\ 1\0\0\13ã¶\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/autoload_psr4.php²\0\0\0\86p«T²\0\0\0Ô\81¨Ð¶\ 1\0\0\0\0\0\0%\0\0\0vendor/composer/autoload_classmap.phpd\0\0\0\86p«Td\0\0\0Z¡¦H¶\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/autoload_real.phpK\ 4\0\0\86p«TK\ 4\0\0J1·\12\ 1\0\0\0\0\0\0!\0\0\0vendor/composer/include_paths.php\9f\ 1\0\0\86p«T\9f\ 1\0\0§Åᢶ\ 1\0\0\0\0\0\0\1f\0\0\0vendor/composer/ClassLoader.php\97\13\0\0\86p«T\97\13\0\0\86\ 1\0\0\0\0\0\0\f\0\0\0bin/composern\ 4\0\0\86p«Tn\ 4\0\0\1f\96\85\ 1\0\0\0\0\0\0\a\0\0\0LICENSE3\ 4\0\0\86p«T3\ 4\0\0\v\812\v\ 1\0\0\0\0\0\0<?php
57
58
59
60
61
62
63
64
65
66
67
68 function includeIfExists($file)
69 {
70 return file_exists($file) ? include $file : false;
71 }
72
73 if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../autoload.php'))) {
74 echo 'You must set up the project dependencies, run the following commands:'.PHP_EOL.
75 'curl -sS https://getcomposer.org/installer | php'.PHP_EOL.
76 'php composer.phar install'.PHP_EOL;
77 exit(1);
78 }
79
80 return $loader;
81 <?php
82
83
84
85
86
87
88
89
90
91
92
93 namespace Composer\IO;
94
95 use Symfony\Component\Console\Input\InputInterface;
96 use Symfony\Component\Console\Output\OutputInterface;
97 use Symfony\Component\Console\Helper\HelperSet;
98 use Symfony\Component\Process\ExecutableFinder;
99
100
101
102
103
104
105
106 class ConsoleIO extends BaseIO
107 {
108 protected $input;
109 protected $output;
110 protected $helperSet;
111 protected $lastMessage;
112 private $startTime;
113
114
115
116
117
118
119
120
121 public function __construct(InputInterface $input, OutputInterface $output, HelperSet $helperSet)
122 {
123 $this->input = $input;
124 $this->output = $output;
125 $this->helperSet = $helperSet;
126 }
127
128 public function enableDebugging($startTime)
129 {
130 $this->startTime = $startTime;
131 }
132
133
134
135
136 public function isInteractive()
137 {
138 return $this->input->isInteractive();
139 }
140
141
142
143
144 public function isDecorated()
145 {
146 return $this->output->isDecorated();
147 }
148
149
150
151
152 public function isVerbose()
153 {
154 return $this->output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE;
155 }
156
157
158
159
160 public function isVeryVerbose()
161 {
162 return $this->output->getVerbosity() >= 3; 
163  }
164
165
166
167
168 public function isDebug()
169 {
170 return $this->output->getVerbosity() >= 4; 
171  }
172
173
174
175
176 public function write($messages, $newline = true)
177 {
178 if (null !== $this->startTime) {
179 $messages = (array) $messages;
180 $messages[0] = sprintf(
181 '[%.1fMB/%.2fs] %s',
182 memory_get_usage() / 1024 / 1024,
183 microtime(true) - $this->startTime,
184 $messages[0]
185 );
186 }
187 $this->output->write($messages, $newline);
188 $this->lastMessage = join($newline ? "\n" : '', (array) $messages);
189 }
190
191
192
193
194 public function overwrite($messages, $newline = true, $size = null)
195 {
196 if (!$this->output->isDecorated()) {
197 if (!$messages) {
198 return;
199 }
200
201 return $this->write($messages, count($messages) === 1 || $newline);
202 }
203
204
205  $messages = join($newline ? "\n" : '', (array) $messages);
206
207
208  if (!isset($size)) {
209
210  $size = strlen(strip_tags($this->lastMessage));
211 }
212
213  $this->write(str_repeat("\x08", $size), false);
214
215
216  $this->write($messages, false);
217
218 $fill = $size - strlen(strip_tags($messages));
219 if ($fill > 0) {
220
221  $this->write(str_repeat(' ', $fill), false);
222
223  $this->write(str_repeat("\x08", $fill), false);
224 }
225
226 if ($newline) {
227 $this->write('');
228 }
229 $this->lastMessage = $messages;
230 }
231
232
233
234
235 public function ask($question, $default = null)
236 {
237 return $this->helperSet->get('dialog')->ask($this->output, $question, $default);
238 }
239
240
241
242
243 public function askConfirmation($question, $default = true)
244 {
245 return $this->helperSet->get('dialog')->askConfirmation($this->output, $question, $default);
246 }
247
248
249
250
251 public function askAndValidate($question, $validator, $attempts = false, $default = null)
252 {
253 return $this->helperSet->get('dialog')->askAndValidate($this->output, $question, $validator, $attempts, $default);
254 }
255
256
257
258
259 public function askAndHideAnswer($question)
260 {
261
262  if (defined('PHP_WINDOWS_VERSION_BUILD')) {
263 $finder = new ExecutableFinder();
264
265
266  if ($finder->find('bash') && $finder->find('stty')) {
267 $this->write($question, false);
268 $value = rtrim(shell_exec('bash -c "stty -echo; read -n0 discard; read -r mypassword; stty echo; echo $mypassword"'));
269 $this->write('');
270
271 return $value;
272 }
273
274
275  $exe = __DIR__.'\\hiddeninput.exe';
276
277
278  if ('phar:' === substr(__FILE__, 0, 5)) {
279 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
280
281
282  
283  $source = fopen(__DIR__.'\\hiddeninput.exe', 'r');
284 $target = fopen($tmpExe, 'w+');
285 stream_copy_to_stream($source, $target);
286 fclose($source);
287 fclose($target);
288 unset($source, $target);
289
290 $exe = $tmpExe;
291 }
292
293 $this->write($question, false);
294 $value = rtrim(shell_exec($exe));
295 $this->write('');
296
297
298  if (isset($tmpExe)) {
299 unlink($tmpExe);
300 }
301
302 return $value;
303 }
304
305 if (file_exists('/usr/bin/env')) {
306
307  $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
308 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
309 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
310 $shell = $sh;
311 break;
312 }
313 }
314 if (isset($shell)) {
315 $this->write($question, false);
316 $readCmd = ($shell === 'csh') ? 'set mypassword = $<' : 'read -r mypassword';
317 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
318 $value = rtrim(shell_exec($command));
319 $this->write('');
320
321 return $value;
322 }
323 }
324
325
326  return $this->ask($question);
327 }
328 }
329 <?php
330
331
332
333
334
335
336
337
338
339
340
341 namespace Composer\IO;
342
343
344
345
346
347
348 class NullIO extends BaseIO
349 {
350
351
352
353 public function isInteractive()
354 {
355 return false;
356 }
357
358
359
360
361 public function isVerbose()
362 {
363 return false;
364 }
365
366
367
368
369 public function isVeryVerbose()
370 {
371 return false;
372 }
373
374
375
376
377 public function isDebug()
378 {
379 return false;
380 }
381
382
383
384
385 public function isDecorated()
386 {
387 return false;
388 }
389
390
391
392
393 public function write($messages, $newline = true)
394 {
395 }
396
397
398
399
400 public function overwrite($messages, $newline = true, $size = 80)
401 {
402 }
403
404
405
406
407 public function ask($question, $default = null)
408 {
409 return $default;
410 }
411
412
413
414
415 public function askConfirmation($question, $default = true)
416 {
417 return $default;
418 }
419
420
421
422
423 public function askAndValidate($question, $validator, $attempts = false, $default = null)
424 {
425 return $default;
426 }
427
428
429
430
431 public function askAndHideAnswer($question)
432 {
433 return null;
434 }
435 }
436 <?php
437
438
439
440
441
442
443
444
445
446
447
448 namespace Composer\IO;
449
450 use Composer\Config;
451
452
453
454
455
456
457 interface IOInterface
458 {
459
460
461
462
463
464 public function isInteractive();
465
466
467
468
469
470
471 public function isVerbose();
472
473
474
475
476
477
478 public function isVeryVerbose();
479
480
481
482
483
484
485 public function isDebug();
486
487
488
489
490
491
492 public function isDecorated();
493
494
495
496
497
498
499
500 public function write($messages, $newline = true);
501
502
503
504
505
506
507
508
509 public function overwrite($messages, $newline = true, $size = null);
510
511
512
513
514
515
516
517
518
519
520
521 public function ask($question, $default = null);
522
523
524
525
526
527
528
529
530
531
532
533 public function askConfirmation($question, $default = true);
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551 public function askAndValidate($question, $validator, $attempts = false, $default = null);
552
553
554
555
556
557
558
559
560 public function askAndHideAnswer($question);
561
562
563
564
565
566
567 public function getAuthentications();
568
569
570
571
572
573
574
575
576 public function hasAuthentication($repositoryName);
577
578
579
580
581
582
583
584
585 public function getAuthentication($repositoryName);
586
587
588
589
590
591
592
593
594 public function setAuthentication($repositoryName, $username, $password = null);
595
596
597
598
599
600
601 public function loadConfiguration(Config $config);
602 }
603 <?php
604
605
606
607
608
609
610
611
612
613
614
615 namespace Composer\IO;
616
617 use Composer\Config;
618
619 abstract class BaseIO implements IOInterface
620 {
621 protected $authentications = array();
622
623
624
625
626 public function getAuthentications()
627 {
628 return $this->authentications;
629 }
630
631
632
633
634 public function hasAuthentication($repositoryName)
635 {
636 return isset($this->authentications[$repositoryName]);
637 }
638
639
640
641
642 public function getAuthentication($repositoryName)
643 {
644 if (isset($this->authentications[$repositoryName])) {
645 return $this->authentications[$repositoryName];
646 }
647
648 return array('username' => null, 'password' => null);
649 }
650
651
652
653
654 public function setAuthentication($repositoryName, $username, $password = null)
655 {
656 $this->authentications[$repositoryName] = array('username' => $username, 'password' => $password);
657 }
658
659
660
661
662 public function loadConfiguration(Config $config)
663 {
664
665  if ($tokens = $config->get('github-oauth')) {
666 foreach ($tokens as $domain => $token) {
667 if (!preg_match('{^[a-z0-9]+$}', $token)) {
668 throw new \UnexpectedValueException('Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"');
669 }
670 $this->setAuthentication($domain, $token, 'x-oauth-basic');
671 }
672 }
673
674
675  if ($creds = $config->get('http-basic')) {
676 foreach ($creds as $domain => $cred) {
677 $this->setAuthentication($domain, $cred['username'], $cred['password']);
678 }
679 }
680 }
681 }
682 <?php
683
684
685
686
687
688
689
690
691
692
693
694 namespace Composer\IO;
695
696 use Symfony\Component\Console\Output\StreamOutput;
697 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
698 use Symfony\Component\Console\Input\StringInput;
699 use Symfony\Component\Console\Helper\HelperSet;
700
701
702
703
704 class BufferIO extends ConsoleIO
705 {
706
707
708
709
710
711 public function __construct($input = '', $verbosity = null, OutputFormatterInterface $formatter = null)
712 {
713 $input = new StringInput($input);
714 $input->setInteractive(false);
715
716 $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity === null ? StreamOutput::VERBOSITY_NORMAL : $verbosity, !empty($formatter), $formatter);
717
718 parent::__construct($input, $output, new HelperSet(array()));
719 }
720
721 public function getOutput()
722 {
723 fseek($this->output->getStream(), 0);
724
725 $output = stream_get_contents($this->output->getStream());
726
727 $output = preg_replace_callback("{(?<=^|\n|\x08)(.+?)(\x08+)}", function ($matches) {
728 $pre = strip_tags($matches[1]);
729
730 if (strlen($pre) === strlen($matches[2])) {
731 return '';
732 }
733
734
735  return rtrim($matches[1])."\n";
736 }, $output);
737
738 return $output;
739 }
740 }
741 <?php
742
743
744
745
746
747
748
749
750
751
752
753 namespace Composer\Command;
754
755 use Composer\Script\CommandEvent;
756 use Composer\Script\ScriptEvents;
757 use Symfony\Component\Console\Input\InputInterface;
758 use Symfony\Component\Console\Input\InputOption;
759 use Symfony\Component\Console\Input\InputArgument;
760 use Symfony\Component\Console\Output\OutputInterface;
761
762
763
764
765 class RunScriptCommand extends Command
766 {
767
768
769
770 protected $commandEvents = array(
771 ScriptEvents::PRE_INSTALL_CMD,
772 ScriptEvents::POST_INSTALL_CMD,
773 ScriptEvents::PRE_UPDATE_CMD,
774 ScriptEvents::POST_UPDATE_CMD,
775 ScriptEvents::PRE_STATUS_CMD,
776 ScriptEvents::POST_STATUS_CMD,
777 ScriptEvents::POST_ROOT_PACKAGE_INSTALL,
778 ScriptEvents::POST_CREATE_PROJECT_CMD
779 );
780
781
782
783
784 protected $scriptEvents = array(
785 ScriptEvents::PRE_ARCHIVE_CMD,
786 ScriptEvents::POST_ARCHIVE_CMD,
787 ScriptEvents::PRE_AUTOLOAD_DUMP,
788 ScriptEvents::POST_AUTOLOAD_DUMP
789 );
790
791 protected function configure()
792 {
793 $this
794 ->setName('run-script')
795 ->setDescription('Run the scripts defined in composer.json.')
796 ->setDefinition(array(
797 new InputArgument('script', InputArgument::REQUIRED, 'Script name to run.'),
798 new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
799 new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
800 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
801 ))
802 ->setHelp(<<<EOT
803 The <info>run-script</info> command runs scripts defined in composer.json:
804
805 <info>php composer.phar run-script post-update-cmd</info>
806 EOT
807 )
808 ;
809 }
810
811 protected function execute(InputInterface $input, OutputInterface $output)
812 {
813 $script = $input->getArgument('script');
814 if (!in_array($script, $this->commandEvents) && !in_array($script, $this->scriptEvents)) {
815 if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
816 throw new \InvalidArgumentException(sprintf('Script "%s" cannot be run with this command', $script));
817 }
818 }
819
820 $composer = $this->getComposer();
821 $hasListeners = $composer->getEventDispatcher()->hasEventListeners(new CommandEvent($script, $composer, $this->getIO()));
822 if (!$hasListeners) {
823 throw new \InvalidArgumentException(sprintf('Script "%s" is not defined in this package', $script));
824 }
825
826
827  $binDir = $composer->getConfig()->get('bin-dir');
828 if (is_dir($binDir)) {
829 putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH'));
830 }
831
832 $args = $input->getArgument('args');
833
834 if (in_array($script, $this->commandEvents)) {
835 return $composer->getEventDispatcher()->dispatchCommandEvent($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args);
836 }
837
838 return $composer->getEventDispatcher()->dispatchScript($script, $input->getOption('dev') || !$input->getOption('no-dev'), $args);
839 }
840 }
841 <?php
842
843
844
845
846
847
848
849
850
851
852
853 namespace Composer\Command;
854
855 use Composer\Composer;
856 use Composer\Factory;
857 use Composer\Downloader\TransportException;
858 use Composer\Plugin\CommandEvent;
859 use Composer\Plugin\PluginEvents;
860 use Composer\Util\ConfigValidator;
861 use Composer\Util\ProcessExecutor;
862 use Composer\Util\RemoteFilesystem;
863 use Composer\Util\StreamContextFactory;
864 use Symfony\Component\Console\Input\InputInterface;
865 use Symfony\Component\Console\Output\OutputInterface;
866
867
868
869
870 class DiagnoseCommand extends Command
871 {
872 protected $rfs;
873 protected $process;
874 protected $failures = 0;
875
876 protected function configure()
877 {
878 $this
879 ->setName('diagnose')
880 ->setDescription('Diagnoses the system to identify common errors.')
881 ->setHelp(<<<EOT
882 The <info>diagnose</info> command checks common errors to help debugging problems.
883
884 EOT
885 )
886 ;
887 }
888
889 protected function execute(InputInterface $input, OutputInterface $output)
890 {
891 $composer = $this->getComposer(false);
892 if ($composer) {
893 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output);
894 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
895
896 $output->write('Checking composer.json: ');
897 $this->outputResult($output, $this->checkComposerSchema());
898 }
899
900 if ($composer) {
901 $config = $composer->getConfig();
902 } else {
903 $config = Factory::createConfig();
904 }
905
906 $this->rfs = new RemoteFilesystem($this->getIO(), $config);
907 $this->process = new ProcessExecutor($this->getIO());
908
909 $output->write('Checking platform settings: ');
910 $this->outputResult($output, $this->checkPlatform());
911
912 $output->write('Checking git settings: ');
913 $this->outputResult($output, $this->checkGit());
914
915 $output->write('Checking http connectivity: ');
916 $this->outputResult($output, $this->checkHttp());
917
918 $opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org'));
919 if (!empty($opts['http']['proxy'])) {
920 $output->write('Checking HTTP proxy: ');
921 $this->outputResult($output, $this->checkHttpProxy());
922 $output->write('Checking HTTP proxy support for request_fulluri: ');
923 $this->outputResult($output, $this->checkHttpProxyFullUriRequestParam());
924 $output->write('Checking HTTPS proxy support for request_fulluri: ');
925 $this->outputResult($output, $this->checkHttpsProxyFullUriRequestParam());
926 }
927
928 if ($oauth = $config->get('github-oauth')) {
929 foreach ($oauth as $domain => $token) {
930 $output->write('Checking '.$domain.' oauth access: ');
931 $this->outputResult($output, $this->checkGithubOauth($domain, $token));
932 }
933 }
934
935 $output->write('Checking disk free space: ');
936 $this->outputResult($output, $this->checkDiskSpace($config));
937
938 $output->write('Checking composer version: ');
939 $this->outputResult($output, $this->checkVersion());
940
941 return $this->failures;
942 }
943
944 private function checkComposerSchema()
945 {
946 $validator = new ConfigValidator($this->getIO());
947 list($errors, $publishErrors, $warnings) = $validator->validate(Factory::getComposerFile());
948
949 if ($errors || $publishErrors || $warnings) {
950 $messages = array(
951 'error' => array_merge($errors, $publishErrors),
952 'warning' => $warnings,
953 );
954
955 $output = '';
956 foreach ($messages as $style => $msgs) {
957 foreach ($msgs as $msg) {
958 $output .= '<' . $style . '>' . $msg . '</' . $style . '>' . PHP_EOL;
959 }
960 }
961
962 return rtrim($output);
963 }
964
965 return true;
966 }
967
968 private function checkGit()
969 {
970 $this->process->execute('git config color.ui', $output);
971 if (strtolower(trim($output)) === 'always') {
972 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>';
973 }
974
975 return true;
976 }
977
978 private function checkHttp()
979 {
980 $protocol = extension_loaded('openssl') ? 'https' : 'http';
981 try {
982 $json = $this->rfs->getContents('packagist.org', $protocol . '://packagist.org/packages.json', false);
983 } catch (\Exception $e) {
984 return $e;
985 }
986
987 return true;
988 }
989
990 private function checkHttpProxy()
991 {
992 $protocol = extension_loaded('openssl') ? 'https' : 'http';
993 try {
994 $json = json_decode($this->rfs->getContents('packagist.org', $protocol . '://packagist.org/packages.json', false), true);
995 $hash = reset($json['provider-includes']);
996 $hash = $hash['sha256'];
997 $path = str_replace('%hash%', $hash, key($json['provider-includes']));
998 $provider = $this->rfs->getContents('packagist.org', $protocol . '://packagist.org/'.$path, false);
999
1000 if (hash('sha256', $provider) !== $hash) {
1001 return 'It seems that your proxy is modifying http traffic on the fly';
1002 }
1003 } catch (\Exception $e) {
1004 return $e;
1005 }
1006
1007 return true;
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017 private function checkHttpProxyFullUriRequestParam()
1018 {
1019 $url = 'http://packagist.org/packages.json';
1020 try {
1021 $this->rfs->getContents('packagist.org', $url, false);
1022 } catch (TransportException $e) {
1023 try {
1024 $this->rfs->getContents('packagist.org', $url, false, array('http' => array('request_fulluri' => false)));
1025 } catch (TransportException $e) {
1026 return 'Unable to assess the situation, maybe packagist.org is down ('.$e->getMessage().')';
1027 }
1028
1029 return 'It seems there is a problem with your proxy server, try setting the "HTTP_PROXY_REQUEST_FULLURI" and "HTTPS_PROXY_REQUEST_FULLURI" environment variables to "false"';
1030 }
1031
1032 return true;
1033 }
1034
1035
1036
1037
1038
1039
1040
1041
1042 private function checkHttpsProxyFullUriRequestParam()
1043 {
1044 if (!extension_loaded('openssl')) {
1045 return 'You need the openssl extension installed for this check';
1046 }
1047
1048 $url = 'https://api.github.com/repos/Seldaek/jsonlint/zipball/1.0.0';
1049 try {
1050 $rfcResult = $this->rfs->getContents('github.com', $url, false);
1051 } catch (TransportException $e) {
1052 try {
1053 $this->rfs->getContents('github.com', $url, false, array('http' => array('request_fulluri' => false)));
1054 } catch (TransportException $e) {
1055 return 'Unable to assess the situation, maybe github is down ('.$e->getMessage().')';
1056 }
1057
1058 return 'It seems there is a problem with your proxy server, try setting the "HTTPS_PROXY_REQUEST_FULLURI" environment variable to "false"';
1059 }
1060
1061 return true;
1062 }
1063
1064 private function checkGithubOauth($domain, $token)
1065 {
1066 $this->getIO()->setAuthentication($domain, $token, 'x-oauth-basic');
1067 try {
1068 $url = $domain === 'github.com' ? 'https://api.'.$domain.'/user/repos' : 'https://'.$domain.'/api/v3/user/repos';
1069
1070 return $this->rfs->getContents($domain, $url, false) ? true : 'Unexpected error';
1071 } catch (\Exception $e) {
1072 if ($e instanceof TransportException && $e->getCode() === 401) {
1073 return '<warning>The oauth token for '.$domain.' seems invalid, run "composer config --global --unset github-oauth.'.$domain.'" to remove it</warning>';
1074 }
1075
1076 return $e;
1077 }
1078 }
1079
1080 private function checkDiskSpace($config)
1081 {
1082 $minSpaceFree = 1024*1024;
1083 if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
1084 || (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
1085 ) {
1086 return '<error>The disk hosting '.$dir.' is full</error>';
1087 }
1088
1089 return true;
1090 }
1091
1092 private function checkVersion()
1093 {
1094 $protocol = extension_loaded('openssl') ? 'https' : 'http';
1095 $latest = trim($this->rfs->getContents('getcomposer.org', $protocol . '://getcomposer.org/version', false));
1096
1097 if (Composer::VERSION !== $latest && Composer::VERSION !== '@package_version@') {
1098 return '<warning>You are not running the latest version</warning>';
1099 }
1100
1101 return true;
1102 }
1103
1104 private function outputResult(OutputInterface $output, $result)
1105 {
1106 if (true === $result) {
1107 $output->writeln('<info>OK</info>');
1108 } else {
1109 $this->failures++;
1110 $output->writeln('<error>FAIL</error>');
1111 if ($result instanceof \Exception) {
1112 $output->writeln('['.get_class($result).'] '.$result->getMessage());
1113 } elseif ($result) {
1114 $output->writeln($result);
1115 }
1116 }
1117 }
1118
1119 private function checkPlatform()
1120 {
1121 $output = '';
1122 $out = function ($msg, $style) use (&$output) {
1123 $output .= '<'.$style.'>'.$msg.'</'.$style.'>';
1124 };
1125
1126
1127  $errors = array();
1128 $warnings = array();
1129
1130 $iniPath = php_ini_loaded_file();
1131 $displayIniMessage = false;
1132 if ($iniPath) {
1133 $iniMessage = PHP_EOL.PHP_EOL.'The php.ini used by your command-line PHP is: ' . $iniPath;
1134 } else {
1135 $iniMessage = PHP_EOL.PHP_EOL.'A php.ini file does not exist. You will have to create one.';
1136 }
1137 $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.';
1138
1139 if (!ini_get('allow_url_fopen')) {
1140 $errors['allow_url_fopen'] = true;
1141 }
1142
1143 if (version_compare(PHP_VERSION, '5.3.2', '<')) {
1144 $errors['php'] = PHP_VERSION;
1145 }
1146
1147 if (!isset($errors['php']) && version_compare(PHP_VERSION, '5.3.4', '<')) {
1148 $warnings['php'] = PHP_VERSION;
1149 }
1150
1151 if (!extension_loaded('openssl')) {
1152 $warnings['openssl'] = true;
1153 }
1154
1155 if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) {
1156 $warnings['apc_cli'] = true;
1157 }
1158
1159 if (ini_get('xdebug.profiler_enabled')) {
1160 $warnings['xdebug_profile'] = true;
1161 } elseif (extension_loaded('xdebug')) {
1162 $warnings['xdebug_loaded'] = true;
1163 }
1164
1165 ob_start();
1166 phpinfo(INFO_GENERAL);
1167 $phpinfo = ob_get_clean();
1168 if (preg_match('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', $phpinfo, $match)) {
1169 $configure = $match[1];
1170
1171 if (false !== strpos($configure, '--enable-sigchild')) {
1172 $warnings['sigchild'] = true;
1173 }
1174
1175 if (false !== strpos($configure, '--with-curlwrappers')) {
1176 $warnings['curlwrappers'] = true;
1177 }
1178 }
1179
1180 if (!empty($errors)) {
1181 foreach ($errors as $error => $current) {
1182 switch ($error) {
1183 case 'php':
1184 $text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.2 or higher.";
1185 break;
1186
1187 case 'allow_url_fopen':
1188 $text = PHP_EOL."The allow_url_fopen setting is incorrect.".PHP_EOL;
1189 $text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
1190 $text .= "    allow_url_fopen = On";
1191 $displayIniMessage = true;
1192 break;
1193 }
1194 $out($text, 'error');
1195 }
1196
1197 $output .= PHP_EOL;
1198 }
1199
1200 if (!empty($warnings)) {
1201 foreach ($warnings as $warning => $current) {
1202 switch ($warning) {
1203 case 'apc_cli':
1204 $text = PHP_EOL."The apc.enable_cli setting is incorrect.".PHP_EOL;
1205 $text .= "Add the following to the end of your `php.ini`:".PHP_EOL;
1206 $text .= "    apc.enable_cli = Off";
1207 $displayIniMessage = true;
1208 break;
1209
1210 case 'sigchild':
1211 $text = PHP_EOL."PHP was compiled with --enable-sigchild which can cause issues on some platforms.".PHP_EOL;
1212 $text .= "Recompile it without this flag if possible, see also:".PHP_EOL;
1213 $text .= "    https://bugs.php.net/bug.php?id=22999";
1214 break;
1215
1216 case 'curlwrappers':
1217 $text = PHP_EOL."PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.".PHP_EOL;
1218 $text .= "Recompile it without this flag if possible";
1219 break;
1220
1221 case 'openssl':
1222 $text = PHP_EOL."The openssl extension is missing, which will reduce the security and stability of Composer.".PHP_EOL;
1223 $text .= "If possible you should enable it or recompile php with --with-openssl";
1224 break;
1225
1226 case 'php':
1227 $text = PHP_EOL."Your PHP ({$current}) is quite old, upgrading to PHP 5.3.4 or higher is recommended.".PHP_EOL;
1228 $text .= "Composer works with 5.3.2+ for most people, but there might be edge case issues.";
1229 break;
1230
1231 case 'xdebug_loaded':
1232 $text = PHP_EOL."The xdebug extension is loaded, this can slow down Composer a little.".PHP_EOL;
1233 $text .= "Disabling it when using Composer is recommended, but should not cause issues beyond slowness.";
1234 break;
1235
1236 case 'xdebug_profile':
1237 $text = PHP_EOL."The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.".PHP_EOL;
1238 $text .= "Add the following to the end of your `php.ini` to disable it:".PHP_EOL;
1239 $text .= "    xdebug.profiler_enabled = 0";
1240 $displayIniMessage = true;
1241 break;
1242 }
1243 $out($text, 'warning');
1244 }
1245 }
1246
1247 if ($displayIniMessage) {
1248 $out($iniMessage, 'warning');
1249 }
1250
1251 return !$warnings && !$errors ? true : $output;
1252 }
1253 }
1254 <?php
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266 namespace Composer\Command;
1267
1268 use Composer\Factory;
1269 use Composer\IO\IOInterface;
1270 use Composer\DependencyResolver\Pool;
1271 use Composer\Repository\CompositeRepository;
1272 use Composer\Script\ScriptEvents;
1273 use Composer\Plugin\CommandEvent;
1274 use Composer\Plugin\PluginEvents;
1275 use Composer\Package\Version\VersionParser;
1276
1277 use Symfony\Component\Console\Input\InputArgument;
1278 use Symfony\Component\Console\Input\InputInterface;
1279 use Symfony\Component\Console\Input\InputOption;
1280 use Symfony\Component\Console\Output\OutputInterface;
1281
1282
1283
1284
1285
1286
1287 class ArchiveCommand extends Command
1288 {
1289 protected function configure()
1290 {
1291 $this
1292 ->setName('archive')
1293 ->setDescription('Create an archive of this composer package')
1294 ->setDefinition(array(
1295 new InputArgument('package', InputArgument::OPTIONAL, 'The package to archive instead of the current project'),
1296 new InputArgument('version', InputArgument::OPTIONAL, 'A version constraint to find the package to archive'),
1297 new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the resulting archive: tar or zip', 'tar'),
1298 new InputOption('dir', false, InputOption::VALUE_REQUIRED, 'Write the archive to this directory', '.'),
1299 ))
1300 ->setHelp(<<<EOT
1301 The <info>archive</info> command creates an archive of the specified format
1302 containing the files and directories of the Composer project or the specified
1303 package in the specified version and writes it to the specified directory.
1304
1305 <info>php composer.phar archive [--format=zip] [--dir=/foo] [package [version]]</info>
1306
1307 EOT
1308 )
1309 ;
1310 }
1311
1312 protected function execute(InputInterface $input, OutputInterface $output)
1313 {
1314 $composer = $this->getComposer(false);
1315 if ($composer) {
1316 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'archive', $input, $output);
1317 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
1318 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::PRE_ARCHIVE_CMD);
1319 }
1320
1321 $returnCode = $this->archive(
1322 $this->getIO(),
1323 $input->getArgument('package'),
1324 $input->getArgument('version'),
1325 $input->getOption('format'),
1326 $input->getOption('dir')
1327 );
1328
1329 if (0 === $returnCode && $composer) {
1330 $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ARCHIVE_CMD);
1331 }
1332
1333 return $returnCode;
1334 }
1335
1336 protected function archive(IOInterface $io, $packageName = null, $version = null, $format = 'tar', $dest = '.')
1337 {
1338 $config = Factory::createConfig();
1339 $factory = new Factory;
1340 $downloadManager = $factory->createDownloadManager($io, $config);
1341 $archiveManager = $factory->createArchiveManager($config, $downloadManager);
1342
1343 if ($packageName) {
1344 $package = $this->selectPackage($io, $packageName, $version);
1345
1346 if (!$package) {
1347 return 1;
1348 }
1349 } else {
1350 $package = $this->getComposer()->getPackage();
1351 }
1352
1353 $io->write('<info>Creating the archive.</info>');
1354 $archiveManager->archive($package, $format, $dest);
1355
1356 return 0;
1357 }
1358
1359 protected function selectPackage(IOInterface $io, $packageName, $version = null)
1360 {
1361 $io->write('<info>Searching for the specified package.</info>');
1362
1363 if ($composer = $this->getComposer(false)) {
1364 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
1365 $repos = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
1366 } else {
1367 $defaultRepos = Factory::createDefaultRepositories($this->getIO());
1368 $io->write('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos)));
1369 $repos = new CompositeRepository($defaultRepos);
1370 }
1371
1372 $pool = new Pool();
1373 $pool->addRepository($repos);
1374
1375 $parser = new VersionParser();
1376 $constraint = ($version) ? $parser->parseConstraints($version) : null;
1377 $packages = $pool->whatProvides($packageName, $constraint, true);
1378
1379 if (count($packages) > 1) {
1380 $package = reset($packages);
1381 $io->write('<info>Found multiple matches, selected '.$package->getPrettyString().'.</info>');
1382 $io->write('Alternatives were '.implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)).'.');
1383 $io->write('<comment>Please use a more specific constraint to pick a different package.</comment>');
1384 } elseif ($packages) {
1385 $package = reset($packages);
1386 $io->write('<info>Found an exact match '.$package->getPrettyString().'.</info>');
1387 } else {
1388 $io->write('<error>Could not find a package matching '.$packageName.'.</error>');
1389
1390 return false;
1391 }
1392
1393 return $package;
1394 }
1395 }
1396 <?php
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 namespace Composer\Command;
1409
1410 use Composer\Cache;
1411 use Composer\Factory;
1412 use Symfony\Component\Console\Input\InputInterface;
1413 use Symfony\Component\Console\Output\OutputInterface;
1414
1415
1416
1417
1418 class ClearCacheCommand extends Command
1419 {
1420 protected function configure()
1421 {
1422 $this
1423 ->setName('clear-cache')
1424 ->setAliases(array('clearcache'))
1425 ->setDescription('Clears composer\'s internal package cache.')
1426 ->setHelp(<<<EOT
1427 The <info>clear-cache</info> deletes all cached packages from composer's
1428 cache directory.
1429 EOT
1430 )
1431 ;
1432 }
1433
1434 protected function execute(InputInterface $input, OutputInterface $output)
1435 {
1436 $config = Factory::createConfig();
1437 $io = $this->getIO();
1438
1439 $cachePaths = array(
1440 'cache-dir' => $config->get('cache-dir'),
1441 'cache-files-dir' => $config->get('cache-files-dir'),
1442 'cache-repo-dir' => $config->get('cache-repo-dir'),
1443 'cache-vcs-dir' => $config->get('cache-vcs-dir'),
1444 );
1445
1446 foreach ($cachePaths as $key => $cachePath) {
1447 $cachePath = realpath($cachePath);
1448 if (!$cachePath) {
1449 $io->write("<info>Cache directory does not exist ($key): $cachePath</info>");
1450
1451 return;
1452 }
1453 $cache = new Cache($io, $cachePath);
1454 if (!$cache->isEnabled()) {
1455 $io->write("<info>Cache is not enabled ($key): $cachePath</info>");
1456
1457 return;
1458 }
1459
1460 $io->write("<info>Clearing cache ($key): $cachePath</info>");
1461 $cache->gc(0, 0);
1462 }
1463
1464 $io->write('<info>All caches cleared.</info>');
1465 }
1466 }
1467 <?php
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479 namespace Composer\Command;
1480
1481 use Composer\Composer;
1482 use Composer\Console\Application;
1483 use Composer\IO\IOInterface;
1484 use Composer\IO\NullIO;
1485 use Symfony\Component\Console\Input\InputInterface;
1486 use Symfony\Component\Console\Output\OutputInterface;
1487 use Symfony\Component\Console\Command\Command as BaseCommand;
1488
1489
1490
1491
1492
1493
1494
1495 abstract class Command extends BaseCommand
1496 {
1497
1498
1499
1500 private $composer;
1501
1502
1503
1504
1505 private $io;
1506
1507
1508
1509
1510
1511
1512
1513 public function getComposer($required = true, $disablePlugins = false)
1514 {
1515 if (null === $this->composer) {
1516 $application = $this->getApplication();
1517 if ($application instanceof Application) {
1518
1519 $this->composer = $application->getComposer($required, $disablePlugins);
1520 } elseif ($required) {
1521 throw new \RuntimeException(
1522 'Could not create a Composer\Composer instance, you must inject '.
1523 'one if this command is not used with a Composer\Console\Application instance'
1524 );
1525 }
1526 }
1527
1528 return $this->composer;
1529 }
1530
1531
1532
1533
1534 public function setComposer(Composer $composer)
1535 {
1536 $this->composer = $composer;
1537 }
1538
1539
1540
1541
1542 public function resetComposer()
1543 {
1544 $this->composer = null;
1545 $this->getApplication()->resetComposer();
1546 }
1547
1548
1549
1550
1551 public function getIO()
1552 {
1553 if (null === $this->io) {
1554 $application = $this->getApplication();
1555 if ($application instanceof Application) {
1556
1557 $this->io = $application->getIO();
1558 } else {
1559 $this->io = new NullIO();
1560 }
1561 }
1562
1563 return $this->io;
1564 }
1565
1566
1567
1568
1569 public function setIO(IOInterface $io)
1570 {
1571 $this->io = $io;
1572 }
1573
1574
1575
1576
1577 protected function initialize(InputInterface $input, OutputInterface $output)
1578 {
1579 if (true === $input->hasParameterOption(array('--no-ansi')) && $input->hasOption('no-progress')) {
1580 $input->setOption('no-progress', true);
1581 }
1582
1583 parent::initialize($input, $output);
1584 }
1585 }
1586 <?php
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598 namespace Composer\Command;
1599
1600 use Composer\Config;
1601 use Composer\Factory;
1602 use Composer\Installer;
1603 use Composer\Installer\ProjectInstaller;
1604 use Composer\Installer\InstallationManager;
1605 use Composer\IO\IOInterface;
1606 use Composer\Package\BasePackage;
1607 use Composer\DependencyResolver\Pool;
1608 use Composer\DependencyResolver\Operation\InstallOperation;
1609 use Composer\Package\Version\VersionSelector;
1610 use Composer\Repository\ComposerRepository;
1611 use Composer\Repository\CompositeRepository;
1612 use Composer\Repository\FilesystemRepository;
1613 use Composer\Repository\InstalledFilesystemRepository;
1614 use Composer\Script\ScriptEvents;
1615 use Symfony\Component\Console\Input\InputArgument;
1616 use Symfony\Component\Console\Input\InputInterface;
1617 use Symfony\Component\Console\Input\InputOption;
1618 use Symfony\Component\Console\Output\OutputInterface;
1619 use Symfony\Component\Finder\Finder;
1620 use Composer\Json\JsonFile;
1621 use Composer\Config\JsonConfigSource;
1622 use Composer\Util\Filesystem;
1623 use Composer\Util\RemoteFilesystem;
1624 use Composer\Package\Version\VersionParser;
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634 class CreateProjectCommand extends Command
1635 {
1636 protected function configure()
1637 {
1638 $this
1639 ->setName('create-project')
1640 ->setDescription('Create new project from a package into given directory.')
1641 ->setDefinition(array(
1642 new InputArgument('package', InputArgument::OPTIONAL, 'Package name to be installed'),
1643 new InputArgument('directory', InputArgument::OPTIONAL, 'Directory where the files should be created'),
1644 new InputArgument('version', InputArgument::OPTIONAL, 'Version, will default to latest'),
1645 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum-stability allowed (unless a version is specified).'),
1646 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
1647 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
1648 new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'Pick a different repository url to look for the package.'),
1649 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
1650 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
1651 new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Whether to disable plugins.'),
1652 new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
1653 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Whether to prevent execution of all defined scripts in the root package.'),
1654 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
1655 new InputOption('keep-vcs', null, InputOption::VALUE_NONE, 'Whether to prevent deletion vcs folder.'),
1656 new InputOption('no-install', null, InputOption::VALUE_NONE, 'Whether to skip installation of the package dependencies.'),
1657 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
1658 ))
1659 ->setHelp(<<<EOT
1660 The <info>create-project</info> command creates a new project from a given
1661 package into a new directory. If executed without params and in a directory
1662 with a composer.json file it installs the packages for the current project.
1663
1664 You can use this command to bootstrap new projects or setup a clean
1665 version-controlled installation for developers of your project.
1666
1667 <info>php composer.phar create-project vendor/project target-directory [version]</info>
1668
1669 You can also specify the version with the package name using = or : as separator.
1670
1671 To install unstable packages, either specify the version you want, or use the
1672 --stability=dev (where dev can be one of RC, beta, alpha or dev).
1673
1674 To setup a developer workable version you should create the project using the source
1675 controlled code by appending the <info>'--prefer-source'</info> flag.
1676
1677 To install a package from another repository than the default one you
1678 can pass the <info>'--repository-url=http://myrepository.org'</info> flag.
1679
1680 EOT
1681 )
1682 ;
1683 }
1684
1685 protected function execute(InputInterface $input, OutputInterface $output)
1686 {
1687 $config = Factory::createConfig();
1688
1689 $preferSource = false;
1690 $preferDist = false;
1691 $this->updatePreferredOptions($config, $input, $preferSource, $preferDist);
1692
1693 if ($input->getOption('no-custom-installers')) {
1694 $output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
1695 $input->setOption('no-plugins', true);
1696 }
1697
1698 return $this->installProject(
1699 $this->getIO(),
1700 $config,
1701 $input->getArgument('package'),
1702 $input->getArgument('directory'),
1703 $input->getArgument('version'),
1704 $input->getOption('stability'),
1705 $preferSource,
1706 $preferDist,
1707 !$input->getOption('no-dev'),
1708 $input->getOption('repository-url'),
1709 $input->getOption('no-plugins'),
1710 $input->getOption('no-scripts'),
1711 $input->getOption('keep-vcs'),
1712 $input->getOption('no-progress'),
1713 $input->getOption('no-install'),
1714 $input->getOption('ignore-platform-reqs'),
1715 $input
1716 );
1717 }
1718
1719 public function installProject(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false, InputInterface $input)
1720 {
1721 $oldCwd = getcwd();
1722
1723
1724  $io->loadConfiguration($config);
1725
1726 if ($packageName !== null) {
1727 $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositoryUrl, $disablePlugins, $noScripts, $keepVcs, $noProgress);
1728 } else {
1729 $installedFromVcs = false;
1730 }
1731
1732 $composer = Factory::create($io, null, $disablePlugins);
1733 $fs = new Filesystem();
1734
1735 if ($noScripts === false) {
1736
1737  $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages);
1738 }
1739
1740 $rootPackageConfig = $composer->getConfig();
1741 $this->updatePreferredOptions($rootPackageConfig, $input, $preferSource, $preferDist);
1742
1743
1744  if ($noInstall === false) {
1745 $installer = Installer::create($io, $composer);
1746 $installer->setPreferSource($preferSource)
1747 ->setPreferDist($preferDist)
1748 ->setDevMode($installDevPackages)
1749 ->setRunScripts(!$noScripts)
1750 ->setIgnorePlatformRequirements($ignorePlatformReqs);
1751
1752 if ($disablePlugins) {
1753 $installer->disablePlugins();
1754 }
1755
1756 $status = $installer->run();
1757 if (0 !== $status) {
1758 return $status;
1759 }
1760 }
1761
1762 $hasVcs = $installedFromVcs;
1763 if (!$keepVcs && $installedFromVcs
1764 && (
1765 !$io->isInteractive()
1766 || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true)
1767 )
1768 ) {
1769 $finder = new Finder();
1770 $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false);
1771 foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg') as $vcsName) {
1772 $finder->name($vcsName);
1773 }
1774
1775 try {
1776 $dirs = iterator_to_array($finder);
1777 unset($finder);
1778 foreach ($dirs as $dir) {
1779 if (!$fs->removeDirectory($dir)) {
1780 throw new \RuntimeException('Could not remove '.$dir);
1781 }
1782 }
1783 } catch (\Exception $e) {
1784 $io->write('<error>An error occurred while removing the VCS metadata: '.$e->getMessage().'</error>');
1785 }
1786
1787 $hasVcs = false;
1788 }
1789
1790
1791  if (!$hasVcs) {
1792 $package = $composer->getPackage();
1793 $configSource = new JsonConfigSource(new JsonFile('composer.json'));
1794 foreach (BasePackage::$supportedLinkTypes as $type => $meta) {
1795 foreach ($package->{'get'.$meta['method']}() as $link) {
1796 if ($link->getPrettyConstraint() === 'self.version') {
1797 $configSource->addLink($type, $link->getTarget(), $package->getPrettyVersion());
1798 }
1799 }
1800 }
1801 }
1802
1803 if ($noScripts === false) {
1804
1805  $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages);
1806 }
1807
1808 chdir($oldCwd);
1809 $vendorComposerDir = $composer->getConfig()->get('vendor-dir').'/composer';
1810 if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) {
1811 @rmdir($vendorComposerDir);
1812 $vendorDir = $composer->getConfig()->get('vendor-dir');
1813 if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) {
1814 @rmdir($vendorDir);
1815 }
1816 }
1817
1818 return 0;
1819 }
1820
1821 protected function installRootPackage(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false)
1822 {
1823 if (null === $repositoryUrl) {
1824 $sourceRepo = new CompositeRepository(Factory::createDefaultRepositories($io, $config));
1825 } elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION) && file_exists($repositoryUrl)) {
1826 $json = new JsonFile($repositoryUrl, new RemoteFilesystem($io, $config));
1827 $data = $json->read();
1828 if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) {
1829 $sourceRepo = new ComposerRepository(array('url' => 'file://' . strtr(realpath($repositoryUrl), '\\', '/')), $io, $config);
1830 } else {
1831 $sourceRepo = new FilesystemRepository($json);
1832 }
1833 } elseif (0 === strpos($repositoryUrl, 'http')) {
1834 $sourceRepo = new ComposerRepository(array('url' => $repositoryUrl), $io, $config);
1835 } else {
1836 throw new \InvalidArgumentException("Invalid repository url given. Has to be a .json file or an http url.");
1837 }
1838
1839 $parser = new VersionParser();
1840 $requirements = $parser->parseNameVersionPairs(array($packageName));
1841 $name = strtolower($requirements[0]['name']);
1842 if (!$packageVersion && isset($requirements[0]['version'])) {
1843 $packageVersion = $requirements[0]['version'];
1844 }
1845
1846 if (null === $stability) {
1847 if (preg_match('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) {
1848 $stability = $match[1];
1849 } else {
1850 $stability = VersionParser::parseStability($packageVersion);
1851 }
1852 }
1853
1854 $stability = VersionParser::normalizeStability($stability);
1855
1856 if (!isset(BasePackage::$stabilities[$stability])) {
1857 throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::$stabilities)));
1858 }
1859
1860 $pool = new Pool($stability);
1861 $pool->addRepository($sourceRepo);
1862
1863
1864  $versionSelector = new VersionSelector($pool);
1865 $package = $versionSelector->findBestCandidate($name, $packageVersion);
1866
1867 if (!$package) {
1868 throw new \InvalidArgumentException("Could not find package $name" . ($packageVersion ? " with version $packageVersion." : " with stability $stability."));
1869 }
1870
1871 if (null === $directory) {
1872 $parts = explode("/", $name, 2);
1873 $directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts);
1874 }
1875
1876 $io->write('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>');
1877
1878 if ($disablePlugins) {
1879 $io->write('<info>Plugins have been disabled.</info>');
1880 }
1881
1882 if (0 === strpos($package->getPrettyVersion(), 'dev-') && in_array($package->getSourceType(), array('git', 'hg'))) {
1883 $package->setSourceReference(substr($package->getPrettyVersion(), 4));
1884 }
1885
1886 $dm = $this->createDownloadManager($io, $config);
1887 $dm->setPreferSource($preferSource)
1888 ->setPreferDist($preferDist)
1889 ->setOutputProgress(!$noProgress);
1890
1891 $projectInstaller = new ProjectInstaller($directory, $dm);
1892 $im = $this->createInstallationManager();
1893 $im->addInstaller($projectInstaller);
1894 $im->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), new InstallOperation($package));
1895 $im->notifyInstalls();
1896
1897 $installedFromVcs = 'source' === $package->getInstallationSource();
1898
1899 $io->write('<info>Created project in ' . $directory . '</info>');
1900 chdir($directory);
1901
1902 putenv('COMPOSER_ROOT_VERSION='.$package->getPrettyVersion());
1903
1904 return $installedFromVcs;
1905 }
1906
1907 protected function createDownloadManager(IOInterface $io, Config $config)
1908 {
1909 $factory = new Factory();
1910
1911 return $factory->createDownloadManager($io, $config);
1912 }
1913
1914 protected function createInstallationManager()
1915 {
1916 return new InstallationManager();
1917 }
1918
1919
1920
1921
1922
1923
1924
1925
1926 protected function updatePreferredOptions(Config $config, InputInterface $input, &$preferSource, &$preferDist)
1927 {
1928 switch ($config->get('preferred-install')) {
1929 case 'source':
1930 $preferSource = true;
1931 $preferDist = false;
1932 break;
1933 case 'dist':
1934 $preferSource = false;
1935 $preferDist = true;
1936 break;
1937 case 'auto':
1938 default:
1939
1940  break;
1941 }
1942
1943 if ($input->getOption('prefer-source') || $input->getOption('prefer-dist')) {
1944 $preferSource = $input->getOption('prefer-source');
1945 $preferDist = $input->getOption('prefer-dist');
1946 }
1947 }
1948 }
1949 <?php
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961 namespace Composer\Command;
1962
1963 use Symfony\Component\Console\Input\InputInterface;
1964 use Symfony\Component\Console\Output\OutputInterface;
1965
1966
1967
1968
1969 class AboutCommand extends Command
1970 {
1971 protected function configure()
1972 {
1973 $this
1974 ->setName('about')
1975 ->setDescription('Short information about Composer')
1976 ->setHelp(<<<EOT
1977 <info>php composer.phar about</info>
1978 EOT
1979 )
1980 ;
1981 }
1982
1983 protected function execute(InputInterface $input, OutputInterface $output)
1984 {
1985 $output->writeln(<<<EOT
1986 <info>Composer - Package Management for PHP</info>
1987 <comment>Composer is a dependency manager tracking local dependencies of your projects and libraries.
1988 See http://getcomposer.org/ for more information.</comment>
1989 EOT
1990 );
1991 }
1992 }
1993 <?php
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005 namespace Composer\Command;
2006
2007 use Symfony\Component\Console\Input\InputInterface;
2008 use Symfony\Component\Console\Input\InputOption;
2009 use Symfony\Component\Console\Input\InputArgument;
2010 use Symfony\Component\Console\Output\OutputInterface;
2011
2012
2013
2014
2015 class ScriptAliasCommand extends Command
2016 {
2017 private $script;
2018
2019 public function __construct($script)
2020 {
2021 $this->script = $script;
2022
2023 parent::__construct();
2024 }
2025
2026 protected function configure()
2027 {
2028 $this
2029 ->setName($this->script)
2030 ->setDescription('Run the '.$this->script.' script as defined in composer.json.')
2031 ->setDefinition(array(
2032 new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'),
2033 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'),
2034 new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
2035 ))
2036 ->setHelp(<<<EOT
2037 The <info>run-script</info> command runs scripts defined in composer.json:
2038
2039 <info>php composer.phar run-script post-update-cmd</info>
2040 EOT
2041 )
2042 ;
2043 }
2044
2045 protected function execute(InputInterface $input, OutputInterface $output)
2046 {
2047 $composer = $this->getComposer();
2048
2049
2050  $binDir = $composer->getConfig()->get('bin-dir');
2051 if (is_dir($binDir)) {
2052 putenv('PATH='.realpath($binDir).PATH_SEPARATOR.getenv('PATH'));
2053 }
2054
2055 $args = $input->getArguments();
2056
2057 return $composer->getEventDispatcher()->dispatchScript($this->script, $input->getOption('dev') || !$input->getOption('no-dev'), $args['args']);
2058 }
2059 }
2060 <?php
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072 namespace Composer\Command;
2073
2074 use Composer\DependencyResolver\Pool;
2075 use Composer\DependencyResolver\DefaultPolicy;
2076 use Composer\Factory;
2077 use Composer\Package\CompletePackageInterface;
2078 use Composer\Package\Version\VersionParser;
2079 use Composer\Plugin\CommandEvent;
2080 use Composer\Plugin\PluginEvents;
2081 use Symfony\Component\Console\Input\InputInterface;
2082 use Symfony\Component\Console\Input\InputArgument;
2083 use Symfony\Component\Console\Input\InputOption;
2084 use Symfony\Component\Console\Output\OutputInterface;
2085 use Composer\Repository\ArrayRepository;
2086 use Composer\Repository\CompositeRepository;
2087 use Composer\Repository\ComposerRepository;
2088 use Composer\Repository\PlatformRepository;
2089 use Composer\Repository\RepositoryInterface;
2090
2091
2092
2093
2094
2095 class ShowCommand extends Command
2096 {
2097 protected $versionParser;
2098
2099 protected function configure()
2100 {
2101 $this
2102 ->setName('show')
2103 ->setDescription('Show information about packages')
2104 ->setDefinition(array(
2105 new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect'),
2106 new InputArgument('version', InputArgument::OPTIONAL, 'Version or version constraint to inspect'),
2107 new InputOption('installed', 'i', InputOption::VALUE_NONE, 'List installed packages only'),
2108 new InputOption('platform', 'p', InputOption::VALUE_NONE, 'List platform packages only'),
2109 new InputOption('available', 'a', InputOption::VALUE_NONE, 'List available packages only'),
2110 new InputOption('self', 's', InputOption::VALUE_NONE, 'Show the root package information'),
2111 new InputOption('name-only', 'N', InputOption::VALUE_NONE, 'List package names only'),
2112 new InputOption('path', 'P', InputOption::VALUE_NONE, 'Show package paths'),
2113 ))
2114 ->setHelp(<<<EOT
2115 The show command displays detailed information about a package, or
2116 lists all packages available.
2117
2118 EOT
2119 )
2120 ;
2121 }
2122
2123 protected function execute(InputInterface $input, OutputInterface $output)
2124 {
2125 $this->versionParser = new VersionParser;
2126
2127
2128  $platformRepo = new PlatformRepository;
2129
2130 $composer = $this->getComposer(false);
2131 if ($input->getOption('self')) {
2132 $package = $this->getComposer()->getPackage();
2133 $repos = $installedRepo = new ArrayRepository(array($package));
2134 } elseif ($input->getOption('platform')) {
2135 $repos = $installedRepo = $platformRepo;
2136 } elseif ($input->getOption('installed')) {
2137 $repos = $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
2138 } elseif ($input->getOption('available')) {
2139 $installedRepo = $platformRepo;
2140 if ($composer) {
2141 $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
2142 } else {
2143 $defaultRepos = Factory::createDefaultRepositories($this->getIO());
2144 $repos = new CompositeRepository($defaultRepos);
2145 $output->writeln('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
2146 }
2147 } elseif ($composer) {
2148 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
2149 $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
2150 $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
2151 } else {
2152 $defaultRepos = Factory::createDefaultRepositories($this->getIO());
2153 $output->writeln('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
2154 $installedRepo = $platformRepo;
2155 $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
2156 }
2157
2158 if ($composer) {
2159 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'show', $input, $output);
2160 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
2161 }
2162
2163
2164  if ($input->getArgument('package') || !empty($package)) {
2165 $versions = array();
2166 if (empty($package)) {
2167 list($package, $versions) = $this->getPackage($installedRepo, $repos, $input->getArgument('package'), $input->getArgument('version'));
2168
2169 if (!$package) {
2170 throw new \InvalidArgumentException('Package '.$input->getArgument('package').' not found');
2171 }
2172 } else {
2173 $versions = array($package->getPrettyVersion() => $package->getVersion());
2174 }
2175
2176 $this->printMeta($input, $output, $package, $versions, $installedRepo, $repos);
2177 $this->printLinks($input, $output, $package, 'requires');
2178 $this->printLinks($input, $output, $package, 'devRequires', 'requires (dev)');
2179 if ($package->getSuggests()) {
2180 $output->writeln("\n<info>suggests</info>");
2181 foreach ($package->getSuggests() as $suggested => $reason) {
2182 $output->writeln($suggested . ' <comment>' . $reason . '</comment>');
2183 }
2184 }
2185 $this->printLinks($input, $output, $package, 'provides');
2186 $this->printLinks($input, $output, $package, 'conflicts');
2187 $this->printLinks($input, $output, $package, 'replaces');
2188
2189 return;
2190 }
2191
2192
2193  $packages = array();
2194
2195 if ($repos instanceof CompositeRepository) {
2196 $repos = $repos->getRepositories();
2197 } elseif (!is_array($repos)) {
2198 $repos = array($repos);
2199 }
2200
2201 foreach ($repos as $repo) {
2202 if ($repo === $platformRepo) {
2203 $type = '<info>platform</info>:';
2204 } elseif (
2205 $repo === $installedRepo
2206 || ($installedRepo instanceof CompositeRepository && in_array($repo, $installedRepo->getRepositories(), true))
2207 ) {
2208 $type = '<info>installed</info>:';
2209 } else {
2210 $type = '<comment>available</comment>:';
2211 }
2212 if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
2213 foreach ($repo->getProviderNames() as $name) {
2214 $packages[$type][$name] = $name;
2215 }
2216 } else {
2217 foreach ($repo->getPackages() as $package) {
2218 if (!isset($packages[$type][$package->getName()])
2219 || !is_object($packages[$type][$package->getName()])
2220 || version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '<')
2221 ) {
2222 $packages[$type][$package->getName()] = $package;
2223 }
2224 }
2225 }
2226 }
2227
2228 $tree = !$input->getOption('platform') && !$input->getOption('installed') && !$input->getOption('available');
2229 $indent = $tree ? '  ' : '';
2230 foreach (array('<info>platform</info>:' => true, '<comment>available</comment>:' => false, '<info>installed</info>:' => true) as $type => $showVersion) {
2231 if (isset($packages[$type])) {
2232 if ($tree) {
2233 $output->writeln($type);
2234 }
2235 ksort($packages[$type]);
2236
2237 $nameLength = $versionLength = 0;
2238 foreach ($packages[$type] as $package) {
2239 if (is_object($package)) {
2240 $nameLength = max($nameLength, strlen($package->getPrettyName()));
2241 $versionLength = max($versionLength, strlen($this->versionParser->formatVersion($package)));
2242 } else {
2243 $nameLength = max($nameLength, $package);
2244 }
2245 }
2246 list($width) = $this->getApplication()->getTerminalDimensions();
2247 if (null === $width) {
2248
2249  
2250  $width = PHP_INT_MAX;
2251 }
2252 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
2253 $width--;
2254 }
2255
2256 $writePath = !$input->getOption('name-only') && $input->getOption('path');
2257 $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion && ($nameLength + $versionLength + 3 <= $width);
2258 $writeDescription = !$input->getOption('name-only') && !$input->getOption('path') && ($nameLength + ($showVersion ? $versionLength : 0) + 24 <= $width);
2259 foreach ($packages[$type] as $package) {
2260 if (is_object($package)) {
2261 $output->write($indent . str_pad($package->getPrettyName(), $nameLength, ' '), false);
2262
2263 if ($writeVersion) {
2264 $output->write(' ' . str_pad($this->versionParser->formatVersion($package), $versionLength, ' '), false);
2265 }
2266
2267 if ($writeDescription) {
2268 $description = strtok($package->getDescription(), "\r\n");
2269 $remaining = $width - $nameLength - $versionLength - 4;
2270 if (strlen($description) > $remaining) {
2271 $description = substr($description, 0, $remaining - 3) . '...';
2272 }
2273 $output->write(' ' . $description);
2274 }
2275
2276 if ($writePath) {
2277 $path = strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n");
2278 $output->write(' ' . $path);
2279 }
2280 } else {
2281 $output->write($indent . $package);
2282 }
2283 $output->writeln('');
2284 }
2285 if ($tree) {
2286 $output->writeln('');
2287 }
2288 }
2289 }
2290 }
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302 protected function getPackage(RepositoryInterface $installedRepo, RepositoryInterface $repos, $name, $version = null)
2303 {
2304 $name = strtolower($name);
2305 $constraint = null;
2306 if ($version) {
2307 $constraint = $this->versionParser->parseConstraints($version);
2308 }
2309
2310 $policy = new DefaultPolicy();
2311 $pool = new Pool('dev');
2312 $pool->addRepository($repos);
2313
2314 $matchedPackage = null;
2315 $versions = array();
2316 $matches = $pool->whatProvides($name, $constraint);
2317 foreach ($matches as $index => $package) {
2318
2319  if ($package->getName() !== $name) {
2320 unset($matches[$index]);
2321 continue;
2322 }
2323
2324
2325  if (null === $version && $installedRepo->hasPackage($package)) {
2326 $matchedPackage = $package;
2327 }
2328
2329 $versions[$package->getPrettyVersion()] = $package->getVersion();
2330 $matches[$index] = $package->getId();
2331 }
2332
2333
2334  if (!$matchedPackage && $matches && $prefered = $policy->selectPreferedPackages($pool, array(), $matches)) {
2335 $matchedPackage = $pool->literalToPackage($prefered[0]);
2336 }
2337
2338 return array($matchedPackage, $versions);
2339 }
2340
2341
2342
2343
2344 protected function printMeta(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos)
2345 {
2346 $output->writeln('<info>name</info>     : ' . $package->getPrettyName());
2347 $output->writeln('<info>descrip.</info> : ' . $package->getDescription());
2348 $output->writeln('<info>keywords</info> : ' . join(', ', $package->getKeywords() ?: array()));
2349 $this->printVersions($input, $output, $package, $versions, $installedRepo, $repos);
2350 $output->writeln('<info>type</info>     : ' . $package->getType());
2351 $output->writeln('<info>license</info>  : ' . implode(', ', $package->getLicense()));
2352 $output->writeln('<info>source</info>   : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
2353 $output->writeln('<info>dist</info>     : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
2354 $output->writeln('<info>names</info>    : ' . implode(', ', $package->getNames()));
2355
2356 if ($package->isAbandoned()) {
2357 $replacement = ($package->getReplacementPackage() !== null)
2358 ? ' The author suggests using the ' . $package->getReplacementPackage(). ' package instead.'
2359 : null;
2360
2361 $output->writeln(
2362 sprintf('<error>Attention: This package is abandoned and no longer maintained.%s</error>', $replacement)
2363 );
2364 }
2365
2366 if ($package->getSupport()) {
2367 $output->writeln("\n<info>support</info>");
2368 foreach ($package->getSupport() as $type => $value) {
2369 $output->writeln('<comment>' . $type . '</comment> : '.$value);
2370 }
2371 }
2372
2373 if ($package->getAutoload()) {
2374 $output->writeln("\n<info>autoload</info>");
2375 foreach ($package->getAutoload() as $type => $autoloads) {
2376 $output->writeln('<comment>' . $type . '</comment>');
2377
2378 if ($type === 'psr-0') {
2379 foreach ($autoloads as $name => $path) {
2380 $output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
2381 }
2382 } elseif ($type === 'psr-4') {
2383 foreach ($autoloads as $name => $path) {
2384 $output->writeln(($name ?: '*') . ' => ' . (is_array($path) ? implode(', ', $path) : ($path ?: '.')));
2385 }
2386 } elseif ($type === 'classmap') {
2387 $output->writeln(implode(', ', $autoloads));
2388 }
2389 }
2390 if ($package->getIncludePaths()) {
2391 $output->writeln('<comment>include-path</comment>');
2392 $output->writeln(implode(', ', $package->getIncludePaths()));
2393 }
2394 }
2395 }
2396
2397
2398
2399
2400 protected function printVersions(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos)
2401 {
2402 uasort($versions, 'version_compare');
2403 $versions = array_keys(array_reverse($versions));
2404
2405
2406  if ($installedRepo->hasPackage($package)) {
2407 $installedVersion = $package->getPrettyVersion();
2408 $key = array_search($installedVersion, $versions);
2409 if (false !== $key) {
2410 $versions[$key] = '<info>* ' . $installedVersion . '</info>';
2411 }
2412 }
2413
2414 $versions = implode(', ', $versions);
2415
2416 $output->writeln('<info>versions</info> : ' . $versions);
2417 }
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428 protected function printLinks(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, $linkType, $title = null)
2429 {
2430 $title = $title ?: $linkType;
2431 if ($links = $package->{'get'.ucfirst($linkType)}()) {
2432 $output->writeln("\n<info>" . $title . "</info>");
2433
2434 foreach ($links as $link) {
2435 $output->writeln($link->getTarget() . ' <comment>' . $link->getPrettyConstraint() . '</comment>');
2436 }
2437 }
2438 }
2439 }
2440 <?php
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452 namespace Composer\Command;
2453
2454 use Composer\Installer;
2455 use Composer\Plugin\CommandEvent;
2456 use Composer\Plugin\PluginEvents;
2457 use Symfony\Component\Console\Input\InputInterface;
2458 use Symfony\Component\Console\Input\InputOption;
2459 use Symfony\Component\Console\Input\InputArgument;
2460 use Symfony\Component\Console\Output\OutputInterface;
2461
2462
2463
2464
2465
2466 class UpdateCommand extends Command
2467 {
2468 protected function configure()
2469 {
2470 $this
2471 ->setName('update')
2472 ->setDescription('Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.')
2473 ->setDefinition(array(
2474 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that should be updated, if not provided all packages are.'),
2475 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
2476 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
2477 new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
2478 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
2479 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
2480 new InputOption('lock', null, InputOption::VALUE_NONE, 'Only updates the lock file hash to suppress warning about the lock file being out of date.'),
2481 new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Disables all plugins.'),
2482 new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
2483 new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'),
2484 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
2485 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
2486 new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Add also all dependencies of whitelisted packages to the whitelist.'),
2487 new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
2488 new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'),
2489 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
2490 new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies.'),
2491 new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies.'),
2492 ))
2493 ->setHelp(<<<EOT
2494 The <info>update</info> command reads the composer.json file from the
2495 current directory, processes it, and updates, removes or installs all the
2496 dependencies.
2497
2498 <info>php composer.phar update</info>
2499
2500 To limit the update operation to a few packages, you can list the package(s)
2501 you want to update as such:
2502
2503 <info>php composer.phar update vendor/package1 foo/mypackage [...]</info>
2504
2505 You may also use an asterisk (*) pattern to limit the update operation to package(s)
2506 from a specific vendor:
2507
2508 <info>php composer.phar update vendor/package1 foo/* [...]</info>
2509 EOT
2510 )
2511 ;
2512 }
2513
2514 protected function execute(InputInterface $input, OutputInterface $output)
2515 {
2516 if ($input->getOption('no-custom-installers')) {
2517 $output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
2518 $input->setOption('no-plugins', true);
2519 }
2520
2521 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
2522 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
2523 $io = $this->getIO();
2524
2525 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'update', $input, $output);
2526 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
2527
2528 $install = Installer::create($io, $composer);
2529
2530 $preferSource = false;
2531 $preferDist = false;
2532
2533 $config = $composer->getConfig();
2534
2535 switch ($config->get('preferred-install')) {
2536 case 'source':
2537 $preferSource = true;
2538 break;
2539 case 'dist':
2540 $preferDist = true;
2541 break;
2542 case 'auto':
2543 default:
2544
2545  break;
2546 }
2547 if ($input->getOption('prefer-source') || $input->getOption('prefer-dist')) {
2548 $preferSource = $input->getOption('prefer-source');
2549 $preferDist = $input->getOption('prefer-dist');
2550 }
2551
2552 $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
2553
2554 $install
2555 ->setDryRun($input->getOption('dry-run'))
2556 ->setVerbose($input->getOption('verbose'))
2557 ->setPreferSource($preferSource)
2558 ->setPreferDist($preferDist)
2559 ->setDevMode(!$input->getOption('no-dev'))
2560 ->setDumpAutoloader(!$input->getOption('no-autoloader'))
2561 ->setRunScripts(!$input->getOption('no-scripts'))
2562 ->setOptimizeAutoloader($optimize)
2563 ->setUpdate(true)
2564 ->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $input->getArgument('packages'))
2565 ->setWhitelistDependencies($input->getOption('with-dependencies'))
2566 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
2567 ->setPreferStable($input->getOption('prefer-stable'))
2568 ->setPreferLowest($input->getOption('prefer-lowest'))
2569 ;
2570
2571 if ($input->getOption('no-plugins')) {
2572 $install->disablePlugins();
2573 }
2574
2575 return $install->run();
2576 }
2577 }
2578 <?php
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590 namespace Composer\Command;
2591
2592 use Symfony\Component\Console\Input\InputInterface;
2593 use Symfony\Component\Console\Input\InputArgument;
2594 use Symfony\Component\Console\Input\InputOption;
2595 use Symfony\Component\Console\Output\OutputInterface;
2596 use Composer\Config;
2597 use Composer\Config\JsonConfigSource;
2598 use Composer\Factory;
2599 use Composer\Json\JsonFile;
2600
2601
2602
2603
2604
2605 class ConfigCommand extends Command
2606 {
2607
2608
2609
2610 protected $config;
2611
2612
2613
2614
2615 protected $configFile;
2616
2617
2618
2619
2620 protected $configSource;
2621
2622
2623
2624
2625 protected function configure()
2626 {
2627 $this
2628 ->setName('config')
2629 ->setDescription('Set config options')
2630 ->setDefinition(array(
2631 new InputOption('global', 'g', InputOption::VALUE_NONE, 'Apply command to the global config file'),
2632 new InputOption('editor', 'e', InputOption::VALUE_NONE, 'Open editor'),
2633 new InputOption('auth', 'a', InputOption::VALUE_NONE, 'Affect auth config file (only used for --editor)'),
2634 new InputOption('unset', null, InputOption::VALUE_NONE, 'Unset the given setting-key'),
2635 new InputOption('list', 'l', InputOption::VALUE_NONE, 'List configuration settings'),
2636 new InputOption('file', 'f', InputOption::VALUE_REQUIRED, 'If you want to choose a different composer.json or config.json', 'composer.json'),
2637 new InputOption('absolute', null, InputOption::VALUE_NONE, 'Returns absolute paths when fetching *-dir config values instead of relative'),
2638 new InputArgument('setting-key', null, 'Setting key'),
2639 new InputArgument('setting-value', InputArgument::IS_ARRAY, 'Setting value'),
2640 ))
2641 ->setHelp(<<<EOT
2642 This command allows you to edit some basic composer settings in either the
2643 local composer.json file or the global config.json file.
2644
2645 To edit the global config.json file:
2646
2647     <comment>%command.full_name% --global</comment>
2648
2649 To add a repository:
2650
2651     <comment>%command.full_name% repositories.foo vcs http://bar.com</comment>
2652
2653 You can add a repository to the global config.json file by passing in the
2654 <info>--global</info> option.
2655
2656 To edit the file in an external editor:
2657
2658     <comment>%command.full_name% --editor</comment>
2659
2660 To choose your editor you can set the "EDITOR" env variable.
2661
2662 To get a list of configuration values in the file:
2663
2664     <comment>%command.full_name% --list</comment>
2665
2666 You can always pass more than one option. As an example, if you want to edit the
2667 global config.json file.
2668
2669     <comment>%command.full_name% --editor --global</comment>
2670 EOT
2671 )
2672 ;
2673 }
2674
2675
2676
2677
2678 protected function initialize(InputInterface $input, OutputInterface $output)
2679 {
2680 parent::initialize($input, $output);
2681
2682 if ($input->getOption('global') && 'composer.json' !== $input->getOption('file')) {
2683 throw new \RuntimeException('--file and --global can not be combined');
2684 }
2685
2686 $this->config = Factory::createConfig($this->getIO());
2687
2688
2689  
2690  $configFile = $input->getOption('global')
2691 ? ($this->config->get('home') . '/config.json')
2692 : $input->getOption('file');
2693
2694 $this->configFile = new JsonFile($configFile);
2695 $this->configSource = new JsonConfigSource($this->configFile);
2696
2697 $authConfigFile = $input->getOption('global')
2698 ? ($this->config->get('home') . '/auth.json')
2699 : dirname(realpath($input->getOption('file'))) . '/auth.json';
2700
2701 $this->authConfigFile = new JsonFile($authConfigFile);
2702 $this->authConfigSource = new JsonConfigSource($this->authConfigFile, true);
2703
2704
2705  if ($input->getOption('global') && !$this->configFile->exists()) {
2706 touch($this->configFile->getPath());
2707 $this->configFile->write(array('config' => new \ArrayObject));
2708 @chmod($this->configFile->getPath(), 0600);
2709 }
2710 if ($input->getOption('global') && !$this->authConfigFile->exists()) {
2711 touch($this->authConfigFile->getPath());
2712 $this->authConfigFile->write(array('http-basic' => new \ArrayObject, 'github-oauth' => new \ArrayObject));
2713 @chmod($this->authConfigFile->getPath(), 0600);
2714 }
2715
2716 if (!$this->configFile->exists()) {
2717 throw new \RuntimeException('No composer.json found in the current directory');
2718 }
2719 }
2720
2721
2722
2723
2724 protected function execute(InputInterface $input, OutputInterface $output)
2725 {
2726
2727  if ($input->getOption('editor')) {
2728 $editor = escapeshellcmd(getenv('EDITOR'));
2729 if (!$editor) {
2730 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
2731 $editor = 'notepad';
2732 } else {
2733 foreach (array('vim', 'vi', 'nano', 'pico', 'ed') as $candidate) {
2734 if (exec('which '.$candidate)) {
2735 $editor = $candidate;
2736 break;
2737 }
2738 }
2739 }
2740 }
2741
2742 $file = $input->getOption('auth') ? $this->authConfigFile->getPath() : $this->configFile->getPath();
2743 system($editor . ' ' . $file . (defined('PHP_WINDOWS_VERSION_BUILD') ? '' : ' > `tty`'));
2744
2745 return 0;
2746 }
2747
2748 if (!$input->getOption('global')) {
2749 $this->config->merge($this->configFile->read());
2750 $this->config->merge(array('config' => $this->authConfigFile->exists() ? $this->authConfigFile->read() : array()));
2751 }
2752
2753
2754  if ($input->getOption('list')) {
2755 $this->listConfiguration($this->config->all(), $this->config->raw(), $output);
2756
2757 return 0;
2758 }
2759
2760 $settingKey = $input->getArgument('setting-key');
2761 if (!$settingKey) {
2762 return 0;
2763 }
2764
2765
2766  if (array() !== $input->getArgument('setting-value') && $input->getOption('unset')) {
2767 throw new \RuntimeException('You can not combine a setting value with --unset');
2768 }
2769
2770
2771  if (array() === $input->getArgument('setting-value') && !$input->getOption('unset')) {
2772 $data = $this->config->all();
2773 if (preg_match('/^repos?(?:itories)?(?:\.(.+))?/', $settingKey, $matches)) {
2774 if (empty($matches[1])) {
2775 $value = isset($data['repositories']) ? $data['repositories'] : array();
2776 } else {
2777 if (!isset($data['repositories'][$matches[1]])) {
2778 throw new \InvalidArgumentException('There is no '.$matches[1].' repository defined');
2779 }
2780
2781 $value = $data['repositories'][$matches[1]];
2782 }
2783 } elseif (strpos($settingKey, '.')) {
2784 $bits = explode('.', $settingKey);
2785 $data = $data['config'];
2786 foreach ($bits as $bit) {
2787 if (isset($data[$bit])) {
2788 $data = $data[$bit];
2789 } elseif (isset($data[implode('.', $bits)])) {
2790
2791  $data = $data[implode('.', $bits)];
2792 break;
2793 } else {
2794 throw new \RuntimeException($settingKey.' is not defined');
2795 }
2796 array_shift($bits);
2797 }
2798
2799 $value = $data;
2800 } elseif (isset($data['config'][$settingKey])) {
2801 $value = $this->config->get($settingKey, $input->getOption('absolute') ? 0 : Config::RELATIVE_PATHS);
2802 } else {
2803 throw new \RuntimeException($settingKey.' is not defined');
2804 }
2805
2806 if (is_array($value)) {
2807 $value = json_encode($value);
2808 }
2809
2810 $output->writeln($value);
2811
2812 return 0;
2813 }
2814
2815 $values = $input->getArgument('setting-value'); 
2816
2817
2818  if (preg_match('/^repos?(?:itories)?\.(.+)/', $settingKey, $matches)) {
2819 if ($input->getOption('unset')) {
2820 return $this->configSource->removeRepository($matches[1]);
2821 }
2822
2823 if (2 !== count($values)) {
2824 throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs http://bar.com');
2825 }
2826
2827 return $this->configSource->addRepository($matches[1], array(
2828 'type' => $values[0],
2829 'url' => $values[1],
2830 ));
2831 }
2832
2833
2834  if (preg_match('/^(github-oauth|http-basic)\.(.+)/', $settingKey, $matches)) {
2835 if ($input->getOption('unset')) {
2836 $this->authConfigSource->removeConfigSetting($matches[1].'.'.$matches[2]);
2837 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
2838
2839 return;
2840 }
2841
2842 if ($matches[1] === 'github-oauth') {
2843 if (1 !== count($values)) {
2844 throw new \RuntimeException('Too many arguments, expected only one token');
2845 }
2846 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
2847 $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], $values[0]);
2848 } elseif ($matches[1] === 'http-basic') {
2849 if (2 !== count($values)) {
2850 throw new \RuntimeException('Expected two arguments (username, password), got '.count($values));
2851 }
2852 $this->configSource->removeConfigSetting($matches[1].'.'.$matches[2]);
2853 $this->authConfigSource->addConfigSetting($matches[1].'.'.$matches[2], array('username' => $values[0], 'password' => $values[1]));
2854 }
2855
2856 return;
2857 }
2858
2859 $booleanValidator = function ($val) { return in_array($val, array('true', 'false', '1', '0'), true); };
2860 $booleanNormalizer = function ($val) { return $val !== 'false' && (bool) $val; };
2861
2862
2863  $uniqueConfigValues = array(
2864 'process-timeout' => array('is_numeric', 'intval'),
2865 'use-include-path' => array($booleanValidator, $booleanNormalizer),
2866 'preferred-install' => array(
2867 function ($val) { return in_array($val, array('auto', 'source', 'dist'), true); },
2868 function ($val) { return $val; }
2869 ),
2870 'store-auths' => array(
2871 function ($val) { return in_array($val, array('true', 'false', 'prompt'), true); },
2872 function ($val) {
2873 if ('prompt' === $val) {
2874 return 'prompt';
2875 }
2876
2877 return $val !== 'false' && (bool) $val;
2878 }
2879 ),
2880 'notify-on-install' => array($booleanValidator, $booleanNormalizer),
2881 'vendor-dir' => array('is_string', function ($val) { return $val; }),
2882 'bin-dir' => array('is_string', function ($val) { return $val; }),
2883 'cache-dir' => array('is_string', function ($val) { return $val; }),
2884 'cache-files-dir' => array('is_string', function ($val) { return $val; }),
2885 'cache-repo-dir' => array('is_string', function ($val) { return $val; }),
2886 'cache-vcs-dir' => array('is_string', function ($val) { return $val; }),
2887 'cache-ttl' => array('is_numeric', 'intval'),
2888 'cache-files-ttl' => array('is_numeric', 'intval'),
2889 'cache-files-maxsize' => array(
2890 function ($val) { return preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $val) > 0; },
2891 function ($val) { return $val; }
2892 ),
2893 'discard-changes' => array(
2894 function ($val) { return in_array($val, array('stash', 'true', 'false', '1', '0'), true); },
2895 function ($val) {
2896 if ('stash' === $val) {
2897 return 'stash';
2898 }
2899
2900 return $val !== 'false' && (bool) $val;
2901 }
2902 ),
2903 'autoloader-suffix' => array('is_string', function ($val) { return $val === 'null' ? null : $val; }),
2904 'optimize-autoloader' => array($booleanValidator, $booleanNormalizer),
2905 'prepend-autoloader' => array($booleanValidator, $booleanNormalizer),
2906 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer),
2907 );
2908 $multiConfigValues = array(
2909 'github-protocols' => array(
2910 function ($vals) {
2911 if (!is_array($vals)) {
2912 return 'array expected';
2913 }
2914
2915 foreach ($vals as $val) {
2916 if (!in_array($val, array('git', 'https', 'ssh'))) {
2917 return 'valid protocols include: git, https, ssh';
2918 }
2919 }
2920
2921 return true;
2922 },
2923 function ($vals) {
2924 return $vals;
2925 }
2926 ),
2927 'github-domains' => array(
2928 function ($vals) {
2929 if (!is_array($vals)) {
2930 return 'array expected';
2931 }
2932
2933 return true;
2934 },
2935 function ($vals) {
2936 return $vals;
2937 }
2938 ),
2939 );
2940
2941 foreach ($uniqueConfigValues as $name => $callbacks) {
2942 if ($settingKey === $name) {
2943 if ($input->getOption('unset')) {
2944 return $this->configSource->removeConfigSetting($settingKey);
2945 }
2946
2947 list($validator, $normalizer) = $callbacks;
2948 if (1 !== count($values)) {
2949 throw new \RuntimeException('You can only pass one value. Example: php composer.phar config process-timeout 300');
2950 }
2951
2952 if (true !== $validation = $validator($values[0])) {
2953 throw new \RuntimeException(sprintf(
2954 '"%s" is an invalid value'.($validation ? ' ('.$validation.')' : ''),
2955 $values[0]
2956 ));
2957 }
2958
2959 return $this->configSource->addConfigSetting($settingKey, $normalizer($values[0]));
2960 }
2961 }
2962
2963 foreach ($multiConfigValues as $name => $callbacks) {
2964 if ($settingKey === $name) {
2965 if ($input->getOption('unset')) {
2966 return $this->configSource->removeConfigSetting($settingKey);
2967 }
2968
2969 list($validator, $normalizer) = $callbacks;
2970 if (true !== $validation = $validator($values)) {
2971 throw new \RuntimeException(sprintf(
2972 '%s is an invalid value'.($validation ? ' ('.$validation.')' : ''),
2973 json_encode($values)
2974 ));
2975 }
2976
2977 return $this->configSource->addConfigSetting($settingKey, $normalizer($values));
2978 }
2979 }
2980
2981 throw new \InvalidArgumentException('Setting '.$settingKey.' does not exist or is not supported by this command');
2982 }
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992 protected function listConfiguration(array $contents, array $rawContents, OutputInterface $output, $k = null)
2993 {
2994 $origK = $k;
2995 foreach ($contents as $key => $value) {
2996 if ($k === null && !in_array($key, array('config', 'repositories'))) {
2997 continue;
2998 }
2999
3000 $rawVal = isset($rawContents[$key]) ? $rawContents[$key] : null;
3001
3002 if (is_array($value) && (!is_numeric(key($value)) || ($key === 'repositories' && null === $k))) {
3003 $k .= preg_replace('{^config\.}', '', $key . '.');
3004 $this->listConfiguration($value, $rawVal, $output, $k);
3005
3006 if (substr_count($k, '.') > 1) {
3007 $k = str_split($k, strrpos($k, '.', -2));
3008 $k = $k[0] . '.';
3009 } else {
3010 $k = $origK;
3011 }
3012
3013 continue;
3014 }
3015
3016 if (is_array($value)) {
3017 $value = array_map(function ($val) {
3018 return is_array($val) ? json_encode($val) : $val;
3019 }, $value);
3020
3021 $value = '['.implode(', ', $value).']';
3022 }
3023
3024 if (is_bool($value)) {
3025 $value = var_export($value, true);
3026 }
3027
3028 if (is_string($rawVal) && $rawVal != $value) {
3029 $output->writeln('[<comment>' . $k . $key . '</comment>] <info>' . $rawVal . ' (' . $value . ')</info>');
3030 } else {
3031 $output->writeln('[<comment>' . $k . $key . '</comment>] <info>' . $value . '</info>');
3032 }
3033 }
3034 }
3035 }
3036 <?php
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048 namespace Composer\Command;
3049
3050 use Composer\Installer;
3051 use Composer\Plugin\CommandEvent;
3052 use Composer\Plugin\PluginEvents;
3053 use Symfony\Component\Console\Input\InputInterface;
3054 use Symfony\Component\Console\Input\InputOption;
3055 use Symfony\Component\Console\Input\InputArgument;
3056 use Symfony\Component\Console\Output\OutputInterface;
3057
3058
3059
3060
3061
3062
3063
3064 class InstallCommand extends Command
3065 {
3066 protected function configure()
3067 {
3068 $this
3069 ->setName('install')
3070 ->setDescription('Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.')
3071 ->setDefinition(array(
3072 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
3073 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
3074 new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
3075 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
3076 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
3077 new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Disables all plugins.'),
3078 new InputOption('no-custom-installers', null, InputOption::VALUE_NONE, 'DEPRECATED: Use no-plugins instead.'),
3079 new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'),
3080 new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'),
3081 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
3082 new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'),
3083 new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump'),
3084 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
3085 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Should not be provided, use composer require instead to add a given package to composer.json.'),
3086 ))
3087 ->setHelp(<<<EOT
3088 The <info>install</info> command reads the composer.lock file from
3089 the current directory, processes it, and downloads and installs all the
3090 libraries and dependencies outlined in that file. If the file does not
3091 exist it will look for composer.json and do the same.
3092
3093 <info>php composer.phar install</info>
3094
3095 EOT
3096 )
3097 ;
3098 }
3099
3100 protected function execute(InputInterface $input, OutputInterface $output)
3101 {
3102 if ($args = $input->getArgument('packages')) {
3103 $output->writeln('<error>Invalid argument '.implode(' ', $args).'. Use "composer require '.implode(' ', $args).'" instead to add packages to your composer.json.</error>');
3104
3105 return 1;
3106 }
3107
3108 if ($input->getOption('no-custom-installers')) {
3109 $output->writeln('<warning>You are using the deprecated option "no-custom-installers". Use "no-plugins" instead.</warning>');
3110 $input->setOption('no-plugins', true);
3111 }
3112
3113 $composer = $this->getComposer(true, $input->getOption('no-plugins'));
3114 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
3115 $io = $this->getIO();
3116
3117 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'install', $input, $output);
3118 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
3119
3120 $install = Installer::create($io, $composer);
3121
3122 $preferSource = false;
3123 $preferDist = false;
3124
3125 $config = $composer->getConfig();
3126
3127 switch ($config->get('preferred-install')) {
3128 case 'source':
3129 $preferSource = true;
3130 break;
3131 case 'dist':
3132 $preferDist = true;
3133 break;
3134 case 'auto':
3135 default:
3136
3137  break;
3138 }
3139 if ($input->getOption('prefer-source') || $input->getOption('prefer-dist')) {
3140 $preferSource = $input->getOption('prefer-source');
3141 $preferDist = $input->getOption('prefer-dist');
3142 }
3143
3144 $optimize = $input->getOption('optimize-autoloader') || $config->get('optimize-autoloader');
3145
3146 $install
3147 ->setDryRun($input->getOption('dry-run'))
3148 ->setVerbose($input->getOption('verbose'))
3149 ->setPreferSource($preferSource)
3150 ->setPreferDist($preferDist)
3151 ->setDevMode(!$input->getOption('no-dev'))
3152 ->setDumpAutoloader(!$input->getOption('no-autoloader'))
3153 ->setRunScripts(!$input->getOption('no-scripts'))
3154 ->setOptimizeAutoloader($optimize)
3155 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
3156 ;
3157
3158 if ($input->getOption('no-plugins')) {
3159 $install->disablePlugins();
3160 }
3161
3162 return $install->run();
3163 }
3164 }
3165 <?php
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177 namespace Composer\Command;
3178
3179 use Composer\Package\Loader\ValidatingArrayLoader;
3180 use Composer\Util\ConfigValidator;
3181 use Symfony\Component\Console\Input\InputArgument;
3182 use Symfony\Component\Console\Input\InputInterface;
3183 use Symfony\Component\Console\Input\InputOption;
3184 use Symfony\Component\Console\Output\OutputInterface;
3185
3186
3187
3188
3189
3190
3191
3192 class ValidateCommand extends Command
3193 {
3194
3195
3196
3197 protected function configure()
3198 {
3199 $this
3200 ->setName('validate')
3201 ->setDescription('Validates a composer.json')
3202 ->setDefinition(array(
3203 new InputOption('no-check-all', null, InputOption::VALUE_NONE, 'Do not make a complete validation'),
3204 new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json')
3205 ))
3206 ->setHelp(<<<EOT
3207 The validate command validates a given composer.json
3208
3209 EOT
3210 );
3211 }
3212
3213
3214
3215
3216
3217
3218
3219 protected function execute(InputInterface $input, OutputInterface $output)
3220 {
3221 $file = $input->getArgument('file');
3222
3223 if (!file_exists($file)) {
3224 $output->writeln('<error>' . $file . ' not found.</error>');
3225
3226 return 1;
3227 }
3228 if (!is_readable($file)) {
3229 $output->writeln('<error>' . $file . ' is not readable.</error>');
3230
3231 return 1;
3232 }
3233
3234 $validator = new ConfigValidator($this->getIO());
3235 $checkAll = $input->getOption('no-check-all') ? 0 : ValidatingArrayLoader::CHECK_ALL;
3236 list($errors, $publishErrors, $warnings) = $validator->validate($file, $checkAll);
3237
3238
3239  if (!$errors && !$publishErrors && !$warnings) {
3240 $output->writeln('<info>' . $file . ' is valid</info>');
3241 } elseif (!$errors && !$publishErrors) {
3242 $output->writeln('<info>' . $file . ' is valid, but with a few warnings</info>');
3243 $output->writeln('<warning>See http://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
3244 } elseif (!$errors) {
3245 $output->writeln('<info>' . $file . ' is valid for simple usage with composer but has</info>');
3246 $output->writeln('<info>strict errors that make it unable to be published as a package:</info>');
3247 $output->writeln('<warning>See http://getcomposer.org/doc/04-schema.md for details on the schema</warning>');
3248 } else {
3249 $output->writeln('<error>' . $file . ' is invalid, the following errors/warnings were found:</error>');
3250 }
3251
3252 $messages = array(
3253 'error' => array_merge($errors, $publishErrors),
3254 'warning' => $warnings,
3255 );
3256
3257 foreach ($messages as $style => $msgs) {
3258 foreach ($msgs as $msg) {
3259 $output->writeln('<' . $style . '>' . $msg . '</' . $style . '>');
3260 }
3261 }
3262
3263 return $errors || $publishErrors ? 1 : 0;
3264 }
3265 }
3266 <?php
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278 namespace Composer\Command;
3279
3280 use Composer\DependencyResolver\Pool;
3281 use Composer\Plugin\CommandEvent;
3282 use Composer\Plugin\PluginEvents;
3283 use Symfony\Component\Console\Input\InputInterface;
3284 use Symfony\Component\Console\Input\InputArgument;
3285 use Symfony\Component\Console\Input\InputOption;
3286 use Symfony\Component\Console\Output\OutputInterface;
3287
3288
3289
3290
3291
3292 class DependsCommand extends Command
3293 {
3294 protected $linkTypes = array(
3295 'require' => array('requires', 'requires'),
3296 'require-dev' => array('devRequires', 'requires (dev)'),
3297 );
3298
3299 protected function configure()
3300 {
3301 $this
3302 ->setName('depends')
3303 ->setDescription('Shows which packages depend on the given package')
3304 ->setDefinition(array(
3305 new InputArgument('package', InputArgument::REQUIRED, 'Package to inspect'),
3306 new InputOption('link-type', '', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Link types to show (require, require-dev)', array_keys($this->linkTypes)),
3307 ))
3308 ->setHelp(<<<EOT
3309 Displays detailed information about where a package is referenced.
3310
3311 <info>php composer.phar depends composer/composer</info>
3312
3313 EOT
3314 )
3315 ;
3316 }
3317
3318 protected function execute(InputInterface $input, OutputInterface $output)
3319 {
3320 $composer = $this->getComposer();
3321
3322 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'depends', $input, $output);
3323 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
3324
3325 $repo = $composer->getRepositoryManager()->getLocalRepository();
3326 $needle = $input->getArgument('package');
3327
3328 $pool = new Pool();
3329 $pool->addRepository($repo);
3330
3331 $packages = $pool->whatProvides($needle);
3332 if (empty($packages)) {
3333 throw new \InvalidArgumentException('Could not find package "'.$needle.'" in your project.');
3334 }
3335
3336 $linkTypes = $this->linkTypes;
3337
3338 $types = array_map(function ($type) use ($linkTypes) {
3339 $type = rtrim($type, 's');
3340 if (!isset($linkTypes[$type])) {
3341 throw new \InvalidArgumentException('Unexpected link type: '.$type.', valid types: '.implode(', ', array_keys($linkTypes)));
3342 }
3343
3344 return $type;
3345 }, $input->getOption('link-type'));
3346
3347 $messages = array();
3348 $outputPackages = array();
3349 foreach ($repo->getPackages() as $package) {
3350 foreach ($types as $type) {
3351 foreach ($package->{'get'.$linkTypes[$type][0]}() as $link) {
3352 if ($link->getTarget() === $needle) {
3353 if (!isset($outputPackages[$package->getName()])) {
3354 $messages[] = '<info>'.$package->getPrettyName() . '</info> ' . $linkTypes[$type][1] . ' ' . $needle .' (<info>' . $link->getPrettyConstraint() . '</info>)';
3355 $outputPackages[$package->getName()] = true;
3356 }
3357 }
3358 }
3359 }
3360 }
3361
3362 if ($messages) {
3363 sort($messages);
3364 $output->writeln($messages);
3365 } else {
3366 $output->writeln('<info>There is no installed package depending on "'.$needle.'".</info>');
3367 }
3368 }
3369 }
3370 <?php
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382 namespace Composer\Command;
3383
3384 use Symfony\Component\Console\Input\InputInterface;
3385 use Symfony\Component\Console\Input\InputArgument;
3386 use Symfony\Component\Console\Input\InputOption;
3387 use Symfony\Component\Console\Output\OutputInterface;
3388 use Composer\Repository\CompositeRepository;
3389 use Composer\Repository\PlatformRepository;
3390 use Composer\Repository\RepositoryInterface;
3391 use Composer\Factory;
3392 use Composer\Plugin\CommandEvent;
3393 use Composer\Plugin\PluginEvents;
3394
3395
3396
3397
3398 class SearchCommand extends Command
3399 {
3400 protected $matches;
3401 protected $lowMatches = array();
3402 protected $tokens;
3403 protected $output;
3404 protected $onlyName;
3405
3406 protected function configure()
3407 {
3408 $this
3409 ->setName('search')
3410 ->setDescription('Search for packages')
3411 ->setDefinition(array(
3412 new InputOption('only-name', 'N', InputOption::VALUE_NONE, 'Search only in name'),
3413 new InputArgument('tokens', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'tokens to search for'),
3414 ))
3415 ->setHelp(<<<EOT
3416 The search command searches for packages by its name
3417 <info>php composer.phar search symfony composer</info>
3418
3419 EOT
3420 )
3421 ;
3422 }
3423
3424 protected function execute(InputInterface $input, OutputInterface $output)
3425 {
3426
3427  $platformRepo = new PlatformRepository;
3428 if ($composer = $this->getComposer(false)) {
3429 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
3430 $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
3431 $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
3432 } else {
3433 $defaultRepos = Factory::createDefaultRepositories($this->getIO());
3434 $output->writeln('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos)));
3435 $installedRepo = $platformRepo;
3436 $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
3437 }
3438
3439 if ($composer) {
3440 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'search', $input, $output);
3441 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
3442 }
3443
3444 $onlyName = $input->getOption('only-name');
3445
3446 $flags = $onlyName ? RepositoryInterface::SEARCH_NAME : RepositoryInterface::SEARCH_FULLTEXT;
3447 $results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags);
3448
3449 foreach ($results as $result) {
3450 $output->writeln($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));
3451 }
3452 }
3453 }
3454 <?php
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466 namespace Composer\Command;
3467
3468 use Composer\Composer;
3469 use Composer\Factory;
3470 use Composer\Util\Filesystem;
3471 use Composer\Util\RemoteFilesystem;
3472 use Composer\Downloader\FilesystemException;
3473 use Symfony\Component\Console\Input\InputInterface;
3474 use Symfony\Component\Console\Input\InputOption;
3475 use Symfony\Component\Console\Input\InputArgument;
3476 use Symfony\Component\Console\Output\OutputInterface;
3477 use Symfony\Component\Finder\Finder;
3478
3479
3480
3481
3482
3483
3484 class SelfUpdateCommand extends Command
3485 {
3486 const HOMEPAGE = 'getcomposer.org';
3487 const OLD_INSTALL_EXT = '-old.phar';
3488
3489 protected function configure()
3490 {
3491 $this
3492 ->setName('self-update')
3493 ->setAliases(array('selfupdate'))
3494 ->setDescription('Updates composer.phar to the latest version.')
3495 ->setDefinition(array(
3496 new InputOption('rollback', 'r', InputOption::VALUE_NONE, 'Revert to an older installation of composer'),
3497 new InputOption('clean-backups', null, InputOption::VALUE_NONE, 'Delete old backups during an update. This makes the current version of composer the only backup available after the update'),
3498 new InputArgument('version', InputArgument::OPTIONAL, 'The version to update to'),
3499 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
3500 ))
3501 ->setHelp(<<<EOT
3502 The <info>self-update</info> command checks getcomposer.org for newer
3503 versions of composer and if found, installs the latest.
3504
3505 <info>php composer.phar self-update</info>
3506
3507 EOT
3508 )
3509 ;
3510 }
3511
3512 protected function execute(InputInterface $input, OutputInterface $output)
3513 {
3514 $baseUrl = (extension_loaded('openssl') ? 'https' : 'http') . '://' . self::HOMEPAGE;
3515 $config = Factory::createConfig();
3516 $remoteFilesystem = new RemoteFilesystem($this->getIO(), $config);
3517 $cacheDir = $config->get('cache-dir');
3518 $rollbackDir = $config->get('home');
3519 $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
3520
3521
3522  $tmpDir = is_writable(dirname($localFilename)) ? dirname($localFilename) : $cacheDir;
3523
3524
3525  if (!is_writable($tmpDir)) {
3526 throw new FilesystemException('Composer update failed: the "'.$tmpDir.'" directory used to download the temp file could not be written');
3527 }
3528 if (!is_writable($localFilename)) {
3529 throw new FilesystemException('Composer update failed: the "'.$localFilename.'" file could not be written');
3530 }
3531
3532 if ($input->getOption('rollback')) {
3533 return $this->rollback($output, $rollbackDir, $localFilename);
3534 }
3535
3536 $latestVersion = trim($remoteFilesystem->getContents(self::HOMEPAGE, $baseUrl. '/version', false));
3537 $updateVersion = $input->getArgument('version') ?: $latestVersion;
3538
3539 if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) {
3540 $output->writeln('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>');
3541
3542 return 1;
3543 }
3544
3545 if (Composer::VERSION === $updateVersion) {
3546 $output->writeln('<info>You are already using composer version '.$updateVersion.'.</info>');
3547
3548 return 0;
3549 }
3550
3551 $tempFilename = $tmpDir . '/' . basename($localFilename, '.phar').'-temp.phar';
3552 $backupFile = sprintf(
3553 '%s/%s-%s%s',
3554 $rollbackDir,
3555 strtr(Composer::RELEASE_DATE, ' :', '_-'),
3556 preg_replace('{^([0-9a-f]{7})[0-9a-f]{33}$}', '$1', Composer::VERSION),
3557 self::OLD_INSTALL_EXT
3558 );
3559
3560 $output->writeln(sprintf("Updating to version <info>%s</info>.", $updateVersion));
3561 $remoteFilename = $baseUrl . (preg_match('{^[0-9a-f]{40}$}', $updateVersion) ? '/composer.phar' : "/download/{$updateVersion}/composer.phar");
3562 $remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename, !$input->getOption('no-progress'));
3563 if (!file_exists($tempFilename)) {
3564 $output->writeln('<error>The download of the new composer version failed for an unexpected reason</error>');
3565
3566 return 1;
3567 }
3568
3569
3570  if ($input->getOption('clean-backups')) {
3571 $finder = $this->getOldInstallationFinder($rollbackDir);
3572
3573 $fs = new Filesystem;
3574 foreach ($finder as $file) {
3575 $file = (string) $file;
3576 $output->writeln('<info>Removing: '.$file.'</info>');
3577 $fs->remove($file);
3578 }
3579 }
3580
3581 if ($err = $this->setLocalPhar($localFilename, $tempFilename, $backupFile)) {
3582 $output->writeln('<error>The file is corrupted ('.$err->getMessage().').</error>');
3583 $output->writeln('<error>Please re-run the self-update command to try again.</error>');
3584
3585 return 1;
3586 }
3587
3588 if (file_exists($backupFile)) {
3589 $output->writeln('Use <info>composer self-update --rollback</info> to return to version '.Composer::VERSION);
3590 } else {
3591 $output->writeln('<warning>A backup of the current version could not be written to '.$backupFile.', no rollback possible</warning>');
3592 }
3593 }
3594
3595 protected function rollback(OutputInterface $output, $rollbackDir, $localFilename)
3596 {
3597 $rollbackVersion = $this->getLastBackupVersion($rollbackDir);
3598 if (!$rollbackVersion) {
3599 throw new \UnexpectedValueException('Composer rollback failed: no installation to roll back to in "'.$rollbackDir.'"');
3600 }
3601
3602 if (!is_writable($rollbackDir)) {
3603 throw new FilesystemException('Composer rollback failed: the "'.$rollbackDir.'" dir could not be written to');
3604 }
3605
3606 $old = $rollbackDir . '/' . $rollbackVersion . self::OLD_INSTALL_EXT;
3607
3608 if (!is_file($old)) {
3609 throw new FilesystemException('Composer rollback failed: "'.$old.'" could not be found');
3610 }
3611 if (!is_readable($old)) {
3612 throw new FilesystemException('Composer rollback failed: "'.$old.'" could not be read');
3613 }
3614
3615 $oldFile = $rollbackDir . "/{$rollbackVersion}" . self::OLD_INSTALL_EXT;
3616 $output->writeln(sprintf("Rolling back to version <info>%s</info>.", $rollbackVersion));
3617 if ($err = $this->setLocalPhar($localFilename, $oldFile)) {
3618 $output->writeln('<error>The backup file was corrupted ('.$err->getMessage().') and has been removed.</error>');
3619
3620 return 1;
3621 }
3622
3623 return 0;
3624 }
3625
3626 protected function setLocalPhar($localFilename, $newFilename, $backupTarget = null)
3627 {
3628 try {
3629 @chmod($newFilename, 0777 & ~umask());
3630 if (!ini_get('phar.readonly')) {
3631
3632  $phar = new \Phar($newFilename);
3633
3634  unset($phar);
3635 }
3636
3637
3638  if ($backupTarget && file_exists($localFilename)) {
3639 @copy($localFilename, $backupTarget);
3640 }
3641
3642 rename($newFilename, $localFilename);
3643 } catch (\Exception $e) {
3644 if ($backupTarget) {
3645 @unlink($newFilename);
3646 }
3647 if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) {
3648 throw $e;
3649 }
3650
3651 return $e;
3652 }
3653 }
3654
3655 protected function getLastBackupVersion($rollbackDir)
3656 {
3657 $finder = $this->getOldInstallationFinder($rollbackDir);
3658 $finder->sortByName();
3659 $files = iterator_to_array($finder);
3660
3661 if (count($files)) {
3662 return basename(end($files), self::OLD_INSTALL_EXT);
3663 }
3664
3665 return false;
3666 }
3667
3668 protected function getOldInstallationFinder($rollbackDir)
3669 {
3670 $finder = Finder::create()
3671 ->depth(0)
3672 ->files()
3673 ->name('*' . self::OLD_INSTALL_EXT)
3674 ->in($rollbackDir);
3675
3676 return $finder;
3677 }
3678 }
3679 <?php
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691 namespace Composer\Command;
3692
3693 use Composer\Json\JsonFile;
3694 use Composer\Package\Version\VersionParser;
3695 use Composer\Plugin\CommandEvent;
3696 use Composer\Plugin\PluginEvents;
3697 use Composer\Package\PackageInterface;
3698 use Composer\Repository\RepositoryInterface;
3699 use Symfony\Component\Console\Helper\TableHelper;
3700 use Symfony\Component\Console\Input\InputInterface;
3701 use Symfony\Component\Console\Input\InputOption;
3702 use Symfony\Component\Console\Output\OutputInterface;
3703
3704
3705
3706
3707 class LicensesCommand extends Command
3708 {
3709 protected function configure()
3710 {
3711 $this
3712 ->setName('licenses')
3713 ->setDescription('Show information about licenses of dependencies')
3714 ->setDefinition(array(
3715 new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Format of the output: text or json', 'text'),
3716 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables search in require-dev packages.'),
3717 ))
3718 ->setHelp(<<<EOT
3719 The license command displays detailed information about the licenses of
3720 the installed dependencies.
3721
3722 EOT
3723 )
3724 ;
3725 }
3726
3727 protected function execute(InputInterface $input, OutputInterface $output)
3728 {
3729 $composer = $this->getComposer();
3730
3731 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'licenses', $input, $output);
3732 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
3733
3734 $root = $composer->getPackage();
3735 $repo = $composer->getRepositoryManager()->getLocalRepository();
3736
3737 $versionParser = new VersionParser;
3738
3739 if ($input->getOption('no-dev')) {
3740 $packages = $this->filterRequiredPackages($repo, $root);
3741 } else {
3742 $packages = $this->appendPackages($repo->getPackages(), array());
3743 }
3744
3745 ksort($packages);
3746
3747 switch ($format = $input->getOption('format')) {
3748 case 'text':
3749 $output->writeln('Name: <comment>'.$root->getPrettyName().'</comment>');
3750 $output->writeln('Version: <comment>'.$versionParser->formatVersion($root).'</comment>');
3751 $output->writeln('Licenses: <comment>'.(implode(', ', $root->getLicense()) ?: 'none').'</comment>');
3752 $output->writeln('Dependencies:');
3753
3754 $table = $this->getHelperSet()->get('table');
3755 $table->setLayout(TableHelper::LAYOUT_BORDERLESS);
3756 $table->setHorizontalBorderChar('');
3757 foreach ($packages as $package) {
3758 $table->addRow(array(
3759 $package->getPrettyName(),
3760 $versionParser->formatVersion($package),
3761 implode(', ', $package->getLicense()) ?: 'none',
3762 ));
3763 }
3764 $table->render($output);
3765 break;
3766
3767 case 'json':
3768 foreach ($packages as $package) {
3769 $dependencies[$package->getPrettyName()] = array(
3770 'version' => $versionParser->formatVersion($package),
3771 'license' => $package->getLicense(),
3772 );
3773 }
3774
3775 $output->writeln(JsonFile::encode(array(
3776 'name' => $root->getPrettyName(),
3777 'version' => $versionParser->formatVersion($root),
3778 'license' => $root->getLicense(),
3779 'dependencies' => $dependencies,
3780 )));
3781 break;
3782
3783 default:
3784 throw new \RuntimeException(sprintf('Unsupported format "%s".  See help for supported formats.', $format));
3785 }
3786 }
3787
3788
3789
3790
3791
3792
3793
3794 private function filterRequiredPackages(RepositoryInterface $repo, PackageInterface $package, $bucket = array())
3795 {
3796 $requires = array_keys($package->getRequires());
3797
3798 $packageListNames = array_keys($bucket);
3799 $packages = array_filter(
3800 $repo->getPackages(),
3801 function ($package) use ($requires, $packageListNames) {
3802 return in_array($package->getName(), $requires) && !in_array($package->getName(), $packageListNames);
3803 }
3804 );
3805
3806 $bucket = $this->appendPackages($packages, $bucket);
3807
3808 foreach ($packages as $package) {
3809 $bucket = $this->filterRequiredPackages($repo, $package, $bucket);
3810 }
3811
3812 return $bucket;
3813 }
3814
3815
3816
3817
3818
3819
3820
3821
3822 public function appendPackages(array $packages, array $bucket)
3823 {
3824 foreach ($packages as $package) {
3825 $bucket[$package->getName()] = $package;
3826 }
3827
3828 return $bucket;
3829 }
3830 }
3831 <?php
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843 namespace Composer\Command;
3844
3845 use Composer\DependencyResolver\Pool;
3846 use Composer\Factory;
3847 use Composer\Package\CompletePackageInterface;
3848 use Composer\Repository\CompositeRepository;
3849 use Composer\Repository\RepositoryInterface;
3850 use Composer\Util\ProcessExecutor;
3851 use Symfony\Component\Console\Input\InputArgument;
3852 use Symfony\Component\Console\Input\InputOption;
3853 use Symfony\Component\Console\Input\InputInterface;
3854 use Symfony\Component\Console\Output\OutputInterface;
3855
3856
3857
3858
3859 class HomeCommand extends Command
3860 {
3861
3862
3863
3864 protected function configure()
3865 {
3866 $this
3867 ->setName('browse')
3868 ->setAliases(array('home'))
3869 ->setDescription('Opens the package\'s repository URL or homepage in your browser.')
3870 ->setDefinition(array(
3871 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Package(s) to browse to.'),
3872 new InputOption('homepage', 'H', InputOption::VALUE_NONE, 'Open the homepage instead of the repository URL.'),
3873 ))
3874 ->setHelp(<<<EOT
3875 The home command opens a package's repository URL or
3876 homepage in your default browser.
3877
3878 To open the homepage by default, use -H or --homepage.
3879 EOT
3880 );
3881 }
3882
3883
3884
3885
3886 protected function execute(InputInterface $input, OutputInterface $output)
3887 {
3888 $repo = $this->initializeRepo();
3889 $return = 0;
3890
3891 foreach ($input->getArgument('packages') as $packageName) {
3892 $package = $this->getPackage($repo, $packageName);
3893
3894 if (!$package instanceof CompletePackageInterface) {
3895 $return = 1;
3896 $output->writeln('<warning>Package '.$packageName.' not found</warning>');
3897
3898 continue;
3899 }
3900
3901 $support = $package->getSupport();
3902 $url = isset($support['source']) ? $support['source'] : $package->getSourceUrl();
3903 if (!$url || $input->getOption('homepage')) {
3904 $url = $package->getHomepage();
3905 }
3906
3907 if (!filter_var($url, FILTER_VALIDATE_URL)) {
3908 $return = 1;
3909 $output->writeln('<warning>'.($input->getOption('homepage') ? 'Invalid or missing homepage' : 'Invalid or missing repository URL').' for '.$packageName.'</warning>');
3910
3911 continue;
3912 }
3913
3914 $this->openBrowser($url);
3915 }
3916
3917 return $return;
3918 }
3919
3920
3921
3922
3923
3924
3925
3926
3927 protected function getPackage(RepositoryInterface $repos, $name)
3928 {
3929 $name = strtolower($name);
3930 $pool = new Pool('dev');
3931 $pool->addRepository($repos);
3932 $matches = $pool->whatProvides($name);
3933
3934 foreach ($matches as $index => $package) {
3935
3936  if ($package->getName() !== $name) {
3937 unset($matches[$index]);
3938 continue;
3939 }
3940
3941 return $package;
3942 }
3943 }
3944
3945
3946
3947
3948
3949
3950 private function openBrowser($url)
3951 {
3952 $url = ProcessExecutor::escape($url);
3953
3954 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
3955 return passthru('start "web" explorer "' . $url . '"');
3956 }
3957
3958 passthru('which xdg-open', $linux);
3959 passthru('which open', $osx);
3960
3961 if (0 === $linux) {
3962 passthru('xdg-open ' . $url);
3963 } elseif (0 === $osx) {
3964 passthru('open ' . $url);
3965 } else {
3966 $this->getIO()->write('no suitable browser opening command found, open yourself: ' . $url);
3967 }
3968 }
3969
3970
3971
3972
3973
3974
3975 private function initializeRepo()
3976 {
3977 $composer = $this->getComposer(false);
3978
3979 if ($composer) {
3980 $repo = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
3981 } else {
3982 $defaultRepos = Factory::createDefaultRepositories($this->getIO());
3983 $repo = new CompositeRepository($defaultRepos);
3984 }
3985
3986 return $repo;
3987 }
3988 }
3989 <?php
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001 namespace Composer\Command;
4002
4003 use Symfony\Component\Console\Input\InputInterface;
4004 use Symfony\Component\Console\Input\InputArgument;
4005 use Symfony\Component\Console\Input\InputOption;
4006 use Symfony\Component\Console\Output\OutputInterface;
4007 use Composer\Factory;
4008 use Composer\Installer;
4009 use Composer\Json\JsonFile;
4010 use Composer\Json\JsonManipulator;
4011 use Composer\Package\Version\VersionParser;
4012 use Composer\Plugin\CommandEvent;
4013 use Composer\Plugin\PluginEvents;
4014 use Composer\Repository\CompositeRepository;
4015 use Composer\Repository\PlatformRepository;
4016
4017
4018
4019
4020
4021 class RequireCommand extends InitCommand
4022 {
4023 protected function configure()
4024 {
4025 $this
4026 ->setName('require')
4027 ->setDescription('Adds required packages to your composer.json and installs them')
4028 ->setDefinition(array(
4029 new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Required package with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
4030 new InputOption('dev', null, InputOption::VALUE_NONE, 'Add requirement to require-dev.'),
4031 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
4032 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
4033 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
4034 new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'),
4035 new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
4036 new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'),
4037 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
4038 new InputOption('sort-packages', null, InputOption::VALUE_NONE, 'Sorts packages when adding/updating a new dependency'),
4039 ))
4040 ->setHelp(<<<EOT
4041 The require command adds required packages to your composer.json and installs them
4042
4043 If you do not want to install the new dependencies immediately you can call it with --no-update
4044
4045 EOT
4046 )
4047 ;
4048 }
4049
4050 protected function execute(InputInterface $input, OutputInterface $output)
4051 {
4052 $file = Factory::getComposerFile();
4053
4054 $newlyCreated = !file_exists($file);
4055 if (!file_exists($file) && !file_put_contents($file, "{\n}\n")) {
4056 $output->writeln('<error>'.$file.' could not be created.</error>');
4057
4058 return 1;
4059 }
4060 if (!is_readable($file)) {
4061 $output->writeln('<error>'.$file.' is not readable.</error>');
4062
4063 return 1;
4064 }
4065 if (!is_writable($file)) {
4066 $output->writeln('<error>'.$file.' is not writable.</error>');
4067
4068 return 1;
4069 }
4070
4071 $json = new JsonFile($file);
4072 $composerDefinition = $json->read();
4073 $composerBackup = file_get_contents($json->getPath());
4074
4075 $composer = $this->getComposer();
4076 $repos = $composer->getRepositoryManager()->getRepositories();
4077
4078 $this->repos = new CompositeRepository(array_merge(
4079 array(new PlatformRepository),
4080 $repos
4081 ));
4082
4083 $requirements = $this->determineRequirements($input, $output, $input->getArgument('packages'));
4084
4085 $requireKey = $input->getOption('dev') ? 'require-dev' : 'require';
4086 $removeKey = $input->getOption('dev') ? 'require' : 'require-dev';
4087 $baseRequirements = array_key_exists($requireKey, $composerDefinition) ? $composerDefinition[$requireKey] : array();
4088 $requirements = $this->formatRequirements($requirements);
4089
4090
4091  $versionParser = new VersionParser();
4092 foreach ($requirements as $constraint) {
4093 $versionParser->parseConstraints($constraint);
4094 }
4095
4096 $sortPackages = $input->getOption('sort-packages');
4097
4098 if (!$this->updateFileCleanly($json, $baseRequirements, $requirements, $requireKey, $removeKey, $sortPackages)) {
4099 foreach ($requirements as $package => $version) {
4100 $baseRequirements[$package] = $version;
4101
4102 if (isset($composerDefinition[$removeKey][$package])) {
4103 unset($composerDefinition[$removeKey][$package]);
4104 }
4105 }
4106
4107 $composerDefinition[$requireKey] = $baseRequirements;
4108 $json->write($composerDefinition);
4109 }
4110
4111 $output->writeln('<info>'.$file.' has been '.($newlyCreated ? 'created' : 'updated').'</info>');
4112
4113 if ($input->getOption('no-update')) {
4114 return 0;
4115 }
4116 $updateDevMode = !$input->getOption('update-no-dev');
4117
4118
4119  $this->resetComposer();
4120 $composer = $this->getComposer();
4121 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
4122 $io = $this->getIO();
4123
4124 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'require', $input, $output);
4125 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
4126
4127 $install = Installer::create($io, $composer);
4128
4129 $install
4130 ->setVerbose($input->getOption('verbose'))
4131 ->setPreferSource($input->getOption('prefer-source'))
4132 ->setPreferDist($input->getOption('prefer-dist'))
4133 ->setDevMode($updateDevMode)
4134 ->setUpdate(true)
4135 ->setUpdateWhitelist(array_keys($requirements))
4136 ->setWhitelistDependencies($input->getOption('update-with-dependencies'))
4137 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
4138 ;
4139
4140 $status = $install->run();
4141 if ($status !== 0) {
4142 if ($newlyCreated) {
4143 $output->writeln("\n".'<error>Installation failed, deleting '.$file.'.</error>');
4144 unlink($json->getPath());
4145 } else {
4146 $output->writeln("\n".'<error>Installation failed, reverting '.$file.' to its original content.</error>');
4147 file_put_contents($json->getPath(), $composerBackup);
4148 }
4149 }
4150
4151 return $status;
4152 }
4153
4154 private function updateFileCleanly($json, array $base, array $new, $requireKey, $removeKey, $sortPackages)
4155 {
4156 $contents = file_get_contents($json->getPath());
4157
4158 $manipulator = new JsonManipulator($contents);
4159
4160 foreach ($new as $package => $constraint) {
4161 if (!$manipulator->addLink($requireKey, $package, $constraint, $sortPackages)) {
4162 return false;
4163 }
4164 if (!$manipulator->removeSubNode($removeKey, $package)) {
4165 return false;
4166 }
4167 }
4168
4169 file_put_contents($json->getPath(), $manipulator->getContents());
4170
4171 return true;
4172 }
4173
4174 protected function interact(InputInterface $input, OutputInterface $output)
4175 {
4176 return;
4177 }
4178 }
4179 <?php
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191 namespace Composer\Command;
4192
4193 use Composer\Plugin\CommandEvent;
4194 use Composer\Plugin\PluginEvents;
4195 use Symfony\Component\Console\Input\InputInterface;
4196 use Symfony\Component\Console\Input\InputOption;
4197 use Symfony\Component\Console\Output\OutputInterface;
4198
4199
4200
4201
4202 class DumpAutoloadCommand extends Command
4203 {
4204 protected function configure()
4205 {
4206 $this
4207 ->setName('dump-autoload')
4208 ->setAliases(array('dumpautoload'))
4209 ->setDescription('Dumps the autoloader')
4210 ->setDefinition(array(
4211 new InputOption('optimize', 'o', InputOption::VALUE_NONE, 'Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.'),
4212 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables autoload-dev rules.'),
4213 ))
4214 ->setHelp(<<<EOT
4215 <info>php composer.phar dump-autoload</info>
4216 EOT
4217 )
4218 ;
4219 }
4220
4221 protected function execute(InputInterface $input, OutputInterface $output)
4222 {
4223 $composer = $this->getComposer();
4224
4225 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'dump-autoload', $input, $output);
4226 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
4227
4228 $installationManager = $composer->getInstallationManager();
4229 $localRepo = $composer->getRepositoryManager()->getLocalRepository();
4230 $package = $composer->getPackage();
4231 $config = $composer->getConfig();
4232
4233 $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader');
4234
4235 if ($optimize) {
4236 $output->writeln('<info>Generating optimized autoload files</info>');
4237 } else {
4238 $output->writeln('<info>Generating autoload files</info>');
4239 }
4240
4241 $generator = $composer->getAutoloadGenerator();
4242 $generator->setDevMode(!$input->getOption('no-dev'));
4243 $generator->dump($config, $localRepo, $package, $installationManager, 'composer', $optimize);
4244 }
4245 }
4246 <?php
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258 namespace Composer\Command;
4259
4260 use Composer\Factory;
4261 use Symfony\Component\Console\Input\InputInterface;
4262 use Symfony\Component\Console\Input\InputArgument;
4263 use Symfony\Component\Console\Input\StringInput;
4264 use Symfony\Component\Console\Output\OutputInterface;
4265
4266
4267
4268
4269 class GlobalCommand extends Command
4270 {
4271 protected function configure()
4272 {
4273 $this
4274 ->setName('global')
4275 ->setDescription('Allows running commands in the global composer dir ($COMPOSER_HOME).')
4276 ->setDefinition(array(
4277 new InputArgument('command-name', InputArgument::REQUIRED, ''),
4278 new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''),
4279 ))
4280 ->setHelp(<<<EOT
4281 Use this command as a wrapper to run other Composer commands
4282 within the global context of COMPOSER_HOME.
4283
4284 You can use this to install CLI utilities globally, all you need
4285 is to add the COMPOSER_HOME/vendor/bin dir to your PATH env var.
4286
4287 COMPOSER_HOME is c:\Users\<user>\AppData\Roaming\Composer on Windows
4288 and /home/<user>/.composer on unix systems.
4289
4290 Note: This path may vary depending on customizations to bin-dir in
4291 composer.json or the environmental variable COMPOSER_BIN_DIR.
4292
4293 EOT
4294 )
4295 ;
4296 }
4297
4298 public function run(InputInterface $input, OutputInterface $output)
4299 {
4300
4301  $tokens = preg_split('{\s+}', $input->__toString());
4302 $args = array();
4303 foreach ($tokens as $token) {
4304 if ($token && $token[0] !== '-') {
4305 $args[] = $token;
4306 if (count($args) >= 2) {
4307 break;
4308 }
4309 }
4310 }
4311
4312
4313  if (count($args) < 2) {
4314 return parent::run($input, $output);
4315 }
4316
4317
4318  $config = Factory::createConfig();
4319 chdir($config->get('home'));
4320 $output->writeln('<info>Changed current directory to '.$config->get('home').'</info>');
4321
4322
4323  $input = new StringInput(preg_replace('{\bg(?:l(?:o(?:b(?:a(?:l)?)?)?)?)?\b}', '', $input->__toString(), 1));
4324
4325 return $this->getApplication()->run($input, $output);
4326 }
4327 }
4328 <?php
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340 namespace Composer\Command;
4341
4342 use Composer\Config\JsonConfigSource;
4343 use Composer\Installer;
4344 use Composer\Plugin\CommandEvent;
4345 use Composer\Plugin\PluginEvents;
4346 use Composer\Json\JsonFile;
4347 use Composer\Factory;
4348 use Symfony\Component\Console\Input\InputInterface;
4349 use Symfony\Component\Console\Input\InputOption;
4350 use Symfony\Component\Console\Input\InputArgument;
4351 use Symfony\Component\Console\Output\OutputInterface;
4352
4353
4354
4355
4356
4357 class RemoveCommand extends Command
4358 {
4359 protected function configure()
4360 {
4361 $this
4362 ->setName('remove')
4363 ->setDescription('Removes a package from the require or require-dev')
4364 ->setDefinition(array(
4365 new InputArgument('packages', InputArgument::IS_ARRAY, 'Packages that should be removed.'),
4366 new InputOption('dev', null, InputOption::VALUE_NONE, 'Removes a package from the require-dev section.'),
4367 new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'),
4368 new InputOption('no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.'),
4369 new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'),
4370 new InputOption('update-with-dependencies', null, InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies.'),
4371 new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore platform requirements (php & ext- packages).'),
4372 ))
4373 ->setHelp(<<<EOT
4374 The <info>remove</info> command removes a package from the current
4375 list of installed packages
4376
4377 <info>php composer.phar remove</info>
4378
4379 EOT
4380 )
4381 ;
4382 }
4383
4384 protected function execute(InputInterface $input, OutputInterface $output)
4385 {
4386 $packages = $input->getArgument('packages');
4387
4388 $file = Factory::getComposerFile();
4389
4390 $jsonFile = new JsonFile($file);
4391 $composer = $jsonFile->read();
4392 $composerBackup = file_get_contents($jsonFile->getPath());
4393
4394 $json = new JsonConfigSource($jsonFile);
4395
4396 $type = $input->getOption('dev') ? 'require-dev' : 'require';
4397 $altType = !$input->getOption('dev') ? 'require-dev' : 'require';
4398
4399 foreach ($packages as $package) {
4400 if (isset($composer[$type][$package])) {
4401 $json->removeLink($type, $package);
4402 } elseif (isset($composer[$altType][$package])) {
4403 $output->writeln('<warning>'.$package.' could not be found in '.$type.' but it is present in '.$altType.'</warning>');
4404 $dialog = $this->getHelperSet()->get('dialog');
4405 if ($this->getIO()->isInteractive()) {
4406 if ($dialog->askConfirmation($output, $dialog->getQuestion('Do you want to remove it from '.$altType, 'yes', '?'), true)) {
4407 $json->removeLink($altType, $package);
4408 }
4409 }
4410 } else {
4411 $output->writeln('<warning>'.$package.' is not required in your composer.json and has not been removed</warning>');
4412 }
4413 }
4414
4415 if ($input->getOption('no-update')) {
4416 return 0;
4417 }
4418
4419
4420  $composer = $this->getComposer();
4421 $composer->getDownloadManager()->setOutputProgress(!$input->getOption('no-progress'));
4422 $io = $this->getIO();
4423
4424 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'remove', $input, $output);
4425 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
4426
4427 $install = Installer::create($io, $composer);
4428
4429 $updateDevMode = !$input->getOption('update-no-dev');
4430 $install
4431 ->setVerbose($input->getOption('verbose'))
4432 ->setDevMode($updateDevMode)
4433 ->setUpdate(true)
4434 ->setUpdateWhitelist($packages)
4435 ->setWhitelistDependencies($input->getOption('update-with-dependencies'))
4436 ->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
4437 ;
4438
4439 $status = $install->run();
4440 if ($status !== 0) {
4441 $output->writeln("\n".'<error>Removal failed, reverting '.$file.' to its original content.</error>');
4442 file_put_contents($jsonFile->getPath(), $composerBackup);
4443 }
4444
4445 return $status;
4446 }
4447 }
4448 <?php
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460 namespace Composer\Command\Helper;
4461
4462 use Symfony\Component\Console\Helper\DialogHelper as BaseDialogHelper;
4463
4464 class DialogHelper extends BaseDialogHelper
4465 {
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477 public function getQuestion($question, $default = null, $sep = ':')
4478 {
4479 return $default !== null ?
4480 sprintf('<info>%s</info> [<comment>%s</comment>]%s ', $question, $default, $sep) :
4481 sprintf('<info>%s</info>%s ', $question, $sep);
4482 }
4483 }
4484 <?php
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496 namespace Composer\Command;
4497
4498 use Symfony\Component\Console\Input\InputInterface;
4499 use Symfony\Component\Console\Input\InputOption;
4500 use Symfony\Component\Console\Output\OutputInterface;
4501 use Composer\Downloader\ChangeReportInterface;
4502 use Composer\Plugin\CommandEvent;
4503 use Composer\Plugin\PluginEvents;
4504 use Composer\Script\ScriptEvents;
4505
4506
4507
4508
4509
4510 class StatusCommand extends Command
4511 {
4512 protected function configure()
4513 {
4514 $this
4515 ->setName('status')
4516 ->setDescription('Show a list of locally modified packages')
4517 ->setDefinition(array(
4518 new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Show modified files for each directory that contains changes.'),
4519 ))
4520 ->setHelp(<<<EOT
4521 The status command displays a list of dependencies that have
4522 been modified locally.
4523
4524 EOT
4525 )
4526 ;
4527 }
4528
4529 protected function execute(InputInterface $input, OutputInterface $output)
4530 {
4531
4532  $composer = $this->getComposer();
4533
4534 $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'status', $input, $output);
4535 $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
4536
4537 $installedRepo = $composer->getRepositoryManager()->getLocalRepository();
4538
4539 $dm = $composer->getDownloadManager();
4540 $im = $composer->getInstallationManager();
4541
4542
4543  $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::PRE_STATUS_CMD, true);
4544
4545 $errors = array();
4546
4547
4548  foreach ($installedRepo->getPackages() as $package) {
4549 $downloader = $dm->getDownloaderForInstalledPackage($package);
4550
4551 if ($downloader instanceof ChangeReportInterface) {
4552 $targetDir = $im->getInstallPath($package);
4553
4554 if ($changes = $downloader->getLocalChanges($package, $targetDir)) {
4555 $errors[$targetDir] = $changes;
4556 }
4557 }
4558 }
4559
4560
4561  if (!$errors) {
4562 $output->writeln('<info>No local changes</info>');
4563 } else {
4564 $output->writeln('<error>You have changes in the following dependencies:</error>');
4565 }
4566
4567 foreach ($errors as $path => $changes) {
4568 if ($input->getOption('verbose')) {
4569 $indentedChanges = implode("\n", array_map(function ($line) {
4570 return '    ' . ltrim($line);
4571 }, explode("\n", $changes)));
4572 $output->writeln('<info>'.$path.'</info>:');
4573 $output->writeln($indentedChanges);
4574 } else {
4575 $output->writeln($path);
4576 }
4577 }
4578
4579 if ($errors && !$input->getOption('verbose')) {
4580 $output->writeln('Use --verbose (-v) to see modified files');
4581 }
4582
4583
4584  $composer->getEventDispatcher()->dispatchCommandEvent(ScriptEvents::POST_STATUS_CMD, true);
4585
4586 return $errors ? 1 : 0;
4587 }
4588 }
4589 <?php
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601 namespace Composer\Command;
4602
4603 use Composer\DependencyResolver\Pool;
4604 use Composer\Json\JsonFile;
4605 use Composer\Factory;
4606 use Composer\Package\BasePackage;
4607 use Composer\Package\Version\VersionSelector;
4608 use Composer\Repository\CompositeRepository;
4609 use Composer\Repository\PlatformRepository;
4610 use Composer\Package\Version\VersionParser;
4611 use Composer\Util\ProcessExecutor;
4612 use Symfony\Component\Console\Input\InputInterface;
4613 use Symfony\Component\Console\Input\InputOption;
4614 use Symfony\Component\Console\Output\OutputInterface;
4615 use Symfony\Component\Process\Process;
4616 use Symfony\Component\Process\ExecutableFinder;
4617
4618
4619
4620
4621
4622 class InitCommand extends Command
4623 {
4624 protected $repos;
4625
4626 private $gitConfig;
4627 private $pool;
4628
4629 public function parseAuthorString($author)
4630 {
4631 if (preg_match('/^(?P<name>[- \.,\p{L}\'’]+) <(?P<email>.+?)>$/u', $author, $match)) {
4632 if ($this->isValidEmail($match['email'])) {
4633 return array(
4634 'name' => trim($match['name']),
4635 'email' => $match['email']
4636 );
4637 }
4638 }
4639
4640 throw new \InvalidArgumentException(
4641 'Invalid author string.  Must be in the format: '.
4642 'John Smith <john@example.com>'
4643 );
4644 }
4645
4646 protected function configure()
4647 {
4648 $this
4649 ->setName('init')
4650 ->setDescription('Creates a basic composer.json file in current directory.')
4651 ->setDefinition(array(
4652 new InputOption('name', null, InputOption::VALUE_REQUIRED, 'Name of the package'),
4653 new InputOption('description', null, InputOption::VALUE_REQUIRED, 'Description of package'),
4654 new InputOption('author', null, InputOption::VALUE_REQUIRED, 'Author name of package'),
4655
4656  new InputOption('homepage', null, InputOption::VALUE_REQUIRED, 'Homepage of package'),
4657 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"'),
4658 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"'),
4659 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::$stabilities)).')'),
4660 new InputOption('license', 'l', InputOption::VALUE_REQUIRED, 'License of package'),
4661 ))
4662 ->setHelp(<<<EOT
4663 The <info>init</info> command creates a basic composer.json file
4664 in the current directory.
4665
4666 <info>php composer.phar init</info>
4667
4668 EOT
4669 )
4670 ;
4671 }
4672
4673 protected function execute(InputInterface $input, OutputInterface $output)
4674 {
4675 $dialog = $this->getHelperSet()->get('dialog');
4676
4677 $whitelist = array('name', 'description', 'author', 'homepage', 'require', 'require-dev', 'stability', 'license');
4678
4679 $options = array_filter(array_intersect_key($input->getOptions(), array_flip($whitelist)));
4680
4681 if (isset($options['author'])) {
4682 $options['authors'] = $this->formatAuthors($options['author']);
4683 unset($options['author']);
4684 }
4685
4686 if (isset($options['stability'])) {
4687 $options['minimum-stability'] = $options['stability'];
4688 unset($options['stability']);
4689 }
4690
4691 $options['require'] = isset($options['require']) ? $this->formatRequirements($options['require']) : new \stdClass;
4692 if (array() === $options['require']) {
4693 $options['require'] = new \stdClass;
4694 }
4695
4696 if (isset($options['require-dev'])) {
4697 $options['require-dev'] = $this->formatRequirements($options['require-dev']);
4698 if (array() === $options['require-dev']) {
4699 $options['require-dev'] = new \stdClass;
4700 }
4701 }
4702
4703 $file = new JsonFile('composer.json');
4704
4705 $json = $file->encode($options);
4706
4707 if ($input->isInteractive()) {
4708 $output->writeln(array(
4709 '',
4710 $json,
4711 ''
4712 ));
4713 if (!$dialog->askConfirmation($output, $dialog->getQuestion('Do you confirm generation', 'yes', '?'), true)) {
4714 $output->writeln('<error>Command aborted</error>');
4715
4716 return 1;
4717 }
4718 }
4719
4720 $file->write($options);
4721
4722 if ($input->isInteractive() && is_dir('.git')) {
4723 $ignoreFile = realpath('.gitignore');
4724
4725 if (false === $ignoreFile) {
4726 $ignoreFile = realpath('.') . '/.gitignore';
4727 }
4728
4729 if (!$this->hasVendorIgnore($ignoreFile)) {
4730 $question = 'Would you like the <info>vendor</info> directory added to your <info>.gitignore</info> [<comment>yes</comment>]?';
4731
4732 if ($dialog->askConfirmation($output, $question, true)) {
4733 $this->addVendorIgnore($ignoreFile);
4734 }
4735 }
4736 }
4737 }
4738
4739 protected function interact(InputInterface $input, OutputInterface $output)
4740 {
4741 $git = $this->getGitConfig();
4742
4743 $dialog = $this->getHelperSet()->get('dialog');
4744 $formatter = $this->getHelperSet()->get('formatter');
4745 $output->writeln(array(
4746 '',
4747 $formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
4748 ''
4749 ));
4750
4751
4752  $output->writeln(array(
4753 '',
4754 'This command will guide you through creating your composer.json config.',
4755 '',
4756 ));
4757
4758 $cwd = realpath(".");
4759
4760 if (!$name = $input->getOption('name')) {
4761 $name = basename($cwd);
4762 $name = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
4763 $name = strtolower($name);
4764 if (isset($git['github.user'])) {
4765 $name = $git['github.user'] . '/' . $name;
4766 } elseif (!empty($_SERVER['USERNAME'])) {
4767 $name = $_SERVER['USERNAME'] . '/' . $name;
4768 } elseif (get_current_user()) {
4769 $name = get_current_user() . '/' . $name;
4770 } else {
4771
4772  $name = $name . '/' . $name;
4773 }
4774 } else {
4775 if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}', $name)) {
4776 throw new \InvalidArgumentException(
4777 'The package name '.$name.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
4778 );
4779 }
4780 }
4781
4782 $name = $dialog->askAndValidate(
4783 $output,
4784 $dialog->getQuestion('Package name (<vendor>/<name>)', $name),
4785 function ($value) use ($name) {
4786 if (null === $value) {
4787 return $name;
4788 }
4789
4790 if (!preg_match('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}', $value)) {
4791 throw new \InvalidArgumentException(
4792 'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
4793 );
4794 }
4795
4796 return $value;
4797 }
4798 );
4799 $input->setOption('name', $name);
4800
4801 $description = $input->getOption('description') ?: false;
4802 $description = $dialog->ask(
4803 $output,
4804 $dialog->getQuestion('Description', $description),
4805 $description
4806 );
4807 $input->setOption('description', $description);
4808
4809 if (null === $author = $input->getOption('author')) {
4810 if (isset($git['user.name']) && isset($git['user.email'])) {
4811 $author = sprintf('%s <%s>', $git['user.name'], $git['user.email']);
4812 }
4813 }
4814
4815 $self = $this;
4816 $author = $dialog->askAndValidate(
4817 $output,
4818 $dialog->getQuestion('Author', $author),
4819 function ($value) use ($self, $author) {
4820 $value = $value ?: $author;
4821 $author = $self->parseAuthorString($value);
4822
4823 return sprintf('%s <%s>', $author['name'], $author['email']);
4824 }
4825 );
4826 $input->setOption('author', $author);
4827
4828 $minimumStability = $input->getOption('stability') ?: '';
4829 $minimumStability = $dialog->askAndValidate(
4830 $output,
4831 $dialog->getQuestion('Minimum Stability', $minimumStability),
4832 function ($value) use ($self, $minimumStability) {
4833 if (null === $value) {
4834 return $minimumStability;
4835 }
4836
4837 if (!isset(BasePackage::$stabilities[$value])) {
4838 throw new \InvalidArgumentException(
4839 'Invalid minimum stability "'.$value.'". Must be empty or one of: '.
4840 implode(', ', array_keys(BasePackage::$stabilities))
4841 );
4842 }
4843
4844 return $value;
4845 }
4846 );
4847 $input->setOption('stability', $minimumStability);
4848
4849 $license = $input->getOption('license') ?: false;
4850 $license = $dialog->ask(
4851 $output,
4852 $dialog->getQuestion('License', $license),
4853 $license
4854 );
4855 $input->setOption('license', $license);
4856
4857 $output->writeln(array(
4858 '',
4859 'Define your dependencies.',
4860 ''
4861 ));
4862
4863 $requirements = array();
4864 if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dependencies (require) interactively', 'yes', '?'), true)) {
4865 $requirements = $this->determineRequirements($input, $output, $input->getOption('require'));
4866 }
4867 $input->setOption('require', $requirements);
4868 $devRequirements = array();
4869 if ($dialog->askConfirmation($output, $dialog->getQuestion('Would you like to define your dev dependencies (require-dev) interactively', 'yes', '?'), true)) {
4870 $devRequirements = $this->determineRequirements($input, $output, $input->getOption('require-dev'));
4871 }
4872 $input->setOption('require-dev', $devRequirements);
4873 }
4874
4875 protected function findPackages($name)
4876 {
4877 return $this->getRepos()->search($name);
4878 }
4879
4880 protected function getRepos()
4881 {
4882 if (!$this->repos) {
4883 $this->repos = new CompositeRepository(array_merge(
4884 array(new PlatformRepository),
4885 Factory::createDefaultRepositories($this->getIO())
4886 ));
4887 }
4888
4889 return $this->repos;
4890 }
4891
4892 protected function determineRequirements(InputInterface $input, OutputInterface $output, $requires = array())
4893 {
4894 $dialog = $this->getHelperSet()->get('dialog');
4895 $prompt = $dialog->getQuestion('Search for a package', false, ':');
4896
4897 if ($requires) {
4898 $requires = $this->normalizeRequirements($requires);
4899 $result = array();
4900
4901 foreach ($requires as $requirement) {
4902 if (!isset($requirement['version'])) {
4903
4904  $version = $this->findBestVersionForPackage($input, $requirement['name']);
4905 $requirement['version'] = $version;
4906
4907 $output->writeln(sprintf(
4908 'Using version <info>%s</info> for <info>%s</info>',
4909 $requirement['version'],
4910 $requirement['name']
4911 ));
4912 }
4913
4914 $result[] = $requirement['name'] . ' ' . $requirement['version'];
4915 }
4916
4917 return $result;
4918 }
4919
4920 while (null !== $package = $dialog->ask($output, $prompt)) {
4921 $matches = $this->findPackages($package);
4922
4923 if (count($matches)) {
4924 $exactMatch = null;
4925 $choices = array();
4926 foreach ($matches as $position => $foundPackage) {
4927 $choices[] = sprintf(' <info>%5s</info> %s', "[$position]", $foundPackage['name']);
4928 if ($foundPackage['name'] === $package) {
4929 $exactMatch = true;
4930 break;
4931 }
4932 }
4933
4934
4935  if (!$exactMatch) {
4936 $output->writeln(array(
4937 '',
4938 sprintf('Found <info>%s</info> packages matching <info>%s</info>', count($matches), $package),
4939 ''
4940 ));
4941
4942 $output->writeln($choices);
4943 $output->writeln('');
4944
4945 $validator = function ($selection) use ($matches) {
4946 if ('' === $selection) {
4947 return false;
4948 }
4949
4950 if (!is_numeric($selection) && preg_match('{^\s*(\S+)\s+(\S.*)\s*$}', $selection, $matches)) {
4951 return $matches[1].' '.$matches[2];
4952 }
4953
4954 if (!isset($matches[(int) $selection])) {
4955 throw new \Exception('Not a valid selection');
4956 }
4957
4958 $package = $matches[(int) $selection];
4959
4960 return $package['name'];
4961 };
4962
4963 $package = $dialog->askAndValidate($output, $dialog->getQuestion('Enter package # to add, or the complete package name if it is not listed', false, ':'), $validator, 3);
4964 }
4965
4966
4967  if (false !== $package && false === strpos($package, ' ')) {
4968 $validator = function ($input) {
4969 $input = trim($input);
4970
4971 return $input ?: false;
4972 };
4973
4974 $constraint = $dialog->askAndValidate(
4975 $output,
4976 $dialog->getQuestion('Enter the version constraint to require (or leave blank to use the latest version)', false, ':'),
4977 $validator,
4978 3)
4979 ;
4980 if (false === $constraint) {
4981 $constraint = $this->findBestVersionForPackage($input, $package);
4982
4983 $output->writeln(sprintf(
4984 'Using version <info>%s</info> for <info>%s</info>',
4985 $constraint,
4986 $package
4987 ));
4988 }
4989
4990 $package .= ' '.$constraint;
4991 }
4992
4993 if (false !== $package) {
4994 $requires[] = $package;
4995 }
4996 }
4997 }
4998
4999 return $requires;
5000 }
5001
5002 protected function formatAuthors($author)
5003 {
5004 return array($this->parseAuthorString($author));
5005 }
5006
5007 protected function formatRequirements(array $requirements)
5008 {
5009 $requires = array();
5010 $requirements = $this->normalizeRequirements($requirements);
5011 foreach ($requirements as $requirement) {
5012 $requires[$requirement['name']] = $requirement['version'];
5013 }
5014
5015 return $requires;
5016 }
5017
5018 protected function getGitConfig()
5019 {
5020 if (null !== $this->gitConfig) {
5021 return $this->gitConfig;
5022 }
5023
5024 $finder = new ExecutableFinder();
5025 $gitBin = $finder->find('git');
5026
5027 $cmd = new Process(sprintf('%s config -l', ProcessExecutor::escape($gitBin)));
5028 $cmd->run();
5029
5030 if ($cmd->isSuccessful()) {
5031 $this->gitConfig = array();
5032 preg_match_all('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches, PREG_SET_ORDER);
5033 foreach ($matches as $match) {
5034 $this->gitConfig[$match[1]] = $match[2];
5035 }
5036
5037 return $this->gitConfig;
5038 }
5039
5040 return $this->gitConfig = array();
5041 }
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059 protected function hasVendorIgnore($ignoreFile, $vendor = 'vendor')
5060 {
5061 if (!file_exists($ignoreFile)) {
5062 return false;
5063 }
5064
5065 $pattern = sprintf('{^/?%s(/\*?)?$}', preg_quote($vendor));
5066
5067 $lines = file($ignoreFile, FILE_IGNORE_NEW_LINES);
5068 foreach ($lines as $line) {
5069 if (preg_match($pattern, $line)) {
5070 return true;
5071 }
5072 }
5073
5074 return false;
5075 }
5076
5077 protected function normalizeRequirements(array $requirements)
5078 {
5079 $parser = new VersionParser();
5080
5081 return $parser->parseNameVersionPairs($requirements);
5082 }
5083
5084 protected function addVendorIgnore($ignoreFile, $vendor = '/vendor/')
5085 {
5086 $contents = "";
5087 if (file_exists($ignoreFile)) {
5088 $contents = file_get_contents($ignoreFile);
5089
5090 if ("\n" !== substr($contents, 0, -1)) {
5091 $contents .= "\n";
5092 }
5093 }
5094
5095 file_put_contents($ignoreFile, $contents . $vendor. "\n");
5096 }
5097
5098 protected function isValidEmail($email)
5099 {
5100
5101  if (!function_exists('filter_var')) {
5102 return true;
5103 }
5104
5105
5106  if (version_compare(PHP_VERSION, '5.3.3', '<')) {
5107 return true;
5108 }
5109
5110 return false !== filter_var($email, FILTER_VALIDATE_EMAIL);
5111 }
5112
5113 private function getPool(InputInterface $input)
5114 {
5115 if (!$this->pool) {
5116 $this->pool = new Pool($this->getMinimumStability($input));
5117 $this->pool->addRepository($this->getRepos());
5118 }
5119
5120 return $this->pool;
5121 }
5122
5123 private function getMinimumStability(InputInterface $input)
5124 {
5125 if ($input->hasOption('stability')) {
5126 return $input->getOption('stability') ?: 'stable';
5127 }
5128
5129 $file = Factory::getComposerFile();
5130 if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
5131 if (!empty($composer['minimum-stability'])) {
5132 return $composer['minimum-stability'];
5133 }
5134 }
5135
5136 return 'stable';
5137 }
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149 private function findBestVersionForPackage(InputInterface $input, $name)
5150 {
5151
5152  $versionSelector = new VersionSelector($this->getPool($input));
5153 $package = $versionSelector->findBestCandidate($name);
5154
5155 if (!$package) {
5156 throw new \InvalidArgumentException(sprintf(
5157 'Could not find package %s at any version for your minimum-stability (%s). Check the package spelling or your minimum-stability',
5158 $name,
5159 $this->getMinimumStability($input)
5160 ));
5161 }
5162
5163 return $versionSelector->findRecommendedRequireVersion($package);
5164 }
5165 }
5166 <?php
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178 namespace Composer\Downloader;
5179
5180 use Composer\Config;
5181 use Composer\Package\PackageInterface;
5182 use Composer\Package\Version\VersionParser;
5183 use Composer\Util\ProcessExecutor;
5184 use Composer\IO\IOInterface;
5185 use Composer\Util\Filesystem;
5186
5187
5188
5189
5190 abstract class VcsDownloader implements DownloaderInterface, ChangeReportInterface
5191 {
5192 protected $io;
5193 protected $config;
5194 protected $process;
5195 protected $filesystem;
5196
5197 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, Filesystem $fs = null)
5198 {
5199 $this->io = $io;
5200 $this->config = $config;
5201 $this->process = $process ?: new ProcessExecutor($io);
5202 $this->filesystem = $fs ?: new Filesystem;
5203 }
5204
5205
5206
5207
5208 public function getInstallationSource()
5209 {
5210 return 'source';
5211 }
5212
5213
5214
5215
5216 public function download(PackageInterface $package, $path)
5217 {
5218 if (!$package->getSourceReference()) {
5219 throw new \InvalidArgumentException('Package '.$package->getPrettyName().' is missing reference information');
5220 }
5221
5222 $this->io->write("  - Installing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
5223 $this->filesystem->emptyDirectory($path);
5224
5225 $urls = $package->getSourceUrls();
5226 while ($url = array_shift($urls)) {
5227 try {
5228 if (Filesystem::isLocalPath($url)) {
5229 $url = realpath($url);
5230 }
5231 $this->doDownload($package, $path, $url);
5232 break;
5233 } catch (\Exception $e) {
5234 if ($this->io->isDebug()) {
5235 $this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage());
5236 } elseif (count($urls)) {
5237 $this->io->write('    Failed, trying the next URL');
5238 }
5239 if (!count($urls)) {
5240 throw $e;
5241 }
5242 }
5243 }
5244
5245 $this->io->write('');
5246 }
5247
5248
5249
5250
5251 public function update(PackageInterface $initial, PackageInterface $target, $path)
5252 {
5253 if (!$target->getSourceReference()) {
5254 throw new \InvalidArgumentException('Package '.$target->getPrettyName().' is missing reference information');
5255 }
5256
5257 $name = $target->getName();
5258 if ($initial->getPrettyVersion() == $target->getPrettyVersion()) {
5259 if ($target->getSourceType() === 'svn') {
5260 $from = $initial->getSourceReference();
5261 $to = $target->getSourceReference();
5262 } else {
5263 $from = substr($initial->getSourceReference(), 0, 7);
5264 $to = substr($target->getSourceReference(), 0, 7);
5265 }
5266 $name .= ' '.$initial->getPrettyVersion();
5267 } else {
5268 $from = VersionParser::formatVersion($initial);
5269 $to = VersionParser::formatVersion($target);
5270 }
5271
5272 $this->io->write("  - Updating <info>" . $name . "</info> (<comment>" . $from . "</comment> => <comment>" . $to . "</comment>)");
5273
5274 $this->cleanChanges($initial, $path, true);
5275 $urls = $target->getSourceUrls();
5276 while ($url = array_shift($urls)) {
5277 try {
5278 if (Filesystem::isLocalPath($url)) {
5279 $url = realpath($url);
5280 }
5281 $this->doUpdate($initial, $target, $path, $url);
5282 break;
5283 } catch (\Exception $e) {
5284 if ($this->io->isDebug()) {
5285 $this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage());
5286 } elseif (count($urls)) {
5287 $this->io->write('    Failed, trying the next URL');
5288 } else {
5289
5290  $this->reapplyChanges($path);
5291
5292 throw $e;
5293 }
5294 }
5295 }
5296
5297 $this->reapplyChanges($path);
5298
5299
5300  if ($this->io->isVerbose()) {
5301 $message = 'Pulling in changes:';
5302 $logs = $this->getCommitLogs($initial->getSourceReference(), $target->getSourceReference(), $path);
5303
5304 if (!trim($logs)) {
5305 $message = 'Rolling back changes:';
5306 $logs = $this->getCommitLogs($target->getSourceReference(), $initial->getSourceReference(), $path);
5307 }
5308
5309 if (trim($logs)) {
5310 $logs = implode("\n", array_map(function ($line) {
5311 return '      ' . $line;
5312 }, explode("\n", $logs)));
5313
5314 $this->io->write('    '.$message);
5315 $this->io->write($logs);
5316 }
5317 }
5318
5319 $this->io->write('');
5320 }
5321
5322
5323
5324
5325 public function remove(PackageInterface $package, $path)
5326 {
5327 $this->io->write("  - Removing <info>" . $package->getName() . "</info> (<comment>" . $package->getPrettyVersion() . "</comment>)");
5328 $this->cleanChanges($package, $path, false);
5329 if (!$this->filesystem->removeDirectory($path)) {
5330 throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
5331 }
5332 }
5333
5334
5335
5336
5337
5338 public function setOutputProgress($outputProgress)
5339 {
5340 return $this;
5341 }
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352 protected function cleanChanges(PackageInterface $package, $path, $update)
5353 {
5354
5355  if (null !== $this->getLocalChanges($package, $path)) {
5356 throw new \RuntimeException('Source directory ' . $path . ' has uncommitted changes.');
5357 }
5358 }
5359
5360
5361
5362
5363
5364
5365
5366 protected function reapplyChanges($path)
5367 {
5368 }
5369
5370
5371
5372
5373
5374
5375
5376
5377 abstract protected function doDownload(PackageInterface $package, $path, $url);
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387 abstract protected function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url);
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397 abstract protected function getCommitLogs($fromReference, $toReference, $path);
5398 }
5399 <?php
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411 namespace Composer\Downloader;
5412
5413 use Composer\Config;
5414 use Composer\Cache;
5415 use Composer\EventDispatcher\EventDispatcher;
5416 use Composer\Util\ProcessExecutor;
5417 use Composer\IO\IOInterface;
5418 use RarArchive;
5419
5420
5421
5422
5423
5424
5425
5426
5427 class RarDownloader extends ArchiveDownloader
5428 {
5429 protected $process;
5430
5431 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
5432 {
5433 $this->process = $process ?: new ProcessExecutor($io);
5434 parent::__construct($io, $config, $eventDispatcher, $cache);
5435 }
5436
5437 protected function extract($file, $path)
5438 {
5439 $processError = null;
5440
5441
5442  if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
5443 $command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' && chmod -R u+w ' . ProcessExecutor::escape($path);
5444
5445 if (0 === $this->process->execute($command, $ignoredOutput)) {
5446 return;
5447 }
5448
5449 $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
5450 }
5451
5452 if (!class_exists('RarArchive')) {
5453
5454  $iniPath = php_ini_loaded_file();
5455
5456 if ($iniPath) {
5457 $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
5458 } else {
5459 $iniMessage = 'A php.ini file does not exist. You will have to create one.';
5460 }
5461
5462 $error = "Could not decompress the archive, enable the PHP rar extension or install unrar.\n"
5463 . $iniMessage . "\n" . $processError;
5464
5465 if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
5466 $error = "Could not decompress the archive, enable the PHP rar extension.\n" . $iniMessage;
5467 }
5468
5469 throw new \RuntimeException($error);
5470 }
5471
5472 $rarArchive = RarArchive::open($file);
5473
5474 if (false === $rarArchive) {
5475 throw new \UnexpectedValueException('Could not open RAR archive: ' . $file);
5476 }
5477
5478 $entries = $rarArchive->getEntries();
5479
5480 if (false === $entries) {
5481 throw new \RuntimeException('Could not retrieve RAR archive entries');
5482 }
5483
5484 foreach ($entries as $entry) {
5485 if (false === $entry->extract($path)) {
5486 throw new \RuntimeException('Could not extract entry');
5487 }
5488 }
5489
5490 $rarArchive->close();
5491 }
5492 }
5493 <?php
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505 namespace Composer\Downloader;
5506
5507 use Composer\Config;
5508 use Composer\Cache;
5509 use Composer\IO\IOInterface;
5510 use Composer\Package\PackageInterface;
5511 use Composer\Package\Version\VersionParser;
5512 use Composer\Plugin\PluginEvents;
5513 use Composer\Plugin\PreFileDownloadEvent;
5514 use Composer\EventDispatcher\EventDispatcher;
5515 use Composer\Util\Filesystem;
5516 use Composer\Util\RemoteFilesystem;
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526 class FileDownloader implements DownloaderInterface
5527 {
5528 protected $io;
5529 protected $config;
5530 protected $rfs;
5531 protected $filesystem;
5532 protected $cache;
5533 protected $outputProgress = true;
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, RemoteFilesystem $rfs = null, Filesystem $filesystem = null)
5546 {
5547 $this->io = $io;
5548 $this->config = $config;
5549 $this->eventDispatcher = $eventDispatcher;
5550 $this->rfs = $rfs ?: new RemoteFilesystem($io, $config);
5551 $this->filesystem = $filesystem ?: new Filesystem();
5552 $this->cache = $cache;
5553
5554 if ($this->cache && $this->cache->gcIsNecessary()) {
5555 $this->cache->gc($config->get('cache-files-ttl'), $config->get('cache-files-maxsize'));
5556 }
5557 }
5558
5559
5560
5561
5562 public function getInstallationSource()
5563 {
5564 return 'dist';
5565 }
5566
5567
5568
5569
5570 public function download(PackageInterface $package, $path)
5571 {
5572 if (!$package->getDistUrl()) {
5573 throw new \InvalidArgumentException('The given package is missing url information');
5574 }
5575
5576 $this->io->write("  - Installing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
5577
5578 $urls = $package->getDistUrls();
5579 while ($url = array_shift($urls)) {
5580 try {
5581 return $this->doDownload($package, $path, $url);
5582 } catch (\Exception $e) {
5583 if ($this->io->isDebug()) {
5584 $this->io->write('');
5585 $this->io->write('Failed: ['.get_class($e).'] '.$e->getMessage());
5586 } elseif (count($urls)) {
5587 $this->io->write('');
5588 $this->io->write('    Failed, trying the next URL');
5589 }
5590
5591 if (!count($urls)) {
5592 throw $e;
5593 }
5594 }
5595 }
5596
5597 $this->io->write('');
5598 }
5599
5600 protected function doDownload(PackageInterface $package, $path, $url)
5601 {
5602 $this->filesystem->emptyDirectory($path);
5603
5604 $fileName = $this->getFileName($package, $path);
5605
5606 $processedUrl = $this->processUrl($package, $url);
5607 $hostname = parse_url($processedUrl, PHP_URL_HOST);
5608
5609 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $processedUrl);
5610 if ($this->eventDispatcher) {
5611 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
5612 }
5613 $rfs = $preFileDownloadEvent->getRemoteFilesystem();
5614
5615 try {
5616 $checksum = $package->getDistSha1Checksum();
5617 $cacheKey = $this->getCacheKey($package);
5618
5619
5620  if (!$this->cache || ($checksum && $checksum !== $this->cache->sha1($cacheKey)) || !$this->cache->copyTo($cacheKey, $fileName)) {
5621 if (!$this->outputProgress) {
5622 $this->io->write('    Downloading');
5623 }
5624
5625
5626  $retries = 3;
5627 while ($retries--) {
5628 try {
5629 $rfs->copy($hostname, $processedUrl, $fileName, $this->outputProgress, $package->getTransportOptions());
5630 break;
5631 } catch (TransportException $e) {
5632
5633  if ((0 !== $e->getCode() && !in_array($e->getCode(),array(500, 502, 503, 504))) || !$retries) {
5634 throw $e;
5635 }
5636 if ($this->io->isVerbose()) {
5637 $this->io->write('    Download failed, retrying...');
5638 }
5639 usleep(500000);
5640 }
5641 }
5642
5643 if ($this->cache) {
5644 $this->cache->copyFrom($cacheKey, $fileName);
5645 }
5646 } else {
5647 $this->io->write('    Loading from cache');
5648 }
5649
5650 if (!file_exists($fileName)) {
5651 throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
5652 .' directory is writable and you have internet connectivity');
5653 }
5654
5655 if ($checksum && hash_file('sha1', $fileName) !== $checksum) {
5656 throw new \UnexpectedValueException('The checksum verification of the file failed (downloaded from '.$url.')');
5657 }
5658 } catch (\Exception $e) {
5659
5660  $this->filesystem->removeDirectory($path);
5661 $this->clearCache($package, $path);
5662 throw $e;
5663 }
5664
5665 return $fileName;
5666 }
5667
5668
5669
5670
5671 public function setOutputProgress($outputProgress)
5672 {
5673 $this->outputProgress = $outputProgress;
5674
5675 return $this;
5676 }
5677
5678 protected function clearCache(PackageInterface $package, $path)
5679 {
5680 if ($this->cache) {
5681 $fileName = $this->getFileName($package, $path);
5682 $this->cache->remove($this->getCacheKey($package));
5683 }
5684 }
5685
5686
5687
5688
5689 public function update(PackageInterface $initial, PackageInterface $target, $path)
5690 {
5691 $this->remove($initial, $path);
5692 $this->download($target, $path);
5693 }
5694
5695
5696
5697
5698 public function remove(PackageInterface $package, $path)
5699 {
5700 $this->io->write("  - Removing <info>" . $package->getName() . "</info> (<comment>" . VersionParser::formatVersion($package) . "</comment>)");
5701 if (!$this->filesystem->removeDirectory($path)) {
5702 throw new \RuntimeException('Could not completely delete '.$path.', aborting.');
5703 }
5704 }
5705
5706
5707
5708
5709
5710
5711
5712
5713 protected function getFileName(PackageInterface $package, $path)
5714 {
5715 return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
5716 }
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727 protected function processUrl(PackageInterface $package, $url)
5728 {
5729 if (!extension_loaded('openssl') && 0 === strpos($url, 'https:')) {
5730 throw new \RuntimeException('You must enable the openssl extension to download files via https');
5731 }
5732
5733 return $url;
5734 }
5735
5736 private function getCacheKey(PackageInterface $package)
5737 {
5738 if (preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) {
5739 return $package->getName().'/'.$package->getDistReference().'.'.$package->getDistType();
5740 }
5741
5742 return $package->getName().'/'.$package->getVersion().'-'.$package->getDistReference().'.'.$package->getDistType();
5743 }
5744 }
5745 <?php
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757 namespace Composer\Downloader;
5758
5759 use Composer\Package\PackageInterface;
5760 use Composer\Util\Svn as SvnUtil;
5761
5762
5763
5764
5765
5766 class SvnDownloader extends VcsDownloader
5767 {
5768
5769
5770
5771 public function doDownload(PackageInterface $package, $path, $url)
5772 {
5773 SvnUtil::cleanEnv();
5774 $ref = $package->getSourceReference();
5775
5776 $this->io->write("    Checking out ".$package->getSourceReference());
5777 $this->execute($url, "svn co", sprintf("%s/%s", $url, $ref), null, $path);
5778 }
5779
5780
5781
5782
5783 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
5784 {
5785 SvnUtil::cleanEnv();
5786 $ref = $target->getSourceReference();
5787
5788 if (!is_dir($path.'/.svn')) {
5789 throw new \RuntimeException('The .svn directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information');
5790 }
5791
5792 $flags = "";
5793 if (0 === $this->process->execute('svn --version', $output)) {
5794 if (preg_match('{(\d+(?:\.\d+)+)}', $output, $match) && version_compare($match[1], '1.7.0', '>=')) {
5795 $flags .= ' --ignore-ancestry';
5796 }
5797 }
5798
5799 $this->io->write("    Checking out " . $ref);
5800 $this->execute($url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path);
5801 }
5802
5803
5804
5805
5806 public function getLocalChanges(PackageInterface $package, $path)
5807 {
5808 if (!is_dir($path.'/.svn')) {
5809 return;
5810 }
5811
5812 $this->process->execute('svn status --ignore-externals', $output, $path);
5813
5814 return preg_match('{^ *[^X ] +}m', $output) ? $output : null;
5815 }
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829 protected function execute($baseUrl, $command, $url, $cwd = null, $path = null)
5830 {
5831 $util = new SvnUtil($baseUrl, $this->io, $this->config);
5832 try {
5833 return $util->execute($command, $url, $cwd, $path, $this->io->isVerbose());
5834 } catch (\RuntimeException $e) {
5835 throw new \RuntimeException(
5836 'Package could not be downloaded, '.$e->getMessage()
5837 );
5838 }
5839 }
5840
5841
5842
5843
5844 protected function cleanChanges(PackageInterface $package, $path, $update)
5845 {
5846 if (!$changes = $this->getLocalChanges($package, $path)) {
5847 return;
5848 }
5849
5850 if (!$this->io->isInteractive()) {
5851 if (true === $this->config->get('discard-changes')) {
5852 return $this->discardChanges($path);
5853 }
5854
5855 return parent::cleanChanges($package, $path, $update);
5856 }
5857
5858 $changes = array_map(function ($elem) {
5859 return '    '.$elem;
5860 }, preg_split('{\s*\r?\n\s*}', $changes));
5861 $this->io->write('    <error>The package has modified files:</error>');
5862 $this->io->write(array_slice($changes, 0, 10));
5863 if (count($changes) > 10) {
5864 $this->io->write('    <info>'.count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>');
5865 }
5866
5867 while (true) {
5868 switch ($this->io->ask('    <info>Discard changes [y,n,v,?]?</info> ', '?')) {
5869 case 'y':
5870 $this->discardChanges($path);
5871 break 2;
5872
5873 case 'n':
5874 throw new \RuntimeException('Update aborted');
5875
5876 case 'v':
5877 $this->io->write($changes);
5878 break;
5879
5880 case '?':
5881 default:
5882 $this->io->write(array(
5883 '    y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
5884 '    n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
5885 '    v - view modified files',
5886 '    ? - print help',
5887 ));
5888 break;
5889 }
5890 }
5891 }
5892
5893
5894
5895
5896 protected function getCommitLogs($fromReference, $toReference, $path)
5897 {
5898 if (preg_match('{.*@(\d+)$}', $fromReference) && preg_match('{.*@(\d+)$}', $toReference) ) {
5899
5900  $fromRevision = preg_replace('{.*@(\d+)$}', '$1', $fromReference);
5901 $toRevision = preg_replace('{.*@(\d+)$}', '$1', $toReference);
5902
5903 $command = sprintf('svn log -r%s:%s --incremental', $fromRevision, $toRevision);
5904
5905 if (0 !== $this->process->execute($command, $output, $path)) {
5906 throw new \RuntimeException(
5907 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()
5908 );
5909 }
5910 } else {
5911 $output = "Could not retrieve changes between $fromReference and $toReference due to missing revision information";
5912 }
5913
5914 return $output;
5915 }
5916
5917 protected function discardChanges($path)
5918 {
5919 if (0 !== $this->process->execute('svn revert -R .', $output, $path)) {
5920 throw new \RuntimeException("Could not reset changes\n\n:".$this->process->getErrorOutput());
5921 }
5922 }
5923 }
5924 <?php
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936 namespace Composer\Downloader;
5937
5938 use Composer\Util\Filesystem;
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949 class PearPackageExtractor
5950 {
5951 private static $rolesWithoutPackageNamePrefix = array('php', 'script', 'www');
5952
5953 private $filesystem;
5954 private $file;
5955
5956 public function __construct($file)
5957 {
5958 if (!is_file($file)) {
5959 throw new \UnexpectedValueException('PEAR package file is not found at '.$file);
5960 }
5961
5962 $this->filesystem = new Filesystem();
5963 $this->file = $file;
5964 }
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976 public function extractTo($target, array $roles = array('php' => '/', 'script' => '/bin'), $vars = array())
5977 {
5978 $extractionPath = $target.'/tarball';
5979
5980 try {
5981 $archive = new \PharData($this->file);
5982 $archive->extractTo($extractionPath, null, true);
5983
5984 if (!is_file($this->combine($extractionPath, '/package.xml'))) {
5985 throw new \RuntimeException('Invalid PEAR package. It must contain package.xml file.');
5986 }
5987
5988 $fileCopyActions = $this->buildCopyActions($extractionPath, $roles, $vars);
5989 $this->copyFiles($fileCopyActions, $extractionPath, $target, $roles, $vars);
5990 $this->filesystem->removeDirectory($extractionPath);
5991 } catch (\Exception $exception) {
5992 throw new \UnexpectedValueException(sprintf('Failed to extract PEAR package %s to %s. Reason: %s', $this->file, $target, $exception->getMessage()), 0, $exception);
5993 }
5994 }
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005 private function copyFiles($files, $source, $target, $roles, $vars)
6006 {
6007 foreach ($files as $file) {
6008 $from = $this->combine($source, $file['from']);
6009 $to = $this->combine($target, $roles[$file['role']]);
6010 $to = $this->combine($to, $file['to']);
6011 $tasks = $file['tasks'];
6012 $this->copyFile($from, $to, $tasks, $vars);
6013 }
6014 }
6015
6016 private function copyFile($from, $to, $tasks, $vars)
6017 {
6018 if (!is_file($from)) {
6019 throw new \RuntimeException('Invalid PEAR package. package.xml defines file that is not located inside tarball.');
6020 }
6021
6022 $this->filesystem->ensureDirectoryExists(dirname($to));
6023
6024 if (0 == count($tasks)) {
6025 $copied = copy($from, $to);
6026 } else {
6027 $content = file_get_contents($from);
6028 $replacements = array();
6029 foreach ($tasks as $task) {
6030 $pattern = $task['from'];
6031 $varName = $task['to'];
6032 if (isset($vars[$varName])) {
6033 if ($varName === 'php_bin' && false === strpos($to, '.bat')) {
6034 $replacements[$pattern] = preg_replace('{\.bat$}', '', $vars[$varName]);
6035 } else {
6036 $replacements[$pattern] = $vars[$varName];
6037 }
6038 }
6039 }
6040 $content = strtr($content, $replacements);
6041
6042 $copied = file_put_contents($to, $content);
6043 }
6044
6045 if (false === $copied) {
6046 throw new \RuntimeException(sprintf('Failed to copy %s to %s', $from, $to));
6047 }
6048 }
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060 private function buildCopyActions($source, array $roles, $vars)
6061 {
6062
6063 $package = simplexml_load_file($this->combine($source, 'package.xml'));
6064 if (false === $package) {
6065 throw new \RuntimeException('Package definition file is not valid.');
6066 }
6067
6068 $packageSchemaVersion = $package['version'];
6069 if ('1.0' == $packageSchemaVersion) {
6070 $children = $package->release->filelist->children();
6071 $packageName = (string) $package->name;
6072 $packageVersion = (string) $package->release->version;
6073 $sourceDir = $packageName . '-' . $packageVersion;
6074 $result = $this->buildSourceList10($children, $roles, $sourceDir, '', null, $packageName);
6075 } elseif ('2.0' == $packageSchemaVersion || '2.1' == $packageSchemaVersion) {
6076 $children = $package->contents->children();
6077 $packageName = (string) $package->name;
6078 $packageVersion = (string) $package->version->release;
6079 $sourceDir = $packageName . '-' . $packageVersion;
6080 $result = $this->buildSourceList20($children, $roles, $sourceDir, '', null, $packageName);
6081
6082 $namespaces = $package->getNamespaces();
6083 $package->registerXPathNamespace('ns', $namespaces['']);
6084 $releaseNodes = $package->xpath('ns:phprelease');
6085 $this->applyRelease($result, $releaseNodes, $vars);
6086 } else {
6087 throw new \RuntimeException('Unsupported schema version of package definition file.');
6088 }
6089
6090 return $result;
6091 }
6092
6093 private function applyRelease(&$actions, $releaseNodes, $vars)
6094 {
6095 foreach ($releaseNodes as $releaseNode) {
6096 $requiredOs = $releaseNode->installconditions && $releaseNode->installconditions->os && $releaseNode->installconditions->os->name ? (string) $releaseNode->installconditions->os->name : '';
6097 if ($requiredOs && $vars['os'] != $requiredOs) {
6098 continue;
6099 }
6100
6101 if ($releaseNode->filelist) {
6102 foreach ($releaseNode->filelist->children() as $action) {
6103 if ('install' == $action->getName()) {
6104 $name = (string) $action['name'];
6105 $as = (string) $action['as'];
6106 if (isset($actions[$name])) {
6107 $actions[$name]['to'] = $as;
6108 }
6109 } elseif ('ignore' == $action->getName()) {
6110 $name = (string) $action['name'];
6111 unset($actions[$name]);
6112 } else {
6113
6114  }
6115 }
6116 }
6117 break;
6118 }
6119 }
6120
6121 private function buildSourceList10($children, $targetRoles, $source, $target, $role, $packageName)
6122 {
6123 $result = array();
6124
6125
6126  foreach ($children as $child) {
6127
6128 if ($child->getName() == 'dir') {
6129 $dirSource = $this->combine($source, (string) $child['name']);
6130 $dirTarget = $child['baseinstalldir'] ?: $target;
6131 $dirRole = $child['role'] ?: $role;
6132 $dirFiles = $this->buildSourceList10($child->children(), $targetRoles, $dirSource, $dirTarget, $dirRole, $packageName);
6133 $result = array_merge($result, $dirFiles);
6134 } elseif ($child->getName() == 'file') {
6135 $fileRole = (string) $child['role'] ?: $role;
6136 if (isset($targetRoles[$fileRole])) {
6137 $fileName = (string) ($child['name'] ?: $child[0]); 
6138  $fileSource = $this->combine($source, $fileName);
6139 $fileTarget = $this->combine((string) $child['baseinstalldir'] ?: $target, $fileName);
6140 if (!in_array($fileRole, self::$rolesWithoutPackageNamePrefix)) {
6141 $fileTarget = $packageName . '/' . $fileTarget;
6142 }
6143 $result[(string) $child['name']] = array('from' => $fileSource, 'to' => $fileTarget, 'role' => $fileRole, 'tasks' => array());
6144 }
6145 }
6146 }
6147
6148 return $result;
6149 }
6150
6151 private function buildSourceList20($children, $targetRoles, $source, $target, $role, $packageName)
6152 {
6153 $result = array();
6154
6155
6156  foreach ($children as $child) {
6157
6158 if ('dir' == $child->getName()) {
6159 $dirSource = $this->combine($source, $child['name']);
6160 $dirTarget = $child['baseinstalldir'] ?: $target;
6161 $dirRole = $child['role'] ?: $role;
6162 $dirFiles = $this->buildSourceList20($child->children(), $targetRoles, $dirSource, $dirTarget, $dirRole, $packageName);
6163 $result = array_merge($result, $dirFiles);
6164 } elseif ('file' == $child->getName()) {
6165 $fileRole = (string) $child['role'] ?: $role;
6166 if (isset($targetRoles[$fileRole])) {
6167 $fileSource = $this->combine($source, (string) $child['name']);
6168 $fileTarget = $this->combine((string) ($child['baseinstalldir'] ?: $target), (string) $child['name']);
6169 $fileTasks = array();
6170 foreach ($child->children('http://pear.php.net/dtd/tasks-1.0') as $taskNode) {
6171 if ('replace' == $taskNode->getName()) {
6172 $fileTasks[] = array('from' => (string) $taskNode->attributes()->from, 'to' => (string) $taskNode->attributes()->to);
6173 }
6174 }
6175 if (!in_array($fileRole, self::$rolesWithoutPackageNamePrefix)) {
6176 $fileTarget = $packageName . '/' . $fileTarget;
6177 }
6178 $result[(string) $child['name']] = array('from' => $fileSource, 'to' => $fileTarget, 'role' => $fileRole, 'tasks' => $fileTasks);
6179 }
6180 }
6181 }
6182
6183 return $result;
6184 }
6185
6186 private function combine($left, $right)
6187 {
6188 return rtrim($left, '/') . '/' . ltrim($right, '/');
6189 }
6190 }
6191 <?php
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203 namespace Composer\Downloader;
6204
6205 use Composer\Package\PackageInterface;
6206 use Composer\IO\IOInterface;
6207 use Composer\Util\Filesystem;
6208
6209
6210
6211
6212
6213
6214 class DownloadManager
6215 {
6216 private $io;
6217 private $preferDist = false;
6218 private $preferSource = false;
6219 private $filesystem;
6220 private $downloaders = array();
6221
6222
6223
6224
6225
6226
6227
6228
6229 public function __construct(IOInterface $io, $preferSource = false, Filesystem $filesystem = null)
6230 {
6231 $this->io = $io;
6232 $this->preferSource = $preferSource;
6233 $this->filesystem = $filesystem ?: new Filesystem();
6234 }
6235
6236
6237
6238
6239
6240
6241
6242 public function setPreferSource($preferSource)
6243 {
6244 $this->preferSource = $preferSource;
6245
6246 return $this;
6247 }
6248
6249
6250
6251
6252
6253
6254
6255 public function setPreferDist($preferDist)
6256 {
6257 $this->preferDist = $preferDist;
6258
6259 return $this;
6260 }
6261
6262
6263
6264
6265
6266
6267
6268
6269 public function setOutputProgress($outputProgress)
6270 {
6271 foreach ($this->downloaders as $downloader) {
6272 $downloader->setOutputProgress($outputProgress);
6273 }
6274
6275 return $this;
6276 }
6277
6278
6279
6280
6281
6282
6283
6284
6285 public function setDownloader($type, DownloaderInterface $downloader)
6286 {
6287 $type = strtolower($type);
6288 $this->downloaders[$type] = $downloader;
6289
6290 return $this;
6291 }
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301 public function getDownloader($type)
6302 {
6303 $type = strtolower($type);
6304 if (!isset($this->downloaders[$type])) {
6305 throw new \InvalidArgumentException(sprintf('Unknown downloader type: %s. Available types: %s.', $type, implode(', ', array_keys($this->downloaders))));
6306 }
6307
6308 return $this->downloaders[$type];
6309 }
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321 public function getDownloaderForInstalledPackage(PackageInterface $package)
6322 {
6323 $installationSource = $package->getInstallationSource();
6324
6325 if ('metapackage' === $package->getType()) {
6326 return;
6327 }
6328
6329 if ('dist' === $installationSource) {
6330 $downloader = $this->getDownloader($package->getDistType());
6331 } elseif ('source' === $installationSource) {
6332 $downloader = $this->getDownloader($package->getSourceType());
6333 } else {
6334 throw new \InvalidArgumentException(
6335 'Package '.$package.' seems not been installed properly'
6336 );
6337 }
6338
6339 if ($installationSource !== $downloader->getInstallationSource()) {
6340 throw new \LogicException(sprintf(
6341 'Downloader "%s" is a %s type downloader and can not be used to download %s',
6342 get_class($downloader), $downloader->getInstallationSource(), $installationSource
6343 ));
6344 }
6345
6346 return $downloader;
6347 }
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359 public function download(PackageInterface $package, $targetDir, $preferSource = null)
6360 {
6361 $preferSource = null !== $preferSource ? $preferSource : $this->preferSource;
6362 $sourceType = $package->getSourceType();
6363 $distType = $package->getDistType();
6364
6365 $sources = array();
6366 if ($sourceType) {
6367 $sources[] = 'source';
6368 }
6369 if ($distType) {
6370 $sources[] = 'dist';
6371 }
6372
6373 if (empty($sources)) {
6374 throw new \InvalidArgumentException('Package '.$package.' must have a source or dist specified');
6375 }
6376
6377 if ((!$package->isDev() || $this->preferDist) && !$preferSource) {
6378 $sources = array_reverse($sources);
6379 }
6380
6381 $this->filesystem->ensureDirectoryExists($targetDir);
6382
6383 foreach ($sources as $i => $source) {
6384 if (isset($e)) {
6385 $this->io->write('    <warning>Now trying to download from ' . $source . '</warning>');
6386 }
6387 $package->setInstallationSource($source);
6388 try {
6389 $downloader = $this->getDownloaderForInstalledPackage($package);
6390 if ($downloader) {
6391 $downloader->download($package, $targetDir);
6392 }
6393 break;
6394 } catch (\RuntimeException $e) {
6395 if ($i === count($sources) - 1) {
6396 throw $e;
6397 }
6398
6399 $this->io->write(
6400 '    <warning>Failed to download '.
6401 $package->getPrettyName().
6402 ' from ' . $source . ': '.
6403 $e->getMessage().'</warning>'
6404 );
6405 }
6406 }
6407 }
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418 public function update(PackageInterface $initial, PackageInterface $target, $targetDir)
6419 {
6420 $downloader = $this->getDownloaderForInstalledPackage($initial);
6421 if (!$downloader) {
6422 return;
6423 }
6424
6425 $installationSource = $initial->getInstallationSource();
6426
6427 if ('dist' === $installationSource) {
6428 $initialType = $initial->getDistType();
6429 $targetType = $target->getDistType();
6430 } else {
6431 $initialType = $initial->getSourceType();
6432 $targetType = $target->getSourceType();
6433 }
6434
6435
6436  if ($target->isDev() && 'dist' === $installationSource) {
6437 $downloader->remove($initial, $targetDir);
6438 $this->download($target, $targetDir);
6439
6440 return;
6441 }
6442
6443 if ($initialType === $targetType) {
6444 $target->setInstallationSource($installationSource);
6445 $downloader->update($initial, $target, $targetDir);
6446 } else {
6447 $downloader->remove($initial, $targetDir);
6448 $this->download($target, $targetDir, 'source' === $installationSource);
6449 }
6450 }
6451
6452
6453
6454
6455
6456
6457
6458 public function remove(PackageInterface $package, $targetDir)
6459 {
6460 $downloader = $this->getDownloaderForInstalledPackage($package);
6461 if ($downloader) {
6462 $downloader->remove($package, $targetDir);
6463 }
6464 }
6465 }
6466 <?php
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478 namespace Composer\Downloader;
6479
6480 use Composer\Package\PackageInterface;
6481
6482
6483
6484
6485
6486
6487
6488 interface DownloaderInterface
6489 {
6490
6491
6492
6493
6494
6495 public function getInstallationSource();
6496
6497
6498
6499
6500
6501
6502
6503 public function download(PackageInterface $package, $path);
6504
6505
6506
6507
6508
6509
6510
6511
6512 public function update(PackageInterface $initial, PackageInterface $target, $path);
6513
6514
6515
6516
6517
6518
6519
6520 public function remove(PackageInterface $package, $path);
6521
6522
6523
6524
6525
6526
6527
6528 public function setOutputProgress($outputProgress);
6529 }
6530 <?php
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542 namespace Composer\Downloader;
6543
6544
6545
6546
6547 class TransportException extends \RuntimeException
6548 {
6549 protected $headers;
6550 protected $response;
6551
6552 public function setHeaders($headers)
6553 {
6554 $this->headers = $headers;
6555 }
6556
6557 public function getHeaders()
6558 {
6559 return $this->headers;
6560 }
6561
6562 public function setResponse($response)
6563 {
6564 $this->response = $response;
6565 }
6566
6567 public function getResponse()
6568 {
6569 return $this->response;
6570 }
6571 }
6572 <?php
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584 namespace Composer\Downloader;
6585
6586
6587
6588
6589
6590
6591 class PharDownloader extends ArchiveDownloader
6592 {
6593
6594
6595
6596 protected function extract($file, $path)
6597 {
6598
6599  $archive = new \Phar($file);
6600 $archive->extractTo($path, null, true);
6601
6602
6603
6604
6605
6606 }
6607 }
6608 <?php
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620 namespace Composer\Downloader;
6621
6622
6623
6624
6625
6626
6627 class TarDownloader extends ArchiveDownloader
6628 {
6629
6630
6631
6632 protected function extract($file, $path)
6633 {
6634
6635  $archive = new \PharData($file);
6636 $archive->extractTo($path, null, true);
6637 }
6638 }
6639 <?php
6640
6641
6642
6643
6644
6645
6646
6647
6648
6649
6650
6651 namespace Composer\Downloader;
6652
6653 use Composer\Package\PackageInterface;
6654 use Composer\Util\ProcessExecutor;
6655
6656
6657
6658
6659 class HgDownloader extends VcsDownloader
6660 {
6661
6662
6663
6664 public function doDownload(PackageInterface $package, $path, $url)
6665 {
6666 $url = ProcessExecutor::escape($url);
6667 $ref = ProcessExecutor::escape($package->getSourceReference());
6668 $this->io->write("    Cloning ".$package->getSourceReference());
6669 $command = sprintf('hg clone %s %s', $url, ProcessExecutor::escape($path));
6670 if (0 !== $this->process->execute($command, $ignoredOutput)) {
6671 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
6672 }
6673 $command = sprintf('hg up %s', $ref);
6674 if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
6675 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
6676 }
6677 }
6678
6679
6680
6681
6682 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
6683 {
6684 $url = ProcessExecutor::escape($url);
6685 $ref = ProcessExecutor::escape($target->getSourceReference());
6686 $this->io->write("    Updating to ".$target->getSourceReference());
6687
6688 if (!is_dir($path.'/.hg')) {
6689 throw new \RuntimeException('The .hg directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information');
6690 }
6691
6692 $command = sprintf('hg pull %s && hg up %s', $url, $ref);
6693 if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) {
6694 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
6695 }
6696 }
6697
6698
6699
6700
6701 public function getLocalChanges(PackageInterface $package, $path)
6702 {
6703 if (!is_dir($path.'/.hg')) {
6704 return;
6705 }
6706
6707 $this->process->execute('hg st', $output, realpath($path));
6708
6709 return trim($output) ?: null;
6710 }
6711
6712
6713
6714
6715 protected function getCommitLogs($fromReference, $toReference, $path)
6716 {
6717 $command = sprintf('hg log -r %s:%s --style compact', $fromReference, $toReference);
6718
6719 if (0 !== $this->process->execute($command, $output, realpath($path))) {
6720 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
6721 }
6722
6723 return $output;
6724 }
6725 }
6726 <?php
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738 namespace Composer\Downloader;
6739
6740 use Composer\Package\PackageInterface;
6741
6742
6743
6744
6745
6746
6747 interface ChangeReportInterface
6748 {
6749
6750
6751
6752
6753
6754
6755
6756 public function getLocalChanges(PackageInterface $package, $path);
6757 }
6758 <?php
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770 namespace Composer\Downloader;
6771
6772 use Composer\Package\PackageInterface;
6773 use Symfony\Component\Finder\Finder;
6774
6775
6776
6777
6778
6779
6780
6781
6782 abstract class ArchiveDownloader extends FileDownloader
6783 {
6784
6785
6786
6787 public function download(PackageInterface $package, $path)
6788 {
6789 $temporaryDir = $this->config->get('vendor-dir').'/composer/'.substr(md5(uniqid('', true)), 0, 8);
6790 $retries = 3;
6791 while ($retries--) {
6792 $fileName = parent::download($package, $path);
6793
6794 if ($this->io->isVerbose()) {
6795 $this->io->write('    Extracting archive');
6796 }
6797
6798 try {
6799 $this->filesystem->ensureDirectoryExists($temporaryDir);
6800 try {
6801 $this->extract($fileName, $temporaryDir);
6802 } catch (\Exception $e) {
6803
6804  parent::clearCache($package, $path);
6805 throw $e;
6806 }
6807
6808 $this->filesystem->unlink($fileName);
6809
6810 $contentDir = $this->getFolderContent($temporaryDir);
6811
6812
6813  if (1 === count($contentDir) && is_dir(reset($contentDir))) {
6814 $contentDir = $this->getFolderContent((string) reset($contentDir));
6815 }
6816
6817
6818  foreach ($contentDir as $file) {
6819 $file = (string) $file;
6820 $this->filesystem->rename($file, $path . '/' . basename($file));
6821 }
6822
6823 $this->filesystem->removeDirectory($temporaryDir);
6824 if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir').'/composer/')) {
6825 $this->filesystem->removeDirectory($this->config->get('vendor-dir').'/composer/');
6826 }
6827 if ($this->filesystem->isDirEmpty($this->config->get('vendor-dir'))) {
6828 $this->filesystem->removeDirectory($this->config->get('vendor-dir'));
6829 }
6830 } catch (\Exception $e) {
6831
6832  $this->filesystem->removeDirectory($path);
6833 $this->filesystem->removeDirectory($temporaryDir);
6834
6835
6836  if ($retries && $e instanceof \UnexpectedValueException && class_exists('ZipArchive') && $e->getCode() === \ZipArchive::ER_NOZIP) {
6837 $this->io->write('    Invalid zip file, retrying...');
6838 usleep(500000);
6839 continue;
6840 }
6841
6842 throw $e;
6843 }
6844
6845 break;
6846 }
6847
6848 $this->io->write('');
6849 }
6850
6851
6852
6853
6854 protected function getFileName(PackageInterface $package, $path)
6855 {
6856 return rtrim($path.'/'.md5($path.spl_object_hash($package)).'.'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_EXTENSION), '.');
6857 }
6858
6859
6860
6861
6862 protected function processUrl(PackageInterface $package, $url)
6863 {
6864 if ($package->getDistReference() && strpos($url, 'github.com')) {
6865 if (preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/(zip|tar)ball/(.+)$}i', $url, $match)) {
6866
6867  $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference();
6868 } elseif ($package->getDistReference() && preg_match('{^https?://(?:www\.)?github\.com/([^/]+)/([^/]+)/archive/.+\.(zip|tar)(?:\.gz)?$}i', $url, $match)) {
6869
6870  $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference();
6871 } elseif ($package->getDistReference() && preg_match('{^https?://api\.github\.com/repos/([^/]+)/([^/]+)/(zip|tar)ball(?:/.+)?$}i', $url, $match)) {
6872
6873  $url = 'https://api.github.com/repos/' . $match[1] . '/'. $match[2] . '/' . $match[3] . 'ball/' . $package->getDistReference();
6874 }
6875 }
6876
6877 if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) {
6878 throw new \RuntimeException('You must enable the openssl extension to download files via https');
6879 }
6880
6881 return parent::processUrl($package, $url);
6882 }
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892 abstract protected function extract($file, $path);
6893
6894
6895
6896
6897
6898
6899
6900 private function getFolderContent($dir)
6901 {
6902 $finder = Finder::create()
6903 ->ignoreVCS(false)
6904 ->ignoreDotFiles(false)
6905 ->depth(0)
6906 ->in($dir);
6907
6908 return iterator_to_array($finder);
6909 }
6910 }
6911 <?php
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923 namespace Composer\Downloader;
6924
6925
6926
6927
6928
6929
6930 class FilesystemException extends \Exception
6931 {
6932 public function __construct($message = null, $code = null, \Exception $previous = null)
6933 {
6934 parent::__construct("Filesystem exception: \n".$message, $code, $previous);
6935 }
6936 }
6937 <?php
6938
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949 namespace Composer\Downloader;
6950
6951 use Composer\Package\PackageInterface;
6952 use Composer\Repository\VcsRepository;
6953 use Composer\Util\Perforce;
6954
6955
6956
6957
6958 class PerforceDownloader extends VcsDownloader
6959 {
6960 protected $perforce;
6961
6962
6963
6964
6965 public function doDownload(PackageInterface $package, $path, $url)
6966 {
6967 $ref = $package->getSourceReference();
6968 $label = $this->getLabelFromSourceReference($ref);
6969
6970 $this->io->write('    Cloning ' . $ref);
6971 $this->initPerforce($package, $path, $url);
6972 $this->perforce->setStream($ref);
6973 $this->perforce->p4Login($this->io);
6974 $this->perforce->writeP4ClientSpec();
6975 $this->perforce->connectClient();
6976 $this->perforce->syncCodeBase($label);
6977 $this->perforce->cleanupClientSpec();
6978 }
6979
6980 private function getLabelFromSourceReference($ref)
6981 {
6982 $pos = strpos($ref,'@');
6983 if (false !== $pos) {
6984 return substr($ref, $pos + 1);
6985 }
6986
6987 return null;
6988 }
6989
6990 public function initPerforce($package, $path, $url)
6991 {
6992 if (!empty($this->perforce)) {
6993 $this->perforce->initializePath($path);
6994
6995 return;
6996 }
6997
6998 $repository = $package->getRepository();
6999 $repoConfig = null;
7000 if ($repository instanceof VcsRepository) {
7001 $repoConfig = $this->getRepoConfig($repository);
7002 }
7003 $this->perforce = Perforce::create($repoConfig, $url, $path, $this->process, $this->io);
7004 }
7005
7006 private function getRepoConfig(VcsRepository $repository)
7007 {
7008 return $repository->getRepoConfig();
7009 }
7010
7011
7012
7013
7014 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
7015 {
7016 $this->doDownload($target, $path, $url);
7017 }
7018
7019
7020
7021
7022 public function getLocalChanges(PackageInterface $package, $path)
7023 {
7024 $this->io->write('Perforce driver does not check for local changes before overriding', true);
7025
7026 return;
7027 }
7028
7029
7030
7031
7032 protected function getCommitLogs($fromReference, $toReference, $path)
7033 {
7034 $commitLogs = $this->perforce->getCommitLogs($fromReference, $toReference);
7035
7036 return $commitLogs;
7037 }
7038
7039 public function setPerforce($perforce)
7040 {
7041 $this->perforce = $perforce;
7042 }
7043 }
7044 <?php
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056 namespace Composer\Downloader;
7057
7058 use Composer\Config;
7059 use Composer\Cache;
7060 use Composer\EventDispatcher\EventDispatcher;
7061 use Composer\Util\ProcessExecutor;
7062 use Composer\IO\IOInterface;
7063 use ZipArchive;
7064
7065
7066
7067
7068 class ZipDownloader extends ArchiveDownloader
7069 {
7070 protected $process;
7071
7072 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
7073 {
7074 $this->process = $process ?: new ProcessExecutor($io);
7075 parent::__construct($io, $config, $eventDispatcher, $cache);
7076 }
7077
7078 protected function extract($file, $path)
7079 {
7080 $processError = null;
7081
7082
7083  if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
7084 $command = 'unzip '.ProcessExecutor::escape($file).' -d '.ProcessExecutor::escape($path) . ' && chmod -R u+w ' . ProcessExecutor::escape($path);
7085 try {
7086 if (0 === $this->process->execute($command, $ignoredOutput)) {
7087 return;
7088 }
7089
7090 $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
7091 } catch (\Exception $e) {
7092 $processError = 'Failed to execute ' . $command . "\n\n" . $e->getMessage();
7093 }
7094 }
7095
7096 if (!class_exists('ZipArchive')) {
7097
7098  $iniPath = php_ini_loaded_file();
7099
7100 if ($iniPath) {
7101 $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
7102 } else {
7103 $iniMessage = 'A php.ini file does not exist. You will have to create one.';
7104 }
7105
7106 $error = "Could not decompress the archive, enable the PHP zip extension or install unzip.\n"
7107 . $iniMessage . "\n" . $processError;
7108
7109 if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
7110 $error = "Could not decompress the archive, enable the PHP zip extension.\n" . $iniMessage;
7111 }
7112
7113 throw new \RuntimeException($error);
7114 }
7115
7116 $zipArchive = new ZipArchive();
7117
7118 if (true !== ($retval = $zipArchive->open($file))) {
7119 throw new \UnexpectedValueException($this->getErrorMessage($retval, $file), $retval);
7120 }
7121
7122 if (true !== $zipArchive->extractTo($path)) {
7123 throw new \RuntimeException("There was an error extracting the ZIP file. Corrupt file?");
7124 }
7125
7126 $zipArchive->close();
7127 }
7128
7129
7130
7131
7132
7133
7134
7135
7136 protected function getErrorMessage($retval, $file)
7137 {
7138 switch ($retval) {
7139 case ZipArchive::ER_EXISTS:
7140 return sprintf("File '%s' already exists.", $file);
7141 case ZipArchive::ER_INCONS:
7142 return sprintf("Zip archive '%s' is inconsistent.", $file);
7143 case ZipArchive::ER_INVAL:
7144 return sprintf("Invalid argument (%s)", $file);
7145 case ZipArchive::ER_MEMORY:
7146 return sprintf("Malloc failure (%s)", $file);
7147 case ZipArchive::ER_NOENT:
7148 return sprintf("No such zip file: '%s'", $file);
7149 case ZipArchive::ER_NOZIP:
7150 return sprintf("'%s' is not a zip archive.", $file);
7151 case ZipArchive::ER_OPEN:
7152 return sprintf("Can't open zip file: %s", $file);
7153 case ZipArchive::ER_READ:
7154 return sprintf("Zip read error (%s)", $file);
7155 case ZipArchive::ER_SEEK:
7156 return sprintf("Zip seek error (%s)", $file);
7157 default:
7158 return sprintf("'%s' is not a valid zip archive, got error code: %s", $file, $retval);
7159 }
7160 }
7161 }
7162 <?php
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174 namespace Composer\Downloader;
7175
7176 use Composer\Config;
7177 use Composer\Cache;
7178 use Composer\EventDispatcher\EventDispatcher;
7179 use Composer\Package\PackageInterface;
7180 use Composer\Util\ProcessExecutor;
7181 use Composer\IO\IOInterface;
7182
7183
7184
7185
7186
7187
7188 class GzipDownloader extends ArchiveDownloader
7189 {
7190 protected $process;
7191
7192 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
7193 {
7194 $this->process = $process ?: new ProcessExecutor($io);
7195 parent::__construct($io, $config, $eventDispatcher, $cache);
7196 }
7197
7198 protected function extract($file, $path)
7199 {
7200 $targetFilepath = $path . DIRECTORY_SEPARATOR . basename(substr($file, 0, -3));
7201
7202
7203  if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
7204 $command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
7205
7206 if (0 === $this->process->execute($command, $ignoredOutput)) {
7207 return;
7208 }
7209
7210 $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
7211 throw new \RuntimeException($processError);
7212 }
7213
7214
7215  $archiveFile = gzopen($file, 'rb');
7216 $targetFile = fopen($targetFilepath, 'wb');
7217 while ($string = gzread($archiveFile, 4096)) {
7218 fwrite($targetFile, $string, strlen($string));
7219 }
7220 gzclose($archiveFile);
7221 fclose($targetFile);
7222 }
7223
7224
7225
7226
7227 protected function getFileName(PackageInterface $package, $path)
7228 {
7229 return $path.'/'.pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_BASENAME);
7230 }
7231 }
7232 <?php
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244 namespace Composer\Downloader;
7245
7246 use Composer\Package\PackageInterface;
7247 use Composer\Util\GitHub;
7248 use Composer\Util\Git as GitUtil;
7249 use Composer\Util\ProcessExecutor;
7250 use Composer\IO\IOInterface;
7251 use Composer\Util\Filesystem;
7252 use Composer\Config;
7253
7254
7255
7256
7257 class GitDownloader extends VcsDownloader
7258 {
7259 private $hasStashedChanges = false;
7260 private $gitUtil;
7261
7262 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, Filesystem $fs = null)
7263 {
7264 parent::__construct($io, $config, $process, $fs);
7265 $this->gitUtil = new GitUtil($this->io, $this->config, $this->process, $this->filesystem);
7266 }
7267
7268
7269
7270
7271 public function doDownload(PackageInterface $package, $path, $url)
7272 {
7273 GitUtil::cleanEnv();
7274 $path = $this->normalizePath($path);
7275
7276 $ref = $package->getSourceReference();
7277 $flag = defined('PHP_WINDOWS_VERSION_MAJOR') ? '/D ' : '';
7278 $command = 'git clone --no-checkout %s %s && cd '.$flag.'%2$s && git remote add composer %1$s && git fetch composer';
7279 $this->io->write("    Cloning ".$ref);
7280
7281 $commandCallable = function ($url) use ($ref, $path, $command) {
7282 return sprintf($command, ProcessExecutor::escape($url), ProcessExecutor::escape($path), ProcessExecutor::escape($ref));
7283 };
7284
7285 $this->gitUtil->runCommand($commandCallable, $url, $path, true);
7286 if ($url !== $package->getSourceUrl()) {
7287 $url = $package->getSourceUrl();
7288 $this->process->execute(sprintf('git remote set-url origin %s', ProcessExecutor::escape($url)), $output, $path);
7289 }
7290 $this->setPushUrl($path, $url);
7291
7292 if ($newRef = $this->updateToCommit($path, $ref, $package->getPrettyVersion(), $package->getReleaseDate())) {
7293 if ($package->getDistReference() === $package->getSourceReference()) {
7294 $package->setDistReference($newRef);
7295 }
7296 $package->setSourceReference($newRef);
7297 }
7298 }
7299
7300
7301
7302
7303 public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url)
7304 {
7305 GitUtil::cleanEnv();
7306 $path = $this->normalizePath($path);
7307 if (!is_dir($path.'/.git')) {
7308 throw new \RuntimeException('The .git directory is missing from '.$path.', see http://getcomposer.org/commit-deps for more information');
7309 }
7310
7311 $ref = $target->getSourceReference();
7312 $this->io->write("    Checking out ".$ref);
7313 $command = 'git remote set-url composer %s && git fetch composer && git fetch --tags composer';
7314
7315 $commandCallable = function ($url) use ($command) {
7316 return sprintf($command, ProcessExecutor::escape ($url));
7317 };
7318
7319 $this->gitUtil->runCommand($commandCallable, $url, $path);
7320 if ($newRef = $this->updateToCommit($path, $ref, $target->getPrettyVersion(), $target->getReleaseDate())) {
7321 if ($target->getDistReference() === $target->getSourceReference()) {
7322 $target->setDistReference($newRef);
7323 }
7324 $target->setSourceReference($newRef);
7325 }
7326 }
7327
7328
7329
7330
7331 public function getLocalChanges(PackageInterface $package, $path)
7332 {
7333 GitUtil::cleanEnv();
7334 $path = $this->normalizePath($path);
7335 if (!is_dir($path.'/.git')) {
7336 return;
7337 }
7338
7339 $command = 'git status --porcelain --untracked-files=no';
7340 if (0 !== $this->process->execute($command, $output, $path)) {
7341 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
7342 }
7343
7344 return trim($output) ?: null;
7345 }
7346
7347
7348
7349
7350 protected function cleanChanges(PackageInterface $package, $path, $update)
7351 {
7352 GitUtil::cleanEnv();
7353 $path = $this->normalizePath($path);
7354 if (!$changes = $this->getLocalChanges($package, $path)) {
7355 return;
7356 }
7357
7358 if (!$this->io->isInteractive()) {
7359 $discardChanges = $this->config->get('discard-changes');
7360 if (true === $discardChanges) {
7361 return $this->discardChanges($path);
7362 }
7363 if ('stash' === $discardChanges) {
7364 if (!$update) {
7365 return parent::cleanChanges($package, $path, $update);
7366 }
7367
7368 return $this->stashChanges($path);
7369 }
7370
7371 return parent::cleanChanges($package, $path, $update);
7372 }
7373
7374 $changes = array_map(function ($elem) {
7375 return '    '.$elem;
7376 }, preg_split('{\s*\r?\n\s*}', $changes));
7377 $this->io->write('    <error>The package has modified files:</error>');
7378 $this->io->write(array_slice($changes, 0, 10));
7379 if (count($changes) > 10) {
7380 $this->io->write('    <info>'.count($changes) - 10 . ' more files modified, choose "v" to view the full list</info>');
7381 }
7382
7383 while (true) {
7384 switch ($this->io->ask('    <info>Discard changes [y,n,v,'.($update ? 's,' : '').'?]?</info> ', '?')) {
7385 case 'y':
7386 $this->discardChanges($path);
7387 break 2;
7388
7389 case 's':
7390 if (!$update) {
7391 goto help;
7392 }
7393
7394 $this->stashChanges($path);
7395 break 2;
7396
7397 case 'n':
7398 throw new \RuntimeException('Update aborted');
7399
7400 case 'v':
7401 $this->io->write($changes);
7402 break;
7403
7404 case '?':
7405 default:
7406 help:
7407 $this->io->write(array(
7408 '    y - discard changes and apply the '.($update ? 'update' : 'uninstall'),
7409 '    n - abort the '.($update ? 'update' : 'uninstall').' and let you manually clean things up',
7410 '    v - view modified files',
7411 ));
7412 if ($update) {
7413 $this->io->write('    s - stash changes and try to reapply them after the update');
7414 }
7415 $this->io->write('    ? - print help');
7416 break;
7417 }
7418 }
7419 }
7420
7421
7422
7423
7424 protected function reapplyChanges($path)
7425 {
7426 $path = $this->normalizePath($path);
7427 if ($this->hasStashedChanges) {
7428 $this->hasStashedChanges = false;
7429 $this->io->write('    <info>Re-applying stashed changes</info>');
7430 if (0 !== $this->process->execute('git stash pop', $output, $path)) {
7431 throw new \RuntimeException("Failed to apply stashed changes:\n\n".$this->process->getErrorOutput());
7432 }
7433 }
7434 }
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447 protected function updateToCommit($path, $reference, $branch, $date)
7448 {
7449 $template = 'git checkout %s && git reset --hard %1$s';
7450 $branch = preg_replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $branch);
7451
7452 $branches = null;
7453 if (0 === $this->process->execute('git branch -r', $output, $path)) {
7454 $branches = $output;
7455 }
7456
7457
7458  $gitRef = $reference;
7459 if (!preg_match('{^[a-f0-9]{40}$}', $reference)
7460 && $branches
7461 && preg_match('{^\s+composer/'.preg_quote($reference).'$}m', $branches)
7462 ) {
7463 $command = sprintf('git checkout -B %s %s && git reset --hard %2$s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference));
7464 if (0 === $this->process->execute($command, $output, $path)) {
7465 return;
7466 }
7467 }
7468
7469
7470  if (preg_match('{^[a-f0-9]{40}$}', $reference)) {
7471
7472  if (!preg_match('{^\s+composer/'.preg_quote($branch).'$}m', $branches) && preg_match('{^\s+composer/v'.preg_quote($branch).'$}m', $branches)) {
7473 $branch = 'v' . $branch;
7474 }
7475
7476 $command = sprintf('git checkout %s', ProcessExecutor::escape($branch));
7477 $fallbackCommand = sprintf('git checkout -B %s %s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch));
7478 if (0 === $this->process->execute($command, $output, $path)
7479 || 0 === $this->process->execute($fallbackCommand, $output, $path)
7480 ) {
7481 $command = sprintf('git reset --hard %s', ProcessExecutor::escape($reference));
7482 if (0 === $this->process->execute($command, $output, $path)) {
7483 return;
7484 }
7485 }
7486 }
7487
7488 $command = sprintf($template, ProcessExecutor::escape($gitRef));
7489 if (0 === $this->process->execute($command, $output, $path)) {
7490 return;
7491 }
7492
7493
7494  if (false !== strpos($this->process->getErrorOutput(), $reference)) {
7495 $this->io->write('    <warning>'.$reference.' is gone (history was rewritten?)</warning>');
7496 }
7497
7498 throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput());
7499 }
7500
7501 protected function setPushUrl($path, $url)
7502 {
7503
7504  if (preg_match('{^(?:https?|git)://'.GitUtil::getGitHubDomainsRegex($this->config).'/([^/]+)/([^/]+?)(?:\.git)?$}', $url, $match)) {
7505 $protocols = $this->config->get('github-protocols');
7506 $pushUrl = 'git@'.$match[1].':'.$match[2].'/'.$match[3].'.git';
7507 if ($protocols[0] !== 'git') {
7508 $pushUrl = 'https://' . $match[1] . '/'.$match[2].'/'.$match[3].'.git';
7509 }
7510 $cmd = sprintf('git remote set-url --push origin %s', ProcessExecutor::escape($pushUrl));
7511 $this->process->execute($cmd, $ignoredOutput, $path);
7512 }
7513 }
7514
7515
7516
7517
7518 protected function getCommitLogs($fromReference, $toReference, $path)
7519 {
7520 $path = $this->normalizePath($path);
7521 $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"', $fromReference, $toReference);
7522
7523 if (0 !== $this->process->execute($command, $output, $path)) {
7524 throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput());
7525 }
7526
7527 return $output;
7528 }
7529
7530
7531
7532
7533
7534 protected function discardChanges($path)
7535 {
7536 $path = $this->normalizePath($path);
7537 if (0 !== $this->process->execute('git reset --hard', $output, $path)) {
7538 throw new \RuntimeException("Could not reset changes\n\n:".$this->process->getErrorOutput());
7539 }
7540 }
7541
7542
7543
7544
7545
7546 protected function stashChanges($path)
7547 {
7548 $path = $this->normalizePath($path);
7549 if (0 !== $this->process->execute('git stash', $output, $path)) {
7550 throw new \RuntimeException("Could not stash changes\n\n:".$this->process->getErrorOutput());
7551 }
7552
7553 $this->hasStashedChanges = true;
7554 }
7555
7556 protected function normalizePath($path)
7557 {
7558 if (defined('PHP_WINDOWS_VERSION_MAJOR') && strlen($path) > 0) {
7559 $basePath = $path;
7560 $removed = array();
7561
7562 while (!is_dir($basePath) && $basePath !== '\\') {
7563 array_unshift($removed, basename($basePath));
7564 $basePath = dirname($basePath);
7565 }
7566
7567 if ($basePath === '\\') {
7568 return $path;
7569 }
7570
7571 $path = rtrim(realpath($basePath) . '/' . implode('/', $removed), '/');
7572 }
7573
7574 return $path;
7575 }
7576 }
7577 <?php
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589 namespace Composer\Repository;
7590
7591
7592
7593
7594
7595
7596 class InvalidRepositoryException extends \Exception
7597 {
7598 }
7599 <?php
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611 namespace Composer\Repository;
7612
7613 use Composer\Package\AliasPackage;
7614 use Composer\Package\PackageInterface;
7615 use Composer\Package\CompletePackageInterface;
7616 use Composer\Package\Version\VersionParser;
7617
7618
7619
7620
7621
7622
7623 class ArrayRepository implements RepositoryInterface
7624 {
7625 protected $packages;
7626
7627 public function __construct(array $packages = array())
7628 {
7629 foreach ($packages as $package) {
7630 $this->addPackage($package);
7631 }
7632 }
7633
7634
7635
7636
7637 public function findPackage($name, $version)
7638 {
7639
7640  $versionParser = new VersionParser();
7641 $version = $versionParser->normalize($version);
7642 $name = strtolower($name);
7643
7644 foreach ($this->getPackages() as $package) {
7645 if ($name === $package->getName() && $version === $package->getVersion()) {
7646 return $package;
7647 }
7648 }
7649 }
7650
7651
7652
7653
7654 public function findPackages($name, $version = null)
7655 {
7656
7657  $name = strtolower($name);
7658
7659
7660  if (null !== $version) {
7661 $versionParser = new VersionParser();
7662 $version = $versionParser->normalize($version);
7663 }
7664
7665 $packages = array();
7666
7667 foreach ($this->getPackages() as $package) {
7668 if ($package->getName() === $name && (null === $version || $version === $package->getVersion())) {
7669 $packages[] = $package;
7670 }
7671 }
7672
7673 return $packages;
7674 }
7675
7676
7677
7678
7679 public function search($query, $mode = 0)
7680 {
7681 $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
7682
7683 $matches = array();
7684 foreach ($this->getPackages() as $package) {
7685 $name = $package->getName();
7686 if (isset($matches[$name])) {
7687 continue;
7688 }
7689 if (preg_match($regex, $name)
7690 || ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && preg_match($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription()))
7691 ) {
7692 $matches[$name] = array(
7693 'name' => $package->getPrettyName(),
7694 'description' => $package->getDescription(),
7695 );
7696 }
7697 }
7698
7699 return array_values($matches);
7700 }
7701
7702
7703
7704
7705 public function hasPackage(PackageInterface $package)
7706 {
7707 $packageId = $package->getUniqueName();
7708
7709 foreach ($this->getPackages() as $repoPackage) {
7710 if ($packageId === $repoPackage->getUniqueName()) {
7711 return true;
7712 }
7713 }
7714
7715 return false;
7716 }
7717
7718
7719
7720
7721
7722
7723 public function addPackage(PackageInterface $package)
7724 {
7725 if (null === $this->packages) {
7726 $this->initialize();
7727 }
7728 $package->setRepository($this);
7729 $this->packages[] = $package;
7730
7731 if ($package instanceof AliasPackage) {
7732 $aliasedPackage = $package->getAliasOf();
7733 if (null === $aliasedPackage->getRepository()) {
7734 $this->addPackage($aliasedPackage);
7735 }
7736 }
7737 }
7738
7739 protected function createAliasPackage(PackageInterface $package, $alias, $prettyAlias)
7740 {
7741 return new AliasPackage($package instanceof AliasPackage ? $package->getAliasOf() : $package, $alias, $prettyAlias);
7742 }
7743
7744
7745
7746
7747
7748
7749 public function removePackage(PackageInterface $package)
7750 {
7751 $packageId = $package->getUniqueName();
7752
7753 foreach ($this->getPackages() as $key => $repoPackage) {
7754 if ($packageId === $repoPackage->getUniqueName()) {
7755 array_splice($this->packages, $key, 1);
7756
7757 return;
7758 }
7759 }
7760 }
7761
7762
7763
7764
7765 public function getPackages()
7766 {
7767 if (null === $this->packages) {
7768 $this->initialize();
7769 }
7770
7771 return $this->packages;
7772 }
7773
7774
7775
7776
7777
7778
7779 public function count()
7780 {
7781 return count($this->packages);
7782 }
7783
7784
7785
7786
7787 protected function initialize()
7788 {
7789 $this->packages = array();
7790 }
7791 }
7792 <?php
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804 namespace Composer\Repository;
7805
7806 use Composer\Json\JsonFile;
7807 use Composer\Package\Loader\ArrayLoader;
7808 use Composer\Package\Dumper\ArrayDumper;
7809
7810
7811
7812
7813
7814
7815
7816 class FilesystemRepository extends WritableArrayRepository
7817 {
7818 private $file;
7819
7820
7821
7822
7823
7824
7825 public function __construct(JsonFile $repositoryFile)
7826 {
7827 $this->file = $repositoryFile;
7828 }
7829
7830
7831
7832
7833 protected function initialize()
7834 {
7835 parent::initialize();
7836
7837 if (!$this->file->exists()) {
7838 return;
7839 }
7840
7841 try {
7842 $packages = $this->file->read();
7843
7844 if (!is_array($packages)) {
7845 throw new \UnexpectedValueException('Could not parse package list from the repository');
7846 }
7847 } catch (\Exception $e) {
7848 throw new InvalidRepositoryException('Invalid repository data in '.$this->file->getPath().', packages could not be loaded: ['.get_class($e).'] '.$e->getMessage());
7849 }
7850
7851 $loader = new ArrayLoader(null, true);
7852 foreach ($packages as $packageData) {
7853 $package = $loader->load($packageData);
7854 $this->addPackage($package);
7855 }
7856 }
7857
7858 public function reload()
7859 {
7860 $this->packages = null;
7861 $this->initialize();
7862 }
7863
7864
7865
7866
7867 public function write()
7868 {
7869 $data = array();
7870 $dumper = new ArrayDumper();
7871
7872 foreach ($this->getCanonicalPackages() as $package) {
7873 $data[] = $dumper->dump($package);
7874 }
7875
7876 $this->file->write($data);
7877 }
7878 }
7879 <?php
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891 namespace Composer\Repository;
7892
7893 use Composer\Package\PackageInterface;
7894
7895
7896
7897
7898
7899
7900 interface WritableRepositoryInterface extends RepositoryInterface
7901 {
7902
7903
7904
7905 public function write();
7906
7907
7908
7909
7910
7911
7912 public function addPackage(PackageInterface $package);
7913
7914
7915
7916
7917
7918
7919 public function removePackage(PackageInterface $package);
7920
7921
7922
7923
7924
7925
7926 public function getCanonicalPackages();
7927
7928
7929
7930
7931 public function reload();
7932 }
7933 <?php
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945 namespace Composer\Repository;
7946
7947 use Composer\IO\IOInterface;
7948 use Composer\Package\Version\VersionParser;
7949 use Composer\Repository\Pear\ChannelReader;
7950 use Composer\Package\CompletePackage;
7951 use Composer\Repository\Pear\ChannelInfo;
7952 use Composer\EventDispatcher\EventDispatcher;
7953 use Composer\Package\Link;
7954 use Composer\Package\LinkConstraint\VersionConstraint;
7955 use Composer\Util\RemoteFilesystem;
7956 use Composer\Config;
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967 class PearRepository extends ArrayRepository
7968 {
7969 private $url;
7970 private $io;
7971 private $rfs;
7972 private $versionParser;
7973
7974
7975
7976
7977 private $vendorAlias;
7978
7979 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, RemoteFilesystem $rfs = null)
7980 {
7981 if (!preg_match('{^https?://}', $repoConfig['url'])) {
7982 $repoConfig['url'] = 'http://'.$repoConfig['url'];
7983 }
7984
7985 $urlBits = parse_url($repoConfig['url']);
7986 if (empty($urlBits['scheme']) || empty($urlBits['host'])) {
7987 throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$repoConfig['url']);
7988 }
7989
7990 $this->url = rtrim($repoConfig['url'], '/');
7991 $this->io = $io;
7992 $this->rfs = $rfs ?: new RemoteFilesystem($this->io, $config);
7993 $this->vendorAlias = isset($repoConfig['vendor-alias']) ? $repoConfig['vendor-alias'] : null;
7994 $this->versionParser = new VersionParser();
7995 }
7996
7997 protected function initialize()
7998 {
7999 parent::initialize();
8000
8001 $this->io->write('Initializing PEAR repository '.$this->url);
8002
8003 $reader = new ChannelReader($this->rfs);
8004 try {
8005 $channelInfo = $reader->read($this->url);
8006 } catch (\Exception $e) {
8007 $this->io->write('<warning>PEAR repository from '.$this->url.' could not be loaded. '.$e->getMessage().'</warning>');
8008
8009 return;
8010 }
8011 $packages = $this->buildComposerPackages($channelInfo, $this->versionParser);
8012 foreach ($packages as $package) {
8013 $this->addPackage($package);
8014 }
8015 }
8016
8017
8018
8019
8020
8021
8022
8023
8024 private function buildComposerPackages(ChannelInfo $channelInfo, VersionParser $versionParser)
8025 {
8026 $result = array();
8027 foreach ($channelInfo->getPackages() as $packageDefinition) {
8028 foreach ($packageDefinition->getReleases() as $version => $releaseInfo) {
8029 try {
8030 $normalizedVersion = $versionParser->normalize($version);
8031 } catch (\UnexpectedValueException $e) {
8032 if ($this->io->isVerbose()) {
8033 $this->io->write('Could not load '.$packageDefinition->getPackageName().' '.$version.': '.$e->getMessage());
8034 }
8035 continue;
8036 }
8037
8038 $composerPackageName = $this->buildComposerPackageName($packageDefinition->getChannelName(), $packageDefinition->getPackageName());
8039
8040
8041  
8042  $urlBits = parse_url($this->url);
8043 $scheme = (isset($urlBits['scheme']) && 'https' === $urlBits['scheme'] && extension_loaded('openssl')) ? 'https' : 'http';
8044 $distUrl = "{$scheme}://{$packageDefinition->getChannelName()}/get/{$packageDefinition->getPackageName()}-{$version}.tgz";
8045
8046 $requires = array();
8047 $suggests = array();
8048 $conflicts = array();
8049 $replaces = array();
8050
8051
8052  
8053  if ($channelInfo->getName() == $packageDefinition->getChannelName()) {
8054 $composerPackageAlias = $this->buildComposerPackageName($channelInfo->getAlias(), $packageDefinition->getPackageName());
8055 $aliasConstraint = new VersionConstraint('==', $normalizedVersion);
8056 $replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
8057 }
8058
8059
8060  if (!empty($this->vendorAlias)
8061 && ($this->vendorAlias != 'pear-'.$channelInfo->getAlias() || $channelInfo->getName() != $packageDefinition->getChannelName())
8062 ) {
8063 $composerPackageAlias = "{$this->vendorAlias}/{$packageDefinition->getPackageName()}";
8064 $aliasConstraint = new VersionConstraint('==', $normalizedVersion);
8065 $replaces[] = new Link($composerPackageName, $composerPackageAlias, $aliasConstraint, 'replaces', (string) $aliasConstraint);
8066 }
8067
8068 foreach ($releaseInfo->getDependencyInfo()->getRequires() as $dependencyConstraint) {
8069 $dependencyPackageName = $this->buildComposerPackageName($dependencyConstraint->getChannelName(), $dependencyConstraint->getPackageName());
8070 $constraint = $versionParser->parseConstraints($dependencyConstraint->getConstraint());
8071 $link = new Link($composerPackageName, $dependencyPackageName, $constraint, $dependencyConstraint->getType(), $dependencyConstraint->getConstraint());
8072 switch ($dependencyConstraint->getType()) {
8073 case 'required':
8074 $requires[] = $link;
8075 break;
8076 case 'conflicts':
8077 $conflicts[] = $link;
8078 break;
8079 case 'replaces':
8080 $replaces[] = $link;
8081 break;
8082 }
8083 }
8084
8085 foreach ($releaseInfo->getDependencyInfo()->getOptionals() as $group => $dependencyConstraints) {
8086 foreach ($dependencyConstraints as $dependencyConstraint) {
8087 $dependencyPackageName = $this->buildComposerPackageName($dependencyConstraint->getChannelName(), $dependencyConstraint->getPackageName());
8088 $suggests[$group.'-'.$dependencyPackageName] = $dependencyConstraint->getConstraint();
8089 }
8090 }
8091
8092 $package = new CompletePackage($composerPackageName, $normalizedVersion, $version);
8093 $package->setType('pear-library');
8094 $package->setDescription($packageDefinition->getDescription());
8095 $package->setLicense(array($packageDefinition->getLicense()));
8096 $package->setDistType('file');
8097 $package->setDistUrl($distUrl);
8098 $package->setAutoload(array('classmap' => array('')));
8099 $package->setIncludePaths(array('/'));
8100 $package->setRequires($requires);
8101 $package->setConflicts($conflicts);
8102 $package->setSuggests($suggests);
8103 $package->setReplaces($replaces);
8104 $result[] = $package;
8105 }
8106 }
8107
8108 return $result;
8109 }
8110
8111 private function buildComposerPackageName($channelName, $packageName)
8112 {
8113 if ('php' === $channelName) {
8114 return "php";
8115 }
8116 if ('ext' === $channelName) {
8117 return "ext-{$packageName}";
8118 }
8119
8120 return "pear-{$channelName}/{$packageName}";
8121 }
8122 }
8123 <?php
8124
8125
8126
8127
8128
8129
8130
8131
8132
8133
8134
8135 namespace Composer\Repository;
8136
8137 use Composer\IO\IOInterface;
8138 use Composer\Config;
8139 use Composer\EventDispatcher\EventDispatcher;
8140
8141
8142
8143
8144
8145
8146
8147
8148 class RepositoryManager
8149 {
8150 private $localRepository;
8151 private $repositories = array();
8152 private $repositoryClasses = array();
8153 private $io;
8154 private $config;
8155 private $eventDispatcher;
8156
8157 public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
8158 {
8159 $this->io = $io;
8160 $this->config = $config;
8161 $this->eventDispatcher = $eventDispatcher;
8162 }
8163
8164
8165
8166
8167
8168
8169
8170
8171
8172 public function findPackage($name, $version)
8173 {
8174 foreach ($this->repositories as $repository) {
8175 if ($package = $repository->findPackage($name, $version)) {
8176 return $package;
8177 }
8178 }
8179 }
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189 public function findPackages($name, $version)
8190 {
8191 $packages = array();
8192
8193 foreach ($this->repositories as $repository) {
8194 $packages = array_merge($packages, $repository->findPackages($name, $version));
8195 }
8196
8197 return $packages;
8198 }
8199
8200
8201
8202
8203
8204
8205 public function addRepository(RepositoryInterface $repository)
8206 {
8207 $this->repositories[] = $repository;
8208 }
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218 public function createRepository($type, $config)
8219 {
8220 if (!isset($this->repositoryClasses[$type])) {
8221 throw new \InvalidArgumentException('Repository type is not registered: '.$type);
8222 }
8223
8224 $class = $this->repositoryClasses[$type];
8225
8226 return new $class($config, $this->io, $this->config, $this->eventDispatcher);
8227 }
8228
8229
8230
8231
8232
8233
8234
8235 public function setRepositoryClass($type, $class)
8236 {
8237 $this->repositoryClasses[$type] = $class;
8238 }
8239
8240
8241
8242
8243
8244
8245 public function getRepositories()
8246 {
8247 return $this->repositories;
8248 }
8249
8250
8251
8252
8253
8254
8255 public function setLocalRepository(WritableRepositoryInterface $repository)
8256 {
8257 $this->localRepository = $repository;
8258 }
8259
8260
8261
8262
8263
8264
8265 public function getLocalRepository()
8266 {
8267 return $this->localRepository;
8268 }
8269
8270
8271
8272
8273
8274
8275
8276 public function getLocalRepositories()
8277 {
8278 trigger_error('This method is deprecated, use getLocalRepository instead since the getLocalDevRepository is now gone', E_USER_DEPRECATED);
8279
8280 return array($this->localRepository);
8281 }
8282 }
8283 <?php
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295 namespace Composer\Repository;
8296
8297 use Composer\Package\AliasPackage;
8298
8299
8300
8301
8302
8303
8304 class WritableArrayRepository extends ArrayRepository implements WritableRepositoryInterface
8305 {
8306
8307
8308
8309 public function write()
8310 {
8311 }
8312
8313
8314
8315
8316 public function reload()
8317 {
8318 }
8319
8320
8321
8322
8323 public function getCanonicalPackages()
8324 {
8325 $packages = $this->getPackages();
8326
8327
8328  $packagesByName = array();
8329 foreach ($packages as $package) {
8330 if (!isset($packagesByName[$package->getName()]) || $packagesByName[$package->getName()] instanceof AliasPackage) {
8331 $packagesByName[$package->getName()] = $package;
8332 }
8333 }
8334
8335 $canonicalPackages = array();
8336
8337
8338  foreach ($packagesByName as $package) {
8339 while ($package instanceof AliasPackage) {
8340 $package = $package->getAliasOf();
8341 }
8342
8343 $canonicalPackages[] = $package;
8344 }
8345
8346 return $canonicalPackages;
8347 }
8348 }
8349 <?php
8350
8351
8352
8353
8354
8355
8356
8357
8358
8359
8360
8361 namespace Composer\Repository\Vcs;
8362
8363 use Composer\Config;
8364 use Composer\Downloader\TransportException;
8365 use Composer\Json\JsonFile;
8366 use Composer\Cache;
8367 use Composer\IO\IOInterface;
8368 use Composer\Util\GitHub;
8369
8370
8371
8372
8373 class GitHubDriver extends VcsDriver
8374 {
8375 protected $cache;
8376 protected $owner;
8377 protected $repository;
8378 protected $tags;
8379 protected $branches;
8380 protected $rootIdentifier;
8381 protected $hasIssues;
8382 protected $infoCache = array();
8383 protected $isPrivate = false;
8384
8385
8386
8387
8388
8389
8390 protected $gitDriver;
8391
8392
8393
8394
8395 public function initialize()
8396 {
8397 preg_match('#^(?:(?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git|/)?$#', $this->url, $match);
8398 $this->owner = $match[3];
8399 $this->repository = $match[4];
8400 $this->originUrl = !empty($match[1]) ? $match[1] : $match[2];
8401 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
8402
8403 if (isset($this->repoConfig['no-api']) && $this->repoConfig['no-api']) {
8404 $this->setupGitDriver($this->url);
8405
8406 return;
8407 }
8408
8409 $this->fetchRootIdentifier();
8410 }
8411
8412 public function getRepositoryUrl()
8413 {
8414 return 'https://'.$this->originUrl.'/'.$this->owner.'/'.$this->repository;
8415 }
8416
8417
8418
8419
8420 public function getRootIdentifier()
8421 {
8422 if ($this->gitDriver) {
8423 return $this->gitDriver->getRootIdentifier();
8424 }
8425
8426 return $this->rootIdentifier;
8427 }
8428
8429
8430
8431
8432 public function getUrl()
8433 {
8434 if ($this->gitDriver) {
8435 return $this->gitDriver->getUrl();
8436 }
8437
8438 return 'https://' . $this->originUrl . '/'.$this->owner.'/'.$this->repository.'.git';
8439 }
8440
8441
8442
8443
8444 protected function getApiUrl()
8445 {
8446 if ('github.com' === $this->originUrl) {
8447 $apiUrl = 'api.github.com';
8448 } else {
8449 $apiUrl = $this->originUrl . '/api/v3';
8450 }
8451
8452 return 'https://' . $apiUrl;
8453 }
8454
8455
8456
8457
8458 public function getSource($identifier)
8459 {
8460 if ($this->gitDriver) {
8461 return $this->gitDriver->getSource($identifier);
8462 }
8463 if ($this->isPrivate) {
8464
8465  
8466  $url = $this->generateSshUrl();
8467 } else {
8468 $url = $this->getUrl();
8469 }
8470
8471 return array('type' => 'git', 'url' => $url, 'reference' => $identifier);
8472 }
8473
8474
8475
8476
8477 public function getDist($identifier)
8478 {
8479 $url = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/zipball/'.$identifier;
8480
8481 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
8482 }
8483
8484
8485
8486
8487 public function getComposerInformation($identifier)
8488 {
8489 if ($this->gitDriver) {
8490 return $this->gitDriver->getComposerInformation($identifier);
8491 }
8492
8493 if (preg_match('{[a-f0-9]{40}}i', $identifier) && $res = $this->cache->read($identifier)) {
8494 $this->infoCache[$identifier] = JsonFile::parseJson($res);
8495 }
8496
8497 if (!isset($this->infoCache[$identifier])) {
8498 $notFoundRetries = 2;
8499 while ($notFoundRetries) {
8500 try {
8501 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/contents/composer.json?ref='.urlencode($identifier);
8502 $composer = JsonFile::parseJson($this->getContents($resource));
8503 if (empty($composer['content']) || $composer['encoding'] !== 'base64' || !($composer = base64_decode($composer['content']))) {
8504 throw new \RuntimeException('Could not retrieve composer.json from '.$resource);
8505 }
8506 break;
8507 } catch (TransportException $e) {
8508 if (404 !== $e->getCode()) {
8509 throw $e;
8510 }
8511
8512
8513  
8514  $notFoundRetries--;
8515 $composer = false;
8516 }
8517 }
8518
8519 if ($composer) {
8520 $composer = JsonFile::parseJson($composer, $resource);
8521
8522 if (empty($composer['time'])) {
8523 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/commits/'.urlencode($identifier);
8524 $commit = JsonFile::parseJson($this->getContents($resource), $resource);
8525 $composer['time'] = $commit['commit']['committer']['date'];
8526 }
8527 if (!isset($composer['support']['source'])) {
8528 $label = array_search($identifier, $this->getTags()) ?: array_search($identifier, $this->getBranches()) ?: $identifier;
8529 $composer['support']['source'] = sprintf('https://%s/%s/%s/tree/%s', $this->originUrl, $this->owner, $this->repository, $label);
8530 }
8531 if (!isset($composer['support']['issues']) && $this->hasIssues) {
8532 $composer['support']['issues'] = sprintf('https://%s/%s/%s/issues', $this->originUrl, $this->owner, $this->repository);
8533 }
8534 }
8535
8536 if (preg_match('{[a-f0-9]{40}}i', $identifier)) {
8537 $this->cache->write($identifier, json_encode($composer));
8538 }
8539
8540 $this->infoCache[$identifier] = $composer;
8541 }
8542
8543 return $this->infoCache[$identifier];
8544 }
8545
8546
8547
8548
8549 public function getTags()
8550 {
8551 if ($this->gitDriver) {
8552 return $this->gitDriver->getTags();
8553 }
8554 if (null === $this->tags) {
8555 $this->tags = array();
8556 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/tags?per_page=100';
8557
8558 do {
8559 $tagsData = JsonFile::parseJson($this->getContents($resource), $resource);
8560 foreach ($tagsData as $tag) {
8561 $this->tags[$tag['name']] = $tag['commit']['sha'];
8562 }
8563
8564 $resource = $this->getNextPage();
8565 } while ($resource);
8566 }
8567
8568 return $this->tags;
8569 }
8570
8571
8572
8573
8574 public function getBranches()
8575 {
8576 if ($this->gitDriver) {
8577 return $this->gitDriver->getBranches();
8578 }
8579 if (null === $this->branches) {
8580 $this->branches = array();
8581 $resource = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository.'/git/refs/heads?per_page=100';
8582
8583 $branchBlacklist = array('gh-pages');
8584
8585 do {
8586 $branchData = JsonFile::parseJson($this->getContents($resource), $resource);
8587 foreach ($branchData as $branch) {
8588 $name = substr($branch['ref'], 11);
8589 if (!in_array($name, $branchBlacklist)) {
8590 $this->branches[$name] = $branch['object']['sha'];
8591 }
8592 }
8593
8594 $resource = $this->getNextPage();
8595 } while ($resource);
8596 }
8597
8598 return $this->branches;
8599 }
8600
8601
8602
8603
8604 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
8605 {
8606 if (!preg_match('#^((?:https?|git)://([^/]+)/|git@([^:]+):)([^/]+)/(.+?)(?:\.git|/)?$#', $url, $matches)) {
8607 return false;
8608 }
8609
8610 $originUrl = !empty($matches[2]) ? $matches[2] : $matches[3];
8611 if (!in_array($originUrl, $config->get('github-domains'))) {
8612 return false;
8613 }
8614
8615 if (!extension_loaded('openssl')) {
8616 if ($io->isVerbose()) {
8617 $io->write('Skipping GitHub driver for '.$url.' because the OpenSSL PHP extension is missing.');
8618 }
8619
8620 return false;
8621 }
8622
8623 return true;
8624 }
8625
8626
8627
8628
8629
8630
8631 protected function generateSshUrl()
8632 {
8633 return 'git@' . $this->originUrl . ':'.$this->owner.'/'.$this->repository.'.git';
8634 }
8635
8636
8637
8638
8639 protected function getContents($url, $fetchingRepoData = false)
8640 {
8641 try {
8642 return parent::getContents($url);
8643 } catch (TransportException $e) {
8644 $gitHubUtil = new GitHub($this->io, $this->config, $this->process, $this->remoteFilesystem);
8645
8646 switch ($e->getCode()) {
8647 case 401:
8648 case 404:
8649
8650  if (!$fetchingRepoData) {
8651 throw $e;
8652 }
8653
8654 if ($gitHubUtil->authorizeOAuth($this->originUrl)) {
8655 return parent::getContents($url);
8656 }
8657
8658 if (!$this->io->isInteractive()) {
8659 return $this->attemptCloneFallback();
8660 }
8661
8662 $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'Your GitHub credentials are required to fetch private repository metadata (<info>'.$this->url.'</info>)');
8663
8664 return parent::getContents($url);
8665
8666 case 403:
8667 if (!$this->io->hasAuthentication($this->originUrl) && $gitHubUtil->authorizeOAuth($this->originUrl)) {
8668 return parent::getContents($url);
8669 }
8670
8671 if (!$this->io->isInteractive() && $fetchingRepoData) {
8672 return $this->attemptCloneFallback();
8673 }
8674
8675 $rateLimited = false;
8676 foreach ($e->getHeaders() as $header) {
8677 if (preg_match('{^X-RateLimit-Remaining: *0$}i', trim($header))) {
8678 $rateLimited = true;
8679 }
8680 }
8681
8682 if (!$this->io->hasAuthentication($this->originUrl)) {
8683 if (!$this->io->isInteractive()) {
8684 $this->io->write('<error>GitHub API limit exhausted. Failed to get metadata for the '.$this->url.' repository, try running in interactive mode so that you can enter your GitHub credentials to increase the API limit</error>');
8685 throw $e;
8686 }
8687
8688 $gitHubUtil->authorizeOAuthInteractively($this->originUrl, 'API limit exhausted. Enter your GitHub credentials to get a larger API limit (<info>'.$this->url.'</info>)');
8689
8690 return parent::getContents($url);
8691 }
8692
8693 if ($rateLimited) {
8694 $rateLimit = $this->getRateLimit($e->getHeaders());
8695 $this->io->write(sprintf(
8696 '<error>GitHub API limit (%d calls/hr) is exhausted. You are already authorized so you have to wait until %s before doing more requests</error>',
8697 $rateLimit['limit'],
8698 $rateLimit['reset']
8699 ));
8700 }
8701
8702 throw $e;
8703
8704 default:
8705 throw $e;
8706 }
8707 }
8708 }
8709
8710
8711
8712
8713
8714
8715
8716
8717 protected function getRateLimit(array $headers)
8718 {
8719 $rateLimit = array(
8720 'limit' => '?',
8721 'reset' => '?',
8722 );
8723
8724 foreach ($headers as $header) {
8725 $header = trim($header);
8726 if (false === strpos($header, 'X-RateLimit-')) {
8727 continue;
8728 }
8729 list($type, $value) = explode(':', $header, 2);
8730 switch ($type) {
8731 case 'X-RateLimit-Limit':
8732 $rateLimit['limit'] = (int) trim($value);
8733 break;
8734 case 'X-RateLimit-Reset':
8735 $rateLimit['reset'] = date('Y-m-d H:i:s', (int) trim($value));
8736 break;
8737 }
8738 }
8739
8740 return $rateLimit;
8741 }
8742
8743
8744
8745
8746
8747
8748 protected function fetchRootIdentifier()
8749 {
8750 $repoDataUrl = $this->getApiUrl() . '/repos/'.$this->owner.'/'.$this->repository;
8751
8752 $repoData = JsonFile::parseJson($this->getContents($repoDataUrl, true), $repoDataUrl);
8753 if (null === $repoData && null !== $this->gitDriver) {
8754 return;
8755 }
8756
8757 $this->owner = $repoData['owner']['login'];
8758 $this->repository = $repoData['name'];
8759
8760 $this->isPrivate = !empty($repoData['private']);
8761 if (isset($repoData['default_branch'])) {
8762 $this->rootIdentifier = $repoData['default_branch'];
8763 } elseif (isset($repoData['master_branch'])) {
8764 $this->rootIdentifier = $repoData['master_branch'];
8765 } else {
8766 $this->rootIdentifier = 'master';
8767 }
8768 $this->hasIssues = !empty($repoData['has_issues']);
8769 }
8770
8771 protected function attemptCloneFallback()
8772 {
8773 $this->isPrivate = true;
8774
8775 try {
8776
8777  
8778  
8779  
8780  $this->setupGitDriver($this->generateSshUrl());
8781
8782 return;
8783 } catch (\RuntimeException $e) {
8784 $this->gitDriver = null;
8785
8786 $this->io->write('<error>Failed to clone the '.$this->generateSshUrl().' repository, try running in interactive mode so that you can enter your GitHub credentials</error>');
8787 throw $e;
8788 }
8789 }
8790
8791 protected function setupGitDriver($url)
8792 {
8793 $this->gitDriver = new GitDriver(
8794 array('url' => $url),
8795 $this->io,
8796 $this->config,
8797 $this->process,
8798 $this->remoteFilesystem
8799 );
8800 $this->gitDriver->initialize();
8801 }
8802
8803 protected function getNextPage()
8804 {
8805 $headers = $this->remoteFilesystem->getLastHeaders();
8806 foreach ($headers as $header) {
8807 if (substr($header, 0, 5) === 'Link:') {
8808 $links = explode(',', substr($header, 5));
8809 foreach ($links as $link) {
8810 if (preg_match('{<(.+?)>; *rel="next"}', $link, $match)) {
8811 return $match[1];
8812 }
8813 }
8814 }
8815 }
8816 }
8817 }
8818 <?php
8819
8820
8821
8822
8823
8824
8825
8826
8827
8828
8829
8830 namespace Composer\Repository\Vcs;
8831
8832 use Composer\Config;
8833 use Composer\Json\JsonFile;
8834 use Composer\IO\IOInterface;
8835
8836
8837
8838
8839 class GitBitbucketDriver extends VcsDriver implements VcsDriverInterface
8840 {
8841 protected $owner;
8842 protected $repository;
8843 protected $tags;
8844 protected $branches;
8845 protected $rootIdentifier;
8846 protected $infoCache = array();
8847
8848
8849
8850
8851 public function initialize()
8852 {
8853 preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $this->url, $match);
8854 $this->owner = $match[1];
8855 $this->repository = $match[2];
8856 $this->originUrl = 'bitbucket.org';
8857 }
8858
8859
8860
8861
8862 public function getRootIdentifier()
8863 {
8864 if (null === $this->rootIdentifier) {
8865 $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository;
8866 $repoData = JsonFile::parseJson($this->getContents($resource), $resource);
8867 $this->rootIdentifier = !empty($repoData['main_branch']) ? $repoData['main_branch'] : 'master';
8868 }
8869
8870 return $this->rootIdentifier;
8871 }
8872
8873
8874
8875
8876 public function getUrl()
8877 {
8878 return $this->url;
8879 }
8880
8881
8882
8883
8884 public function getSource($identifier)
8885 {
8886 return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $identifier);
8887 }
8888
8889
8890
8891
8892 public function getDist($identifier)
8893 {
8894 $url = $this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/get/'.$identifier.'.zip';
8895
8896 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
8897 }
8898
8899
8900
8901
8902 public function getComposerInformation($identifier)
8903 {
8904 if (!isset($this->infoCache[$identifier])) {
8905 $resource = $this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json';
8906 $composer = $this->getContents($resource);
8907 if (!$composer) {
8908 return;
8909 }
8910
8911 $composer = JsonFile::parseJson($composer, $resource);
8912
8913 if (empty($composer['time'])) {
8914 $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier;
8915 $changeset = JsonFile::parseJson($this->getContents($resource), $resource);
8916 $composer['time'] = $changeset['timestamp'];
8917 }
8918 $this->infoCache[$identifier] = $composer;
8919 }
8920
8921 return $this->infoCache[$identifier];
8922 }
8923
8924
8925
8926
8927 public function getTags()
8928 {
8929 if (null === $this->tags) {
8930 $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags';
8931 $tagsData = JsonFile::parseJson($this->getContents($resource), $resource);
8932 $this->tags = array();
8933 foreach ($tagsData as $tag => $data) {
8934 $this->tags[$tag] = $data['raw_node'];
8935 }
8936 }
8937
8938 return $this->tags;
8939 }
8940
8941
8942
8943
8944 public function getBranches()
8945 {
8946 if (null === $this->branches) {
8947 $resource = $this->getScheme() . '://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches';
8948 $branchData = JsonFile::parseJson($this->getContents($resource), $resource);
8949 $this->branches = array();
8950 foreach ($branchData as $branch => $data) {
8951 $this->branches[$branch] = $data['raw_node'];
8952 }
8953 }
8954
8955 return $this->branches;
8956 }
8957
8958
8959
8960
8961 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
8962 {
8963 if (!preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url)) {
8964 return false;
8965 }
8966
8967 if (!extension_loaded('openssl')) {
8968 if ($io->isVerbose()) {
8969 $io->write('Skipping Bitbucket git driver for '.$url.' because the OpenSSL PHP extension is missing.');
8970 }
8971
8972 return false;
8973 }
8974
8975 return true;
8976 }
8977 }
8978 <?php
8979
8980
8981
8982
8983
8984
8985
8986
8987
8988
8989
8990 namespace Composer\Repository\Vcs;
8991
8992 use Composer\Json\JsonFile;
8993 use Composer\Util\ProcessExecutor;
8994 use Composer\Util\Filesystem;
8995 use Composer\Util\Git as GitUtil;
8996 use Composer\IO\IOInterface;
8997 use Composer\Cache;
8998 use Composer\Config;
8999
9000
9001
9002
9003 class GitDriver extends VcsDriver
9004 {
9005 protected $cache;
9006 protected $tags;
9007 protected $branches;
9008 protected $rootIdentifier;
9009 protected $repoDir;
9010 protected $infoCache = array();
9011
9012
9013
9014
9015 public function initialize()
9016 {
9017 if (Filesystem::isLocalPath($this->url)) {
9018 $this->repoDir = $this->url;
9019 $cacheUrl = realpath($this->url);
9020 } else {
9021 $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
9022
9023 GitUtil::cleanEnv();
9024
9025 $fs = new Filesystem();
9026 $fs->ensureDirectoryExists(dirname($this->repoDir));
9027
9028 if (!is_writable(dirname($this->repoDir))) {
9029 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.');
9030 }
9031
9032 if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) {
9033 throw new \InvalidArgumentException('The source URL '.$this->url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
9034 }
9035
9036 $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs);
9037
9038
9039  if (is_dir($this->repoDir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $this->repoDir) && trim($output) === '.') {
9040 try {
9041 $commandCallable = function ($url) {
9042 return sprintf('git remote set-url origin %s && git remote update --prune origin', ProcessExecutor::escape($url));
9043 };
9044 $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir);
9045 } catch (\Exception $e) {
9046 $this->io->write('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$e->getMessage().')</error>');
9047 }
9048 } else {
9049
9050  $fs->removeDirectory($this->repoDir);
9051
9052 $repoDir = $this->repoDir;
9053 $commandCallable = function ($url) use ($repoDir) {
9054 return sprintf('git clone --mirror %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir));
9055 };
9056
9057 $gitUtil->runCommand($commandCallable, $this->url, $this->repoDir, true);
9058 }
9059
9060 $cacheUrl = $this->url;
9061 }
9062
9063 $this->getTags();
9064 $this->getBranches();
9065
9066 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
9067 }
9068
9069
9070
9071
9072 public function getRootIdentifier()
9073 {
9074 if (null === $this->rootIdentifier) {
9075 $this->rootIdentifier = 'master';
9076
9077
9078  $this->process->execute('git branch --no-color', $output, $this->repoDir);
9079 $branches = $this->process->splitLines($output);
9080 if (!in_array('* master', $branches)) {
9081 foreach ($branches as $branch) {
9082 if ($branch && preg_match('{^\* +(\S+)}', $branch, $match)) {
9083 $this->rootIdentifier = $match[1];
9084 break;
9085 }
9086 }
9087 }
9088 }
9089
9090 return $this->rootIdentifier;
9091 }
9092
9093
9094
9095
9096 public function getUrl()
9097 {
9098 return $this->url;
9099 }
9100
9101
9102
9103
9104 public function getSource($identifier)
9105 {
9106 return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $identifier);
9107 }
9108
9109
9110
9111
9112 public function getDist($identifier)
9113 {
9114 return null;
9115 }
9116
9117
9118
9119
9120 public function getComposerInformation($identifier)
9121 {
9122 if (preg_match('{[a-f0-9]{40}}i', $identifier) && $res = $this->cache->read($identifier)) {
9123 $this->infoCache[$identifier] = JsonFile::parseJson($res);
9124 }
9125
9126 if (!isset($this->infoCache[$identifier])) {
9127 $resource = sprintf('%s:composer.json', ProcessExecutor::escape($identifier));
9128 $this->process->execute(sprintf('git show %s', $resource), $composer, $this->repoDir);
9129
9130 if (!trim($composer)) {
9131 return;
9132 }
9133
9134 $composer = JsonFile::parseJson($composer, $resource);
9135
9136 if (empty($composer['time'])) {
9137 $this->process->execute(sprintf('git log -1 --format=%%at %s', ProcessExecutor::escape($identifier)), $output, $this->repoDir);
9138 $date = new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
9139 $composer['time'] = $date->format('Y-m-d H:i:s');
9140 }
9141
9142 if (preg_match('{[a-f0-9]{40}}i', $identifier)) {
9143 $this->cache->write($identifier, json_encode($composer));
9144 }
9145
9146 $this->infoCache[$identifier] = $composer;
9147 }
9148
9149 return $this->infoCache[$identifier];
9150 }
9151
9152
9153
9154
9155 public function getTags()
9156 {
9157 if (null === $this->tags) {
9158 $this->tags = array();
9159
9160 $this->process->execute('git show-ref --tags', $output, $this->repoDir);
9161 foreach ($output = $this->process->splitLines($output) as $tag) {
9162 if ($tag && preg_match('{^([a-f0-9]{40}) refs/tags/(\S+)$}', $tag, $match)) {
9163 $this->tags[$match[2]] = $match[1];
9164 }
9165 }
9166 }
9167
9168 return $this->tags;
9169 }
9170
9171
9172
9173
9174 public function getBranches()
9175 {
9176 if (null === $this->branches) {
9177 $branches = array();
9178
9179 $this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir);
9180 foreach ($this->process->splitLines($output) as $branch) {
9181 if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
9182 if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match)) {
9183 $branches[$match[1]] = $match[2];
9184 }
9185 }
9186 }
9187
9188 $this->branches = $branches;
9189 }
9190
9191 return $this->branches;
9192 }
9193
9194
9195
9196
9197 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
9198 {
9199 if (preg_match('#(^git://|\.git$|git(?:olite)?@|//git\.|//github.com/)#i', $url)) {
9200 return true;
9201 }
9202
9203
9204  if (Filesystem::isLocalPath($url)) {
9205 $url = Filesystem::getPlatformPath($url);
9206 if (!is_dir($url)) {
9207 return false;
9208 }
9209
9210 $process = new ProcessExecutor($io);
9211
9212  if ($process->execute('git tag', $output, $url) === 0) {
9213 return true;
9214 }
9215 }
9216
9217 if (!$deep) {
9218 return false;
9219 }
9220
9221
9222  return false;
9223 }
9224 }
9225 <?php
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235
9236
9237 namespace Composer\Repository\Vcs;
9238
9239 use Composer\Config;
9240 use Composer\IO\IOInterface;
9241 use Composer\Util\ProcessExecutor;
9242 use Composer\Util\Perforce;
9243
9244
9245
9246
9247 class PerforceDriver extends VcsDriver
9248 {
9249 protected $depot;
9250 protected $branch;
9251 protected $perforce;
9252 protected $composerInfo;
9253 protected $composerInfoIdentifier;
9254
9255
9256
9257
9258 public function initialize()
9259 {
9260 $this->depot = $this->repoConfig['depot'];
9261 $this->branch = '';
9262 if (!empty($this->repoConfig['branch'])) {
9263 $this->branch = $this->repoConfig['branch'];
9264 }
9265
9266 $this->initPerforce($this->repoConfig);
9267 $this->perforce->p4Login($this->io);
9268 $this->perforce->checkStream($this->depot);
9269
9270 $this->perforce->writeP4ClientSpec();
9271 $this->perforce->connectClient();
9272
9273 return true;
9274 }
9275
9276 private function initPerforce($repoConfig)
9277 {
9278 if (!empty($this->perforce)) {
9279 return;
9280 }
9281
9282 $repoDir = $this->config->get('cache-vcs-dir') . '/' . $this->depot;
9283 $this->perforce = Perforce::create($repoConfig, $this->getUrl(), $repoDir, $this->process, $this->io);
9284 }
9285
9286
9287
9288
9289 public function getComposerInformation($identifier)
9290 {
9291 if (!empty($this->composerInfoIdentifier)) {
9292 if (strcmp($identifier, $this->composerInfoIdentifier) === 0) {
9293 return $this->composerInfo;
9294 }
9295 }
9296 $composer_info = $this->perforce->getComposerInformation($identifier);
9297
9298 return $composer_info;
9299 }
9300
9301
9302
9303
9304 public function getRootIdentifier()
9305 {
9306 return $this->branch;
9307 }
9308
9309
9310
9311
9312 public function getBranches()
9313 {
9314 $branches = $this->perforce->getBranches();
9315
9316 return $branches;
9317 }
9318
9319
9320
9321
9322 public function getTags()
9323 {
9324 $tags = $this->perforce->getTags();
9325
9326 return $tags;
9327 }
9328
9329
9330
9331
9332 public function getDist($identifier)
9333 {
9334 return null;
9335 }
9336
9337
9338
9339
9340 public function getSource($identifier)
9341 {
9342 $source = array(
9343 'type' => 'perforce',
9344 'url' => $this->repoConfig['url'],
9345 'reference' => $identifier,
9346 'p4user' => $this->perforce->getUser()
9347 );
9348
9349 return $source;
9350 }
9351
9352
9353
9354
9355 public function getUrl()
9356 {
9357 return $this->url;
9358 }
9359
9360
9361
9362
9363 public function hasComposerFile($identifier)
9364 {
9365 $this->composerInfo = $this->perforce->getComposerInformation('//' . $this->depot . '/' . $identifier);
9366 $this->composerInfoIdentifier = $identifier;
9367
9368 return !empty($this->composerInfo);
9369 }
9370
9371
9372
9373
9374 public function getContents($url)
9375 {
9376 return false;
9377 }
9378
9379
9380
9381
9382 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
9383 {
9384 if ($deep || preg_match('#\b(perforce|p4)\b#i', $url)) {
9385 return Perforce::checkServerExists($url, new ProcessExecutor($io));
9386 }
9387
9388 return false;
9389 }
9390
9391
9392
9393
9394 public function cleanup()
9395 {
9396 $this->perforce->cleanupClientSpec();
9397 $this->perforce = null;
9398 }
9399
9400 public function getDepot()
9401 {
9402 return $this->depot;
9403 }
9404
9405 public function getBranch()
9406 {
9407 return $this->branch;
9408 }
9409 }
9410 <?php
9411
9412
9413
9414
9415
9416
9417
9418
9419
9420
9421
9422 namespace Composer\Repository\Vcs;
9423
9424 use Composer\Cache;
9425 use Composer\Config;
9426 use Composer\Json\JsonFile;
9427 use Composer\Util\ProcessExecutor;
9428 use Composer\Util\Filesystem;
9429 use Composer\Util\Svn as SvnUtil;
9430 use Composer\IO\IOInterface;
9431 use Composer\Downloader\TransportException;
9432
9433
9434
9435
9436
9437 class SvnDriver extends VcsDriver
9438 {
9439
9440
9441
9442 protected $cache;
9443 protected $baseUrl;
9444 protected $tags;
9445 protected $branches;
9446 protected $rootIdentifier;
9447 protected $infoCache = array();
9448
9449 protected $trunkPath = 'trunk';
9450 protected $branchesPath = 'branches';
9451 protected $tagsPath = 'tags';
9452 protected $packagePath = '';
9453 protected $cacheCredentials = true;
9454
9455
9456
9457
9458 private $util;
9459
9460
9461
9462
9463 public function initialize()
9464 {
9465 $this->url = $this->baseUrl = rtrim(self::normalizeUrl($this->url), '/');
9466
9467 SvnUtil::cleanEnv();
9468
9469 if (isset($this->repoConfig['trunk-path'])) {
9470 $this->trunkPath = $this->repoConfig['trunk-path'];
9471 }
9472 if (isset($this->repoConfig['branches-path'])) {
9473 $this->branchesPath = $this->repoConfig['branches-path'];
9474 }
9475 if (isset($this->repoConfig['tags-path'])) {
9476 $this->tagsPath = $this->repoConfig['tags-path'];
9477 }
9478 if (array_key_exists('svn-cache-credentials', $this->repoConfig)) {
9479 $this->cacheCredentials = (bool) $this->repoConfig['svn-cache-credentials'];
9480 }
9481 if (isset($this->repoConfig['package-path'])) {
9482 $this->packagePath = '/' . trim($this->repoConfig['package-path'], '/');
9483 }
9484
9485 if (false !== ($pos = strrpos($this->url, '/' . $this->trunkPath))) {
9486 $this->baseUrl = substr($this->url, 0, $pos);
9487 }
9488
9489 $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->baseUrl));
9490
9491 $this->getBranches();
9492 $this->getTags();
9493 }
9494
9495
9496
9497
9498 public function getRootIdentifier()
9499 {
9500 return $this->rootIdentifier ?: $this->trunkPath;
9501 }
9502
9503
9504
9505
9506 public function getUrl()
9507 {
9508 return $this->url;
9509 }
9510
9511
9512
9513
9514 public function getSource($identifier)
9515 {
9516 return array('type' => 'svn', 'url' => $this->baseUrl, 'reference' => $identifier);
9517 }
9518
9519
9520
9521
9522 public function getDist($identifier)
9523 {
9524 return null;
9525 }
9526
9527
9528
9529
9530 public function getComposerInformation($identifier)
9531 {
9532 $identifier = '/' . trim($identifier, '/') . '/';
9533
9534 if ($res = $this->cache->read($identifier.'.json')) {
9535 $this->infoCache[$identifier] = JsonFile::parseJson($res);
9536 }
9537
9538 if (!isset($this->infoCache[$identifier])) {
9539 preg_match('{^(.+?)(@\d+)?/$}', $identifier, $match);
9540 if (!empty($match[2])) {
9541 $path = $match[1];
9542 $rev = $match[2];
9543 } else {
9544 $path = $identifier;
9545 $rev = '';
9546 }
9547
9548 try {
9549 $resource = $path.'composer.json';
9550 $output = $this->execute('svn cat', $this->baseUrl . $resource . $rev);
9551 if (!trim($output)) {
9552 return;
9553 }
9554 } catch (\RuntimeException $e) {
9555 throw new TransportException($e->getMessage());
9556 }
9557
9558 $composer = JsonFile::parseJson($output, $this->baseUrl . $resource . $rev);
9559
9560 if (empty($composer['time'])) {
9561 $output = $this->execute('svn info', $this->baseUrl . $path . $rev);
9562 foreach ($this->process->splitLines($output) as $line) {
9563 if ($line && preg_match('{^Last Changed Date: ([^(]+)}', $line, $match)) {
9564 $date = new \DateTime($match[1], new \DateTimeZone('UTC'));
9565 $composer['time'] = $date->format('Y-m-d H:i:s');
9566 break;
9567 }
9568 }
9569 }
9570
9571 $this->cache->write($identifier.'.json', json_encode($composer));
9572 $this->infoCache[$identifier] = $composer;
9573 }
9574
9575 return $this->infoCache[$identifier];
9576 }
9577
9578
9579
9580
9581 public function getTags()
9582 {
9583 if (null === $this->tags) {
9584 $this->tags = array();
9585
9586 if ($this->tagsPath !== false) {
9587 $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->tagsPath);
9588 if ($output) {
9589 foreach ($this->process->splitLines($output) as $line) {
9590 $line = trim($line);
9591 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
9592 if (isset($match[1]) && isset($match[2]) && $match[2] !== './') {
9593 $this->tags[rtrim($match[2], '/')] = $this->buildIdentifier(
9594 '/' . $this->tagsPath . '/' . $match[2],
9595 $match[1]
9596 );
9597 }
9598 }
9599 }
9600 }
9601 }
9602 }
9603
9604 return $this->tags;
9605 }
9606
9607
9608
9609
9610 public function getBranches()
9611 {
9612 if (null === $this->branches) {
9613 $this->branches = array();
9614
9615 if (false === $this->trunkPath) {
9616 $trunkParent = $this->baseUrl . '/';
9617 } else {
9618 $trunkParent = $this->baseUrl . '/' . $this->trunkPath;
9619 }
9620
9621 $output = $this->execute('svn ls --verbose', $trunkParent);
9622 if ($output) {
9623 foreach ($this->process->splitLines($output) as $line) {
9624 $line = trim($line);
9625 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
9626 if (isset($match[1]) && isset($match[2]) && $match[2] === './') {
9627 $this->branches['trunk'] = $this->buildIdentifier(
9628 '/' . $this->trunkPath,
9629 $match[1]
9630 );
9631 $this->rootIdentifier = $this->branches['trunk'];
9632 break;
9633 }
9634 }
9635 }
9636 }
9637 unset($output);
9638
9639 if ($this->branchesPath !== false) {
9640 $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->branchesPath);
9641 if ($output) {
9642 foreach ($this->process->splitLines(trim($output)) as $line) {
9643 $line = trim($line);
9644 if ($line && preg_match('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) {
9645 if (isset($match[1]) && isset($match[2]) && $match[2] !== './') {
9646 $this->branches[rtrim($match[2], '/')] = $this->buildIdentifier(
9647 '/' . $this->branchesPath . '/' . $match[2],
9648 $match[1]
9649 );
9650 }
9651 }
9652 }
9653 }
9654 }
9655 }
9656
9657 return $this->branches;
9658 }
9659
9660
9661
9662
9663 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
9664 {
9665 $url = self::normalizeUrl($url);
9666 if (preg_match('#(^svn://|^svn\+ssh://|svn\.)#i', $url)) {
9667 return true;
9668 }
9669
9670
9671  if (!$deep && !Filesystem::isLocalPath($url)) {
9672 return false;
9673 }
9674
9675 $processExecutor = new ProcessExecutor();
9676
9677 $exit = $processExecutor->execute(
9678 "svn info --non-interactive {$url}",
9679 $ignoredOutput
9680 );
9681
9682 if ($exit === 0) {
9683
9684  return true;
9685 }
9686
9687 if (false !== stripos($processExecutor->getErrorOutput(), 'authorization failed:')) {
9688
9689  
9690  return true;
9691 }
9692
9693 return false;
9694 }
9695
9696
9697
9698
9699
9700
9701
9702
9703 protected static function normalizeUrl($url)
9704 {
9705 $fs = new Filesystem();
9706 if ($fs->isAbsolutePath($url)) {
9707 return 'file://' . strtr($url, '\\', '/');
9708 }
9709
9710 return $url;
9711 }
9712
9713
9714
9715
9716
9717
9718
9719
9720
9721
9722 protected function execute($command, $url)
9723 {
9724 if (null === $this->util) {
9725 $this->util = new SvnUtil($this->baseUrl, $this->io, $this->config, $this->process);
9726 $this->util->setCacheCredentials($this->cacheCredentials);
9727 }
9728
9729 try {
9730 return $this->util->execute($command, $url);
9731 } catch (\RuntimeException $e) {
9732 if (0 !== $this->process->execute('svn --version', $ignoredOutput)) {
9733 throw new \RuntimeException('Failed to load '.$this->url.', svn was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput());
9734 }
9735
9736 throw new \RuntimeException(
9737 'Repository '.$this->url.' could not be processed, '.$e->getMessage()
9738 );
9739 }
9740 }
9741
9742
9743
9744
9745
9746
9747
9748
9749
9750 protected function buildIdentifier($baseDir, $revision)
9751 {
9752 return rtrim($baseDir, '/') . $this->packagePath . '/@' . $revision;
9753 }
9754 }
9755 <?php
9756
9757
9758
9759
9760
9761
9762
9763
9764
9765
9766
9767 namespace Composer\Repository\Vcs;
9768
9769 use Composer\Config;
9770 use Composer\IO\IOInterface;
9771
9772
9773
9774
9775 interface VcsDriverInterface
9776 {
9777
9778
9779
9780 public function initialize();
9781
9782
9783
9784
9785
9786
9787
9788 public function getComposerInformation($identifier);
9789
9790
9791
9792
9793
9794
9795 public function getRootIdentifier();
9796
9797
9798
9799
9800
9801
9802 public function getBranches();
9803
9804
9805
9806
9807
9808
9809 public function getTags();
9810
9811
9812
9813
9814
9815 public function getDist($identifier);
9816
9817
9818
9819
9820
9821 public function getSource($identifier);
9822
9823
9824
9825
9826
9827
9828 public function getUrl();
9829
9830
9831
9832
9833
9834
9835
9836
9837 public function hasComposerFile($identifier);
9838
9839
9840
9841
9842
9843 public function cleanup();
9844
9845
9846
9847
9848
9849
9850
9851
9852
9853
9854 public static function supports(IOInterface $io, Config $config, $url, $deep = false);
9855 }
9856 <?php
9857
9858
9859
9860
9861
9862
9863
9864
9865
9866
9867
9868 namespace Composer\Repository\Vcs;
9869
9870 use Composer\Config;
9871 use Composer\Json\JsonFile;
9872 use Composer\Util\ProcessExecutor;
9873 use Composer\Util\Filesystem;
9874 use Composer\IO\IOInterface;
9875
9876
9877
9878
9879 class HgDriver extends VcsDriver
9880 {
9881 protected $tags;
9882 protected $branches;
9883 protected $rootIdentifier;
9884 protected $repoDir;
9885 protected $infoCache = array();
9886
9887
9888
9889
9890 public function initialize()
9891 {
9892 if (Filesystem::isLocalPath($this->url)) {
9893 $this->repoDir = $this->url;
9894 } else {
9895 $cacheDir = $this->config->get('cache-vcs-dir');
9896 $this->repoDir = $cacheDir . '/' . preg_replace('{[^a-z0-9]}i', '-', $this->url) . '/';
9897
9898 $fs = new Filesystem();
9899 $fs->ensureDirectoryExists($cacheDir);
9900
9901 if (!is_writable(dirname($this->repoDir))) {
9902 throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.$cacheDir.'" directory is not writable by the current user.');
9903 }
9904
9905
9906  if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) {
9907 if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) {
9908 $this->io->write('<error>Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')</error>');
9909 }
9910 } else {
9911
9912  $fs->removeDirectory($this->repoDir);
9913
9914 if (0 !== $this->process->execute(sprintf('hg clone --noupdate %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoDir)), $output, $cacheDir)) {
9915 $output = $this->process->getErrorOutput();
9916
9917 if (0 !== $this->process->execute('hg --version', $ignoredOutput)) {
9918 throw new \RuntimeException('Failed to clone '.$this->url.', hg was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput());
9919 }
9920
9921 throw new \RuntimeException('Failed to clone '.$this->url.', could not read packages from it' . "\n\n" .$output);
9922 }
9923 }
9924 }
9925
9926 $this->getTags();
9927 $this->getBranches();
9928 }
9929
9930
9931
9932
9933 public function getRootIdentifier()
9934 {
9935 if (null === $this->rootIdentifier) {
9936 $this->process->execute(sprintf('hg tip --template "{node}"'), $output, $this->repoDir);
9937 $output = $this->process->splitLines($output);
9938 $this->rootIdentifier = $output[0];
9939 }
9940
9941 return $this->rootIdentifier;
9942 }
9943
9944
9945
9946
9947 public function getUrl()
9948 {
9949 return $this->url;
9950 }
9951
9952
9953
9954
9955 public function getSource($identifier)
9956 {
9957 return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $identifier);
9958 }
9959
9960
9961
9962
9963 public function getDist($identifier)
9964 {
9965 return null;
9966 }
9967
9968
9969
9970
9971 public function getComposerInformation($identifier)
9972 {
9973 if (!isset($this->infoCache[$identifier])) {
9974 $this->process->execute(sprintf('hg cat -r %s composer.json', ProcessExecutor::escape($identifier)), $composer, $this->repoDir);
9975
9976 if (!trim($composer)) {
9977 return;
9978 }
9979
9980 $composer = JsonFile::parseJson($composer, $identifier);
9981
9982 if (empty($composer['time'])) {
9983 $this->process->execute(sprintf('hg log --template "{date|rfc3339date}" -r %s', ProcessExecutor::escape($identifier)), $output, $this->repoDir);
9984 $date = new \DateTime(trim($output), new \DateTimeZone('UTC'));
9985 $composer['time'] = $date->format('Y-m-d H:i:s');
9986 }
9987 $this->infoCache[$identifier] = $composer;
9988 }
9989
9990 return $this->infoCache[$identifier];
9991 }
9992
9993
9994
9995
9996 public function getTags()
9997 {
9998 if (null === $this->tags) {
9999 $tags = array();
10000
10001 $this->process->execute('hg tags', $output, $this->repoDir);
10002 foreach ($this->process->splitLines($output) as $tag) {
10003 if ($tag && preg_match('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) {
10004 $tags[$match[1]] = $match[2];
10005 }
10006 }
10007 unset($tags['tip']);
10008
10009 $this->tags = $tags;
10010 }
10011
10012 return $this->tags;
10013 }
10014
10015
10016
10017
10018 public function getBranches()
10019 {
10020 if (null === $this->branches) {
10021 $branches = array();
10022 $bookmarks = array();
10023
10024 $this->process->execute('hg branches', $output, $this->repoDir);
10025 foreach ($this->process->splitLines($output) as $branch) {
10026 if ($branch && preg_match('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match)) {
10027 $branches[$match[1]] = $match[2];
10028 }
10029 }
10030
10031 $this->process->execute('hg bookmarks', $output, $this->repoDir);
10032 foreach ($this->process->splitLines($output) as $branch) {
10033 if ($branch && preg_match('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match)) {
10034 $bookmarks[$match[1]] = $match[2];
10035 }
10036 }
10037
10038
10039  $this->branches = array_merge($bookmarks, $branches);
10040 }
10041
10042 return $this->branches;
10043 }
10044
10045
10046
10047
10048 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
10049 {
10050 if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) {
10051 return true;
10052 }
10053
10054
10055  if (Filesystem::isLocalPath($url)) {
10056 $url = Filesystem::getPlatformPath($url);
10057 if (!is_dir($url)) {
10058 return false;
10059 }
10060
10061 $process = new ProcessExecutor();
10062
10063  if ($process->execute('hg summary', $output, $url) === 0) {
10064 return true;
10065 }
10066 }
10067
10068 if (!$deep) {
10069 return false;
10070 }
10071
10072 $processExecutor = new ProcessExecutor();
10073 $exit = $processExecutor->execute(sprintf('hg identify %s', ProcessExecutor::escape($url)), $ignored);
10074
10075 return $exit === 0;
10076 }
10077 }
10078 <?php
10079
10080
10081
10082
10083
10084
10085
10086
10087
10088
10089
10090 namespace Composer\Repository\Vcs;
10091
10092 use Composer\Downloader\TransportException;
10093 use Composer\Config;
10094 use Composer\IO\IOInterface;
10095 use Composer\Util\ProcessExecutor;
10096 use Composer\Util\RemoteFilesystem;
10097 use Composer\Util\Filesystem;
10098
10099
10100
10101
10102
10103
10104 abstract class VcsDriver implements VcsDriverInterface
10105 {
10106 protected $url;
10107 protected $originUrl;
10108 protected $repoConfig;
10109 protected $io;
10110 protected $config;
10111 protected $process;
10112 protected $remoteFilesystem;
10113
10114
10115
10116
10117
10118
10119
10120
10121
10122
10123 final public function __construct(array $repoConfig, IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
10124 {
10125 if (Filesystem::isLocalPath($repoConfig['url'])) {
10126 $repoConfig['url'] = Filesystem::getPlatformPath($repoConfig['url']);
10127 }
10128
10129 $this->url = $repoConfig['url'];
10130 $this->originUrl = $repoConfig['url'];
10131 $this->repoConfig = $repoConfig;
10132 $this->io = $io;
10133 $this->config = $config;
10134 $this->process = $process ?: new ProcessExecutor($io);
10135 $this->remoteFilesystem = $remoteFilesystem ?: new RemoteFilesystem($io, $config);
10136 }
10137
10138
10139
10140
10141 public function hasComposerFile($identifier)
10142 {
10143 try {
10144 return (bool) $this->getComposerInformation($identifier);
10145 } catch (TransportException $e) {
10146 }
10147
10148 return false;
10149 }
10150
10151
10152
10153
10154
10155
10156
10157
10158 protected function getScheme()
10159 {
10160 if (extension_loaded('openssl')) {
10161 return 'https';
10162 }
10163
10164 return 'http';
10165 }
10166
10167
10168
10169
10170
10171
10172
10173
10174 protected function getContents($url)
10175 {
10176 return $this->remoteFilesystem->getContents($this->originUrl, $url, false);
10177 }
10178
10179
10180
10181
10182 public function cleanup()
10183 {
10184 return;
10185 }
10186 }
10187 <?php
10188
10189
10190
10191
10192
10193
10194
10195
10196
10197
10198
10199 namespace Composer\Repository\Vcs;
10200
10201 use Composer\Config;
10202 use Composer\Json\JsonFile;
10203 use Composer\IO\IOInterface;
10204
10205
10206
10207
10208 class HgBitbucketDriver extends VcsDriver
10209 {
10210 protected $owner;
10211 protected $repository;
10212 protected $tags;
10213 protected $branches;
10214 protected $rootIdentifier;
10215 protected $infoCache = array();
10216
10217
10218
10219
10220 public function initialize()
10221 {
10222 preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $this->url, $match);
10223 $this->owner = $match[1];
10224 $this->repository = $match[2];
10225 $this->originUrl = 'bitbucket.org';
10226 }
10227
10228
10229
10230
10231 public function getRootIdentifier()
10232 {
10233 if (null === $this->rootIdentifier) {
10234 $resource = $this->getScheme() . '://bitbucket.org/api/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags';
10235 $repoData = JsonFile::parseJson($this->getContents($resource), $resource);
10236 if (array() === $repoData || !isset($repoData['tip'])) {
10237 throw new \RuntimeException($this->url.' does not appear to be a mercurial repository, use '.$this->url.'.git if this is a git bitbucket repository');
10238 }
10239 $this->rootIdentifier = $repoData['tip']['raw_node'];
10240 }
10241
10242 return $this->rootIdentifier;
10243 }
10244
10245
10246
10247
10248 public function getUrl()
10249 {
10250 return $this->url;
10251 }
10252
10253
10254
10255
10256 public function getSource($identifier)
10257 {
10258 return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $identifier);
10259 }
10260
10261
10262
10263
10264 public function getDist($identifier)
10265 {
10266 $url = $this->getScheme() . '://bitbucket.org/'.$this->owner.'/'.$this->repository.'/get/'.$identifier.'.zip';
10267
10268 return array('type' => 'zip', 'url' => $url, 'reference' => $identifier, 'shasum' => '');
10269 }
10270
10271
10272
10273
10274 public function getComposerInformation($identifier)
10275 {
10276 if (!isset($this->infoCache[$identifier])) {
10277 $resource = $this->getScheme() . '://bitbucket.org/api/1.0/repositories/'.$this->owner.'/'.$this->repository.'/src/'.$identifier.'/composer.json';
10278 $repoData = JsonFile::parseJson($this->getContents($resource), $resource);
10279
10280
10281  
10282  
10283  
10284
10285 if (!array_key_exists('data', $repoData)) {
10286 return;
10287 }
10288
10289 $composer = JsonFile::parseJson($repoData['data'], $resource);
10290
10291 if (empty($composer['time'])) {
10292 $resource = $this->getScheme() . '://bitbucket.org/api/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier;
10293 $changeset = JsonFile::parseJson($this->getContents($resource), $resource);
10294 $composer['time'] = $changeset['timestamp'];
10295 }
10296 $this->infoCache[$identifier] = $composer;
10297 }
10298
10299 return $this->infoCache[$identifier];
10300 }
10301
10302
10303
10304
10305 public function getTags()
10306 {
10307 if (null === $this->tags) {
10308 $resource = $this->getScheme() . '://bitbucket.org/api/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags';
10309 $tagsData = JsonFile::parseJson($this->getContents($resource), $resource);
10310 $this->tags = array();
10311 foreach ($tagsData as $tag => $data) {
10312 $this->tags[$tag] = $data['raw_node'];
10313 }
10314 unset($this->tags['tip']);
10315 }
10316
10317 return $this->tags;
10318 }
10319
10320
10321
10322
10323 public function getBranches()
10324 {
10325 if (null === $this->branches) {
10326 $resource = $this->getScheme() . '://bitbucket.org/api/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches';
10327 $branchData = JsonFile::parseJson($this->getContents($resource), $resource);
10328 $this->branches = array();
10329 foreach ($branchData as $branch => $data) {
10330 $this->branches[$branch] = $data['raw_node'];
10331 }
10332 }
10333
10334 return $this->branches;
10335 }
10336
10337
10338
10339
10340 public static function supports(IOInterface $io, Config $config, $url, $deep = false)
10341 {
10342 if (!preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url)) {
10343 return false;
10344 }
10345
10346 if (!extension_loaded('openssl')) {
10347 if ($io->isVerbose()) {
10348 $io->write('Skipping Bitbucket hg driver for '.$url.' because the OpenSSL PHP extension is missing.');
10349 }
10350
10351 return false;
10352 }
10353
10354 return true;
10355 }
10356 }
10357 <?php
10358
10359
10360
10361
10362
10363
10364
10365
10366
10367
10368
10369 namespace Composer\Repository;
10370
10371
10372
10373
10374
10375
10376
10377
10378 class InstalledArrayRepository extends WritableArrayRepository implements InstalledRepositoryInterface
10379 {
10380 }
10381 <?php
10382
10383
10384
10385
10386
10387
10388
10389
10390
10391
10392
10393 namespace Composer\Repository;
10394
10395
10396
10397
10398
10399
10400 class RepositorySecurityException extends \Exception
10401 {
10402 }
10403 <?php
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415 namespace Composer\Repository;
10416
10417 use Composer\Downloader\TransportException;
10418 use Composer\Repository\Vcs\VcsDriverInterface;
10419 use Composer\Package\Version\VersionParser;
10420 use Composer\Package\Loader\ArrayLoader;
10421 use Composer\Package\Loader\ValidatingArrayLoader;
10422 use Composer\Package\Loader\InvalidPackageException;
10423 use Composer\Package\Loader\LoaderInterface;
10424 use Composer\EventDispatcher\EventDispatcher;
10425 use Composer\IO\IOInterface;
10426 use Composer\Config;
10427
10428
10429
10430
10431 class VcsRepository extends ArrayRepository
10432 {
10433 protected $url;
10434 protected $packageName;
10435 protected $verbose;
10436 protected $io;
10437 protected $config;
10438 protected $versionParser;
10439 protected $type;
10440 protected $loader;
10441 protected $repoConfig;
10442 protected $branchErrorOccurred = false;
10443
10444 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, array $drivers = null)
10445 {
10446 $this->drivers = $drivers ?: array(
10447 'github' => 'Composer\Repository\Vcs\GitHubDriver',
10448 'git-bitbucket' => 'Composer\Repository\Vcs\GitBitbucketDriver',
10449 'git' => 'Composer\Repository\Vcs\GitDriver',
10450 'hg-bitbucket' => 'Composer\Repository\Vcs\HgBitbucketDriver',
10451 'hg' => 'Composer\Repository\Vcs\HgDriver',
10452 'perforce' => 'Composer\Repository\Vcs\PerforceDriver',
10453
10454  'svn' => 'Composer\Repository\Vcs\SvnDriver',
10455 );
10456
10457 $this->url = $repoConfig['url'];
10458 $this->io = $io;
10459 $this->type = isset($repoConfig['type']) ? $repoConfig['type'] : 'vcs';
10460 $this->verbose = $io->isVerbose();
10461 $this->config = $config;
10462 $this->repoConfig = $repoConfig;
10463 }
10464
10465 public function getRepoConfig()
10466 {
10467 return $this->repoConfig;
10468 }
10469
10470 public function setLoader(LoaderInterface $loader)
10471 {
10472 $this->loader = $loader;
10473 }
10474
10475 public function getDriver()
10476 {
10477 if (isset($this->drivers[$this->type])) {
10478 $class = $this->drivers[$this->type];
10479 $driver = new $class($this->repoConfig, $this->io, $this->config);
10480 $driver->initialize();
10481
10482 return $driver;
10483 }
10484
10485 foreach ($this->drivers as $driver) {
10486 if ($driver::supports($this->io, $this->config, $this->url)) {
10487 $driver = new $driver($this->repoConfig, $this->io, $this->config);
10488 $driver->initialize();
10489
10490 return $driver;
10491 }
10492 }
10493
10494 foreach ($this->drivers as $driver) {
10495 if ($driver::supports($this->io, $this->config, $this->url, true)) {
10496 $driver = new $driver($this->repoConfig, $this->io, $this->config);
10497 $driver->initialize();
10498
10499 return $driver;
10500 }
10501 }
10502 }
10503
10504 public function hadInvalidBranches()
10505 {
10506 return $this->branchErrorOccurred;
10507 }
10508
10509 protected function initialize()
10510 {
10511 parent::initialize();
10512
10513 $verbose = $this->verbose;
10514
10515 $driver = $this->getDriver();
10516 if (!$driver) {
10517 throw new \InvalidArgumentException('No driver found to handle VCS repository '.$this->url);
10518 }
10519
10520 $this->versionParser = new VersionParser;
10521 if (!$this->loader) {
10522 $this->loader = new ArrayLoader($this->versionParser);
10523 }
10524
10525 try {
10526 if ($driver->hasComposerFile($driver->getRootIdentifier())) {
10527 $data = $driver->getComposerInformation($driver->getRootIdentifier());
10528 $this->packageName = !empty($data['name']) ? $data['name'] : null;
10529 }
10530 } catch (\Exception $e) {
10531 if ($verbose) {
10532 $this->io->write('<error>Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().'</error>');
10533 }
10534 }
10535
10536 foreach ($driver->getTags() as $tag => $identifier) {
10537 $msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $tag . '</comment>)';
10538 if ($verbose) {
10539 $this->io->write($msg);
10540 } else {
10541 $this->io->overwrite($msg, false);
10542 }
10543
10544
10545  $tag = str_replace('release-', '', $tag);
10546
10547 if (!$parsedTag = $this->validateTag($tag)) {
10548 if ($verbose) {
10549 $this->io->write('<warning>Skipped tag '.$tag.', invalid tag name</warning>');
10550 }
10551 continue;
10552 }
10553
10554 try {
10555 if (!$data = $driver->getComposerInformation($identifier)) {
10556 if ($verbose) {
10557 $this->io->write('<warning>Skipped tag '.$tag.', no composer file</warning>');
10558 }
10559 continue;
10560 }
10561
10562
10563  if (isset($data['version'])) {
10564 $data['version_normalized'] = $this->versionParser->normalize($data['version']);
10565 } else {
10566
10567  $data['version'] = $tag;
10568 $data['version_normalized'] = $parsedTag;
10569 }
10570
10571
10572  $data['version'] = preg_replace('{[.-]?dev$}i', '', $data['version']);
10573 $data['version_normalized'] = preg_replace('{(^dev-|[.-]?dev$)}i', '', $data['version_normalized']);
10574
10575
10576  if ($data['version_normalized'] !== $parsedTag) {
10577 if ($verbose) {
10578 $this->io->write('<warning>Skipped tag '.$tag.', tag ('.$parsedTag.') does not match version ('.$data['version_normalized'].') in composer.json</warning>');
10579 }
10580 continue;
10581 }
10582
10583 if ($verbose) {
10584 $this->io->write('Importing tag '.$tag.' ('.$data['version_normalized'].')');
10585 }
10586
10587 $this->addPackage($this->loader->load($this->preProcess($driver, $data, $identifier)));
10588 } catch (\Exception $e) {
10589 if ($verbose) {
10590 $this->io->write('<warning>Skipped tag '.$tag.', '.($e instanceof TransportException ? 'no composer file was found' : $e->getMessage()).'</warning>');
10591 }
10592 continue;
10593 }
10594 }
10595
10596 if (!$verbose) {
10597 $this->io->overwrite('', false);
10598 }
10599
10600 foreach ($driver->getBranches() as $branch => $identifier) {
10601 $msg = 'Reading composer.json of <info>' . ($this->packageName ?: $this->url) . '</info> (<comment>' . $branch . '</comment>)';
10602 if ($verbose) {
10603 $this->io->write($msg);
10604 } else {
10605 $this->io->overwrite($msg, false);
10606 }
10607
10608 if (!$parsedBranch = $this->validateBranch($branch)) {
10609 if ($verbose) {
10610 $this->io->write('<warning>Skipped branch '.$branch.', invalid name</warning>');
10611 }
10612 continue;
10613 }
10614
10615 try {
10616 if (!$data = $driver->getComposerInformation($identifier)) {
10617 if ($verbose) {
10618 $this->io->write('<warning>Skipped branch '.$branch.', no composer file</warning>');
10619 }
10620 continue;
10621 }
10622
10623
10624  $data['version'] = $branch;
10625 $data['version_normalized'] = $parsedBranch;
10626
10627
10628  if ('dev-' === substr($parsedBranch, 0, 4) || '9999999-dev' === $parsedBranch) {
10629 $data['version'] = 'dev-' . $data['version'];
10630 } else {
10631 $data['version'] = preg_replace('{(\.9{7})+}', '.x', $parsedBranch);
10632 }
10633
10634 if ($verbose) {
10635 $this->io->write('Importing branch '.$branch.' ('.$data['version'].')');
10636 }
10637
10638 $packageData = $this->preProcess($driver, $data, $identifier);
10639 $package = $this->loader->load($packageData);
10640 if ($this->loader instanceof ValidatingArrayLoader && $this->loader->getWarnings()) {
10641 throw new InvalidPackageException($this->loader->getErrors(), $this->loader->getWarnings(), $packageData);
10642 }
10643 $this->addPackage($package);
10644 } catch (TransportException $e) {
10645 if ($verbose) {
10646 $this->io->write('<warning>Skipped branch '.$branch.', no composer file was found</warning>');
10647 }
10648 continue;
10649 } catch (\Exception $e) {
10650 if (!$verbose) {
10651 $this->io->write('');
10652 }
10653 $this->branchErrorOccurred = true;
10654 $this->io->write('<error>Skipped branch '.$branch.', '.$e->getMessage().'</error>');
10655 $this->io->write('');
10656 continue;
10657 }
10658 }
10659 $driver->cleanup();
10660
10661 if (!$verbose) {
10662 $this->io->overwrite('', false);
10663 }
10664
10665 if (!$this->getPackages()) {
10666 throw new InvalidRepositoryException('No valid composer.json was found in any branch or tag of '.$this->url.', could not load a package from it.');
10667 }
10668 }
10669
10670 protected function preProcess(VcsDriverInterface $driver, array $data, $identifier)
10671 {
10672
10673  $data['name'] = $this->packageName ?: $data['name'];
10674
10675 if (!isset($data['dist'])) {
10676 $data['dist'] = $driver->getDist($identifier);
10677 }
10678 if (!isset($data['source'])) {
10679 $data['source'] = $driver->getSource($identifier);
10680 }
10681
10682 return $data;
10683 }
10684
10685 private function validateBranch($branch)
10686 {
10687 try {
10688 return $this->versionParser->normalizeBranch($branch);
10689 } catch (\Exception $e) {
10690 }
10691
10692 return false;
10693 }
10694
10695 private function validateTag($version)
10696 {
10697 try {
10698 return $this->versionParser->normalize($version);
10699 } catch (\Exception $e) {
10700 }
10701
10702 return false;
10703 }
10704 }
10705 <?php
10706
10707
10708
10709
10710
10711
10712
10713
10714
10715
10716
10717 namespace Composer\Repository;
10718
10719 use Composer\Package\CompletePackage;
10720 use Composer\Package\Version\VersionParser;
10721 use Composer\Plugin\PluginInterface;
10722
10723
10724
10725
10726 class PlatformRepository extends ArrayRepository
10727 {
10728 const PLATFORM_PACKAGE_REGEX = '{^(?:php(?:-64bit)?|hhvm|(?:ext|lib)-[^/]+)$}i';
10729
10730 protected function initialize()
10731 {
10732 parent::initialize();
10733
10734 $versionParser = new VersionParser();
10735
10736 $prettyVersion = PluginInterface::PLUGIN_API_VERSION;
10737 $version = $versionParser->normalize($prettyVersion);
10738 $composerPluginApi = new CompletePackage('composer-plugin-api', $version, $prettyVersion);
10739 $composerPluginApi->setDescription('The Composer Plugin API');
10740 parent::addPackage($composerPluginApi);
10741
10742 try {
10743 $prettyVersion = PHP_VERSION;
10744 $version = $versionParser->normalize($prettyVersion);
10745 } catch (\UnexpectedValueException $e) {
10746 $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', PHP_VERSION);
10747 $version = $versionParser->normalize($prettyVersion);
10748 }
10749
10750 $php = new CompletePackage('php', $version, $prettyVersion);
10751 $php->setDescription('The PHP interpreter');
10752 parent::addPackage($php);
10753
10754 if (PHP_INT_SIZE === 8) {
10755 $php64 = new CompletePackage('php-64bit', $version, $prettyVersion);
10756 $php64->setDescription('The PHP interpreter (64bit)');
10757 parent::addPackage($php64);
10758 }
10759
10760 $loadedExtensions = get_loaded_extensions();
10761
10762
10763  foreach ($loadedExtensions as $name) {
10764 if (in_array($name, array('standard', 'Core'))) {
10765 continue;
10766 }
10767
10768 $reflExt = new \ReflectionExtension($name);
10769 try {
10770 $prettyVersion = $reflExt->getVersion();
10771 $version = $versionParser->normalize($prettyVersion);
10772 } catch (\UnexpectedValueException $e) {
10773 $prettyVersion = '0';
10774 $version = $versionParser->normalize($prettyVersion);
10775 }
10776
10777 $packageName = $this->buildPackageName($name);
10778 $ext = new CompletePackage($packageName, $version, $prettyVersion);
10779 $ext->setDescription('The '.$name.' PHP extension');
10780 parent::addPackage($ext);
10781 }
10782
10783
10784  
10785  
10786  foreach ($loadedExtensions as $name) {
10787 $prettyVersion = null;
10788 switch ($name) {
10789 case 'curl':
10790 $curlVersion = curl_version();
10791 $prettyVersion = $curlVersion['version'];
10792 break;
10793
10794 case 'iconv':
10795 $prettyVersion = ICONV_VERSION;
10796 break;
10797
10798 case 'intl':
10799 $name = 'ICU';
10800 if (defined('INTL_ICU_VERSION')) {
10801 $prettyVersion = INTL_ICU_VERSION;
10802 } else {
10803 $reflector = new \ReflectionExtension('intl');
10804
10805 ob_start();
10806 $reflector->info();
10807 $output = ob_get_clean();
10808
10809 preg_match('/^ICU version => (.*)$/m', $output, $matches);
10810 $prettyVersion = $matches[1];
10811 }
10812
10813 break;
10814
10815 case 'libxml':
10816 $prettyVersion = LIBXML_DOTTED_VERSION;
10817 break;
10818
10819 case 'openssl':
10820 $prettyVersion = preg_replace_callback('{^(?:OpenSSL\s*)?([0-9.]+)([a-z]?).*}', function ($match) {
10821 return $match[1] . (empty($match[2]) ? '' : '.'.(ord($match[2]) - 96));
10822 }, OPENSSL_VERSION_TEXT);
10823 break;
10824
10825 case 'pcre':
10826 $prettyVersion = preg_replace('{^(\S+).*}', '$1', PCRE_VERSION);
10827 break;
10828
10829 case 'uuid':
10830 $prettyVersion = phpversion('uuid');
10831 break;
10832
10833 case 'xsl':
10834 $prettyVersion = LIBXSLT_DOTTED_VERSION;
10835 break;
10836
10837 default:
10838
10839  continue 2;
10840 }
10841
10842 try {
10843 $version = $versionParser->normalize($prettyVersion);
10844 } catch (\UnexpectedValueException $e) {
10845 continue;
10846 }
10847
10848 $lib = new CompletePackage('lib-'.$name, $version, $prettyVersion);
10849 $lib->setDescription('The '.$name.' PHP library');
10850 parent::addPackage($lib);
10851 }
10852
10853 if (defined('HHVM_VERSION')) {
10854 try {
10855 $prettyVersion = HHVM_VERSION;
10856 $version = $versionParser->normalize($prettyVersion);
10857 } catch (\UnexpectedValueException $e) {
10858 $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', HHVM_VERSION);
10859 $version = $versionParser->normalize($prettyVersion);
10860 }
10861
10862 $hhvm = new CompletePackage('hhvm', $version, $prettyVersion);
10863 $hhvm->setDescription('The HHVM Runtime (64bit)');
10864 parent::addPackage($hhvm);
10865 }
10866 }
10867
10868 private function buildPackageName($name)
10869 {
10870 return 'ext-' . str_replace(' ', '-', $name);
10871 }
10872 }
10873 <?php
10874
10875
10876
10877
10878
10879
10880
10881
10882
10883
10884
10885 namespace Composer\Repository;
10886
10887
10888
10889
10890
10891
10892 class InstalledFilesystemRepository extends FilesystemRepository implements InstalledRepositoryInterface
10893 {
10894 }
10895 <?php
10896
10897
10898
10899
10900
10901
10902
10903
10904
10905
10906
10907 namespace Composer\Repository;
10908
10909 use Composer\Package\PackageInterface;
10910
10911
10912
10913
10914
10915
10916 class CompositeRepository implements RepositoryInterface
10917 {
10918
10919
10920
10921
10922 private $repositories;
10923
10924
10925
10926
10927
10928 public function __construct(array $repositories)
10929 {
10930 $this->repositories = array();
10931 foreach ($repositories as $repo) {
10932 $this->addRepository($repo);
10933 }
10934 }
10935
10936
10937
10938
10939
10940
10941 public function getRepositories()
10942 {
10943 return $this->repositories;
10944 }
10945
10946
10947
10948
10949 public function hasPackage(PackageInterface $package)
10950 {
10951 foreach ($this->repositories as $repository) {
10952
10953 if ($repository->hasPackage($package)) {
10954 return true;
10955 }
10956 }
10957
10958 return false;
10959 }
10960
10961
10962
10963
10964 public function findPackage($name, $version)
10965 {
10966 foreach ($this->repositories as $repository) {
10967
10968 $package = $repository->findPackage($name, $version);
10969 if (null !== $package) {
10970 return $package;
10971 }
10972 }
10973
10974 return null;
10975 }
10976
10977
10978
10979
10980 public function findPackages($name, $version = null)
10981 {
10982 $packages = array();
10983 foreach ($this->repositories as $repository) {
10984
10985 $packages[] = $repository->findPackages($name, $version);
10986 }
10987
10988 return $packages ? call_user_func_array('array_merge', $packages) : array();
10989 }
10990
10991
10992
10993
10994 public function search($query, $mode = 0)
10995 {
10996 $matches = array();
10997 foreach ($this->repositories as $repository) {
10998
10999 $matches[] = $repository->search($query, $mode);
11000 }
11001
11002 return $matches ? call_user_func_array('array_merge', $matches) : array();
11003 }
11004
11005
11006
11007
11008 public function filterPackages($callback, $class = 'Composer\Package\Package')
11009 {
11010 foreach ($this->repositories as $repository) {
11011 if (false === $repository->filterPackages($callback, $class)) {
11012 return false;
11013 }
11014 }
11015
11016 return true;
11017 }
11018
11019
11020
11021
11022 public function getPackages()
11023 {
11024 $packages = array();
11025 foreach ($this->repositories as $repository) {
11026
11027 $packages[] = $repository->getPackages();
11028 }
11029
11030 return $packages ? call_user_func_array('array_merge', $packages) : array();
11031 }
11032
11033
11034
11035
11036 public function removePackage(PackageInterface $package)
11037 {
11038 foreach ($this->repositories as $repository) {
11039
11040 $repository->removePackage($package);
11041 }
11042 }
11043
11044
11045
11046
11047 public function count()
11048 {
11049 $total = 0;
11050 foreach ($this->repositories as $repository) {
11051
11052 $total += $repository->count();
11053 }
11054
11055 return $total;
11056 }
11057
11058
11059
11060
11061
11062 public function addRepository(RepositoryInterface $repository)
11063 {
11064 if ($repository instanceof self) {
11065 foreach ($repository->getRepositories() as $repo) {
11066 $this->addRepository($repo);
11067 }
11068 } else {
11069 $this->repositories[] = $repository;
11070 }
11071 }
11072 }
11073 <?php
11074
11075
11076
11077
11078
11079
11080
11081
11082
11083
11084
11085 namespace Composer\Repository;
11086
11087
11088
11089
11090
11091
11092
11093
11094 interface InstalledRepositoryInterface extends WritableRepositoryInterface
11095 {
11096 }
11097 <?php
11098
11099
11100
11101
11102
11103
11104
11105
11106
11107
11108
11109 namespace Composer\Repository;
11110
11111 use Composer\Package\Loader\ArrayLoader;
11112 use Composer\Package\Package;
11113 use Composer\Package\PackageInterface;
11114 use Composer\Package\AliasPackage;
11115 use Composer\Package\Version\VersionParser;
11116 use Composer\DependencyResolver\Pool;
11117 use Composer\Json\JsonFile;
11118 use Composer\Cache;
11119 use Composer\Config;
11120 use Composer\IO\IOInterface;
11121 use Composer\Util\RemoteFilesystem;
11122 use Composer\Plugin\PluginEvents;
11123 use Composer\Plugin\PreFileDownloadEvent;
11124 use Composer\EventDispatcher\EventDispatcher;
11125
11126
11127
11128
11129 class ComposerRepository extends ArrayRepository
11130 {
11131 protected $config;
11132 protected $options;
11133 protected $url;
11134 protected $baseUrl;
11135 protected $io;
11136 protected $rfs;
11137 protected $cache;
11138 protected $notifyUrl;
11139 protected $searchUrl;
11140 protected $hasProviders = false;
11141 protected $providersUrl;
11142 protected $lazyProvidersUrl;
11143 protected $providerListing;
11144 protected $providers = array();
11145 protected $providersByUid = array();
11146 protected $loader;
11147 protected $rootAliases;
11148 protected $allowSslDowngrade = false;
11149 protected $eventDispatcher;
11150 protected $sourceMirrors;
11151 protected $distMirrors;
11152 private $degradedMode = false;
11153 private $rootData;
11154
11155 public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
11156 {
11157 if (!preg_match('{^[\w.]+\??://}', $repoConfig['url'])) {
11158
11159  $repoConfig['url'] = 'http://'.$repoConfig['url'];
11160 }
11161 $repoConfig['url'] = rtrim($repoConfig['url'], '/');
11162
11163 if ('https?' === substr($repoConfig['url'], 0, 6)) {
11164 $repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
11165 }
11166
11167 $urlBits = parse_url($repoConfig['url']);
11168 if ($urlBits === false || empty($urlBits['scheme'])) {
11169 throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
11170 }
11171
11172 if (!isset($repoConfig['options'])) {
11173 $repoConfig['options'] = array();
11174 }
11175 if (isset($repoConfig['allow_ssl_downgrade']) && true === $repoConfig['allow_ssl_downgrade']) {
11176 $this->allowSslDowngrade = true;
11177 }
11178
11179 $this->config = $config;
11180 $this->options = $repoConfig['options'];
11181 $this->url = $repoConfig['url'];
11182 $this->baseUrl = rtrim(preg_replace('{^(.*)(?:/[^/\\]+.json)?(?:[?#].*)?$}', '$1', $this->url), '/');
11183 $this->io = $io;
11184 $this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$');
11185 $this->loader = new ArrayLoader();
11186 $this->rfs = new RemoteFilesystem($this->io, $this->config, $this->options);
11187 $this->eventDispatcher = $eventDispatcher;
11188 }
11189
11190 public function setRootAliases(array $rootAliases)
11191 {
11192 $this->rootAliases = $rootAliases;
11193 }
11194
11195
11196
11197
11198 public function findPackage($name, $version)
11199 {
11200 if (!$this->hasProviders()) {
11201 return parent::findPackage($name, $version);
11202 }
11203
11204  $versionParser = new VersionParser();
11205 $version = $versionParser->normalize($version);
11206 $name = strtolower($name);
11207
11208 foreach ($this->getProviderNames() as $providerName) {
11209 if ($name === $providerName) {
11210 $packages = $this->whatProvides(new Pool('dev'), $providerName);
11211 foreach ($packages as $package) {
11212 if ($name == $package->getName() && $version === $package->getVersion()) {
11213 return $package;
11214 }
11215 }
11216 }
11217 }
11218 }
11219
11220
11221
11222
11223 public function findPackages($name, $version = null)
11224 {
11225 if (!$this->hasProviders()) {
11226 return parent::findPackages($name, $version);
11227 }
11228
11229  $name = strtolower($name);
11230
11231
11232  if (null !== $version) {
11233 $versionParser = new VersionParser();
11234 $version = $versionParser->normalize($version);
11235 }
11236
11237 $packages = array();
11238
11239 foreach ($this->getProviderNames() as $providerName) {
11240 if ($name === $providerName) {
11241 $packages = $this->whatProvides(new Pool('dev'), $providerName);
11242 foreach ($packages as $package) {
11243 if ($name == $package->getName() && (null === $version || $version === $package->getVersion())) {
11244 $packages[] = $package;
11245 }
11246 }
11247 }
11248 }
11249
11250 return $packages;
11251 }
11252
11253 public function getPackages()
11254 {
11255 if ($this->hasProviders()) {
11256 throw new \LogicException('Composer repositories that have providers can not load the complete list of packages, use getProviderNames instead.');
11257 }
11258
11259 return parent::getPackages();
11260 }
11261
11262
11263
11264
11265 public function search($query, $mode = 0)
11266 {
11267 $this->loadRootServerFile();
11268
11269 if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) {
11270 $url = str_replace('%query%', $query, $this->searchUrl);
11271
11272 $hostname = parse_url($url, PHP_URL_HOST) ?: $url;
11273 $json = $this->rfs->getContents($hostname, $url, false);
11274 $results = JsonFile::parseJson($json, $url);
11275
11276 return $results['results'];
11277 }
11278
11279 if ($this->hasProviders()) {
11280 $results = array();
11281 $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
11282
11283 foreach ($this->getProviderNames() as $name) {
11284 if (preg_match($regex, $name)) {
11285 $results[] = array('name' => $name);
11286 }
11287 }
11288
11289 return $results;
11290 }
11291
11292 return parent::search($query, $mode);
11293 }
11294
11295 public function getProviderNames()
11296 {
11297 $this->loadRootServerFile();
11298
11299 if (null === $this->providerListing) {
11300 $this->loadProviderListings($this->loadRootServerFile());
11301 }
11302
11303 if ($this->providersUrl) {
11304 return array_keys($this->providerListing);
11305 }
11306
11307
11308  $providers = array();
11309 foreach (array_keys($this->providerListing) as $provider) {
11310 $providers[] = substr($provider, 2, -5);
11311 }
11312
11313 return $providers;
11314 }
11315
11316 protected function configurePackageTransportOptions(PackageInterface $package)
11317 {
11318 foreach ($package->getDistUrls() as $url) {
11319 if (strpos($url, $this->baseUrl) === 0) {
11320 $package->setTransportOptions($this->options);
11321
11322 return;
11323 }
11324 }
11325 }
11326
11327 public function hasProviders()
11328 {
11329 $this->loadRootServerFile();
11330
11331 return $this->hasProviders;
11332 }
11333
11334 public function resetPackageIds()
11335 {
11336 foreach ($this->providersByUid as $package) {
11337 if ($package instanceof AliasPackage) {
11338 $package->getAliasOf()->setId(-1);
11339 }
11340 $package->setId(-1);
11341 }
11342 }
11343
11344 public function whatProvides(Pool $pool, $name)
11345 {
11346 if (isset($this->providers[$name])) {
11347 return $this->providers[$name];
11348 }
11349
11350
11351  if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) {
11352 return array();
11353 }
11354
11355 if (null === $this->providerListing) {
11356 $this->loadProviderListings($this->loadRootServerFile());
11357 }
11358
11359 if ($this->lazyProvidersUrl && !isset($this->providerListing[$name])) {
11360 $hash = null;
11361 $url = str_replace('%package%', $name, $this->lazyProvidersUrl);
11362 $cacheKey = false;
11363 } elseif ($this->providersUrl) {
11364
11365  if (!isset($this->providerListing[$name])) {
11366 return array();
11367 }
11368
11369 $hash = $this->providerListing[$name]['sha256'];
11370 $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl);
11371 $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
11372 } else {
11373
11374  $url = 'p/'.$name.'.json';
11375
11376
11377  if (!isset($this->providerListing[$url])) {
11378 return array();
11379 }
11380 $hash = $this->providerListing[$url]['sha256'];
11381 $cacheKey = null;
11382 }
11383
11384 if ($cacheKey && $this->cache->sha256($cacheKey) === $hash) {
11385 $packages = json_decode($this->cache->read($cacheKey), true);
11386 } else {
11387 $packages = $this->fetchFile($url, $cacheKey, $hash);
11388 }
11389
11390 $this->providers[$name] = array();
11391 foreach ($packages['packages'] as $versions) {
11392 foreach ($versions as $version) {
11393
11394  if (isset($this->providersByUid[$version['uid']])) {
11395
11396  if (!isset($this->providers[$name][$version['uid']])) {
11397
11398  if ($this->providersByUid[$version['uid']] instanceof AliasPackage) {
11399 $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']]->getAliasOf();
11400 $this->providers[$name][$version['uid'].'-alias'] = $this->providersByUid[$version['uid']];
11401 } else {
11402 $this->providers[$name][$version['uid']] = $this->providersByUid[$version['uid']];
11403 }
11404
11405  if (isset($this->providersByUid[$version['uid'].'-root'])) {
11406 $this->providers[$name][$version['uid'].'-root'] = $this->providersByUid[$version['uid'].'-root'];
11407 }
11408 }
11409 } else {
11410 if (!$pool->isPackageAcceptable(strtolower($version['name']), VersionParser::parseStability($version['version']))) {
11411 continue;
11412 }
11413
11414
11415  $package = $this->createPackage($version, 'Composer\Package\Package');
11416 $package->setRepository($this);
11417
11418 if ($package instanceof AliasPackage) {
11419 $aliased = $package->getAliasOf();
11420 $aliased->setRepository($this);
11421
11422 $this->providers[$name][$version['uid']] = $aliased;
11423 $this->providers[$name][$version['uid'].'-alias'] = $package;
11424
11425
11426  $this->providersByUid[$version['uid']] = $package;
11427 } else {
11428 $this->providers[$name][$version['uid']] = $package;
11429 $this->providersByUid[$version['uid']] = $package;
11430 }
11431
11432
11433  unset($rootAliasData);
11434
11435 if (isset($this->rootAliases[$package->getName()][$package->getVersion()])) {
11436 $rootAliasData = $this->rootAliases[$package->getName()][$package->getVersion()];
11437 } elseif ($package instanceof AliasPackage && isset($this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()])) {
11438 $rootAliasData = $this->rootAliases[$package->getName()][$package->getAliasOf()->getVersion()];
11439 }
11440
11441 if (isset($rootAliasData)) {
11442 $alias = $this->createAliasPackage($package, $rootAliasData['alias_normalized'], $rootAliasData['alias']);
11443 $alias->setRepository($this);
11444
11445 $this->providers[$name][$version['uid'].'-root'] = $alias;
11446 $this->providersByUid[$version['uid'].'-root'] = $alias;
11447 }
11448 }
11449 }
11450 }
11451
11452 return $this->providers[$name];
11453 }
11454
11455
11456
11457
11458 protected function initialize()
11459 {
11460 parent::initialize();
11461
11462 $repoData = $this->loadDataFromServer();
11463
11464 foreach ($repoData as $package) {
11465 $this->addPackage($this->createPackage($package, 'Composer\Package\CompletePackage'));
11466 }
11467 }
11468
11469
11470
11471
11472
11473
11474 public function addPackage(PackageInterface $package)
11475 {
11476 parent::addPackage($package);
11477 $this->configurePackageTransportOptions($package);
11478 }
11479
11480 protected function loadRootServerFile()
11481 {
11482 if (null !== $this->rootData) {
11483 return $this->rootData;
11484 }
11485
11486 if (!extension_loaded('openssl') && 'https' === substr($this->url, 0, 5)) {
11487 throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url);
11488 }
11489
11490 $jsonUrlParts = parse_url($this->url);
11491
11492 if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '.json')) {
11493 $jsonUrl = $this->url;
11494 } else {
11495 $jsonUrl = $this->url . '/packages.json';
11496 }
11497
11498 $data = $this->fetchFile($jsonUrl, 'packages.json');
11499
11500 if (!empty($data['notify-batch'])) {
11501 $this->notifyUrl = $this->canonicalizeUrl($data['notify-batch']);
11502 } elseif (!empty($data['notify_batch'])) {
11503
11504  $this->notifyUrl = $this->canonicalizeUrl($data['notify_batch']);
11505 } elseif (!empty($data['notify'])) {
11506 $this->notifyUrl = $this->canonicalizeUrl($data['notify']);
11507 }
11508
11509 if (!empty($data['search'])) {
11510 $this->searchUrl = $this->canonicalizeUrl($data['search']);
11511 }
11512
11513 if (!empty($data['mirrors'])) {
11514 foreach ($data['mirrors'] as $mirror) {
11515 if (!empty($mirror['git-url'])) {
11516 $this->sourceMirrors['git'][] = array('url' => $mirror['git-url'], 'preferred' => !empty($mirror['preferred']));
11517 }
11518 if (!empty($mirror['hg-url'])) {
11519 $this->sourceMirrors['hg'][] = array('url' => $mirror['hg-url'], 'preferred' => !empty($mirror['preferred']));
11520 }
11521 if (!empty($mirror['dist-url'])) {
11522 $this->distMirrors[] = array('url' => $mirror['dist-url'], 'preferred' => !empty($mirror['preferred']));
11523 }
11524 }
11525 }
11526
11527 if (!empty($data['warning'])) {
11528 $this->io->write('<warning>Warning from '.$this->url.': '.$data['warning'].'</warning>');
11529 }
11530
11531 if (!empty($data['providers-lazy-url'])) {
11532 $this->lazyProvidersUrl = $this->canonicalizeUrl($data['providers-lazy-url']);
11533 $this->hasProviders = true;
11534 }
11535
11536 if ($this->allowSslDowngrade) {
11537 $this->url = str_replace('https://', 'http://', $this->url);
11538 }
11539
11540 if (!empty($data['providers-url'])) {
11541 $this->providersUrl = $this->canonicalizeUrl($data['providers-url']);
11542 $this->hasProviders = true;
11543 }
11544
11545 if (!empty($data['providers']) || !empty($data['providers-includes'])) {
11546 $this->hasProviders = true;
11547 }
11548
11549 return $this->rootData = $data;
11550 }
11551
11552 protected function canonicalizeUrl($url)
11553 {
11554 if ('/' === $url[0]) {
11555 return preg_replace('{(https?://[^/]+).*}i', '$1' . $url, $this->url);
11556 }
11557
11558 return $url;
11559 }
11560
11561 protected function loadDataFromServer()
11562 {
11563 $data = $this->loadRootServerFile();
11564
11565 return $this->loadIncludes($data);
11566 }
11567
11568 protected function loadProviderListings($data)
11569 {
11570 if (isset($data['providers'])) {
11571 if (!is_array($this->providerListing)) {
11572 $this->providerListing = array();
11573 }
11574 $this->providerListing = array_merge($this->providerListing, $data['providers']);
11575 }
11576
11577 if ($this->providersUrl && isset($data['provider-includes'])) {
11578 $includes = $data['provider-includes'];
11579 foreach ($includes as $include => $metadata) {
11580 $url = $this->baseUrl . '/' . str_replace('%hash%', $metadata['sha256'], $include);
11581 $cacheKey = str_replace(array('%hash%','$'), '', $include);
11582 if ($this->cache->sha256($cacheKey) === $metadata['sha256']) {
11583 $includedData = json_decode($this->cache->read($cacheKey), true);
11584 } else {
11585 $includedData = $this->fetchFile($url, $cacheKey, $metadata['sha256']);
11586 }
11587
11588 $this->loadProviderListings($includedData);
11589 }
11590 } elseif (isset($data['providers-includes'])) {
11591
11592  $includes = $data['providers-includes'];
11593 foreach ($includes as $include => $metadata) {
11594 if ($this->cache->sha256($include) === $metadata['sha256']) {
11595 $includedData = json_decode($this->cache->read($include), true);
11596 } else {
11597 $includedData = $this->fetchFile($include, null, $metadata['sha256']);
11598 }
11599
11600 $this->loadProviderListings($includedData);
11601 }
11602 }
11603 }
11604
11605 protected function loadIncludes($data)
11606 {
11607 $packages = array();
11608
11609
11610  if (!isset($data['packages']) && !isset($data['includes'])) {
11611 foreach ($data as $pkg) {
11612 foreach ($pkg['versions'] as $metadata) {
11613 $packages[] = $metadata;
11614 }
11615 }
11616
11617 return $packages;
11618 }
11619
11620 if (isset($data['packages'])) {
11621 foreach ($data['packages'] as $package => $versions) {
11622 foreach ($versions as $version => $metadata) {
11623 $packages[] = $metadata;
11624 }
11625 }
11626 }
11627
11628 if (isset($data['includes'])) {
11629 foreach ($data['includes'] as $include => $metadata) {
11630 if ($this->cache->sha1($include) === $metadata['sha1']) {
11631 $includedData = json_decode($this->cache->read($include), true);
11632 } else {
11633 $includedData = $this->fetchFile($include);
11634 }
11635 $packages = array_merge($packages, $this->loadIncludes($includedData));
11636 }
11637 }
11638
11639 return $packages;
11640 }
11641
11642 protected function createPackage(array $data, $class)
11643 {
11644 try {
11645 if (!isset($data['notification-url'])) {
11646 $data['notification-url'] = $this->notifyUrl;
11647 }
11648
11649 $package = $this->loader->load($data, 'Composer\Package\CompletePackage');
11650 if (isset($this->sourceMirrors[$package->getSourceType()])) {
11651 $package->setSourceMirrors($this->sourceMirrors[$package->getSourceType()]);
11652 }
11653 $package->setDistMirrors($this->distMirrors);
11654 $this->configurePackageTransportOptions($package);
11655
11656 return $package;
11657 } catch (\Exception $e) {
11658 throw new \RuntimeException('Could not load package '.(isset($data['name']) ? $data['name'] : json_encode($data)).' in '.$this->url.': ['.get_class($e).'] '.$e->getMessage(), 0, $e);
11659 }
11660 }
11661
11662 protected function fetchFile($filename, $cacheKey = null, $sha256 = null)
11663 {
11664 if (null === $cacheKey) {
11665 $cacheKey = $filename;
11666 $filename = $this->baseUrl.'/'.$filename;
11667 }
11668
11669 $retries = 3;
11670 while ($retries--) {
11671 try {
11672 $preFileDownloadEvent = new PreFileDownloadEvent(PluginEvents::PRE_FILE_DOWNLOAD, $this->rfs, $filename);
11673 if ($this->eventDispatcher) {
11674 $this->eventDispatcher->dispatch($preFileDownloadEvent->getName(), $preFileDownloadEvent);
11675 }
11676
11677 $hostname = parse_url($filename, PHP_URL_HOST) ?: $filename;
11678 $json = $preFileDownloadEvent->getRemoteFilesystem()->getContents($hostname, $filename, false);
11679 if ($sha256 && $sha256 !== hash('sha256', $json)) {
11680 if ($retries) {
11681 usleep(100000);
11682
11683 continue;
11684 }
11685
11686
11687  throw new RepositorySecurityException('The contents of '.$filename.' do not match its signature. This should indicate a man-in-the-middle attack. Try running composer again and report this if you think it is a mistake.');
11688 }
11689 $data = JsonFile::parseJson($json, $filename);
11690 if ($cacheKey) {
11691 $this->cache->write($cacheKey, $json);
11692 }
11693
11694 break;
11695 } catch (\Exception $e) {
11696 if ($retries) {
11697 usleep(100000);
11698 continue;
11699 }
11700
11701 if ($e instanceof RepositorySecurityException) {
11702 throw $e;
11703 }
11704
11705 if ($cacheKey && ($contents = $this->cache->read($cacheKey))) {
11706 if (!$this->degradedMode) {
11707 $this->io->write('<warning>'.$e->getMessage().'</warning>');
11708 $this->io->write('<warning>'.$this->url.' could not be fully loaded, package information was loaded from the local cache and may be out of date</warning>');
11709 }
11710 $this->degradedMode = true;
11711 $data = JsonFile::parseJson($contents, $this->cache->getRoot().$cacheKey);
11712
11713 break;
11714 }
11715
11716 throw $e;
11717 }
11718 }
11719
11720 return $data;
11721 }
11722 }
11723 <?php
11724
11725
11726
11727
11728
11729
11730
11731
11732
11733
11734
11735 namespace Composer\Repository\Pear;
11736
11737
11738
11739
11740
11741
11742 class DependencyInfo
11743 {
11744 private $requires;
11745 private $optionals;
11746
11747
11748
11749
11750
11751 public function __construct($requires, $optionals)
11752 {
11753 $this->requires = $requires;
11754 $this->optionals = $optionals;
11755 }
11756
11757
11758
11759
11760 public function getRequires()
11761 {
11762 return $this->requires;
11763 }
11764
11765
11766
11767
11768 public function getOptionals()
11769 {
11770 return $this->optionals;
11771 }
11772 }
11773 <?php
11774
11775
11776
11777
11778
11779
11780
11781
11782
11783
11784
11785 namespace Composer\Repository\Pear;
11786
11787
11788
11789
11790
11791
11792 class PackageDependencyParser
11793 {
11794
11795
11796
11797
11798
11799
11800 public function buildDependencyInfo($depArray)
11801 {
11802 if (!is_array($depArray)) {
11803 return new DependencyInfo(array(), array());
11804 }
11805 if (!$this->isHash($depArray)) {
11806 return new DependencyInfo($this->buildDependency10Info($depArray), array());
11807 }
11808
11809 return $this->buildDependency20Info($depArray);
11810 }
11811
11812
11813
11814
11815
11816
11817
11818
11819
11820
11821
11822
11823
11824 private function buildDependency10Info($depArray)
11825 {
11826 static $dep10toOperatorMap = array('has' => '==', 'eq' => '==', 'ge' => '>=', 'gt' => '>', 'le' => '<=', 'lt' => '<', 'not' => '!=');
11827
11828 $result = array();
11829
11830 foreach ($depArray as $depItem) {
11831 if (empty($depItem['rel']) || !array_key_exists($depItem['rel'], $dep10toOperatorMap)) {
11832
11833  continue;
11834 }
11835
11836 $depType = !empty($depItem['optional']) && 'yes' == $depItem['optional']
11837 ? 'optional'
11838 : 'required';
11839 $depType = 'not' == $depItem['rel']
11840 ? 'conflicts'
11841 : $depType;
11842
11843 $depVersion = !empty($depItem['version']) ? $this->parseVersion($depItem['version']) : '*';
11844
11845
11846  $depVersionConstraint = ('has' == $depItem['rel'] || 'not' == $depItem['rel']) && '*' == $depVersion
11847 ? '*'
11848 : $dep10toOperatorMap[$depItem['rel']] . $depVersion;
11849
11850 switch ($depItem['type']) {
11851 case 'php':
11852 $depChannelName = 'php';
11853 $depPackageName = '';
11854 break;
11855 case 'pkg':
11856 $depChannelName = !empty($depItem['channel']) ? $depItem['channel'] : 'pear.php.net';
11857 $depPackageName = $depItem['name'];
11858 break;
11859 case 'ext':
11860 $depChannelName = 'ext';
11861 $depPackageName = $depItem['name'];
11862 break;
11863 case 'os':
11864 case 'sapi':
11865 $depChannelName = '';
11866 $depPackageName = '';
11867 break;
11868 default:
11869 $depChannelName = '';
11870 $depPackageName = '';
11871 break;
11872 }
11873
11874 if ('' != $depChannelName) {
11875 $result[] = new DependencyConstraint(
11876 $depType,
11877 $depVersionConstraint,
11878 $depChannelName,
11879 $depPackageName
11880 );
11881 }
11882 }
11883
11884 return $result;
11885 }
11886
11887
11888
11889
11890
11891
11892
11893 private function buildDependency20Info($depArray)
11894 {
11895 $result = array();
11896 $optionals = array();
11897 $defaultOptionals = array();
11898 foreach ($depArray as $depType => $depTypeGroup) {
11899 if (!is_array($depTypeGroup)) {
11900 continue;
11901 }
11902 if ('required' == $depType || 'optional' == $depType) {
11903 foreach ($depTypeGroup as $depItemType => $depItem) {
11904 switch ($depItemType) {
11905 case 'php':
11906 $result[] = new DependencyConstraint(
11907 $depType,
11908 $this->parse20VersionConstraint($depItem),
11909 'php',
11910 ''
11911 );
11912 break;
11913 case 'package':
11914 $deps = $this->buildDepPackageConstraints($depItem, $depType);
11915 $result = array_merge($result, $deps);
11916 break;
11917 case 'extension':
11918 $deps = $this->buildDepExtensionConstraints($depItem, $depType);
11919 $result = array_merge($result, $deps);
11920 break;
11921 case 'subpackage':
11922 $deps = $this->buildDepPackageConstraints($depItem, 'replaces');
11923 $defaultOptionals += $deps;
11924 break;
11925 case 'os':
11926 case 'pearinstaller':
11927 break;
11928 default:
11929 break;
11930 }
11931 }
11932 } elseif ('group' == $depType) {
11933 if ($this->isHash($depTypeGroup)) {
11934 $depTypeGroup = array($depTypeGroup);
11935 }
11936
11937 foreach ($depTypeGroup as $depItem) {
11938 $groupName = $depItem['attribs']['name'];
11939 if (!isset($optionals[$groupName])) {
11940 $optionals[$groupName] = array();
11941 }
11942
11943 if (isset($depItem['subpackage'])) {
11944 $optionals[$groupName] += $this->buildDepPackageConstraints($depItem['subpackage'], 'replaces');
11945 } else {
11946 $result += $this->buildDepPackageConstraints($depItem['package'], 'optional');
11947 }
11948 }
11949 }
11950 }
11951
11952 if (count($defaultOptionals) > 0) {
11953 $optionals['*'] = $defaultOptionals;
11954 }
11955
11956 return new DependencyInfo($result, $optionals);
11957 }
11958
11959
11960
11961
11962
11963
11964
11965
11966 private function buildDepExtensionConstraints($depItem, $depType)
11967 {
11968 if ($this->isHash($depItem)) {
11969 $depItem = array($depItem);
11970 }
11971
11972 $result = array();
11973 foreach ($depItem as $subDepItem) {
11974 $depChannelName = 'ext';
11975 $depPackageName = $subDepItem['name'];
11976 $depVersionConstraint = $this->parse20VersionConstraint($subDepItem);
11977
11978 $result[] = new DependencyConstraint(
11979 $depType,
11980 $depVersionConstraint,
11981 $depChannelName,
11982 $depPackageName
11983 );
11984 }
11985
11986 return $result;
11987 }
11988
11989
11990
11991
11992
11993
11994
11995
11996 private function buildDepPackageConstraints($depItem, $depType)
11997 {
11998 if ($this->isHash($depItem)) {
11999 $depItem = array($depItem);
12000 }
12001
12002 $result = array();
12003 foreach ($depItem as $subDepItem) {
12004 $depChannelName = $subDepItem['channel'];
12005 $depPackageName = $subDepItem['name'];
12006 $depVersionConstraint = $this->parse20VersionConstraint($subDepItem);
12007 if (isset($subDepItem['conflicts'])) {
12008 $depType = 'conflicts';
12009 }
12010
12011 $result[] = new DependencyConstraint(
12012 $depType,
12013 $depVersionConstraint,
12014 $depChannelName,
12015 $depPackageName
12016 );
12017 }
12018
12019 return $result;
12020 }
12021
12022
12023
12024
12025
12026
12027
12028 private function parse20VersionConstraint(array $data)
12029 {
12030 static $dep20toOperatorMap = array('has' => '==', 'min' => '>=', 'max' => '<=', 'exclude' => '!=');
12031
12032 $versions = array();
12033 $values = array_intersect_key($data, $dep20toOperatorMap);
12034 if (0 == count($values)) {
12035 return '*';
12036 }
12037 if (isset($values['min']) && isset($values['exclude']) && $data['min'] == $data['exclude']) {
12038 $versions[] = '>' . $this->parseVersion($values['min']);
12039 } elseif (isset($values['max']) && isset($values['exclude']) && $data['max'] == $data['exclude']) {
12040 $versions[] = '<' . $this->parseVersion($values['max']);
12041 } else {
12042 foreach ($values as $op => $version) {
12043 if ('exclude' == $op && is_array($version)) {
12044 foreach ($version as $versionPart) {
12045 $versions[] = $dep20toOperatorMap[$op] . $this->parseVersion($versionPart);
12046 }
12047 } else {
12048 $versions[] = $dep20toOperatorMap[$op] . $this->parseVersion($version);
12049 }
12050 }
12051 }
12052
12053 return implode(',', $versions);
12054 }
12055
12056
12057
12058
12059
12060
12061
12062 private function parseVersion($version)
12063 {
12064 if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?}i', $version, $matches)) {
12065 $version = $matches[1]
12066 .(!empty($matches[2]) ? $matches[2] : '.0')
12067 .(!empty($matches[3]) ? $matches[3] : '.0')
12068 .(!empty($matches[4]) ? $matches[4] : '.0');
12069
12070 return $version;
12071 }
12072
12073 return null;
12074 }
12075
12076
12077
12078
12079
12080
12081
12082 private function isHash(array $array)
12083 {
12084 return !array_key_exists(1, $array) && !array_key_exists(0, $array);
12085 }
12086 }
12087 <?php
12088
12089
12090
12091
12092
12093
12094
12095
12096
12097
12098
12099 namespace Composer\Repository\Pear;
12100
12101
12102
12103
12104
12105
12106 class ChannelInfo
12107 {
12108 private $name;
12109 private $alias;
12110 private $packages;
12111
12112
12113
12114
12115
12116
12117 public function __construct($name, $alias, array $packages)
12118 {
12119 $this->name = $name;
12120 $this->alias = $alias;
12121 $this->packages = $packages;
12122 }
12123
12124
12125
12126
12127
12128
12129 public function getName()
12130 {
12131 return $this->name;
12132 }
12133
12134
12135
12136
12137
12138
12139 public function getAlias()
12140 {
12141 return $this->alias;
12142 }
12143
12144
12145
12146
12147
12148
12149 public function getPackages()
12150 {
12151 return $this->packages;
12152 }
12153 }
12154 <?php
12155
12156
12157
12158
12159
12160
12161
12162
12163
12164
12165
12166 namespace Composer\Repository\Pear;
12167
12168 use Composer\Util\RemoteFilesystem;
12169
12170
12171
12172
12173
12174
12175
12176
12177 class ChannelReader extends BaseChannelReader
12178 {
12179
12180 private $readerMap;
12181
12182 public function __construct(RemoteFilesystem $rfs)
12183 {
12184 parent::__construct($rfs);
12185
12186 $rest10reader = new ChannelRest10Reader($rfs);
12187 $rest11reader = new ChannelRest11Reader($rfs);
12188
12189 $this->readerMap = array(
12190 'REST1.3' => $rest11reader,
12191 'REST1.2' => $rest11reader,
12192 'REST1.1' => $rest11reader,
12193 'REST1.0' => $rest10reader,
12194 );
12195 }
12196
12197
12198
12199
12200
12201
12202
12203
12204 public function read($url)
12205 {
12206 $xml = $this->requestXml($url, "/channel.xml");
12207
12208 $channelName = (string) $xml->name;
12209 $channelSummary = (string) $xml->summary;
12210 $channelAlias = (string) $xml->suggestedalias;
12211
12212 $supportedVersions = array_keys($this->readerMap);
12213 $selectedRestVersion = $this->selectRestVersion($xml, $supportedVersions);
12214 if (!$selectedRestVersion) {
12215 throw new \UnexpectedValueException(sprintf('PEAR repository %s does not supports any of %s protocols.', $url, implode(', ', $supportedVersions)));
12216 }
12217
12218 $reader = $this->readerMap[$selectedRestVersion['version']];
12219 $packageDefinitions = $reader->read($selectedRestVersion['baseUrl']);
12220
12221 return new ChannelInfo($channelName, $channelAlias, $packageDefinitions);
12222 }
12223
12224
12225
12226
12227
12228
12229
12230
12231 private function selectRestVersion($channelXml, $supportedVersions)
12232 {
12233 $channelXml->registerXPathNamespace('ns', self::CHANNEL_NS);
12234
12235 foreach ($supportedVersions as $version) {
12236 $xpathTest = "ns:servers/ns:primary/ns:rest/ns:baseurl[@type='{$version}']";
12237 $testResult = $channelXml->xpath($xpathTest);
12238 if (count($testResult) > 0) {
12239 return array('version' => $version, 'baseUrl' => (string) $testResult[0]);
12240 }
12241 }
12242
12243 return null;
12244 }
12245 }
12246 <?php
12247
12248
12249
12250
12251
12252
12253
12254
12255
12256
12257
12258 namespace Composer\Repository\Pear;
12259
12260
12261
12262
12263
12264
12265 class PackageInfo
12266 {
12267 private $channelName;
12268 private $packageName;
12269 private $license;
12270 private $shortDescription;
12271 private $description;
12272 private $releases;
12273
12274
12275
12276
12277
12278
12279
12280
12281
12282 public function __construct($channelName, $packageName, $license, $shortDescription, $description, $releases)
12283 {
12284 $this->channelName = $channelName;
12285 $this->packageName = $packageName;
12286 $this->license = $license;
12287 $this->shortDescription = $shortDescription;
12288 $this->description = $description;
12289 $this->releases = $releases;
12290 }
12291
12292
12293
12294
12295 public function getChannelName()
12296 {
12297 return $this->channelName;
12298 }
12299
12300
12301
12302
12303 public function getPackageName()
12304 {
12305 return $this->packageName;
12306 }
12307
12308
12309
12310
12311 public function getDescription()
12312 {
12313 return $this->description;
12314 }
12315
12316
12317
12318
12319 public function getShortDescription()
12320 {
12321 return $this->shortDescription;
12322 }
12323
12324
12325
12326
12327 public function getLicense()
12328 {
12329 return $this->license;
12330 }
12331
12332
12333
12334
12335 public function getReleases()
12336 {
12337 return $this->releases;
12338 }
12339 }
12340 <?php
12341
12342
12343
12344
12345
12346
12347
12348
12349
12350
12351
12352 namespace Composer\Repository\Pear;
12353
12354
12355
12356
12357
12358
12359 class DependencyConstraint
12360 {
12361 private $type;
12362 private $constraint;
12363 private $channelName;
12364 private $packageName;
12365
12366
12367
12368
12369
12370
12371
12372 public function __construct($type, $constraint, $channelName, $packageName)
12373 {
12374 $this->type = $type;
12375 $this->constraint = $constraint;
12376 $this->channelName = $channelName;
12377 $this->packageName = $packageName;
12378 }
12379
12380 public function getChannelName()
12381 {
12382 return $this->channelName;
12383 }
12384
12385 public function getConstraint()
12386 {
12387 return $this->constraint;
12388 }
12389
12390 public function getPackageName()
12391 {
12392 return $this->packageName;
12393 }
12394
12395 public function getType()
12396 {
12397 return $this->type;
12398 }
12399 }
12400 <?php
12401
12402
12403
12404
12405
12406
12407
12408
12409
12410
12411
12412 namespace Composer\Repository\Pear;
12413
12414
12415
12416
12417
12418
12419
12420
12421
12422
12423 class ChannelRest11Reader extends BaseChannelReader
12424 {
12425 private $dependencyReader;
12426
12427 public function __construct($rfs)
12428 {
12429 parent::__construct($rfs);
12430
12431 $this->dependencyReader = new PackageDependencyParser();
12432 }
12433
12434
12435
12436
12437
12438
12439
12440
12441 public function read($baseUrl)
12442 {
12443 return $this->readChannelPackages($baseUrl);
12444 }
12445
12446
12447
12448
12449
12450
12451
12452
12453 private function readChannelPackages($baseUrl)
12454 {
12455 $result = array();
12456
12457 $xml = $this->requestXml($baseUrl, "/c/categories.xml");
12458 $xml->registerXPathNamespace('ns', self::ALL_CATEGORIES_NS);
12459 foreach ($xml->xpath('ns:c') as $node) {
12460 $categoryName = (string) $node;
12461 $categoryPackages = $this->readCategoryPackages($baseUrl, $categoryName);
12462 $result = array_merge($result, $categoryPackages);
12463 }
12464
12465 return $result;
12466 }
12467
12468
12469
12470
12471
12472
12473
12474
12475
12476 private function readCategoryPackages($baseUrl, $categoryName)
12477 {
12478 $result = array();
12479
12480 $categoryPath = '/c/'.urlencode($categoryName).'/packagesinfo.xml';
12481 $xml = $this->requestXml($baseUrl, $categoryPath);
12482 $xml->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
12483 foreach ($xml->xpath('ns:pi') as $node) {
12484 $packageInfo = $this->parsePackage($node);
12485 $result[] = $packageInfo;
12486 }
12487
12488 return $result;
12489 }
12490
12491
12492
12493
12494
12495
12496
12497 private function parsePackage($packageInfo)
12498 {
12499 $packageInfo->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
12500 $channelName = (string) $packageInfo->p->c;
12501 $packageName = (string) $packageInfo->p->n;
12502 $license = (string) $packageInfo->p->l;
12503 $shortDescription = (string) $packageInfo->p->s;
12504 $description = (string) $packageInfo->p->d;
12505
12506 $dependencies = array();
12507 foreach ($packageInfo->xpath('ns:deps') as $node) {
12508 $dependencyVersion = (string) $node->v;
12509 $dependencyArray = unserialize((string) $node->d);
12510
12511 $dependencyInfo = $this->dependencyReader->buildDependencyInfo($dependencyArray);
12512
12513 $dependencies[$dependencyVersion] = $dependencyInfo;
12514 }
12515
12516 $releases = array();
12517 $releasesInfo = $packageInfo->xpath('ns:a/ns:r');
12518 if ($releasesInfo) {
12519 foreach ($releasesInfo as $node) {
12520 $releaseVersion = (string) $node->v;
12521 $releaseStability = (string) $node->s;
12522 $releases[$releaseVersion] = new ReleaseInfo(
12523 $releaseStability,
12524 isset($dependencies[$releaseVersion]) ? $dependencies[$releaseVersion] : new DependencyInfo(array(), array())
12525 );
12526 }
12527 }
12528
12529 return new PackageInfo(
12530 $channelName,
12531 $packageName,
12532 $license,
12533 $shortDescription,
12534 $description,
12535 $releases
12536 );
12537 }
12538 }
12539 <?php
12540
12541
12542
12543
12544
12545
12546
12547
12548
12549
12550
12551 namespace Composer\Repository\Pear;
12552
12553
12554
12555
12556
12557
12558 class ReleaseInfo
12559 {
12560 private $stability;
12561 private $dependencyInfo;
12562
12563
12564
12565
12566
12567 public function __construct($stability, $dependencyInfo)
12568 {
12569 $this->stability = $stability;
12570 $this->dependencyInfo = $dependencyInfo;
12571 }
12572
12573
12574
12575
12576 public function getDependencyInfo()
12577 {
12578 return $this->dependencyInfo;
12579 }
12580
12581
12582
12583
12584 public function getStability()
12585 {
12586 return $this->stability;
12587 }
12588 }
12589 <?php
12590
12591
12592
12593
12594
12595
12596
12597
12598
12599
12600
12601 namespace Composer\Repository\Pear;
12602
12603 use Composer\Util\RemoteFilesystem;
12604
12605
12606
12607
12608
12609
12610
12611
12612 abstract class BaseChannelReader
12613 {
12614
12615
12616
12617 const CHANNEL_NS = 'http://pear.php.net/channel-1.0';
12618 const ALL_CATEGORIES_NS = 'http://pear.php.net/dtd/rest.allcategories';
12619 const CATEGORY_PACKAGES_INFO_NS = 'http://pear.php.net/dtd/rest.categorypackageinfo';
12620 const ALL_PACKAGES_NS = 'http://pear.php.net/dtd/rest.allpackages';
12621 const ALL_RELEASES_NS = 'http://pear.php.net/dtd/rest.allreleases';
12622 const PACKAGE_INFO_NS = 'http://pear.php.net/dtd/rest.package';
12623
12624
12625 private $rfs;
12626
12627 protected function __construct(RemoteFilesystem $rfs)
12628 {
12629 $this->rfs = $rfs;
12630 }
12631
12632
12633
12634
12635
12636
12637
12638
12639
12640 protected function requestContent($origin, $path)
12641 {
12642 $url = rtrim($origin, '/') . '/' . ltrim($path, '/');
12643 $content = $this->rfs->getContents($origin, $url, false);
12644 if (!$content) {
12645 throw new \UnexpectedValueException('The PEAR channel at ' . $url . ' did not respond.');
12646 }
12647
12648 return $content;
12649 }
12650
12651
12652
12653
12654
12655
12656
12657
12658
12659 protected function requestXml($origin, $path)
12660 {
12661
12662  $xml = simplexml_load_string($this->requestContent($origin, $path), "SimpleXMLElement", LIBXML_NOERROR);
12663
12664 if (false == $xml) {
12665 $url = rtrim($origin, '/') . '/' . ltrim($path, '/');
12666 throw new \UnexpectedValueException(sprintf('The PEAR channel at ' . $origin . ' is broken. (Invalid XML at file `%s`)', $path));
12667 }
12668
12669 return $xml;
12670 }
12671 }
12672 <?php
12673
12674
12675
12676
12677
12678
12679
12680
12681
12682
12683
12684 namespace Composer\Repository\Pear;
12685
12686 use Composer\Downloader\TransportException;
12687
12688
12689
12690
12691
12692
12693
12694
12695
12696
12697
12698
12699 class ChannelRest10Reader extends BaseChannelReader
12700 {
12701 private $dependencyReader;
12702
12703 public function __construct($rfs)
12704 {
12705 parent::__construct($rfs);
12706
12707 $this->dependencyReader = new PackageDependencyParser();
12708 }
12709
12710
12711
12712
12713
12714
12715
12716
12717 public function read($baseUrl)
12718 {
12719 return $this->readPackages($baseUrl);
12720 }
12721
12722
12723
12724
12725
12726
12727
12728
12729 private function readPackages($baseUrl)
12730 {
12731 $result = array();
12732
12733 $xmlPath = '/p/packages.xml';
12734 $xml = $this->requestXml($baseUrl, $xmlPath);
12735 $xml->registerXPathNamespace('ns', self::ALL_PACKAGES_NS);
12736 foreach ($xml->xpath('ns:p') as $node) {
12737 $packageName = (string) $node;
12738 $packageInfo = $this->readPackage($baseUrl, $packageName);
12739 $result[] = $packageInfo;
12740 }
12741
12742 return $result;
12743 }
12744
12745
12746
12747
12748
12749
12750
12751
12752
12753 private function readPackage($baseUrl, $packageName)
12754 {
12755 $xmlPath = '/p/' . strtolower($packageName) . '/info.xml';
12756 $xml = $this->requestXml($baseUrl, $xmlPath);
12757 $xml->registerXPathNamespace('ns', self::PACKAGE_INFO_NS);
12758
12759 $channelName = (string) $xml->c;
12760 $packageName = (string) $xml->n;
12761 $license = (string) $xml->l;
12762 $shortDescription = (string) $xml->s;
12763 $description = (string) $xml->d;
12764
12765 return new PackageInfo(
12766 $channelName,
12767 $packageName,
12768 $license,
12769 $shortDescription,
12770 $description,
12771 $this->readPackageReleases($baseUrl, $packageName)
12772 );
12773 }
12774
12775
12776
12777
12778
12779
12780
12781
12782
12783
12784 private function readPackageReleases($baseUrl, $packageName)
12785 {
12786 $result = array();
12787
12788 try {
12789 $xmlPath = '/r/' . strtolower($packageName) . '/allreleases.xml';
12790 $xml = $this->requestXml($baseUrl, $xmlPath);
12791 $xml->registerXPathNamespace('ns', self::ALL_RELEASES_NS);
12792 foreach ($xml->xpath('ns:r') as $node) {
12793 $releaseVersion = (string) $node->v;
12794 $releaseStability = (string) $node->s;
12795
12796 try {
12797 $result[$releaseVersion] = new ReleaseInfo(
12798 $releaseStability,
12799 $this->readPackageReleaseDependencies($baseUrl, $packageName, $releaseVersion)
12800 );
12801 } catch (TransportException $exception) {
12802 if ($exception->getCode() != 404) {
12803 throw $exception;
12804 }
12805 }
12806 }
12807 } catch (TransportException $exception) {
12808 if ($exception->getCode() != 404) {
12809 throw $exception;
12810 }
12811 }
12812
12813 return $result;
12814 }
12815
12816
12817
12818
12819
12820
12821
12822
12823
12824
12825 private function readPackageReleaseDependencies($baseUrl, $packageName, $version)
12826 {
12827 $dependencyReader = new PackageDependencyParser();
12828
12829 $depthPath = '/r/' . strtolower($packageName) . '/deps.' . $version . '.txt';
12830 $content = $this->requestContent($baseUrl, $depthPath);
12831 $dependencyArray = unserialize($content);
12832 $result = $dependencyReader->buildDependencyInfo($dependencyArray);
12833
12834 return $result;
12835 }
12836 }
12837 <?php
12838
12839
12840
12841
12842
12843
12844
12845
12846
12847
12848
12849 namespace Composer\Repository;
12850
12851 use Composer\Package\PackageInterface;
12852
12853
12854
12855
12856
12857
12858
12859
12860 interface RepositoryInterface extends \Countable
12861 {
12862 const SEARCH_FULLTEXT = 0;
12863 const SEARCH_NAME = 1;
12864
12865
12866
12867
12868
12869
12870
12871
12872 public function hasPackage(PackageInterface $package);
12873
12874
12875
12876
12877
12878
12879
12880
12881
12882 public function findPackage($name, $version);
12883
12884
12885
12886
12887
12888
12889
12890
12891
12892 public function findPackages($name, $version = null);
12893
12894
12895
12896
12897
12898
12899 public function getPackages();
12900
12901
12902
12903
12904
12905
12906
12907
12908 public function search($query, $mode = 0);
12909 }
12910 <?php
12911
12912
12913
12914
12915
12916
12917
12918
12919
12920
12921
12922 namespace Composer\Repository;
12923
12924 use Composer\IO\IOInterface;
12925 use Composer\Json\JsonFile;
12926 use Composer\Package\Loader\ArrayLoader;
12927
12928
12929
12930
12931 class ArtifactRepository extends ArrayRepository
12932 {
12933
12934 protected $loader;
12935
12936 protected $lookup;
12937
12938 public function __construct(array $repoConfig, IOInterface $io)
12939 {
12940 if (!extension_loaded('zip')) {
12941 throw new \RuntimeException('The artifact repository requires PHP\'s zip extension');
12942 }
12943
12944 $this->loader = new ArrayLoader();
12945 $this->lookup = $repoConfig['url'];
12946 $this->io = $io;
12947 }
12948
12949 protected function initialize()
12950 {
12951 parent::initialize();
12952
12953 $this->scanDirectory($this->lookup);
12954 }
12955
12956 private function scanDirectory($path)
12957 {
12958 $io = $this->io;
12959
12960 $directory = new \RecursiveDirectoryIterator($path);
12961 $iterator = new \RecursiveIteratorIterator($directory);
12962 $regex = new \RegexIterator($iterator, '/^.+\.(zip|phar)$/i');
12963 foreach ($regex as $file) {
12964
12965 if (!$file->isFile()) {
12966 continue;
12967 }
12968
12969 $package = $this->getComposerInformation($file);
12970 if (!$package) {
12971 if ($io->isVerbose()) {
12972 $io->write("File <comment>{$file->getBasename()}</comment> doesn't seem to hold a package");
12973 }
12974 continue;
12975 }
12976
12977 if ($io->isVerbose()) {
12978 $template = 'Found package <info>%s</info> (<comment>%s</comment>) in file <info>%s</info>';
12979 $io->write(sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename()));
12980 }
12981
12982 $this->addPackage($package);
12983 }
12984 }
12985
12986
12987
12988
12989
12990
12991
12992
12993 private function locateFile(\ZipArchive $zip, $filename)
12994 {
12995 $indexOfShortestMatch = false;
12996 $lengthOfShortestMatch = -1;
12997
12998 for ($i = 0; $i < $zip->numFiles; $i++) {
12999 $stat = $zip->statIndex($i);
13000 if (strcmp(basename($stat['name']), $filename) === 0) {
13001 $directoryName = dirname($stat['name']);
13002 if ($directoryName == '.') {
13003
13004  
13005  return $i;
13006 }
13007
13008 if (strpos($directoryName, '\\') !== false ||
13009 strpos($directoryName, '/') !== false) {
13010
13011  continue;
13012 }
13013
13014 $length = strlen($stat['name']);
13015 if ($indexOfShortestMatch == false || $length < $lengthOfShortestMatch) {
13016
13017  $contents = $zip->getFromIndex($i);
13018 if ($contents !== false) {
13019 $indexOfShortestMatch = $i;
13020 $lengthOfShortestMatch = $length;
13021 }
13022 }
13023 }
13024 }
13025
13026 return $indexOfShortestMatch;
13027 }
13028
13029 private function getComposerInformation(\SplFileInfo $file)
13030 {
13031 $zip = new \ZipArchive();
13032 $zip->open($file->getPathname());
13033
13034 if (0 == $zip->numFiles) {
13035 return false;
13036 }
13037
13038 $foundFileIndex = $this->locateFile($zip, 'composer.json');
13039 if (false === $foundFileIndex) {
13040 return false;
13041 }
13042
13043 $configurationFileName = $zip->getNameIndex($foundFileIndex);
13044
13045 $composerFile = "zip://{$file->getPathname()}#$configurationFileName";
13046 $json = file_get_contents($composerFile);
13047
13048 $package = JsonFile::parseJson($json, $composerFile);
13049 $package['dist'] = array(
13050 'type' => 'zip',
13051 'url' => $file->getPathname(),
13052 'shasum' => sha1_file($file->getRealPath())
13053 );
13054
13055 $package = $this->loader->load($package);
13056
13057 return $package;
13058 }
13059 }
13060 <?php
13061
13062
13063
13064
13065
13066
13067
13068
13069
13070
13071
13072 namespace Composer\Repository;
13073
13074 use Composer\Package\Loader\ArrayLoader;
13075 use Composer\Package\Loader\ValidatingArrayLoader;
13076
13077
13078
13079
13080
13081
13082 class PackageRepository extends ArrayRepository
13083 {
13084 private $config;
13085
13086
13087
13088
13089
13090
13091 public function __construct(array $config)
13092 {
13093 $this->config = $config['package'];
13094
13095
13096  if (!is_numeric(key($this->config))) {
13097 $this->config = array($this->config);
13098 }
13099 }
13100
13101
13102
13103
13104 protected function initialize()
13105 {
13106 parent::initialize();
13107
13108 $loader = new ValidatingArrayLoader(new ArrayLoader, false);
13109 foreach ($this->config as $package) {
13110 try {
13111 $package = $loader->load($package);
13112 } catch (\Exception $e) {
13113 throw new InvalidRepositoryException('A repository of type "package" contains an invalid package definition: '.$e->getMessage()."\n\nInvalid package definition:\n".json_encode($package));
13114 }
13115
13116 $this->addPackage($package);
13117 }
13118 }
13119 }
13120 <?php
13121
13122
13123
13124
13125
13126
13127
13128
13129
13130
13131
13132 namespace Composer\Package;
13133
13134
13135
13136
13137
13138
13139 class CompletePackage extends Package implements CompletePackageInterface
13140 {
13141 protected $repositories;
13142 protected $license = array();
13143 protected $keywords;
13144 protected $authors;
13145 protected $description;
13146 protected $homepage;
13147 protected $scripts = array();
13148 protected $support = array();
13149 protected $abandoned = false;
13150
13151
13152
13153
13154 public function setScripts(array $scripts)
13155 {
13156 $this->scripts = $scripts;
13157 }
13158
13159
13160
13161
13162 public function getScripts()
13163 {
13164 return $this->scripts;
13165 }
13166
13167
13168
13169
13170
13171
13172 public function setRepositories($repositories)
13173 {
13174 $this->repositories = $repositories;
13175 }
13176
13177
13178
13179
13180 public function getRepositories()
13181 {
13182 return $this->repositories;
13183 }
13184
13185
13186
13187
13188
13189
13190 public function setLicense(array $license)
13191 {
13192 $this->license = $license;
13193 }
13194
13195
13196
13197
13198 public function getLicense()
13199 {
13200 return $this->license;
13201 }
13202
13203
13204
13205
13206
13207
13208 public function setKeywords(array $keywords)
13209 {
13210 $this->keywords = $keywords;
13211 }
13212
13213
13214
13215
13216 public function getKeywords()
13217 {
13218 return $this->keywords;
13219 }
13220
13221
13222
13223
13224
13225
13226 public function setAuthors(array $authors)
13227 {
13228 $this->authors = $authors;
13229 }
13230
13231
13232
13233
13234 public function getAuthors()
13235 {
13236 return $this->authors;
13237 }
13238
13239
13240
13241
13242
13243
13244 public function setDescription($description)
13245 {
13246 $this->description = $description;
13247 }
13248
13249
13250
13251
13252 public function getDescription()
13253 {
13254 return $this->description;
13255 }
13256
13257
13258
13259
13260
13261
13262 public function setHomepage($homepage)
13263 {
13264 $this->homepage = $homepage;
13265 }
13266
13267
13268
13269
13270 public function getHomepage()
13271 {
13272 return $this->homepage;
13273 }
13274
13275
13276
13277
13278
13279
13280 public function setSupport(array $support)
13281 {
13282 $this->support = $support;
13283 }
13284
13285
13286
13287
13288 public function getSupport()
13289 {
13290 return $this->support;
13291 }
13292
13293
13294
13295
13296 public function isAbandoned()
13297 {
13298 return (boolean) $this->abandoned;
13299 }
13300
13301
13302
13303
13304 public function setAbandoned($abandoned)
13305 {
13306 $this->abandoned = $abandoned;
13307 }
13308
13309
13310
13311
13312
13313
13314 public function getReplacementPackage()
13315 {
13316 return is_string($this->abandoned) ? $this->abandoned : null;
13317 }
13318 }
13319 <?php
13320
13321
13322
13323
13324
13325
13326
13327
13328
13329
13330
13331 namespace Composer\Package\Dumper;
13332
13333 use Composer\Package\BasePackage;
13334 use Composer\Package\PackageInterface;
13335 use Composer\Package\CompletePackageInterface;
13336 use Composer\Package\RootPackageInterface;
13337
13338
13339
13340
13341
13342 class ArrayDumper
13343 {
13344 public function dump(PackageInterface $package)
13345 {
13346 $keys = array(
13347 'binaries' => 'bin',
13348 'type',
13349 'extra',
13350 'installationSource' => 'installation-source',
13351 'autoload',
13352 'devAutoload' => 'autoload-dev',
13353 'notificationUrl' => 'notification-url',
13354 'includePaths' => 'include-path',
13355 );
13356
13357 $data = array();
13358 $data['name'] = $package->getPrettyName();
13359 $data['version'] = $package->getPrettyVersion();
13360 $data['version_normalized'] = $package->getVersion();
13361
13362 if ($package->getTargetDir()) {
13363 $data['target-dir'] = $package->getTargetDir();
13364 }
13365
13366 if ($package->getSourceType()) {
13367 $data['source']['type'] = $package->getSourceType();
13368 $data['source']['url'] = $package->getSourceUrl();
13369 $data['source']['reference'] = $package->getSourceReference();
13370 if ($mirrors = $package->getSourceMirrors()) {
13371 $data['source']['mirrors'] = $mirrors;
13372 }
13373 }
13374
13375 if ($package->getDistType()) {
13376 $data['dist']['type'] = $package->getDistType();
13377 $data['dist']['url'] = $package->getDistUrl();
13378 $data['dist']['reference'] = $package->getDistReference();
13379 $data['dist']['shasum'] = $package->getDistSha1Checksum();
13380 if ($mirrors = $package->getDistMirrors()) {
13381 $data['dist']['mirrors'] = $mirrors;
13382 }
13383 }
13384
13385 if ($package->getArchiveExcludes()) {
13386 $data['archive']['exclude'] = $package->getArchiveExcludes();
13387 }
13388
13389 foreach (BasePackage::$supportedLinkTypes as $type => $opts) {
13390 if ($links = $package->{'get'.ucfirst($opts['method'])}()) {
13391 foreach ($links as $link) {
13392 $data[$type][$link->getTarget()] = $link->getPrettyConstraint();
13393 }
13394 ksort($data[$type]);
13395 }
13396 }
13397
13398 if ($packages = $package->getSuggests()) {
13399 ksort($packages);
13400 $data['suggest'] = $packages;
13401 }
13402
13403 if ($package->getReleaseDate()) {
13404 $data['time'] = $package->getReleaseDate()->format('Y-m-d H:i:s');
13405 }
13406
13407 $data = $this->dumpValues($package, $keys, $data);
13408
13409 if ($package instanceof CompletePackageInterface) {
13410 $keys = array(
13411 'scripts',
13412 'license',
13413 'authors',
13414 'description',
13415 'homepage',
13416 'keywords',
13417 'repositories',
13418 'support',
13419 );
13420
13421 $data = $this->dumpValues($package, $keys, $data);
13422
13423 if (isset($data['keywords']) && is_array($data['keywords'])) {
13424 sort($data['keywords']);
13425 }
13426
13427 if ($package->isAbandoned()) {
13428 $data['abandoned'] = $package->getReplacementPackage() ?: true;
13429 }
13430 }
13431
13432 if ($package instanceof RootPackageInterface) {
13433 $minimumStability = $package->getMinimumStability();
13434 if ($minimumStability) {
13435 $data['minimum-stability'] = $minimumStability;
13436 }
13437 }
13438
13439 if (count($package->getTransportOptions()) > 0) {
13440 $data['transport-options'] = $package->getTransportOptions();
13441 }
13442
13443 return $data;
13444 }
13445
13446 private function dumpValues(PackageInterface $package, array $keys, array $data)
13447 {
13448 foreach ($keys as $method => $key) {
13449 if (is_numeric($method)) {
13450 $method = $key;
13451 }
13452
13453 $getter = 'get'.ucfirst($method);
13454 $value = $package->$getter();
13455
13456 if (null !== $value && !(is_array($value) && 0 === count($value))) {
13457 $data[$key] = $value;
13458 }
13459 }
13460
13461 return $data;
13462 }
13463 }
13464 <?php
13465
13466
13467
13468
13469
13470
13471
13472
13473
13474
13475
13476 namespace Composer\Package\Loader;
13477
13478
13479
13480
13481 class InvalidPackageException extends \Exception
13482 {
13483 private $errors;
13484 private $warnings;
13485 private $data;
13486
13487 public function __construct(array $errors, array $warnings, array $data)
13488 {
13489 $this->errors = $errors;
13490 $this->warnings = $warnings;
13491 $this->data = $data;
13492 parent::__construct("Invalid package information: \n".implode("\n", array_merge($errors, $warnings)));
13493 }
13494
13495 public function getData()
13496 {
13497 return $this->data;
13498 }
13499
13500 public function getErrors()
13501 {
13502 return $this->errors;
13503 }
13504
13505 public function getWarnings()
13506 {
13507 return $this->warnings;
13508 }
13509 }
13510 <?php
13511
13512
13513
13514
13515
13516
13517
13518
13519
13520
13521
13522 namespace Composer\Package\Loader;
13523
13524 use Composer\Json\JsonFile;
13525
13526
13527
13528
13529 class JsonLoader
13530 {
13531 private $loader;
13532
13533 public function __construct(LoaderInterface $loader)
13534 {
13535 $this->loader = $loader;
13536 }
13537
13538
13539
13540
13541
13542 public function load($json)
13543 {
13544 if ($json instanceof JsonFile) {
13545 $config = $json->read();
13546 } elseif (file_exists($json)) {
13547 $config = JsonFile::parseJson(file_get_contents($json), $json);
13548 } elseif (is_string($json)) {
13549 $config = JsonFile::parseJson($json);
13550 }
13551
13552 return $this->loader->load($config);
13553 }
13554 }
13555 <?php
13556
13557
13558
13559
13560
13561
13562
13563
13564
13565
13566
13567 namespace Composer\Package\Loader;
13568
13569
13570
13571
13572
13573
13574 interface LoaderInterface
13575 {
13576
13577
13578
13579
13580
13581
13582
13583 public function load(array $package, $class = 'Composer\Package\CompletePackage');
13584 }
13585 <?php
13586
13587
13588
13589
13590
13591
13592
13593
13594
13595
13596
13597 namespace Composer\Package\Loader;
13598
13599 use Composer\Package;
13600 use Composer\Package\AliasPackage;
13601 use Composer\Package\RootAliasPackage;
13602 use Composer\Package\RootPackageInterface;
13603 use Composer\Package\Version\VersionParser;
13604
13605
13606
13607
13608
13609 class ArrayLoader implements LoaderInterface
13610 {
13611 protected $versionParser;
13612 protected $loadOptions;
13613
13614 public function __construct(VersionParser $parser = null, $loadOptions = false)
13615 {
13616 if (!$parser) {
13617 $parser = new VersionParser;
13618 }
13619 $this->versionParser = $parser;
13620 $this->loadOptions = $loadOptions;
13621 }
13622
13623 public function load(array $config, $class = 'Composer\Package\CompletePackage')
13624 {
13625 if (!isset($config['name'])) {
13626 throw new \UnexpectedValueException('Unknown package has no name defined ('.json_encode($config).').');
13627 }
13628 if (!isset($config['version'])) {
13629 throw new \UnexpectedValueException('Package '.$config['name'].' has no version defined.');
13630 }
13631
13632
13633  if (isset($config['version_normalized'])) {
13634 $version = $config['version_normalized'];
13635 } else {
13636 $version = $this->versionParser->normalize($config['version']);
13637 }
13638 $package = new $class($config['name'], $version, $config['version']);
13639 $package->setType(isset($config['type']) ? strtolower($config['type']) : 'library');
13640
13641 if (isset($config['target-dir'])) {
13642 $package->setTargetDir($config['target-dir']);
13643 }
13644
13645 if (isset($config['extra']) && is_array($config['extra'])) {
13646 $package->setExtra($config['extra']);
13647 }
13648
13649 if (isset($config['bin'])) {
13650 if (!is_array($config['bin'])) {
13651 throw new \UnexpectedValueException('Package '.$config['name'].'\'s bin key should be an array, '.gettype($config['bin']).' given.');
13652 }
13653 foreach ($config['bin'] as $key => $bin) {
13654 $config['bin'][$key] = ltrim($bin, '/');
13655 }
13656 $package->setBinaries($config['bin']);
13657 }
13658
13659 if (isset($config['installation-source'])) {
13660 $package->setInstallationSource($config['installation-source']);
13661 }
13662
13663 if (isset($config['source'])) {
13664 if (!isset($config['source']['type']) || !isset($config['source']['url']) || !isset($config['source']['reference'])) {
13665 throw new \UnexpectedValueException(sprintf(
13666 "Package %s's source key should be specified as {\"type\": ..., \"url\": ..., \"reference\": ...},\n%s given.",
13667 $config['name'],
13668 json_encode($config['source'])
13669 ));
13670 }
13671 $package->setSourceType($config['source']['type']);
13672 $package->setSourceUrl($config['source']['url']);
13673 $package->setSourceReference($config['source']['reference']);
13674 if (isset($config['source']['mirrors'])) {
13675 $package->setSourceMirrors($config['source']['mirrors']);
13676 }
13677 }
13678
13679 if (isset($config['dist'])) {
13680 if (!isset($config['dist']['type'])
13681 || !isset($config['dist']['url'])) {
13682 throw new \UnexpectedValueException(sprintf(
13683 "Package %s's dist key should be specified as ".
13684 "{\"type\": ..., \"url\": ..., \"reference\": ..., \"shasum\": ...},\n%s given.",
13685 $config['name'],
13686 json_encode($config['dist'])
13687 ));
13688 }
13689 $package->setDistType($config['dist']['type']);
13690 $package->setDistUrl($config['dist']['url']);
13691 $package->setDistReference(isset($config['dist']['reference']) ? $config['dist']['reference'] : null);
13692 $package->setDistSha1Checksum(isset($config['dist']['shasum']) ? $config['dist']['shasum'] : null);
13693 if (isset($config['dist']['mirrors'])) {
13694 $package->setDistMirrors($config['dist']['mirrors']);
13695 }
13696 }
13697
13698 foreach (Package\BasePackage::$supportedLinkTypes as $type => $opts) {
13699 if (isset($config[$type])) {
13700 $method = 'set'.ucfirst($opts['method']);
13701 $package->{$method}(
13702 $this->versionParser->parseLinks(
13703 $package->getName(),
13704 $package->getPrettyVersion(),
13705 $opts['description'],
13706 $config[$type]
13707 )
13708 );
13709 }
13710 }
13711
13712 if (isset($config['suggest']) && is_array($config['suggest'])) {
13713 foreach ($config['suggest'] as $target => $reason) {
13714 if ('self.version' === trim($reason)) {
13715 $config['suggest'][$target] = $package->getPrettyVersion();
13716 }
13717 }
13718 $package->setSuggests($config['suggest']);
13719 }
13720
13721 if (isset($config['autoload'])) {
13722 $package->setAutoload($config['autoload']);
13723 }
13724
13725 if (isset($config['autoload-dev'])) {
13726 $package->setDevAutoload($config['autoload-dev']);
13727 }
13728
13729 if (isset($config['include-path'])) {
13730 $package->setIncludePaths($config['include-path']);
13731 }
13732
13733 if (!empty($config['time'])) {
13734 $time = ctype_digit($config['time']) ? '@'.$config['time'] : $config['time'];
13735
13736 try {
13737 $date = new \DateTime($time, new \DateTimeZone('UTC'));
13738 $package->setReleaseDate($date);
13739 } catch (\Exception $e) {
13740 }
13741 }
13742
13743 if (!empty($config['notification-url'])) {
13744 $package->setNotificationUrl($config['notification-url']);
13745 }
13746
13747 if (!empty($config['archive']['exclude'])) {
13748 $package->setArchiveExcludes($config['archive']['exclude']);
13749 }
13750
13751 if ($package instanceof Package\CompletePackageInterface) {
13752 if (isset($config['scripts']) && is_array($config['scripts'])) {
13753 foreach ($config['scripts'] as $event => $listeners) {
13754 $config['scripts'][$event] = (array) $listeners;
13755 }
13756 $package->setScripts($config['scripts']);
13757 }
13758
13759 if (!empty($config['description']) && is_string($config['description'])) {
13760 $package->setDescription($config['description']);
13761 }
13762
13763 if (!empty($config['homepage']) && is_string($config['homepage'])) {
13764 $package->setHomepage($config['homepage']);
13765 }
13766
13767 if (!empty($config['keywords']) && is_array($config['keywords'])) {
13768 $package->setKeywords($config['keywords']);
13769 }
13770
13771 if (!empty($config['license'])) {
13772 $package->setLicense(is_array($config['license']) ? $config['license'] : array($config['license']));
13773 }
13774
13775 if (!empty($config['authors']) && is_array($config['authors'])) {
13776 $package->setAuthors($config['authors']);
13777 }
13778
13779 if (isset($config['support'])) {
13780 $package->setSupport($config['support']);
13781 }
13782
13783 if (isset($config['abandoned'])) {
13784 $package->setAbandoned($config['abandoned']);
13785 }
13786 }
13787
13788 if ($aliasNormalized = $this->getBranchAlias($config)) {
13789 if ($package instanceof RootPackageInterface) {
13790 $package = new RootAliasPackage($package, $aliasNormalized, preg_replace('{(\.9{7})+}', '.x', $aliasNormalized));
13791 } else {
13792 $package = new AliasPackage($package, $aliasNormalized, preg_replace('{(\.9{7})+}', '.x', $aliasNormalized));
13793 }
13794 }
13795
13796 if ($this->loadOptions && isset($config['transport-options'])) {
13797 $package->setTransportOptions($config['transport-options']);
13798 }
13799
13800 return $package;
13801 }
13802
13803
13804
13805
13806
13807
13808
13809 public function getBranchAlias(array $config)
13810 {
13811 if ('dev-' !== substr($config['version'], 0, 4)
13812 || !isset($config['extra']['branch-alias'])
13813 || !is_array($config['extra']['branch-alias'])
13814 ) {
13815 return;
13816 }
13817
13818 foreach ($config['extra']['branch-alias'] as $sourceBranch => $targetBranch) {
13819
13820  if ('-dev' !== substr($targetBranch, -4)) {
13821 continue;
13822 }
13823
13824
13825  $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
13826 if ('-dev' !== substr($validatedTargetBranch, -4)) {
13827 continue;
13828 }
13829
13830
13831  if (strtolower($config['version']) !== strtolower($sourceBranch)) {
13832 continue;
13833 }
13834
13835 return $validatedTargetBranch;
13836 }
13837 }
13838 }
13839 <?php
13840
13841
13842
13843
13844
13845
13846
13847
13848
13849
13850
13851 namespace Composer\Package\Loader;
13852
13853 use Composer\Package;
13854 use Composer\Package\BasePackage;
13855 use Composer\Package\LinkConstraint\VersionConstraint;
13856 use Composer\Package\Version\VersionParser;
13857 use Composer\Repository\PlatformRepository;
13858
13859
13860
13861
13862 class ValidatingArrayLoader implements LoaderInterface
13863 {
13864 const CHECK_ALL = 1;
13865 const CHECK_UNBOUND_CONSTRAINTS = 1;
13866
13867 private $loader;
13868 private $versionParser;
13869 private $errors;
13870 private $warnings;
13871 private $config;
13872 private $strictName;
13873 private $flags;
13874
13875 public function __construct(LoaderInterface $loader, $strictName = true, VersionParser $parser = null, $flags = 0)
13876 {
13877 $this->loader = $loader;
13878 $this->versionParser = $parser ?: new VersionParser();
13879 $this->strictName = $strictName;
13880 $this->flags = $flags;
13881 }
13882
13883 public function load(array $config, $class = 'Composer\Package\CompletePackage')
13884 {
13885 $this->errors = array();
13886 $this->warnings = array();
13887 $this->config = $config;
13888
13889 if ($this->strictName) {
13890 $this->validateRegex('name', '[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*', true);
13891 } else {
13892 $this->validateString('name', true);
13893 }
13894
13895 if (!empty($this->config['version'])) {
13896 try {
13897 $this->versionParser->normalize($this->config['version']);
13898 } catch (\Exception $e) {
13899 $this->errors[] = 'version : invalid value ('.$this->config['version'].'): '.$e->getMessage();
13900 unset($this->config['version']);
13901 }
13902 }
13903
13904 $this->validateRegex('type', '[A-Za-z0-9-]+');
13905 $this->validateString('target-dir');
13906 $this->validateArray('extra');
13907 $this->validateFlatArray('bin');
13908 $this->validateArray('scripts'); 
13909  $this->validateString('description');
13910 $this->validateUrl('homepage');
13911 $this->validateFlatArray('keywords', '[A-Za-z0-9 ._-]+');
13912
13913 if (isset($this->config['license'])) {
13914 if (is_string($this->config['license'])) {
13915 $this->validateRegex('license', '[A-Za-z0-9+. ()-]+');
13916 } else {
13917 $this->validateFlatArray('license', '[A-Za-z0-9+. ()-]+');
13918 }
13919 }
13920
13921 $this->validateString('time');
13922 if (!empty($this->config['time'])) {
13923 try {
13924 $date = new \DateTime($this->config['time'], new \DateTimeZone('UTC'));
13925 } catch (\Exception $e) {
13926 $this->errors[] = 'time : invalid value ('.$this->config['time'].'): '.$e->getMessage();
13927 unset($this->config['time']);
13928 }
13929 }
13930
13931 if ($this->validateArray('authors') && !empty($this->config['authors'])) {
13932 foreach ($this->config['authors'] as $key => $author) {
13933 if (!is_array($author)) {
13934 $this->errors[] = 'authors.'.$key.' : should be an array, '.gettype($author).' given';
13935 unset($this->config['authors'][$key]);
13936 continue;
13937 }
13938 foreach (array('homepage', 'email', 'name', 'role') as $authorData) {
13939 if (isset($author[$authorData]) && !is_string($author[$authorData])) {
13940 $this->errors[] = 'authors.'.$key.'.'.$authorData.' : invalid value, must be a string';
13941 unset($this->config['authors'][$key][$authorData]);
13942 }
13943 }
13944 if (isset($author['homepage']) && !$this->filterUrl($author['homepage'])) {
13945 $this->warnings[] = 'authors.'.$key.'.homepage : invalid value ('.$author['homepage'].'), must be an http/https URL';
13946 unset($this->config['authors'][$key]['homepage']);
13947 }
13948 if (isset($author['email']) && !filter_var($author['email'], FILTER_VALIDATE_EMAIL)) {
13949 $this->warnings[] = 'authors.'.$key.'.email : invalid value ('.$author['email'].'), must be a valid email address';
13950 unset($this->config['authors'][$key]['email']);
13951 }
13952 if (empty($this->config['authors'][$key])) {
13953 unset($this->config['authors'][$key]);
13954 }
13955 }
13956 if (empty($this->config['authors'])) {
13957 unset($this->config['authors']);
13958 }
13959 }
13960
13961 if ($this->validateArray('support') && !empty($this->config['support'])) {
13962 foreach (array('issues', 'forum', 'wiki', 'source', 'email', 'irc') as $key) {
13963 if (isset($this->config['support'][$key]) && !is_string($this->config['support'][$key])) {
13964 $this->errors[] = 'support.'.$key.' : invalid value, must be a string';
13965 unset($this->config['support'][$key]);
13966 }
13967 }
13968
13969 if (isset($this->config['support']['email']) && !filter_var($this->config['support']['email'], FILTER_VALIDATE_EMAIL)) {
13970 $this->warnings[] = 'support.email : invalid value ('.$this->config['support']['email'].'), must be a valid email address';
13971 unset($this->config['support']['email']);
13972 }
13973
13974 if (isset($this->config['support']['irc']) && !$this->filterUrl($this->config['support']['irc'], array('irc'))) {
13975 $this->warnings[] = 'support.irc : invalid value ('.$this->config['support']['irc'].'), must be a irc://<server>/<channel> URL';
13976 unset($this->config['support']['irc']);
13977 }
13978
13979 foreach (array('issues', 'forum', 'wiki', 'source') as $key) {
13980 if (isset($this->config['support'][$key]) && !$this->filterUrl($this->config['support'][$key])) {
13981 $this->warnings[] = 'support.'.$key.' : invalid value ('.$this->config['support'][$key].'), must be an http/https URL';
13982 unset($this->config['support'][$key]);
13983 }
13984 }
13985 if (empty($this->config['support'])) {
13986 unset($this->config['support']);
13987 }
13988 }
13989
13990 $unboundConstraint = new VersionConstraint('=', $this->versionParser->normalize('dev-master'));
13991
13992 foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
13993 if ($this->validateArray($linkType) && isset($this->config[$linkType])) {
13994 foreach ($this->config[$linkType] as $package => $constraint) {
13995 if (!preg_match('{^[A-Za-z0-9_./-]+$}', $package)) {
13996 $this->warnings[] = $linkType.'.'.$package.' : invalid key, package names must be strings containing only [A-Za-z0-9_./-]';
13997 }
13998 if (!is_string($constraint)) {
13999 $this->errors[] = $linkType.'.'.$package.' : invalid value, must be a string containing a version constraint';
14000 unset($this->config[$linkType][$package]);
14001 } elseif ('self.version' !== $constraint) {
14002 try {
14003 $linkConstraint = $this->versionParser->parseConstraints($constraint);
14004 } catch (\Exception $e) {
14005 $this->errors[] = $linkType.'.'.$package.' : invalid version constraint ('.$e->getMessage().')';
14006 unset($this->config[$linkType][$package]);
14007 continue;
14008 }
14009
14010
14011  if (
14012 ($this->flags & self::CHECK_UNBOUND_CONSTRAINTS)
14013 && 'require' === $linkType
14014 && $linkConstraint->matches($unboundConstraint)
14015 && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $package)
14016 ) {
14017 $this->warnings[] = $linkType.'.'.$package.' : unbound version constraints ('.$constraint.') should be avoided';
14018 }
14019 }
14020 }
14021 }
14022 }
14023
14024 if ($this->validateArray('suggest') && !empty($this->config['suggest'])) {
14025 foreach ($this->config['suggest'] as $package => $description) {
14026 if (!is_string($description)) {
14027 $this->errors[] = 'suggest.'.$package.' : invalid value, must be a string describing why the package is suggested';
14028 unset($this->config['suggest'][$package]);
14029 }
14030 }
14031 }
14032
14033 if ($this->validateString('minimum-stability') && !empty($this->config['minimum-stability'])) {
14034 if (!isset(BasePackage::$stabilities[$this->config['minimum-stability']])) {
14035 $this->errors[] = 'minimum-stability : invalid value ('.$this->config['minimum-stability'].'), must be one of '.implode(', ', array_keys(BasePackage::$stabilities));
14036 unset($this->config['minimum-stability']);
14037 }
14038 }
14039
14040 if ($this->validateArray('autoload') && !empty($this->config['autoload'])) {
14041 $types = array('psr-0', 'psr-4', 'classmap', 'files');
14042 foreach ($this->config['autoload'] as $type => $typeConfig) {
14043 if (!in_array($type, $types)) {
14044 $this->errors[] = 'autoload : invalid value ('.$type.'), must be one of '.implode(', ', $types);
14045 unset($this->config['autoload'][$type]);
14046 }
14047 if ($type === 'psr-4') {
14048 foreach ($typeConfig as $namespace => $dirs) {
14049 if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
14050 $this->errors[] = 'autoload.psr-4 : invalid value ('.$namespace.'), namespaces must end with a namespace separator, should be '.$namespace.'\\';
14051 }
14052 }
14053 }
14054 }
14055 }
14056
14057 if (!empty($this->config['autoload']['psr-4']) && !empty($this->config['target-dir'])) {
14058 $this->errors[] = 'target-dir : this can not be used together with the autoload.psr-4 setting, remove target-dir to upgrade to psr-4';
14059
14060  
14061  unset($this->config['autoload']['psr-4']);
14062 }
14063
14064
14065  
14066
14067
14068  
14069
14070 $this->validateFlatArray('include-path');
14071 $this->validateArray('transport-options');
14072
14073
14074  if (isset($this->config['extra']['branch-alias'])) {
14075 if (!is_array($this->config['extra']['branch-alias'])) {
14076 $this->errors[] = 'extra.branch-alias : must be an array of versions => aliases';
14077 } else {
14078 foreach ($this->config['extra']['branch-alias'] as $sourceBranch => $targetBranch) {
14079
14080  if ('-dev' !== substr($targetBranch, -4)) {
14081 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must end in -dev';
14082 unset($this->config['extra']['branch-alias'][$sourceBranch]);
14083
14084 continue;
14085 }
14086
14087
14088  $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4));
14089 if ('-dev' !== substr($validatedTargetBranch, -4)) {
14090 $this->warnings[] = 'extra.branch-alias.'.$sourceBranch.' : the target branch ('.$targetBranch.') must be a parseable number like 2.0-dev';
14091 unset($this->config['extra']['branch-alias'][$sourceBranch]);
14092 }
14093 }
14094 }
14095 }
14096
14097 if ($this->errors) {
14098 throw new InvalidPackageException($this->errors, $this->warnings, $config);
14099 }
14100
14101 $package = $this->loader->load($this->config, $class);
14102 $this->config = null;
14103
14104 return $package;
14105 }
14106
14107 public function getWarnings()
14108 {
14109 return $this->warnings;
14110 }
14111
14112 public function getErrors()
14113 {
14114 return $this->errors;
14115 }
14116
14117 private function validateRegex($property, $regex, $mandatory = false)
14118 {
14119 if (!$this->validateString($property, $mandatory)) {
14120 return false;
14121 }
14122
14123 if (!preg_match('{^'.$regex.'$}u', $this->config[$property])) {
14124 $message = $property.' : invalid value ('.$this->config[$property].'), must match '.$regex;
14125 if ($mandatory) {
14126 $this->errors[] = $message;
14127 } else {
14128 $this->warnings[] = $message;
14129 }
14130 unset($this->config[$property]);
14131
14132 return false;
14133 }
14134
14135 return true;
14136 }
14137
14138 private function validateString($property, $mandatory = false)
14139 {
14140 if (isset($this->config[$property]) && !is_string($this->config[$property])) {
14141 $this->errors[] = $property.' : should be a string, '.gettype($this->config[$property]).' given';
14142 unset($this->config[$property]);
14143
14144 return false;
14145 }
14146
14147 if (!isset($this->config[$property]) || trim($this->config[$property]) === '') {
14148 if ($mandatory) {
14149 $this->errors[] = $property.' : must be present';
14150 }
14151 unset($this->config[$property]);
14152
14153 return false;
14154 }
14155
14156 return true;
14157 }
14158
14159 private function validateArray($property, $mandatory = false)
14160 {
14161 if (isset($this->config[$property]) && !is_array($this->config[$property])) {
14162 $this->errors[] = $property.' : should be an array, '.gettype($this->config[$property]).' given';
14163 unset($this->config[$property]);
14164
14165 return false;
14166 }
14167
14168 if (!isset($this->config[$property]) || !count($this->config[$property])) {
14169 if ($mandatory) {
14170 $this->errors[] = $property.' : must be present and contain at least one element';
14171 }
14172 unset($this->config[$property]);
14173
14174 return false;
14175 }
14176
14177 return true;
14178 }
14179
14180 private function validateFlatArray($property, $regex = null, $mandatory = false)
14181 {
14182 if (!$this->validateArray($property, $mandatory)) {
14183 return false;
14184 }
14185
14186 $pass = true;
14187 foreach ($this->config[$property] as $key => $value) {
14188 if (!is_string($value) && !is_numeric($value)) {
14189 $this->errors[] = $property.'.'.$key.' : must be a string or int, '.gettype($value).' given';
14190 unset($this->config[$property][$key]);
14191 $pass = false;
14192
14193 continue;
14194 }
14195
14196 if ($regex && !preg_match('{^'.$regex.'$}u', $value)) {
14197 $this->warnings[] = $property.'.'.$key.' : invalid value ('.$value.'), must match '.$regex;
14198 unset($this->config[$property][$key]);
14199 $pass = false;
14200 }
14201 }
14202
14203 return $pass;
14204 }
14205
14206 private function validateUrl($property, $mandatory = false)
14207 {
14208 if (!$this->validateString($property, $mandatory)) {
14209 return false;
14210 }
14211
14212 if (!$this->filterUrl($this->config[$property])) {
14213 $this->warnings[] = $property.' : invalid value ('.$this->config[$property].'), must be an http/https URL';
14214 unset($this->config[$property]);
14215
14216 return false;
14217 }
14218
14219 return true;
14220 }
14221
14222 private function filterUrl($value, array $schemes = array('http', 'https'))
14223 {
14224 if ($value === '') {
14225 return true;
14226 }
14227
14228 $bits = parse_url($value);
14229 if (empty($bits['scheme']) || empty($bits['host'])) {
14230 return false;
14231 }
14232
14233 if (!in_array($bits['scheme'], $schemes, true)) {
14234 return false;
14235 }
14236
14237 return true;
14238 }
14239 }
14240 <?php
14241
14242
14243
14244
14245
14246
14247
14248
14249
14250
14251
14252 namespace Composer\Package\Loader;
14253
14254 use Composer\Package\BasePackage;
14255 use Composer\Package\AliasPackage;
14256 use Composer\Config;
14257 use Composer\Factory;
14258 use Composer\Package\Version\VersionParser;
14259 use Composer\Repository\RepositoryManager;
14260 use Composer\Repository\Vcs\HgDriver;
14261 use Composer\IO\NullIO;
14262 use Composer\Util\ProcessExecutor;
14263 use Composer\Util\Git as GitUtil;
14264 use Composer\Util\Svn as SvnUtil;
14265
14266
14267
14268
14269
14270
14271
14272
14273 class RootPackageLoader extends ArrayLoader
14274 {
14275 private $manager;
14276 private $config;
14277 private $process;
14278
14279 public function __construct(RepositoryManager $manager, Config $config, VersionParser $parser = null, ProcessExecutor $process = null)
14280 {
14281 $this->manager = $manager;
14282 $this->config = $config;
14283 $this->process = $process ?: new ProcessExecutor();
14284 parent::__construct($parser);
14285 }
14286
14287 public function load(array $config, $class = 'Composer\Package\RootPackage')
14288 {
14289 if (!isset($config['name'])) {
14290 $config['name'] = '__root__';
14291 }
14292 if (!isset($config['version'])) {
14293
14294  if (getenv('COMPOSER_ROOT_VERSION')) {
14295 $version = getenv('COMPOSER_ROOT_VERSION');
14296 } else {
14297 $version = $this->guessVersion($config);
14298 }
14299
14300 if (!$version) {
14301 $version = '1.0.0';
14302 }
14303
14304 $config['version'] = $version;
14305 }
14306
14307 $realPackage = $package = parent::load($config, $class);
14308
14309 if ($realPackage instanceof AliasPackage) {
14310 $realPackage = $package->getAliasOf();
14311 }
14312
14313 if (isset($config['minimum-stability'])) {
14314 $realPackage->setMinimumStability(VersionParser::normalizeStability($config['minimum-stability']));
14315 }
14316
14317 $aliases = array();
14318 $stabilityFlags = array();
14319 $references = array();
14320 foreach (array('require', 'require-dev') as $linkType) {
14321 if (isset($config[$linkType])) {
14322 $linkInfo = BasePackage::$supportedLinkTypes[$linkType];
14323 $method = 'get'.ucfirst($linkInfo['method']);
14324 $links = array();
14325 foreach ($realPackage->$method() as $link) {
14326 $links[$link->getTarget()] = $link->getConstraint()->getPrettyString();
14327 }
14328 $aliases = $this->extractAliases($links, $aliases);
14329 $stabilityFlags = $this->extractStabilityFlags($links, $stabilityFlags, $realPackage->getMinimumStability());
14330 $references = $this->extractReferences($links, $references);
14331 }
14332 }
14333
14334 $realPackage->setAliases($aliases);
14335 $realPackage->setStabilityFlags($stabilityFlags);
14336 $realPackage->setReferences($references);
14337
14338 if (isset($config['prefer-stable'])) {
14339 $realPackage->setPreferStable((bool) $config['prefer-stable']);
14340 }
14341
14342 $repos = Factory::createDefaultRepositories(null, $this->config, $this->manager);
14343 foreach ($repos as $repo) {
14344 $this->manager->addRepository($repo);
14345 }
14346 $realPackage->setRepositories($this->config->getRepositories());
14347
14348 return $package;
14349 }
14350
14351 private function extractAliases(array $requires, array $aliases)
14352 {
14353 foreach ($requires as $reqName => $reqVersion) {
14354 if (preg_match('{^([^,\s#]+)(?:#[^ ]+)? +as +([^,\s]+)$}', $reqVersion, $match)) {
14355 $aliases[] = array(
14356 'package' => strtolower($reqName),
14357 'version' => $this->versionParser->normalize($match[1], $reqVersion),
14358 'alias' => $match[2],
14359 'alias_normalized' => $this->versionParser->normalize($match[2], $reqVersion),
14360 );
14361 }
14362 }
14363
14364 return $aliases;
14365 }
14366
14367 private function extractStabilityFlags(array $requires, array $stabilityFlags, $minimumStability)
14368 {
14369 $stabilities = BasePackage::$stabilities;
14370 $minimumStability = $stabilities[$minimumStability];
14371 foreach ($requires as $reqName => $reqVersion) {
14372
14373  if (preg_match('{^[^@]*?@('.implode('|', array_keys($stabilities)).')$}i', $reqVersion, $match)) {
14374 $name = strtolower($reqName);
14375 $stability = $stabilities[VersionParser::normalizeStability($match[1])];
14376
14377 if (isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) {
14378 continue;
14379 }
14380 $stabilityFlags[$name] = $stability;
14381
14382 continue;
14383 }
14384
14385
14386  
14387  $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
14388 if (preg_match('{^[^,\s@]+$}', $reqVersion) && 'stable' !== ($stabilityName = VersionParser::parseStability($reqVersion))) {
14389 $name = strtolower($reqName);
14390 $stability = $stabilities[$stabilityName];
14391 if ((isset($stabilityFlags[$name]) && $stabilityFlags[$name] > $stability) || ($minimumStability > $stability)) {
14392 continue;
14393 }
14394 $stabilityFlags[$name] = $stability;
14395 }
14396 }
14397
14398 return $stabilityFlags;
14399 }
14400
14401 private function extractReferences(array $requires, array $references)
14402 {
14403 foreach ($requires as $reqName => $reqVersion) {
14404 $reqVersion = preg_replace('{^([^,\s@]+) as .+$}', '$1', $reqVersion);
14405 if (preg_match('{^[^,\s@]+?#([a-f0-9]+)$}', $reqVersion, $match) && 'dev' === ($stabilityName = VersionParser::parseStability($reqVersion))) {
14406 $name = strtolower($reqName);
14407 $references[$name] = $match[1];
14408 }
14409 }
14410
14411 return $references;
14412 }
14413
14414 private function guessVersion(array $config)
14415 {
14416 if (function_exists('proc_open')) {
14417 $version = $this->guessGitVersion($config);
14418 if (null !== $version) {
14419 return $version;
14420 }
14421
14422 $version = $this->guessHgVersion($config);
14423 if (null !== $version) {
14424 return $version;
14425 }
14426
14427 return $this->guessSvnVersion($config);
14428 }
14429 }
14430
14431 private function guessGitVersion(array $config)
14432 {
14433 GitUtil::cleanEnv();
14434
14435
14436  if (0 === $this->process->execute('git describe --exact-match --tags', $output)) {
14437 try {
14438 return $this->versionParser->normalize(trim($output));
14439 } catch (\Exception $e) {
14440 }
14441 }
14442
14443
14444  if (0 === $this->process->execute('git branch --no-color --no-abbrev -v', $output)) {
14445 $branches = array();
14446 $isFeatureBranch = false;
14447 $version = null;
14448
14449
14450  foreach ($this->process->splitLines($output) as $branch) {
14451 if ($branch && preg_match('{^(?:\* ) *(\(no branch\)|\(detached from \S+\)|\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
14452 if ($match[1] === '(no branch)' || substr($match[1], 0, 10) === '(detached ') {
14453 $version = 'dev-'.$match[2];
14454 $isFeatureBranch = true;
14455 } else {
14456 $version = $this->versionParser->normalizeBranch($match[1]);
14457 $isFeatureBranch = 0 === strpos($version, 'dev-');
14458 if ('9999999-dev' === $version) {
14459 $version = 'dev-'.$match[1];
14460 }
14461 }
14462 }
14463
14464 if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) {
14465 if (preg_match('{^(?:\* )? *(\S+) *([a-f0-9]+) .*$}', $branch, $match)) {
14466 $branches[] = $match[1];
14467 }
14468 }
14469 }
14470
14471 if (!$isFeatureBranch) {
14472 return $version;
14473 }
14474
14475
14476  $version = $this->guessFeatureVersion($config, $version, $branches, 'git rev-list %candidate%..%branch%');
14477
14478 return $version;
14479 }
14480 }
14481
14482 private function guessHgVersion(array $config)
14483 {
14484
14485  if (0 === $this->process->execute('hg branch', $output)) {
14486 $branch = trim($output);
14487 $version = $this->versionParser->normalizeBranch($branch);
14488 $isFeatureBranch = 0 === strpos($version, 'dev-');
14489
14490 if ('9999999-dev' === $version) {
14491 $version = 'dev-'.$branch;
14492 }
14493
14494 if (!$isFeatureBranch) {
14495 return $version;
14496 }
14497
14498
14499  $config = array('url' => getcwd());
14500 $driver = new HgDriver($config, new NullIO(), $this->config, $this->process);
14501 $branches = array_keys($driver->getBranches());
14502
14503
14504  $version = $this->guessFeatureVersion($config, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"');
14505
14506 return $version;
14507 }
14508 }
14509
14510 private function guessFeatureVersion(array $config, $version, array $branches, $scmCmdline)
14511 {
14512
14513  
14514  if ((isset($config['extra']['branch-alias']) && !isset($config['extra']['branch-alias'][$version]))
14515 || strpos(json_encode($config), '"self.version"')
14516 ) {
14517 $branch = preg_replace('{^dev-}', '', $version);
14518 $length = PHP_INT_MAX;
14519 foreach ($branches as $candidate) {
14520
14521  if ($candidate === $branch || !preg_match('{^(master|trunk|default|develop|\d+\..+)$}', $candidate, $match)) {
14522 continue;
14523 }
14524
14525 $cmdLine = str_replace(array('%candidate%', '%branch%'), array($candidate, $branch), $scmCmdline);
14526 if (0 !== $this->process->execute($cmdLine, $output)) {
14527 continue;
14528 }
14529
14530 if (strlen($output) < $length) {
14531 $length = strlen($output);
14532 $version = $this->versionParser->normalizeBranch($candidate);
14533 if ('9999999-dev' === $version) {
14534 $version = 'dev-'.$match[1];
14535 }
14536 }
14537 }
14538 }
14539
14540 return $version;
14541 }
14542
14543 private function guessSvnVersion(array $config)
14544 {
14545 SvnUtil::cleanEnv();
14546
14547
14548  if (0 === $this->process->execute('svn info --xml', $output)) {
14549 $trunkPath = isset($config['trunk-path']) ? preg_quote($config['trunk-path'], '#') : 'trunk';
14550 $branchesPath = isset($config['branches-path']) ? preg_quote($config['branches-path'], '#') : 'branches';
14551 $tagsPath = isset($config['tags-path']) ? preg_quote($config['tags-path'], '#') : 'tags';
14552
14553 $urlPattern = '#<url>.*/('.$trunkPath.'|('.$branchesPath.'|'. $tagsPath .')/(.*))</url>#';
14554
14555 if (preg_match($urlPattern, $output, $matches)) {
14556 if (isset($matches[2]) && ($branchesPath === $matches[2] || $tagsPath === $matches[2])) {
14557
14558  $version = $this->versionParser->normalizeBranch($matches[3]);
14559 if ('9999999-dev' === $version) {
14560 $version = 'dev-'.$matches[3];
14561 }
14562
14563 return $version;
14564 }
14565
14566 return $this->versionParser->normalize(trim($matches[1]));
14567 }
14568 }
14569 }
14570 }
14571 <?php
14572
14573
14574
14575
14576
14577
14578
14579
14580
14581
14582
14583 namespace Composer\Package;
14584
14585 use Composer\Json\JsonFile;
14586 use Composer\Installer\InstallationManager;
14587 use Composer\Repository\RepositoryManager;
14588 use Composer\Util\ProcessExecutor;
14589 use Composer\Repository\ArrayRepository;
14590 use Composer\Package\Dumper\ArrayDumper;
14591 use Composer\Package\Loader\ArrayLoader;
14592 use Composer\Package\Version\VersionParser;
14593 use Composer\Util\Git as GitUtil;
14594 use Composer\IO\IOInterface;
14595
14596
14597
14598
14599
14600
14601
14602 class Locker
14603 {
14604 private $lockFile;
14605 private $repositoryManager;
14606 private $installationManager;
14607 private $hash;
14608 private $loader;
14609 private $dumper;
14610 private $process;
14611 private $lockDataCache;
14612
14613
14614
14615
14616
14617
14618
14619
14620
14621
14622 public function __construct(IOInterface $io, JsonFile $lockFile, RepositoryManager $repositoryManager, InstallationManager $installationManager, $hash)
14623 {
14624 $this->lockFile = $lockFile;
14625 $this->repositoryManager = $repositoryManager;
14626 $this->installationManager = $installationManager;
14627 $this->hash = $hash;
14628 $this->loader = new ArrayLoader(null, true);
14629 $this->dumper = new ArrayDumper();
14630 $this->process = new ProcessExecutor($io);
14631 }
14632
14633
14634
14635
14636
14637
14638 public function isLocked()
14639 {
14640 if (!$this->lockFile->exists()) {
14641 return false;
14642 }
14643
14644 $data = $this->getLockData();
14645
14646 return isset($data['packages']);
14647 }
14648
14649
14650
14651
14652
14653
14654 public function isFresh()
14655 {
14656 $lock = $this->lockFile->read();
14657
14658 return $this->hash === $lock['hash'];
14659 }
14660
14661
14662
14663
14664
14665
14666
14667
14668 public function getLockedRepository($withDevReqs = false)
14669 {
14670 $lockData = $this->getLockData();
14671 $packages = new ArrayRepository();
14672
14673 $lockedPackages = $lockData['packages'];
14674 if ($withDevReqs) {
14675 if (isset($lockData['packages-dev'])) {
14676 $lockedPackages = array_merge($lockedPackages, $lockData['packages-dev']);
14677 } else {
14678 throw new \RuntimeException('The lock file does not contain require-dev information, run install with the --no-dev option or run update to install those packages.');
14679 }
14680 }
14681
14682 if (empty($lockedPackages)) {
14683 return $packages;
14684 }
14685
14686 if (isset($lockedPackages[0]['name'])) {
14687 foreach ($lockedPackages as $info) {
14688 $packages->addPackage($this->loader->load($info));
14689 }
14690
14691 return $packages;
14692 }
14693
14694 throw new \RuntimeException('Your composer.lock was created before 2012-09-15, and is not supported anymore. Run "composer update" to generate a new one.');
14695 }
14696
14697
14698
14699
14700
14701
14702
14703 public function getPlatformRequirements($withDevReqs = false)
14704 {
14705 $lockData = $this->getLockData();
14706 $versionParser = new VersionParser();
14707 $requirements = array();
14708
14709 if (!empty($lockData['platform'])) {
14710 $requirements = $versionParser->parseLinks(
14711 '__ROOT__',
14712 '1.0.0',
14713 'requires',
14714 isset($lockData['platform']) ? $lockData['platform'] : array()
14715 );
14716 }
14717
14718 if ($withDevReqs && !empty($lockData['platform-dev'])) {
14719 $devRequirements = $versionParser->parseLinks(
14720 '__ROOT__',
14721 '1.0.0',
14722 'requires',
14723 isset($lockData['platform-dev']) ? $lockData['platform-dev'] : array()
14724 );
14725
14726 $requirements = array_merge($requirements, $devRequirements);
14727 }
14728
14729 return $requirements;
14730 }
14731
14732 public function getMinimumStability()
14733 {
14734 $lockData = $this->getLockData();
14735
14736 return isset($lockData['minimum-stability']) ? $lockData['minimum-stability'] : 'stable';
14737 }
14738
14739 public function getStabilityFlags()
14740 {
14741 $lockData = $this->getLockData();
14742
14743 return isset($lockData['stability-flags']) ? $lockData['stability-flags'] : array();
14744 }
14745
14746 public function getPreferStable()
14747 {
14748 $lockData = $this->getLockData();
14749
14750
14751  
14752  return isset($lockData['prefer-stable']) ? $lockData['prefer-stable'] : null;
14753 }
14754
14755 public function getPreferLowest()
14756 {
14757 $lockData = $this->getLockData();
14758
14759
14760  
14761  return isset($lockData['prefer-lowest']) ? $lockData['prefer-lowest'] : null;
14762 }
14763
14764 public function getAliases()
14765 {
14766 $lockData = $this->getLockData();
14767
14768 return isset($lockData['aliases']) ? $lockData['aliases'] : array();
14769 }
14770
14771 public function getLockData()
14772 {
14773 if (null !== $this->lockDataCache) {
14774 return $this->lockDataCache;
14775 }
14776
14777 if (!$this->lockFile->exists()) {
14778 throw new \LogicException('No lockfile found. Unable to read locked packages');
14779 }
14780
14781 return $this->lockDataCache = $this->lockFile->read();
14782 }
14783
14784
14785
14786
14787
14788
14789
14790
14791
14792
14793
14794
14795
14796
14797
14798
14799 public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable, $preferLowest)
14800 {
14801 $lock = array(
14802 '_readme' => array('This file locks the dependencies of your project to a known state',
14803 'Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file',
14804 'This file is @gener'.'ated automatically'),
14805 'hash' => $this->hash,
14806 'packages' => null,
14807 'packages-dev' => null,
14808 'aliases' => array(),
14809 'minimum-stability' => $minimumStability,
14810 'stability-flags' => $stabilityFlags,
14811 'prefer-stable' => $preferStable,
14812 'prefer-lowest' => $preferLowest,
14813 );
14814
14815 foreach ($aliases as $package => $versions) {
14816 foreach ($versions as $version => $alias) {
14817 $lock['aliases'][] = array(
14818 'alias' => $alias['alias'],
14819 'alias_normalized' => $alias['alias_normalized'],
14820 'version' => $version,
14821 'package' => $package,
14822 );
14823 }
14824 }
14825
14826 $lock['packages'] = $this->lockPackages($packages);
14827 if (null !== $devPackages) {
14828 $lock['packages-dev'] = $this->lockPackages($devPackages);
14829 }
14830
14831 if (empty($lock['packages']) && empty($lock['packages-dev'])) {
14832 if ($this->lockFile->exists()) {
14833 unlink($this->lockFile->getPath());
14834 }
14835
14836 return false;
14837 }
14838
14839 $lock['platform'] = $platformReqs;
14840 $lock['platform-dev'] = $platformDevReqs;
14841
14842 if (!$this->isLocked() || $lock !== $this->getLockData()) {
14843 $this->lockFile->write($lock);
14844 $this->lockDataCache = null;
14845
14846 return true;
14847 }
14848
14849 return false;
14850 }
14851
14852 private function lockPackages(array $packages)
14853 {
14854 $locked = array();
14855
14856 foreach ($packages as $package) {
14857 if ($package instanceof AliasPackage) {
14858 continue;
14859 }
14860
14861 $name = $package->getPrettyName();
14862 $version = $package->getPrettyVersion();
14863
14864 if (!$name || !$version) {
14865 throw new \LogicException(sprintf(
14866 'Package "%s" has no version or name and can not be locked', $package
14867 ));
14868 }
14869
14870 $spec = $this->dumper->dump($package);
14871 unset($spec['version_normalized']);
14872
14873
14874  $time = isset($spec['time']) ? $spec['time'] : null;
14875 unset($spec['time']);
14876 if ($package->isDev() && $package->getInstallationSource() === 'source') {
14877
14878  $time = $this->getPackageTime($package) ?: $time;
14879 }
14880 if (null !== $time) {
14881 $spec['time'] = $time;
14882 }
14883
14884 unset($spec['installation-source']);
14885
14886 $locked[] = $spec;
14887 }
14888
14889 usort($locked, function ($a, $b) {
14890 $comparison = strcmp($a['name'], $b['name']);
14891
14892 if (0 !== $comparison) {
14893 return $comparison;
14894 }
14895
14896
14897  return strcmp($a['version'], $b['version']);
14898 });
14899
14900 return $locked;
14901 }
14902
14903
14904
14905
14906
14907
14908
14909 private function getPackageTime(PackageInterface $package)
14910 {
14911 if (!function_exists('proc_open')) {
14912 return null;
14913 }
14914
14915 $path = realpath($this->installationManager->getInstallPath($package));
14916 $sourceType = $package->getSourceType();
14917 $datetime = null;
14918
14919 if ($path && in_array($sourceType, array('git', 'hg'))) {
14920 $sourceRef = $package->getSourceReference() ?: $package->getDistReference();
14921 switch ($sourceType) {
14922 case 'git':
14923 GitUtil::cleanEnv();
14924
14925 if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef), $output, $path) && preg_match('{^\s*\d+\s*$}', $output)) {
14926 $datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC'));
14927 }
14928 break;
14929
14930 case 'hg':
14931 if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r '.ProcessExecutor::escape($sourceRef), $output, $path) && preg_match('{^\s*(\d+)\s*}', $output, $match)) {
14932 $datetime = new \DateTime('@'.$match[1], new \DateTimeZone('UTC'));
14933 }
14934 break;
14935 }
14936 }
14937
14938 return $datetime ? $datetime->format('Y-m-d H:i:s') : null;
14939 }
14940 }
14941 <?php
14942
14943
14944
14945
14946
14947
14948
14949
14950
14951
14952
14953 namespace Composer\Package;
14954
14955 use Composer\Repository\RepositoryInterface;
14956
14957
14958
14959
14960
14961
14962 interface PackageInterface
14963 {
14964
14965
14966
14967
14968
14969 public function getName();
14970
14971
14972
14973
14974
14975
14976 public function getPrettyName();
14977
14978
14979
14980
14981
14982
14983
14984
14985
14986 public function getNames();
14987
14988
14989
14990
14991
14992
14993 public function setId($id);
14994
14995
14996
14997
14998
14999
15000 public function getId();
15001
15002
15003
15004
15005
15006
15007 public function isDev();
15008
15009
15010
15011
15012
15013
15014 public function getType();
15015
15016
15017
15018
15019
15020
15021 public function getTargetDir();
15022
15023
15024
15025
15026
15027
15028 public function getExtra();
15029
15030
15031
15032
15033
15034
15035 public function setInstallationSource($type);
15036
15037
15038
15039
15040
15041
15042 public function getInstallationSource();
15043
15044
15045
15046
15047
15048
15049 public function getSourceType();
15050
15051
15052
15053
15054
15055
15056 public function getSourceUrl();
15057
15058
15059
15060
15061
15062
15063 public function getSourceUrls();
15064
15065
15066
15067
15068
15069
15070 public function getSourceReference();
15071
15072
15073
15074
15075
15076
15077 public function getSourceMirrors();
15078
15079
15080
15081
15082
15083
15084 public function getDistType();
15085
15086
15087
15088
15089
15090
15091 public function getDistUrl();
15092
15093
15094
15095
15096
15097
15098 public function getDistUrls();
15099
15100
15101
15102
15103
15104
15105 public function getDistReference();
15106
15107
15108
15109
15110
15111
15112 public function getDistSha1Checksum();
15113
15114
15115
15116
15117
15118
15119 public function getDistMirrors();
15120
15121
15122
15123
15124
15125
15126 public function getVersion();
15127
15128
15129
15130
15131
15132
15133 public function getPrettyVersion();
15134
15135
15136
15137
15138
15139
15140 public function getReleaseDate();
15141
15142
15143
15144
15145
15146
15147 public function getStability();
15148
15149
15150
15151
15152
15153
15154
15155 public function getRequires();
15156
15157
15158
15159
15160
15161
15162
15163 public function getConflicts();
15164
15165
15166
15167
15168
15169
15170
15171 public function getProvides();
15172
15173
15174
15175
15176
15177
15178
15179 public function getReplaces();
15180
15181
15182
15183
15184
15185
15186
15187 public function getDevRequires();
15188
15189
15190
15191
15192
15193
15194
15195 public function getSuggests();
15196
15197
15198
15199
15200
15201
15202
15203
15204
15205
15206
15207 public function getAutoload();
15208
15209
15210
15211
15212
15213
15214
15215
15216
15217
15218
15219 public function getDevAutoload();
15220
15221
15222
15223
15224
15225
15226
15227 public function getIncludePaths();
15228
15229
15230
15231
15232
15233
15234 public function setRepository(RepositoryInterface $repository);
15235
15236
15237
15238
15239
15240
15241 public function getRepository();
15242
15243
15244
15245
15246
15247
15248 public function getBinaries();
15249
15250
15251
15252
15253
15254
15255 public function getUniqueName();
15256
15257
15258
15259
15260
15261
15262 public function getNotificationUrl();
15263
15264
15265
15266
15267
15268
15269 public function __toString();
15270
15271
15272
15273
15274
15275
15276 public function getPrettyString();
15277
15278
15279
15280
15281
15282
15283 public function getArchiveExcludes();
15284
15285
15286
15287
15288
15289
15290 public function getTransportOptions();
15291 }
15292 <?php
15293
15294
15295
15296
15297
15298
15299
15300
15301
15302
15303
15304 namespace Composer\Package;
15305
15306 use Composer\Repository\RepositoryInterface;
15307 use Composer\Repository\PlatformRepository;
15308
15309
15310
15311
15312
15313
15314 abstract class BasePackage implements PackageInterface
15315 {
15316 public static $supportedLinkTypes = array(
15317 'require' => array('description' => 'requires', 'method' => 'requires'),
15318 'conflict' => array('description' => 'conflicts', 'method' => 'conflicts'),
15319 'provide' => array('description' => 'provides', 'method' => 'provides'),
15320 'replace' => array('description' => 'replaces', 'method' => 'replaces'),
15321 'require-dev' => array('description' => 'requires (for development)', 'method' => 'devRequires'),
15322 );
15323
15324 const STABILITY_STABLE = 0;
15325 const STABILITY_RC = 5;
15326 const STABILITY_BETA = 10;
15327 const STABILITY_ALPHA = 15;
15328 const STABILITY_DEV = 20;
15329
15330 public static $stabilities = array(
15331 'stable' => self::STABILITY_STABLE,
15332 'RC' => self::STABILITY_RC,
15333 'beta' => self::STABILITY_BETA,
15334 'alpha' => self::STABILITY_ALPHA,
15335 'dev' => self::STABILITY_DEV,
15336 );
15337
15338
15339
15340
15341
15342 public $id;
15343
15344 protected $name;
15345 protected $prettyName;
15346
15347 protected $repository;
15348 protected $transportOptions;
15349
15350
15351
15352
15353
15354
15355 public function __construct($name)
15356 {
15357 $this->prettyName = $name;
15358 $this->name = strtolower($name);
15359 $this->id = -1;
15360 $this->transportOptions = array();
15361 }
15362
15363
15364
15365
15366 public function getName()
15367 {
15368 return $this->name;
15369 }
15370
15371
15372
15373
15374 public function getPrettyName()
15375 {
15376 return $this->prettyName;
15377 }
15378
15379
15380
15381
15382 public function getNames()
15383 {
15384 $names = array(
15385 $this->getName() => true,
15386 );
15387
15388 foreach ($this->getProvides() as $link) {
15389 $names[$link->getTarget()] = true;
15390 }
15391
15392 foreach ($this->getReplaces() as $link) {
15393 $names[$link->getTarget()] = true;
15394 }
15395
15396 return array_keys($names);
15397 }
15398
15399
15400
15401
15402 public function setId($id)
15403 {
15404 $this->id = $id;
15405 }
15406
15407
15408
15409
15410 public function getId()
15411 {
15412 return $this->id;
15413 }
15414
15415
15416
15417
15418 public function setRepository(RepositoryInterface $repository)
15419 {
15420 if ($this->repository && $repository !== $this->repository) {
15421 throw new \LogicException('A package can only be added to one repository');
15422 }
15423 $this->repository = $repository;
15424 }
15425
15426
15427
15428
15429 public function getRepository()
15430 {
15431 return $this->repository;
15432 }
15433
15434
15435
15436
15437 public function getTransportOptions()
15438 {
15439 return $this->transportOptions;
15440 }
15441
15442
15443
15444
15445
15446
15447 public function setTransportOptions(array $options)
15448 {
15449 $this->transportOptions = $options;
15450 }
15451
15452
15453
15454
15455
15456
15457 public function isPlatform()
15458 {
15459 return $this->getRepository() instanceof PlatformRepository;
15460 }
15461
15462
15463
15464
15465
15466
15467 public function getUniqueName()
15468 {
15469 return $this->getName().'-'.$this->getVersion();
15470 }
15471
15472 public function equals(PackageInterface $package)
15473 {
15474 $self = $this;
15475 if ($this instanceof AliasPackage) {
15476 $self = $this->getAliasOf();
15477 }
15478 if ($package instanceof AliasPackage) {
15479 $package = $package->getAliasOf();
15480 }
15481
15482 return $package === $self;
15483 }
15484
15485
15486
15487
15488
15489
15490 public function __toString()
15491 {
15492 return $this->getUniqueName();
15493 }
15494
15495 public function getPrettyString()
15496 {
15497 return $this->getPrettyName().' '.$this->getPrettyVersion();
15498 }
15499
15500 public function __clone()
15501 {
15502 $this->repository = null;
15503 $this->id = -1;
15504 }
15505 }
15506 <?php
15507
15508
15509
15510
15511
15512
15513
15514
15515
15516
15517
15518 namespace Composer\Package\Version;
15519
15520 use Composer\DependencyResolver\Pool;
15521 use Composer\Package\PackageInterface;
15522 use Composer\Package\Loader\ArrayLoader;
15523 use Composer\Package\Dumper\ArrayDumper;
15524
15525
15526
15527
15528
15529
15530 class VersionSelector
15531 {
15532 private $pool;
15533
15534 private $parser;
15535
15536 public function __construct(Pool $pool)
15537 {
15538 $this->pool = $pool;
15539 }
15540
15541
15542
15543
15544
15545
15546
15547
15548
15549 public function findBestCandidate($packageName, $targetPackageVersion = null)
15550 {
15551 $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null;
15552 $candidates = $this->pool->whatProvides($packageName, $constraint, true);
15553
15554 if (!$candidates) {
15555 return false;
15556 }
15557
15558
15559  $package = reset($candidates);
15560 foreach ($candidates as $candidate) {
15561 if (version_compare($package->getVersion(), $candidate->getVersion(), '<')) {
15562 $package = $candidate;
15563 }
15564 }
15565
15566 return $package;
15567 }
15568
15569
15570
15571
15572
15573
15574
15575
15576
15577
15578
15579
15580
15581
15582
15583
15584 public function findRecommendedRequireVersion(PackageInterface $package)
15585 {
15586 $version = $package->getVersion();
15587 if (!$package->isDev()) {
15588 return $this->transformVersion($version, $package->getPrettyVersion(), $package->getStability());
15589 }
15590
15591 $loader = new ArrayLoader($this->getParser());
15592 $dumper = new ArrayDumper();
15593 $extra = $loader->getBranchAlias($dumper->dump($package));
15594 if ($extra) {
15595 $extra = preg_replace('{^(\d+\.\d+\.\d+)(\.9999999)-dev$}', '$1.0', $extra, -1, $count);
15596 if ($count) {
15597 $extra = str_replace('.9999999', '.0', $extra);
15598
15599 return $this->transformVersion($extra, $extra, 'dev');
15600 }
15601 }
15602
15603 return $package->getPrettyVersion();
15604 }
15605
15606 private function transformVersion($version, $prettyVersion, $stability)
15607 {
15608
15609  
15610  $semanticVersionParts = explode('.', $version);
15611 $op = '~';
15612
15613
15614  if (count($semanticVersionParts) == 4 && preg_match('{^0\D?}', $semanticVersionParts[3])) {
15615
15616  if ($semanticVersionParts[0] === '0') {
15617 if ($semanticVersionParts[1] === '0') {
15618 $semanticVersionParts[3] = '*';
15619 } else {
15620 $semanticVersionParts[2] = '*';
15621 unset($semanticVersionParts[3]);
15622 }
15623 $op = '';
15624 } else {
15625 unset($semanticVersionParts[2], $semanticVersionParts[3]);
15626 }
15627 $version = implode('.', $semanticVersionParts);
15628 } else {
15629 return $prettyVersion;
15630 }
15631
15632
15633  if ($stability != 'stable') {
15634 $version .= '@'.$stability;
15635 }
15636
15637
15638  return $op.$version;
15639 }
15640
15641 private function getParser()
15642 {
15643 if ($this->parser === null) {
15644 $this->parser = new VersionParser();
15645 }
15646
15647 return $this->parser;
15648 }
15649 }
15650 <?php
15651
15652
15653
15654
15655
15656
15657
15658
15659
15660
15661
15662 namespace Composer\Package\Version;
15663
15664 use Composer\Package\BasePackage;
15665 use Composer\Package\PackageInterface;
15666 use Composer\Package\Link;
15667 use Composer\Package\LinkConstraint\EmptyConstraint;
15668 use Composer\Package\LinkConstraint\MultiConstraint;
15669 use Composer\Package\LinkConstraint\VersionConstraint;
15670
15671
15672
15673
15674
15675
15676 class VersionParser
15677 {
15678 private static $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?';
15679
15680
15681
15682
15683
15684
15685
15686 public static function parseStability($version)
15687 {
15688 $version = preg_replace('{#.+$}i', '', $version);
15689
15690 if ('dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4)) {
15691 return 'dev';
15692 }
15693
15694 preg_match('{'.self::$modifierRegex.'$}i', strtolower($version), $match);
15695 if (!empty($match[3])) {
15696 return 'dev';
15697 }
15698
15699 if (!empty($match[1])) {
15700 if ('beta' === $match[1] || 'b' === $match[1]) {
15701 return 'beta';
15702 }
15703 if ('alpha' === $match[1] || 'a' === $match[1]) {
15704 return 'alpha';
15705 }
15706 if ('rc' === $match[1]) {
15707 return 'RC';
15708 }
15709 }
15710
15711 return 'stable';
15712 }
15713
15714 public static function normalizeStability($stability)
15715 {
15716 $stability = strtolower($stability);
15717
15718 return $stability === 'rc' ? 'RC' : $stability;
15719 }
15720
15721 public static function formatVersion(PackageInterface $package, $truncate = true)
15722 {
15723 if (!$package->isDev() || !in_array($package->getSourceType(), array('hg', 'git'))) {
15724 return $package->getPrettyVersion();
15725 }
15726
15727
15728  if ($truncate && strlen($package->getSourceReference()) === 40) {
15729 return $package->getPrettyVersion() . ' ' . substr($package->getSourceReference(), 0, 7);
15730 }
15731
15732 return $package->getPrettyVersion() . ' ' . $package->getSourceReference();
15733 }
15734
15735
15736
15737
15738
15739
15740
15741
15742
15743 public function normalize($version, $fullVersion = null)
15744 {
15745 $version = trim($version);
15746 if (null === $fullVersion) {
15747 $fullVersion = $version;
15748 }
15749
15750
15751  if (preg_match('{^([^,\s]+) +as +([^,\s]+)$}', $version, $match)) {
15752 $version = $match[1];
15753 }
15754
15755
15756  if (preg_match('{^([^,\s+]+)\+[^\s]+$}', $version, $match)) {
15757 $version = $match[1];
15758 }
15759
15760
15761  if (preg_match('{^(?:dev-)?(?:master|trunk|default)$}i', $version)) {
15762 return '9999999-dev';
15763 }
15764
15765 if ('dev-' === strtolower(substr($version, 0, 4))) {
15766 return 'dev-'.substr($version, 4);
15767 }
15768
15769
15770  if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?'.self::$modifierRegex.'$}i', $version, $matches)) {
15771 $version = $matches[1]
15772 .(!empty($matches[2]) ? $matches[2] : '.0')
15773 .(!empty($matches[3]) ? $matches[3] : '.0')
15774 .(!empty($matches[4]) ? $matches[4] : '.0');
15775 $index = 5;
15776 } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)'.self::$modifierRegex.'$}i', $version, $matches)) { 
15777  $version = preg_replace('{\D}', '-', $matches[1]);
15778 $index = 2;
15779 } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?'.self::$modifierRegex.'$}i', $version, $matches)) {
15780 $version = $matches[1]
15781 .(!empty($matches[2]) ? $matches[2] : '.0')
15782 .(!empty($matches[3]) ? $matches[3] : '.0')
15783 .(!empty($matches[4]) ? $matches[4] : '.0');
15784 $index = 5;
15785 }
15786
15787
15788  if (isset($index)) {
15789 if (!empty($matches[$index])) {
15790 if ('stable' === $matches[$index]) {
15791 return $version;
15792 }
15793 $version .= '-' . $this->expandStability($matches[$index]) . (!empty($matches[$index+1]) ? $matches[$index+1] : '');
15794 }
15795
15796 if (!empty($matches[$index+2])) {
15797 $version .= '-dev';
15798 }
15799
15800 return $version;
15801 }
15802
15803
15804  if (preg_match('{(.*?)[.-]?dev$}i', $version, $match)) {
15805 try {
15806 return $this->normalizeBranch($match[1]);
15807 } catch (\Exception $e) {
15808 }
15809 }
15810
15811 $extraMessage = '';
15812 if (preg_match('{ +as +'.preg_quote($version).'$}', $fullVersion)) {
15813 $extraMessage = ' in "'.$fullVersion.'", the alias must be an exact version';
15814 } elseif (preg_match('{^'.preg_quote($version).' +as +}', $fullVersion)) {
15815 $extraMessage = ' in "'.$fullVersion.'", the alias source must be an exact version, if it is a branch name you should prefix it with dev-';
15816 }
15817
15818 throw new \UnexpectedValueException('Invalid version string "'.$version.'"'.$extraMessage);
15819 }
15820
15821
15822
15823
15824
15825
15826
15827 public function normalizeBranch($name)
15828 {
15829 $name = trim($name);
15830
15831 if (in_array($name, array('master', 'trunk', 'default'))) {
15832 return $this->normalize($name);
15833 }
15834
15835 if (preg_match('#^v?(\d+)(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?(\.(?:\d+|[xX*]))?$#i', $name, $matches)) {
15836 $version = '';
15837 for ($i = 1; $i < 5; $i++) {
15838 $version .= isset($matches[$i]) ? str_replace(array('*', 'X'), 'x', $matches[$i]) : '.x';
15839 }
15840
15841 return str_replace('x', '9999999', $version).'-dev';
15842 }
15843
15844 return 'dev-'.$name;
15845 }
15846
15847
15848
15849
15850
15851
15852
15853
15854 public function parseLinks($source, $sourceVersion, $description, $links)
15855 {
15856 $res = array();
15857 foreach ($links as $target => $constraint) {
15858 if ('self.version' === $constraint) {
15859 $parsedConstraint = $this->parseConstraints($sourceVersion);
15860 } else {
15861 $parsedConstraint = $this->parseConstraints($constraint);
15862 }
15863 $res[strtolower($target)] = new Link($source, $target, $parsedConstraint, $description, $constraint);
15864 }
15865
15866 return $res;
15867 }
15868
15869
15870
15871
15872
15873
15874
15875 public function parseConstraints($constraints)
15876 {
15877 $prettyConstraint = $constraints;
15878
15879 if (preg_match('{^([^,\s]*?)@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $constraints, $match)) {
15880 $constraints = empty($match[1]) ? '*' : $match[1];
15881 }
15882
15883 if (preg_match('{^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$}i', $constraints, $match)) {
15884 $constraints = $match[1];
15885 }
15886
15887 $orConstraints = preg_split('{\s*\|\|?\s*}', trim($constraints));
15888 $orGroups = array();
15889 foreach ($orConstraints as $constraints) {
15890 $andConstraints = preg_split('{(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)}', $constraints);
15891 if (count($andConstraints) > 1) {
15892 $constraintObjects = array();
15893 foreach ($andConstraints as $constraint) {
15894 $constraintObjects = array_merge($constraintObjects, $this->parseConstraint($constraint));
15895 }
15896 } else {
15897 $constraintObjects = $this->parseConstraint($andConstraints[0]);
15898 }
15899
15900 if (1 === count($constraintObjects)) {
15901 $constraint = $constraintObjects[0];
15902 } else {
15903 $constraint = new MultiConstraint($constraintObjects);
15904 }
15905
15906 $orGroups[] = $constraint;
15907 }
15908
15909 if (1 === count($orGroups)) {
15910 $constraint = $orGroups[0];
15911 } else {
15912 $constraint = new MultiConstraint($orGroups, false);
15913 }
15914
15915 $constraint->setPrettyString($prettyConstraint);
15916
15917 return $constraint;
15918 }
15919
15920 private function parseConstraint($constraint)
15921 {
15922 if (preg_match('{^([^,\s]+?)@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $constraint, $match)) {
15923 $constraint = $match[1];
15924 if ($match[2] !== 'stable') {
15925 $stabilityModifier = $match[2];
15926 }
15927 }
15928
15929 if (preg_match('{^[xX*](\.[xX*])*$}i', $constraint)) {
15930 return array(new EmptyConstraint);
15931 }
15932
15933 $versionRegex = '(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?'.self::$modifierRegex;
15934
15935
15936  
15937  
15938  
15939  
15940  if (preg_match('{^~>?'.$versionRegex.'$}i', $constraint, $matches)) {
15941 if (substr($constraint, 0, 2) === '~>') {
15942 throw new \UnexpectedValueException(
15943 'Could not parse version constraint '.$constraint.': '.
15944 'Invalid operator "~>", you probably meant to use the "~" operator'
15945 );
15946 }
15947
15948
15949  if (isset($matches[4]) && '' !== $matches[4]) {
15950 $position = 4;
15951 } elseif (isset($matches[3]) && '' !== $matches[3]) {
15952 $position = 3;
15953 } elseif (isset($matches[2]) && '' !== $matches[2]) {
15954 $position = 2;
15955 } else {
15956 $position = 1;
15957 }
15958
15959
15960  $stabilitySuffix = '';
15961 if (!empty($matches[5])) {
15962 $stabilitySuffix .= '-' . $this->expandStability($matches[5]) . (!empty($matches[6]) ? $matches[6] : '');
15963 }
15964
15965 if (!empty($matches[7])) {
15966 $stabilitySuffix .= '-dev';
15967 }
15968
15969 if (!$stabilitySuffix) {
15970 $stabilitySuffix = "-dev";
15971 }
15972 $lowVersion = $this->manipulateVersionString($matches, $position, 0) . $stabilitySuffix;
15973 $lowerBound = new VersionConstraint('>=', $lowVersion);
15974
15975
15976  
15977  $highPosition = max(1, $position - 1);
15978 $highVersion = $this->manipulateVersionString($matches, $highPosition, 1) . '-dev';
15979 $upperBound = new VersionConstraint('<', $highVersion);
15980
15981 return array(
15982 $lowerBound,
15983 $upperBound
15984 );
15985 }
15986
15987
15988  if (preg_match('{^\^'.$versionRegex.'($)}i', $constraint, $matches)) {
15989
15990  if ('0' !== $matches[1] || '' === $matches[2]) {
15991 $position = 1;
15992 } elseif ('0' !== $matches[2] || '' === $matches[3]) {
15993 $position = 2;
15994 } else {
15995 $position = 3;
15996 }
15997
15998
15999  $stabilitySuffix = '';
16000 if (empty($matches[5]) && empty($matches[7])) {
16001 $stabilitySuffix .= '-dev';
16002 }
16003
16004 $lowVersion = $this->normalize(substr($constraint . $stabilitySuffix, 1));
16005 $lowerBound = new VersionConstraint('>=', $lowVersion);
16006
16007
16008  
16009  $highVersion = $this->manipulateVersionString($matches, $position, 1) . '-dev';
16010 $upperBound = new VersionConstraint('<', $highVersion);
16011
16012 return array(
16013 $lowerBound,
16014 $upperBound
16015 );
16016 }
16017
16018
16019  if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[xX*]$}', $constraint, $matches)) {
16020 if (isset($matches[3]) && '' !== $matches[3]) {
16021 $position = 3;
16022 } elseif (isset($matches[2]) && '' !== $matches[2]) {
16023 $position = 2;
16024 } else {
16025 $position = 1;
16026 }
16027
16028 $lowVersion = $this->manipulateVersionString($matches, $position) . "-dev";
16029 $highVersion = $this->manipulateVersionString($matches, $position, 1) . "-dev";
16030
16031 if ($lowVersion === "0.0.0.0-dev") {
16032 return array(new VersionConstraint('<', $highVersion));
16033 }
16034
16035 return array(
16036 new VersionConstraint('>=', $lowVersion),
16037 new VersionConstraint('<', $highVersion),
16038 );
16039 }
16040
16041
16042  if (preg_match('{^(?P<from>'.$versionRegex.') +- +(?P<to>'.$versionRegex.')($)}i', $constraint, $matches)) {
16043
16044  $lowStabilitySuffix = '';
16045 if (empty($matches[6]) && empty($matches[8])) {
16046 $lowStabilitySuffix = '-dev';
16047 }
16048
16049 $lowVersion = $this->normalize($matches['from']);
16050 $lowerBound = new VersionConstraint('>=', $lowVersion . $lowStabilitySuffix);
16051
16052 $highVersion = $matches[10];
16053 if ((!empty($matches[11]) && !empty($matches[12])) || !empty($matches[14]) || !empty($matches[16])) {
16054 $highVersion = $this->normalize($matches['to']);
16055 $upperBound = new VersionConstraint('<=', $highVersion);
16056 } else {
16057 $highMatch = array('', $matches[10], $matches[11], $matches[12], $matches[13]);
16058 $highVersion = $this->manipulateVersionString($highMatch, empty($matches[11]) ? 1 : 2, 1) . '-dev';
16059 $upperBound = new VersionConstraint('<', $highVersion);
16060 }
16061
16062 return array(
16063 $lowerBound,
16064 $upperBound
16065 );
16066 }
16067
16068
16069  if (preg_match('{^(<>|!=|>=?|<=?|==?)?\s*(.*)}', $constraint, $matches)) {
16070 try {
16071 $version = $this->normalize($matches[2]);
16072
16073 if (!empty($stabilityModifier) && $this->parseStability($version) === 'stable') {
16074 $version .= '-' . $stabilityModifier;
16075 } elseif ('<' === $matches[1]) {
16076 if (!preg_match('/-' . self::$modifierRegex . '$/', strtolower($matches[2]))) {
16077 $version .= '-dev';
16078 }
16079 }
16080
16081 return array(new VersionConstraint($matches[1] ?: '=', $version));
16082 } catch (\Exception $e) {
16083 }
16084 }
16085
16086 $message = 'Could not parse version constraint '.$constraint;
16087 if (isset($e)) {
16088 $message .= ': '. $e->getMessage();
16089 }
16090
16091 throw new \UnexpectedValueException($message);
16092 }
16093
16094
16095
16096
16097
16098
16099
16100
16101
16102
16103
16104
16105 private function manipulateVersionString($matches, $position, $increment = 0, $pad = '0')
16106 {
16107 for ($i = 4; $i > 0; $i--) {
16108 if ($i > $position) {
16109 $matches[$i] = $pad;
16110 } elseif ($i == $position && $increment) {
16111 $matches[$i] += $increment;
16112
16113  if ($matches[$i] < 0) {
16114 $matches[$i] = $pad;
16115 $position--;
16116
16117
16118  if ($i == 1) {
16119 return;
16120 }
16121 }
16122 }
16123 }
16124
16125 return $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4];
16126 }
16127
16128 private function expandStability($stability)
16129 {
16130 $stability = strtolower($stability);
16131
16132 switch ($stability) {
16133 case 'a':
16134 return 'alpha';
16135 case 'b':
16136 return 'beta';
16137 case 'p':
16138 case 'pl':
16139 return 'patch';
16140 case 'rc':
16141 return 'RC';
16142 default:
16143 return $stability;
16144 }
16145 }
16146
16147
16148
16149
16150
16151
16152
16153 public function parseNameVersionPairs(array $pairs)
16154 {
16155 $pairs = array_values($pairs);
16156 $result = array();
16157
16158 for ($i = 0, $count = count($pairs); $i < $count; $i++) {
16159 $pair = preg_replace('{^([^=: ]+)[=: ](.*)$}', '$1 $2', trim($pairs[$i]));
16160 if (false === strpos($pair, ' ') && isset($pairs[$i+1]) && false === strpos($pairs[$i+1], '/')) {
16161 $pair .= ' '.$pairs[$i+1];
16162 $i++;
16163 }
16164
16165 if (strpos($pair, ' ')) {
16166 list($name, $version) = explode(" ", $pair, 2);
16167 $result[] = array('name' => $name, 'version' => $version);
16168 } else {
16169 $result[] = array('name' => $pair);
16170 }
16171 }
16172
16173 return $result;
16174 }
16175 }
16176 <?php
16177
16178
16179
16180
16181
16182
16183
16184
16185
16186
16187
16188 namespace Composer\Package;
16189
16190
16191
16192
16193
16194
16195 interface CompletePackageInterface extends PackageInterface
16196 {
16197
16198
16199
16200
16201
16202 public function getScripts();
16203
16204
16205
16206
16207
16208
16209
16210
16211 public function getRepositories();
16212
16213
16214
16215
16216
16217
16218 public function getLicense();
16219
16220
16221
16222
16223
16224
16225 public function getKeywords();
16226
16227
16228
16229
16230
16231
16232 public function getDescription();
16233
16234
16235
16236
16237
16238
16239 public function getHomepage();
16240
16241
16242
16243
16244
16245
16246
16247
16248 public function getAuthors();
16249
16250
16251
16252
16253
16254
16255 public function getSupport();
16256
16257
16258
16259
16260
16261
16262 public function isAbandoned();
16263
16264
16265
16266
16267
16268
16269 public function getReplacementPackage();
16270 }
16271 <?php
16272
16273
16274
16275
16276
16277
16278
16279
16280
16281
16282
16283 namespace Composer\Package;
16284
16285
16286
16287
16288
16289
16290 interface RootPackageInterface extends CompletePackageInterface
16291 {
16292
16293
16294
16295
16296
16297 public function getAliases();
16298
16299
16300
16301
16302
16303
16304 public function getMinimumStability();
16305
16306
16307
16308
16309
16310
16311
16312
16313 public function getStabilityFlags();
16314
16315
16316
16317
16318
16319
16320
16321
16322 public function getReferences();
16323
16324
16325
16326
16327
16328
16329 public function getPreferStable();
16330
16331
16332
16333
16334
16335
16336 public function setRequires(array $requires);
16337
16338
16339
16340
16341
16342
16343 public function setDevRequires(array $devRequires);
16344 }
16345 <?php
16346
16347
16348
16349
16350
16351
16352
16353
16354
16355
16356
16357 namespace Composer\Package;
16358
16359
16360
16361
16362
16363
16364 class RootPackage extends CompletePackage implements RootPackageInterface
16365 {
16366 protected $minimumStability = 'stable';
16367 protected $preferStable = false;
16368 protected $stabilityFlags = array();
16369 protected $references = array();
16370 protected $aliases = array();
16371
16372
16373
16374
16375
16376
16377 public function setMinimumStability($minimumStability)
16378 {
16379 $this->minimumStability = $minimumStability;
16380 }
16381
16382
16383
16384
16385 public function getMinimumStability()
16386 {
16387 return $this->minimumStability;
16388 }
16389
16390
16391
16392
16393
16394
16395 public function setStabilityFlags(array $stabilityFlags)
16396 {
16397 $this->stabilityFlags = $stabilityFlags;
16398 }
16399
16400
16401
16402
16403 public function getStabilityFlags()
16404 {
16405 return $this->stabilityFlags;
16406 }
16407
16408
16409
16410
16411
16412
16413 public function setPreferStable($preferStable)
16414 {
16415 $this->preferStable = $preferStable;
16416 }
16417
16418
16419
16420
16421 public function getPreferStable()
16422 {
16423 return $this->preferStable;
16424 }
16425
16426
16427
16428
16429
16430
16431 public function setReferences(array $references)
16432 {
16433 $this->references = $references;
16434 }
16435
16436
16437
16438
16439 public function getReferences()
16440 {
16441 return $this->references;
16442 }
16443
16444
16445
16446
16447
16448
16449 public function setAliases(array $aliases)
16450 {
16451 $this->aliases = $aliases;
16452 }
16453
16454
16455
16456
16457 public function getAliases()
16458 {
16459 return $this->aliases;
16460 }
16461 }
16462 <?php
16463
16464
16465
16466
16467
16468
16469
16470
16471
16472
16473
16474 namespace Composer\Package\Archiver;
16475
16476
16477
16478
16479
16480
16481 interface ArchiverInterface
16482 {
16483
16484
16485
16486
16487
16488
16489
16490
16491
16492
16493 public function archive($sources, $target, $format, array $excludes = array());
16494
16495
16496
16497
16498
16499
16500
16501
16502
16503 public function supports($format, $sourceType);
16504 }
16505 <?php
16506
16507
16508
16509
16510
16511
16512
16513
16514
16515
16516
16517 namespace Composer\Package\Archiver;
16518
16519
16520
16521
16522
16523
16524 class ComposerExcludeFilter extends BaseExcludeFilter
16525 {
16526
16527
16528
16529
16530 public function __construct($sourcePath, array $excludeRules)
16531 {
16532 parent::__construct($sourcePath);
16533 $this->excludePatterns = $this->generatePatterns($excludeRules);
16534 }
16535 }
16536 <?php
16537
16538
16539
16540
16541
16542
16543
16544
16545
16546
16547
16548 namespace Composer\Package\Archiver;
16549
16550
16551
16552
16553
16554
16555 class PharArchiver implements ArchiverInterface
16556 {
16557 protected static $formats = array(
16558 'zip' => \Phar::ZIP,
16559 'tar' => \Phar::TAR,
16560 );
16561
16562
16563
16564
16565 public function archive($sources, $target, $format, array $excludes = array())
16566 {
16567 $sources = realpath($sources);
16568
16569
16570  if (file_exists($target)) {
16571 unlink($target);
16572 }
16573
16574 try {
16575 $phar = new \PharData($target, null, null, static::$formats[$format]);
16576 $files = new ArchivableFilesFinder($sources, $excludes);
16577 $phar->buildFromIterator($files, $sources);
16578
16579 return $target;
16580 } catch (\UnexpectedValueException $e) {
16581 $message = sprintf("Could not create archive '%s' from '%s': %s",
16582 $target,
16583 $sources,
16584 $e->getMessage()
16585 );
16586
16587 throw new \RuntimeException($message, $e->getCode(), $e);
16588 }
16589 }
16590
16591
16592
16593
16594 public function supports($format, $sourceType)
16595 {
16596 return isset(static::$formats[$format]);
16597 }
16598 }
16599 <?php
16600
16601
16602
16603
16604
16605
16606
16607
16608
16609
16610
16611 namespace Composer\Package\Archiver;
16612
16613 use Symfony\Component\Finder;
16614
16615
16616
16617
16618 abstract class BaseExcludeFilter
16619 {
16620
16621
16622
16623 protected $sourcePath;
16624
16625
16626
16627
16628 protected $excludePatterns;
16629
16630
16631
16632
16633 public function __construct($sourcePath)
16634 {
16635 $this->sourcePath = $sourcePath;
16636 $this->excludePatterns = array();
16637 }
16638
16639
16640
16641
16642
16643
16644
16645
16646
16647
16648
16649 public function filter($relativePath, $exclude)
16650 {
16651 foreach ($this->excludePatterns as $patternData) {
16652 list($pattern, $negate, $stripLeadingSlash) = $patternData;
16653
16654 if ($stripLeadingSlash) {
16655 $path = substr($relativePath, 1);
16656 } else {
16657 $path = $relativePath;
16658 }
16659
16660 if (preg_match($pattern, $path)) {
16661 $exclude = !$negate;
16662 }
16663 }
16664
16665 return $exclude;
16666 }
16667
16668
16669
16670
16671
16672
16673
16674
16675
16676 protected function parseLines(array $lines, $lineParser)
16677 {
16678 return array_filter(
16679 array_map(
16680 function ($line) use ($lineParser) {
16681 $line = trim($line);
16682
16683 if (!$line || 0 === strpos($line, '#')) {
16684 return;
16685 }
16686
16687 return call_user_func($lineParser, $line);
16688 },
16689 $lines
16690 ),
16691 function ($pattern) {
16692 return $pattern !== null;
16693 }
16694 );
16695 }
16696
16697
16698
16699
16700
16701
16702
16703
16704 protected function generatePatterns($rules)
16705 {
16706 $patterns = array();
16707 foreach ($rules as $rule) {
16708 $patterns[] = $this->generatePattern($rule);
16709 }
16710
16711 return $patterns;
16712 }
16713
16714
16715
16716
16717
16718
16719
16720
16721 protected function generatePattern($rule)
16722 {
16723 $negate = false;
16724 $pattern = '#';
16725
16726 if (strlen($rule) && $rule[0] === '!') {
16727 $negate = true;
16728 $rule = substr($rule, 1);
16729 }
16730
16731 if (strlen($rule) && $rule[0] === '/') {
16732 $pattern .= '^/';
16733 $rule = substr($rule, 1);
16734 } elseif (strlen($rule) - 1 === strpos($rule, '/')) {
16735 $pattern .= '/';
16736 $rule = substr($rule, 0, -1);
16737 } elseif (false === strpos($rule, '/')) {
16738 $pattern .= '/';
16739 }
16740
16741
16742  $pattern .= substr(Finder\Glob::toRegex($rule), 2, -2) . '(?=$|/)';
16743
16744 return array($pattern . '#', $negate, false);
16745 }
16746 }
16747 <?php
16748
16749
16750
16751
16752
16753
16754
16755
16756
16757
16758
16759 namespace Composer\Package\Archiver;
16760
16761
16762
16763
16764
16765
16766
16767
16768 class GitExcludeFilter extends BaseExcludeFilter
16769 {
16770
16771
16772
16773
16774
16775 public function __construct($sourcePath)
16776 {
16777 parent::__construct($sourcePath);
16778
16779 if (file_exists($sourcePath.'/.gitignore')) {
16780 $this->excludePatterns = $this->parseLines(
16781 file($sourcePath.'/.gitignore'),
16782 array($this, 'parseGitIgnoreLine')
16783 );
16784 }
16785 if (file_exists($sourcePath.'/.gitattributes')) {
16786 $this->excludePatterns = array_merge(
16787 $this->excludePatterns,
16788 $this->parseLines(
16789 file($sourcePath.'/.gitattributes'),
16790 array($this, 'parseGitAttributesLine')
16791 ));
16792 }
16793 }
16794
16795
16796
16797
16798
16799
16800
16801
16802 public function parseGitIgnoreLine($line)
16803 {
16804 return $this->generatePattern($line);
16805 }
16806
16807
16808
16809
16810
16811
16812
16813
16814 public function parseGitAttributesLine($line)
16815 {
16816 $parts = preg_split('#\s+#', $line);
16817
16818 if (count($parts) != 2) {
16819 return null;
16820 }
16821
16822 if ($parts[1] === 'export-ignore') {
16823 return $this->generatePattern($parts[0]);
16824 }
16825 }
16826 }
16827 <?php
16828
16829
16830
16831
16832
16833
16834
16835
16836
16837
16838
16839 namespace Composer\Package\Archiver;
16840
16841 use Composer\Util\Filesystem;
16842
16843 use Symfony\Component\Finder;
16844
16845
16846
16847
16848
16849
16850
16851
16852
16853 class ArchivableFilesFinder extends \FilterIterator
16854 {
16855
16856
16857
16858 protected $finder;
16859
16860
16861
16862
16863
16864
16865
16866 public function __construct($sources, array $excludes)
16867 {
16868 $fs = new Filesystem();
16869
16870 $sources = $fs->normalizePath($sources);
16871
16872 $filters = array(
16873 new HgExcludeFilter($sources),
16874 new GitExcludeFilter($sources),
16875 new ComposerExcludeFilter($sources, $excludes),
16876 );
16877
16878 $this->finder = new Finder\Finder();
16879
16880 $filter = function (\SplFileInfo $file) use ($sources, $filters, $fs) {
16881 if ($file->isLink() && strpos($file->getLinkTarget(), $sources) !== 0) {
16882 return false;
16883 }
16884
16885 $relativePath = preg_replace(
16886 '#^'.preg_quote($sources, '#').'#',
16887 '',
16888 $fs->normalizePath($file->getRealPath())
16889 );
16890
16891 $exclude = false;
16892 foreach ($filters as $filter) {
16893 $exclude = $filter->filter($relativePath, $exclude);
16894 }
16895
16896 return !$exclude;
16897 };
16898
16899 if (method_exists($filter, 'bindTo')) {
16900 $filter = $filter->bindTo(null);
16901 }
16902
16903 $this->finder
16904 ->in($sources)
16905 ->filter($filter)
16906 ->ignoreVCS(true)
16907 ->ignoreDotFiles(false);
16908
16909 parent::__construct($this->finder->getIterator());
16910 }
16911
16912 public function accept()
16913 {
16914 return !$this->getInnerIterator()->current()->isDir();
16915 }
16916 }
16917 <?php
16918
16919
16920
16921
16922
16923
16924
16925
16926
16927
16928
16929 namespace Composer\Package\Archiver;
16930
16931 use Composer\Downloader\DownloadManager;
16932 use Composer\Package\PackageInterface;
16933 use Composer\Package\RootPackageInterface;
16934 use Composer\Util\Filesystem;
16935 use Composer\Json\JsonFile;
16936
16937
16938
16939
16940
16941 class ArchiveManager
16942 {
16943 protected $downloadManager;
16944
16945 protected $archivers = array();
16946
16947
16948
16949
16950 protected $overwriteFiles = true;
16951
16952
16953
16954
16955 public function __construct(DownloadManager $downloadManager)
16956 {
16957 $this->downloadManager = $downloadManager;
16958 }
16959
16960
16961
16962
16963 public function addArchiver(ArchiverInterface $archiver)
16964 {
16965 $this->archivers[] = $archiver;
16966 }
16967
16968
16969
16970
16971
16972
16973
16974
16975 public function setOverwriteFiles($overwriteFiles)
16976 {
16977 $this->overwriteFiles = $overwriteFiles;
16978
16979 return $this;
16980 }
16981
16982
16983
16984
16985
16986
16987
16988
16989 public function getPackageFilename(PackageInterface $package)
16990 {
16991 $nameParts = array(preg_replace('#[^a-z0-9-_]#i', '-', $package->getName()));
16992
16993 if (preg_match('{^[a-f0-9]{40}$}', $package->getDistReference())) {
16994 $nameParts = array_merge($nameParts, array($package->getDistReference(), $package->getDistType()));
16995 } else {
16996 $nameParts = array_merge($nameParts, array($package->getPrettyVersion(), $package->getDistReference()));
16997 }
16998
16999 if ($package->getSourceReference()) {
17000 $nameParts[] = substr(sha1($package->getSourceReference()), 0, 6);
17001 }
17002
17003 $name = implode('-', array_filter($nameParts, function ($p) {
17004 return !empty($p);
17005 }));
17006
17007 return str_replace('/', '-', $name);
17008 }
17009
17010
17011
17012
17013
17014
17015
17016
17017
17018
17019
17020 public function archive(PackageInterface $package, $format, $targetDir)
17021 {
17022 if (empty($format)) {
17023 throw new \InvalidArgumentException('Format must be specified');
17024 }
17025
17026
17027  $usableArchiver = null;
17028 foreach ($this->archivers as $archiver) {
17029 if ($archiver->supports($format, $package->getSourceType())) {
17030 $usableArchiver = $archiver;
17031 break;
17032 }
17033 }
17034
17035
17036  if (null === $usableArchiver) {
17037 throw new \RuntimeException(sprintf('No archiver found to support %s format', $format));
17038 }
17039
17040 $filesystem = new Filesystem();
17041 $packageName = $this->getPackageFilename($package);
17042
17043
17044  $filesystem->ensureDirectoryExists($targetDir);
17045 $target = realpath($targetDir).'/'.$packageName.'.'.$format;
17046 $filesystem->ensureDirectoryExists(dirname($target));
17047
17048 if (!$this->overwriteFiles && file_exists($target)) {
17049 return $target;
17050 }
17051
17052 if ($package instanceof RootPackageInterface) {
17053 $sourcePath = realpath('.');
17054 } else {
17055
17056  $sourcePath = sys_get_temp_dir().'/composer_archive'.uniqid();
17057 $filesystem->ensureDirectoryExists($sourcePath);
17058
17059
17060  $this->downloadManager->download($package, $sourcePath);
17061
17062
17063  if (file_exists($composerJsonPath = $sourcePath.'/composer.json')) {
17064 $jsonFile = new JsonFile($composerJsonPath);
17065 $jsonData = $jsonFile->read();
17066 if (!empty($jsonData['archive']['exclude'])) {
17067 $package->setArchiveExcludes($jsonData['archive']['exclude']);
17068 }
17069 }
17070 }
17071
17072
17073  $tempTarget = sys_get_temp_dir().'/composer_archive'.uniqid().'.'.$format;
17074 $filesystem->ensureDirectoryExists(dirname($tempTarget));
17075
17076 $archivePath = $usableArchiver->archive($sourcePath, $tempTarget, $format, $package->getArchiveExcludes());
17077 rename($archivePath, $target);
17078
17079
17080  if (!$package instanceof RootPackageInterface) {
17081 $filesystem->removeDirectory($sourcePath);
17082 }
17083 $filesystem->remove($tempTarget);
17084
17085 return $target;
17086 }
17087 }
17088 <?php
17089
17090
17091
17092
17093
17094
17095
17096
17097
17098
17099
17100 namespace Composer\Package\Archiver;
17101
17102 use Symfony\Component\Finder;
17103
17104
17105
17106
17107
17108
17109 class HgExcludeFilter extends BaseExcludeFilter
17110 {
17111 const HG_IGNORE_REGEX = 1;
17112 const HG_IGNORE_GLOB = 2;
17113
17114
17115
17116
17117
17118 protected $patternMode;
17119
17120
17121
17122
17123
17124
17125 public function __construct($sourcePath)
17126 {
17127 parent::__construct($sourcePath);
17128
17129 $this->patternMode = self::HG_IGNORE_REGEX;
17130
17131 if (file_exists($sourcePath.'/.hgignore')) {
17132 $this->excludePatterns = $this->parseLines(
17133 file($sourcePath.'/.hgignore'),
17134 array($this, 'parseHgIgnoreLine')
17135 );
17136 }
17137 }
17138
17139
17140
17141
17142
17143
17144
17145
17146 public function parseHgIgnoreLine($line)
17147 {
17148 if (preg_match('#^syntax\s*:\s*(glob|regexp)$#', $line, $matches)) {
17149 if ($matches[1] === 'glob') {
17150 $this->patternMode = self::HG_IGNORE_GLOB;
17151 } else {
17152 $this->patternMode = self::HG_IGNORE_REGEX;
17153 }
17154
17155 return null;
17156 }
17157
17158 if ($this->patternMode == self::HG_IGNORE_GLOB) {
17159 return $this->patternFromGlob($line);
17160 } else {
17161 return $this->patternFromRegex($line);
17162 }
17163 }
17164
17165
17166
17167
17168
17169
17170
17171
17172 protected function patternFromGlob($line)
17173 {
17174 $pattern = '#'.substr(Finder\Glob::toRegex($line), 2, -1).'#';
17175 $pattern = str_replace('[^/]*', '.*', $pattern);
17176
17177 return array($pattern, false, true);
17178 }
17179
17180
17181
17182
17183
17184
17185
17186
17187 public function patternFromRegex($line)
17188 {
17189
17190  $pattern = '#'.preg_replace('/((?:\\\\\\\\)*)(\\\\?)#/', '\1\2\2\\#', $line).'#';
17191
17192 return array($pattern, false, true);
17193 }
17194 }
17195 <?php
17196
17197
17198
17199
17200
17201
17202
17203
17204
17205
17206
17207 namespace Composer\Package;
17208
17209
17210
17211
17212 class RootAliasPackage extends AliasPackage implements RootPackageInterface
17213 {
17214 public function __construct(RootPackageInterface $aliasOf, $version, $prettyVersion)
17215 {
17216 parent::__construct($aliasOf, $version, $prettyVersion);
17217 }
17218
17219
17220
17221
17222 public function getAliases()
17223 {
17224 return $this->aliasOf->getAliases();
17225 }
17226
17227
17228
17229
17230 public function getMinimumStability()
17231 {
17232 return $this->aliasOf->getMinimumStability();
17233 }
17234
17235
17236
17237
17238 public function getStabilityFlags()
17239 {
17240 return $this->aliasOf->getStabilityFlags();
17241 }
17242
17243
17244
17245
17246 public function getReferences()
17247 {
17248 return $this->aliasOf->getReferences();
17249 }
17250
17251
17252
17253
17254 public function getPreferStable()
17255 {
17256 return $this->aliasOf->getPreferStable();
17257 }
17258
17259
17260
17261
17262 public function setRequires(array $require)
17263 {
17264 return $this->aliasOf->setRequires($require);
17265 }
17266
17267
17268
17269
17270 public function setDevRequires(array $devRequire)
17271 {
17272 return $this->aliasOf->setDevRequires($devRequire);
17273 }
17274
17275 public function __clone()
17276 {
17277 parent::__clone();
17278 $this->aliasOf = clone $this->aliasOf;
17279 }
17280 }
17281 <?php
17282
17283
17284
17285
17286
17287
17288
17289
17290
17291
17292
17293 namespace Composer\Package;
17294
17295 use Composer\Package\Version\VersionParser;
17296 use Composer\Util\ComposerMirror;
17297
17298
17299
17300
17301
17302
17303 class Package extends BasePackage
17304 {
17305 protected $type;
17306 protected $targetDir;
17307 protected $installationSource;
17308 protected $sourceType;
17309 protected $sourceUrl;
17310 protected $sourceReference;
17311 protected $sourceMirrors;
17312 protected $distType;
17313 protected $distUrl;
17314 protected $distReference;
17315 protected $distSha1Checksum;
17316 protected $distMirrors;
17317 protected $version;
17318 protected $prettyVersion;
17319 protected $releaseDate;
17320 protected $extra = array();
17321 protected $binaries = array();
17322 protected $dev;
17323 protected $stability;
17324 protected $notificationUrl;
17325
17326 protected $requires = array();
17327 protected $conflicts = array();
17328 protected $provides = array();
17329 protected $replaces = array();
17330 protected $devRequires = array();
17331 protected $suggests = array();
17332 protected $autoload = array();
17333 protected $devAutoload = array();
17334 protected $includePaths = array();
17335 protected $archiveExcludes = array();
17336
17337
17338
17339
17340
17341
17342
17343
17344 public function __construct($name, $version, $prettyVersion)
17345 {
17346 parent::__construct($name);
17347
17348 $this->version = $version;
17349 $this->prettyVersion = $prettyVersion;
17350
17351 $this->stability = VersionParser::parseStability($version);
17352 $this->dev = $this->stability === 'dev';
17353 }
17354
17355
17356
17357
17358 public function isDev()
17359 {
17360 return $this->dev;
17361 }
17362
17363
17364
17365
17366 public function setType($type)
17367 {
17368 $this->type = $type;
17369 }
17370
17371
17372
17373
17374 public function getType()
17375 {
17376 return $this->type ?: 'library';
17377 }
17378
17379
17380
17381
17382 public function getStability()
17383 {
17384 return $this->stability;
17385 }
17386
17387
17388
17389
17390 public function setTargetDir($targetDir)
17391 {
17392 $this->targetDir = $targetDir;
17393 }
17394
17395
17396
17397
17398 public function getTargetDir()
17399 {
17400 if (null === $this->targetDir) {
17401 return;
17402 }
17403
17404 return ltrim(preg_replace('{ (?:^|[\\\\/]+) \.\.? (?:[\\\\/]+|$) (?:\.\.? (?:[\\\\/]+|$) )*}x', '/', $this->targetDir), '/');
17405 }
17406
17407
17408
17409
17410 public function setExtra(array $extra)
17411 {
17412 $this->extra = $extra;
17413 }
17414
17415
17416
17417
17418 public function getExtra()
17419 {
17420 return $this->extra;
17421 }
17422
17423
17424
17425
17426 public function setBinaries(array $binaries)
17427 {
17428 $this->binaries = $binaries;
17429 }
17430
17431
17432
17433
17434 public function getBinaries()
17435 {
17436 return $this->binaries;
17437 }
17438
17439
17440
17441
17442 public function setInstallationSource($type)
17443 {
17444 $this->installationSource = $type;
17445 }
17446
17447
17448
17449
17450 public function getInstallationSource()
17451 {
17452 return $this->installationSource;
17453 }
17454
17455
17456
17457
17458 public function setSourceType($type)
17459 {
17460 $this->sourceType = $type;
17461 }
17462
17463
17464
17465
17466 public function getSourceType()
17467 {
17468 return $this->sourceType;
17469 }
17470
17471
17472
17473
17474 public function setSourceUrl($url)
17475 {
17476 $this->sourceUrl = $url;
17477 }
17478
17479
17480
17481
17482 public function getSourceUrl()
17483 {
17484 return $this->sourceUrl;
17485 }
17486
17487
17488
17489
17490 public function setSourceReference($reference)
17491 {
17492 $this->sourceReference = $reference;
17493 }
17494
17495
17496
17497
17498 public function getSourceReference()
17499 {
17500 return $this->sourceReference;
17501 }
17502
17503
17504
17505
17506 public function setSourceMirrors($mirrors)
17507 {
17508 $this->sourceMirrors = $mirrors;
17509 }
17510
17511
17512
17513
17514 public function getSourceMirrors()
17515 {
17516 return $this->sourceMirrors;
17517 }
17518
17519
17520
17521
17522 public function getSourceUrls()
17523 {
17524 return $this->getUrls($this->sourceUrl, $this->sourceMirrors, $this->sourceReference, $this->sourceType, 'source');
17525 }
17526
17527
17528
17529
17530 public function setDistType($type)
17531 {
17532 $this->distType = $type;
17533 }
17534
17535
17536
17537
17538 public function getDistType()
17539 {
17540 return $this->distType;
17541 }
17542
17543
17544
17545
17546 public function setDistUrl($url)
17547 {
17548 $this->distUrl = $url;
17549 }
17550
17551
17552
17553
17554 public function getDistUrl()
17555 {
17556 return $this->distUrl;
17557 }
17558
17559
17560
17561
17562 public function setDistReference($reference)
17563 {
17564 $this->distReference = $reference;
17565 }
17566
17567
17568
17569
17570 public function getDistReference()
17571 {
17572 return $this->distReference;
17573 }
17574
17575
17576
17577
17578 public function setDistSha1Checksum($sha1checksum)
17579 {
17580 $this->distSha1Checksum = $sha1checksum;
17581 }
17582
17583
17584
17585
17586 public function getDistSha1Checksum()
17587 {
17588 return $this->distSha1Checksum;
17589 }
17590
17591
17592
17593
17594 public function setDistMirrors($mirrors)
17595 {
17596 $this->distMirrors = $mirrors;
17597 }
17598
17599
17600
17601
17602 public function getDistMirrors()
17603 {
17604 return $this->distMirrors;
17605 }
17606
17607
17608
17609
17610 public function getDistUrls()
17611 {
17612 return $this->getUrls($this->distUrl, $this->distMirrors, $this->distReference, $this->distType, 'dist');
17613 }
17614
17615
17616
17617
17618 public function getVersion()
17619 {
17620 return $this->version;
17621 }
17622
17623
17624
17625
17626 public function getPrettyVersion()
17627 {
17628 return $this->prettyVersion;
17629 }
17630
17631
17632
17633
17634
17635
17636 public function setReleaseDate(\DateTime $releaseDate)
17637 {
17638 $this->releaseDate = $releaseDate;
17639 }
17640
17641
17642
17643
17644 public function getReleaseDate()
17645 {
17646 return $this->releaseDate;
17647 }
17648
17649
17650
17651
17652
17653
17654 public function setRequires(array $requires)
17655 {
17656 $this->requires = $requires;
17657 }
17658
17659
17660
17661
17662 public function getRequires()
17663 {
17664 return $this->requires;
17665 }
17666
17667
17668
17669
17670
17671
17672 public function setConflicts(array $conflicts)
17673 {
17674 $this->conflicts = $conflicts;
17675 }
17676
17677
17678
17679
17680 public function getConflicts()
17681 {
17682 return $this->conflicts;
17683 }
17684
17685
17686
17687
17688
17689
17690 public function setProvides(array $provides)
17691 {
17692 $this->provides = $provides;
17693 }
17694
17695
17696
17697
17698 public function getProvides()
17699 {
17700 return $this->provides;
17701 }
17702
17703
17704
17705
17706
17707
17708 public function setReplaces(array $replaces)
17709 {
17710 $this->replaces = $replaces;
17711 }
17712
17713
17714
17715
17716 public function getReplaces()
17717 {
17718 return $this->replaces;
17719 }
17720
17721
17722
17723
17724
17725
17726 public function setDevRequires(array $devRequires)
17727 {
17728 $this->devRequires = $devRequires;
17729 }
17730
17731
17732
17733
17734 public function getDevRequires()
17735 {
17736 return $this->devRequires;
17737 }
17738
17739
17740
17741
17742
17743
17744 public function setSuggests(array $suggests)
17745 {
17746 $this->suggests = $suggests;
17747 }
17748
17749
17750
17751
17752 public function getSuggests()
17753 {
17754 return $this->suggests;
17755 }
17756
17757
17758
17759
17760
17761
17762 public function setAutoload(array $autoload)
17763 {
17764 $this->autoload = $autoload;
17765 }
17766
17767
17768
17769
17770 public function getAutoload()
17771 {
17772 return $this->autoload;
17773 }
17774
17775
17776
17777
17778
17779
17780 public function setDevAutoload(array $devAutoload)
17781 {
17782 $this->devAutoload = $devAutoload;
17783 }
17784
17785
17786
17787
17788 public function getDevAutoload()
17789 {
17790 return $this->devAutoload;
17791 }
17792
17793
17794
17795
17796
17797
17798 public function setIncludePaths(array $includePaths)
17799 {
17800 $this->includePaths = $includePaths;
17801 }
17802
17803
17804
17805
17806 public function getIncludePaths()
17807 {
17808 return $this->includePaths;
17809 }
17810
17811
17812
17813
17814
17815
17816 public function setNotificationUrl($notificationUrl)
17817 {
17818 $this->notificationUrl = $notificationUrl;
17819 }
17820
17821
17822
17823
17824 public function getNotificationUrl()
17825 {
17826 return $this->notificationUrl;
17827 }
17828
17829
17830
17831
17832
17833
17834 public function setArchiveExcludes(array $excludes)
17835 {
17836 $this->archiveExcludes = $excludes;
17837 }
17838
17839
17840
17841
17842 public function getArchiveExcludes()
17843 {
17844 return $this->archiveExcludes;
17845 }
17846
17847
17848
17849
17850
17851
17852
17853
17854 public function replaceVersion($version, $prettyVersion)
17855 {
17856 $this->version = $version;
17857 $this->prettyVersion = $prettyVersion;
17858
17859 $this->stability = VersionParser::parseStability($version);
17860 $this->dev = $this->stability === 'dev';
17861 }
17862
17863 protected function getUrls($url, $mirrors, $ref, $type, $urlType)
17864 {
17865 if (!$url) {
17866 return array();
17867 }
17868 $urls = array($url);
17869 if ($mirrors) {
17870 foreach ($mirrors as $mirror) {
17871 if ($urlType === 'dist') {
17872 $mirrorUrl = ComposerMirror::processUrl($mirror['url'], $this->name, $this->version, $ref, $type);
17873 } elseif ($urlType === 'source' && $type === 'git') {
17874 $mirrorUrl = ComposerMirror::processGitUrl($mirror['url'], $this->name, $url, $type);
17875 } elseif ($urlType === 'source' && $type === 'hg') {
17876 $mirrorUrl = ComposerMirror::processHgUrl($mirror['url'], $this->name, $url, $type);
17877 }
17878 if (!in_array($mirrorUrl, $urls)) {
17879 $func = $mirror['preferred'] ? 'array_unshift' : 'array_push';
17880 $func($urls, $mirrorUrl);
17881 }
17882 }
17883 }
17884
17885 return $urls;
17886 }
17887 }
17888 <?php
17889
17890
17891
17892
17893
17894
17895
17896
17897
17898
17899
17900 namespace Composer\Package;
17901
17902 use Composer\Package\LinkConstraint\VersionConstraint;
17903 use Composer\Package\Version\VersionParser;
17904
17905
17906
17907
17908 class AliasPackage extends BasePackage implements CompletePackageInterface
17909 {
17910 protected $version;
17911 protected $prettyVersion;
17912 protected $dev;
17913 protected $aliasOf;
17914 protected $rootPackageAlias = false;
17915 protected $stability;
17916
17917 protected $requires;
17918 protected $conflicts;
17919 protected $provides;
17920 protected $replaces;
17921 protected $recommends;
17922 protected $suggests;
17923
17924
17925
17926
17927
17928
17929
17930
17931 public function __construct(PackageInterface $aliasOf, $version, $prettyVersion)
17932 {
17933 parent::__construct($aliasOf->getName());
17934
17935 $this->version = $version;
17936 $this->prettyVersion = $prettyVersion;
17937 $this->aliasOf = $aliasOf;
17938 $this->stability = VersionParser::parseStability($version);
17939 $this->dev = $this->stability === 'dev';
17940
17941
17942  foreach (array('requires', 'devRequires') as $type) {
17943 $links = $aliasOf->{'get'.ucfirst($type)}();
17944 foreach ($links as $index => $link) {
17945
17946  if ('self.version' === $link->getPrettyConstraint()) {
17947 $links[$index] = new Link($link->getSource(), $link->getTarget(), new VersionConstraint('=', $this->version), $type, $prettyVersion);
17948 }
17949 }
17950 $this->$type = $links;
17951 }
17952
17953
17954  foreach (array('conflicts', 'provides', 'replaces') as $type) {
17955 $links = $aliasOf->{'get'.ucfirst($type)}();
17956 $newLinks = array();
17957 foreach ($links as $link) {
17958
17959  if ('self.version' === $link->getPrettyConstraint()) {
17960 $newLinks[] = new Link($link->getSource(), $link->getTarget(), new VersionConstraint('=', $this->version), $type, $prettyVersion);
17961 }
17962 }
17963 $this->$type = array_merge($links, $newLinks);
17964 }
17965 }
17966
17967 public function getAliasOf()
17968 {
17969 return $this->aliasOf;
17970 }
17971
17972
17973
17974
17975 public function getVersion()
17976 {
17977 return $this->version;
17978 }
17979
17980
17981
17982
17983 public function getStability()
17984 {
17985 return $this->stability;
17986 }
17987
17988
17989
17990
17991 public function getPrettyVersion()
17992 {
17993 return $this->prettyVersion;
17994 }
17995
17996
17997
17998
17999 public function isDev()
18000 {
18001 return $this->dev;
18002 }
18003
18004
18005
18006
18007 public function getRequires()
18008 {
18009 return $this->requires;
18010 }
18011
18012
18013
18014
18015 public function getConflicts()
18016 {
18017 return $this->conflicts;
18018 }
18019
18020
18021
18022
18023 public function getProvides()
18024 {
18025 return $this->provides;
18026 }
18027
18028
18029
18030
18031 public function getReplaces()
18032 {
18033 return $this->replaces;
18034 }
18035
18036
18037
18038
18039 public function getDevRequires()
18040 {
18041 return $this->devRequires;
18042 }
18043
18044
18045
18046
18047
18048
18049
18050
18051
18052
18053 public function setRootPackageAlias($value)
18054 {
18055 return $this->rootPackageAlias = $value;
18056 }
18057
18058
18059
18060
18061
18062 public function isRootPackageAlias()
18063 {
18064 return $this->rootPackageAlias;
18065 }
18066
18067
18068
18069
18070
18071 public function getType()
18072 {
18073 return $this->aliasOf->getType();
18074 }
18075 public function getTargetDir()
18076 {
18077 return $this->aliasOf->getTargetDir();
18078 }
18079 public function getExtra()
18080 {
18081 return $this->aliasOf->getExtra();
18082 }
18083 public function setInstallationSource($type)
18084 {
18085 $this->aliasOf->setInstallationSource($type);
18086 }
18087 public function getInstallationSource()
18088 {
18089 return $this->aliasOf->getInstallationSource();
18090 }
18091 public function getSourceType()
18092 {
18093 return $this->aliasOf->getSourceType();
18094 }
18095 public function getSourceUrl()
18096 {
18097 return $this->aliasOf->getSourceUrl();
18098 }
18099 public function getSourceUrls()
18100 {
18101 return $this->aliasOf->getSourceUrls();
18102 }
18103 public function getSourceReference()
18104 {
18105 return $this->aliasOf->getSourceReference();
18106 }
18107 public function setSourceReference($reference)
18108 {
18109 return $this->aliasOf->setSourceReference($reference);
18110 }
18111 public function setSourceMirrors($mirrors)
18112 {
18113 return $this->aliasOf->setSourceMirrors($mirrors);
18114 }
18115 public function getSourceMirrors()
18116 {
18117 return $this->aliasOf->getSourceMirrors();
18118 }
18119 public function getDistType()
18120 {
18121 return $this->aliasOf->getDistType();
18122 }
18123 public function getDistUrl()
18124 {
18125 return $this->aliasOf->getDistUrl();
18126 }
18127 public function getDistUrls()
18128 {
18129 return $this->aliasOf->getDistUrls();
18130 }
18131 public function getDistReference()
18132 {
18133 return $this->aliasOf->getDistReference();
18134 }
18135 public function setDistReference($reference)
18136 {
18137 return $this->aliasOf->setDistReference($reference);
18138 }
18139 public function getDistSha1Checksum()
18140 {
18141 return $this->aliasOf->getDistSha1Checksum();
18142 }
18143 public function setTransportOptions(array $options)
18144 {
18145 return $this->aliasOf->setTransportOptions($options);
18146 }
18147 public function getTransportOptions()
18148 {
18149 return $this->aliasOf->getTransportOptions();
18150 }
18151 public function setDistMirrors($mirrors)
18152 {
18153 return $this->aliasOf->setDistMirrors($mirrors);
18154 }
18155 public function getDistMirrors()
18156 {
18157 return $this->aliasOf->getDistMirrors();
18158 }
18159 public function getScripts()
18160 {
18161 return $this->aliasOf->getScripts();
18162 }
18163 public function getLicense()
18164 {
18165 return $this->aliasOf->getLicense();
18166 }
18167 public function getAutoload()
18168 {
18169 return $this->aliasOf->getAutoload();
18170 }
18171 public function getDevAutoload()
18172 {
18173 return $this->aliasOf->getDevAutoload();
18174 }
18175 public function getIncludePaths()
18176 {
18177 return $this->aliasOf->getIncludePaths();
18178 }
18179 public function getRepositories()
18180 {
18181 return $this->aliasOf->getRepositories();
18182 }
18183 public function getReleaseDate()
18184 {
18185 return $this->aliasOf->getReleaseDate();
18186 }
18187 public function getBinaries()
18188 {
18189 return $this->aliasOf->getBinaries();
18190 }
18191 public function getKeywords()
18192 {
18193 return $this->aliasOf->getKeywords();
18194 }
18195 public function getDescription()
18196 {
18197 return $this->aliasOf->getDescription();
18198 }
18199 public function getHomepage()
18200 {
18201 return $this->aliasOf->getHomepage();
18202 }
18203 public function getSuggests()
18204 {
18205 return $this->aliasOf->getSuggests();
18206 }
18207 public function getAuthors()
18208 {
18209 return $this->aliasOf->getAuthors();
18210 }
18211 public function getSupport()
18212 {
18213 return $this->aliasOf->getSupport();
18214 }
18215 public function getNotificationUrl()
18216 {
18217 return $this->aliasOf->getNotificationUrl();
18218 }
18219 public function getArchiveExcludes()
18220 {
18221 return $this->aliasOf->getArchiveExcludes();
18222 }
18223 public function isAbandoned()
18224 {
18225 return $this->aliasOf->isAbandoned();
18226 }
18227 public function getReplacementPackage()
18228 {
18229 return $this->aliasOf->getReplacementPackage();
18230 }
18231 public function __toString()
18232 {
18233 return parent::__toString().' (alias of '.$this->aliasOf->getVersion().')';
18234 }
18235 }
18236 <?php
18237
18238
18239
18240
18241
18242
18243
18244
18245
18246
18247
18248 namespace Composer\Package;
18249
18250 use Composer\Package\LinkConstraint\LinkConstraintInterface;
18251
18252
18253
18254
18255
18256
18257 class Link
18258 {
18259 protected $source;
18260 protected $target;
18261 protected $constraint;
18262 protected $description;
18263 protected $prettyConstraint;
18264
18265
18266
18267
18268
18269
18270
18271
18272
18273
18274 public function __construct($source, $target, LinkConstraintInterface $constraint = null, $description = 'relates to', $prettyConstraint = null)
18275 {
18276 $this->source = strtolower($source);
18277 $this->target = strtolower($target);
18278 $this->constraint = $constraint;
18279 $this->description = $description;
18280 $this->prettyConstraint = $prettyConstraint;
18281 }
18282
18283 public function getSource()
18284 {
18285 return $this->source;
18286 }
18287
18288 public function getTarget()
18289 {
18290 return $this->target;
18291 }
18292
18293 public function getConstraint()
18294 {
18295 return $this->constraint;
18296 }
18297
18298 public function getPrettyConstraint()
18299 {
18300 if (null === $this->prettyConstraint) {
18301 throw new \UnexpectedValueException(sprintf('Link %s has been misconfigured and had no prettyConstraint given.', $this));
18302 }
18303
18304 return $this->prettyConstraint;
18305 }
18306
18307 public function __toString()
18308 {
18309 return $this->source.' '.$this->description.' '.$this->target.' ('.$this->constraint.')';
18310 }
18311
18312 public function getPrettyString(PackageInterface $sourcePackage)
18313 {
18314 return $sourcePackage->getPrettyString().' '.$this->description.' '.$this->target.' '.$this->constraint->getPrettyString().'';
18315 }
18316 }
18317 <?php
18318
18319
18320
18321
18322
18323
18324
18325
18326
18327
18328
18329 namespace Composer\Package\LinkConstraint;
18330
18331
18332
18333
18334
18335
18336 class EmptyConstraint implements LinkConstraintInterface
18337 {
18338 protected $prettyString;
18339
18340 public function matches(LinkConstraintInterface $provider)
18341 {
18342 return true;
18343 }
18344
18345 public function setPrettyString($prettyString)
18346 {
18347 $this->prettyString = $prettyString;
18348 }
18349
18350 public function getPrettyString()
18351 {
18352 if ($this->prettyString) {
18353 return $this->prettyString;
18354 }
18355
18356 return $this->__toString();
18357 }
18358
18359 public function __toString()
18360 {
18361 return '[]';
18362 }
18363 }
18364 <?php
18365
18366
18367
18368
18369
18370
18371
18372
18373
18374
18375
18376 namespace Composer\Package\LinkConstraint;
18377
18378
18379
18380
18381
18382
18383
18384 class MultiConstraint implements LinkConstraintInterface
18385 {
18386 protected $constraints;
18387 protected $prettyString;
18388 protected $conjunctive;
18389
18390
18391
18392
18393
18394
18395
18396 public function __construct(array $constraints, $conjunctive = true)
18397 {
18398 $this->constraints = $constraints;
18399 $this->conjunctive = $conjunctive;
18400 }
18401
18402 public function matches(LinkConstraintInterface $provider)
18403 {
18404 if (false === $this->conjunctive) {
18405 foreach ($this->constraints as $constraint) {
18406 if ($constraint->matches($provider)) {
18407 return true;
18408 }
18409 }
18410
18411 return false;
18412 }
18413
18414 foreach ($this->constraints as $constraint) {
18415 if (!$constraint->matches($provider)) {
18416 return false;
18417 }
18418 }
18419
18420 return true;
18421 }
18422
18423 public function setPrettyString($prettyString)
18424 {
18425 $this->prettyString = $prettyString;
18426 }
18427
18428 public function getPrettyString()
18429 {
18430 if ($this->prettyString) {
18431 return $this->prettyString;
18432 }
18433
18434 return $this->__toString();
18435 }
18436
18437 public function __toString()
18438 {
18439 $constraints = array();
18440 foreach ($this->constraints as $constraint) {
18441 $constraints[] = $constraint->__toString();
18442 }
18443
18444 return '['.implode($this->conjunctive ? ' ' : ' || ', $constraints).']';
18445 }
18446 }
18447 <?php
18448
18449
18450
18451
18452
18453
18454
18455
18456
18457
18458
18459 namespace Composer\Package\LinkConstraint;
18460
18461
18462
18463
18464
18465
18466
18467
18468 class VersionConstraint extends SpecificConstraint
18469 {
18470 private $operator;
18471 private $version;
18472
18473
18474
18475
18476
18477
18478
18479 public function __construct($operator, $version)
18480 {
18481 if ('=' === $operator) {
18482 $operator = '==';
18483 }
18484
18485 if ('<>' === $operator) {
18486 $operator = '!=';
18487 }
18488
18489 $this->operator = $operator;
18490 $this->version = $version;
18491 }
18492
18493 public function versionCompare($a, $b, $operator, $compareBranches = false)
18494 {
18495 $aIsBranch = 'dev-' === substr($a, 0, 4);
18496 $bIsBranch = 'dev-' === substr($b, 0, 4);
18497 if ($aIsBranch && $bIsBranch) {
18498 return $operator == '==' && $a === $b;
18499 }
18500
18501
18502  if (!$compareBranches && ($aIsBranch || $bIsBranch)) {
18503 return false;
18504 }
18505
18506 return version_compare($a, $b, $operator);
18507 }
18508
18509
18510
18511
18512
18513
18514 public function matchSpecific(VersionConstraint $provider, $compareBranches = false)
18515 {
18516 static $cache = array();
18517 if (isset($cache[$this->operator][$this->version][$provider->operator][$provider->version][$compareBranches])) {
18518 return $cache[$this->operator][$this->version][$provider->operator][$provider->version][$compareBranches];
18519 }
18520
18521 return $cache[$this->operator][$this->version][$provider->operator][$provider->version][$compareBranches] =
18522 $this->doMatchSpecific($provider, $compareBranches);
18523 }
18524
18525
18526
18527
18528
18529
18530 private function doMatchSpecific(VersionConstraint $provider, $compareBranches = false)
18531 {
18532 $noEqualOp = str_replace('=', '', $this->operator);
18533 $providerNoEqualOp = str_replace('=', '', $provider->operator);
18534
18535 $isEqualOp = '==' === $this->operator;
18536 $isNonEqualOp = '!=' === $this->operator;
18537 $isProviderEqualOp = '==' === $provider->operator;
18538 $isProviderNonEqualOp = '!=' === $provider->operator;
18539
18540
18541  
18542  if ($isNonEqualOp || $isProviderNonEqualOp) {
18543 return !$isEqualOp && !$isProviderEqualOp
18544 || $this->versionCompare($provider->version, $this->version, '!=', $compareBranches);
18545 }
18546
18547
18548  
18549  if ($this->operator != '==' && $noEqualOp == $providerNoEqualOp) {
18550 return true;
18551 }
18552
18553 if ($this->versionCompare($provider->version, $this->version, $this->operator, $compareBranches)) {
18554
18555  
18556  if ($provider->version == $this->version && $provider->operator == $providerNoEqualOp && $this->operator != $noEqualOp) {
18557 return false;
18558 }
18559
18560 return true;
18561 }
18562
18563 return false;
18564 }
18565
18566 public function __toString()
18567 {
18568 return $this->operator.' '.$this->version;
18569 }
18570 }
18571 <?php
18572
18573
18574
18575
18576
18577
18578
18579
18580
18581
18582
18583 namespace Composer\Package\LinkConstraint;
18584
18585
18586
18587
18588
18589
18590 abstract class SpecificConstraint implements LinkConstraintInterface
18591 {
18592 protected $prettyString;
18593
18594 public function matches(LinkConstraintInterface $provider)
18595 {
18596 if ($provider instanceof MultiConstraint) {
18597
18598  return $provider->matches($this);
18599 } elseif ($provider instanceof $this) {
18600 return $this->matchSpecific($provider);
18601 }
18602
18603 return true;
18604 }
18605
18606 public function setPrettyString($prettyString)
18607 {
18608 $this->prettyString = $prettyString;
18609 }
18610
18611 public function getPrettyString()
18612 {
18613 if ($this->prettyString) {
18614 return $this->prettyString;
18615 }
18616
18617 return $this->__toString();
18618 }
18619
18620
18621  
18622  
18623 }
18624 <?php
18625
18626
18627
18628
18629
18630
18631
18632
18633
18634
18635
18636 namespace Composer\Package\LinkConstraint;
18637
18638
18639
18640
18641
18642
18643 interface LinkConstraintInterface
18644 {
18645 public function matches(LinkConstraintInterface $provider);
18646 public function setPrettyString($prettyString);
18647 public function getPrettyString();
18648 public function __toString();
18649 }
18650 <?php
18651
18652
18653
18654
18655
18656
18657
18658
18659
18660
18661
18662 namespace Composer;
18663
18664 use Composer\IO\IOInterface;
18665 use Composer\Util\Filesystem;
18666 use Symfony\Component\Finder\Finder;
18667
18668
18669
18670
18671
18672
18673 class Cache
18674 {
18675 private static $cacheCollected = false;
18676 private $io;
18677 private $root;
18678 private $enabled = true;
18679 private $whitelist;
18680 private $filesystem;
18681
18682
18683
18684
18685
18686
18687
18688 public function __construct(IOInterface $io, $cacheDir, $whitelist = 'a-z0-9.', Filesystem $filesystem = null)
18689 {
18690 $this->io = $io;
18691 $this->root = rtrim($cacheDir, '/\\') . '/';
18692 $this->whitelist = $whitelist;
18693 $this->filesystem = $filesystem ?: new Filesystem();
18694
18695 if (!is_dir($this->root)) {
18696 if (!@mkdir($this->root, 0777, true)) {
18697 $this->enabled = false;
18698 }
18699 }
18700 }
18701
18702 public function isEnabled()
18703 {
18704 return $this->enabled;
18705 }
18706
18707 public function getRoot()
18708 {
18709 return $this->root;
18710 }
18711
18712 public function read($file)
18713 {
18714 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18715 if ($this->enabled && file_exists($this->root . $file)) {
18716 if ($this->io->isDebug()) {
18717 $this->io->write('Reading '.$this->root . $file.' from cache');
18718 }
18719
18720 return file_get_contents($this->root . $file);
18721 }
18722
18723 return false;
18724 }
18725
18726 public function write($file, $contents)
18727 {
18728 if ($this->enabled) {
18729 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18730
18731 if ($this->io->isDebug()) {
18732 $this->io->write('Writing '.$this->root . $file.' into cache');
18733 }
18734
18735 try {
18736 return file_put_contents($this->root . $file, $contents);
18737 } catch (\ErrorException $e) {
18738 if (preg_match('{^file_put_contents\(\): Only ([0-9]+) of ([0-9]+) bytes written}', $e->getMessage(), $m)) {
18739
18740  unlink($this->root . $file);
18741
18742 $message = sprintf(
18743 '<warning>Writing %1$s into cache failed after %2$u of %3$u bytes written, only %4$u bytes of free space available</warning>',
18744 $this->root . $file,
18745 $m[1],
18746 $m[2],
18747 @disk_free_space($this->root . dirname($file))
18748 );
18749
18750 $this->io->write($message);
18751
18752 return false;
18753 }
18754
18755 throw $e;
18756 }
18757 }
18758
18759 return false;
18760 }
18761
18762
18763
18764
18765 public function copyFrom($file, $source)
18766 {
18767 if ($this->enabled) {
18768 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18769 $this->filesystem->ensureDirectoryExists(dirname($this->root . $file));
18770
18771 if ($this->io->isDebug()) {
18772 $this->io->write('Writing '.$this->root . $file.' into cache');
18773 }
18774
18775 return copy($source, $this->root . $file);
18776 }
18777
18778 return false;
18779 }
18780
18781
18782
18783
18784 public function copyTo($file, $target)
18785 {
18786 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18787 if ($this->enabled && file_exists($this->root . $file)) {
18788 touch($this->root . $file);
18789
18790 if ($this->io->isDebug()) {
18791 $this->io->write('Reading '.$this->root . $file.' from cache');
18792 }
18793
18794 return copy($this->root . $file, $target);
18795 }
18796
18797 return false;
18798 }
18799
18800 public function gcIsNecessary()
18801 {
18802 return (!self::$cacheCollected && !mt_rand(0, 50));
18803 }
18804
18805 public function remove($file)
18806 {
18807 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18808 if ($this->enabled && file_exists($this->root . $file)) {
18809 return $this->filesystem->unlink($this->root . $file);
18810 }
18811
18812 return false;
18813 }
18814
18815 public function gc($ttl, $maxSize)
18816 {
18817 if ($this->enabled) {
18818 $expire = new \DateTime();
18819 $expire->modify('-'.$ttl.' seconds');
18820
18821 $finder = $this->getFinder()->date('until '.$expire->format('Y-m-d H:i:s'));
18822 foreach ($finder as $file) {
18823 $this->filesystem->unlink($file->getPathname());
18824 }
18825
18826 $totalSize = $this->filesystem->size($this->root);
18827 if ($totalSize > $maxSize) {
18828 $iterator = $this->getFinder()->sortByAccessedTime()->getIterator();
18829 while ($totalSize > $maxSize && $iterator->valid()) {
18830 $filepath = $iterator->current()->getPathname();
18831 $totalSize -= $this->filesystem->size($filepath);
18832 $this->filesystem->unlink($filepath);
18833 $iterator->next();
18834 }
18835 }
18836
18837 self::$cacheCollected = true;
18838
18839 return true;
18840 }
18841
18842 return false;
18843 }
18844
18845 public function sha1($file)
18846 {
18847 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18848 if ($this->enabled && file_exists($this->root . $file)) {
18849 return sha1_file($this->root . $file);
18850 }
18851
18852 return false;
18853 }
18854
18855 public function sha256($file)
18856 {
18857 $file = preg_replace('{[^'.$this->whitelist.']}i', '-', $file);
18858 if ($this->enabled && file_exists($this->root . $file)) {
18859 return hash_file('sha256', $this->root . $file);
18860 }
18861
18862 return false;
18863 }
18864
18865 protected function getFinder()
18866 {
18867 return Finder::create()->in($this->root)->files();
18868 }
18869 }
18870 <?php
18871
18872
18873
18874
18875
18876
18877
18878
18879
18880
18881
18882 namespace Composer\DependencyResolver;
18883
18884 use Composer\Package\PackageInterface;
18885
18886
18887
18888
18889 interface PolicyInterface
18890 {
18891 public function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
18892 public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package);
18893 public function selectPreferedPackages(Pool $pool, array $installedMap, array $literals);
18894 }
18895 <?php
18896
18897
18898
18899
18900
18901
18902
18903
18904
18905
18906
18907 namespace Composer\DependencyResolver;
18908
18909
18910
18911
18912 class RuleSet implements \IteratorAggregate, \Countable
18913 {
18914
18915  const TYPE_PACKAGE = 0;
18916 const TYPE_JOB = 1;
18917 const TYPE_LEARNED = 4;
18918
18919
18920
18921
18922
18923
18924 public $ruleById;
18925
18926 protected static $types = array(
18927 -1 => 'UNKNOWN',
18928 self::TYPE_PACKAGE => 'PACKAGE',
18929 self::TYPE_JOB => 'JOB',
18930 self::TYPE_LEARNED => 'LEARNED',
18931 );
18932
18933 protected $rules;
18934 protected $nextRuleId;
18935
18936 protected $rulesByHash;
18937
18938 public function __construct()
18939 {
18940 $this->nextRuleId = 0;
18941
18942 foreach ($this->getTypes() as $type) {
18943 $this->rules[$type] = array();
18944 }
18945
18946 $this->rulesByHash = array();
18947 }
18948
18949 public function add(Rule $rule, $type)
18950 {
18951 if (!isset(self::$types[$type])) {
18952 throw new \OutOfBoundsException('Unknown rule type: ' . $type);
18953 }
18954
18955 if (!isset($this->rules[$type])) {
18956 $this->rules[$type] = array();
18957 }
18958
18959 $this->rules[$type][] = $rule;
18960 $this->ruleById[$this->nextRuleId] = $rule;
18961 $rule->setType($type);
18962
18963 $rule->setId($this->nextRuleId);
18964 $this->nextRuleId++;
18965
18966 $hash = $rule->getHash();
18967 if (!isset($this->rulesByHash[$hash])) {
18968 $this->rulesByHash[$hash] = array($rule);
18969 } else {
18970 $this->rulesByHash[$hash][] = $rule;
18971 }
18972 }
18973
18974 public function count()
18975 {
18976 return $this->nextRuleId;
18977 }
18978
18979 public function ruleById($id)
18980 {
18981 return $this->ruleById[$id];
18982 }
18983
18984 public function getRules()
18985 {
18986 return $this->rules;
18987 }
18988
18989 public function getIterator()
18990 {
18991 return new RuleSetIterator($this->getRules());
18992 }
18993
18994 public function getIteratorFor($types)
18995 {
18996 if (!is_array($types)) {
18997 $types = array($types);
18998 }
18999
19000 $allRules = $this->getRules();
19001 $rules = array();
19002
19003 foreach ($types as $type) {
19004 $rules[$type] = $allRules[$type];
19005 }
19006
19007 return new RuleSetIterator($rules);
19008 }
19009
19010 public function getIteratorWithout($types)
19011 {
19012 if (!is_array($types)) {
19013 $types = array($types);
19014 }
19015
19016 $rules = $this->getRules();
19017
19018 foreach ($types as $type) {
19019 unset($rules[$type]);
19020 }
19021
19022 return new RuleSetIterator($rules);
19023 }
19024
19025 public function getTypes()
19026 {
19027 $types = self::$types;
19028 unset($types[-1]);
19029
19030 return array_keys($types);
19031 }
19032
19033 public function containsEqual($rule)
19034 {
19035 if (isset($this->rulesByHash[$rule->getHash()])) {
19036 $potentialDuplicates = $this->rulesByHash[$rule->getHash()];
19037 foreach ($potentialDuplicates as $potentialDuplicate) {
19038 if ($rule->equals($potentialDuplicate)) {
19039 return true;
19040 }
19041 }
19042 }
19043
19044 return false;
19045 }
19046
19047 public function getPrettyString(Pool $pool = null)
19048 {
19049 $string = "\n";
19050 foreach ($this->rules as $type => $rules) {
19051 $string .= str_pad(self::$types[$type], 8, ' ') . ": ";
19052 foreach ($rules as $rule) {
19053 $string .= ($pool ? $rule->getPrettyString($pool) : $rule)."\n";
19054 }
19055 $string .= "\n\n";
19056 }
19057
19058 return $string;
19059 }
19060
19061 public function __toString()
19062 {
19063 return $this->getPrettyString(null);
19064 }
19065 }
19066 <?php
19067
19068
19069
19070
19071
19072
19073
19074
19075
19076
19077
19078 namespace Composer\DependencyResolver;
19079
19080
19081
19082
19083 class SolverBugException extends \RuntimeException
19084 {
19085 public function __construct($message)
19086 {
19087 parent::__construct(
19088 $message."\nThis exception was most likely caused by a bug in Composer.\n".
19089 "Please report the command you ran, the exact error you received, and your composer.json on https://github.com/composer/composer/issues - thank you!\n");
19090 }
19091 }
19092 <?php
19093
19094
19095
19096
19097
19098
19099
19100
19101
19102
19103
19104 namespace Composer\DependencyResolver;
19105
19106 use Composer\Package\PackageInterface;
19107 use Composer\Package\AliasPackage;
19108 use Composer\Package\BasePackage;
19109 use Composer\Package\LinkConstraint\VersionConstraint;
19110
19111
19112
19113
19114
19115 class DefaultPolicy implements PolicyInterface
19116 {
19117 private $preferStable;
19118 private $preferLowest;
19119
19120 public function __construct($preferStable = false, $preferLowest = false)
19121 {
19122 $this->preferStable = $preferStable;
19123 $this->preferLowest = $preferLowest;
19124 }
19125
19126 public function versionCompare(PackageInterface $a, PackageInterface $b, $operator)
19127 {
19128 if ($this->preferStable && ($stabA = $a->getStability()) !== ($stabB = $b->getStability())) {
19129 return BasePackage::$stabilities[$stabA] < BasePackage::$stabilities[$stabB];
19130 }
19131
19132 $constraint = new VersionConstraint($operator, $b->getVersion());
19133 $version = new VersionConstraint('==', $a->getVersion());
19134
19135 return $constraint->matchSpecific($version, true);
19136 }
19137
19138 public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package, $mustMatchName = false)
19139 {
19140 $packages = array();
19141
19142 foreach ($pool->whatProvides($package->getName(), null, $mustMatchName) as $candidate) {
19143 if ($candidate !== $package) {
19144 $packages[] = $candidate;
19145 }
19146 }
19147
19148 return $packages;
19149 }
19150
19151 public function getPriority(Pool $pool, PackageInterface $package)
19152 {
19153 return $pool->getPriority($package->getRepository());
19154 }
19155
19156 public function selectPreferedPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null)
19157 {
19158 $packages = $this->groupLiteralsByNamePreferInstalled($pool, $installedMap, $literals);
19159
19160 foreach ($packages as &$literals) {
19161 $policy = $this;
19162 usort($literals, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
19163 return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage, true);
19164 });
19165 }
19166
19167 foreach ($packages as &$literals) {
19168 $literals = $this->pruneToBestVersion($pool, $literals);
19169
19170 $literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals);
19171
19172 $literals = $this->pruneRemoteAliases($pool, $literals);
19173 }
19174
19175 $selected = call_user_func_array('array_merge', $packages);
19176
19177
19178  usort($selected, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
19179 return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage);
19180 });
19181
19182 return $selected;
19183 }
19184
19185 protected function groupLiteralsByNamePreferInstalled(Pool $pool, array $installedMap, $literals)
19186 {
19187 $packages = array();
19188 foreach ($literals as $literal) {
19189 $packageName = $pool->literalToPackage($literal)->getName();
19190
19191 if (!isset($packages[$packageName])) {
19192 $packages[$packageName] = array();
19193 }
19194
19195 if (isset($installedMap[abs($literal)])) {
19196 array_unshift($packages[$packageName], $literal);
19197 } else {
19198 $packages[$packageName][] = $literal;
19199 }
19200 }
19201
19202 return $packages;
19203 }
19204
19205
19206
19207
19208 public function compareByPriorityPreferInstalled(Pool $pool, array $installedMap, PackageInterface $a, PackageInterface $b, $requiredPackage = null, $ignoreReplace = false)
19209 {
19210 if ($a->getRepository() === $b->getRepository()) {
19211
19212  if ($a->getName() === $b->getName()) {
19213 $aAliased = $a instanceof AliasPackage;
19214 $bAliased = $b instanceof AliasPackage;
19215 if ($aAliased && !$bAliased) {
19216 return -1; 
19217  }
19218 if (!$aAliased && $bAliased) {
19219 return 1; 
19220  }
19221 }
19222
19223 if (!$ignoreReplace) {
19224
19225  if ($this->replaces($a, $b)) {
19226 return 1; 
19227  }
19228 if ($this->replaces($b, $a)) {
19229 return -1; 
19230  }
19231
19232
19233  
19234  if ($requiredPackage && false !== ($pos = strpos($requiredPackage, '/'))) {
19235 $requiredVendor = substr($requiredPackage, 0, $pos);
19236
19237 $aIsSameVendor = substr($a->getName(), 0, $pos) === $requiredVendor;
19238 $bIsSameVendor = substr($b->getName(), 0, $pos) === $requiredVendor;
19239
19240 if ($bIsSameVendor !== $aIsSameVendor) {
19241 return $aIsSameVendor ? -1 : 1;
19242 }
19243 }
19244 }
19245
19246
19247  if ($a->id === $b->id) {
19248 return 0;
19249 }
19250
19251 return ($a->id < $b->id) ? -1 : 1;
19252 }
19253
19254 if (isset($installedMap[$a->id])) {
19255 return -1;
19256 }
19257
19258 if (isset($installedMap[$b->id])) {
19259 return 1;
19260 }
19261
19262 return ($this->getPriority($pool, $a) > $this->getPriority($pool, $b)) ? -1 : 1;
19263 }
19264
19265
19266
19267
19268
19269
19270
19271
19272
19273
19274
19275 protected function replaces(PackageInterface $source, PackageInterface $target)
19276 {
19277 foreach ($source->getReplaces() as $link) {
19278 if ($link->getTarget() === $target->getName()
19279
19280
19281  ) {
19282 return true;
19283 }
19284 }
19285
19286 return false;
19287 }
19288
19289 protected function pruneToBestVersion(Pool $pool, $literals)
19290 {
19291 $operator = $this->preferLowest ? '<' : '>';
19292 $bestLiterals = array($literals[0]);
19293 $bestPackage = $pool->literalToPackage($literals[0]);
19294 foreach ($literals as $i => $literal) {
19295 if (0 === $i) {
19296 continue;
19297 }
19298
19299 $package = $pool->literalToPackage($literal);
19300
19301 if ($this->versionCompare($package, $bestPackage, $operator)) {
19302 $bestPackage = $package;
19303 $bestLiterals = array($literal);
19304 } elseif ($this->versionCompare($package, $bestPackage, '==')) {
19305 $bestLiterals[] = $literal;
19306 }
19307 }
19308
19309 return $bestLiterals;
19310 }
19311
19312
19313
19314
19315 protected function pruneToHighestPriorityOrInstalled(Pool $pool, array $installedMap, array $literals)
19316 {
19317 $selected = array();
19318
19319 $priority = null;
19320
19321 foreach ($literals as $literal) {
19322 $package = $pool->literalToPackage($literal);
19323
19324 if (isset($installedMap[$package->id])) {
19325 $selected[] = $literal;
19326 continue;
19327 }
19328
19329 if (null === $priority) {
19330 $priority = $this->getPriority($pool, $package);
19331 }
19332
19333 if ($this->getPriority($pool, $package) != $priority) {
19334 break;
19335 }
19336
19337 $selected[] = $literal;
19338 }
19339
19340 return $selected;
19341 }
19342
19343
19344
19345
19346
19347
19348 protected function pruneRemoteAliases(Pool $pool, array $literals)
19349 {
19350 $hasLocalAlias = false;
19351
19352 foreach ($literals as $literal) {
19353 $package = $pool->literalToPackage($literal);
19354
19355 if ($package instanceof AliasPackage && $package->isRootPackageAlias()) {
19356 $hasLocalAlias = true;
19357 break;
19358 }
19359 }
19360
19361 if (!$hasLocalAlias) {
19362 return $literals;
19363 }
19364
19365 $selected = array();
19366 foreach ($literals as $literal) {
19367 $package = $pool->literalToPackage($literal);
19368
19369 if ($package instanceof AliasPackage && $package->isRootPackageAlias()) {
19370 $selected[] = $literal;
19371 }
19372 }
19373
19374 return $selected;
19375 }
19376 }
19377 <?php
19378
19379
19380
19381
19382
19383
19384
19385
19386
19387
19388
19389 namespace Composer\DependencyResolver;
19390
19391
19392
19393
19394
19395
19396 class Decisions implements \Iterator, \Countable
19397 {
19398 const DECISION_LITERAL = 0;
19399 const DECISION_REASON = 1;
19400
19401 protected $pool;
19402 protected $decisionMap;
19403 protected $decisionQueue = array();
19404
19405 public function __construct($pool)
19406 {
19407 $this->pool = $pool;
19408 $this->decisionMap = array();
19409 }
19410
19411 public function decide($literal, $level, $why)
19412 {
19413 $this->addDecision($literal, $level);
19414 $this->decisionQueue[] = array(
19415 self::DECISION_LITERAL => $literal,
19416 self::DECISION_REASON => $why,
19417 );
19418 }
19419
19420 public function satisfy($literal)
19421 {
19422 $packageId = abs($literal);
19423
19424 return (
19425 $literal > 0 && isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] > 0 ||
19426 $literal < 0 && isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] < 0
19427 );
19428 }
19429
19430 public function conflict($literal)
19431 {
19432 $packageId = abs($literal);
19433
19434 return (
19435 (isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] > 0 && $literal < 0) ||
19436 (isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] < 0 && $literal > 0)
19437 );
19438 }
19439
19440 public function decided($literalOrPackageId)
19441 {
19442 return !empty($this->decisionMap[abs($literalOrPackageId)]);
19443 }
19444
19445 public function undecided($literalOrPackageId)
19446 {
19447 return empty($this->decisionMap[abs($literalOrPackageId)]);
19448 }
19449
19450 public function decidedInstall($literalOrPackageId)
19451 {
19452 $packageId = abs($literalOrPackageId);
19453
19454 return isset($this->decisionMap[$packageId]) && $this->decisionMap[$packageId] > 0;
19455 }
19456
19457 public function decisionLevel($literalOrPackageId)
19458 {
19459 $packageId = abs($literalOrPackageId);
19460 if (isset($this->decisionMap[$packageId])) {
19461 return abs($this->decisionMap[$packageId]);
19462 }
19463
19464 return 0;
19465 }
19466
19467 public function decisionRule($literalOrPackageId)
19468 {
19469 $packageId = abs($literalOrPackageId);
19470
19471 foreach ($this->decisionQueue as $i => $decision) {
19472 if ($packageId === abs($decision[self::DECISION_LITERAL])) {
19473 return $decision[self::DECISION_REASON];
19474 }
19475 }
19476
19477 return null;
19478 }
19479
19480 public function atOffset($queueOffset)
19481 {
19482 return $this->decisionQueue[$queueOffset];
19483 }
19484
19485 public function validOffset($queueOffset)
19486 {
19487 return $queueOffset >= 0 && $queueOffset < count($this->decisionQueue);
19488 }
19489
19490 public function lastReason()
19491 {
19492 return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_REASON];
19493 }
19494
19495 public function lastLiteral()
19496 {
19497 return $this->decisionQueue[count($this->decisionQueue) - 1][self::DECISION_LITERAL];
19498 }
19499
19500 public function reset()
19501 {
19502 while ($decision = array_pop($this->decisionQueue)) {
19503 $this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
19504 }
19505 }
19506
19507 public function resetToOffset($offset)
19508 {
19509 while (count($this->decisionQueue) > $offset + 1) {
19510 $decision = array_pop($this->decisionQueue);
19511 $this->decisionMap[abs($decision[self::DECISION_LITERAL])] = 0;
19512 }
19513 }
19514
19515 public function revertLast()
19516 {
19517 $this->decisionMap[abs($this->lastLiteral())] = 0;
19518 array_pop($this->decisionQueue);
19519 }
19520
19521 public function count()
19522 {
19523 return count($this->decisionQueue);
19524 }
19525
19526 public function rewind()
19527 {
19528 end($this->decisionQueue);
19529 }
19530
19531 public function current()
19532 {
19533 return current($this->decisionQueue);
19534 }
19535
19536 public function key()
19537 {
19538 return key($this->decisionQueue);
19539 }
19540
19541 public function next()
19542 {
19543 return prev($this->decisionQueue);
19544 }
19545
19546 public function valid()
19547 {
19548 return false !== current($this->decisionQueue);
19549 }
19550
19551 public function isEmpty()
19552 {
19553 return count($this->decisionQueue) === 0;
19554 }
19555
19556 protected function addDecision($literal, $level)
19557 {
19558 $packageId = abs($literal);
19559
19560 $previousDecision = isset($this->decisionMap[$packageId]) ? $this->decisionMap[$packageId] : null;
19561 if ($previousDecision != 0) {
19562 $literalString = $this->pool->literalToString($literal);
19563 $package = $this->pool->literalToPackage($literal);
19564 throw new SolverBugException(
19565 "Trying to decide $literalString on level $level, even though $package was previously decided as ".(int) $previousDecision."."
19566 );
19567 }
19568
19569 if ($literal > 0) {
19570 $this->decisionMap[$packageId] = $level;
19571 } else {
19572 $this->decisionMap[$packageId] = -$level;
19573 }
19574 }
19575 }
19576 <?php
19577
19578
19579
19580
19581
19582
19583
19584
19585
19586
19587
19588 namespace Composer\DependencyResolver;
19589
19590
19591
19592
19593
19594
19595
19596
19597 class RuleWatchNode
19598 {
19599 public $watch1;
19600 public $watch2;
19601
19602 protected $rule;
19603
19604
19605
19606
19607
19608
19609 public function __construct($rule)
19610 {
19611 $this->rule = $rule;
19612
19613 $literals = $rule->literals;
19614
19615 $this->watch1 = count($literals) > 0 ? $literals[0] : 0;
19616 $this->watch2 = count($literals) > 1 ? $literals[1] : 0;
19617 }
19618
19619
19620
19621
19622
19623
19624
19625
19626
19627 public function watch2OnHighest(Decisions $decisions)
19628 {
19629 $literals = $this->rule->literals;
19630
19631
19632  if (count($literals) < 3) {
19633 return;
19634 }
19635
19636 $watchLevel = 0;
19637
19638 foreach ($literals as $literal) {
19639 $level = $decisions->decisionLevel($literal);
19640
19641 if ($level > $watchLevel) {
19642 $this->watch2 = $literal;
19643 $watchLevel = $level;
19644 }
19645 }
19646 }
19647
19648
19649
19650
19651
19652
19653 public function getRule()
19654 {
19655 return $this->rule;
19656 }
19657
19658
19659
19660
19661
19662
19663
19664 public function getOtherWatch($literal)
19665 {
19666 if ($this->watch1 == $literal) {
19667 return $this->watch2;
19668 } else {
19669 return $this->watch1;
19670 }
19671 }
19672
19673
19674
19675
19676
19677
19678
19679 public function moveWatch($from, $to)
19680 {
19681 if ($this->watch1 == $from) {
19682 $this->watch1 = $to;
19683 } else {
19684 $this->watch2 = $to;
19685 }
19686 }
19687 }
19688 <?php
19689
19690
19691
19692
19693
19694
19695
19696
19697
19698
19699
19700 namespace Composer\DependencyResolver;
19701
19702
19703
19704
19705 class SolverProblemsException extends \RuntimeException
19706 {
19707 protected $problems;
19708 protected $installedMap;
19709
19710 public function __construct(array $problems, array $installedMap)
19711 {
19712 $this->problems = $problems;
19713 $this->installedMap = $installedMap;
19714
19715 parent::__construct($this->createMessage(), 2);
19716 }
19717
19718 protected function createMessage()
19719 {
19720 $text = "\n";
19721 foreach ($this->problems as $i => $problem) {
19722 $text .= "  Problem ".($i+1).$problem->getPrettyString($this->installedMap)."\n";
19723 }
19724
19725 if (strpos($text, 'could not be found') || strpos($text, 'no matching package found')) {
19726 $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.";
19727 }
19728
19729 return $text;
19730 }
19731
19732 public function getProblems()
19733 {
19734 return $this->problems;
19735 }
19736 }
19737 <?php
19738
19739
19740
19741
19742
19743
19744
19745
19746
19747
19748
19749 namespace Composer\DependencyResolver;
19750
19751 use Composer\Package\AliasPackage;
19752
19753
19754
19755
19756 class Transaction
19757 {
19758 protected $policy;
19759 protected $pool;
19760 protected $installedMap;
19761 protected $decisions;
19762 protected $transaction;
19763
19764 public function __construct($policy, $pool, $installedMap, $decisions)
19765 {
19766 $this->policy = $policy;
19767 $this->pool = $pool;
19768 $this->installedMap = $installedMap;
19769 $this->decisions = $decisions;
19770 $this->transaction = array();
19771 }
19772
19773 public function getOperations()
19774 {
19775 $installMeansUpdateMap = $this->findUpdates();
19776
19777 $updateMap = array();
19778 $installMap = array();
19779 $uninstallMap = array();
19780
19781 foreach ($this->decisions as $i => $decision) {
19782 $literal = $decision[Decisions::DECISION_LITERAL];
19783 $reason = $decision[Decisions::DECISION_REASON];
19784
19785 $package = $this->pool->literalToPackage($literal);
19786
19787
19788  if (($literal > 0) == (isset($this->installedMap[$package->id]))) {
19789 continue;
19790 }
19791
19792 if ($literal > 0) {
19793 if (isset($installMeansUpdateMap[abs($literal)]) && !$package instanceof AliasPackage) {
19794 $source = $installMeansUpdateMap[abs($literal)];
19795
19796 $updateMap[$package->id] = array(
19797 'package' => $package,
19798 'source' => $source,
19799 'reason' => $reason,
19800 );
19801
19802
19803  unset($installMeansUpdateMap[abs($literal)]);
19804 $ignoreRemove[$source->id] = true;
19805 } else {
19806 $installMap[$package->id] = array(
19807 'package' => $package,
19808 'reason' => $reason,
19809 );
19810 }
19811 }
19812 }
19813
19814 foreach ($this->decisions as $i => $decision) {
19815 $literal = $decision[Decisions::DECISION_LITERAL];
19816 $reason = $decision[Decisions::DECISION_REASON];
19817 $package = $this->pool->literalToPackage($literal);
19818
19819 if ($literal <= 0 &&
19820 isset($this->installedMap[$package->id]) &&
19821 !isset($ignoreRemove[$package->id])) {
19822 $uninstallMap[$package->id] = array(
19823 'package' => $package,
19824 'reason' => $reason,
19825 );
19826 }
19827 }
19828
19829 $this->transactionFromMaps($installMap, $updateMap, $uninstallMap);
19830
19831 return $this->transaction;
19832 }
19833
19834 protected function transactionFromMaps($installMap, $updateMap, $uninstallMap)
19835 {
19836 $queue = array_map(function ($operation) {
19837 return $operation['package'];
19838 },
19839 $this->findRootPackages($installMap, $updateMap)
19840 );
19841
19842 $visited = array();
19843
19844 while (!empty($queue)) {
19845 $package = array_pop($queue);
19846 $packageId = $package->id;
19847
19848 if (!isset($visited[$packageId])) {
19849 array_push($queue, $package);
19850
19851 if ($package instanceof AliasPackage) {
19852 array_push($queue, $package->getAliasOf());
19853 } else {
19854 foreach ($package->getRequires() as $link) {
19855 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
19856
19857 foreach ($possibleRequires as $require) {
19858 array_push($queue, $require);
19859 }
19860 }
19861 }
19862
19863 $visited[$package->id] = true;
19864 } else {
19865 if (isset($installMap[$packageId])) {
19866 $this->install(
19867 $installMap[$packageId]['package'],
19868 $installMap[$packageId]['reason']
19869 );
19870 unset($installMap[$packageId]);
19871 }
19872 if (isset($updateMap[$packageId])) {
19873 $this->update(
19874 $updateMap[$packageId]['source'],
19875 $updateMap[$packageId]['package'],
19876 $updateMap[$packageId]['reason']
19877 );
19878 unset($updateMap[$packageId]);
19879 }
19880 }
19881 }
19882
19883 foreach ($uninstallMap as $uninstall) {
19884 $this->uninstall($uninstall['package'], $uninstall['reason']);
19885 }
19886 }
19887
19888 protected function findRootPackages($installMap, $updateMap)
19889 {
19890 $packages = $installMap + $updateMap;
19891 $roots = $packages;
19892
19893 foreach ($packages as $packageId => $operation) {
19894 $package = $operation['package'];
19895
19896 if (!isset($roots[$packageId])) {
19897 continue;
19898 }
19899
19900 foreach ($package->getRequires() as $link) {
19901 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
19902
19903 foreach ($possibleRequires as $require) {
19904 unset($roots[$require->id]);
19905 }
19906 }
19907 }
19908
19909 return $roots;
19910 }
19911
19912 protected function findUpdates()
19913 {
19914 $installMeansUpdateMap = array();
19915
19916 foreach ($this->decisions as $i => $decision) {
19917 $literal = $decision[Decisions::DECISION_LITERAL];
19918 $package = $this->pool->literalToPackage($literal);
19919
19920 if ($package instanceof AliasPackage) {
19921 continue;
19922 }
19923
19924
19925  if ($literal <= 0 && isset($this->installedMap[$package->id])) {
19926 $updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package);
19927
19928 $literals = array($package->id);
19929
19930 foreach ($updates as $update) {
19931 $literals[] = $update->id;
19932 }
19933
19934 foreach ($literals as $updateLiteral) {
19935 if ($updateLiteral !== $literal) {
19936 $installMeansUpdateMap[abs($updateLiteral)] = $package;
19937 }
19938 }
19939 }
19940 }
19941
19942 return $installMeansUpdateMap;
19943 }
19944
19945 protected function install($package, $reason)
19946 {
19947 if ($package instanceof AliasPackage) {
19948 return $this->markAliasInstalled($package, $reason);
19949 }
19950
19951 $this->transaction[] = new Operation\InstallOperation($package, $reason);
19952 }
19953
19954 protected function update($from, $to, $reason)
19955 {
19956 $this->transaction[] = new Operation\UpdateOperation($from, $to, $reason);
19957 }
19958
19959 protected function uninstall($package, $reason)
19960 {
19961 if ($package instanceof AliasPackage) {
19962 return $this->markAliasUninstalled($package, $reason);
19963 }
19964
19965 $this->transaction[] = new Operation\UninstallOperation($package, $reason);
19966 }
19967
19968 protected function markAliasInstalled($package, $reason)
19969 {
19970 $this->transaction[] = new Operation\MarkAliasInstalledOperation($package, $reason);
19971 }
19972
19973 protected function markAliasUninstalled($package, $reason)
19974 {
19975 $this->transaction[] = new Operation\MarkAliasUninstalledOperation($package, $reason);
19976 }
19977 }
19978 <?php
19979
19980
19981
19982
19983
19984
19985
19986
19987
19988
19989
19990 namespace Composer\DependencyResolver\Operation;
19991
19992 use Composer\Package\PackageInterface;
19993
19994
19995
19996
19997
19998
19999 class UninstallOperation extends SolverOperation
20000 {
20001 protected $package;
20002
20003
20004
20005
20006
20007
20008
20009 public function __construct(PackageInterface $package, $reason = null)
20010 {
20011 parent::__construct($reason);
20012
20013 $this->package = $package;
20014 }
20015
20016
20017
20018
20019
20020
20021 public function getPackage()
20022 {
20023 return $this->package;
20024 }
20025
20026
20027
20028
20029
20030
20031 public function getJobType()
20032 {
20033 return 'uninstall';
20034 }
20035
20036
20037
20038
20039 public function __toString()
20040 {
20041 return 'Uninstalling '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
20042 }
20043 }
20044 <?php
20045
20046
20047
20048
20049
20050
20051
20052
20053
20054
20055
20056 namespace Composer\DependencyResolver\Operation;
20057
20058 use Composer\Package\PackageInterface;
20059
20060
20061
20062
20063
20064
20065 class UpdateOperation extends SolverOperation
20066 {
20067 protected $initialPackage;
20068 protected $targetPackage;
20069
20070
20071
20072
20073
20074
20075
20076
20077 public function __construct(PackageInterface $initial, PackageInterface $target, $reason = null)
20078 {
20079 parent::__construct($reason);
20080
20081 $this->initialPackage = $initial;
20082 $this->targetPackage = $target;
20083 }
20084
20085
20086
20087
20088
20089
20090 public function getInitialPackage()
20091 {
20092 return $this->initialPackage;
20093 }
20094
20095
20096
20097
20098
20099
20100 public function getTargetPackage()
20101 {
20102 return $this->targetPackage;
20103 }
20104
20105
20106
20107
20108
20109
20110 public function getJobType()
20111 {
20112 return 'update';
20113 }
20114
20115
20116
20117
20118 public function __toString()
20119 {
20120 return 'Updating '.$this->initialPackage->getPrettyName().' ('.$this->formatVersion($this->initialPackage).') to '.
20121 $this->targetPackage->getPrettyName(). ' ('.$this->formatVersion($this->targetPackage).')';
20122 }
20123 }
20124 <?php
20125
20126
20127
20128
20129
20130
20131
20132
20133
20134
20135
20136 namespace Composer\DependencyResolver\Operation;
20137
20138 use Composer\Package\AliasPackage;
20139
20140
20141
20142
20143
20144
20145 class MarkAliasInstalledOperation extends SolverOperation
20146 {
20147 protected $package;
20148
20149
20150
20151
20152
20153
20154
20155 public function __construct(AliasPackage $package, $reason = null)
20156 {
20157 parent::__construct($reason);
20158
20159 $this->package = $package;
20160 }
20161
20162
20163
20164
20165
20166
20167 public function getPackage()
20168 {
20169 return $this->package;
20170 }
20171
20172
20173
20174
20175
20176
20177 public function getJobType()
20178 {
20179 return 'markAliasInstalled';
20180 }
20181
20182
20183
20184
20185 public function __toString()
20186 {
20187 return 'Marking '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).') as installed, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->formatVersion($this->package->getAliasOf()).')';
20188 }
20189 }
20190 <?php
20191
20192
20193
20194
20195
20196
20197
20198
20199
20200
20201
20202 namespace Composer\DependencyResolver\Operation;
20203
20204 use Composer\Package\PackageInterface;
20205
20206
20207
20208
20209
20210
20211 class InstallOperation extends SolverOperation
20212 {
20213 protected $package;
20214
20215
20216
20217
20218
20219
20220
20221 public function __construct(PackageInterface $package, $reason = null)
20222 {
20223 parent::__construct($reason);
20224
20225 $this->package = $package;
20226 }
20227
20228
20229
20230
20231
20232
20233 public function getPackage()
20234 {
20235 return $this->package;
20236 }
20237
20238
20239
20240
20241
20242
20243 public function getJobType()
20244 {
20245 return 'install';
20246 }
20247
20248
20249
20250
20251 public function __toString()
20252 {
20253 return 'Installing '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
20254 }
20255 }
20256 <?php
20257
20258
20259
20260
20261
20262
20263
20264
20265
20266
20267
20268 namespace Composer\DependencyResolver\Operation;
20269
20270 use Composer\Package\Version\VersionParser;
20271 use Composer\Package\PackageInterface;
20272
20273
20274
20275
20276
20277
20278 abstract class SolverOperation implements OperationInterface
20279 {
20280 protected $reason;
20281
20282
20283
20284
20285
20286
20287 public function __construct($reason = null)
20288 {
20289 $this->reason = $reason;
20290 }
20291
20292
20293
20294
20295
20296
20297 public function getReason()
20298 {
20299 return $this->reason;
20300 }
20301
20302 protected function formatVersion(PackageInterface $package)
20303 {
20304 return VersionParser::formatVersion($package);
20305 }
20306 }
20307 <?php
20308
20309
20310
20311
20312
20313
20314
20315
20316
20317
20318
20319 namespace Composer\DependencyResolver\Operation;
20320
20321 use Composer\Package\AliasPackage;
20322
20323
20324
20325
20326
20327
20328 class MarkAliasUninstalledOperation extends SolverOperation
20329 {
20330 protected $package;
20331
20332
20333
20334
20335
20336
20337
20338 public function __construct(AliasPackage $package, $reason = null)
20339 {
20340 parent::__construct($reason);
20341
20342 $this->package = $package;
20343 }
20344
20345
20346
20347
20348
20349
20350 public function getPackage()
20351 {
20352 return $this->package;
20353 }
20354
20355
20356
20357
20358
20359
20360 public function getJobType()
20361 {
20362 return 'markAliasUninstalled';
20363 }
20364
20365
20366
20367
20368 public function __toString()
20369 {
20370 return 'Marking '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).') as uninstalled, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->formatVersion($this->package->getAliasOf()).')';
20371 }
20372 }
20373 <?php
20374
20375
20376
20377
20378
20379
20380
20381
20382
20383
20384
20385 namespace Composer\DependencyResolver\Operation;
20386
20387
20388
20389
20390
20391
20392 interface OperationInterface
20393 {
20394
20395
20396
20397
20398
20399 public function getJobType();
20400
20401
20402
20403
20404
20405
20406 public function getReason();
20407
20408
20409
20410
20411
20412
20413 public function __toString();
20414 }
20415 <?php
20416
20417
20418
20419
20420
20421
20422
20423
20424
20425
20426
20427 namespace Composer\DependencyResolver;
20428
20429 use Composer\Package\BasePackage;
20430 use Composer\Package\AliasPackage;
20431 use Composer\Package\Version\VersionParser;
20432 use Composer\Package\LinkConstraint\LinkConstraintInterface;
20433 use Composer\Package\LinkConstraint\VersionConstraint;
20434 use Composer\Package\LinkConstraint\EmptyConstraint;
20435 use Composer\Repository\RepositoryInterface;
20436 use Composer\Repository\CompositeRepository;
20437 use Composer\Repository\ComposerRepository;
20438 use Composer\Repository\InstalledRepositoryInterface;
20439 use Composer\Repository\PlatformRepository;
20440 use Composer\Package\PackageInterface;
20441
20442
20443
20444
20445
20446
20447
20448 class Pool
20449 {
20450 const MATCH_NAME = -1;
20451 const MATCH_NONE = 0;
20452 const MATCH = 1;
20453 const MATCH_PROVIDE = 2;
20454 const MATCH_REPLACE = 3;
20455 const MATCH_FILTERED = 4;
20456
20457 protected $repositories = array();
20458 protected $providerRepos = array();
20459 protected $packages = array();
20460 protected $packageByName = array();
20461 protected $packageByExactName = array();
20462 protected $acceptableStabilities;
20463 protected $stabilityFlags;
20464 protected $versionParser;
20465 protected $providerCache = array();
20466 protected $filterRequires;
20467 protected $whitelist = null;
20468 protected $id = 1;
20469
20470 public function __construct($minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array())
20471 {
20472 $stabilities = BasePackage::$stabilities;
20473 $this->versionParser = new VersionParser;
20474 $this->acceptableStabilities = array();
20475 foreach (BasePackage::$stabilities as $stability => $value) {
20476 if ($value <= BasePackage::$stabilities[$minimumStability]) {
20477 $this->acceptableStabilities[$stability] = $value;
20478 }
20479 }
20480 $this->stabilityFlags = $stabilityFlags;
20481 $this->filterRequires = $filterRequires;
20482 }
20483
20484 public function setWhitelist($whitelist)
20485 {
20486 $this->whitelist = $whitelist;
20487 $this->providerCache = array();
20488 }
20489
20490
20491
20492
20493
20494
20495
20496 public function addRepository(RepositoryInterface $repo, $rootAliases = array())
20497 {
20498 if ($repo instanceof CompositeRepository) {
20499 $repos = $repo->getRepositories();
20500 } else {
20501 $repos = array($repo);
20502 }
20503
20504 foreach ($repos as $repo) {
20505 $this->repositories[] = $repo;
20506
20507 $exempt = $repo instanceof PlatformRepository || $repo instanceof InstalledRepositoryInterface;
20508
20509 if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
20510 $this->providerRepos[] = $repo;
20511 $repo->setRootAliases($rootAliases);
20512 $repo->resetPackageIds();
20513 } else {
20514 foreach ($repo->getPackages() as $package) {
20515 $names = $package->getNames();
20516 $stability = $package->getStability();
20517 if ($exempt || $this->isPackageAcceptable($names, $stability)) {
20518 $package->setId($this->id++);
20519 $this->packages[] = $package;
20520 $this->packageByExactName[$package->getName()][$package->id] = $package;
20521
20522 foreach ($names as $provided) {
20523 $this->packageByName[$provided][] = $package;
20524 }
20525
20526
20527  $name = $package->getName();
20528 if (isset($rootAliases[$name][$package->getVersion()])) {
20529 $alias = $rootAliases[$name][$package->getVersion()];
20530 if ($package instanceof AliasPackage) {
20531 $package = $package->getAliasOf();
20532 }
20533 $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
20534 $aliasPackage->setRootPackageAlias(true);
20535 $aliasPackage->setId($this->id++);
20536
20537 $package->getRepository()->addPackage($aliasPackage);
20538 $this->packages[] = $aliasPackage;
20539 $this->packageByExactName[$aliasPackage->getName()][$aliasPackage->id] = $aliasPackage;
20540
20541 foreach ($aliasPackage->getNames() as $name) {
20542 $this->packageByName[$name][] = $aliasPackage;
20543 }
20544 }
20545 }
20546 }
20547 }
20548 }
20549 }
20550
20551 public function getPriority(RepositoryInterface $repo)
20552 {
20553 $priority = array_search($repo, $this->repositories, true);
20554
20555 if (false === $priority) {
20556 throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool.");
20557 }
20558
20559 return -$priority;
20560 }
20561
20562
20563
20564
20565
20566
20567
20568 public function packageById($id)
20569 {
20570 return $this->packages[$id - 1];
20571 }
20572
20573
20574
20575
20576
20577
20578
20579
20580
20581
20582
20583 public function whatProvides($name, LinkConstraintInterface $constraint = null, $mustMatchName = false)
20584 {
20585 $key = ((int) $mustMatchName).$constraint;
20586 if (isset($this->providerCache[$name][$key])) {
20587 return $this->providerCache[$name][$key];
20588 }
20589
20590 return $this->providerCache[$name][$key] = $this->computeWhatProvides($name, $constraint, $mustMatchName);
20591 }
20592
20593
20594
20595
20596 private function computeWhatProvides($name, $constraint, $mustMatchName = false)
20597 {
20598 $candidates = array();
20599
20600 foreach ($this->providerRepos as $repo) {
20601 foreach ($repo->whatProvides($this, $name) as $candidate) {
20602 $candidates[] = $candidate;
20603 if ($candidate->id < 1) {
20604 $candidate->setId($this->id++);
20605 $this->packages[$this->id - 2] = $candidate;
20606 }
20607 }
20608 }
20609
20610 if ($mustMatchName) {
20611 $candidates = array_filter($candidates, function ($candidate) use ($name) {
20612 return $candidate->getName() == $name;
20613 });
20614 if (isset($this->packageByExactName[$name])) {
20615 $candidates = array_merge($candidates, $this->packageByExactName[$name]);
20616 }
20617 } elseif (isset($this->packageByName[$name])) {
20618 $candidates = array_merge($candidates, $this->packageByName[$name]);
20619 }
20620
20621 $matches = $provideMatches = array();
20622 $nameMatch = false;
20623
20624 foreach ($candidates as $candidate) {
20625 $aliasOfCandidate = null;
20626
20627
20628  
20629  if ($candidate instanceof AliasPackage) {
20630 $aliasOfCandidate = $candidate->getAliasOf();
20631 }
20632
20633 if ($this->whitelist !== null && (
20634 (!($candidate instanceof AliasPackage) && !isset($this->whitelist[$candidate->id])) ||
20635 ($candidate instanceof AliasPackage && !isset($this->whitelist[$aliasOfCandidate->id]))
20636 )) {
20637 continue;
20638 }
20639 switch ($this->match($candidate, $name, $constraint)) {
20640 case self::MATCH_NONE:
20641 break;
20642
20643 case self::MATCH_NAME:
20644 $nameMatch = true;
20645 break;
20646
20647 case self::MATCH:
20648 $nameMatch = true;
20649 $matches[] = $candidate;
20650 break;
20651
20652 case self::MATCH_PROVIDE:
20653 $provideMatches[] = $candidate;
20654 break;
20655
20656 case self::MATCH_REPLACE:
20657 $matches[] = $candidate;
20658 break;
20659
20660 case self::MATCH_FILTERED:
20661 break;
20662
20663 default:
20664 throw new \UnexpectedValueException('Unexpected match type');
20665 }
20666 }
20667
20668
20669  if ($nameMatch) {
20670 return $matches;
20671 }
20672
20673 return array_merge($matches, $provideMatches);
20674 }
20675
20676 public function literalToPackage($literal)
20677 {
20678 $packageId = abs($literal);
20679
20680 return $this->packageById($packageId);
20681 }
20682
20683 public function literalToString($literal)
20684 {
20685 return ($literal > 0 ? '+' : '-') . $this->literalToPackage($literal);
20686 }
20687
20688 public function literalToPrettyString($literal, $installedMap)
20689 {
20690 $package = $this->literalToPackage($literal);
20691
20692 if (isset($installedMap[$package->id])) {
20693 $prefix = ($literal > 0 ? 'keep' : 'remove');
20694 } else {
20695 $prefix = ($literal > 0 ? 'install' : 'don\'t install');
20696 }
20697
20698 return $prefix.' '.$package->getPrettyString();
20699 }
20700
20701 public function isPackageAcceptable($name, $stability)
20702 {
20703 foreach ((array) $name as $n) {
20704
20705  if (!isset($this->stabilityFlags[$n]) && isset($this->acceptableStabilities[$stability])) {
20706 return true;
20707 }
20708
20709
20710  if (isset($this->stabilityFlags[$n]) && BasePackage::$stabilities[$stability] <= $this->stabilityFlags[$n]) {
20711 return true;
20712 }
20713 }
20714
20715 return false;
20716 }
20717
20718
20719
20720
20721
20722
20723
20724
20725
20726
20727 private function match($candidate, $name, LinkConstraintInterface $constraint = null)
20728 {
20729 $candidateName = $candidate->getName();
20730 $candidateVersion = $candidate->getVersion();
20731 $isDev = $candidate->getStability() === 'dev';
20732 $isAlias = $candidate instanceof AliasPackage;
20733
20734 if (!$isDev && !$isAlias && isset($this->filterRequires[$name])) {
20735 $requireFilter = $this->filterRequires[$name];
20736 } else {
20737 $requireFilter = new EmptyConstraint;
20738 }
20739
20740 if ($candidateName === $name) {
20741 $pkgConstraint = new VersionConstraint('==', $candidateVersion);
20742
20743 if ($constraint === null || $constraint->matches($pkgConstraint)) {
20744 return $requireFilter->matches($pkgConstraint) ? self::MATCH : self::MATCH_FILTERED;
20745 }
20746
20747 return self::MATCH_NAME;
20748 }
20749
20750 $provides = $candidate->getProvides();
20751 $replaces = $candidate->getReplaces();
20752
20753
20754  if (isset($replaces[0]) || isset($provides[0])) {
20755 foreach ($provides as $link) {
20756 if ($link->getTarget() === $name && ($constraint === null || $constraint->matches($link->getConstraint()))) {
20757 return $requireFilter->matches($link->getConstraint()) ? self::MATCH_PROVIDE : self::MATCH_FILTERED;
20758 }
20759 }
20760
20761 foreach ($replaces as $link) {
20762 if ($link->getTarget() === $name && ($constraint === null || $constraint->matches($link->getConstraint()))) {
20763 return $requireFilter->matches($link->getConstraint()) ? self::MATCH_REPLACE : self::MATCH_FILTERED;
20764 }
20765 }
20766
20767 return self::MATCH_NONE;
20768 }
20769
20770 if (isset($provides[$name]) && ($constraint === null || $constraint->matches($provides[$name]->getConstraint()))) {
20771 return $requireFilter->matches($provides[$name]->getConstraint()) ? self::MATCH_PROVIDE : self::MATCH_FILTERED;
20772 }
20773
20774 if (isset($replaces[$name]) && ($constraint === null || $constraint->matches($replaces[$name]->getConstraint()))) {
20775 return $requireFilter->matches($replaces[$name]->getConstraint()) ? self::MATCH_REPLACE : self::MATCH_FILTERED;
20776 }
20777
20778 return self::MATCH_NONE;
20779 }
20780 }
20781 <?php
20782
20783
20784
20785
20786
20787
20788
20789
20790
20791
20792
20793 namespace Composer\DependencyResolver;
20794
20795
20796
20797
20798 class Rule
20799 {
20800 const RULE_INTERNAL_ALLOW_UPDATE = 1;
20801 const RULE_JOB_INSTALL = 2;
20802 const RULE_JOB_REMOVE = 3;
20803 const RULE_PACKAGE_CONFLICT = 6;
20804 const RULE_PACKAGE_REQUIRES = 7;
20805 const RULE_PACKAGE_OBSOLETES = 8;
20806 const RULE_INSTALLED_PACKAGE_OBSOLETES = 9;
20807 const RULE_PACKAGE_SAME_NAME = 10;
20808 const RULE_PACKAGE_IMPLICIT_OBSOLETES = 11;
20809 const RULE_LEARNED = 12;
20810 const RULE_PACKAGE_ALIAS = 13;
20811
20812
20813
20814
20815
20816 public $literals;
20817
20818 protected $disabled;
20819 protected $type;
20820 protected $id;
20821 protected $reason;
20822 protected $reasonData;
20823
20824 protected $job;
20825
20826 protected $ruleHash;
20827
20828 public function __construct(array $literals, $reason, $reasonData, $job = null)
20829 {
20830
20831  sort($literals);
20832
20833 $this->literals = $literals;
20834 $this->reason = $reason;
20835 $this->reasonData = $reasonData;
20836
20837 $this->disabled = false;
20838
20839 $this->job = $job;
20840
20841 $this->type = -1;
20842
20843 $this->ruleHash = substr(md5(implode(',', $this->literals)), 0, 5);
20844 }
20845
20846 public function getHash()
20847 {
20848 return $this->ruleHash;
20849 }
20850
20851 public function setId($id)
20852 {
20853 $this->id = $id;
20854 }
20855
20856 public function getId()
20857 {
20858 return $this->id;
20859 }
20860
20861 public function getJob()
20862 {
20863 return $this->job;
20864 }
20865
20866 public function getReason()
20867 {
20868 return $this->reason;
20869 }
20870
20871 public function getReasonData()
20872 {
20873 return $this->reasonData;
20874 }
20875
20876 public function getRequiredPackage()
20877 {
20878 if ($this->reason === self::RULE_JOB_INSTALL) {
20879 return $this->reasonData;
20880 }
20881
20882 if ($this->reason === self::RULE_PACKAGE_REQUIRES) {
20883 return $this->reasonData->getTarget();
20884 }
20885 }
20886
20887
20888
20889
20890
20891
20892
20893
20894
20895 public function equals(Rule $rule)
20896 {
20897 if ($this->ruleHash !== $rule->ruleHash) {
20898 return false;
20899 }
20900
20901 if (count($this->literals) != count($rule->literals)) {
20902 return false;
20903 }
20904
20905 for ($i = 0, $n = count($this->literals); $i < $n; $i++) {
20906 if ($this->literals[$i] !== $rule->literals[$i]) {
20907 return false;
20908 }
20909 }
20910
20911 return true;
20912 }
20913
20914 public function setType($type)
20915 {
20916 $this->type = $type;
20917 }
20918
20919 public function getType()
20920 {
20921 return $this->type;
20922 }
20923
20924 public function disable()
20925 {
20926 $this->disabled = true;
20927 }
20928
20929 public function enable()
20930 {
20931 $this->disabled = false;
20932 }
20933
20934 public function isDisabled()
20935 {
20936 return $this->disabled;
20937 }
20938
20939 public function isEnabled()
20940 {
20941 return !$this->disabled;
20942 }
20943
20944
20945
20946
20947 public function getLiterals()
20948 {
20949 return $this->literals;
20950 }
20951
20952 public function isAssertion()
20953 {
20954 return 1 === count($this->literals);
20955 }
20956
20957 public function getPrettyString(Pool $pool, array $installedMap = array())
20958 {
20959 $ruleText = '';
20960 foreach ($this->literals as $i => $literal) {
20961 if ($i != 0) {
20962 $ruleText .= '|';
20963 }
20964 $ruleText .= $pool->literalToPrettyString($literal, $installedMap);
20965 }
20966
20967 switch ($this->reason) {
20968 case self::RULE_INTERNAL_ALLOW_UPDATE:
20969 return $ruleText;
20970
20971 case self::RULE_JOB_INSTALL:
20972 return "Install command rule ($ruleText)";
20973
20974 case self::RULE_JOB_REMOVE:
20975 return "Remove command rule ($ruleText)";
20976
20977 case self::RULE_PACKAGE_CONFLICT:
20978 $package1 = $pool->literalToPackage($this->literals[0]);
20979 $package2 = $pool->literalToPackage($this->literals[1]);
20980
20981 return $package1->getPrettyString().' conflicts with '.$this->formatPackagesUnique($pool, array($package2)).'.';
20982
20983 case self::RULE_PACKAGE_REQUIRES:
20984 $literals = $this->literals;
20985 $sourceLiteral = array_shift($literals);
20986 $sourcePackage = $pool->literalToPackage($sourceLiteral);
20987
20988 $requires = array();
20989 foreach ($literals as $literal) {
20990 $requires[] = $pool->literalToPackage($literal);
20991 }
20992
20993 $text = $this->reasonData->getPrettyString($sourcePackage);
20994 if ($requires) {
20995 $text .= ' -> satisfiable by ' . $this->formatPackagesUnique($pool, $requires) . '.';
20996 } else {
20997 $targetName = $this->reasonData->getTarget();
20998
20999
21000  if (0 === strpos($targetName, 'ext-')) {
21001 $ext = substr($targetName, 4);
21002 $error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
21003
21004 $text .= ' -> the requested PHP extension '.$ext.' '.$error.'.';
21005 } elseif (0 === strpos($targetName, 'lib-')) {
21006
21007  $lib = substr($targetName, 4);
21008
21009 $text .= ' -> the requested linked library '.$lib.' has the wrong version installed or is missing from your system, make sure to have the extension providing it.';
21010 } else {
21011 $text .= ' -> no matching package found.';
21012 }
21013 }
21014
21015 return $text;
21016
21017 case self::RULE_PACKAGE_OBSOLETES:
21018 return $ruleText;
21019 case self::RULE_INSTALLED_PACKAGE_OBSOLETES:
21020 return $ruleText;
21021 case self::RULE_PACKAGE_SAME_NAME:
21022 return 'Can only install one of: ' . $this->formatPackagesUnique($pool, $this->literals) . '.';
21023 case self::RULE_PACKAGE_IMPLICIT_OBSOLETES:
21024 return $ruleText;
21025 case self::RULE_LEARNED:
21026 return 'Conclusion: '.$ruleText;
21027 case self::RULE_PACKAGE_ALIAS:
21028 return $ruleText;
21029 default:
21030 return '('.$ruleText.')';
21031 }
21032 }
21033
21034 protected function formatPackagesUnique($pool, array $packages)
21035 {
21036 $prepared = array();
21037 foreach ($packages as $package) {
21038 if (!is_object($package)) {
21039 $package = $pool->literalToPackage($package);
21040 }
21041 $prepared[$package->getName()]['name'] = $package->getPrettyName();
21042 $prepared[$package->getName()]['versions'][$package->getVersion()] = $package->getPrettyVersion();
21043 }
21044 foreach ($prepared as $name => $package) {
21045 $prepared[$name] = $package['name'].'['.implode(', ', $package['versions']).']';
21046 }
21047
21048 return implode(', ', $prepared);
21049 }
21050
21051
21052
21053
21054
21055
21056 public function __toString()
21057 {
21058 $result = ($this->isDisabled()) ? 'disabled(' : '(';
21059
21060 foreach ($this->literals as $i => $literal) {
21061 if ($i != 0) {
21062 $result .= '|';
21063 }
21064 $result .= $literal;
21065 }
21066
21067 $result .= ')';
21068
21069 return $result;
21070 }
21071 }
21072 <?php
21073
21074
21075
21076
21077
21078
21079
21080
21081
21082
21083
21084 namespace Composer\DependencyResolver;
21085
21086 use Composer\Package\PackageInterface;
21087 use Composer\Package\AliasPackage;
21088 use Composer\Repository\PlatformRepository;
21089
21090
21091
21092
21093 class RuleSetGenerator
21094 {
21095 protected $policy;
21096 protected $pool;
21097 protected $rules;
21098 protected $jobs;
21099 protected $installedMap;
21100 protected $whitelistedMap;
21101 protected $addedMap;
21102
21103 public function __construct(PolicyInterface $policy, Pool $pool)
21104 {
21105 $this->policy = $policy;
21106 $this->pool = $pool;
21107 }
21108
21109
21110
21111
21112
21113
21114
21115
21116
21117
21118
21119
21120
21121
21122
21123 protected function createRequireRule(PackageInterface $package, array $providers, $reason, $reasonData = null)
21124 {
21125 $literals = array(-$package->id);
21126
21127 foreach ($providers as $provider) {
21128
21129  if ($provider === $package) {
21130 return null;
21131 }
21132 $literals[] = $provider->id;
21133 }
21134
21135 return new Rule($literals, $reason, $reasonData);
21136 }
21137
21138
21139
21140
21141
21142
21143
21144
21145
21146
21147
21148
21149
21150 protected function createInstallOneOfRule(array $packages, $reason, $job)
21151 {
21152 $literals = array();
21153 foreach ($packages as $package) {
21154 $literals[] = $package->id;
21155 }
21156
21157 return new Rule($literals, $reason, $job['packageName'], $job);
21158 }
21159
21160
21161
21162
21163
21164
21165
21166
21167
21168
21169
21170
21171 protected function createRemoveRule(PackageInterface $package, $reason, $job)
21172 {
21173 return new Rule(array(-$package->id), $reason, $job['packageName'], $job);
21174 }
21175
21176
21177
21178
21179
21180
21181
21182
21183
21184
21185
21186
21187
21188
21189
21190 protected function createConflictRule(PackageInterface $issuer, PackageInterface $provider, $reason, $reasonData = null)
21191 {
21192
21193  if ($issuer === $provider) {
21194 return null;
21195 }
21196
21197 return new Rule(array(-$issuer->id, -$provider->id), $reason, $reasonData);
21198 }
21199
21200
21201
21202
21203
21204
21205
21206
21207
21208
21209 private function addRule($type, Rule $newRule = null)
21210 {
21211 if (!$newRule || $this->rules->containsEqual($newRule)) {
21212 return;
21213 }
21214
21215 $this->rules->add($newRule, $type);
21216 }
21217
21218 protected function whitelistFromPackage(PackageInterface $package)
21219 {
21220 $workQueue = new \SplQueue;
21221 $workQueue->enqueue($package);
21222
21223 while (!$workQueue->isEmpty()) {
21224 $package = $workQueue->dequeue();
21225 if (isset($this->whitelistedMap[$package->id])) {
21226 continue;
21227 }
21228
21229 $this->whitelistedMap[$package->id] = true;
21230
21231 foreach ($package->getRequires() as $link) {
21232 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint(), true);
21233
21234 foreach ($possibleRequires as $require) {
21235 $workQueue->enqueue($require);
21236 }
21237 }
21238
21239 $obsoleteProviders = $this->pool->whatProvides($package->getName(), null, true);
21240
21241 foreach ($obsoleteProviders as $provider) {
21242 if ($provider === $package) {
21243 continue;
21244 }
21245
21246 if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
21247 $workQueue->enqueue($provider);
21248 }
21249 }
21250 }
21251 }
21252
21253 protected function addRulesForPackage(PackageInterface $package, $ignorePlatformReqs)
21254 {
21255 $workQueue = new \SplQueue;
21256 $workQueue->enqueue($package);
21257
21258 while (!$workQueue->isEmpty()) {
21259 $package = $workQueue->dequeue();
21260 if (isset($this->addedMap[$package->id])) {
21261 continue;
21262 }
21263
21264 $this->addedMap[$package->id] = true;
21265
21266 foreach ($package->getRequires() as $link) {
21267 if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
21268 continue;
21269 }
21270
21271 $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
21272
21273 $this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createRequireRule($package, $possibleRequires, Rule::RULE_PACKAGE_REQUIRES, $link));
21274
21275 foreach ($possibleRequires as $require) {
21276 $workQueue->enqueue($require);
21277 }
21278 }
21279
21280 foreach ($package->getConflicts() as $link) {
21281 $possibleConflicts = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
21282
21283 foreach ($possibleConflicts as $conflict) {
21284 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $conflict, Rule::RULE_PACKAGE_CONFLICT, $link));
21285 }
21286 }
21287
21288
21289  $isInstalled = (isset($this->installedMap[$package->id]));
21290
21291 foreach ($package->getReplaces() as $link) {
21292 $obsoleteProviders = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
21293
21294 foreach ($obsoleteProviders as $provider) {
21295 if ($provider === $package) {
21296 continue;
21297 }
21298
21299 if (!$this->obsoleteImpossibleForAlias($package, $provider)) {
21300 $reason = ($isInstalled) ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES;
21301 $this->addRule(RuleSet::TYPE_PACKAGE, $this->createConflictRule($package, $provider, $reason, $link));
21302 }
21303 }
21304 }
21305
21306 $obsoleteProviders = $this->pool->whatProvides($package->getName(), null);
21307
21308 foreach ($obsoleteProviders as $provider) {
21309 if ($provider === $package) {
21310 continue;
21311 }
21312
21313 if (($package instanceof AliasPackage) && $package->getAliasOf() === $provider) {
21314 $this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createRequireRule($package, array($provider), Rule::RULE_PACKAGE_ALIAS, $package));
21315 } elseif (!$this->obsoleteImpossibleForAlias($package, $provider)) {
21316 $reason = ($package->getName() == $provider->getName()) ? Rule::RULE_PACKAGE_SAME_NAME : Rule::RULE_PACKAGE_IMPLICIT_OBSOLETES;
21317 $this->addRule(RuleSet::TYPE_PACKAGE, $rule = $this->createConflictRule($package, $provider, $reason, $package));
21318 }
21319 }
21320 }
21321 }
21322
21323 protected function obsoleteImpossibleForAlias($package, $provider)
21324 {
21325 $packageIsAlias = $package instanceof AliasPackage;
21326 $providerIsAlias = $provider instanceof AliasPackage;
21327
21328 $impossible = (
21329 ($packageIsAlias && $package->getAliasOf() === $provider) ||
21330 ($providerIsAlias && $provider->getAliasOf() === $package) ||
21331 ($packageIsAlias && $providerIsAlias && $provider->getAliasOf() === $package->getAliasOf())
21332 );
21333
21334 return $impossible;
21335 }
21336
21337 protected function whitelistFromJobs()
21338 {
21339 foreach ($this->jobs as $job) {
21340 switch ($job['cmd']) {
21341 case 'install':
21342 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint'], true);
21343 foreach ($packages as $package) {
21344 $this->whitelistFromPackage($package);
21345 }
21346 break;
21347 }
21348 }
21349 }
21350
21351 protected function addRulesForJobs($ignorePlatformReqs)
21352 {
21353 foreach ($this->jobs as $job) {
21354 switch ($job['cmd']) {
21355 case 'install':
21356 if (!$job['fixed'] && $ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
21357 continue;
21358 }
21359
21360 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
21361 if ($packages) {
21362 foreach ($packages as $package) {
21363 if (!isset($this->installedMap[$package->id])) {
21364 $this->addRulesForPackage($package, $ignorePlatformReqs);
21365 }
21366 }
21367
21368 $rule = $this->createInstallOneOfRule($packages, Rule::RULE_JOB_INSTALL, $job);
21369 $this->addRule(RuleSet::TYPE_JOB, $rule);
21370 }
21371 break;
21372 case 'remove':
21373
21374  
21375  $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
21376 foreach ($packages as $package) {
21377 $rule = $this->createRemoveRule($package, Rule::RULE_JOB_REMOVE, $job);
21378 $this->addRule(RuleSet::TYPE_JOB, $rule);
21379 }
21380 break;
21381 }
21382 }
21383 }
21384
21385 public function getRulesFor($jobs, $installedMap, $ignorePlatformReqs = false)
21386 {
21387 $this->jobs = $jobs;
21388 $this->rules = new RuleSet;
21389 $this->installedMap = $installedMap;
21390
21391 $this->whitelistedMap = array();
21392 foreach ($this->installedMap as $package) {
21393 $this->whitelistFromPackage($package);
21394 }
21395 $this->whitelistFromJobs();
21396
21397 $this->pool->setWhitelist($this->whitelistedMap);
21398
21399 $this->addedMap = array();
21400 foreach ($this->installedMap as $package) {
21401 $this->addRulesForPackage($package, $ignorePlatformReqs);
21402 }
21403
21404 $this->addRulesForJobs($ignorePlatformReqs);
21405
21406 return $this->rules;
21407 }
21408 }
21409 <?php
21410
21411
21412
21413
21414
21415
21416
21417
21418
21419
21420
21421 namespace Composer\DependencyResolver;
21422
21423
21424
21425
21426 class DebugSolver extends Solver
21427 {
21428 protected function printDecisionMap()
21429 {
21430 echo "\nDecisionMap: \n";
21431 foreach ($this->decisionMap as $packageId => $level) {
21432 if ($packageId === 0) {
21433 continue;
21434 }
21435 if ($level > 0) {
21436 echo '    +' . $this->pool->packageById($packageId)."\n";
21437 } elseif ($level < 0) {
21438 echo '    -' . $this->pool->packageById($packageId)."\n";
21439 } else {
21440 echo '    ?' . $this->pool->packageById($packageId)."\n";
21441 }
21442 }
21443 echo "\n";
21444 }
21445
21446 protected function printDecisionQueue()
21447 {
21448 echo "DecisionQueue: \n";
21449 foreach ($this->decisionQueue as $i => $literal) {
21450 echo '    ' . $this->pool->literalToString($literal) . ' ' . $this->decisionQueueWhy[$i]." level ".$this->decisionMap[abs($literal)]."\n";
21451 }
21452 echo "\n";
21453 }
21454
21455 protected function printWatches()
21456 {
21457 echo "\nWatches:\n";
21458 foreach ($this->watches as $literalId => $watch) {
21459 echo '  '.$this->literalFromId($literalId)."\n";
21460 $queue = array(array('    ', $watch));
21461
21462 while (!empty($queue)) {
21463 list($indent, $watch) = array_pop($queue);
21464
21465 echo $indent.$watch;
21466
21467 if ($watch) {
21468 echo ' [id='.$watch->getId().',watch1='.$this->literalFromId($watch->watch1).',watch2='.$this->literalFromId($watch->watch2)."]";
21469 }
21470
21471 echo "\n";
21472
21473 if ($watch && ($watch->next1 == $watch || $watch->next2 == $watch)) {
21474 if ($watch->next1 == $watch) {
21475 echo $indent."    1 *RECURSION*";
21476 }
21477 if ($watch->next2 == $watch) {
21478 echo $indent."    2 *RECURSION*";
21479 }
21480 } elseif ($watch && ($watch->next1 || $watch->next2)) {
21481 $indent = str_replace(array('1', '2'), ' ', $indent);
21482
21483 array_push($queue, array($indent.'    2 ', $watch->next2));
21484 array_push($queue, array($indent.'    1 ', $watch->next1));
21485 }
21486 }
21487
21488 echo "\n";
21489 }
21490 }
21491 }
21492 <?php
21493
21494
21495
21496
21497
21498
21499
21500
21501
21502
21503
21504 namespace Composer\DependencyResolver;
21505
21506
21507
21508
21509 class RuleSetIterator implements \Iterator
21510 {
21511 protected $rules;
21512 protected $types;
21513
21514 protected $currentOffset;
21515 protected $currentType;
21516 protected $currentTypeOffset;
21517
21518 public function __construct(array $rules)
21519 {
21520 $this->rules = $rules;
21521 $this->types = array_keys($rules);
21522 sort($this->types);
21523
21524 $this->rewind();
21525 }
21526
21527 public function current()
21528 {
21529 return $this->rules[$this->currentType][$this->currentOffset];
21530 }
21531
21532 public function key()
21533 {
21534 return $this->currentType;
21535 }
21536
21537 public function next()
21538 {
21539 $this->currentOffset++;
21540
21541 if (!isset($this->rules[$this->currentType])) {
21542 return;
21543 }
21544
21545 if ($this->currentOffset >= sizeof($this->rules[$this->currentType])) {
21546 $this->currentOffset = 0;
21547
21548 do {
21549 $this->currentTypeOffset++;
21550
21551 if (!isset($this->types[$this->currentTypeOffset])) {
21552 $this->currentType = -1;
21553 break;
21554 }
21555
21556 $this->currentType = $this->types[$this->currentTypeOffset];
21557 } while (isset($this->types[$this->currentTypeOffset]) && !sizeof($this->rules[$this->currentType]));
21558 }
21559 }
21560
21561 public function rewind()
21562 {
21563 $this->currentOffset = 0;
21564
21565 $this->currentTypeOffset = -1;
21566 $this->currentType = -1;
21567
21568 do {
21569 $this->currentTypeOffset++;
21570
21571 if (!isset($this->types[$this->currentTypeOffset])) {
21572 $this->currentType = -1;
21573 break;
21574 }
21575
21576 $this->currentType = $this->types[$this->currentTypeOffset];
21577 } while (isset($this->types[$this->currentTypeOffset]) && !sizeof($this->rules[$this->currentType]));
21578 }
21579
21580 public function valid()
21581 {
21582 return isset($this->rules[$this->currentType])
21583 && isset($this->rules[$this->currentType][$this->currentOffset]);
21584 }
21585 }
21586 <?php
21587
21588
21589
21590
21591
21592
21593
21594
21595
21596
21597
21598 namespace Composer\DependencyResolver;
21599
21600
21601
21602
21603
21604
21605
21606
21607
21608 class RuleWatchChain extends \SplDoublyLinkedList
21609 {
21610 protected $offset = 0;
21611
21612
21613
21614
21615
21616
21617 public function seek($offset)
21618 {
21619 $this->rewind();
21620 for ($i = 0; $i < $offset; $i++, $this->next());
21621 }
21622
21623
21624
21625
21626
21627
21628
21629
21630
21631 public function remove()
21632 {
21633 $offset = $this->key();
21634 $this->offsetUnset($offset);
21635 $this->seek($offset);
21636 }
21637 }
21638 <?php
21639
21640
21641
21642
21643
21644
21645
21646
21647
21648
21649
21650 namespace Composer\DependencyResolver;
21651
21652 use Composer\Repository\RepositoryInterface;
21653 use Composer\Repository\PlatformRepository;
21654
21655
21656
21657
21658 class Solver
21659 {
21660 const BRANCH_LITERALS = 0;
21661 const BRANCH_LEVEL = 1;
21662
21663 protected $policy;
21664 protected $pool;
21665 protected $installed;
21666 protected $rules;
21667 protected $ruleSetGenerator;
21668 protected $updateAll;
21669
21670 protected $addedMap = array();
21671 protected $updateMap = array();
21672 protected $watchGraph;
21673 protected $decisions;
21674 protected $installedMap;
21675
21676 protected $propagateIndex;
21677 protected $branches = array();
21678 protected $problems = array();
21679 protected $learnedPool = array();
21680
21681 public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed)
21682 {
21683 $this->policy = $policy;
21684 $this->pool = $pool;
21685 $this->installed = $installed;
21686 $this->ruleSetGenerator = new RuleSetGenerator($policy, $pool);
21687 }
21688
21689
21690  private function makeAssertionRuleDecisions()
21691 {
21692 $decisionStart = count($this->decisions) - 1;
21693
21694 $rulesCount = count($this->rules);
21695 for ($ruleIndex = 0; $ruleIndex < $rulesCount; $ruleIndex++) {
21696 $rule = $this->rules->ruleById[$ruleIndex];
21697
21698 if (!$rule->isAssertion() || $rule->isDisabled()) {
21699 continue;
21700 }
21701
21702 $literals = $rule->literals;
21703 $literal = $literals[0];
21704
21705 if (!$this->decisions->decided(abs($literal))) {
21706 $this->decisions->decide($literal, 1, $rule);
21707 continue;
21708 }
21709
21710 if ($this->decisions->satisfy($literal)) {
21711 continue;
21712 }
21713
21714
21715  if (RuleSet::TYPE_LEARNED === $rule->getType()) {
21716 $rule->disable();
21717 continue;
21718 }
21719
21720 $conflict = $this->decisions->decisionRule($literal);
21721
21722 if ($conflict && RuleSet::TYPE_PACKAGE === $conflict->getType()) {
21723 $problem = new Problem($this->pool);
21724
21725 $problem->addRule($rule);
21726 $problem->addRule($conflict);
21727 $this->disableProblem($rule);
21728 $this->problems[] = $problem;
21729 continue;
21730 }
21731
21732
21733  $problem = new Problem($this->pool);
21734 $problem->addRule($rule);
21735 $problem->addRule($conflict);
21736
21737
21738  
21739  foreach ($this->rules->getIteratorFor(RuleSet::TYPE_JOB) as $assertRule) {
21740 if ($assertRule->isDisabled() || !$assertRule->isAssertion()) {
21741 continue;
21742 }
21743
21744 $assertRuleLiterals = $assertRule->literals;
21745 $assertRuleLiteral = $assertRuleLiterals[0];
21746
21747 if (abs($literal) !== abs($assertRuleLiteral)) {
21748 continue;
21749 }
21750
21751 $problem->addRule($assertRule);
21752 $this->disableProblem($assertRule);
21753 }
21754 $this->problems[] = $problem;
21755
21756 $this->decisions->resetToOffset($decisionStart);
21757 $ruleIndex = -1;
21758 }
21759 }
21760
21761 protected function setupInstalledMap()
21762 {
21763 $this->installedMap = array();
21764 foreach ($this->installed->getPackages() as $package) {
21765 $this->installedMap[$package->id] = $package;
21766 }
21767 }
21768
21769 protected function checkForRootRequireProblems($ignorePlatformReqs)
21770 {
21771 foreach ($this->jobs as $job) {
21772 switch ($job['cmd']) {
21773 case 'update':
21774 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
21775 foreach ($packages as $package) {
21776 if (isset($this->installedMap[$package->id])) {
21777 $this->updateMap[$package->id] = true;
21778 }
21779 }
21780 break;
21781
21782 case 'update-all':
21783 foreach ($this->installedMap as $package) {
21784 $this->updateMap[$package->id] = true;
21785 }
21786 break;
21787
21788 case 'install':
21789 if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
21790 break;
21791 }
21792
21793 if (!$this->pool->whatProvides($job['packageName'], $job['constraint'])) {
21794 $problem = new Problem($this->pool);
21795 $problem->addRule(new Rule(array(), null, null, $job));
21796 $this->problems[] = $problem;
21797 }
21798 break;
21799 }
21800 }
21801 }
21802
21803 public function solve(Request $request, $ignorePlatformReqs = false)
21804 {
21805 $this->jobs = $request->getJobs();
21806
21807 $this->setupInstalledMap();
21808 $this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs);
21809 $this->checkForRootRequireProblems($ignorePlatformReqs);
21810 $this->decisions = new Decisions($this->pool);
21811 $this->watchGraph = new RuleWatchGraph;
21812
21813 foreach ($this->rules as $rule) {
21814 $this->watchGraph->insert(new RuleWatchNode($rule));
21815 }
21816
21817
21818 $this->makeAssertionRuleDecisions();
21819
21820 $this->runSat(true);
21821
21822
21823  foreach ($this->installedMap as $packageId => $void) {
21824 if ($this->decisions->undecided($packageId)) {
21825 $this->decisions->decide(-$packageId, 1, null);
21826 }
21827 }
21828
21829 if ($this->problems) {
21830 throw new SolverProblemsException($this->problems, $this->installedMap);
21831 }
21832
21833 $transaction = new Transaction($this->policy, $this->pool, $this->installedMap, $this->decisions);
21834
21835 return $transaction->getOperations();
21836 }
21837
21838 protected function literalFromId($id)
21839 {
21840 $package = $this->pool->packageById(abs($id));
21841
21842 return new Literal($package, $id > 0);
21843 }
21844
21845
21846
21847
21848
21849
21850
21851
21852
21853
21854 protected function propagate($level)
21855 {
21856 while ($this->decisions->validOffset($this->propagateIndex)) {
21857 $decision = $this->decisions->atOffset($this->propagateIndex);
21858
21859 $conflict = $this->watchGraph->propagateLiteral(
21860 $decision[Decisions::DECISION_LITERAL],
21861 $level,
21862 $this->decisions
21863 );
21864
21865 $this->propagateIndex++;
21866
21867 if ($conflict) {
21868 return $conflict;
21869 }
21870 }
21871
21872 return null;
21873 }
21874
21875
21876
21877
21878 private function revert($level)
21879 {
21880 while (!$this->decisions->isEmpty()) {
21881 $literal = $this->decisions->lastLiteral();
21882
21883 if ($this->decisions->undecided($literal)) {
21884 break;
21885 }
21886
21887 $decisionLevel = $this->decisions->decisionLevel($literal);
21888
21889 if ($decisionLevel <= $level) {
21890 break;
21891 }
21892
21893 $this->decisions->revertLast();
21894 $this->propagateIndex = count($this->decisions);
21895 }
21896
21897 while (!empty($this->branches) && $this->branches[count($this->branches) - 1][self::BRANCH_LEVEL] >= $level) {
21898 array_pop($this->branches);
21899 }
21900 }
21901
21902
21903
21904
21905
21906
21907
21908
21909
21910
21911
21912
21913
21914
21915
21916
21917 private function setPropagateLearn($level, $literal, $disableRules, Rule $rule)
21918 {
21919 $level++;
21920
21921 $this->decisions->decide($literal, $level, $rule);
21922
21923 while (true) {
21924 $rule = $this->propagate($level);
21925
21926 if (!$rule) {
21927 break;
21928 }
21929
21930 if ($level == 1) {
21931 return $this->analyzeUnsolvable($rule, $disableRules);
21932 }
21933
21934
21935  list($learnLiteral, $newLevel, $newRule, $why) = $this->analyze($level, $rule);
21936
21937 if ($newLevel <= 0 || $newLevel >= $level) {
21938 throw new SolverBugException(
21939 "Trying to revert to invalid level ".(int) $newLevel." from level ".(int) $level."."
21940 );
21941 } elseif (!$newRule) {
21942 throw new SolverBugException(
21943 "No rule was learned from analyzing $rule at level $level."
21944 );
21945 }
21946
21947 $level = $newLevel;
21948
21949 $this->revert($level);
21950
21951 $this->rules->add($newRule, RuleSet::TYPE_LEARNED);
21952
21953 $this->learnedWhy[$newRule->getId()] = $why;
21954
21955 $ruleNode = new RuleWatchNode($newRule);
21956 $ruleNode->watch2OnHighest($this->decisions);
21957 $this->watchGraph->insert($ruleNode);
21958
21959 $this->decisions->decide($learnLiteral, $level, $newRule);
21960 }
21961
21962 return $level;
21963 }
21964
21965 private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule)
21966 {
21967
21968  $literals = $this->policy->selectPreferedPackages($this->pool, $this->installedMap, $decisionQueue, $rule->getRequiredPackage());
21969
21970 $selectedLiteral = array_shift($literals);
21971
21972
21973  if (count($literals)) {
21974 $this->branches[] = array($literals, $level);
21975 }
21976
21977 return $this->setPropagateLearn($level, $selectedLiteral, $disableRules, $rule);
21978 }
21979
21980 protected function analyze($level, $rule)
21981 {
21982 $analyzedRule = $rule;
21983 $ruleLevel = 1;
21984 $num = 0;
21985 $l1num = 0;
21986 $seen = array();
21987 $learnedLiterals = array(null);
21988
21989 $decisionId = count($this->decisions);
21990
21991 $this->learnedPool[] = array();
21992
21993 while (true) {
21994 $this->learnedPool[count($this->learnedPool) - 1][] = $rule;
21995
21996 foreach ($rule->literals as $literal) {
21997
21998  if ($this->decisions->satisfy($literal)) {
21999 continue;
22000 }
22001
22002 if (isset($seen[abs($literal)])) {
22003 continue;
22004 }
22005 $seen[abs($literal)] = true;
22006
22007 $l = $this->decisions->decisionLevel($literal);
22008
22009 if (1 === $l) {
22010 $l1num++;
22011 } elseif ($level === $l) {
22012 $num++;
22013 } else {
22014
22015  $learnedLiterals[] = $literal;
22016
22017 if ($l > $ruleLevel) {
22018 $ruleLevel = $l;
22019 }
22020 }
22021 }
22022
22023 $l1retry = true;
22024 while ($l1retry) {
22025 $l1retry = false;
22026
22027 if (!$num && !--$l1num) {
22028
22029  break 2;
22030 }
22031
22032 while (true) {
22033 if ($decisionId <= 0) {
22034 throw new SolverBugException(
22035 "Reached invalid decision id $decisionId while looking through $rule for a literal present in the analyzed rule $analyzedRule."
22036 );
22037 }
22038
22039 $decisionId--;
22040
22041 $decision = $this->decisions->atOffset($decisionId);
22042 $literal = $decision[Decisions::DECISION_LITERAL];
22043
22044 if (isset($seen[abs($literal)])) {
22045 break;
22046 }
22047 }
22048
22049 unset($seen[abs($literal)]);
22050
22051 if ($num && 0 === --$num) {
22052 $learnedLiterals[0] = -abs($literal);
22053
22054 if (!$l1num) {
22055 break 2;
22056 }
22057
22058 foreach ($learnedLiterals as $i => $learnedLiteral) {
22059 if ($i !== 0) {
22060 unset($seen[abs($learnedLiteral)]);
22061 }
22062 }
22063
22064  $l1num++;
22065 $l1retry = true;
22066 }
22067 }
22068
22069 $decision = $this->decisions->atOffset($decisionId);
22070 $rule = $decision[Decisions::DECISION_REASON];
22071 }
22072
22073 $why = count($this->learnedPool) - 1;
22074
22075 if (!$learnedLiterals[0]) {
22076 throw new SolverBugException(
22077 "Did not find a learnable literal in analyzed rule $analyzedRule."
22078 );
22079 }
22080
22081 $newRule = new Rule($learnedLiterals, Rule::RULE_LEARNED, $why);
22082
22083 return array($learnedLiterals[0], $ruleLevel, $newRule, $why);
22084 }
22085
22086 private function analyzeUnsolvableRule($problem, $conflictRule)
22087 {
22088 $why = $conflictRule->getId();
22089
22090 if ($conflictRule->getType() == RuleSet::TYPE_LEARNED) {
22091 $learnedWhy = $this->learnedWhy[$why];
22092 $problemRules = $this->learnedPool[$learnedWhy];
22093
22094 foreach ($problemRules as $problemRule) {
22095 $this->analyzeUnsolvableRule($problem, $problemRule);
22096 }
22097
22098 return;
22099 }
22100
22101 if ($conflictRule->getType() == RuleSet::TYPE_PACKAGE) {
22102
22103  return;
22104 }
22105
22106 $problem->nextSection();
22107 $problem->addRule($conflictRule);
22108 }
22109
22110 private function analyzeUnsolvable($conflictRule, $disableRules)
22111 {
22112 $problem = new Problem($this->pool);
22113 $problem->addRule($conflictRule);
22114
22115 $this->analyzeUnsolvableRule($problem, $conflictRule);
22116
22117 $this->problems[] = $problem;
22118
22119 $seen = array();
22120 $literals = $conflictRule->literals;
22121
22122 foreach ($literals as $literal) {
22123
22124  if ($this->decisions->satisfy($literal)) {
22125 continue;
22126 }
22127 $seen[abs($literal)] = true;
22128 }
22129
22130 foreach ($this->decisions as $decision) {
22131 $literal = $decision[Decisions::DECISION_LITERAL];
22132
22133
22134  if (!isset($seen[abs($literal)])) {
22135 continue;
22136 }
22137
22138 $why = $decision[Decisions::DECISION_REASON];
22139
22140 $problem->addRule($why);
22141 $this->analyzeUnsolvableRule($problem, $why);
22142
22143 $literals = $why->literals;
22144
22145 foreach ($literals as $literal) {
22146
22147  if ($this->decisions->satisfy($literal)) {
22148 continue;
22149 }
22150 $seen[abs($literal)] = true;
22151 }
22152 }
22153
22154 if ($disableRules) {
22155 foreach ($this->problems[count($this->problems) - 1] as $reason) {
22156 $this->disableProblem($reason['rule']);
22157 }
22158
22159 $this->resetSolver();
22160
22161 return 1;
22162 }
22163
22164 return 0;
22165 }
22166
22167 private function disableProblem($why)
22168 {
22169 $job = $why->getJob();
22170
22171 if (!$job) {
22172 $why->disable();
22173
22174 return;
22175 }
22176
22177
22178  foreach ($this->rules as $rule) {
22179 if ($job === $rule->getJob()) {
22180 $rule->disable();
22181 }
22182 }
22183 }
22184
22185 private function resetSolver()
22186 {
22187 $this->decisions->reset();
22188
22189 $this->propagateIndex = 0;
22190 $this->branches = array();
22191
22192 $this->enableDisableLearnedRules();
22193 $this->makeAssertionRuleDecisions();
22194 }
22195
22196
22197
22198
22199
22200
22201
22202
22203 private function enableDisableLearnedRules()
22204 {
22205 foreach ($this->rules->getIteratorFor(RuleSet::TYPE_LEARNED) as $rule) {
22206 $why = $this->learnedWhy[$rule->getId()];
22207 $problemRules = $this->learnedPool[$why];
22208
22209 $foundDisabled = false;
22210 foreach ($problemRules as $problemRule) {
22211 if ($problemRule->isDisabled()) {
22212 $foundDisabled = true;
22213 break;
22214 }
22215 }
22216
22217 if ($foundDisabled && $rule->isEnabled()) {
22218 $rule->disable();
22219 } elseif (!$foundDisabled && $rule->isDisabled()) {
22220 $rule->enable();
22221 }
22222 }
22223 }
22224
22225 private function runSat($disableRules = true)
22226 {
22227 $this->propagateIndex = 0;
22228
22229
22230  
22231  
22232  
22233  
22234  
22235  
22236  
22237  
22238
22239 $decisionQueue = array();
22240 $decisionSupplementQueue = array();
22241 $disableRules = array();
22242
22243 $level = 1;
22244 $systemLevel = $level + 1;
22245 $installedPos = 0;
22246
22247 while (true) {
22248 if (1 === $level) {
22249 $conflictRule = $this->propagate($level);
22250 if (null !== $conflictRule) {
22251 if ($this->analyzeUnsolvable($conflictRule, $disableRules)) {
22252 continue;
22253 }
22254
22255 return;
22256 }
22257 }
22258
22259
22260  if ($level < $systemLevel) {
22261 $iterator = $this->rules->getIteratorFor(RuleSet::TYPE_JOB);
22262 foreach ($iterator as $rule) {
22263 if ($rule->isEnabled()) {
22264 $decisionQueue = array();
22265 $noneSatisfied = true;
22266
22267 foreach ($rule->literals as $literal) {
22268 if ($this->decisions->satisfy($literal)) {
22269 $noneSatisfied = false;
22270 break;
22271 }
22272 if ($literal > 0 && $this->decisions->undecided($literal)) {
22273 $decisionQueue[] = $literal;
22274 }
22275 }
22276
22277 if ($noneSatisfied && count($decisionQueue)) {
22278
22279  
22280  if (count($this->installed) != count($this->updateMap)) {
22281 $prunedQueue = array();
22282 foreach ($decisionQueue as $literal) {
22283 if (isset($this->installedMap[abs($literal)])) {
22284 $prunedQueue[] = $literal;
22285 if (isset($this->updateMap[abs($literal)])) {
22286 $prunedQueue = $decisionQueue;
22287 break;
22288 }
22289 }
22290 }
22291 $decisionQueue = $prunedQueue;
22292 }
22293 }
22294
22295 if ($noneSatisfied && count($decisionQueue)) {
22296 $oLevel = $level;
22297 $level = $this->selectAndInstall($level, $decisionQueue, $disableRules, $rule);
22298
22299 if (0 === $level) {
22300 return;
22301 }
22302 if ($level <= $oLevel) {
22303 break;
22304 }
22305 }
22306 }
22307 }
22308
22309 $systemLevel = $level + 1;
22310
22311
22312  $iterator->next();
22313 if ($iterator->valid()) {
22314 continue;
22315 }
22316 }
22317
22318 if ($level < $systemLevel) {
22319 $systemLevel = $level;
22320 }
22321
22322 for ($i = 0, $n = 0; $n < count($this->rules); $i++, $n++) {
22323 if ($i == count($this->rules)) {
22324 $i = 0;
22325 }
22326
22327 $rule = $this->rules->ruleById[$i];
22328 $literals = $rule->literals;
22329
22330 if ($rule->isDisabled()) {
22331 continue;
22332 }
22333
22334 $decisionQueue = array();
22335
22336
22337  
22338  
22339  
22340  
22341  
22342  foreach ($literals as $literal) {
22343 if ($literal <= 0) {
22344 if (!$this->decisions->decidedInstall(abs($literal))) {
22345 continue 2; 
22346  }
22347 } else {
22348 if ($this->decisions->decidedInstall(abs($literal))) {
22349 continue 2; 
22350  }
22351 if ($this->decisions->undecided(abs($literal))) {
22352 $decisionQueue[] = $literal;
22353 }
22354 }
22355 }
22356
22357
22358  if (count($decisionQueue) < 2) {
22359 continue;
22360 }
22361
22362 $oLevel = $level;
22363 $level = $this->selectAndInstall($level, $decisionQueue, $disableRules, $rule);
22364
22365 if (0 === $level) {
22366 return;
22367 }
22368
22369
22370  $n = -1;
22371 }
22372
22373 if ($level < $systemLevel) {
22374 continue;
22375 }
22376
22377
22378  if (count($this->branches)) {
22379 $lastLiteral = null;
22380 $lastLevel = null;
22381 $lastBranchIndex = 0;
22382 $lastBranchOffset = 0;
22383 $l = 0;
22384
22385 for ($i = count($this->branches) - 1; $i >= 0; $i--) {
22386 list($literals, $l) = $this->branches[$i];
22387
22388 foreach ($literals as $offset => $literal) {
22389 if ($literal && $literal > 0 && $this->decisions->decisionLevel($literal) > $l + 1) {
22390 $lastLiteral = $literal;
22391 $lastBranchIndex = $i;
22392 $lastBranchOffset = $offset;
22393 $lastLevel = $l;
22394 }
22395 }
22396 }
22397
22398 if ($lastLiteral) {
22399 unset($this->branches[$lastBranchIndex][self::BRANCH_LITERALS][$lastBranchOffset]);
22400
22401 $level = $lastLevel;
22402 $this->revert($level);
22403
22404 $why = $this->decisions->lastReason();
22405
22406 $oLevel = $level;
22407 $level = $this->setPropagateLearn($level, $lastLiteral, $disableRules, $why);
22408
22409 if ($level == 0) {
22410 return;
22411 }
22412
22413 continue;
22414 }
22415 }
22416
22417 break;
22418 }
22419 }
22420 }
22421 <?php
22422
22423
22424
22425
22426
22427
22428
22429
22430
22431
22432
22433 namespace Composer\DependencyResolver;
22434
22435 use Composer\Package\LinkConstraint\LinkConstraintInterface;
22436
22437
22438
22439
22440 class Request
22441 {
22442 protected $jobs;
22443 protected $pool;
22444
22445 public function __construct(Pool $pool)
22446 {
22447 $this->pool = $pool;
22448 $this->jobs = array();
22449 }
22450
22451 public function install($packageName, LinkConstraintInterface $constraint = null)
22452 {
22453 $this->addJob($packageName, 'install', $constraint);
22454 }
22455
22456 public function update($packageName, LinkConstraintInterface $constraint = null)
22457 {
22458 $this->addJob($packageName, 'update', $constraint);
22459 }
22460
22461 public function remove($packageName, LinkConstraintInterface $constraint = null)
22462 {
22463 $this->addJob($packageName, 'remove', $constraint);
22464 }
22465
22466
22467
22468
22469
22470
22471 public function fix($packageName, LinkConstraintInterface $constraint = null)
22472 {
22473 $this->addJob($packageName, 'install', $constraint, true);
22474 }
22475
22476 protected function addJob($packageName, $cmd, LinkConstraintInterface $constraint = null, $fixed = false)
22477 {
22478 $packageName = strtolower($packageName);
22479
22480 $this->jobs[] = array(
22481 'cmd' => $cmd,
22482 'packageName' => $packageName,
22483 'constraint' => $constraint,
22484 'fixed' => $fixed
22485 );
22486 }
22487
22488 public function updateAll()
22489 {
22490 $this->jobs[] = array('cmd' => 'update-all');
22491 }
22492
22493 public function getJobs()
22494 {
22495 return $this->jobs;
22496 }
22497 }
22498 <?php
22499
22500
22501
22502
22503
22504
22505
22506
22507
22508
22509
22510 namespace Composer\DependencyResolver;
22511
22512
22513
22514
22515
22516
22517 class Problem
22518 {
22519
22520
22521
22522
22523 protected $reasonSeen;
22524
22525
22526
22527
22528
22529 protected $reasons = array();
22530
22531 protected $section = 0;
22532
22533 protected $pool;
22534
22535 public function __construct(Pool $pool)
22536 {
22537 $this->pool = $pool;
22538 }
22539
22540
22541
22542
22543
22544
22545 public function addRule(Rule $rule)
22546 {
22547 $this->addReason($rule->getId(), array(
22548 'rule' => $rule,
22549 'job' => $rule->getJob(),
22550 ));
22551 }
22552
22553
22554
22555
22556
22557
22558 public function getReasons()
22559 {
22560 return $this->reasons;
22561 }
22562
22563
22564
22565
22566
22567
22568
22569 public function getPrettyString(array $installedMap = array())
22570 {
22571 $reasons = call_user_func_array('array_merge', array_reverse($this->reasons));
22572
22573 if (count($reasons) === 1) {
22574 reset($reasons);
22575 $reason = current($reasons);
22576
22577 $rule = $reason['rule'];
22578 $job = $reason['job'];
22579
22580 if (isset($job['constraint'])) {
22581 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
22582 } else {
22583 $packages = array();
22584 }
22585
22586 if ($job && $job['cmd'] === 'install' && empty($packages)) {
22587
22588  if (0 === stripos($job['packageName'], 'ext-')) {
22589 $ext = substr($job['packageName'], 4);
22590 $error = extension_loaded($ext) ? 'has the wrong version ('.(phpversion($ext) ?: '0').') installed' : 'is missing from your system';
22591
22592 return "\n    - The requested PHP extension ".$job['packageName'].$this->constraintToText($job['constraint']).' '.$error.'.';
22593 }
22594
22595
22596  if (0 === stripos($job['packageName'], 'lib-')) {
22597 if (strtolower($job['packageName']) === 'lib-icu') {
22598 $error = extension_loaded('intl') ? 'has the wrong version installed, try upgrading the intl extension.' : 'is missing from your system, make sure the intl extension is loaded.';
22599
22600 return "\n    - The requested linked library ".$job['packageName'].$this->constraintToText($job['constraint']).' '.$error;
22601 }
22602
22603 return "\n    - The requested linked library ".$job['packageName'].$this->constraintToText($job['constraint']).' has the wrong version installed or is missing from your system, make sure to load the extension providing it.';
22604 }
22605
22606 if (!preg_match('{^[A-Za-z0-9_./-]+$}', $job['packageName'])) {
22607 $illegalChars = preg_replace('{[A-Za-z0-9_./-]+}', '', $job['packageName']);
22608
22609 return "\n    - The requested package ".$job['packageName'].' could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.';
22610 }
22611
22612 if (!$this->pool->whatProvides($job['packageName'])) {
22613 return "\n    - The requested package ".$job['packageName'].' could not be found in any version, there may be a typo in the package name.';
22614 }
22615
22616 return "\n    - The requested package ".$job['packageName'].$this->constraintToText($job['constraint']).' could not be found.';
22617 }
22618 }
22619
22620 $messages = array();
22621
22622 foreach ($reasons as $reason) {
22623 $rule = $reason['rule'];
22624 $job = $reason['job'];
22625
22626 if ($job) {
22627 $messages[] = $this->jobToText($job);
22628 } elseif ($rule) {
22629 if ($rule instanceof Rule) {
22630 $messages[] = $rule->getPrettyString($this->pool, $installedMap);
22631 }
22632 }
22633 }
22634
22635 return "\n    - ".implode("\n    - ", $messages);
22636 }
22637
22638
22639
22640
22641
22642
22643
22644 protected function addReason($id, $reason)
22645 {
22646 if (!isset($this->reasonSeen[$id])) {
22647 $this->reasonSeen[$id] = true;
22648 $this->reasons[$this->section][] = $reason;
22649 }
22650 }
22651
22652 public function nextSection()
22653 {
22654 $this->section++;
22655 }
22656
22657
22658
22659
22660
22661
22662
22663 protected function jobToText($job)
22664 {
22665 switch ($job['cmd']) {
22666 case 'install':
22667 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
22668 if (!$packages) {
22669 return 'No package found to satisfy install request for '.$job['packageName'].$this->constraintToText($job['constraint']);
22670 }
22671
22672 return 'Installation request for '.$job['packageName'].$this->constraintToText($job['constraint']).' -> satisfiable by '.$this->getPackageList($packages).'.';
22673 case 'update':
22674 return 'Update request for '.$job['packageName'].$this->constraintToText($job['constraint']).'.';
22675 case 'remove':
22676 return 'Removal request for '.$job['packageName'].$this->constraintToText($job['constraint']).'';
22677 }
22678
22679 if (isset($job['constraint'])) {
22680 $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
22681 } else {
22682 $packages = array();
22683 }
22684
22685 return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($packages).'])';
22686 }
22687
22688 protected function getPackageList($packages)
22689 {
22690 $prepared = array();
22691 foreach ($packages as $package) {
22692 $prepared[$package->getName()]['name'] = $package->getPrettyName();
22693 $prepared[$package->getName()]['versions'][$package->getVersion()] = $package->getPrettyVersion();
22694 }
22695 foreach ($prepared as $name => $package) {
22696 $prepared[$name] = $package['name'].'['.implode(', ', $package['versions']).']';
22697 }
22698
22699 return implode(', ', $prepared);
22700 }
22701
22702
22703
22704
22705
22706
22707
22708 protected function constraintToText($constraint)
22709 {
22710 return ($constraint) ? ' '.$constraint->getPrettyString() : '';
22711 }
22712 }
22713 <?php
22714
22715
22716
22717
22718
22719
22720
22721
22722
22723
22724
22725 namespace Composer\DependencyResolver;
22726
22727
22728
22729
22730
22731
22732
22733
22734
22735
22736
22737 class RuleWatchGraph
22738 {
22739 protected $watchChains = array();
22740
22741
22742
22743
22744
22745
22746
22747
22748
22749
22750
22751
22752
22753 public function insert(RuleWatchNode $node)
22754 {
22755 if ($node->getRule()->isAssertion()) {
22756 return;
22757 }
22758
22759 foreach (array($node->watch1, $node->watch2) as $literal) {
22760 if (!isset($this->watchChains[$literal])) {
22761 $this->watchChains[$literal] = new RuleWatchChain;
22762 }
22763
22764 $this->watchChains[$literal]->unshift($node);
22765 }
22766 }
22767
22768
22769
22770
22771
22772
22773
22774
22775
22776
22777
22778
22779
22780
22781
22782
22783
22784
22785
22786
22787
22788
22789
22790
22791 public function propagateLiteral($decidedLiteral, $level, $decisions)
22792 {
22793
22794  
22795  
22796  $literal = -$decidedLiteral;
22797
22798 if (!isset($this->watchChains[$literal])) {
22799 return null;
22800 }
22801
22802 $chain = $this->watchChains[$literal];
22803
22804 $chain->rewind();
22805 while ($chain->valid()) {
22806 $node = $chain->current();
22807 $otherWatch = $node->getOtherWatch($literal);
22808
22809 if (!$node->getRule()->isDisabled() && !$decisions->satisfy($otherWatch)) {
22810 $ruleLiterals = $node->getRule()->literals;
22811
22812 $alternativeLiterals = array_filter($ruleLiterals, function ($ruleLiteral) use ($literal, $otherWatch, $decisions) {
22813 return $literal !== $ruleLiteral &&
22814 $otherWatch !== $ruleLiteral &&
22815 !$decisions->conflict($ruleLiteral);
22816 });
22817
22818 if ($alternativeLiterals) {
22819 reset($alternativeLiterals);
22820 $this->moveWatch($literal, current($alternativeLiterals), $node);
22821 continue;
22822 }
22823
22824 if ($decisions->conflict($otherWatch)) {
22825 return $node->getRule();
22826 }
22827
22828 $decisions->decide($otherWatch, $level, $node->getRule());
22829 }
22830
22831 $chain->next();
22832 }
22833
22834 return null;
22835 }
22836
22837
22838
22839
22840
22841
22842
22843
22844
22845
22846 protected function moveWatch($fromLiteral, $toLiteral, $node)
22847 {
22848 if (!isset($this->watchChains[$toLiteral])) {
22849 $this->watchChains[$toLiteral] = new RuleWatchChain;
22850 }
22851
22852 $node->moveWatch($fromLiteral, $toLiteral);
22853 $this->watchChains[$fromLiteral]->remove();
22854 $this->watchChains[$toLiteral]->unshift($node);
22855 }
22856 }
22857 <?php
22858
22859
22860
22861
22862
22863
22864
22865
22866
22867
22868
22869 namespace Composer\Config;
22870
22871
22872
22873
22874
22875
22876
22877 interface ConfigSourceInterface
22878 {
22879
22880
22881
22882
22883
22884
22885 public function addRepository($name, $config);
22886
22887
22888
22889
22890
22891
22892 public function removeRepository($name);
22893
22894
22895
22896
22897
22898
22899
22900 public function addConfigSetting($name, $value);
22901
22902
22903
22904
22905
22906
22907 public function removeConfigSetting($name);
22908
22909
22910
22911
22912
22913
22914
22915
22916 public function addLink($type, $name, $value);
22917
22918
22919
22920
22921
22922
22923
22924 public function removeLink($type, $name);
22925
22926
22927
22928
22929
22930
22931 public function getName();
22932 }
22933 <?php
22934
22935
22936
22937
22938
22939
22940
22941
22942
22943
22944
22945 namespace Composer\Config;
22946
22947 use Composer\Json\JsonFile;
22948 use Composer\Json\JsonManipulator;
22949
22950
22951
22952
22953
22954
22955
22956 class JsonConfigSource implements ConfigSourceInterface
22957 {
22958
22959
22960
22961 private $file;
22962
22963
22964
22965
22966 private $authConfig;
22967
22968
22969
22970
22971
22972
22973
22974 public function __construct(JsonFile $file, $authConfig = false)
22975 {
22976 $this->file = $file;
22977 $this->authConfig = $authConfig;
22978 }
22979
22980
22981
22982
22983 public function getName()
22984 {
22985 return $this->file->getPath();
22986 }
22987
22988
22989
22990
22991 public function addRepository($name, $config)
22992 {
22993 $this->manipulateJson('addRepository', $name, $config, function (&$config, $repo, $repoConfig) {
22994 $config['repositories'][$repo] = $repoConfig;
22995 });
22996 }
22997
22998
22999
23000
23001 public function removeRepository($name)
23002 {
23003 $this->manipulateJson('removeRepository', $name, function (&$config, $repo) {
23004 unset($config['repositories'][$repo]);
23005 });
23006 }
23007
23008
23009
23010
23011 public function addConfigSetting($name, $value)
23012 {
23013 $this->manipulateJson('addConfigSetting', $name, $value, function (&$config, $key, $val) {
23014 if ($key === 'github-oauth' || $key === 'http-basic') {
23015 list($key, $host) = explode('.', $key, 2);
23016 if ($this->authConfig) {
23017 $config[$key][$host] = $val;
23018 } else {
23019 $config['config'][$key][$host] = $val;
23020 }
23021 } else {
23022 $config['config'][$key] = $val;
23023 }
23024 });
23025 }
23026
23027
23028
23029
23030 public function removeConfigSetting($name)
23031 {
23032 $this->manipulateJson('removeConfigSetting', $name, function (&$config, $key) {
23033 if ($key === 'github-oauth' || $key === 'http-basic') {
23034 list($key, $host) = explode('.', $key, 2);
23035 if ($this->authConfig) {
23036 unset($config[$key][$host]);
23037 } else {
23038 unset($config['config'][$key][$host]);
23039 }
23040 } else {
23041 unset($config['config'][$key]);
23042 }
23043 });
23044 }
23045
23046
23047
23048
23049 public function addLink($type, $name, $value)
23050 {
23051 $this->manipulateJson('addLink', $type, $name, $value, function (&$config, $type, $name, $value) {
23052 $config[$type][$name] = $value;
23053 });
23054 }
23055
23056
23057
23058
23059 public function removeLink($type, $name)
23060 {
23061 $this->manipulateJson('removeSubNode', $type, $name, function (&$config, $type, $name) {
23062 unset($config[$type][$name]);
23063 });
23064 }
23065
23066 protected function manipulateJson($method, $args, $fallback)
23067 {
23068 $args = func_get_args();
23069
23070  array_shift($args);
23071 $fallback = array_pop($args);
23072
23073 if ($this->file->exists()) {
23074 $contents = file_get_contents($this->file->getPath());
23075 } elseif ($this->authConfig) {
23076 $contents = "{\n}\n";
23077 } else {
23078 $contents = "{\n    \"config\": {\n    }\n}\n";
23079 }
23080
23081 $manipulator = new JsonManipulator($contents);
23082
23083 $newFile = !$this->file->exists();
23084
23085
23086  if ($this->authConfig && $method === 'addConfigSetting') {
23087 $method = 'addSubNode';
23088 list($mainNode, $name) = explode('.', $args[0], 2);
23089 $args = array($mainNode, $name, $args[1]);
23090 } elseif ($this->authConfig && $method === 'removeConfigSetting') {
23091 $method = 'removeSubNode';
23092 list($mainNode, $name) = explode('.', $args[0], 2);
23093 $args = array($mainNode, $name);
23094 }
23095
23096
23097  if (call_user_func_array(array($manipulator, $method), $args)) {
23098 file_put_contents($this->file->getPath(), $manipulator->getContents());
23099 } else {
23100
23101  $config = $this->file->read();
23102 $this->arrayUnshiftRef($args, $config);
23103 call_user_func_array($fallback, $args);
23104 $this->file->write($config);
23105 }
23106
23107 if ($newFile) {
23108 @chmod($this->file->getPath(), 0600);
23109 }
23110 }
23111
23112
23113
23114
23115
23116
23117
23118
23119 private function arrayUnshiftRef(&$array, &$value)
23120 {
23121 $return = array_unshift($array, '');
23122 $array[0] = &$value;
23123
23124 return $return;
23125 }
23126 }
23127 <?php
23128
23129
23130
23131
23132
23133
23134
23135
23136
23137
23138
23139 namespace Composer\Plugin;
23140
23141
23142
23143
23144
23145
23146 class PluginEvents
23147 {
23148
23149
23150
23151
23152
23153
23154
23155
23156 const COMMAND = 'command';
23157
23158
23159
23160
23161
23162
23163
23164
23165
23166 const PRE_FILE_DOWNLOAD = 'pre-file-download';
23167 }
23168 <?php
23169
23170
23171
23172
23173
23174
23175
23176
23177
23178
23179
23180 namespace Composer\Plugin;
23181
23182 use Composer\EventDispatcher\Event;
23183 use Symfony\Component\Console\Input\InputInterface;
23184 use Symfony\Component\Console\Output\OutputInterface;
23185
23186
23187
23188
23189
23190
23191 class CommandEvent extends Event
23192 {
23193
23194
23195
23196 private $commandName;
23197
23198
23199
23200
23201 private $input;
23202
23203
23204
23205
23206 private $output;
23207
23208
23209
23210
23211
23212
23213
23214
23215
23216
23217
23218 public function __construct($name, $commandName, $input, $output, array $args = array(), array $flags = array())
23219 {
23220 parent::__construct($name, $args, $flags);
23221 $this->commandName = $commandName;
23222 $this->input = $input;
23223 $this->output = $output;
23224 }
23225
23226
23227
23228
23229
23230
23231 public function getInput()
23232 {
23233 return $this->input;
23234 }
23235
23236
23237
23238
23239
23240
23241 public function getOutput()
23242 {
23243 return $this->output;
23244 }
23245
23246
23247
23248
23249
23250
23251 public function getCommandName()
23252 {
23253 return $this->commandName;
23254 }
23255 }
23256 <?php
23257
23258
23259
23260
23261
23262
23263
23264
23265
23266
23267
23268 namespace Composer\Plugin;
23269
23270 use Composer\EventDispatcher\Event;
23271 use Composer\Util\RemoteFilesystem;
23272
23273
23274
23275
23276
23277
23278 class PreFileDownloadEvent extends Event
23279 {
23280
23281
23282
23283 private $rfs;
23284
23285
23286
23287
23288 private $processedUrl;
23289
23290
23291
23292
23293
23294
23295
23296
23297 public function __construct($name, RemoteFilesystem $rfs, $processedUrl)
23298 {
23299 parent::__construct($name);
23300 $this->rfs = $rfs;
23301 $this->processedUrl = $processedUrl;
23302 }
23303
23304
23305
23306
23307
23308
23309 public function getRemoteFilesystem()
23310 {
23311 return $this->rfs;
23312 }
23313
23314
23315
23316
23317
23318
23319 public function setRemoteFilesystem(RemoteFilesystem $rfs)
23320 {
23321 $this->rfs = $rfs;
23322 }
23323
23324
23325
23326
23327
23328
23329 public function getProcessedUrl()
23330 {
23331 return $this->processedUrl;
23332 }
23333 }
23334 <?php
23335
23336
23337
23338
23339
23340
23341
23342
23343
23344
23345
23346 namespace Composer\Plugin;
23347
23348 use Composer\Composer;
23349 use Composer\IO\IOInterface;
23350
23351
23352
23353
23354
23355
23356 interface PluginInterface
23357 {
23358
23359
23360
23361
23362
23363 const PLUGIN_API_VERSION = '1.0.0';
23364
23365
23366
23367
23368
23369
23370
23371 public function activate(Composer $composer, IOInterface $io);
23372 }
23373 <?php
23374
23375
23376
23377
23378
23379
23380
23381
23382
23383
23384
23385 namespace Composer\Plugin;
23386
23387 use Composer\Composer;
23388 use Composer\EventDispatcher\EventSubscriberInterface;
23389 use Composer\IO\IOInterface;
23390 use Composer\Package\Package;
23391 use Composer\Package\Version\VersionParser;
23392 use Composer\Repository\RepositoryInterface;
23393 use Composer\Package\AliasPackage;
23394 use Composer\Package\PackageInterface;
23395 use Composer\Package\Link;
23396 use Composer\Package\LinkConstraint\VersionConstraint;
23397 use Composer\DependencyResolver\Pool;
23398
23399
23400
23401
23402
23403
23404
23405 class PluginManager
23406 {
23407 protected $composer;
23408 protected $io;
23409 protected $globalComposer;
23410 protected $versionParser;
23411
23412 protected $plugins = array();
23413 protected $registeredPlugins = array();
23414
23415 private static $classCounter = 0;
23416
23417
23418
23419
23420
23421
23422
23423
23424 public function __construct(IOInterface $io, Composer $composer, Composer $globalComposer = null)
23425 {
23426 $this->io = $io;
23427 $this->composer = $composer;
23428 $this->globalComposer = $globalComposer;
23429 $this->versionParser = new VersionParser();
23430 }
23431
23432
23433
23434
23435 public function loadInstalledPlugins()
23436 {
23437 $repo = $this->composer->getRepositoryManager()->getLocalRepository();
23438 $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
23439 if ($repo) {
23440 $this->loadRepository($repo);
23441 }
23442 if ($globalRepo) {
23443 $this->loadRepository($globalRepo);
23444 }
23445 }
23446
23447
23448
23449
23450
23451
23452 public function addPlugin(PluginInterface $plugin)
23453 {
23454 $this->plugins[] = $plugin;
23455 $plugin->activate($this->composer, $this->io);
23456
23457 if ($plugin instanceof EventSubscriberInterface) {
23458 $this->composer->getEventDispatcher()->addSubscriber($plugin);
23459 }
23460 }
23461
23462
23463
23464
23465
23466
23467 public function getPlugins()
23468 {
23469 return $this->plugins;
23470 }
23471
23472
23473
23474
23475
23476
23477
23478
23479
23480
23481
23482
23483 public function loadRepository(RepositoryInterface $repo)
23484 {
23485 foreach ($repo->getPackages() as $package) {
23486 if ($package instanceof AliasPackage) {
23487 continue;
23488 }
23489 if ('composer-plugin' === $package->getType()) {
23490 $requiresComposer = null;
23491 foreach ($package->getRequires() as $link) {
23492 if ($link->getTarget() == 'composer-plugin-api') {
23493 $requiresComposer = $link->getConstraint();
23494 }
23495 }
23496
23497 if (!$requiresComposer) {
23498 throw new \RuntimeException("Plugin ".$package->getName()." is missing a require statement for a version of the composer-plugin-api package.");
23499 }
23500
23501 if (!$requiresComposer->matches(new VersionConstraint('==', $this->versionParser->normalize(PluginInterface::PLUGIN_API_VERSION)))) {
23502 $this->io->write("<warning>The plugin ".$package->getName()." requires a version of composer-plugin-api that does not match your composer installation. You may need to run composer update with the '--no-plugins' option.</warning>");
23503 }
23504
23505 $this->registerPackage($package);
23506 }
23507
23508  if ('composer-installer' === $package->getType()) {
23509 $this->registerPackage($package);
23510 }
23511 }
23512 }
23513
23514
23515
23516
23517
23518
23519
23520
23521
23522
23523 protected function collectDependencies(Pool $pool, array $collected, PackageInterface $package)
23524 {
23525 $requires = array_merge(
23526 $package->getRequires(),
23527 $package->getDevRequires()
23528 );
23529
23530 foreach ($requires as $requireLink) {
23531 $requiredPackage = $this->lookupInstalledPackage($pool, $requireLink);
23532 if ($requiredPackage && !isset($collected[$requiredPackage->getName()])) {
23533 $collected[$requiredPackage->getName()] = $requiredPackage;
23534 $collected = $this->collectDependencies($pool, $collected, $requiredPackage);
23535 }
23536 }
23537
23538 return $collected;
23539 }
23540
23541
23542
23543
23544
23545
23546
23547
23548
23549
23550
23551 protected function lookupInstalledPackage(Pool $pool, Link $link)
23552 {
23553 $packages = $pool->whatProvides($link->getTarget(), $link->getConstraint());
23554
23555 return (!empty($packages)) ? $packages[0] : null;
23556 }
23557
23558
23559
23560
23561
23562
23563
23564
23565
23566
23567
23568
23569 public function registerPackage(PackageInterface $package, $failOnMissingClasses = false)
23570 {
23571 $oldInstallerPlugin = ($package->getType() === 'composer-installer');
23572
23573 if (in_array($package->getName(), $this->registeredPlugins)) {
23574 return;
23575 }
23576
23577 $extra = $package->getExtra();
23578 if (empty($extra['class'])) {
23579 throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
23580 }
23581 $classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']);
23582
23583 $localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
23584 $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
23585
23586 $pool = new Pool('dev');
23587 $pool->addRepository($localRepo);
23588 if ($globalRepo) {
23589 $pool->addRepository($globalRepo);
23590 }
23591
23592 $autoloadPackages = array($package->getName() => $package);
23593 $autoloadPackages = $this->collectDependencies($pool, $autoloadPackages, $package);
23594
23595 $generator = $this->composer->getAutoloadGenerator();
23596 $autoloads = array();
23597 foreach ($autoloadPackages as $autoloadPackage) {
23598 $downloadPath = $this->getInstallPath($autoloadPackage, ($globalRepo && $globalRepo->hasPackage($autoloadPackage)));
23599 $autoloads[] = array($autoloadPackage, $downloadPath);
23600 }
23601
23602 $map = $generator->parseAutoloads($autoloads, new Package('dummy', '1.0.0.0', '1.0.0'));
23603 $classLoader = $generator->createLoader($map);
23604 $classLoader->register();
23605
23606 foreach ($classes as $class) {
23607 if (class_exists($class, false)) {
23608 $code = file_get_contents($classLoader->findFile($class));
23609 $code = preg_replace('{^(\s*)class\s+(\S+)}mi', '$1class $2_composer_tmp'.self::$classCounter, $code);
23610 eval('?>'.$code);
23611 $class .= '_composer_tmp'.self::$classCounter;
23612 self::$classCounter++;
23613 }
23614
23615 if ($oldInstallerPlugin) {
23616 $installer = new $class($this->io, $this->composer);
23617 $this->composer->getInstallationManager()->addInstaller($installer);
23618 } elseif (class_exists($class)) {
23619 $plugin = new $class();
23620 $this->addPlugin($plugin);
23621 $this->registeredPlugins[] = $package->getName();
23622 } elseif ($failOnMissingClasses) {
23623 throw new \UnexpectedValueException('Plugin '.$package->getName().' could not be initialized, class not found: '.$class);
23624 }
23625 }
23626 }
23627
23628
23629
23630
23631
23632
23633
23634
23635
23636 public function getInstallPath(PackageInterface $package, $global = false)
23637 {
23638 if (!$global) {
23639 return $this->composer->getInstallationManager()->getInstallPath($package);
23640 }
23641
23642 return $this->globalComposer->getInstallationManager()->getInstallPath($package);
23643 }
23644 }
23645 <?php
23646
23647
23648
23649
23650
23651
23652
23653
23654
23655
23656
23657 namespace Composer;
23658
23659 use Composer\Config\JsonConfigSource;
23660 use Composer\Json\JsonFile;
23661 use Composer\IO\IOInterface;
23662 use Composer\Package\Archiver;
23663 use Composer\Repository\RepositoryManager;
23664 use Composer\Repository\RepositoryInterface;
23665 use Composer\Repository\WritableRepositoryInterface;
23666 use Composer\Util\ProcessExecutor;
23667 use Composer\Util\RemoteFilesystem;
23668 use Composer\Util\Filesystem;
23669 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
23670 use Composer\EventDispatcher\EventDispatcher;
23671 use Composer\Autoload\AutoloadGenerator;
23672 use Composer\Package\Version\VersionParser;
23673
23674
23675
23676
23677
23678
23679
23680
23681
23682 class Factory
23683 {
23684
23685
23686
23687
23688 protected static function getHomeDir()
23689 {
23690 $home = getenv('COMPOSER_HOME');
23691 if (!$home) {
23692 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
23693 if (!getenv('APPDATA')) {
23694 throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly');
23695 }
23696 $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer';
23697 } else {
23698 if (!getenv('HOME')) {
23699 throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly');
23700 }
23701 $home = rtrim(getenv('HOME'), '/') . '/.composer';
23702 }
23703 }
23704
23705 return $home;
23706 }
23707
23708
23709
23710
23711
23712
23713 protected static function getCacheDir($home)
23714 {
23715 $cacheDir = getenv('COMPOSER_CACHE_DIR');
23716 if (!$cacheDir) {
23717 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
23718 if ($cacheDir = getenv('LOCALAPPDATA')) {
23719 $cacheDir .= '/Composer';
23720 } else {
23721 $cacheDir = $home . '/cache';
23722 }
23723 $cacheDir = strtr($cacheDir, '\\', '/');
23724 } else {
23725 $cacheDir = $home.'/cache';
23726 }
23727 }
23728
23729 return $cacheDir;
23730 }
23731
23732
23733
23734
23735
23736 public static function createConfig(IOInterface $io = null, $cwd = null)
23737 {
23738 $cwd = $cwd ?: getcwd();
23739
23740
23741  $home = self::getHomeDir();
23742 $cacheDir = self::getCacheDir($home);
23743
23744
23745  
23746  
23747  foreach (array($home, $cacheDir) as $dir) {
23748 if (!file_exists($dir . '/.htaccess')) {
23749 if (!is_dir($dir)) {
23750 @mkdir($dir, 0777, true);
23751 }
23752 @file_put_contents($dir . '/.htaccess', 'Deny from all');
23753 }
23754 }
23755
23756 $config = new Config(true, $cwd);
23757
23758
23759  $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir)));
23760
23761
23762  $file = new JsonFile($home.'/config.json');
23763 if ($file->exists()) {
23764 if ($io && $io->isDebug()) {
23765 $io->write('Loading config file ' . $file->getPath());
23766 }
23767 $config->merge($file->read());
23768 }
23769 $config->setConfigSource(new JsonConfigSource($file));
23770
23771
23772  $file = new JsonFile($config->get('home').'/auth.json');
23773 if ($file->exists()) {
23774 if ($io && $io->isDebug()) {
23775 $io->write('Loading config file ' . $file->getPath());
23776 }
23777 $config->merge(array('config' => $file->read()));
23778 }
23779 $config->setAuthConfigSource(new JsonConfigSource($file, true));
23780
23781 return $config;
23782 }
23783
23784 public static function getComposerFile()
23785 {
23786 return trim(getenv('COMPOSER')) ?: './composer.json';
23787 }
23788
23789 public static function createAdditionalStyles()
23790 {
23791 return array(
23792 'highlight' => new OutputFormatterStyle('red'),
23793 'warning' => new OutputFormatterStyle('black', 'yellow'),
23794 );
23795 }
23796
23797 public static function createDefaultRepositories(IOInterface $io = null, Config $config = null, RepositoryManager $rm = null)
23798 {
23799 $repos = array();
23800
23801 if (!$config) {
23802 $config = static::createConfig($io);
23803 }
23804 if (!$rm) {
23805 if (!$io) {
23806 throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager');
23807 }
23808 $factory = new static;
23809 $rm = $factory->createRepositoryManager($io, $config);
23810 }
23811
23812 foreach ($config->getRepositories() as $index => $repo) {
23813 if (!is_array($repo)) {
23814 throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') should be an array, '.gettype($repo).' given');
23815 }
23816 if (!isset($repo['type'])) {
23817 throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined');
23818 }
23819 $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
23820 while (isset($repos[$name])) {
23821 $name .= '2';
23822 }
23823 $repos[$name] = $rm->createRepository($repo['type'], $repo);
23824 }
23825
23826 return $repos;
23827 }
23828
23829
23830
23831
23832
23833
23834
23835
23836
23837
23838
23839
23840
23841 public function createComposer(IOInterface $io, $localConfig = null, $disablePlugins = false, $cwd = null, $fullLoad = true)
23842 {
23843 $cwd = $cwd ?: getcwd();
23844
23845
23846  if (null === $localConfig) {
23847 $localConfig = static::getComposerFile();
23848 }
23849
23850 if (is_string($localConfig)) {
23851 $composerFile = $localConfig;
23852 $file = new JsonFile($localConfig, new RemoteFilesystem($io));
23853
23854 if (!$file->exists()) {
23855 if ($localConfig === './composer.json' || $localConfig === 'composer.json') {
23856 $message = 'Composer could not find a composer.json file in '.$cwd;
23857 } else {
23858 $message = 'Composer could not find the config file: '.$localConfig;
23859 }
23860 $instructions = 'To initialize a project, please create a composer.json file as described in the http://getcomposer.org/ "Getting Started" section';
23861 throw new \InvalidArgumentException($message.PHP_EOL.$instructions);
23862 }
23863
23864 $file->validateSchema(JsonFile::LAX_SCHEMA);
23865 $localConfig = $file->read();
23866 }
23867
23868
23869  $config = static::createConfig($io, $cwd);
23870 $config->merge($localConfig);
23871 if (isset($composerFile)) {
23872 if ($io && $io->isDebug()) {
23873 $io->write('Loading config file ' . $composerFile);
23874 }
23875 $localAuthFile = new JsonFile(dirname(realpath($composerFile)) . '/auth.json');
23876 if ($localAuthFile->exists()) {
23877 if ($io && $io->isDebug()) {
23878 $io->write('Loading config file ' . $localAuthFile->getPath());
23879 }
23880 $config->merge(array('config' => $localAuthFile->read()));
23881 $config->setAuthConfigSource(new JsonConfigSource($localAuthFile, true));
23882 }
23883 }
23884
23885 $vendorDir = $config->get('vendor-dir');
23886 $binDir = $config->get('bin-dir');
23887
23888
23889  $composer = new Composer();
23890 $composer->setConfig($config);
23891
23892 if ($fullLoad) {
23893
23894  $io->loadConfiguration($config);
23895
23896
23897  ProcessExecutor::setTimeout((int) $config->get('process-timeout'));
23898 }
23899
23900
23901  $dispatcher = new EventDispatcher($composer, $io);
23902 $composer->setEventDispatcher($dispatcher);
23903
23904
23905  $rm = $this->createRepositoryManager($io, $config, $dispatcher);
23906 $composer->setRepositoryManager($rm);
23907
23908
23909  $this->addLocalRepository($rm, $vendorDir);
23910
23911
23912  $parser = new VersionParser;
23913 $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, new ProcessExecutor($io));
23914 $package = $loader->load($localConfig);
23915 $composer->setPackage($package);
23916
23917
23918  $im = $this->createInstallationManager();
23919 $composer->setInstallationManager($im);
23920
23921 if ($fullLoad) {
23922
23923  $dm = $this->createDownloadManager($io, $config, $dispatcher);
23924 $composer->setDownloadManager($dm);
23925
23926
23927  $generator = new AutoloadGenerator($dispatcher, $io);
23928 $composer->setAutoloadGenerator($generator);
23929 }
23930
23931
23932  $this->createDefaultInstallers($im, $composer, $io);
23933
23934 if ($fullLoad) {
23935 $globalComposer = $this->createGlobalComposer($io, $config, $disablePlugins);
23936 $pm = $this->createPluginManager($io, $composer, $globalComposer);
23937 $composer->setPluginManager($pm);
23938
23939 if (!$disablePlugins) {
23940 $pm->loadInstalledPlugins();
23941 }
23942
23943
23944  
23945  if ($rm->getLocalRepository()) {
23946 $this->purgePackages($rm->getLocalRepository(), $im);
23947 }
23948 }
23949
23950
23951  if ($fullLoad && isset($composerFile)) {
23952 $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION)
23953 ? substr($composerFile, 0, -4).'lock'
23954 : $composerFile . '.lock';
23955 $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile));
23956 $composer->setLocker($locker);
23957 }
23958
23959 return $composer;
23960 }
23961
23962
23963
23964
23965
23966
23967
23968 protected function createRepositoryManager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
23969 {
23970 $rm = new RepositoryManager($io, $config, $eventDispatcher);
23971 $rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
23972 $rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
23973 $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
23974 $rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
23975 $rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
23976 $rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
23977 $rm->setRepositoryClass('perforce', 'Composer\Repository\VcsRepository');
23978 $rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository');
23979 $rm->setRepositoryClass('artifact', 'Composer\Repository\ArtifactRepository');
23980
23981 return $rm;
23982 }
23983
23984
23985
23986
23987
23988 protected function addLocalRepository(RepositoryManager $rm, $vendorDir)
23989 {
23990 $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed.json')));
23991 }
23992
23993
23994
23995
23996
23997 protected function createGlobalComposer(IOInterface $io, Config $config, $disablePlugins)
23998 {
23999 if (realpath($config->get('home')) === getcwd()) {
24000 return;
24001 }
24002
24003 $composer = null;
24004 try {
24005 $composer = self::createComposer($io, $config->get('home') . '/composer.json', $disablePlugins, $config->get('home'), false);
24006 } catch (\Exception $e) {
24007 if ($io->isDebug()) {
24008 $io->write('Failed to initialize global composer: '.$e->getMessage());
24009 }
24010 }
24011
24012 return $composer;
24013 }
24014
24015
24016
24017
24018
24019
24020
24021 public function createDownloadManager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
24022 {
24023 $cache = null;
24024 if ($config->get('cache-files-ttl') > 0) {
24025 $cache = new Cache($io, $config->get('cache-files-dir'), 'a-z0-9_./');
24026 }
24027
24028 $dm = new Downloader\DownloadManager($io);
24029 switch ($config->get('preferred-install')) {
24030 case 'dist':
24031 $dm->setPreferDist(true);
24032 break;
24033 case 'source':
24034 $dm->setPreferSource(true);
24035 break;
24036 case 'auto':
24037 default:
24038
24039  break;
24040 }
24041
24042 $dm->setDownloader('git', new Downloader\GitDownloader($io, $config));
24043 $dm->setDownloader('svn', new Downloader\SvnDownloader($io, $config));
24044 $dm->setDownloader('hg', new Downloader\HgDownloader($io, $config));
24045 $dm->setDownloader('perforce', new Downloader\PerforceDownloader($io, $config));
24046 $dm->setDownloader('zip', new Downloader\ZipDownloader($io, $config, $eventDispatcher, $cache));
24047 $dm->setDownloader('rar', new Downloader\RarDownloader($io, $config, $eventDispatcher, $cache));
24048 $dm->setDownloader('tar', new Downloader\TarDownloader($io, $config, $eventDispatcher, $cache));
24049 $dm->setDownloader('gzip', new Downloader\GzipDownloader($io, $config, $eventDispatcher, $cache));
24050 $dm->setDownloader('phar', new Downloader\PharDownloader($io, $config, $eventDispatcher, $cache));
24051 $dm->setDownloader('file', new Downloader\FileDownloader($io, $config, $eventDispatcher, $cache));
24052
24053 return $dm;
24054 }
24055
24056
24057
24058
24059
24060
24061
24062 public function createArchiveManager(Config $config, Downloader\DownloadManager $dm = null)
24063 {
24064 if (null === $dm) {
24065 $io = new IO\NullIO();
24066 $io->loadConfiguration($config);
24067 $dm = $this->createDownloadManager($io, $config);
24068 }
24069
24070 $am = new Archiver\ArchiveManager($dm);
24071 $am->addArchiver(new Archiver\PharArchiver);
24072
24073 return $am;
24074 }
24075
24076
24077
24078
24079
24080
24081
24082 protected function createPluginManager(IOInterface $io, Composer $composer, Composer $globalComposer = null)
24083 {
24084 return new Plugin\PluginManager($io, $composer, $globalComposer);
24085 }
24086
24087
24088
24089
24090 protected function createInstallationManager()
24091 {
24092 return new Installer\InstallationManager();
24093 }
24094
24095
24096
24097
24098
24099
24100 protected function createDefaultInstallers(Installer\InstallationManager $im, Composer $composer, IOInterface $io)
24101 {
24102 $im->addInstaller(new Installer\LibraryInstaller($io, $composer, null));
24103 $im->addInstaller(new Installer\PearInstaller($io, $composer, 'pear-library'));
24104 $im->addInstaller(new Installer\PluginInstaller($io, $composer));
24105 $im->addInstaller(new Installer\MetapackageInstaller($io));
24106 }
24107
24108
24109
24110
24111
24112 protected function purgePackages(WritableRepositoryInterface $repo, Installer\InstallationManager $im)
24113 {
24114 foreach ($repo->getPackages() as $package) {
24115 if (!$im->isPackageInstalled($repo, $package)) {
24116 $repo->removePackage($package);
24117 }
24118 }
24119 }
24120
24121
24122
24123
24124
24125
24126
24127
24128 public static function create(IOInterface $io, $config = null, $disablePlugins = false)
24129 {
24130 $factory = new static();
24131
24132 return $factory->createComposer($io, $config, $disablePlugins);
24133 }
24134 }
24135 <?php
24136
24137
24138
24139
24140
24141
24142
24143
24144
24145
24146
24147 namespace Composer\Util;
24148
24149 use RecursiveDirectoryIterator;
24150 use RecursiveIteratorIterator;
24151 use Symfony\Component\Finder\Finder;
24152
24153
24154
24155
24156
24157 class Filesystem
24158 {
24159 private $processExecutor;
24160
24161 public function __construct(ProcessExecutor $executor = null)
24162 {
24163 $this->processExecutor = $executor ?: new ProcessExecutor();
24164 }
24165
24166 public function remove($file)
24167 {
24168 if (is_dir($file)) {
24169 return $this->removeDirectory($file);
24170 }
24171
24172 if (file_exists($file)) {
24173 return $this->unlink($file);
24174 }
24175
24176 return false;
24177 }
24178
24179
24180
24181
24182
24183
24184
24185 public function isDirEmpty($dir)
24186 {
24187 $finder = Finder::create()
24188 ->ignoreVCS(false)
24189 ->ignoreDotFiles(false)
24190 ->depth(0)
24191 ->in($dir);
24192
24193 return count($finder) === 0;
24194 }
24195
24196 public function emptyDirectory($dir, $ensureDirectoryExists = true)
24197 {
24198 if (file_exists($dir) && is_link($dir)) {
24199 $this->unlink($dir);
24200 }
24201
24202 if ($ensureDirectoryExists) {
24203 $this->ensureDirectoryExists($dir);
24204 }
24205
24206 if (is_dir($dir)) {
24207 $finder = Finder::create()
24208 ->ignoreVCS(false)
24209 ->ignoreDotFiles(false)
24210 ->depth(0)
24211 ->in($dir);
24212
24213 foreach ($finder as $path) {
24214 $this->remove((string) $path);
24215 }
24216 }
24217 }
24218
24219
24220
24221
24222
24223
24224
24225
24226
24227
24228
24229
24230 public function removeDirectory($directory)
24231 {
24232 if ($this->isSymlinkedDirectory($directory)) {
24233 return $this->unlinkSymlinkedDirectory($directory);
24234 }
24235
24236 if (!file_exists($directory) || !is_dir($directory)) {
24237 return true;
24238 }
24239
24240 if (preg_match('{^(?:[a-z]:)?[/\\\\]+$}i', $directory)) {
24241 throw new \RuntimeException('Aborting an attempted deletion of '.$directory.', this was probably not intended, if it is a real use case please report it.');
24242 }
24243
24244 if (!function_exists('proc_open')) {
24245 return $this->removeDirectoryPhp($directory);
24246 }
24247
24248 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
24249 $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory)));
24250 } else {
24251 $cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory));
24252 }
24253
24254 $result = $this->getProcess()->execute($cmd, $output) === 0;
24255
24256
24257  clearstatcache();
24258
24259 if ($result && !file_exists($directory)) {
24260 return true;
24261 }
24262
24263 return $this->removeDirectoryPhp($directory);
24264 }
24265
24266
24267
24268
24269
24270
24271
24272
24273
24274
24275
24276 public function removeDirectoryPhp($directory)
24277 {
24278 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
24279 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
24280
24281 foreach ($ri as $file) {
24282 if ($file->isDir()) {
24283 $this->rmdir($file->getPathname());
24284 } else {
24285 $this->unlink($file->getPathname());
24286 }
24287 }
24288
24289 return $this->rmdir($directory);
24290 }
24291
24292 public function ensureDirectoryExists($directory)
24293 {
24294 if (!is_dir($directory)) {
24295 if (file_exists($directory)) {
24296 throw new \RuntimeException(
24297 $directory.' exists and is not a directory.'
24298 );
24299 }
24300 if (!@mkdir($directory, 0777, true)) {
24301 throw new \RuntimeException(
24302 $directory.' does not exist and could not be created.'
24303 );
24304 }
24305 }
24306 }
24307
24308
24309
24310
24311
24312
24313
24314
24315
24316 public function unlink($path)
24317 {
24318 if (!@$this->unlinkImplementation($path)) {
24319
24320  if (!defined('PHP_WINDOWS_VERSION_BUILD') || (usleep(350000) && !@$this->unlinkImplementation($path))) {
24321 $error = error_get_last();
24322 $message = 'Could not delete '.$path.': ' . @$error['message'];
24323 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
24324 $message .= "\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed";
24325 }
24326
24327 throw new \RuntimeException($message);
24328 }
24329 }
24330
24331 return true;
24332 }
24333
24334
24335
24336
24337
24338
24339
24340
24341
24342 public function rmdir($path)
24343 {
24344 if (!@rmdir($path)) {
24345
24346  if (!defined('PHP_WINDOWS_VERSION_BUILD') || (usleep(350000) && !@rmdir($path))) {
24347 $error = error_get_last();
24348 $message = 'Could not delete '.$path.': ' . @$error['message'];
24349 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
24350 $message .= "\nThis can be due to an antivirus or the Windows Search Indexer locking the file while they are analyzed";
24351 }
24352
24353 throw new \RuntimeException($message);
24354 }
24355 }
24356
24357 return true;
24358 }
24359
24360
24361
24362
24363
24364
24365
24366
24367
24368
24369 public function copyThenRemove($source, $target)
24370 {
24371 if (!is_dir($source)) {
24372 copy($source, $target);
24373 $this->unlink($source);
24374
24375 return;
24376 }
24377
24378 $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS);
24379 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::SELF_FIRST);
24380 $this->ensureDirectoryExists($target);
24381
24382 foreach ($ri as $file) {
24383 $targetPath = $target . DIRECTORY_SEPARATOR . $ri->getSubPathName();
24384 if ($file->isDir()) {
24385 $this->ensureDirectoryExists($targetPath);
24386 } else {
24387 copy($file->getPathname(), $targetPath);
24388 }
24389 }
24390
24391 $this->removeDirectoryPhp($source);
24392 }
24393
24394 public function rename($source, $target)
24395 {
24396 if (true === @rename($source, $target)) {
24397 return;
24398 }
24399
24400 if (!function_exists('proc_open')) {
24401 return $this->copyThenRemove($source, $target);
24402 }
24403
24404 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
24405
24406  $command = sprintf('xcopy %s %s /E /I /Q', ProcessExecutor::escape($source), ProcessExecutor::escape($target));
24407 $result = $this->processExecutor->execute($command, $output);
24408
24409
24410  clearstatcache();
24411
24412 if (0 === $result) {
24413 $this->remove($source);
24414
24415 return;
24416 }
24417 } else {
24418
24419  
24420  $command = sprintf('mv %s %s', ProcessExecutor::escape($source), ProcessExecutor::escape($target));
24421 $result = $this->processExecutor->execute($command, $output);
24422
24423
24424  clearstatcache();
24425
24426 if (0 === $result) {
24427 return;
24428 }
24429 }
24430
24431 return $this->copyThenRemove($source, $target);
24432 }
24433
24434
24435
24436
24437
24438
24439
24440
24441
24442
24443 public function findShortestPath($from, $to, $directories = false)
24444 {
24445 if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
24446 throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
24447 }
24448
24449 $from = lcfirst($this->normalizePath($from));
24450 $to = lcfirst($this->normalizePath($to));
24451
24452 if ($directories) {
24453 $from .= '/dummy_file';
24454 }
24455
24456 if (dirname($from) === dirname($to)) {
24457 return './'.basename($to);
24458 }
24459
24460 $commonPath = $to;
24461 while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath)) {
24462 $commonPath = strtr(dirname($commonPath), '\\', '/');
24463 }
24464
24465 if (0 !== strpos($from, $commonPath) || '/' === $commonPath) {
24466 return $to;
24467 }
24468
24469 $commonPath = rtrim($commonPath, '/') . '/';
24470 $sourcePathDepth = substr_count(substr($from, strlen($commonPath)), '/');
24471 $commonPathCode = str_repeat('../', $sourcePathDepth);
24472
24473 return ($commonPathCode . substr($to, strlen($commonPath))) ?: './';
24474 }
24475
24476
24477
24478
24479
24480
24481
24482
24483
24484
24485 public function findShortestPathCode($from, $to, $directories = false)
24486 {
24487 if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) {
24488 throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to));
24489 }
24490
24491 $from = lcfirst($this->normalizePath($from));
24492 $to = lcfirst($this->normalizePath($to));
24493
24494 if ($from === $to) {
24495 return $directories ? '__DIR__' : '__FILE__';
24496 }
24497
24498 $commonPath = $to;
24499 while (strpos($from.'/', $commonPath.'/') !== 0 && '/' !== $commonPath && !preg_match('{^[a-z]:/?$}i', $commonPath) && '.' !== $commonPath) {
24500 $commonPath = strtr(dirname($commonPath), '\\', '/');
24501 }
24502
24503 if (0 !== strpos($from, $commonPath) || '/' === $commonPath || '.' === $commonPath) {
24504 return var_export($to, true);
24505 }
24506
24507 $commonPath = rtrim($commonPath, '/') . '/';
24508 if (strpos($to, $from.'/') === 0) {
24509 return '__DIR__ . '.var_export(substr($to, strlen($from)), true);
24510 }
24511 $sourcePathDepth = substr_count(substr($from, strlen($commonPath)), '/') + $directories;
24512 $commonPathCode = str_repeat('dirname(', $sourcePathDepth).'__DIR__'.str_repeat(')', $sourcePathDepth);
24513 $relTarget = substr($to, strlen($commonPath));
24514
24515 return $commonPathCode . (strlen($relTarget) ? '.' . var_export('/' . $relTarget, true) : '');
24516 }
24517
24518
24519
24520
24521
24522
24523
24524 public function isAbsolutePath($path)
24525 {
24526 return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':';
24527 }
24528
24529
24530
24531
24532
24533
24534
24535
24536
24537 public function size($path)
24538 {
24539 if (!file_exists($path)) {
24540 throw new \RuntimeException("$path does not exist.");
24541 }
24542 if (is_dir($path)) {
24543 return $this->directorySize($path);
24544 }
24545
24546 return filesize($path);
24547 }
24548
24549
24550
24551
24552
24553
24554
24555
24556 public function normalizePath($path)
24557 {
24558 $parts = array();
24559 $path = strtr($path, '\\', '/');
24560 $prefix = '';
24561 $absolute = false;
24562
24563 if (preg_match('{^([0-9a-z]+:(?://(?:[a-z]:)?)?)}i', $path, $match)) {
24564 $prefix = $match[1];
24565 $path = substr($path, strlen($prefix));
24566 }
24567
24568 if (substr($path, 0, 1) === '/') {
24569 $absolute = true;
24570 $path = substr($path, 1);
24571 }
24572
24573 $up = false;
24574 foreach (explode('/', $path) as $chunk) {
24575 if ('..' === $chunk && ($absolute || $up)) {
24576 array_pop($parts);
24577 $up = !(empty($parts) || '..' === end($parts));
24578 } elseif ('.' !== $chunk && '' !== $chunk) {
24579 $parts[] = $chunk;
24580 $up = '..' !== $chunk;
24581 }
24582 }
24583
24584 return $prefix.($absolute ? '/' : '').implode('/', $parts);
24585 }
24586
24587
24588
24589
24590
24591
24592
24593 public static function isLocalPath($path)
24594 {
24595 return (bool) preg_match('{^(file://|/|[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path);
24596 }
24597
24598 public static function getPlatformPath($path)
24599 {
24600 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
24601 $path = preg_replace('{^(?:file:///([a-z])/)}i', 'file://$1:/', $path);
24602 }
24603
24604 return preg_replace('{^file://}i', '', $path);
24605 }
24606
24607 protected function directorySize($directory)
24608 {
24609 $it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);
24610 $ri = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
24611
24612 $size = 0;
24613 foreach ($ri as $file) {
24614 if ($file->isFile()) {
24615 $size += $file->getSize();
24616 }
24617 }
24618
24619 return $size;
24620 }
24621
24622 protected function getProcess()
24623 {
24624 return new ProcessExecutor;
24625 }
24626
24627
24628
24629
24630
24631
24632
24633
24634
24635
24636 private function unlinkImplementation($path)
24637 {
24638 if (defined('PHP_WINDOWS_VERSION_BUILD') && is_dir($path) && is_link($path)) {
24639 return rmdir($path);
24640 }
24641
24642 return unlink($path);
24643 }
24644
24645 private function isSymlinkedDirectory($directory)
24646 {
24647 if (!is_dir($directory)) {
24648 return false;
24649 }
24650
24651 $resolved = $this->resolveSymlinkedDirectorySymlink($directory);
24652
24653 return is_link($resolved);
24654 }
24655
24656
24657
24658
24659
24660
24661 private function unlinkSymlinkedDirectory($directory)
24662 {
24663 $resolved = $this->resolveSymlinkedDirectorySymlink($directory);
24664
24665 return $this->unlink($resolved);
24666 }
24667
24668
24669
24670
24671
24672
24673
24674
24675 private function resolveSymlinkedDirectorySymlink($pathname)
24676 {
24677 if (!is_dir($pathname)) {
24678 return $pathname;
24679 }
24680
24681 $resolved = rtrim($pathname, '/');
24682
24683 if (!strlen($resolved)) {
24684 return $pathname;
24685 }
24686
24687 return $resolved;
24688 }
24689 }
24690 <?php
24691
24692
24693
24694
24695
24696
24697
24698
24699
24700
24701
24702 namespace Composer\Util;
24703
24704 use Composer\IO\IOInterface;
24705 use Composer\Config;
24706 use Composer\Downloader\TransportException;
24707 use Composer\Json\JsonFile;
24708
24709
24710
24711
24712 class GitHub
24713 {
24714 protected $io;
24715 protected $config;
24716 protected $process;
24717 protected $remoteFilesystem;
24718
24719
24720
24721
24722
24723
24724
24725
24726
24727 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null)
24728 {
24729 $this->io = $io;
24730 $this->config = $config;
24731 $this->process = $process ?: new ProcessExecutor;
24732 $this->remoteFilesystem = $remoteFilesystem ?: new RemoteFilesystem($io, $config);
24733 }
24734
24735
24736
24737
24738
24739
24740
24741 public function authorizeOAuth($originUrl)
24742 {
24743 if (!in_array($originUrl, $this->config->get('github-domains'))) {
24744 return false;
24745 }
24746
24747
24748  if (0 === $this->process->execute('git config github.accesstoken', $output)) {
24749 $this->io->setAuthentication($originUrl, trim($output), 'x-oauth-basic');
24750
24751 return true;
24752 }
24753
24754 return false;
24755 }
24756
24757
24758
24759
24760
24761
24762
24763
24764
24765
24766 public function authorizeOAuthInteractively($originUrl, $message = null)
24767 {
24768 $attemptCounter = 0;
24769
24770 $apiUrl = ('github.com' === $originUrl) ? 'api.github.com' : $originUrl . '/api/v3';
24771
24772 if ($message) {
24773 $this->io->write($message);
24774 }
24775 $this->io->write('The credentials will be swapped for an OAuth token stored in '.$this->config->getAuthConfigSource()->getName().', your password will not be stored');
24776 $this->io->write('To revoke access to this token you can visit https://github.com/settings/applications');
24777 while ($attemptCounter++ < 5) {
24778 try {
24779 if (empty($otp) || !$this->io->hasAuthentication($originUrl)) {
24780 $username = $this->io->ask('Username: ');
24781 $password = $this->io->askAndHideAnswer('Password: ');
24782 $otp = null;
24783
24784 $this->io->setAuthentication($originUrl, $username, $password);
24785 }
24786
24787
24788  $appName = 'Composer';
24789 if ($this->config->get('github-expose-hostname') === true && 0 === $this->process->execute('hostname', $output)) {
24790 $appName .= ' on ' . trim($output);
24791 } else {
24792 $appName .= ' [' . date('YmdHis') . ']';
24793 }
24794
24795 $headers = array();
24796 if ($otp) {
24797 $headers = array('X-GitHub-OTP: ' . $otp);
24798 }
24799
24800
24801  $contents = null;
24802 $auths = JsonFile::parseJson($this->remoteFilesystem->getContents($originUrl, 'https://'. $apiUrl . '/authorizations', false, array(
24803 'retry-auth-failure' => false,
24804 'http' => array(
24805 'header' => $headers
24806 )
24807 )));
24808 foreach ($auths as $auth) {
24809 if (
24810 isset($auth['app']['name'])
24811 && 0 === strpos($auth['app']['name'], $appName)
24812 && $auth['app']['url'] === 'https://getcomposer.org/'
24813 ) {
24814 $this->io->write('An existing OAuth token for Composer is present and will be reused');
24815
24816 $contents['token'] = $auth['token'];
24817 break;
24818 }
24819 }
24820
24821
24822  if (empty($contents['token'])) {
24823 $headers[] = 'Content-Type: application/json';
24824
24825 $contents = JsonFile::parseJson($this->remoteFilesystem->getContents($originUrl, 'https://'. $apiUrl . '/authorizations', false, array(
24826 'retry-auth-failure' => false,
24827 'http' => array(
24828 'method' => 'POST',
24829 'follow_location' => false,
24830 'header' => $headers,
24831 'content' => json_encode(array(
24832 'scopes' => array('repo'),
24833 'note' => $appName,
24834 'note_url' => 'https://getcomposer.org/',
24835 )),
24836 )
24837 )));
24838 $this->io->write('Token successfully created');
24839 }
24840 } catch (TransportException $e) {
24841 if (in_array($e->getCode(), array(403, 401))) {
24842
24843  if ($this->io->hasAuthentication($originUrl)) {
24844 $headerNames = array_map(function ($header) {
24845 return strtolower(strstr($header, ':', true));
24846 }, $e->getHeaders());
24847
24848 if ($key = array_search('x-github-otp', $headerNames)) {
24849 $headers = $e->getHeaders();
24850 list($required, $method) = array_map('trim', explode(';', substr(strstr($headers[$key], ':'), 1)));
24851
24852 if ('required' === $required) {
24853 $this->io->write('Two-factor Authentication');
24854
24855 if ('app' === $method) {
24856 $this->io->write('Open the two-factor authentication app on your device to view your authentication code and verify your identity.');
24857 }
24858
24859 if ('sms' === $method) {
24860 $this->io->write('You have been sent an SMS message with an authentication code to verify your identity.');
24861 }
24862
24863 $otp = $this->io->ask('Authentication Code: ');
24864
24865 continue;
24866 }
24867 }
24868 }
24869
24870 $this->io->write('Invalid credentials.');
24871 continue;
24872 }
24873
24874 throw $e;
24875 }
24876
24877 $this->io->setAuthentication($originUrl, $contents['token'], 'x-oauth-basic');
24878
24879
24880  $this->config->getConfigSource()->removeConfigSetting('github-oauth.'.$originUrl);
24881 $this->config->getAuthConfigSource()->addConfigSetting('github-oauth.'.$originUrl, $contents['token']);
24882
24883 return true;
24884 }
24885
24886 throw new \RuntimeException("Invalid GitHub credentials 5 times in a row, aborting.");
24887 }
24888 }
24889 <?php
24890
24891
24892
24893
24894
24895
24896
24897
24898
24899
24900
24901 namespace Composer\Util;
24902
24903
24904
24905
24906
24907
24908 class ComposerMirror
24909 {
24910 public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type)
24911 {
24912 if ($reference) {
24913 $reference = preg_match('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference);
24914 }
24915 $version = strpos($version, '/') === false ? $version : md5($version);
24916
24917 return str_replace(
24918 array('%package%', '%version%', '%reference%', '%type%'),
24919 array($packageName, $version, $reference, $type),
24920 $mirrorUrl
24921 );
24922 }
24923
24924 public static function processGitUrl($mirrorUrl, $packageName, $url, $type)
24925 {
24926 if (preg_match('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) {
24927 $url = 'gh-'.$match[1].'/'.$match[2];
24928 } elseif (preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)(?:\.git)?/?$#', $url, $match)) {
24929 $url = 'bb-'.$match[1].'/'.$match[2];
24930 } else {
24931 $url = preg_replace('{[^a-z0-9_.-]}i', '-', trim($url, '/'));
24932 }
24933
24934 return str_replace(
24935 array('%package%', '%normalizedUrl%', '%type%'),
24936 array($packageName, $url, $type),
24937 $mirrorUrl
24938 );
24939 }
24940
24941 public static function processHgUrl($mirrorUrl, $packageName, $url, $type)
24942 {
24943 return self::processGitUrl($mirrorUrl, $packageName, $url, $type);
24944 }
24945 }
24946 <?php
24947
24948
24949
24950
24951
24952
24953
24954
24955
24956
24957
24958 namespace Composer\Util;
24959
24960 use Composer\IO\IOInterface;
24961 use Symfony\Component\Process\Process;
24962
24963
24964
24965
24966 class Perforce
24967 {
24968 protected $path;
24969 protected $p4Depot;
24970 protected $p4Client;
24971 protected $p4User;
24972 protected $p4Password;
24973 protected $p4Port;
24974 protected $p4Stream;
24975 protected $p4ClientSpec;
24976 protected $p4DepotType;
24977 protected $p4Branch;
24978 protected $process;
24979 protected $uniquePerforceClientName;
24980 protected $windowsFlag;
24981 protected $commandResult;
24982
24983 protected $io;
24984
24985 protected $filesystem;
24986
24987 public function __construct($repoConfig, $port, $path, ProcessExecutor $process, $isWindows, IOInterface $io)
24988 {
24989 $this->windowsFlag = $isWindows;
24990 $this->p4Port = $port;
24991 $this->initializePath($path);
24992 $this->process = $process;
24993 $this->initialize($repoConfig);
24994 $this->io = $io;
24995 }
24996
24997 public static function create($repoConfig, $port, $path, ProcessExecutor $process, IOInterface $io)
24998 {
24999 $isWindows = defined('PHP_WINDOWS_VERSION_BUILD');
25000 $perforce = new Perforce($repoConfig, $port, $path, $process, $isWindows, $io);
25001
25002 return $perforce;
25003 }
25004
25005 public static function checkServerExists($url, ProcessExecutor $processExecutor)
25006 {
25007 $output = null;
25008
25009 return 0 === $processExecutor->execute('p4 -p ' . $url . ' info -s', $output);
25010 }
25011
25012 public function initialize($repoConfig)
25013 {
25014 $this->uniquePerforceClientName = $this->generateUniquePerforceClientName();
25015 if (null == $repoConfig) {
25016 return;
25017 }
25018 if (isset($repoConfig['unique_perforce_client_name'])) {
25019 $this->uniquePerforceClientName = $repoConfig['unique_perforce_client_name'];
25020 }
25021
25022 if (isset($repoConfig['depot'])) {
25023 $this->p4Depot = $repoConfig['depot'];
25024 }
25025 if (isset($repoConfig['branch'])) {
25026 $this->p4Branch = $repoConfig['branch'];
25027 }
25028 if (isset($repoConfig['p4user'])) {
25029 $this->p4User = $repoConfig['p4user'];
25030 } else {
25031 $this->p4User = $this->getP4variable('P4USER');
25032 }
25033 if (isset($repoConfig['p4password'])) {
25034 $this->p4Password = $repoConfig['p4password'];
25035 }
25036 }
25037
25038 public function initializeDepotAndBranch($depot, $branch)
25039 {
25040 if (isset($depot)) {
25041 $this->p4Depot = $depot;
25042 }
25043 if (isset($branch)) {
25044 $this->p4Branch = $branch;
25045 }
25046 }
25047
25048 public function generateUniquePerforceClientName()
25049 {
25050 return gethostname() . "_" . time();
25051 }
25052
25053 public function cleanupClientSpec()
25054 {
25055 $client = $this->getClient();
25056 $task = 'client -d ' . $client;
25057 $useP4Client = false;
25058 $command = $this->generateP4Command($task, $useP4Client);
25059 $this->executeCommand($command);
25060 $clientSpec = $this->getP4ClientSpec();
25061 $fileSystem = $this->getFilesystem();
25062 $fileSystem->remove($clientSpec);
25063 }
25064
25065 protected function executeCommand($command)
25066 {
25067 $this->commandResult = "";
25068 $exit_code = $this->process->execute($command, $this->commandResult);
25069
25070 return $exit_code;
25071 }
25072
25073 public function getClient()
25074 {
25075 if (!isset($this->p4Client)) {
25076 $cleanStreamName = str_replace('@', '', str_replace('/', '_', str_replace('//', '', $this->getStream())));
25077 $this->p4Client = 'composer_perforce_' . $this->uniquePerforceClientName . '_' . $cleanStreamName;
25078 }
25079
25080 return $this->p4Client;
25081 }
25082
25083 protected function getPath()
25084 {
25085 return $this->path;
25086 }
25087
25088 public function initializePath($path)
25089 {
25090 $this->path = $path;
25091 $fs = $this->getFilesystem();
25092 $fs->ensureDirectoryExists($path);
25093 }
25094
25095 protected function getPort()
25096 {
25097 return $this->p4Port;
25098 }
25099
25100 public function setStream($stream)
25101 {
25102 $this->p4Stream = $stream;
25103 $index = strrpos($stream, '/');
25104
25105  if ($index > 2) {
25106 $this->p4DepotType = 'stream';
25107 }
25108 }
25109
25110 public function isStream()
25111 {
25112 return (strcmp($this->p4DepotType, 'stream') === 0);
25113 }
25114
25115 public function getStream()
25116 {
25117 if (!isset($this->p4Stream)) {
25118 if ($this->isStream()) {
25119 $this->p4Stream = '//' . $this->p4Depot . '/' . $this->p4Branch;
25120 } else {
25121 $this->p4Stream = '//' . $this->p4Depot;
25122 }
25123 }
25124
25125 return $this->p4Stream;
25126 }
25127
25128 public function getStreamWithoutLabel($stream)
25129 {
25130 $index = strpos($stream, '@');
25131 if ($index === false) {
25132 return $stream;
25133 }
25134
25135 return substr($stream, 0, $index);
25136 }
25137
25138 public function getP4ClientSpec()
25139 {
25140 $p4clientSpec = $this->path . '/' . $this->getClient() . '.p4.spec';
25141
25142 return $p4clientSpec;
25143 }
25144
25145 public function getUser()
25146 {
25147 return $this->p4User;
25148 }
25149
25150 public function setUser($user)
25151 {
25152 $this->p4User = $user;
25153 }
25154
25155 public function queryP4User()
25156 {
25157 $this->getUser();
25158 if (strlen($this->p4User) > 0) {
25159 return;
25160 }
25161 $this->p4User = $this->getP4variable('P4USER');
25162 if (strlen($this->p4User) > 0) {
25163 return;
25164 }
25165 $this->p4User = $this->io->ask('Enter P4 User:');
25166 if ($this->windowsFlag) {
25167 $command = 'p4 set P4USER=' . $this->p4User;
25168 } else {
25169 $command = 'export P4USER=' . $this->p4User;
25170 }
25171 $this->executeCommand($command);
25172 }
25173
25174 protected function getP4variable($name)
25175 {
25176 if ($this->windowsFlag) {
25177 $command = 'p4 set';
25178 $this->executeCommand($command);
25179 $result = trim($this->commandResult);
25180 $resArray = explode(PHP_EOL, $result);
25181 foreach ($resArray as $line) {
25182 $fields = explode('=', $line);
25183 if (strcmp($name, $fields[0]) == 0) {
25184 $index = strpos($fields[1], ' ');
25185 if ($index === false) {
25186 $value = $fields[1];
25187 } else {
25188 $value = substr($fields[1], 0, $index);
25189 }
25190 $value = trim($value);
25191
25192 return $value;
25193 }
25194 }
25195 } else {
25196 $command = 'echo $' . $name;
25197 $this->executeCommand($command);
25198 $result = trim($this->commandResult);
25199
25200 return $result;
25201 }
25202 }
25203
25204 public function queryP4Password()
25205 {
25206 if (isset($this->p4Password)) {
25207 return $this->p4Password;
25208 }
25209 $password = $this->getP4variable('P4PASSWD');
25210 if (strlen($password) <= 0) {
25211 $password = $this->io->askAndHideAnswer('Enter password for Perforce user ' . $this->getUser() . ': ');
25212 }
25213 $this->p4Password = $password;
25214
25215 return $password;
25216 }
25217
25218 public function generateP4Command($command, $useClient = true)
25219 {
25220 $p4Command = 'p4 ';
25221 $p4Command = $p4Command . '-u ' . $this->getUser() . ' ';
25222 if ($useClient) {
25223 $p4Command = $p4Command . '-c ' . $this->getClient() . ' ';
25224 }
25225 $p4Command = $p4Command . '-p ' . $this->getPort() . ' ';
25226 $p4Command = $p4Command . $command;
25227
25228 return $p4Command;
25229 }
25230
25231 public function isLoggedIn()
25232 {
25233 $command = $this->generateP4Command('login -s', false);
25234 $exitCode = $this->executeCommand($command);
25235 if ($exitCode) {
25236 $errorOutput = $this->process->getErrorOutput();
25237 $index = strpos($errorOutput, $this->getUser());
25238 if ($index === false) {
25239 $index = strpos($errorOutput, 'p4');
25240 if ($index === false) {
25241 return false;
25242 }
25243 throw new \Exception('p4 command not found in path: ' . $errorOutput);
25244 }
25245 throw new \Exception('Invalid user name: ' . $this->getUser() );
25246 }
25247
25248 return true;
25249 }
25250
25251 public function connectClient()
25252 {
25253 $p4CreateClientCommand = $this->generateP4Command('client -i < ' . str_replace( " ", "\\ ", $this->getP4ClientSpec() ));
25254 $this->executeCommand($p4CreateClientCommand);
25255 }
25256
25257 public function syncCodeBase($sourceReference)
25258 {
25259 $prevDir = getcwd();
25260 chdir($this->path);
25261 $p4SyncCommand = $this->generateP4Command('sync -f ');
25262 if (null != $sourceReference) {
25263 $p4SyncCommand = $p4SyncCommand . '@' . $sourceReference;
25264 }
25265 $this->executeCommand($p4SyncCommand);
25266 chdir($prevDir);
25267 }
25268
25269 public function writeClientSpecToFile($spec)
25270 {
25271 fwrite($spec, 'Client: ' . $this->getClient() . PHP_EOL . PHP_EOL);
25272 fwrite($spec, 'Update: ' . date('Y/m/d H:i:s') . PHP_EOL . PHP_EOL);
25273 fwrite($spec, 'Access: ' . date('Y/m/d H:i:s') . PHP_EOL);
25274 fwrite($spec, 'Owner:  ' . $this->getUser() . PHP_EOL . PHP_EOL);
25275 fwrite($spec, 'Description:' . PHP_EOL);
25276 fwrite($spec, '  Created by ' . $this->getUser() . ' from composer.' . PHP_EOL . PHP_EOL);
25277 fwrite($spec, 'Root: ' . $this->getPath() . PHP_EOL . PHP_EOL);
25278 fwrite($spec, 'Options:  noallwrite noclobber nocompress unlocked modtime rmdir' . PHP_EOL . PHP_EOL);
25279 fwrite($spec, 'SubmitOptions:  revertunchanged' . PHP_EOL . PHP_EOL);
25280 fwrite($spec, 'LineEnd:  local' . PHP_EOL . PHP_EOL);
25281 if ($this->isStream()) {
25282 fwrite($spec, 'Stream:' . PHP_EOL);
25283 fwrite($spec, '  ' . $this->getStreamWithoutLabel($this->p4Stream) . PHP_EOL);
25284 } else {
25285 fwrite(
25286 $spec,
25287 'View:  ' . $this->getStream() . '/...  //' . $this->getClient() . '/... ' . PHP_EOL
25288 );
25289 }
25290 }
25291
25292 public function writeP4ClientSpec()
25293 {
25294 $clientSpec = $this->getP4ClientSpec();
25295 $spec = fopen($clientSpec, 'w');
25296 try {
25297 $this->writeClientSpecToFile($spec);
25298 } catch (\Exception $e) {
25299 fclose($spec);
25300 throw $e;
25301 }
25302 fclose($spec);
25303 }
25304
25305 protected function read($pipe, $name)
25306 {
25307 if (feof($pipe)) {
25308 return;
25309 }
25310 $line = fgets($pipe);
25311 while ($line != false) {
25312 $line = fgets($pipe);
25313 }
25314
25315 return;
25316 }
25317
25318 public function windowsLogin($password)
25319 {
25320 $command = $this->generateP4Command(' login -a');
25321 $process = new Process($command, null, null, $password);
25322
25323 return $process->run();
25324 }
25325
25326 public function p4Login()
25327 {
25328 $this->queryP4User();
25329 if (!$this->isLoggedIn()) {
25330 $password = $this->queryP4Password();
25331 if ($this->windowsFlag) {
25332 $this->windowsLogin($password);
25333 } else {
25334 $command = 'echo ' . $password . ' | ' . $this->generateP4Command(' login -a', false);
25335 $exitCode = $this->executeCommand($command);
25336 $result = trim($this->commandResult);
25337 if ($exitCode) {
25338 throw new \Exception("Error logging in:" . $this->process->getErrorOutput());
25339 }
25340 }
25341 }
25342 }
25343
25344 public function getComposerInformation($identifier)
25345 {
25346 $index = strpos($identifier, '@');
25347 if ($index === false) {
25348 $composerJson = $identifier. '/composer.json';
25349
25350 return $this->getComposerInformationFromPath($composerJson);
25351 }
25352
25353 return $this->getComposerInformationFromLabel($identifier, $index);
25354 }
25355
25356 public function getComposerInformationFromPath($composerJson)
25357 {
25358 $command = $this->generateP4Command(' print ' . $composerJson);
25359 $this->executeCommand($command);
25360 $result = $this->commandResult;
25361 $index = strpos($result, '{');
25362 if ($index === false) {
25363 return '';
25364 }
25365 if ($index >= 0) {
25366 $rawData = substr($result, $index);
25367 $composer_info = json_decode($rawData, true);
25368
25369 return $composer_info;
25370 }
25371
25372 return '';
25373 }
25374
25375 public function getComposerInformationFromLabel($identifier, $index)
25376 {
25377 $composerJsonPath = substr($identifier, 0, $index) . '/composer.json' . substr($identifier, $index);
25378 $command = $this->generateP4Command(' files ' . $composerJsonPath, false);
25379 $this->executeCommand($command);
25380 $result = $this->commandResult;
25381 $index2 = strpos($result, 'no such file(s).');
25382 if ($index2 === false) {
25383 $index3 = strpos($result, 'change');
25384 if (!($index3 === false)) {
25385 $phrase = trim(substr($result, $index3));
25386 $fields = explode(' ', $phrase);
25387 $id = $fields[1];
25388 $composerJson = substr($identifier, 0, $index) . '/composer.json@' . $id;
25389
25390 return $this->getComposerInformationFromPath($composerJson);
25391 }
25392 }
25393
25394 return "";
25395 }
25396
25397 public function getBranches()
25398 {
25399 $possibleBranches = array();
25400 if (!$this->isStream()) {
25401 $possibleBranches[$this->p4Branch] = $this->getStream();
25402 } else {
25403 $command = $this->generateP4Command('streams //' . $this->p4Depot . '/...');
25404 $this->executeCommand($command);
25405 $result = $this->commandResult;
25406 $resArray = explode(PHP_EOL, $result);
25407 foreach ($resArray as $line) {
25408 $resBits = explode(' ', $line);
25409 if (count($resBits) > 4) {
25410 $branch = preg_replace('/[^A-Za-z0-9 ]/', '', $resBits[4]);
25411 $possibleBranches[$branch] = $resBits[1];
25412 }
25413 }
25414 }
25415 $command = $this->generateP4Command('changes '. $this->getStream() . '/...', false);
25416 $this->executeCommand($command);
25417 $result = $this->commandResult;
25418 $resArray = explode(PHP_EOL, $result);
25419 $lastCommit = $resArray[0];
25420 $lastCommitArr = explode(' ', $lastCommit);
25421 $lastCommitNum = $lastCommitArr[1];
25422
25423 $branches = array('master' => $possibleBranches[$this->p4Branch] . '@'. $lastCommitNum);
25424
25425 return $branches;
25426 }
25427
25428 public function getTags()
25429 {
25430 $command = $this->generateP4Command('labels');
25431 $this->executeCommand($command);
25432 $result = $this->commandResult;
25433 $resArray = explode(PHP_EOL, $result);
25434 $tags = array();
25435 foreach ($resArray as $line) {
25436 $index = strpos($line, 'Label');
25437 if (!($index === false)) {
25438 $fields = explode(' ', $line);
25439 $tags[$fields[1]] = $this->getStream() . '@' . $fields[1];
25440 }
25441 }
25442
25443 return $tags;
25444 }
25445
25446 public function checkStream()
25447 {
25448 $command = $this->generateP4Command('depots', false);
25449 $this->executeCommand($command);
25450 $result = $this->commandResult;
25451 $resArray = explode(PHP_EOL, $result);
25452 foreach ($resArray as $line) {
25453 $index = strpos($line, 'Depot');
25454 if (!($index === false)) {
25455 $fields = explode(' ', $line);
25456 if (strcmp($this->p4Depot, $fields[1]) === 0) {
25457 $this->p4DepotType = $fields[3];
25458
25459 return $this->isStream();
25460 }
25461 }
25462 }
25463
25464 return false;
25465 }
25466
25467 protected function getChangeList($reference)
25468 {
25469 $index = strpos($reference, '@');
25470 if ($index === false) {
25471 return;
25472 }
25473 $label = substr($reference, $index);
25474 $command = $this->generateP4Command(' changes -m1 ' . $label);
25475 $this->executeCommand($command);
25476 $changes = $this->commandResult;
25477 if (strpos($changes, 'Change') !== 0) {
25478 return;
25479 }
25480 $fields = explode(' ', $changes);
25481 $changeList = $fields[1];
25482
25483 return $changeList;
25484 }
25485
25486 public function getCommitLogs($fromReference, $toReference)
25487 {
25488 $fromChangeList = $this->getChangeList($fromReference);
25489 if ($fromChangeList == null) {
25490 return;
25491 }
25492 $toChangeList = $this->getChangeList($toReference);
25493 if ($toChangeList == null) {
25494 return;
25495 }
25496 $index = strpos($fromReference, '@');
25497 $main = substr($fromReference, 0, $index) . '/...';
25498 $command = $this->generateP4Command('filelog ' . $main . '@' . $fromChangeList. ',' . $toChangeList);
25499 $this->executeCommand($command);
25500 $result = $this->commandResult;
25501
25502 return $result;
25503 }
25504
25505 public function getFilesystem()
25506 {
25507 if (empty($this->filesystem)) {
25508 $this->filesystem = new Filesystem($this->process);
25509 }
25510
25511 return $this->filesystem;
25512 }
25513
25514 public function setFilesystem(Filesystem $fs)
25515 {
25516 $this->filesystem = $fs;
25517 }
25518 }
25519 <?php
25520
25521
25522
25523
25524
25525
25526
25527
25528
25529
25530
25531 namespace Composer\Util;
25532
25533 use Symfony\Component\Process\Process;
25534 use Symfony\Component\Process\ProcessUtils;
25535 use Composer\IO\IOInterface;
25536
25537
25538
25539
25540 class ProcessExecutor
25541 {
25542 protected static $timeout = 300;
25543
25544 protected $captureOutput;
25545 protected $errorOutput;
25546 protected $io;
25547
25548 public function __construct(IOInterface $io = null)
25549 {
25550 $this->io = $io;
25551 }
25552
25553
25554
25555
25556
25557
25558
25559
25560
25561
25562 public function execute($command, &$output = null, $cwd = null)
25563 {
25564 if ($this->io && $this->io->isDebug()) {
25565 $safeCommand = preg_replace('{(://[^:/\s]+:)[^@\s/]+}i', '$1****', $command);
25566 $this->io->write('Executing command ('.($cwd ?: 'CWD').'): '.$safeCommand);
25567 }
25568
25569
25570  
25571  if (null === $cwd && defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($command, 'git') && getcwd()) {
25572 $cwd = realpath(getcwd());
25573 }
25574
25575 $this->captureOutput = count(func_get_args()) > 1;
25576 $this->errorOutput = null;
25577 $process = new Process($command, $cwd, null, null, static::getTimeout());
25578
25579 $callback = is_callable($output) ? $output : array($this, 'outputHandler');
25580 $process->run($callback);
25581
25582 if ($this->captureOutput && !is_callable($output)) {
25583 $output = $process->getOutput();
25584 }
25585
25586 $this->errorOutput = $process->getErrorOutput();
25587
25588 return $process->getExitCode();
25589 }
25590
25591 public function splitLines($output)
25592 {
25593 $output = trim($output);
25594
25595 return ((string) $output === '') ? array() : preg_split('{\r?\n}', $output);
25596 }
25597
25598
25599
25600
25601
25602
25603 public function getErrorOutput()
25604 {
25605 return $this->errorOutput;
25606 }
25607
25608 public function outputHandler($type, $buffer)
25609 {
25610 if ($this->captureOutput) {
25611 return;
25612 }
25613
25614 echo $buffer;
25615 }
25616
25617 public static function getTimeout()
25618 {
25619 return static::$timeout;
25620 }
25621
25622 public static function setTimeout($timeout)
25623 {
25624 static::$timeout = $timeout;
25625 }
25626
25627
25628
25629
25630
25631
25632
25633
25634
25635 public static function escape($argument)
25636 {
25637 return ProcessUtils::escapeArgument($argument);
25638 }
25639 }
25640 <?php
25641
25642
25643
25644
25645
25646
25647
25648
25649
25650
25651
25652 namespace Composer\Util;
25653
25654 use Composer\Config;
25655 use Composer\IO\IOInterface;
25656
25657
25658
25659
25660 class Git
25661 {
25662 protected $io;
25663 protected $config;
25664 protected $process;
25665 protected $filesystem;
25666
25667 public function __construct(IOInterface $io, Config $config, ProcessExecutor $process, Filesystem $fs)
25668 {
25669 $this->io = $io;
25670 $this->config = $config;
25671 $this->process = $process;
25672 $this->filesystem = $fs;
25673 }
25674
25675 public function runCommand($commandCallable, $url, $cwd, $initialClone = false)
25676 {
25677 if ($initialClone) {
25678 $origCwd = $cwd;
25679 $cwd = null;
25680 }
25681
25682 if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $url)) {
25683 throw new \InvalidArgumentException('The source URL '.$url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
25684 }
25685
25686 if (!$initialClone) {
25687
25688  $this->process->execute('git remote -v', $output, $cwd);
25689 if (preg_match('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match)) {
25690 $this->io->setAuthentication($match[3], urldecode($match[1]), urldecode($match[2]));
25691 }
25692 }
25693
25694
25695  if (preg_match('{^(?:https?|git)://'.self::getGitHubDomainsRegex($this->config).'/(.*)}', $url, $match)) {
25696 $protocols = $this->config->get('github-protocols');
25697 if (!is_array($protocols)) {
25698 throw new \RuntimeException('Config value "github-protocols" must be an array, got '.gettype($protocols));
25699 }
25700 $messages = array();
25701 foreach ($protocols as $protocol) {
25702 if ('ssh' === $protocol) {
25703 $url = "git@" . $match[1] . ":" . $match[2];
25704 } else {
25705 $url = $protocol ."://" . $match[1] . "/" . $match[2];
25706 }
25707
25708 if (0 === $this->process->execute(call_user_func($commandCallable, $url), $ignoredOutput, $cwd)) {
25709 return;
25710 }
25711 $messages[] = '- ' . $url . "\n" . preg_replace('#^#m', '  ', $this->process->getErrorOutput());
25712 if ($initialClone) {
25713 $this->filesystem->removeDirectory($origCwd);
25714 }
25715 }
25716
25717
25718  $this->throwException('Failed to clone ' . self::sanitizeUrl($url) .' via '.implode(', ', $protocols).' protocols, aborting.' . "\n\n" . implode("\n", $messages), $url);
25719 }
25720
25721 $command = call_user_func($commandCallable, $url);
25722 if (0 !== $this->process->execute($command, $ignoredOutput, $cwd)) {
25723
25724  if (preg_match('{^git@'.self::getGitHubDomainsRegex($this->config).':(.+?)\.git$}i', $url, $match)) {
25725 if (!$this->io->hasAuthentication($match[1])) {
25726 $gitHubUtil = new GitHub($this->io, $this->config, $this->process);
25727 $message = 'Cloning failed using an ssh key for authentication, enter your GitHub credentials to access private repos';
25728
25729 if (!$gitHubUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) {
25730 $gitHubUtil->authorizeOAuthInteractively($match[1], $message);
25731 }
25732 }
25733
25734 if ($this->io->hasAuthentication($match[1])) {
25735 $auth = $this->io->getAuthentication($match[1]);
25736 $url = 'https://'.rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@'.$match[1].'/'.$match[2].'.git';
25737
25738 $command = call_user_func($commandCallable, $url);
25739 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
25740 return;
25741 }
25742 }
25743 } elseif ( 
25744  preg_match('{(https?://)([^/]+)(.*)$}i', $url, $match) &&
25745 strpos($this->process->getErrorOutput(), 'fatal: Authentication failed') !== false
25746 ) {
25747 if (strpos($match[2], '@')) {
25748 list($authParts, $match[2]) = explode('@', $match[2], 2);
25749 }
25750
25751 $storeAuth = false;
25752 if ($this->io->hasAuthentication($match[2])) {
25753 $auth = $this->io->getAuthentication($match[2]);
25754 } elseif ($this->io->isInteractive()) {
25755 $defaultUsername = null;
25756 if (isset($authParts) && $authParts) {
25757 if (false !== strpos($authParts, ':')) {
25758 list($defaultUsername,) = explode(':', $authParts, 2);
25759 } else {
25760 $defaultUsername = $authParts;
25761 }
25762 }
25763
25764 $this->io->write('    Authentication required (<info>'.parse_url($url, PHP_URL_HOST).'</info>):');
25765 $auth = array(
25766 'username' => $this->io->ask('      Username: ', $defaultUsername),
25767 'password' => $this->io->askAndHideAnswer('      Password: '),
25768 );
25769 $storeAuth = $this->config->get('store-auths');
25770 }
25771
25772 if ($auth) {
25773 $url = $match[1].rawurlencode($auth['username']).':'.rawurlencode($auth['password']).'@'.$match[2].$match[3];
25774
25775 $command = call_user_func($commandCallable, $url);
25776 if (0 === $this->process->execute($command, $ignoredOutput, $cwd)) {
25777 $this->io->setAuthentication($match[2], $auth['username'], $auth['password']);
25778 $authHelper = new AuthHelper($this->io, $this->config);
25779 $authHelper->storeAuth($match[2], $storeAuth);
25780
25781 return;
25782 }
25783 }
25784 }
25785
25786 if ($initialClone) {
25787 $this->filesystem->removeDirectory($origCwd);
25788 }
25789 $this->throwException('Failed to execute ' . self::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput(), $url);
25790 }
25791 }
25792
25793 public static function cleanEnv()
25794 {
25795 if (ini_get('safe_mode') && false === strpos(ini_get('safe_mode_allowed_env_vars'), 'GIT_ASKPASS')) {
25796 throw new \RuntimeException('safe_mode is enabled and safe_mode_allowed_env_vars does not contain GIT_ASKPASS, can not set env var. You can disable safe_mode with "-dsafe_mode=0" when running composer');
25797 }
25798
25799
25800  if (getenv('GIT_ASKPASS') !== 'echo') {
25801 putenv('GIT_ASKPASS=echo');
25802 }
25803
25804
25805  if (getenv('GIT_DIR')) {
25806 putenv('GIT_DIR');
25807 }
25808 if (getenv('GIT_WORK_TREE')) {
25809 putenv('GIT_WORK_TREE');
25810 }
25811 }
25812
25813 public static function getGitHubDomainsRegex(Config $config)
25814 {
25815 return '('.implode('|', array_map('preg_quote', $config->get('github-domains'))).')';
25816 }
25817
25818 public static function sanitizeUrl($message)
25819 {
25820 return preg_replace('{://([^@]+?):.+?@}', '://$1:***@', $message);
25821 }
25822
25823 private function throwException($message, $url)
25824 {
25825 if (0 !== $this->process->execute('git --version', $ignoredOutput)) {
25826 throw new \RuntimeException('Failed to clone '.self::sanitizeUrl($url).', git was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput());
25827 }
25828
25829 throw new \RuntimeException($message);
25830 }
25831 }
25832 <?php
25833
25834
25835
25836
25837
25838
25839
25840
25841
25842
25843
25844 namespace Composer\Util;
25845
25846 use Composer\Composer;
25847 use Composer\Config;
25848 use Composer\IO\IOInterface;
25849 use Composer\Downloader\TransportException;
25850
25851
25852
25853
25854
25855
25856 class RemoteFilesystem
25857 {
25858 private $io;
25859 private $config;
25860 private $bytesMax;
25861 private $originUrl;
25862 private $fileUrl;
25863 private $fileName;
25864 private $retry;
25865 private $progress;
25866 private $lastProgress;
25867 private $options;
25868 private $retryAuthFailure;
25869 private $lastHeaders;
25870 private $storeAuth;
25871
25872
25873
25874
25875
25876
25877
25878
25879 public function __construct(IOInterface $io, Config $config = null, array $options = array())
25880 {
25881 $this->io = $io;
25882 $this->config = $config;
25883 $this->options = $options;
25884 }
25885
25886
25887
25888
25889
25890
25891
25892
25893
25894
25895
25896
25897 public function copy($originUrl, $fileUrl, $fileName, $progress = true, $options = array())
25898 {
25899 return $this->get($originUrl, $fileUrl, $options, $fileName, $progress);
25900 }
25901
25902
25903
25904
25905
25906
25907
25908
25909
25910
25911
25912 public function getContents($originUrl, $fileUrl, $progress = true, $options = array())
25913 {
25914 return $this->get($originUrl, $fileUrl, $options, null, $progress);
25915 }
25916
25917
25918
25919
25920
25921
25922 public function getOptions()
25923 {
25924 return $this->options;
25925 }
25926
25927
25928
25929
25930
25931
25932 public function getLastHeaders()
25933 {
25934 return $this->lastHeaders;
25935 }
25936
25937
25938
25939
25940
25941
25942
25943
25944
25945
25946
25947
25948
25949
25950
25951 protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true)
25952 {
25953 if (strpos($originUrl, '.github.com') === (strlen($originUrl) - 11)) {
25954 $originUrl = 'github.com';
25955 }
25956
25957 $this->bytesMax = 0;
25958 $this->originUrl = $originUrl;
25959 $this->fileUrl = $fileUrl;
25960 $this->fileName = $fileName;
25961 $this->progress = $progress;
25962 $this->lastProgress = null;
25963 $this->retryAuthFailure = true;
25964 $this->lastHeaders = array();
25965
25966
25967  if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) {
25968 $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2]));
25969 }
25970
25971 if (isset($additionalOptions['retry-auth-failure'])) {
25972 $this->retryAuthFailure = (bool) $additionalOptions['retry-auth-failure'];
25973
25974 unset($additionalOptions['retry-auth-failure']);
25975 }
25976
25977 $options = $this->getOptionsForUrl($originUrl, $additionalOptions);
25978
25979 if ($this->io->isDebug()) {
25980 $this->io->write((substr($fileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $fileUrl);
25981 }
25982 if (isset($options['github-token'])) {
25983 $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token='.$options['github-token'];
25984 unset($options['github-token']);
25985 }
25986 if (isset($options['http'])) {
25987 $options['http']['ignore_errors'] = true;
25988 }
25989 $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet')));
25990
25991 if ($this->progress) {
25992 $this->io->write("    Downloading: <comment>connection...</comment>", false);
25993 }
25994
25995 $errorMessage = '';
25996 $errorCode = 0;
25997 $result = false;
25998 set_error_handler(function ($code, $msg) use (&$errorMessage) {
25999 if ($errorMessage) {
26000 $errorMessage .= "\n";
26001 }
26002 $errorMessage .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg);
26003 });
26004 try {
26005 $result = file_get_contents($fileUrl, false, $ctx);
26006 } catch (\Exception $e) {
26007 if ($e instanceof TransportException && !empty($http_response_header[0])) {
26008 $e->setHeaders($http_response_header);
26009 }
26010 if ($e instanceof TransportException && $result !== false) {
26011 $e->setResponse($result);
26012 }
26013 $result = false;
26014 }
26015 if ($errorMessage && !ini_get('allow_url_fopen')) {
26016 $errorMessage = 'allow_url_fopen must be enabled in php.ini ('.$errorMessage.')';
26017 }
26018 restore_error_handler();
26019 if (isset($e) && !$this->retry) {
26020 throw $e;
26021 }
26022
26023
26024  if (!empty($http_response_header[0]) && preg_match('{^HTTP/\S+ ([45]\d\d)}i', $http_response_header[0], $match)) {
26025 $errorCode = $match[1];
26026 if (!$this->retry) {
26027 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded ('.$http_response_header[0].')', $errorCode);
26028 $e->setHeaders($http_response_header);
26029 $e->setResponse($result);
26030 throw $e;
26031 }
26032 $result = false;
26033 }
26034
26035
26036  if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') {
26037 $decode = false;
26038 foreach ($http_response_header as $header) {
26039 if (preg_match('{^content-encoding: *gzip *$}i', $header)) {
26040 $decode = true;
26041 continue;
26042 } elseif (preg_match('{^HTTP/}i', $header)) {
26043 $decode = false;
26044 }
26045 }
26046
26047 if ($decode) {
26048 if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
26049 $result = zlib_decode($result);
26050 } else {
26051
26052  $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result));
26053 }
26054
26055 if (!$result) {
26056 throw new TransportException('Failed to decode zlib stream');
26057 }
26058 }
26059 }
26060
26061 if ($this->progress && !$this->retry) {
26062 $this->io->overwrite("    Downloading: <comment>100%</comment>");
26063 }
26064
26065
26066  if (false !== $result && null !== $fileName) {
26067 if ('' === $result) {
26068 throw new TransportException('"'.$this->fileUrl.'" appears broken, and returned an empty 200 response');
26069 }
26070
26071 $errorMessage = '';
26072 set_error_handler(function ($code, $msg) use (&$errorMessage) {
26073 if ($errorMessage) {
26074 $errorMessage .= "\n";
26075 }
26076 $errorMessage .= preg_replace('{^file_put_contents\(.*?\): }', '', $msg);
26077 });
26078 $result = (bool) file_put_contents($fileName, $result);
26079 restore_error_handler();
26080 if (false === $result) {
26081 throw new TransportException('The "'.$this->fileUrl.'" file could not be written to '.$fileName.': '.$errorMessage);
26082 }
26083 }
26084
26085 if ($this->retry) {
26086 $this->retry = false;
26087
26088 $result = $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
26089
26090 $authHelper = new AuthHelper($this->io, $this->config);
26091 $authHelper->storeAuth($this->originUrl, $this->storeAuth);
26092 $this->storeAuth = false;
26093
26094 return $result;
26095 }
26096
26097 if (false === $result) {
26098 $e = new TransportException('The "'.$this->fileUrl.'" file could not be downloaded: '.$errorMessage, $errorCode);
26099 if (!empty($http_response_header[0])) {
26100 $e->setHeaders($http_response_header);
26101 }
26102
26103 throw $e;
26104 }
26105
26106 if (!empty($http_response_header[0])) {
26107 $this->lastHeaders = $http_response_header;
26108 }
26109
26110 return $result;
26111 }
26112
26113
26114
26115
26116
26117
26118
26119
26120
26121
26122
26123
26124 protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
26125 {
26126 switch ($notificationCode) {
26127 case STREAM_NOTIFY_FAILURE:
26128 case STREAM_NOTIFY_AUTH_REQUIRED:
26129 if (401 === $messageCode) {
26130
26131  if (!$this->retryAuthFailure) {
26132 break;
26133 }
26134
26135 $this->promptAuthAndRetry($messageCode);
26136 break;
26137 }
26138 break;
26139
26140 case STREAM_NOTIFY_AUTH_RESULT:
26141 if (403 === $messageCode) {
26142 $this->promptAuthAndRetry($messageCode, $message);
26143 break;
26144 }
26145 break;
26146
26147 case STREAM_NOTIFY_FILE_SIZE_IS:
26148 if ($this->bytesMax < $bytesMax) {
26149 $this->bytesMax = $bytesMax;
26150 }
26151 break;
26152
26153 case STREAM_NOTIFY_PROGRESS:
26154 if ($this->bytesMax > 0 && $this->progress) {
26155 $progression = 0;
26156
26157 if ($this->bytesMax > 0) {
26158 $progression = round($bytesTransferred / $this->bytesMax * 100);
26159 }
26160
26161 if ((0 === $progression % 5) && $progression !== $this->lastProgress) {
26162 $this->lastProgress = $progression;
26163 $this->io->overwrite("    Downloading: <comment>$progression%</comment>", false);
26164 }
26165 }
26166 break;
26167
26168 default:
26169 break;
26170 }
26171 }
26172
26173 protected function promptAuthAndRetry($httpStatus, $reason = null)
26174 {
26175 if ($this->config && in_array($this->originUrl, $this->config->get('github-domains'), true)) {
26176 $message = "\n".'Could not fetch '.$this->fileUrl.', enter your GitHub credentials '.($httpStatus === 404 ? 'to access private repos' : 'to go over the API rate limit');
26177 $gitHubUtil = new GitHub($this->io, $this->config, null, $this);
26178 if (!$gitHubUtil->authorizeOAuth($this->originUrl)
26179 && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($this->originUrl, $message))
26180 ) {
26181 throw new TransportException('Could not authenticate against '.$this->originUrl, 401);
26182 }
26183 } else {
26184
26185  if ($httpStatus === 404) {
26186 return;
26187 }
26188
26189
26190  if (!$this->io->isInteractive()) {
26191 if ($httpStatus === 401) {
26192 $message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console to authenticate";
26193 }
26194 if ($httpStatus === 403) {
26195 $message = "The '" . $this->fileUrl . "' URL could not be accessed: " . $reason;
26196 }
26197
26198 throw new TransportException($message, $httpStatus);
26199 }
26200
26201  if ($this->io->hasAuthentication($this->originUrl)) {
26202 throw new TransportException("Invalid credentials for '" . $this->fileUrl . "', aborting.", $httpStatus);
26203 }
26204
26205 $this->io->overwrite('    Authentication required (<info>'.parse_url($this->fileUrl, PHP_URL_HOST).'</info>):');
26206 $username = $this->io->ask('      Username: ');
26207 $password = $this->io->askAndHideAnswer('      Password: ');
26208 $this->io->setAuthentication($this->originUrl, $username, $password);
26209 $this->storeAuth = $this->config->get('store-auths');
26210 }
26211
26212 $this->retry = true;
26213 throw new TransportException('RETRY');
26214 }
26215
26216 protected function getOptionsForUrl($originUrl, $additionalOptions)
26217 {
26218 if (defined('HHVM_VERSION')) {
26219 $phpVersion = 'HHVM ' . HHVM_VERSION;
26220 } else {
26221 $phpVersion = 'PHP ' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
26222 }
26223
26224 $headers = array(
26225 sprintf(
26226 'User-Agent: Composer/%s (%s; %s; %s)',
26227 Composer::VERSION === '@package_version@' ? 'source' : Composer::VERSION,
26228 php_uname('s'),
26229 php_uname('r'),
26230 $phpVersion
26231 )
26232 );
26233
26234 if (extension_loaded('zlib')) {
26235 $headers[] = 'Accept-Encoding: gzip';
26236 }
26237
26238 $options = array_replace_recursive($this->options, $additionalOptions);
26239
26240 if ($this->io->hasAuthentication($originUrl)) {
26241 $auth = $this->io->getAuthentication($originUrl);
26242 if ('github.com' === $originUrl && 'x-oauth-basic' === $auth['password']) {
26243 $options['github-token'] = $auth['username'];
26244 } else {
26245 $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
26246 $headers[] = 'Authorization: Basic '.$authStr;
26247 }
26248 }
26249
26250 if (isset($options['http']['header']) && !is_array($options['http']['header'])) {
26251 $options['http']['header'] = explode("\r\n", trim($options['http']['header'], "\r\n"));
26252 }
26253 foreach ($headers as $header) {
26254 $options['http']['header'][] = $header;
26255 }
26256
26257 return $options;
26258 }
26259 }
26260 <?php
26261
26262
26263
26264
26265
26266
26267
26268
26269
26270
26271
26272 namespace Composer\Util;
26273
26274
26275
26276
26277
26278
26279
26280 final class StreamContextFactory
26281 {
26282
26283
26284
26285
26286
26287
26288
26289
26290
26291 public static function getContext($url, array $defaultOptions = array(), array $defaultParams = array())
26292 {
26293 $options = array('http' => array(
26294
26295  'follow_location' => 1,
26296 'max_redirects' => 20,
26297 ));
26298
26299
26300  if (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy'])) {
26301
26302  $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']);
26303 }
26304
26305
26306  if (preg_match('{^https://}i', $url) && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) {
26307 $proxy = parse_url(!empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY']);
26308 }
26309
26310
26311  if (!empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) {
26312 $pattern = new NoProxyPattern($_SERVER['no_proxy']);
26313 if ($pattern->test($url)) {
26314 unset($proxy);
26315 }
26316 }
26317
26318 if (!empty($proxy)) {
26319 $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : '';
26320 $proxyURL .= isset($proxy['host']) ? $proxy['host'] : '';
26321
26322 if (isset($proxy['port'])) {
26323 $proxyURL .= ":" . $proxy['port'];
26324 } elseif ('http://' == substr($proxyURL, 0, 7)) {
26325 $proxyURL .= ":80";
26326 } elseif ('https://' == substr($proxyURL, 0, 8)) {
26327 $proxyURL .= ":443";
26328 }
26329
26330
26331  $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL);
26332
26333 if (0 === strpos($proxyURL, 'ssl:') && !extension_loaded('openssl')) {
26334 throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
26335 }
26336
26337 $options['http']['proxy'] = $proxyURL;
26338
26339
26340  switch (parse_url($url, PHP_URL_SCHEME)) {
26341 case 'http': 
26342  $reqFullUriEnv = getenv('HTTP_PROXY_REQUEST_FULLURI');
26343 if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
26344 $options['http']['request_fulluri'] = true;
26345 }
26346 break;
26347 case 'https': 
26348  $reqFullUriEnv = getenv('HTTPS_PROXY_REQUEST_FULLURI');
26349 if ($reqFullUriEnv === false || $reqFullUriEnv === '' || (strtolower($reqFullUriEnv) !== 'false' && (bool) $reqFullUriEnv)) {
26350 $options['http']['request_fulluri'] = true;
26351 }
26352 break;
26353 }
26354
26355
26356  if ('https' === parse_url($url, PHP_URL_SCHEME)) {
26357 $options['ssl']['SNI_enabled'] = true;
26358 if (version_compare(PHP_VERSION, '5.6.0', '<')) {
26359 $options['ssl']['SNI_server_name'] = parse_url($url, PHP_URL_HOST);
26360 }
26361 }
26362
26363
26364  if (isset($proxy['user'])) {
26365 $auth = urldecode($proxy['user']);
26366 if (isset($proxy['pass'])) {
26367 $auth .= ':' . urldecode($proxy['pass']);
26368 }
26369 $auth = base64_encode($auth);
26370
26371
26372  if (isset($defaultOptions['http']['header'])) {
26373 if (is_string($defaultOptions['http']['header'])) {
26374 $defaultOptions['http']['header'] = array($defaultOptions['http']['header']);
26375 }
26376 $defaultOptions['http']['header'][] = "Proxy-Authorization: Basic {$auth}";
26377 } else {
26378 $options['http']['header'] = array("Proxy-Authorization: Basic {$auth}");
26379 }
26380 }
26381 }
26382
26383 $options = array_replace_recursive($options, $defaultOptions);
26384
26385 if (isset($options['http']['header'])) {
26386 $options['http']['header'] = self::fixHttpHeaderField($options['http']['header']);
26387 }
26388
26389 return stream_context_create($options, $defaultParams);
26390 }
26391
26392
26393
26394
26395
26396
26397
26398
26399
26400
26401
26402 private static function fixHttpHeaderField($header)
26403 {
26404 if (!is_array($header)) {
26405 $header = explode("\r\n", $header);
26406 }
26407 uasort($header, function ($el) {
26408 return preg_match('{^content-type}i', $el) ? 1 : -1;
26409 });
26410
26411 return $header;
26412 }
26413 }
26414 <?php
26415
26416
26417
26418
26419
26420
26421
26422
26423
26424
26425
26426 namespace Composer\Util;
26427
26428 use Composer\Package\Loader\ArrayLoader;
26429 use Composer\Package\Loader\ValidatingArrayLoader;
26430 use Composer\Package\Loader\InvalidPackageException;
26431 use Composer\Json\JsonValidationException;
26432 use Composer\IO\IOInterface;
26433 use Composer\Json\JsonFile;
26434
26435
26436
26437
26438
26439
26440
26441 class ConfigValidator
26442 {
26443 private $io;
26444
26445 public function __construct(IOInterface $io)
26446 {
26447 $this->io = $io;
26448 }
26449
26450
26451
26452
26453
26454
26455
26456
26457
26458 public function validate($file, $arrayLoaderValidationFlags = ValidatingArrayLoader::CHECK_ALL)
26459 {
26460 $errors = array();
26461 $publishErrors = array();
26462 $warnings = array();
26463
26464
26465  $laxValid = false;
26466 try {
26467 $json = new JsonFile($file, new RemoteFilesystem($this->io));
26468 $manifest = $json->read();
26469
26470 $json->validateSchema(JsonFile::LAX_SCHEMA);
26471 $laxValid = true;
26472 $json->validateSchema();
26473 } catch (JsonValidationException $e) {
26474 foreach ($e->getErrors() as $message) {
26475 if ($laxValid) {
26476 $publishErrors[] = $message;
26477 } else {
26478 $errors[] = $message;
26479 }
26480 }
26481 } catch (\Exception $e) {
26482 $errors[] = $e->getMessage();
26483
26484 return array($errors, $publishErrors, $warnings);
26485 }
26486
26487
26488  if (!empty($manifest['license'])) {
26489
26490  if (is_array($manifest['license'])) {
26491 foreach ($manifest['license'] as $key => $license) {
26492 if ('proprietary' === $license) {
26493 unset($manifest['license'][$key]);
26494 }
26495 }
26496 }
26497
26498 $licenseValidator = new SpdxLicenseIdentifier();
26499 if ('proprietary' !== $manifest['license'] && array() !== $manifest['license'] && !$licenseValidator->validate($manifest['license'])) {
26500 $warnings[] = sprintf(
26501 'License %s is not a valid SPDX license identifier, see http://www.spdx.org/licenses/ if you use an open license.'
26502 ."\nIf the software is closed-source, you may use \"proprietary\" as license.",
26503 json_encode($manifest['license'])
26504 );
26505 }
26506 } else {
26507 $warnings[] = 'No license specified, it is recommended to do so. For closed-source software you may use "proprietary" as license.';
26508 }
26509
26510 if (isset($manifest['version'])) {
26511 $warnings[] = 'The version field is present, it is recommended to leave it out if the package is published on Packagist.';
26512 }
26513
26514 if (!empty($manifest['name']) && preg_match('{[A-Z]}', $manifest['name'])) {
26515 $suggestName = preg_replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $manifest['name']);
26516 $suggestName = strtolower($suggestName);
26517
26518 $warnings[] = sprintf(
26519 'Name "%s" does not match the best practice (e.g. lower-cased/with-dashes). We suggest using "%s" instead. As such you will not be able to submit it to Packagist.',
26520 $manifest['name'],
26521 $suggestName
26522 );
26523 }
26524
26525 if (!empty($manifest['type']) && $manifest['type'] == 'composer-installer') {
26526 $warnings[] = "The package type 'composer-installer' is deprecated. Please distribute your custom installers as plugins from now on. See http://getcomposer.org/doc/articles/plugins.md for plugin documentation.";
26527 }
26528
26529
26530  if (isset($manifest['require']) && isset($manifest['require-dev'])) {
26531 $requireOverrides = array_intersect_key($manifest['require'], $manifest['require-dev']);
26532
26533 if (!empty($requireOverrides)) {
26534 $plural = (count($requireOverrides) > 1) ? 'are' : 'is';
26535 $warnings[] = implode(', ', array_keys($requireOverrides)). " {$plural} required both in require and require-dev, this can lead to unexpected behavior";
26536 }
26537 }
26538
26539 try {
26540 $loader = new ValidatingArrayLoader(new ArrayLoader(), true, null, $arrayLoaderValidationFlags);
26541 if (!isset($manifest['version'])) {
26542 $manifest['version'] = '1.0.0';
26543 }
26544 if (!isset($manifest['name'])) {
26545 $manifest['name'] = 'dummy/dummy';
26546 }
26547 $loader->load($manifest);
26548 } catch (InvalidPackageException $e) {
26549 $errors = array_merge($errors, $e->getErrors());
26550 }
26551
26552 $warnings = array_merge($warnings, $loader->getWarnings());
26553
26554 return array($errors, $publishErrors, $warnings);
26555 }
26556 }
26557 <?php
26558
26559
26560
26561
26562
26563
26564
26565
26566
26567
26568
26569 namespace Composer\Util;
26570
26571
26572
26573
26574
26575
26576 class ErrorHandler
26577 {
26578
26579
26580
26581
26582
26583
26584
26585
26586
26587
26588
26589 public static function handle($level, $message, $file, $line)
26590 {
26591
26592  if (!error_reporting()) {
26593 return;
26594 }
26595
26596 if (ini_get('xdebug.scream')) {
26597 $message .= "\n\nWarning: You have xdebug.scream enabled, the warning above may be".
26598 "\na legitimately suppressed error that you were not supposed to see.";
26599 }
26600
26601 throw new \ErrorException($message, 0, $level, $file, $line);
26602 }
26603
26604
26605
26606
26607
26608
26609 public static function register()
26610 {
26611 set_error_handler(array(__CLASS__, 'handle'));
26612 }
26613 }
26614 <?php
26615
26616
26617
26618
26619
26620
26621
26622
26623
26624
26625
26626 namespace Composer\Util;
26627
26628 use Composer\Config;
26629 use Composer\IO\IOInterface;
26630
26631
26632
26633
26634 class AuthHelper
26635 {
26636 protected $io;
26637 protected $config;
26638
26639 public function __construct(IOInterface $io, Config $config)
26640 {
26641 $this->io = $io;
26642 $this->config = $config;
26643 }
26644
26645 public function storeAuth($originUrl, $storeAuth)
26646 {
26647 $store = false;
26648 $configSource = $this->config->getAuthConfigSource();
26649 if ($storeAuth === true) {
26650 $store = $configSource;
26651 } elseif ($storeAuth === 'prompt') {
26652 $answer = $this->io->askAndValidate(
26653 'Do you want to store credentials for '.$originUrl.' in '.$configSource->getName().' ? [Yn] ',
26654 function ($value) {
26655 $input = strtolower(substr(trim($value), 0, 1));
26656 if (in_array($input, array('y','n'))) {
26657 return $input;
26658 }
26659 throw new \RuntimeException('Please answer (y)es or (n)o');
26660 },
26661 false,
26662 'y'
26663 );
26664
26665 if ($answer === 'y') {
26666 $store = $configSource;
26667 }
26668 }
26669 if ($store) {
26670 $store->addConfigSetting(
26671 'http-basic.'.$originUrl,
26672 $this->io->getAuthentication($originUrl)
26673 );
26674 }
26675 }
26676 }
26677 <?php
26678
26679
26680
26681
26682
26683
26684
26685
26686
26687
26688
26689 namespace Composer\Util;
26690
26691 use Composer\Json\JsonFile;
26692
26693
26694
26695
26696
26697
26698
26699 class SpdxLicenseIdentifier
26700 {
26701
26702
26703
26704 private $identifiers;
26705
26706 public function __construct()
26707 {
26708 $this->initIdentifiers();
26709 }
26710
26711
26712
26713
26714
26715
26716
26717 public function validate($license)
26718 {
26719 if (is_array($license)) {
26720 $count = count($license);
26721 if ($count !== count(array_filter($license, 'is_string'))) {
26722 throw new \InvalidArgumentException('Array of strings expected.');
26723 }
26724 $license = $count > 1 ? '('.implode(' or ', $license).')' : (string) reset($license);
26725 }
26726 if (!is_string($license)) {
26727 throw new \InvalidArgumentException(sprintf(
26728 'Array or String expected, %s given.', gettype($license)
26729 ));
26730 }
26731
26732 return $this->isValidLicenseString($license);
26733 }
26734
26735
26736
26737
26738 private function initIdentifiers()
26739 {
26740 $jsonFile = new JsonFile(__DIR__ . '/../../../res/spdx-identifier.json');
26741 $this->identifiers = $jsonFile->read();
26742 }
26743
26744
26745
26746
26747
26748
26749 private function isValidLicenseIdentifier($identifier)
26750 {
26751 return in_array($identifier, $this->identifiers);
26752 }
26753
26754
26755
26756
26757
26758
26759
26760 private function isValidLicenseString($license)
26761 {
26762 $tokens = array(
26763 'po' => '\(',
26764 'pc' => '\)',
26765 'op' => '(?:or|and)',
26766 'lix' => '(?:NONE|NOASSERTION)',
26767 'lir' => 'LicenseRef-\d+',
26768 'lic' => '[-+_.a-zA-Z0-9]{3,}',
26769 'ws' => '\s+',
26770 '_' => '.',
26771 );
26772
26773 $next = function () use ($license, $tokens) {
26774 static $offset = 0;
26775
26776 if ($offset >= strlen($license)) {
26777 return null;
26778 }
26779
26780 foreach ($tokens as $name => $token) {
26781 if (false === $r = preg_match('{' . $token . '}', $license, $matches, PREG_OFFSET_CAPTURE, $offset)) {
26782 throw new \RuntimeException('Pattern for token %s failed (regex error).', $name);
26783 }
26784 if ($r === 0) {
26785 continue;
26786 }
26787 if ($matches[0][1] !== $offset) {
26788 continue;
26789 }
26790 $offset += strlen($matches[0][0]);
26791
26792 return array($name, $matches[0][0]);
26793 }
26794
26795 throw new \RuntimeException('At least the last pattern needs to match, but it did not (dot-match-all is missing?).');
26796 };
26797
26798 $open = 0;
26799 $require = 1;
26800 $lastop = null;
26801
26802 while (list($token, $string) = $next()) {
26803 switch ($token) {
26804 case 'po':
26805 if ($open || !$require) {
26806 return false;
26807 }
26808 $open = 1;
26809 break;
26810 case 'pc':
26811 if ($open !== 1 || $require || !$lastop) {
26812 return false;
26813 }
26814 $open = 2;
26815 break;
26816 case 'op':
26817 if ($require || !$open) {
26818 return false;
26819 }
26820 $lastop || $lastop = $string;
26821 if ($lastop !== $string) {
26822 return false;
26823 }
26824 $require = 1;
26825 break;
26826 case 'lix':
26827 if ($open) {
26828 return false;
26829 }
26830 goto lir;
26831 case 'lic':
26832 if (!$this->isValidLicenseIdentifier($string)) {
26833 return false;
26834 }
26835
26836  case 'lir':
26837 lir:
26838 if (!$require) {
26839 return false;
26840 }
26841 $require = 0;
26842 break;
26843 case 'ws':
26844 break;
26845 case '_':
26846 return false;
26847 default:
26848 throw new \RuntimeException(sprintf('Unparsed token: %s.', print_r($token, true)));
26849 }
26850 }
26851
26852 return !($open % 2 || $require);
26853 }
26854 }
26855 <?php
26856
26857
26858
26859
26860
26861
26862
26863
26864
26865
26866
26867 namespace Composer\Util;
26868
26869
26870
26871
26872 class NoProxyPattern
26873 {
26874
26875
26876
26877 protected $rules = array();
26878
26879
26880
26881
26882 public function __construct($pattern)
26883 {
26884 $this->rules = preg_split("/[\s,]+/", $pattern);
26885 }
26886
26887
26888
26889
26890
26891
26892
26893
26894 public function test($url)
26895 {
26896 $host = parse_url($url, PHP_URL_HOST);
26897 $port = parse_url($url, PHP_URL_PORT);
26898
26899 if (empty($port)) {
26900 switch (parse_url($url, PHP_URL_SCHEME)) {
26901 case 'http':
26902 $port = 80;
26903 break;
26904 case 'https':
26905 $port = 443;
26906 break;
26907 }
26908 }
26909
26910 foreach ($this->rules as $rule) {
26911 if ($rule == '*') {
26912 return true;
26913 }
26914
26915 $match = false;
26916
26917 list($ruleHost) = explode(':', $rule);
26918 list($base) = explode('/', $ruleHost);
26919
26920 if (filter_var($base, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
26921
26922
26923 if (!isset($ip)) {
26924 $ip = gethostbyname($host);
26925 }
26926
26927 if (strpos($ruleHost, '/') === false) {
26928 $match = $ip === $ruleHost;
26929 } else {
26930
26931  
26932  if ($ip === $host) {
26933 $match = false;
26934 } else {
26935
26936  $match = self::inCIDRBlock($ruleHost, $ip);
26937 }
26938 }
26939 } else {
26940
26941
26942 $haystack = '.' . trim($host, '.') . '.';
26943 $needle = '.'. trim($ruleHost, '.') .'.';
26944 $match = stripos(strrev($haystack), strrev($needle)) === 0;
26945 }
26946
26947
26948  if ($match && strpos($rule, ':') !== false) {
26949 list(, $rulePort) = explode(':', $rule);
26950 if (!empty($rulePort) && $port != $rulePort) {
26951 $match = false;
26952 }
26953 }
26954
26955 if ($match) {
26956 return true;
26957 }
26958 }
26959
26960 return false;
26961 }
26962
26963
26964
26965
26966
26967
26968
26969
26970
26971
26972
26973 private static function inCIDRBlock($cidr, $ip)
26974 {
26975
26976  list($base, $bits) = explode('/', $cidr);
26977
26978
26979  list($a, $b, $c, $d) = explode('.', $base);
26980
26981
26982  $i = ($a << 24) + ($b << 16) + ($c << 8) + $d;
26983 $mask = $bits == 0 ? 0 : (~0 << (32 - $bits));
26984
26985
26986  $low = $i & $mask;
26987
26988
26989  $high = $i | (~$mask & 0xFFFFFFFF);
26990
26991
26992  list($a, $b, $c, $d) = explode('.', $ip);
26993
26994
26995  $check = ($a << 24) + ($b << 16) + ($c << 8) + $d;
26996
26997
26998  
26999  return $check >= $low && $check <= $high;
27000 }
27001 }
27002 <?php
27003
27004
27005
27006
27007
27008
27009
27010
27011
27012
27013
27014 namespace Composer\Util;
27015
27016 use Composer\Config;
27017 use Composer\IO\IOInterface;
27018
27019
27020
27021
27022
27023 class Svn
27024 {
27025 const MAX_QTY_AUTH_TRIES = 5;
27026
27027
27028
27029
27030 protected $credentials;
27031
27032
27033
27034
27035 protected $hasAuth;
27036
27037
27038
27039
27040 protected $io;
27041
27042
27043
27044
27045 protected $url;
27046
27047
27048
27049
27050 protected $cacheCredentials = true;
27051
27052
27053
27054
27055 protected $process;
27056
27057
27058
27059
27060 protected $qtyAuthTries = 0;
27061
27062
27063
27064
27065 protected $config;
27066
27067
27068
27069
27070
27071
27072
27073 public function __construct($url, IOInterface $io, Config $config, ProcessExecutor $process = null)
27074 {
27075 $this->url = $url;
27076 $this->io = $io;
27077 $this->config = $config;
27078 $this->process = $process ?: new ProcessExecutor;
27079 }
27080
27081 public static function cleanEnv()
27082 {
27083
27084  putenv("DYLD_LIBRARY_PATH");
27085 }
27086
27087
27088
27089
27090
27091
27092
27093
27094
27095
27096
27097
27098
27099
27100
27101 public function execute($command, $url, $cwd = null, $path = null, $verbose = false)
27102 {
27103 $svnCommand = $this->getCommand($command, $url, $path);
27104 $output = null;
27105 $io = $this->io;
27106 $handler = function ($type, $buffer) use (&$output, $io, $verbose) {
27107 if ($type !== 'out') {
27108 return;
27109 }
27110 if ('Redirecting to URL ' === substr($buffer, 0, 19)) {
27111 return;
27112 }
27113 $output .= $buffer;
27114 if ($verbose) {
27115 $io->write($buffer, false);
27116 }
27117 };
27118 $status = $this->process->execute($svnCommand, $handler, $cwd);
27119 if (0 === $status) {
27120 return $output;
27121 }
27122
27123 if (empty($output)) {
27124 $output = $this->process->getErrorOutput();
27125 }
27126
27127
27128  if (false === stripos($output, 'Could not authenticate to server:')
27129 && false === stripos($output, 'authorization failed')
27130 && false === stripos($output, 'svn: E170001:')
27131 && false === stripos($output, 'svn: E215004:')) {
27132 throw new \RuntimeException($output);
27133 }
27134
27135 if (!$this->hasAuth()) {
27136 $this->doAuthDance();
27137 }
27138
27139
27140  if ($this->qtyAuthTries++ < self::MAX_QTY_AUTH_TRIES) {
27141
27142  return $this->execute($command, $url, $cwd, $path, $verbose);
27143 }
27144
27145 throw new \RuntimeException(
27146 'wrong credentials provided ('.$output.')'
27147 );
27148 }
27149
27150
27151
27152
27153 public function setCacheCredentials($cacheCredentials)
27154 {
27155 $this->cacheCredentials = $cacheCredentials;
27156 }
27157
27158
27159
27160
27161
27162
27163
27164 protected function doAuthDance()
27165 {
27166
27167  if (!$this->io->isInteractive()) {
27168 throw new \RuntimeException(
27169 'can not ask for authentication in non interactive mode'
27170 );
27171 }
27172
27173 $this->io->write("The Subversion server ({$this->url}) requested credentials:");
27174
27175 $this->hasAuth = true;
27176 $this->credentials['username'] = $this->io->ask("Username: ");
27177 $this->credentials['password'] = $this->io->askAndHideAnswer("Password: ");
27178
27179 $this->cacheCredentials = $this->io->askConfirmation("Should Subversion cache these credentials? (yes/no) ", true);
27180
27181 return $this;
27182 }
27183
27184
27185
27186
27187
27188
27189
27190
27191
27192
27193 protected function getCommand($cmd, $url, $path = null)
27194 {
27195 $cmd = sprintf('%s %s%s %s',
27196 $cmd,
27197 '--non-interactive ',
27198 $this->getCredentialString(),
27199 ProcessExecutor::escape($url)
27200 );
27201
27202 if ($path) {
27203 $cmd .= ' ' . ProcessExecutor::escape($path);
27204 }
27205
27206 return $cmd;
27207 }
27208
27209
27210
27211
27212
27213
27214
27215
27216 protected function getCredentialString()
27217 {
27218 if (!$this->hasAuth()) {
27219 return '';
27220 }
27221
27222 return sprintf(
27223 ' %s--username %s --password %s ',
27224 $this->getAuthCache(),
27225 ProcessExecutor::escape($this->getUsername()),
27226 ProcessExecutor::escape($this->getPassword())
27227 );
27228 }
27229
27230
27231
27232
27233
27234
27235
27236 protected function getPassword()
27237 {
27238 if ($this->credentials === null) {
27239 throw new \LogicException("No svn auth detected.");
27240 }
27241
27242 return isset($this->credentials['password']) ? $this->credentials['password'] : '';
27243 }
27244
27245
27246
27247
27248
27249
27250
27251 protected function getUsername()
27252 {
27253 if ($this->credentials === null) {
27254 throw new \LogicException("No svn auth detected.");
27255 }
27256
27257 return $this->credentials['username'];
27258 }
27259
27260
27261
27262
27263
27264
27265 protected function hasAuth()
27266 {
27267 if (null !== $this->hasAuth) {
27268 return $this->hasAuth;
27269 }
27270
27271 if (false === $this->createAuthFromConfig()) {
27272 $this->createAuthFromUrl();
27273 }
27274
27275 return $this->hasAuth;
27276 }
27277
27278
27279
27280
27281
27282
27283 protected function getAuthCache()
27284 {
27285 return $this->cacheCredentials ? '' : '--no-auth-cache ';
27286 }
27287
27288
27289
27290
27291
27292
27293 private function createAuthFromConfig()
27294 {
27295 if (!$this->config->has('http-basic')) {
27296 return $this->hasAuth = false;
27297 }
27298
27299 $authConfig = $this->config->get('http-basic');
27300
27301 $host = parse_url($this->url, PHP_URL_HOST);
27302 if (isset($authConfig[$host])) {
27303 $this->credentials['username'] = $authConfig[$host]['username'];
27304 $this->credentials['password'] = $authConfig[$host]['password'];
27305
27306 return $this->hasAuth = true;
27307 }
27308
27309 return $this->hasAuth = false;
27310 }
27311
27312
27313
27314
27315
27316
27317 private function createAuthFromUrl()
27318 {
27319 $uri = parse_url($this->url);
27320 if (empty($uri['user'])) {
27321 return $this->hasAuth = false;
27322 }
27323
27324 $this->credentials['username'] = $uri['user'];
27325 if (!empty($uri['pass'])) {
27326 $this->credentials['password'] = $uri['pass'];
27327 }
27328
27329 return $this->hasAuth = true;
27330 }
27331 }
27332 <?php
27333
27334
27335
27336
27337
27338
27339
27340
27341
27342
27343
27344 namespace Composer;
27345
27346 use Composer\Package\RootPackageInterface;
27347 use Composer\Package\Locker;
27348 use Composer\Repository\RepositoryManager;
27349 use Composer\Installer\InstallationManager;
27350 use Composer\Plugin\PluginManager;
27351 use Composer\Downloader\DownloadManager;
27352 use Composer\EventDispatcher\EventDispatcher;
27353 use Composer\Autoload\AutoloadGenerator;
27354
27355
27356
27357
27358
27359
27360 class Composer
27361 {
27362 const VERSION = 'c58b7d917c65692eeb00c22b2fbaaa251cb390dc';
27363 const BRANCH_ALIAS_VERSION = '1.0-dev';
27364 const RELEASE_DATE = '2015-01-05 16:31:16';
27365
27366
27367
27368
27369 private $package;
27370
27371
27372
27373
27374 private $locker;
27375
27376
27377
27378
27379 private $repositoryManager;
27380
27381
27382
27383
27384 private $downloadManager;
27385
27386
27387
27388
27389 private $installationManager;
27390
27391
27392
27393
27394 private $pluginManager;
27395
27396
27397
27398
27399 private $config;
27400
27401
27402
27403
27404 private $eventDispatcher;
27405
27406
27407
27408
27409 private $autoloadGenerator;
27410
27411
27412
27413
27414
27415 public function setPackage(RootPackageInterface $package)
27416 {
27417 $this->package = $package;
27418 }
27419
27420
27421
27422
27423 public function getPackage()
27424 {
27425 return $this->package;
27426 }
27427
27428
27429
27430
27431 public function setConfig(Config $config)
27432 {
27433 $this->config = $config;
27434 }
27435
27436
27437
27438
27439 public function getConfig()
27440 {
27441 return $this->config;
27442 }
27443
27444
27445
27446
27447 public function setLocker(Locker $locker)
27448 {
27449 $this->locker = $locker;
27450 }
27451
27452
27453
27454
27455 public function getLocker()
27456 {
27457 return $this->locker;
27458 }
27459
27460
27461
27462
27463 public function setRepositoryManager(RepositoryManager $manager)
27464 {
27465 $this->repositoryManager = $manager;
27466 }
27467
27468
27469
27470
27471 public function getRepositoryManager()
27472 {
27473 return $this->repositoryManager;
27474 }
27475
27476
27477
27478
27479 public function setDownloadManager(DownloadManager $manager)
27480 {
27481 $this->downloadManager = $manager;
27482 }
27483
27484
27485
27486
27487 public function getDownloadManager()
27488 {
27489 return $this->downloadManager;
27490 }
27491
27492
27493
27494
27495 public function setInstallationManager(InstallationManager $manager)
27496 {
27497 $this->installationManager = $manager;
27498 }
27499
27500
27501
27502
27503 public function getInstallationManager()
27504 {
27505 return $this->installationManager;
27506 }
27507
27508
27509
27510
27511 public function setPluginManager(PluginManager $manager)
27512 {
27513 $this->pluginManager = $manager;
27514 }
27515
27516
27517
27518
27519 public function getPluginManager()
27520 {
27521 return $this->pluginManager;
27522 }
27523
27524
27525
27526
27527 public function setEventDispatcher(EventDispatcher $eventDispatcher)
27528 {
27529 $this->eventDispatcher = $eventDispatcher;
27530 }
27531
27532
27533
27534
27535 public function getEventDispatcher()
27536 {
27537 return $this->eventDispatcher;
27538 }
27539
27540
27541
27542
27543 public function setAutoloadGenerator(AutoloadGenerator $autoloadGenerator)
27544 {
27545 $this->autoloadGenerator = $autoloadGenerator;
27546 }
27547
27548
27549
27550
27551 public function getAutoloadGenerator()
27552 {
27553 return $this->autoloadGenerator;
27554 }
27555 }
27556 <?php
27557
27558
27559
27560
27561
27562
27563
27564
27565
27566
27567
27568 namespace Composer\Json;
27569
27570
27571
27572
27573 class JsonManipulator
27574 {
27575 private static $RECURSE_BLOCKS;
27576 private static $RECURSE_ARRAYS;
27577 private static $JSON_VALUE;
27578 private static $JSON_STRING;
27579
27580 private $contents;
27581 private $newline;
27582 private $indent;
27583
27584 public function __construct($contents)
27585 {
27586 if (!self::$RECURSE_BLOCKS) {
27587 self::$RECURSE_BLOCKS = '(?:[^{}]*|\{(?:[^{}]*|\{(?:[^{}]*|\{(?:[^{}]*|\{[^{}]*\})*\})*\})*\})*';
27588 self::$RECURSE_ARRAYS = '(?:[^\]]*|\[(?:[^\]]*|\[(?:[^\]]*|\[(?:[^\]]*|\[[^\]]*\])*\])*\])*\]|'.self::$RECURSE_BLOCKS.')*';
27589 self::$JSON_STRING = '"(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f\\\\"])*"';
27590 self::$JSON_VALUE = '(?:[0-9.]+|null|true|false|'.self::$JSON_STRING.'|\['.self::$RECURSE_ARRAYS.'\]|\{'.self::$RECURSE_BLOCKS.'\})';
27591 }
27592
27593 $contents = trim($contents);
27594 if ($contents === '') {
27595 $contents = '{}';
27596 }
27597 if (!$this->pregMatch('#^\{(.*)\}$#s', $contents)) {
27598 throw new \InvalidArgumentException('The json file must be an object ({})');
27599 }
27600 $this->newline = false !== strpos($contents, "\r\n") ? "\r\n" : "\n";
27601 $this->contents = $contents === '{}' ? '{' . $this->newline . '}' : $contents;
27602 $this->detectIndenting();
27603 }
27604
27605 public function getContents()
27606 {
27607 return $this->contents . $this->newline;
27608 }
27609
27610 public function addLink($type, $package, $constraint, $sortPackages = false)
27611 {
27612 $decoded = JsonFile::parseJson($this->contents);
27613
27614
27615  if (!isset($decoded[$type])) {
27616 return $this->addMainKey($type, array($package => $constraint));
27617 }
27618
27619 $regex = '{^(\s*\{\s*(?:'.self::$JSON_STRING.'\s*:\s*'.self::$JSON_VALUE.'\s*,\s*)*?)'.
27620 '('.preg_quote(JsonFile::encode($type)).'\s*:\s*)('.self::$JSON_VALUE.')(.*)}s';
27621 if (!$this->pregMatch($regex, $this->contents, $matches)) {
27622 return false;
27623 }
27624
27625 $links = $matches[3];
27626
27627 if (isset($decoded[$type][$package])) {
27628
27629  $packageRegex = str_replace('/', '\\\\?/', preg_quote($package));
27630
27631  $links = preg_replace('{"'.$packageRegex.'"(\s*:\s*)'.self::$JSON_STRING.'}i', addcslashes(JsonFile::encode($package).'${1}"'.$constraint.'"', '\\'), $links);
27632 } else {
27633 if ($this->pregMatch('#^\s*\{\s*\S+.*?(\s*\}\s*)$#s', $links, $match)) {
27634
27635  $links = preg_replace(
27636 '{'.preg_quote($match[1]).'$}',
27637 addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $match[1], '\\'),
27638 $links
27639 );
27640 } else {
27641
27642  $links = '{' . $this->newline .
27643 $this->indent . $this->indent . JsonFile::encode($package).': '.JsonFile::encode($constraint) . $this->newline .
27644 $this->indent . '}';
27645 }
27646 }
27647
27648 if (true === $sortPackages) {
27649 $requirements = json_decode($links, true);
27650
27651 ksort($requirements);
27652 $links = $this->format($requirements);
27653 }
27654
27655 $this->contents = $matches[1] . $matches[2] . $links . $matches[4];
27656
27657 return true;
27658 }
27659
27660 public function addRepository($name, $config)
27661 {
27662 return $this->addSubNode('repositories', $name, $config);
27663 }
27664
27665 public function removeRepository($name)
27666 {
27667 return $this->removeSubNode('repositories', $name);
27668 }
27669
27670 public function addConfigSetting($name, $value)
27671 {
27672 return $this->addSubNode('config', $name, $value);
27673 }
27674
27675 public function removeConfigSetting($name)
27676 {
27677 return $this->removeSubNode('config', $name);
27678 }
27679
27680 public function addSubNode($mainNode, $name, $value)
27681 {
27682 $decoded = JsonFile::parseJson($this->contents);
27683
27684
27685  if (!isset($decoded[$mainNode])) {
27686 $this->addMainKey($mainNode, array($name => $value));
27687
27688 return true;
27689 }
27690
27691 $subName = null;
27692 if (in_array($mainNode, array('config', 'repositories')) && false !== strpos($name, '.')) {
27693 list($name, $subName) = explode('.', $name, 2);
27694 }
27695
27696
27697  $nodeRegex = '#("'.$mainNode.'":\s*\{)('.self::$RECURSE_BLOCKS.')(\})#s';
27698 if (!$this->pregMatch($nodeRegex, $this->contents, $match)) {
27699 return false;
27700 }
27701
27702 $children = $match[2];
27703
27704
27705  if (!@json_decode('{'.$children.'}')) {
27706 return false;
27707 }
27708
27709 $that = $this;
27710
27711
27712  if ($this->pregMatch('{("'.preg_quote($name).'"\s*:\s*)('.self::$JSON_VALUE.')(,?)}', $children, $matches)) {
27713 $children = preg_replace_callback('{("'.preg_quote($name).'"\s*:\s*)('.self::$JSON_VALUE.')(,?)}', function ($matches) use ($name, $subName, $value, $that) {
27714 if ($subName !== null) {
27715 $curVal = json_decode($matches[2], true);
27716 $curVal[$subName] = $value;
27717 $value = $curVal;
27718 }
27719
27720 return $matches[1] . $that->format($value, 1) . $matches[3];
27721 }, $children);
27722 } elseif ($this->pregMatch('#[^\s](\s*)$#', $children, $match)) {
27723 if ($subName !== null) {
27724 $value = array($subName => $value);
27725 }
27726
27727
27728  $children = preg_replace(
27729 '#'.$match[1].'$#',
27730 addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $match[1], '\\'),
27731 $children
27732 );
27733 } else {
27734 if ($subName !== null) {
27735 $value = array($subName => $value);
27736 }
27737
27738
27739  $children = $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $children;
27740 }
27741
27742 $this->contents = preg_replace($nodeRegex, addcslashes('${1}'.$children.'$3', '\\'), $this->contents);
27743
27744 return true;
27745 }
27746
27747 public function removeSubNode($mainNode, $name)
27748 {
27749 $decoded = JsonFile::parseJson($this->contents);
27750
27751
27752  if (empty($decoded[$mainNode])) {
27753 return true;
27754 }
27755
27756
27757  $nodeRegex = '#("'.$mainNode.'":\s*\{)('.self::$RECURSE_BLOCKS.')(\})#s';
27758 if (!$this->pregMatch($nodeRegex, $this->contents, $match)) {
27759 return false;
27760 }
27761
27762 $children = $match[2];
27763
27764
27765  if (!@json_decode('{'.$children.'}')) {
27766 return false;
27767 }
27768
27769 $subName = null;
27770 if (in_array($mainNode, array('config', 'repositories')) && false !== strpos($name, '.')) {
27771 list($name, $subName) = explode('.', $name, 2);
27772 }
27773
27774
27775  if (!isset($decoded[$mainNode][$name]) || ($subName && !isset($decoded[$mainNode][$name][$subName]))) {
27776 return true;
27777 }
27778
27779
27780  if ($this->pregMatch('{"'.preg_quote($name).'"\s*:}i', $children)) {
27781
27782  if (preg_match_all('{"'.preg_quote($name).'"\s*:\s*(?:'.self::$JSON_VALUE.')}', $children, $matches)) {
27783 $bestMatch = '';
27784 foreach ($matches[0] as $match) {
27785 if (strlen($bestMatch) < strlen($match)) {
27786 $bestMatch = $match;
27787 }
27788 }
27789 $childrenClean = preg_replace('{,\s*'.preg_quote($bestMatch).'}i', '', $children, -1, $count);
27790 if (1 !== $count) {
27791 $childrenClean = preg_replace('{'.preg_quote($bestMatch).'\s*,?\s*}i', '', $childrenClean, -1, $count);
27792 if (1 !== $count) {
27793 return false;
27794 }
27795 }
27796 }
27797 } else {
27798 $childrenClean = $children;
27799 }
27800
27801
27802  if (!trim($childrenClean)) {
27803 $this->contents = preg_replace($nodeRegex, '$1'.$this->newline.$this->indent.'}', $this->contents);
27804
27805
27806  if ($subName !== null) {
27807 $curVal = json_decode('{'.$children.'}', true);
27808 unset($curVal[$name][$subName]);
27809 $this->addSubNode($mainNode, $name, $curVal[$name]);
27810 }
27811
27812 return true;
27813 }
27814
27815 $that = $this;
27816 $this->contents = preg_replace_callback($nodeRegex, function ($matches) use ($that, $name, $subName, $childrenClean) {
27817 if ($subName !== null) {
27818 $curVal = json_decode('{'.$matches[2].'}', true);
27819 unset($curVal[$name][$subName]);
27820 $childrenClean = substr($that->format($curVal, 0), 1, -1);
27821 }
27822
27823 return $matches[1] . $childrenClean . $matches[3];
27824 }, $this->contents);
27825
27826 return true;
27827 }
27828
27829 public function addMainKey($key, $content)
27830 {
27831 $decoded = JsonFile::parseJson($this->contents);
27832 $content = $this->format($content);
27833
27834
27835  $regex = '{^(\s*\{\s*(?:'.self::$JSON_STRING.'\s*:\s*'.self::$JSON_VALUE.'\s*,\s*)*?)'.
27836 '('.preg_quote(JsonFile::encode($key)).'\s*:\s*'.self::$JSON_VALUE.')(.*)}s';
27837 if (isset($decoded[$key]) && $this->pregMatch($regex, $this->contents, $matches)) {
27838
27839  if (!@json_decode('{'.$matches[2].'}')) {
27840 return false;
27841 }
27842
27843 $this->contents = $matches[1] . JsonFile::encode($key).': '.$content . $matches[3];
27844
27845 return true;
27846 }
27847
27848
27849  if ($this->pregMatch('#[^{\s](\s*)\}$#', $this->contents, $match)) {
27850 $this->contents = preg_replace(
27851 '#'.$match[1].'\}$#',
27852 addcslashes(',' . $this->newline . $this->indent . JsonFile::encode($key). ': '. $content . $this->newline . '}', '\\'),
27853 $this->contents
27854 );
27855
27856 return true;
27857 }
27858
27859
27860  $this->contents = preg_replace(
27861 '#\}$#',
27862 addcslashes($this->indent . JsonFile::encode($key). ': '.$content . $this->newline . '}', '\\'),
27863 $this->contents
27864 );
27865
27866 return true;
27867 }
27868
27869 public function format($data, $depth = 0)
27870 {
27871 if (is_array($data)) {
27872 reset($data);
27873
27874 if (is_numeric(key($data))) {
27875 foreach ($data as $key => $val) {
27876 $data[$key] = $this->format($val, $depth + 1);
27877 }
27878
27879 return '['.implode(', ', $data).']';
27880 }
27881
27882 $out = '{' . $this->newline;
27883 $elems = array();
27884 foreach ($data as $key => $val) {
27885 $elems[] = str_repeat($this->indent, $depth + 2) . JsonFile::encode($key). ': '.$this->format($val, $depth + 1);
27886 }
27887
27888 return $out . implode(','.$this->newline, $elems) . $this->newline . str_repeat($this->indent, $depth + 1) . '}';
27889 }
27890
27891 return JsonFile::encode($data);
27892 }
27893
27894 protected function detectIndenting()
27895 {
27896 if ($this->pregMatch('{^(\s+)"}m', $this->contents, $match)) {
27897 $this->indent = $match[1];
27898 } else {
27899 $this->indent = '    ';
27900 }
27901 }
27902
27903 protected function pregMatch($re, $str, &$matches = array())
27904 {
27905 $count = preg_match($re, $str, $matches);
27906
27907 if ($count === false) {
27908 switch (preg_last_error()) {
27909 case PREG_NO_ERROR:
27910 throw new \RuntimeException('Failed to execute regex: PREG_NO_ERROR');
27911 case PREG_INTERNAL_ERROR:
27912 throw new \RuntimeException('Failed to execute regex: PREG_INTERNAL_ERROR');
27913 case PREG_BACKTRACK_LIMIT_ERROR:
27914 throw new \RuntimeException('Failed to execute regex: PREG_BACKTRACK_LIMIT_ERROR');
27915 case PREG_RECURSION_LIMIT_ERROR:
27916 throw new \RuntimeException('Failed to execute regex: PREG_RECURSION_LIMIT_ERROR');
27917 case PREG_BAD_UTF8_ERROR:
27918 throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_ERROR');
27919 case PREG_BAD_UTF8_OFFSET_ERROR:
27920 throw new \RuntimeException('Failed to execute regex: PREG_BAD_UTF8_OFFSET_ERROR');
27921 default:
27922 throw new \RuntimeException('Failed to execute regex: Unknown error');
27923 }
27924 }
27925
27926 return $count;
27927 }
27928 }
27929 <?php
27930
27931
27932
27933
27934
27935
27936
27937
27938
27939
27940
27941 namespace Composer\Json;
27942
27943 use JsonSchema\Validator;
27944 use Seld\JsonLint\JsonParser;
27945 use Seld\JsonLint\ParsingException;
27946 use Composer\Util\RemoteFilesystem;
27947 use Composer\Downloader\TransportException;
27948
27949
27950
27951
27952
27953
27954
27955 class JsonFile
27956 {
27957 const LAX_SCHEMA = 1;
27958 const STRICT_SCHEMA = 2;
27959
27960 const JSON_UNESCAPED_SLASHES = 64;
27961 const JSON_PRETTY_PRINT = 128;
27962 const JSON_UNESCAPED_UNICODE = 256;
27963
27964 private $path;
27965 private $rfs;
27966
27967
27968
27969
27970
27971
27972
27973
27974 public function __construct($path, RemoteFilesystem $rfs = null)
27975 {
27976 $this->path = $path;
27977
27978 if (null === $rfs && preg_match('{^https?://}i', $path)) {
27979 throw new \InvalidArgumentException('http urls require a RemoteFilesystem instance to be passed');
27980 }
27981 $this->rfs = $rfs;
27982 }
27983
27984
27985
27986
27987 public function getPath()
27988 {
27989 return $this->path;
27990 }
27991
27992
27993
27994
27995
27996
27997 public function exists()
27998 {
27999 return is_file($this->path);
28000 }
28001
28002
28003
28004
28005
28006
28007
28008 public function read()
28009 {
28010 try {
28011 if ($this->rfs) {
28012 $json = $this->rfs->getContents($this->path, $this->path, false);
28013 } else {
28014 $json = file_get_contents($this->path);
28015 }
28016 } catch (TransportException $e) {
28017 throw new \RuntimeException($e->getMessage(), 0, $e);
28018 } catch (\Exception $e) {
28019 throw new \RuntimeException('Could not read '.$this->path."\n\n".$e->getMessage());
28020 }
28021
28022 return static::parseJson($json, $this->path);
28023 }
28024
28025
28026
28027
28028
28029
28030
28031
28032 public function write(array $hash, $options = 448)
28033 {
28034 $dir = dirname($this->path);
28035 if (!is_dir($dir)) {
28036 if (file_exists($dir)) {
28037 throw new \UnexpectedValueException(
28038 $dir.' exists and is not a directory.'
28039 );
28040 }
28041 if (!@mkdir($dir, 0777, true)) {
28042 throw new \UnexpectedValueException(
28043 $dir.' does not exist and could not be created.'
28044 );
28045 }
28046 }
28047
28048 $retries = 3;
28049 while ($retries--) {
28050 try {
28051 file_put_contents($this->path, static::encode($hash, $options). ($options & self::JSON_PRETTY_PRINT ? "\n" : ''));
28052 break;
28053 } catch (\Exception $e) {
28054 if ($retries) {
28055 usleep(500000);
28056 continue;
28057 }
28058
28059 throw $e;
28060 }
28061 }
28062 }
28063
28064
28065
28066
28067
28068
28069
28070
28071 public function validateSchema($schema = self::STRICT_SCHEMA)
28072 {
28073 $content = file_get_contents($this->path);
28074 $data = json_decode($content);
28075
28076 if (null === $data && 'null' !== $content) {
28077 self::validateSyntax($content, $this->path);
28078 }
28079
28080 $schemaFile = __DIR__ . '/../../../res/composer-schema.json';
28081 $schemaData = json_decode(file_get_contents($schemaFile));
28082
28083 if ($schema === self::LAX_SCHEMA) {
28084 $schemaData->additionalProperties = true;
28085 $schemaData->required = array();
28086 }
28087
28088 $validator = new Validator();
28089 $validator->check($data, $schemaData);
28090
28091
28092
28093 if (!$validator->isValid()) {
28094 $errors = array();
28095 foreach ((array) $validator->getErrors() as $error) {
28096 $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message'];
28097 }
28098 throw new JsonValidationException('"'.$this->path.'" does not match the expected JSON schema', $errors);
28099 }
28100
28101 return true;
28102 }
28103
28104
28105
28106
28107
28108
28109
28110
28111 public static function encode($data, $options = 448)
28112 {
28113 if (version_compare(PHP_VERSION, '5.4', '>=')) {
28114 $json = json_encode($data, $options);
28115
28116
28117  if (PHP_VERSION_ID < 50428 || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50512) || (defined('JSON_C_VERSION') && version_compare(phpversion('json'), '1.3.6', '<'))) {
28118 $json = preg_replace('/\[\s+\]/', '[]', $json);
28119 $json = preg_replace('/\{\s+\}/', '{}', $json);
28120 }
28121
28122 return $json;
28123 }
28124
28125 $json = json_encode($data);
28126
28127 $prettyPrint = (bool) ($options & self::JSON_PRETTY_PRINT);
28128 $unescapeUnicode = (bool) ($options & self::JSON_UNESCAPED_UNICODE);
28129 $unescapeSlashes = (bool) ($options & self::JSON_UNESCAPED_SLASHES);
28130
28131 if (!$prettyPrint && !$unescapeUnicode && !$unescapeSlashes) {
28132 return $json;
28133 }
28134
28135 $result = JsonFormatter::format($json, $unescapeUnicode, $unescapeSlashes);
28136
28137 return $result;
28138 }
28139
28140
28141
28142
28143
28144
28145
28146
28147
28148 public static function parseJson($json, $file = null)
28149 {
28150 $data = json_decode($json, true);
28151 if (null === $data && JSON_ERROR_NONE !== json_last_error()) {
28152 self::validateSyntax($json, $file);
28153 }
28154
28155 return $data;
28156 }
28157
28158
28159
28160
28161
28162
28163
28164
28165
28166
28167
28168 protected static function validateSyntax($json, $file = null)
28169 {
28170 $parser = new JsonParser();
28171 $result = $parser->lint($json);
28172 if (null === $result) {
28173 if (defined('JSON_ERROR_UTF8') && JSON_ERROR_UTF8 === json_last_error()) {
28174 throw new \UnexpectedValueException('"'.$file.'" is not UTF-8, could not parse as JSON');
28175 }
28176
28177 return true;
28178 }
28179
28180 throw new ParsingException('"'.$file.'" does not contain valid JSON'."\n".$result->getMessage(), $result->getDetails());
28181 }
28182 }
28183 <?php
28184
28185
28186
28187
28188
28189
28190
28191
28192
28193
28194
28195 namespace Composer\Json;
28196
28197
28198
28199
28200
28201
28202
28203
28204
28205 class JsonFormatter
28206 {
28207
28208
28209
28210
28211
28212
28213
28214
28215
28216
28217
28218
28219
28220 public static function format($json, $unescapeUnicode, $unescapeSlashes)
28221 {
28222 $result = '';
28223 $pos = 0;
28224 $strLen = strlen($json);
28225 $indentStr = '    ';
28226 $newLine = "\n";
28227 $outOfQuotes = true;
28228 $buffer = '';
28229 $noescape = true;
28230
28231 for ($i = 0; $i < $strLen; $i++) {
28232
28233  $char = substr($json, $i, 1);
28234
28235
28236  if ('"' === $char && $noescape) {
28237 $outOfQuotes = !$outOfQuotes;
28238 }
28239
28240 if (!$outOfQuotes) {
28241 $buffer .= $char;
28242 $noescape = '\\' === $char ? !$noescape : true;
28243 continue;
28244 } elseif ('' !== $buffer) {
28245 if ($unescapeSlashes) {
28246 $buffer = str_replace('\\/', '/', $buffer);
28247 }
28248
28249 if ($unescapeUnicode && function_exists('mb_convert_encoding')) {
28250
28251  $buffer = preg_replace_callback('/(\\\\+)u([0-9a-f]{4})/i', function ($match) {
28252 $l = strlen($match[1]);
28253
28254 if ($l % 2) {
28255 return str_repeat('\\', $l - 1) . mb_convert_encoding(
28256 pack('H*', $match[2]),
28257 'UTF-8',
28258 'UCS-2BE'
28259 );
28260 }
28261
28262 return $match[0];
28263 }, $buffer);
28264 }
28265
28266 $result .= $buffer.$char;
28267 $buffer = '';
28268 continue;
28269 }
28270
28271 if (':' === $char) {
28272
28273  $char .= ' ';
28274 } elseif (('}' === $char || ']' === $char)) {
28275 $pos--;
28276 $prevChar = substr($json, $i - 1, 1);
28277
28278 if ('{' !== $prevChar && '[' !== $prevChar) {
28279
28280  
28281  $result .= $newLine;
28282 for ($j = 0; $j < $pos; $j++) {
28283 $result .= $indentStr;
28284 }
28285 } else {
28286
28287  $result = rtrim($result);
28288 }
28289 }
28290
28291 $result .= $char;
28292
28293
28294  
28295  if (',' === $char || '{' === $char || '[' === $char) {
28296 $result .= $newLine;
28297
28298 if ('{' === $char || '[' === $char) {
28299 $pos++;
28300 }
28301
28302 for ($j = 0; $j < $pos; $j++) {
28303 $result .= $indentStr;
28304 }
28305 }
28306 }
28307
28308 return $result;
28309 }
28310 }
28311 <?php
28312
28313
28314
28315
28316
28317
28318
28319
28320
28321
28322
28323 namespace Composer\Json;
28324
28325 use Exception;
28326
28327
28328
28329
28330 class JsonValidationException extends Exception
28331 {
28332 protected $errors;
28333
28334 public function __construct($message, $errors = array(), \Exception $previous = null)
28335 {
28336 $this->errors = $errors;
28337 parent::__construct($message, 0, $previous);
28338 }
28339
28340 public function getErrors()
28341 {
28342 return $this->errors;
28343 }
28344 }
28345 <?php
28346
28347
28348
28349
28350
28351
28352
28353
28354
28355
28356
28357 namespace Composer;
28358
28359 use Composer\Config\ConfigSourceInterface;
28360
28361
28362
28363
28364 class Config
28365 {
28366 const RELATIVE_PATHS = 1;
28367
28368 public static $defaultConfig = array(
28369 'process-timeout' => 300,
28370 'use-include-path' => false,
28371 'preferred-install' => 'auto',
28372 'notify-on-install' => true,
28373 'github-protocols' => array('git', 'https', 'ssh'),
28374 'vendor-dir' => 'vendor',
28375 'bin-dir' => '{$vendor-dir}/bin',
28376 'cache-dir' => '{$home}/cache',
28377 'cache-files-dir' => '{$cache-dir}/files',
28378 'cache-repo-dir' => '{$cache-dir}/repo',
28379 'cache-vcs-dir' => '{$cache-dir}/vcs',
28380 'cache-ttl' => 15552000, 
28381  'cache-files-ttl' => null, 
28382  'cache-files-maxsize' => '300MiB',
28383 'discard-changes' => false,
28384 'autoloader-suffix' => null,
28385 'optimize-autoloader' => false,
28386 'prepend-autoloader' => true,
28387 'github-domains' => array('github.com'),
28388 'github-expose-hostname' => true,
28389 'store-auths' => 'prompt',
28390
28391  
28392  
28393  );
28394
28395 public static $defaultRepositories = array(
28396 'packagist' => array(
28397 'type' => 'composer',
28398 'url' => 'https?://packagist.org',
28399 'allow_ssl_downgrade' => true,
28400 )
28401 );
28402
28403 private $config;
28404 private $baseDir;
28405 private $repositories;
28406 private $configSource;
28407 private $authConfigSource;
28408 private $useEnvironment;
28409
28410
28411
28412
28413 public function __construct($useEnvironment = true, $baseDir = null)
28414 {
28415
28416  $this->config = static::$defaultConfig;
28417 $this->repositories = static::$defaultRepositories;
28418 $this->useEnvironment = (bool) $useEnvironment;
28419 $this->baseDir = $baseDir;
28420 }
28421
28422 public function setConfigSource(ConfigSourceInterface $source)
28423 {
28424 $this->configSource = $source;
28425 }
28426
28427 public function getConfigSource()
28428 {
28429 return $this->configSource;
28430 }
28431
28432 public function setAuthConfigSource(ConfigSourceInterface $source)
28433 {
28434 $this->authConfigSource = $source;
28435 }
28436
28437 public function getAuthConfigSource()
28438 {
28439 return $this->authConfigSource;
28440 }
28441
28442
28443
28444
28445
28446
28447 public function merge($config)
28448 {
28449
28450  if (!empty($config['config']) && is_array($config['config'])) {
28451 foreach ($config['config'] as $key => $val) {
28452 if (in_array($key, array('github-oauth', 'http-basic')) && isset($this->config[$key])) {
28453 $this->config[$key] = array_merge($this->config[$key], $val);
28454 } else {
28455 $this->config[$key] = $val;
28456 }
28457 }
28458 }
28459
28460 if (!empty($config['repositories']) && is_array($config['repositories'])) {
28461 $this->repositories = array_reverse($this->repositories, true);
28462 $newRepos = array_reverse($config['repositories'], true);
28463 foreach ($newRepos as $name => $repository) {
28464
28465  if (false === $repository) {
28466 unset($this->repositories[$name]);
28467 continue;
28468 }
28469
28470
28471  if (1 === count($repository) && false === current($repository)) {
28472 unset($this->repositories[key($repository)]);
28473 continue;
28474 }
28475
28476
28477  if (is_int($name)) {
28478 $this->repositories[] = $repository;
28479 } else {
28480 $this->repositories[$name] = $repository;
28481 }
28482 }
28483 $this->repositories = array_reverse($this->repositories, true);
28484 }
28485 }
28486
28487
28488
28489
28490 public function getRepositories()
28491 {
28492 return $this->repositories;
28493 }
28494
28495
28496
28497
28498
28499
28500
28501
28502
28503 public function get($key, $flags = 0)
28504 {
28505 switch ($key) {
28506 case 'vendor-dir':
28507 case 'bin-dir':
28508 case 'process-timeout':
28509 case 'cache-dir':
28510 case 'cache-files-dir':
28511 case 'cache-repo-dir':
28512 case 'cache-vcs-dir':
28513
28514  $env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_'));
28515
28516 $val = rtrim($this->process($this->getComposerEnv($env) ?: $this->config[$key], $flags), '/\\');
28517 $val = preg_replace('#^(\$HOME|~)(/|$)#', rtrim(getenv('HOME') ?: getenv('USERPROFILE'), '/\\') . '/', $val);
28518
28519 if (substr($key, -4) !== '-dir') {
28520 return $val;
28521 }
28522
28523 return ($flags & self::RELATIVE_PATHS == 1) ? $val : $this->realpath($val);
28524
28525 case 'cache-ttl':
28526 return (int) $this->config[$key];
28527
28528 case 'cache-files-maxsize':
28529 if (!preg_match('/^\s*([0-9.]+)\s*(?:([kmg])(?:i?b)?)?\s*$/i', $this->config[$key], $matches)) {
28530 throw new \RuntimeException(
28531 "Could not parse the value of 'cache-files-maxsize': {$this->config[$key]}"
28532 );
28533 }
28534 $size = $matches[1];
28535 if (isset($matches[2])) {
28536 switch (strtolower($matches[2])) {
28537 case 'g':
28538 $size *= 1024;
28539
28540  case 'm':
28541 $size *= 1024;
28542
28543  case 'k':
28544 $size *= 1024;
28545 break;
28546 }
28547 }
28548
28549 return $size;
28550
28551 case 'cache-files-ttl':
28552 if (isset($this->config[$key])) {
28553 return (int) $this->config[$key];
28554 }
28555
28556 return (int) $this->config['cache-ttl'];
28557
28558 case 'home':
28559 return rtrim($this->process($this->config[$key], $flags), '/\\');
28560
28561 case 'discard-changes':
28562 if ($env = $this->getComposerEnv('COMPOSER_DISCARD_CHANGES')) {
28563 if (!in_array($env, array('stash', 'true', 'false', '1', '0'), true)) {
28564 throw new \RuntimeException(
28565 "Invalid value for COMPOSER_DISCARD_CHANGES: {$env}. Expected 1, 0, true, false or stash"
28566 );
28567 }
28568 if ('stash' === $env) {
28569 return 'stash';
28570 }
28571
28572
28573  return $env !== 'false' && (bool) $env;
28574 }
28575
28576 if (!in_array($this->config[$key], array(true, false, 'stash'), true)) {
28577 throw new \RuntimeException(
28578 "Invalid value for 'discard-changes': {$this->config[$key]}. Expected true, false or stash"
28579 );
28580 }
28581
28582 return $this->config[$key];
28583
28584 case 'github-protocols':
28585 if (reset($this->config['github-protocols']) === 'http') {
28586 throw new \RuntimeException('The http protocol for github is not available anymore, update your config\'s github-protocols to use "https", "git" or "ssh"');
28587 }
28588
28589 return $this->config[$key];
28590
28591 default:
28592 if (!isset($this->config[$key])) {
28593 return null;
28594 }
28595
28596 return $this->process($this->config[$key], $flags);
28597 }
28598 }
28599
28600 public function all($flags = 0)
28601 {
28602 $all = array(
28603 'repositories' => $this->getRepositories(),
28604 );
28605 foreach (array_keys($this->config) as $key) {
28606 $all['config'][$key] = $this->get($key, $flags);
28607 }
28608
28609 return $all;
28610 }
28611
28612 public function raw()
28613 {
28614 return array(
28615 'repositories' => $this->getRepositories(),
28616 'config' => $this->config,
28617 );
28618 }
28619
28620
28621
28622
28623
28624
28625
28626 public function has($key)
28627 {
28628 return array_key_exists($key, $this->config);
28629 }
28630
28631
28632
28633
28634
28635
28636
28637
28638 private function process($value, $flags)
28639 {
28640 $config = $this;
28641
28642 if (!is_string($value)) {
28643 return $value;
28644 }
28645
28646 return preg_replace_callback('#\{\$(.+)\}#', function ($match) use ($config, $flags) {
28647 return $config->get($match[1], $flags);
28648 }, $value);
28649 }
28650
28651
28652
28653
28654
28655
28656
28657
28658
28659 private function realpath($path)
28660 {
28661 if (substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':') {
28662 return $path;
28663 }
28664
28665 return $this->baseDir . '/' . $path;
28666 }
28667
28668
28669
28670
28671
28672
28673
28674
28675
28676
28677 private function getComposerEnv($var)
28678 {
28679 if ($this->useEnvironment) {
28680 return getenv($var);
28681 }
28682
28683 return false;
28684 }
28685 }
28686 <?php
28687
28688
28689
28690
28691
28692
28693
28694
28695
28696
28697
28698 namespace Composer\EventDispatcher;
28699
28700
28701
28702
28703
28704
28705
28706
28707
28708
28709
28710
28711
28712 interface EventSubscriberInterface
28713 {
28714
28715
28716
28717
28718
28719
28720
28721
28722
28723
28724
28725
28726
28727
28728
28729
28730
28731
28732 public static function getSubscribedEvents();
28733 }
28734 <?php
28735
28736
28737
28738
28739
28740
28741
28742
28743
28744
28745
28746 namespace Composer\EventDispatcher;
28747
28748
28749
28750
28751
28752
28753 class Event
28754 {
28755
28756
28757
28758 protected $name;
28759
28760
28761
28762
28763 protected $args;
28764
28765
28766
28767
28768 protected $flags;
28769
28770
28771
28772
28773 private $propagationStopped = false;
28774
28775
28776
28777
28778
28779
28780
28781
28782 public function __construct($name, array $args = array(), array $flags = array())
28783 {
28784 $this->name = $name;
28785 $this->args = $args;
28786 $this->flags = $flags;
28787 }
28788
28789
28790
28791
28792
28793
28794 public function getName()
28795 {
28796 return $this->name;
28797 }
28798
28799
28800
28801
28802
28803
28804 public function getArguments()
28805 {
28806 return $this->args;
28807 }
28808
28809
28810
28811
28812
28813
28814 public function getFlags()
28815 {
28816 return $this->flags;
28817 }
28818
28819
28820
28821
28822
28823
28824 public function isPropagationStopped()
28825 {
28826 return $this->propagationStopped;
28827 }
28828
28829
28830
28831
28832 public function stopPropagation()
28833 {
28834 $this->propagationStopped = true;
28835 }
28836 }
28837 <?php
28838
28839
28840
28841
28842
28843
28844
28845
28846
28847
28848
28849 namespace Composer\EventDispatcher;
28850
28851 use Composer\DependencyResolver\PolicyInterface;
28852 use Composer\DependencyResolver\Pool;
28853 use Composer\DependencyResolver\Request;
28854 use Composer\Installer\InstallerEvent;
28855 use Composer\IO\IOInterface;
28856 use Composer\Composer;
28857 use Composer\DependencyResolver\Operation\OperationInterface;
28858 use Composer\Repository\CompositeRepository;
28859 use Composer\Script;
28860 use Composer\Script\CommandEvent;
28861 use Composer\Script\PackageEvent;
28862 use Composer\Util\ProcessExecutor;
28863
28864
28865
28866
28867
28868
28869
28870
28871
28872
28873
28874
28875
28876
28877 class EventDispatcher
28878 {
28879 protected $composer;
28880 protected $io;
28881 protected $loader;
28882 protected $process;
28883
28884
28885
28886
28887
28888
28889
28890
28891 public function __construct(Composer $composer, IOInterface $io, ProcessExecutor $process = null)
28892 {
28893 $this->composer = $composer;
28894 $this->io = $io;
28895 $this->process = $process ?: new ProcessExecutor($io);
28896 }
28897
28898
28899
28900
28901
28902
28903
28904
28905
28906 public function dispatch($eventName, Event $event = null)
28907 {
28908 if (null == $event) {
28909 $event = new Event($eventName);
28910 }
28911
28912 return $this->doDispatch($event);
28913 }
28914
28915
28916
28917
28918
28919
28920
28921
28922
28923
28924
28925 public function dispatchScript($eventName, $devMode = false, $additionalArgs = array(), $flags = array())
28926 {
28927 return $this->doDispatch(new Script\Event($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
28928 }
28929
28930
28931
28932
28933
28934
28935
28936
28937
28938
28939 public function dispatchPackageEvent($eventName, $devMode, OperationInterface $operation)
28940 {
28941 return $this->doDispatch(new PackageEvent($eventName, $this->composer, $this->io, $devMode, $operation));
28942 }
28943
28944
28945
28946
28947
28948
28949
28950
28951
28952
28953
28954 public function dispatchCommandEvent($eventName, $devMode, $additionalArgs = array(), $flags = array())
28955 {
28956 return $this->doDispatch(new CommandEvent($eventName, $this->composer, $this->io, $devMode, $additionalArgs, $flags));
28957 }
28958
28959
28960
28961
28962
28963
28964
28965
28966
28967
28968
28969
28970
28971
28972 public function dispatchInstallerEvent($eventName, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
28973 {
28974 return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $policy, $pool, $installedRepo, $request, $operations));
28975 }
28976
28977
28978
28979
28980
28981
28982
28983
28984
28985
28986
28987 protected function doDispatch(Event $event)
28988 {
28989 $listeners = $this->getListeners($event);
28990
28991 $return = 0;
28992 foreach ($listeners as $callable) {
28993 if (!is_string($callable) && is_callable($callable)) {
28994 $event = $this->checkListenerExpectedEvent($callable, $event);
28995 $return = false === call_user_func($callable, $event) ? 1 : 0;
28996 } elseif ($this->isPhpScript($callable)) {
28997 $className = substr($callable, 0, strpos($callable, '::'));
28998 $methodName = substr($callable, strpos($callable, '::') + 2);
28999
29000 if (!class_exists($className)) {
29001 $this->io->write('<warning>Class '.$className.' is not autoloadable, can not call '.$event->getName().' script</warning>');
29002 continue;
29003 }
29004 if (!is_callable($callable)) {
29005 $this->io->write('<warning>Method '.$callable.' is not callable, can not call '.$event->getName().' script</warning>');
29006 continue;
29007 }
29008
29009 try {
29010 $return = false === $this->executeEventPhpScript($className, $methodName, $event) ? 1 : 0;
29011 } catch (\Exception $e) {
29012 $message = "Script %s handling the %s event terminated with an exception";
29013 $this->io->write('<error>'.sprintf($message, $callable, $event->getName()).'</error>');
29014 throw $e;
29015 }
29016 } else {
29017 $args = implode(' ', array_map(array('Composer\Util\ProcessExecutor','escape'), $event->getArguments()));
29018 if (0 !== ($exitCode = $this->process->execute($callable . ($args === '' ? '' : ' '.$args)))) {
29019 $this->io->write(sprintf('<error>Script %s handling the %s event returned with an error</error>', $callable, $event->getName()));
29020
29021 throw new \RuntimeException('Error Output: '.$this->process->getErrorOutput(), $exitCode);
29022 }
29023 }
29024
29025 if ($event->isPropagationStopped()) {
29026 break;
29027 }
29028 }
29029
29030 return $return;
29031 }
29032
29033
29034
29035
29036
29037
29038 protected function executeEventPhpScript($className, $methodName, Event $event)
29039 {
29040 $event = $this->checkListenerExpectedEvent(array($className, $methodName), $event);
29041
29042 return $className::$methodName($event);
29043 }
29044
29045
29046
29047
29048
29049
29050 protected function checkListenerExpectedEvent($target, Event $event)
29051 {
29052 if (!$event instanceof Script\Event) {
29053 return $event;
29054 }
29055
29056 try {
29057 $reflected = new \ReflectionParameter($target, 0);
29058 } catch (\Exception $e) {
29059 return $event;
29060 }
29061
29062 $typehint = $reflected->getClass();
29063
29064 if (!$typehint instanceof \ReflectionClass) {
29065 return $event;
29066 }
29067
29068 $expected = $typehint->getName();
29069
29070 if (!$event instanceof $expected && $expected === 'Composer\Script\CommandEvent') {
29071 $event = new CommandEvent($event->getName(), $event->getComposer(), $event->getIO(), $event->isDevMode(), $event->getArguments());
29072 }
29073
29074 return $event;
29075 }
29076
29077
29078
29079
29080
29081
29082
29083
29084 protected function addListener($eventName, $listener, $priority = 0)
29085 {
29086 $this->listeners[$eventName][$priority][] = $listener;
29087 }
29088
29089
29090
29091
29092
29093
29094
29095
29096 public function addSubscriber(EventSubscriberInterface $subscriber)
29097 {
29098 foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
29099 if (is_string($params)) {
29100 $this->addListener($eventName, array($subscriber, $params));
29101 } elseif (is_string($params[0])) {
29102 $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
29103 } else {
29104 foreach ($params as $listener) {
29105 $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
29106 }
29107 }
29108 }
29109 }
29110
29111
29112
29113
29114
29115
29116
29117 protected function getListeners(Event $event)
29118 {
29119 $scriptListeners = $this->getScriptListeners($event);
29120
29121 if (!isset($this->listeners[$event->getName()][0])) {
29122 $this->listeners[$event->getName()][0] = array();
29123 }
29124 krsort($this->listeners[$event->getName()]);
29125
29126 $listeners = $this->listeners;
29127 $listeners[$event->getName()][0] = array_merge($listeners[$event->getName()][0], $scriptListeners);
29128
29129 return call_user_func_array('array_merge', $listeners[$event->getName()]);
29130 }
29131
29132
29133
29134
29135
29136
29137
29138 public function hasEventListeners(Event $event)
29139 {
29140 $listeners = $this->getListeners($event);
29141
29142 return count($listeners) > 0;
29143 }
29144
29145
29146
29147
29148
29149
29150
29151 protected function getScriptListeners(Event $event)
29152 {
29153 $package = $this->composer->getPackage();
29154 $scripts = $package->getScripts();
29155
29156 if (empty($scripts[$event->getName()])) {
29157 return array();
29158 }
29159
29160 if ($this->loader) {
29161 $this->loader->unregister();
29162 }
29163
29164 $generator = $this->composer->getAutoloadGenerator();
29165 $packages = $this->composer->getRepositoryManager()->getLocalRepository()->getCanonicalPackages();
29166 $packageMap = $generator->buildPackageMap($this->composer->getInstallationManager(), $package, $packages);
29167 $map = $generator->parseAutoloads($packageMap, $package);
29168 $this->loader = $generator->createLoader($map);
29169 $this->loader->register();
29170
29171 return $scripts[$event->getName()];
29172 }
29173
29174
29175
29176
29177
29178
29179
29180 protected function isPhpScript($callable)
29181 {
29182 return false === strpos($callable, ' ') && false !== strpos($callable, '::');
29183 }
29184 }
29185 <?php
29186
29187
29188
29189
29190
29191
29192
29193
29194
29195
29196
29197 namespace Composer\Script;
29198
29199 use Composer\Composer;
29200 use Composer\IO\IOInterface;
29201 use Composer\EventDispatcher\Event as BaseEvent;
29202
29203
29204
29205
29206
29207
29208
29209 class Event extends BaseEvent
29210 {
29211
29212
29213
29214 private $composer;
29215
29216
29217
29218
29219 private $io;
29220
29221
29222
29223
29224 private $devMode;
29225
29226
29227
29228
29229
29230
29231
29232
29233
29234
29235
29236 public function __construct($name, Composer $composer, IOInterface $io, $devMode = false, array $args = array(), array $flags = array())
29237 {
29238 parent::__construct($name, $args, $flags);
29239 $this->composer = $composer;
29240 $this->io = $io;
29241 $this->devMode = $devMode;
29242 }
29243
29244
29245
29246
29247
29248
29249 public function getComposer()
29250 {
29251 return $this->composer;
29252 }
29253
29254
29255
29256
29257
29258
29259 public function getIO()
29260 {
29261 return $this->io;
29262 }
29263
29264
29265
29266
29267
29268
29269 public function isDevMode()
29270 {
29271 return $this->devMode;
29272 }
29273 }
29274 <?php
29275
29276
29277
29278
29279
29280
29281
29282
29283
29284
29285
29286 namespace Composer\Script;
29287
29288
29289
29290
29291
29292
29293
29294 class ScriptEvents
29295 {
29296
29297
29298
29299
29300
29301
29302
29303 const PRE_INSTALL_CMD = 'pre-install-cmd';
29304
29305
29306
29307
29308
29309
29310
29311
29312 const POST_INSTALL_CMD = 'post-install-cmd';
29313
29314
29315
29316
29317
29318
29319
29320
29321 const PRE_UPDATE_CMD = 'pre-update-cmd';
29322
29323
29324
29325
29326
29327
29328
29329
29330 const POST_UPDATE_CMD = 'post-update-cmd';
29331
29332
29333
29334
29335
29336
29337
29338
29339 const PRE_STATUS_CMD = 'pre-status-cmd';
29340
29341
29342
29343
29344
29345
29346
29347
29348 const POST_STATUS_CMD = 'post-status-cmd';
29349
29350
29351
29352
29353
29354
29355
29356
29357 const PRE_PACKAGE_INSTALL = 'pre-package-install';
29358
29359
29360
29361
29362
29363
29364
29365
29366 const POST_PACKAGE_INSTALL = 'post-package-install';
29367
29368
29369
29370
29371
29372
29373
29374
29375 const PRE_PACKAGE_UPDATE = 'pre-package-update';
29376
29377
29378
29379
29380
29381
29382
29383
29384 const POST_PACKAGE_UPDATE = 'post-package-update';
29385
29386
29387
29388
29389
29390
29391
29392
29393 const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall';
29394
29395
29396
29397
29398
29399
29400
29401
29402 const POST_PACKAGE_UNINSTALL = 'post-package-uninstall';
29403
29404
29405
29406
29407
29408
29409
29410
29411 const PRE_AUTOLOAD_DUMP = 'pre-autoload-dump';
29412
29413
29414
29415
29416
29417
29418
29419
29420 const POST_AUTOLOAD_DUMP = 'post-autoload-dump';
29421
29422
29423
29424
29425
29426
29427
29428
29429 const POST_ROOT_PACKAGE_INSTALL = 'post-root-package-install';
29430
29431
29432
29433
29434
29435
29436
29437
29438
29439 const POST_CREATE_PROJECT_CMD = 'post-create-project-cmd';
29440
29441
29442
29443
29444
29445
29446
29447
29448 const PRE_ARCHIVE_CMD = 'pre-archive-cmd';
29449
29450
29451
29452
29453
29454
29455
29456
29457 const POST_ARCHIVE_CMD = 'post-archive-cmd';
29458 }
29459 <?php
29460
29461
29462
29463
29464
29465
29466
29467
29468
29469
29470
29471 namespace Composer\Script;
29472
29473
29474
29475
29476
29477
29478 class CommandEvent extends Event
29479 {
29480 }
29481 <?php
29482
29483
29484
29485
29486
29487
29488
29489
29490
29491
29492
29493 namespace Composer\Script;
29494
29495 use Composer\Composer;
29496 use Composer\IO\IOInterface;
29497 use Composer\DependencyResolver\Operation\OperationInterface;
29498
29499
29500
29501
29502
29503
29504 class PackageEvent extends Event
29505 {
29506
29507
29508
29509 private $operation;
29510
29511
29512
29513
29514
29515
29516
29517
29518
29519
29520 public function __construct($name, Composer $composer, IOInterface $io, $devMode, OperationInterface $operation)
29521 {
29522 parent::__construct($name, $composer, $io, $devMode);
29523 $this->operation = $operation;
29524 }
29525
29526
29527
29528
29529
29530
29531 public function getOperation()
29532 {
29533 return $this->operation;
29534 }
29535 }
29536 <?php
29537
29538
29539
29540
29541
29542
29543
29544
29545
29546
29547
29548 namespace Composer\Installer;
29549
29550 use Composer\Composer;
29551 use Composer\DependencyResolver\PolicyInterface;
29552 use Composer\DependencyResolver\Operation\OperationInterface;
29553 use Composer\DependencyResolver\Pool;
29554 use Composer\DependencyResolver\Request;
29555 use Composer\EventDispatcher\Event;
29556 use Composer\IO\IOInterface;
29557 use Composer\Repository\CompositeRepository;
29558
29559
29560
29561
29562
29563
29564 class InstallerEvent extends Event
29565 {
29566
29567
29568
29569 private $composer;
29570
29571
29572
29573
29574 private $io;
29575
29576
29577
29578
29579 private $policy;
29580
29581
29582
29583
29584 private $pool;
29585
29586
29587
29588
29589 private $installedRepo;
29590
29591
29592
29593
29594 private $request;
29595
29596
29597
29598
29599 private $operations;
29600
29601
29602
29603
29604
29605
29606
29607
29608
29609
29610
29611
29612
29613 public function __construct($eventName, Composer $composer, IOInterface $io, PolicyInterface $policy, Pool $pool, CompositeRepository $installedRepo, Request $request, array $operations = array())
29614 {
29615 parent::__construct($eventName);
29616
29617 $this->composer = $composer;
29618 $this->io = $io;
29619 $this->policy = $policy;
29620 $this->pool = $pool;
29621 $this->installedRepo = $installedRepo;
29622 $this->request = $request;
29623 $this->operations = $operations;
29624 }
29625
29626
29627
29628
29629 public function getComposer()
29630 {
29631 return $this->composer;
29632 }
29633
29634
29635
29636
29637 public function getIO()
29638 {
29639 return $this->io;
29640 }
29641
29642
29643
29644
29645 public function getPolicy()
29646 {
29647 return $this->policy;
29648 }
29649
29650
29651
29652
29653 public function getPool()
29654 {
29655 return $this->pool;
29656 }
29657
29658
29659
29660
29661 public function getInstalledRepo()
29662 {
29663 return $this->installedRepo;
29664 }
29665
29666
29667
29668
29669 public function getRequest()
29670 {
29671 return $this->request;
29672 }
29673
29674
29675
29676
29677 public function getOperations()
29678 {
29679 return $this->operations;
29680 }
29681 }
29682 <?php
29683
29684
29685
29686
29687
29688
29689
29690
29691
29692
29693
29694 namespace Composer\Installer;
29695
29696 use Composer\Repository\InstalledRepositoryInterface;
29697 use Composer\Package\PackageInterface;
29698
29699
29700
29701
29702
29703
29704
29705
29706 class NoopInstaller implements InstallerInterface
29707 {
29708
29709
29710
29711 public function supports($packageType)
29712 {
29713 return true;
29714 }
29715
29716
29717
29718
29719 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
29720 {
29721 return $repo->hasPackage($package);
29722 }
29723
29724
29725
29726
29727 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
29728 {
29729 if (!$repo->hasPackage($package)) {
29730 $repo->addPackage(clone $package);
29731 }
29732 }
29733
29734
29735
29736
29737 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
29738 {
29739 if (!$repo->hasPackage($initial)) {
29740 throw new \InvalidArgumentException('Package is not installed: '.$initial);
29741 }
29742
29743 $repo->removePackage($initial);
29744 if (!$repo->hasPackage($target)) {
29745 $repo->addPackage(clone $target);
29746 }
29747 }
29748
29749
29750
29751
29752 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
29753 {
29754 if (!$repo->hasPackage($package)) {
29755 throw new \InvalidArgumentException('Package is not installed: '.$package);
29756 }
29757 $repo->removePackage($package);
29758 }
29759
29760
29761
29762
29763 public function getInstallPath(PackageInterface $package)
29764 {
29765 $targetDir = $package->getTargetDir();
29766
29767 return $package->getPrettyName() . ($targetDir ? '/'.$targetDir : '');
29768 }
29769 }
29770 <?php
29771
29772
29773
29774
29775
29776
29777
29778
29779
29780
29781
29782 namespace Composer\Installer;
29783
29784 use Composer\Repository\InstalledRepositoryInterface;
29785 use Composer\Package\PackageInterface;
29786
29787
29788
29789
29790
29791
29792 class MetapackageInstaller implements InstallerInterface
29793 {
29794
29795
29796
29797 public function supports($packageType)
29798 {
29799 return $packageType === 'metapackage';
29800 }
29801
29802
29803
29804
29805 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
29806 {
29807 return $repo->hasPackage($package);
29808 }
29809
29810
29811
29812
29813 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
29814 {
29815 $repo->addPackage(clone $package);
29816 }
29817
29818
29819
29820
29821 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
29822 {
29823 if (!$repo->hasPackage($initial)) {
29824 throw new \InvalidArgumentException('Package is not installed: '.$initial);
29825 }
29826
29827 $repo->removePackage($initial);
29828 $repo->addPackage(clone $target);
29829 }
29830
29831
29832
29833
29834 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
29835 {
29836 if (!$repo->hasPackage($package)) {
29837 throw new \InvalidArgumentException('Package is not installed: '.$package);
29838 }
29839
29840 $repo->removePackage($package);
29841 }
29842
29843
29844
29845
29846 public function getInstallPath(PackageInterface $package)
29847 {
29848 return '';
29849 }
29850 }
29851 <?php
29852
29853
29854
29855
29856
29857
29858
29859
29860
29861
29862
29863 namespace Composer\Installer;
29864
29865 use Composer\IO\IOInterface;
29866 use Composer\Composer;
29867 use Composer\Downloader\PearPackageExtractor;
29868 use Composer\Repository\InstalledRepositoryInterface;
29869 use Composer\Package\PackageInterface;
29870 use Composer\Util\ProcessExecutor;
29871
29872
29873
29874
29875
29876
29877
29878 class PearInstaller extends LibraryInstaller
29879 {
29880
29881
29882
29883
29884
29885
29886
29887 public function __construct(IOInterface $io, Composer $composer, $type = 'pear-library')
29888 {
29889 parent::__construct($io, $composer, $type);
29890 }
29891
29892
29893
29894
29895 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
29896 {
29897 $this->uninstall($repo, $initial);
29898 $this->install($repo, $target);
29899 }
29900
29901 protected function installCode(PackageInterface $package)
29902 {
29903 parent::installCode($package);
29904 parent::initializeBinDir();
29905
29906 $isWindows = defined('PHP_WINDOWS_VERSION_BUILD');
29907 $php_bin = $this->binDir . ($isWindows ? '/composer-php.bat' : '/composer-php');
29908
29909 if (!$isWindows) {
29910 $php_bin = '/usr/bin/env ' . $php_bin;
29911 }
29912
29913 $installPath = $this->getInstallPath($package);
29914 $vars = array(
29915 'os' => $isWindows ? 'windows' : 'linux',
29916 'php_bin' => $php_bin,
29917 'pear_php' => $installPath,
29918 'php_dir' => $installPath,
29919 'bin_dir' => $installPath . '/bin',
29920 'data_dir' => $installPath . '/data',
29921 'version' => $package->getPrettyVersion(),
29922 );
29923
29924 $packageArchive = $this->getInstallPath($package).'/'.pathinfo($package->getDistUrl(), PATHINFO_BASENAME);
29925 $pearExtractor = new PearPackageExtractor($packageArchive);
29926 $pearExtractor->extractTo($this->getInstallPath($package), array('php' => '/', 'script' => '/bin', 'data' => '/data'), $vars);
29927
29928 if ($this->io->isVerbose()) {
29929 $this->io->write('    Cleaning up');
29930 }
29931 $this->filesystem->unlink($packageArchive);
29932 }
29933
29934 protected function getBinaries(PackageInterface $package)
29935 {
29936 $binariesPath = $this->getInstallPath($package) . '/bin/';
29937 $binaries = array();
29938 if (file_exists($binariesPath)) {
29939 foreach (new \FilesystemIterator($binariesPath, \FilesystemIterator::KEY_AS_FILENAME | \FilesystemIterator::CURRENT_AS_FILEINFO) as $fileName => $value) {
29940 if (!$value->isDir()) {
29941 $binaries[] = 'bin/'.$fileName;
29942 }
29943 }
29944 }
29945
29946 return $binaries;
29947 }
29948
29949 protected function initializeBinDir()
29950 {
29951 parent::initializeBinDir();
29952 file_put_contents($this->binDir.'/composer-php', $this->generateUnixyPhpProxyCode());
29953 @chmod($this->binDir.'/composer-php', 0777);
29954 file_put_contents($this->binDir.'/composer-php.bat', $this->generateWindowsPhpProxyCode());
29955 @chmod($this->binDir.'/composer-php.bat', 0777);
29956 }
29957
29958 protected function generateWindowsProxyCode($bin, $link)
29959 {
29960 $binPath = $this->filesystem->findShortestPath($link, $bin);
29961 if ('.bat' === substr($bin, -4)) {
29962 $caller = 'call';
29963 } else {
29964 $handle = fopen($bin, 'r');
29965 $line = fgets($handle);
29966 fclose($handle);
29967 if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
29968 $caller = trim($match[1]);
29969 } else {
29970 $caller = 'php';
29971 }
29972
29973 if ($caller === 'php') {
29974 return "@echo off\r\n".
29975 "pushd .\r\n".
29976 "cd %~dp0\r\n".
29977 "set PHP_PROXY=%CD%\\composer-php.bat\r\n".
29978 "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n".
29979 "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n".
29980 "popd\r\n".
29981 "%PHP_PROXY% \"%BIN_TARGET%\" %*\r\n";
29982 }
29983 }
29984
29985 return "@echo off\r\n".
29986 "pushd .\r\n".
29987 "cd %~dp0\r\n".
29988 "cd ".ProcessExecutor::escape(dirname($binPath))."\r\n".
29989 "set BIN_TARGET=%CD%\\".basename($binPath)."\r\n".
29990 "popd\r\n".
29991 $caller." \"%BIN_TARGET%\" %*\r\n";
29992 }
29993
29994 private function generateWindowsPhpProxyCode()
29995 {
29996 $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true);
29997
29998 return
29999 "@echo off\r\n" .
30000 "setlocal enabledelayedexpansion\r\n" .
30001 "set BIN_DIR=%~dp0\r\n" .
30002 "set VENDOR_DIR=%BIN_DIR%\\".$binToVendor."\r\n" .
30003 "set DIRS=.\r\n" .
30004 "FOR /D %%V IN (%VENDOR_DIR%\\*) DO (\r\n" .
30005 "    FOR /D %%P IN (%%V\\*) DO (\r\n" .
30006 "        set DIRS=!DIRS!;%%~fP\r\n" .
30007 "    )\r\n" .
30008 ")\r\n" .
30009 "php.exe -d include_path=!DIRS! %*\r\n";
30010 }
30011
30012 private function generateUnixyPhpProxyCode()
30013 {
30014 $binToVendor = $this->filesystem->findShortestPath($this->binDir, $this->vendorDir, true);
30015
30016 return
30017 "#!/usr/bin/env sh\n".
30018 "SRC_DIR=`pwd`\n".
30019 "BIN_DIR=`dirname $0`\n".
30020 "VENDOR_DIR=\$BIN_DIR/".escapeshellarg($binToVendor)."\n".
30021 "DIRS=\"\"\n".
30022 "for vendor in \$VENDOR_DIR/*; do\n".
30023 "    if [ -d \"\$vendor\" ]; then\n".
30024 "        for package in \$vendor/*; do\n".
30025 "            if [ -d \"\$package\" ]; then\n".
30026 "                DIRS=\"\${DIRS}:\${package}\"\n".
30027 "            fi\n".
30028 "        done\n".
30029 "    fi\n".
30030 "done\n".
30031 "php -d include_path=\".\$DIRS\" $@\n";
30032 }
30033 }
30034 <?php
30035
30036
30037
30038
30039
30040
30041
30042
30043
30044
30045
30046 namespace Composer\Installer;
30047
30048 use Composer\Package\PackageInterface;
30049 use Composer\Downloader\DownloadManager;
30050 use Composer\Repository\InstalledRepositoryInterface;
30051 use Composer\Util\Filesystem;
30052
30053
30054
30055
30056
30057
30058
30059 class ProjectInstaller implements InstallerInterface
30060 {
30061 private $installPath;
30062 private $downloadManager;
30063 private $filesystem;
30064
30065 public function __construct($installPath, DownloadManager $dm)
30066 {
30067 $this->installPath = rtrim(strtr($installPath, '\\', '/'), '/').'/';
30068 $this->downloadManager = $dm;
30069 $this->filesystem = new Filesystem;
30070 }
30071
30072
30073
30074
30075
30076
30077
30078 public function supports($packageType)
30079 {
30080 return true;
30081 }
30082
30083
30084
30085
30086 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
30087 {
30088 return false;
30089 }
30090
30091
30092
30093
30094 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
30095 {
30096 $installPath = $this->installPath;
30097 if (file_exists($installPath) && !$this->filesystem->isDirEmpty($installPath)) {
30098 throw new \InvalidArgumentException("Project directory $installPath is not empty.");
30099 }
30100 if (!is_dir($installPath)) {
30101 mkdir($installPath, 0777, true);
30102 }
30103 $this->downloadManager->download($package, $installPath);
30104 }
30105
30106
30107
30108
30109 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
30110 {
30111 throw new \InvalidArgumentException("not supported");
30112 }
30113
30114
30115
30116
30117 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
30118 {
30119 throw new \InvalidArgumentException("not supported");
30120 }
30121
30122
30123
30124
30125
30126
30127
30128 public function getInstallPath(PackageInterface $package)
30129 {
30130 return $this->installPath;
30131 }
30132 }
30133 <?php
30134
30135
30136
30137
30138
30139
30140
30141
30142
30143
30144
30145 namespace Composer\Installer;
30146
30147 use Composer\Composer;
30148 use Composer\IO\IOInterface;
30149 use Composer\Repository\InstalledRepositoryInterface;
30150 use Composer\Package\PackageInterface;
30151 use Composer\Util\Filesystem;
30152 use Composer\Util\ProcessExecutor;
30153
30154
30155
30156
30157
30158
30159
30160 class LibraryInstaller implements InstallerInterface
30161 {
30162 protected $composer;
30163 protected $vendorDir;
30164 protected $binDir;
30165 protected $downloadManager;
30166 protected $io;
30167 protected $type;
30168 protected $filesystem;
30169
30170
30171
30172
30173
30174
30175
30176
30177
30178 public function __construct(IOInterface $io, Composer $composer, $type = 'library', Filesystem $filesystem = null)
30179 {
30180 $this->composer = $composer;
30181 $this->downloadManager = $composer->getDownloadManager();
30182 $this->io = $io;
30183 $this->type = $type;
30184
30185 $this->filesystem = $filesystem ?: new Filesystem();
30186 $this->vendorDir = rtrim($composer->getConfig()->get('vendor-dir'), '/');
30187 $this->binDir = rtrim($composer->getConfig()->get('bin-dir'), '/');
30188 }
30189
30190
30191
30192
30193 public function supports($packageType)
30194 {
30195 return $packageType === $this->type || null === $this->type;
30196 }
30197
30198
30199
30200
30201 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
30202 {
30203 return $repo->hasPackage($package) && is_readable($this->getInstallPath($package));
30204 }
30205
30206
30207
30208
30209 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
30210 {
30211 $this->initializeVendorDir();
30212 $downloadPath = $this->getInstallPath($package);
30213
30214
30215  if (!is_readable($downloadPath) && $repo->hasPackage($package)) {
30216 $this->removeBinaries($package);
30217 }
30218
30219 $this->installCode($package);
30220 $this->installBinaries($package);
30221 if (!$repo->hasPackage($package)) {
30222 $repo->addPackage(clone $package);
30223 }
30224 }
30225
30226
30227
30228
30229 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
30230 {
30231 if (!$repo->hasPackage($initial)) {
30232 throw new \InvalidArgumentException('Package is not installed: '.$initial);
30233 }
30234
30235 $this->initializeVendorDir();
30236
30237 $this->removeBinaries($initial);
30238 $this->updateCode($initial, $target);
30239 $this->installBinaries($target);
30240 $repo->removePackage($initial);
30241 if (!$repo->hasPackage($target)) {
30242 $repo->addPackage(clone $target);
30243 }
30244 }
30245
30246
30247
30248
30249 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
30250 {
30251 if (!$repo->hasPackage($package)) {
30252 throw new \InvalidArgumentException('Package is not installed: '.$package);
30253 }
30254
30255 $this->removeCode($package);
30256 $this->removeBinaries($package);
30257 $repo->removePackage($package);
30258
30259 $downloadPath = $this->getPackageBasePath($package);
30260 if (strpos($package->getName(), '/')) {
30261 $packageVendorDir = dirname($downloadPath);
30262 if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) {
30263 @rmdir($packageVendorDir);
30264 }
30265 }
30266 }
30267
30268
30269
30270
30271 public function getInstallPath(PackageInterface $package)
30272 {
30273 $targetDir = $package->getTargetDir();
30274
30275 return $this->getPackageBasePath($package) . ($targetDir ? '/'.$targetDir : '');
30276 }
30277
30278 protected function getPackageBasePath(PackageInterface $package)
30279 {
30280 $this->initializeVendorDir();
30281
30282 return ($this->vendorDir ? $this->vendorDir.'/' : '') . $package->getPrettyName();
30283 }
30284
30285 protected function installCode(PackageInterface $package)
30286 {
30287 $downloadPath = $this->getInstallPath($package);
30288 $this->downloadManager->download($package, $downloadPath);
30289 }
30290
30291 protected function updateCode(PackageInterface $initial, PackageInterface $target)
30292 {
30293 $initialDownloadPath = $this->getInstallPath($initial);
30294 $targetDownloadPath = $this->getInstallPath($target);
30295 if ($targetDownloadPath !== $initialDownloadPath) {
30296
30297  
30298  if (substr($initialDownloadPath, 0, strlen($targetDownloadPath)) === $targetDownloadPath
30299 || substr($targetDownloadPath, 0, strlen($initialDownloadPath)) === $initialDownloadPath
30300 ) {
30301 $this->removeCode($initial);
30302 $this->installCode($target);
30303
30304 return;
30305 }
30306
30307 $this->filesystem->rename($initialDownloadPath, $targetDownloadPath);
30308 }
30309 $this->downloadManager->update($initial, $target, $targetDownloadPath);
30310 }
30311
30312 protected function removeCode(PackageInterface $package)
30313 {
30314 $downloadPath = $this->getPackageBasePath($package);
30315 $this->downloadManager->remove($package, $downloadPath);
30316 }
30317
30318 protected function getBinaries(PackageInterface $package)
30319 {
30320 return $package->getBinaries();
30321 }
30322
30323 protected function installBinaries(PackageInterface $package)
30324 {
30325 $binaries = $this->getBinaries($package);
30326 if (!$binaries) {
30327 return;
30328 }
30329 foreach ($binaries as $bin) {
30330 $binPath = $this->getInstallPath($package).'/'.$bin;
30331 if (!file_exists($binPath)) {
30332 $this->io->write('    <warning>Skipped installation of bin '.$bin.' for package '.$package->getName().': file not found in package</warning>');
30333 continue;
30334 }
30335
30336
30337  
30338  
30339  
30340  $binPath = realpath($binPath);
30341
30342 $this->initializeBinDir();
30343 $link = $this->binDir.'/'.basename($bin);
30344 if (file_exists($link)) {
30345 if (is_link($link)) {
30346
30347  
30348  
30349  @chmod($link, 0777 & ~umask());
30350 }
30351 $this->io->write('    Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
30352 continue;
30353 }
30354 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
30355
30356  if ('.bat' !== substr($binPath, -4)) {
30357 file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link));
30358 @chmod($link, 0777 & ~umask());
30359 $link .= '.bat';
30360 if (file_exists($link)) {
30361 $this->io->write('    Skipped installation of bin '.$bin.'.bat proxy for package '.$package->getName().': a .bat proxy was already installed');
30362 }
30363 }
30364 if (!file_exists($link)) {
30365 file_put_contents($link, $this->generateWindowsProxyCode($binPath, $link));
30366 }
30367 } else {
30368 $cwd = getcwd();
30369 try {
30370
30371  
30372  $relativeBin = $this->filesystem->findShortestPath($link, $binPath);
30373 chdir(dirname($link));
30374 if (false === symlink($relativeBin, $link)) {
30375 throw new \ErrorException();
30376 }
30377 } catch (\ErrorException $e) {
30378 file_put_contents($link, $this->generateUnixyProxyCode($binPath, $link));
30379 }
30380 chdir($cwd);
30381 }
30382 @chmod($link, 0777 & ~umask());
30383 }
30384 }
30385
30386 protected function removeBinaries(PackageInterface $package)
30387 {
30388 $binaries = $this->getBinaries($package);
30389 if (!$binaries) {
30390 return;
30391 }
30392 foreach ($binaries as $bin) {
30393 $link = $this->binDir.'/'.basename($bin);
30394 if (is_link($link) || file_exists($link)) {
30395 $this->filesystem->unlink($link);
30396 }
30397 if (file_exists($link.'.bat')) {
30398 $this->filesystem->unlink($link.'.bat');
30399 }
30400 }
30401 }
30402
30403 protected function initializeVendorDir()
30404 {
30405 $this->filesystem->ensureDirectoryExists($this->vendorDir);
30406 $this->vendorDir = realpath($this->vendorDir);
30407 }
30408
30409 protected function initializeBinDir()
30410 {
30411 $this->filesystem->ensureDirectoryExists($this->binDir);
30412 $this->binDir = realpath($this->binDir);
30413 }
30414
30415 protected function generateWindowsProxyCode($bin, $link)
30416 {
30417 $binPath = $this->filesystem->findShortestPath($link, $bin);
30418 if ('.bat' === substr($bin, -4) || '.exe' === substr($bin, -4)) {
30419 $caller = 'call';
30420 } else {
30421 $handle = fopen($bin, 'r');
30422 $line = fgets($handle);
30423 fclose($handle);
30424 if (preg_match('{^#!/(?:usr/bin/env )?(?:[^/]+/)*(.+)$}m', $line, $match)) {
30425 $caller = trim($match[1]);
30426 } else {
30427 $caller = 'php';
30428 }
30429 }
30430
30431 return "@ECHO OFF\r\n".
30432 "SET BIN_TARGET=%~dp0/".trim(ProcessExecutor::escape($binPath), '"')."\r\n".
30433 "{$caller} \"%BIN_TARGET%\" %*\r\n";
30434 }
30435
30436 protected function generateUnixyProxyCode($bin, $link)
30437 {
30438 $binPath = $this->filesystem->findShortestPath($link, $bin);
30439
30440 return "#!/usr/bin/env sh\n".
30441 'SRC_DIR="`pwd`"'."\n".
30442 'cd "`dirname "$0"`"'."\n".
30443 'cd '.ProcessExecutor::escape(dirname($binPath))."\n".
30444 'BIN_TARGET="`pwd`/'.basename($binPath)."\"\n".
30445 'cd "$SRC_DIR"'."\n".
30446 '"$BIN_TARGET" "$@"'."\n";
30447 }
30448 }
30449 <?php
30450
30451
30452
30453
30454
30455
30456
30457
30458
30459
30460
30461 namespace Composer\Installer;
30462
30463 use Composer\Package\PackageInterface;
30464 use Composer\Package\AliasPackage;
30465 use Composer\Repository\RepositoryInterface;
30466 use Composer\Repository\InstalledRepositoryInterface;
30467 use Composer\DependencyResolver\Operation\OperationInterface;
30468 use Composer\DependencyResolver\Operation\InstallOperation;
30469 use Composer\DependencyResolver\Operation\UpdateOperation;
30470 use Composer\DependencyResolver\Operation\UninstallOperation;
30471 use Composer\DependencyResolver\Operation\MarkAliasInstalledOperation;
30472 use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
30473 use Composer\Util\StreamContextFactory;
30474
30475
30476
30477
30478
30479
30480
30481
30482 class InstallationManager
30483 {
30484 private $installers = array();
30485 private $cache = array();
30486 private $notifiablePackages = array();
30487
30488 public function reset()
30489 {
30490 $this->notifiablePackages = array();
30491 }
30492
30493
30494
30495
30496
30497
30498 public function addInstaller(InstallerInterface $installer)
30499 {
30500 array_unshift($this->installers, $installer);
30501 $this->cache = array();
30502 }
30503
30504
30505
30506
30507
30508
30509 public function removeInstaller(InstallerInterface $installer)
30510 {
30511 if (false !== ($key = array_search($installer, $this->installers, true))) {
30512 array_splice($this->installers, $key, 1);
30513 $this->cache = array();
30514 }
30515 }
30516
30517
30518
30519
30520
30521
30522
30523
30524 public function disablePlugins()
30525 {
30526 foreach ($this->installers as $i => $installer) {
30527 if (!$installer instanceof PluginInstaller) {
30528 continue;
30529 }
30530
30531 unset($this->installers[$i]);
30532 }
30533 }
30534
30535
30536
30537
30538
30539
30540
30541
30542
30543
30544 public function getInstaller($type)
30545 {
30546 $type = strtolower($type);
30547
30548 if (isset($this->cache[$type])) {
30549 return $this->cache[$type];
30550 }
30551
30552 foreach ($this->installers as $installer) {
30553 if ($installer->supports($type)) {
30554 return $this->cache[$type] = $installer;
30555 }
30556 }
30557
30558 throw new \InvalidArgumentException('Unknown installer type: '.$type);
30559 }
30560
30561
30562
30563
30564
30565
30566
30567
30568
30569 public function isPackageInstalled(InstalledRepositoryInterface $repo, PackageInterface $package)
30570 {
30571 if ($package instanceof AliasPackage) {
30572 return $repo->hasPackage($package) && $this->isPackageInstalled($repo, $package->getAliasOf());
30573 }
30574
30575 return $this->getInstaller($package->getType())->isInstalled($repo, $package);
30576 }
30577
30578
30579
30580
30581
30582
30583
30584 public function execute(RepositoryInterface $repo, OperationInterface $operation)
30585 {
30586 $method = $operation->getJobType();
30587 $this->$method($repo, $operation);
30588 }
30589
30590
30591
30592
30593
30594
30595
30596 public function install(RepositoryInterface $repo, InstallOperation $operation)
30597 {
30598 $package = $operation->getPackage();
30599 $installer = $this->getInstaller($package->getType());
30600 $installer->install($repo, $package);
30601 $this->markForNotification($package);
30602 }
30603
30604
30605
30606
30607
30608
30609
30610 public function update(RepositoryInterface $repo, UpdateOperation $operation)
30611 {
30612 $initial = $operation->getInitialPackage();
30613 $target = $operation->getTargetPackage();
30614
30615 $initialType = $initial->getType();
30616 $targetType = $target->getType();
30617
30618 if ($initialType === $targetType) {
30619 $installer = $this->getInstaller($initialType);
30620 $installer->update($repo, $initial, $target);
30621 $this->markForNotification($target);
30622 } else {
30623 $this->getInstaller($initialType)->uninstall($repo, $initial);
30624 $this->getInstaller($targetType)->install($repo, $target);
30625 }
30626 }
30627
30628
30629
30630
30631
30632
30633
30634 public function uninstall(RepositoryInterface $repo, UninstallOperation $operation)
30635 {
30636 $package = $operation->getPackage();
30637 $installer = $this->getInstaller($package->getType());
30638 $installer->uninstall($repo, $package);
30639 }
30640
30641
30642
30643
30644
30645
30646
30647 public function markAliasInstalled(RepositoryInterface $repo, MarkAliasInstalledOperation $operation)
30648 {
30649 $package = $operation->getPackage();
30650
30651 if (!$repo->hasPackage($package)) {
30652 $repo->addPackage(clone $package);
30653 }
30654 }
30655
30656
30657
30658
30659
30660
30661
30662 public function markAliasUninstalled(RepositoryInterface $repo, MarkAliasUninstalledOperation $operation)
30663 {
30664 $package = $operation->getPackage();
30665
30666 $repo->removePackage($package);
30667 }
30668
30669
30670
30671
30672
30673
30674
30675 public function getInstallPath(PackageInterface $package)
30676 {
30677 $installer = $this->getInstaller($package->getType());
30678
30679 return $installer->getInstallPath($package);
30680 }
30681
30682 public function notifyInstalls()
30683 {
30684 foreach ($this->notifiablePackages as $repoUrl => $packages) {
30685
30686  if (strpos($repoUrl, '%package%')) {
30687 foreach ($packages as $package) {
30688 $url = str_replace('%package%', $package->getPrettyName(), $repoUrl);
30689
30690 $params = array(
30691 'version' => $package->getPrettyVersion(),
30692 'version_normalized' => $package->getVersion(),
30693 );
30694 $opts = array('http' =>
30695 array(
30696 'method' => 'POST',
30697 'header' => array('Content-type: application/x-www-form-urlencoded'),
30698 'content' => http_build_query($params, '', '&'),
30699 'timeout' => 3,
30700 )
30701 );
30702
30703 $context = StreamContextFactory::getContext($url, $opts);
30704 @file_get_contents($url, false, $context);
30705 }
30706
30707 continue;
30708 }
30709
30710 $postData = array('downloads' => array());
30711 foreach ($packages as $package) {
30712 $postData['downloads'][] = array(
30713 'name' => $package->getPrettyName(),
30714 'version' => $package->getVersion(),
30715 );
30716 }
30717
30718 $opts = array('http' =>
30719 array(
30720 'method' => 'POST',
30721 'header' => array('Content-Type: application/json'),
30722 'content' => json_encode($postData),
30723 'timeout' => 6,
30724 )
30725 );
30726
30727 $context = StreamContextFactory::getContext($repoUrl, $opts);
30728 @file_get_contents($repoUrl, false, $context);
30729 }
30730
30731 $this->reset();
30732 }
30733
30734 private function markForNotification(PackageInterface $package)
30735 {
30736 if ($package->getNotificationUrl()) {
30737 $this->notifiablePackages[$package->getNotificationUrl()][$package->getName()] = $package;
30738 }
30739 }
30740 }
30741 <?php
30742
30743
30744
30745
30746
30747
30748
30749
30750
30751
30752
30753 namespace Composer\Installer;
30754
30755
30756
30757
30758
30759
30760 class InstallerEvents
30761 {
30762
30763
30764
30765
30766
30767
30768
30769
30770
30771 const PRE_DEPENDENCIES_SOLVING = 'pre-dependencies-solving';
30772
30773
30774
30775
30776
30777
30778
30779
30780
30781
30782 const POST_DEPENDENCIES_SOLVING = 'post-dependencies-solving';
30783 }
30784 <?php
30785
30786
30787
30788
30789
30790
30791
30792
30793
30794
30795
30796 namespace Composer\Installer;
30797
30798 use Composer\Composer;
30799 use Composer\Package\Package;
30800 use Composer\IO\IOInterface;
30801 use Composer\Repository\InstalledRepositoryInterface;
30802 use Composer\Package\PackageInterface;
30803
30804
30805
30806
30807
30808
30809
30810 class PluginInstaller extends LibraryInstaller
30811 {
30812 private $installationManager;
30813 private static $classCounter = 0;
30814
30815
30816
30817
30818
30819
30820
30821
30822 public function __construct(IOInterface $io, Composer $composer, $type = 'library')
30823 {
30824 parent::__construct($io, $composer, 'composer-plugin');
30825 $this->installationManager = $composer->getInstallationManager();
30826 }
30827
30828
30829
30830
30831 public function supports($packageType)
30832 {
30833 return $packageType === 'composer-plugin' || $packageType === 'composer-installer';
30834 }
30835
30836
30837
30838
30839 public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
30840 {
30841 $extra = $package->getExtra();
30842 if (empty($extra['class'])) {
30843 throw new \UnexpectedValueException('Error while installing '.$package->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
30844 }
30845
30846 parent::install($repo, $package);
30847 $this->composer->getPluginManager()->registerPackage($package, true);
30848 }
30849
30850
30851
30852
30853 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
30854 {
30855 $extra = $target->getExtra();
30856 if (empty($extra['class'])) {
30857 throw new \UnexpectedValueException('Error while installing '.$target->getPrettyName().', composer-plugin packages should have a class defined in their extra key to be usable.');
30858 }
30859
30860 parent::update($repo, $initial, $target);
30861 $this->composer->getPluginManager()->registerPackage($target, true);
30862 }
30863 }
30864 <?php
30865
30866
30867
30868
30869
30870
30871
30872
30873
30874
30875
30876 namespace Composer\Installer;
30877
30878 use Composer\Package\PackageInterface;
30879 use Composer\Repository\InstalledRepositoryInterface;
30880
30881
30882
30883
30884
30885
30886
30887 interface InstallerInterface
30888 {
30889
30890
30891
30892
30893
30894
30895 public function supports($packageType);
30896
30897
30898
30899
30900
30901
30902
30903
30904
30905 public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package);
30906
30907
30908
30909
30910
30911
30912
30913 public function install(InstalledRepositoryInterface $repo, PackageInterface $package);
30914
30915
30916
30917
30918
30919
30920
30921
30922
30923
30924 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target);
30925
30926
30927
30928
30929
30930
30931
30932 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package);
30933
30934
30935
30936
30937
30938
30939
30940 public function getInstallPath(PackageInterface $package);
30941 }
30942 <?php
30943
30944
30945
30946
30947
30948
30949
30950
30951
30952
30953
30954 namespace Composer\Console;
30955
30956 use Symfony\Component\Console\Application as BaseApplication;
30957 use Symfony\Component\Console\Input\InputInterface;
30958 use Symfony\Component\Console\Input\InputOption;
30959 use Symfony\Component\Console\Output\OutputInterface;
30960 use Symfony\Component\Console\Output\ConsoleOutput;
30961 use Symfony\Component\Console\Formatter\OutputFormatter;
30962 use Composer\Command;
30963 use Composer\Command\Helper\DialogHelper;
30964 use Composer\Composer;
30965 use Composer\Factory;
30966 use Composer\IO\IOInterface;
30967 use Composer\IO\ConsoleIO;
30968 use Composer\Json\JsonValidationException;
30969 use Composer\Util\ErrorHandler;
30970
30971
30972
30973
30974
30975
30976
30977
30978 class Application extends BaseApplication
30979 {
30980
30981
30982
30983 protected $composer;
30984
30985
30986
30987
30988 protected $io;
30989
30990 private static $logo = '   ______
30991   / ____/___  ____ ___  ____  ____  ________  _____
30992  / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
30993 / /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
30994 \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
30995                     /_/
30996 ';
30997
30998 public function __construct()
30999 {
31000 if (function_exists('ini_set') && extension_loaded('xdebug')) {
31001 ini_set('xdebug.show_exception_trace', false);
31002 ini_set('xdebug.scream', false);
31003 }
31004
31005 if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
31006 date_default_timezone_set(@date_default_timezone_get());
31007 }
31008
31009 ErrorHandler::register();
31010 parent::__construct('Composer', Composer::VERSION);
31011 }
31012
31013
31014
31015
31016 public function run(InputInterface $input = null, OutputInterface $output = null)
31017 {
31018 if (null === $output) {
31019 $styles = Factory::createAdditionalStyles();
31020 $formatter = new OutputFormatter(null, $styles);
31021 $output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, null, $formatter);
31022 }
31023
31024 return parent::run($input, $output);
31025 }
31026
31027
31028
31029
31030 public function doRun(InputInterface $input, OutputInterface $output)
31031 {
31032 $this->io = new ConsoleIO($input, $output, $this->getHelperSet());
31033
31034 if (version_compare(PHP_VERSION, '5.3.2', '<')) {
31035 $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>');
31036 }
31037
31038 if (defined('COMPOSER_DEV_WARNING_TIME')) {
31039 $commandName = '';
31040 if ($name = $this->getCommandName($input)) {
31041 try {
31042 $commandName = $this->find($name)->getName();
31043 } catch (\InvalidArgumentException $e) {
31044 }
31045 }
31046 if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
31047 if (time() > COMPOSER_DEV_WARNING_TIME) {
31048 $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']));
31049 }
31050 }
31051 }
31052
31053 if (getenv('COMPOSER_NO_INTERACTION')) {
31054 $input->setInteractive(false);
31055 }
31056
31057
31058  if ($newWorkDir = $this->getNewWorkingDir($input)) {
31059 $oldWorkingDir = getcwd();
31060 chdir($newWorkDir);
31061 if ($output->getVerbosity() >= 4) {
31062 $output->writeln('Changed CWD to ' . getcwd());
31063 }
31064 }
31065
31066
31067  $file = Factory::getComposerFile();
31068 if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
31069 if (isset($composer['scripts']) && is_array($composer['scripts'])) {
31070 foreach ($composer['scripts'] as $script => $dummy) {
31071 if (!defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
31072 if ($this->has($script)) {
31073 $output->writeln('<warning>A script named '.$script.' would override a native Composer function and has been skipped</warning>');
31074 } else {
31075 $this->add(new Command\ScriptAliasCommand($script));
31076 }
31077 }
31078 }
31079 }
31080 }
31081
31082 if ($input->hasParameterOption('--profile')) {
31083 $startTime = microtime(true);
31084 $this->io->enableDebugging($startTime);
31085 }
31086
31087 $result = parent::doRun($input, $output);
31088
31089 if (isset($oldWorkingDir)) {
31090 chdir($oldWorkingDir);
31091 }
31092
31093 if (isset($startTime)) {
31094 $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');
31095 }
31096
31097 return $result;
31098 }
31099
31100
31101
31102
31103
31104
31105 private function getNewWorkingDir(InputInterface $input)
31106 {
31107 $workingDir = $input->getParameterOption(array('--working-dir', '-d'));
31108 if (false !== $workingDir && !is_dir($workingDir)) {
31109 throw new \RuntimeException('Invalid working directory specified.');
31110 }
31111
31112 return $workingDir;
31113 }
31114
31115
31116
31117
31118 public function renderException($exception, $output)
31119 {
31120 try {
31121 $composer = $this->getComposer(false, true);
31122 if ($composer) {
31123 $config = $composer->getConfig();
31124
31125 $minSpaceFree = 1024*1024;
31126 if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
31127 || (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
31128 || (($df = @disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree)
31129 ) {
31130 $output->writeln('<error>The disk hosting '.$dir.' is full, this may be the cause of the following exception</error>');
31131 }
31132 }
31133 } catch (\Exception $e) {
31134 }
31135
31136 if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
31137 $output->writeln('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>');
31138 $output->writeln('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>');
31139 }
31140
31141 if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) {
31142 $output->writeln('<error>The following exception is caused by a lack of memory and not having swap configured</error>');
31143 $output->writeln('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>');
31144 }
31145
31146 return parent::renderException($exception, $output);
31147 }
31148
31149
31150
31151
31152
31153
31154
31155 public function getComposer($required = true, $disablePlugins = false)
31156 {
31157 if (null === $this->composer) {
31158 try {
31159 $this->composer = Factory::create($this->io, null, $disablePlugins);
31160 } catch (\InvalidArgumentException $e) {
31161 if ($required) {
31162 $this->io->write($e->getMessage());
31163 exit(1);
31164 }
31165 } catch (JsonValidationException $e) {
31166 $errors = ' - ' . implode(PHP_EOL . ' - ', $e->getErrors());
31167 $message = $e->getMessage() . ':' . PHP_EOL . $errors;
31168 throw new JsonValidationException($message);
31169 }
31170 }
31171
31172 return $this->composer;
31173 }
31174
31175
31176
31177
31178 public function resetComposer()
31179 {
31180 $this->composer = null;
31181 }
31182
31183
31184
31185
31186 public function getIO()
31187 {
31188 return $this->io;
31189 }
31190
31191 public function getHelp()
31192 {
31193 return self::$logo . parent::getHelp();
31194 }
31195
31196
31197
31198
31199 protected function getDefaultCommands()
31200 {
31201 $commands = parent::getDefaultCommands();
31202 $commands[] = new Command\AboutCommand();
31203 $commands[] = new Command\ConfigCommand();
31204 $commands[] = new Command\DependsCommand();
31205 $commands[] = new Command\InitCommand();
31206 $commands[] = new Command\InstallCommand();
31207 $commands[] = new Command\CreateProjectCommand();
31208 $commands[] = new Command\UpdateCommand();
31209 $commands[] = new Command\SearchCommand();
31210 $commands[] = new Command\ValidateCommand();
31211 $commands[] = new Command\ShowCommand();
31212 $commands[] = new Command\RequireCommand();
31213 $commands[] = new Command\DumpAutoloadCommand();
31214 $commands[] = new Command\StatusCommand();
31215 $commands[] = new Command\ArchiveCommand();
31216 $commands[] = new Command\DiagnoseCommand();
31217 $commands[] = new Command\RunScriptCommand();
31218 $commands[] = new Command\LicensesCommand();
31219 $commands[] = new Command\GlobalCommand();
31220 $commands[] = new Command\ClearCacheCommand();
31221 $commands[] = new Command\RemoveCommand();
31222 $commands[] = new Command\HomeCommand();
31223
31224 if ('phar:' === substr(__FILE__, 0, 5)) {
31225 $commands[] = new Command\SelfUpdateCommand();
31226 }
31227
31228 return $commands;
31229 }
31230
31231
31232
31233
31234 public function getLongVersion()
31235 {
31236 if (Composer::BRANCH_ALIAS_VERSION) {
31237 return sprintf(
31238 '<info>%s</info> version <comment>%s (%s)</comment> %s',
31239 $this->getName(),
31240 Composer::BRANCH_ALIAS_VERSION,
31241 $this->getVersion(),
31242 Composer::RELEASE_DATE
31243 );
31244 }
31245
31246 return parent::getLongVersion() . ' ' . Composer::RELEASE_DATE;
31247 }
31248
31249
31250
31251
31252 protected function getDefaultInputDefinition()
31253 {
31254 $definition = parent::getDefaultInputDefinition();
31255 $definition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Display timing and memory usage information'));
31256 $definition->addOption(new InputOption('--working-dir', '-d', InputOption::VALUE_REQUIRED, 'If specified, use the given directory as working directory.'));
31257
31258 return $definition;
31259 }
31260
31261
31262
31263
31264 protected function getDefaultHelperSet()
31265 {
31266 $helperSet = parent::getDefaultHelperSet();
31267
31268 $helperSet->set(new DialogHelper());
31269
31270 return $helperSet;
31271 }
31272 }
31273 <?php
31274
31275
31276
31277
31278
31279
31280
31281
31282
31283
31284
31285 namespace Composer\Console;
31286
31287 use Symfony\Component\Console\Formatter\OutputFormatter;
31288
31289
31290
31291
31292 class HtmlOutputFormatter extends OutputFormatter
31293 {
31294 private static $availableForegroundColors = array(
31295 30 => 'black',
31296 31 => 'red',
31297 32 => 'green',
31298 33 => 'yellow',
31299 34 => 'blue',
31300 35 => 'magenta',
31301 36 => 'cyan',
31302 37 => 'white'
31303 );
31304 private static $availableBackgroundColors = array(
31305 40 => 'black',
31306 41 => 'red',
31307 42 => 'green',
31308 43 => 'yellow',
31309 44 => 'blue',
31310 45 => 'magenta',
31311 46 => 'cyan',
31312 47 => 'white'
31313 );
31314 private static $availableOptions = array(
31315 1 => 'bold',
31316 4 => 'underscore',
31317
31318  
31319  
31320  );
31321
31322
31323
31324
31325 public function __construct(array $styles = array())
31326 {
31327 parent::__construct(true, $styles);
31328 }
31329
31330 public function format($message)
31331 {
31332 $formatted = parent::format($message);
31333
31334 return preg_replace_callback("{\033\[([0-9;]+)m(.*?)\033\[0m}s", array($this, 'formatHtml'), $formatted);
31335 }
31336
31337 private function formatHtml($matches)
31338 {
31339 $out = '<span style="';
31340 foreach (explode(';', $matches[1]) as $code) {
31341 if (isset(self::$availableForegroundColors[$code])) {
31342 $out .= 'color:'.self::$availableForegroundColors[$code].';';
31343 } elseif (isset(self::$availableBackgroundColors[$code])) {
31344 $out .= 'background-color:'.self::$availableBackgroundColors[$code].';';
31345 } elseif (isset(self::$availableOptions[$code])) {
31346 switch (self::$availableOptions[$code]) {
31347 case 'bold':
31348 $out .= 'font-weight:bold;';
31349 break;
31350
31351 case 'underscore':
31352 $out .= 'text-decoration:underline;';
31353 break;
31354 }
31355 }
31356 }
31357
31358 return $out . '">'.$matches[2].'</span>';
31359 }
31360 }
31361 <?php
31362
31363
31364
31365
31366
31367
31368
31369
31370
31371
31372
31373 namespace Composer\Autoload;
31374
31375 use Composer\Config;
31376 use Composer\EventDispatcher\EventDispatcher;
31377 use Composer\Installer\InstallationManager;
31378 use Composer\IO\IOInterface;
31379 use Composer\Package\AliasPackage;
31380 use Composer\Package\PackageInterface;
31381 use Composer\Repository\InstalledRepositoryInterface;
31382 use Composer\Util\Filesystem;
31383 use Composer\Script\ScriptEvents;
31384
31385
31386
31387
31388
31389 class AutoloadGenerator
31390 {
31391
31392
31393
31394 private $eventDispatcher;
31395
31396
31397
31398
31399 private $io;
31400
31401 private $devMode = false;
31402
31403 public function __construct(EventDispatcher $eventDispatcher, IOInterface $io = null)
31404 {
31405 $this->eventDispatcher = $eventDispatcher;
31406 $this->io = $io;
31407 }
31408
31409 public function setDevMode($devMode = true)
31410 {
31411 $this->devMode = (boolean) $devMode;
31412 }
31413
31414 public function dump(Config $config, InstalledRepositoryInterface $localRepo, PackageInterface $mainPackage, InstallationManager $installationManager, $targetDir, $scanPsr0Packages = false, $suffix = '')
31415 {
31416 $this->eventDispatcher->dispatchScript(ScriptEvents::PRE_AUTOLOAD_DUMP, $this->devMode, array(), array(
31417 'optimize' => (bool) $scanPsr0Packages,
31418 ));
31419
31420 $filesystem = new Filesystem();
31421 $filesystem->ensureDirectoryExists($config->get('vendor-dir'));
31422 $basePath = $filesystem->normalizePath(realpath(getcwd()));
31423 $vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
31424 $useGlobalIncludePath = (bool) $config->get('use-include-path');
31425 $prependAutoloader = $config->get('prepend-autoloader') === false ? 'false' : 'true';
31426 $targetDir = $vendorPath.'/'.$targetDir;
31427 $filesystem->ensureDirectoryExists($targetDir);
31428
31429 $vendorPathCode = $filesystem->findShortestPathCode(realpath($targetDir), $vendorPath, true);
31430 $vendorPathCode52 = str_replace('__DIR__', 'dirname(__FILE__)', $vendorPathCode);
31431 $vendorPathToTargetDirCode = $filesystem->findShortestPathCode($vendorPath, realpath($targetDir), true);
31432
31433 $appBaseDirCode = $filesystem->findShortestPathCode($vendorPath, $basePath, true);
31434 $appBaseDirCode = str_replace('__DIR__', '$vendorDir', $appBaseDirCode);
31435
31436 $namespacesFile = <<<EOF
31437 <?php
31438
31439 // autoload_namespaces.php @generated by Composer
31440
31441 \$vendorDir = $vendorPathCode52;
31442 \$baseDir = $appBaseDirCode;
31443
31444 return array(
31445
31446 EOF;
31447
31448 $psr4File = <<<EOF
31449 <?php
31450
31451 // autoload_psr4.php @generated by Composer
31452
31453 \$vendorDir = $vendorPathCode52;
31454 \$baseDir = $appBaseDirCode;
31455
31456 return array(
31457
31458 EOF;
31459
31460
31461  $packageMap = $this->buildPackageMap($installationManager, $mainPackage, $localRepo->getCanonicalPackages());
31462 $autoloads = $this->parseAutoloads($packageMap, $mainPackage);
31463
31464
31465  foreach ($autoloads['psr-0'] as $namespace => $paths) {
31466 $exportedPaths = array();
31467 foreach ($paths as $path) {
31468 $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
31469 }
31470 $exportedPrefix = var_export($namespace, true);
31471 $namespacesFile .= "    $exportedPrefix => ";
31472 $namespacesFile .= "array(".implode(', ', $exportedPaths)."),\n";
31473 }
31474 $namespacesFile .= ");\n";
31475
31476
31477  foreach ($autoloads['psr-4'] as $namespace => $paths) {
31478 $exportedPaths = array();
31479 foreach ($paths as $path) {
31480 $exportedPaths[] = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
31481 }
31482 $exportedPrefix = var_export($namespace, true);
31483 $psr4File .= "    $exportedPrefix => ";
31484 $psr4File .= "array(".implode(', ', $exportedPaths)."),\n";
31485 }
31486 $psr4File .= ");\n";
31487
31488 $classmapFile = <<<EOF
31489 <?php
31490
31491 // autoload_classmap.php @generated by Composer
31492
31493 \$vendorDir = $vendorPathCode52;
31494 \$baseDir = $appBaseDirCode;
31495
31496 return array(
31497
31498 EOF;
31499
31500
31501  $targetDirLoader = null;
31502 $mainAutoload = $mainPackage->getAutoload();
31503 if ($mainPackage->getTargetDir() && !empty($mainAutoload['psr-0'])) {
31504 $levels = count(explode('/', $filesystem->normalizePath($mainPackage->getTargetDir())));
31505 $prefixes = implode(', ', array_map(function ($prefix) {
31506 return var_export($prefix, true);
31507 }, array_keys($mainAutoload['psr-0'])));
31508 $baseDirFromTargetDirCode = $filesystem->findShortestPathCode($targetDir, $basePath, true);
31509
31510 $targetDirLoader = <<<EOF
31511
31512     public static function autoload(\$class)
31513     {
31514         \$dir = $baseDirFromTargetDirCode . '/';
31515         \$prefixes = array($prefixes);
31516         foreach (\$prefixes as \$prefix) {
31517             if (0 !== strpos(\$class, \$prefix)) {
31518                 continue;
31519             }
31520             \$path = \$dir . implode('/', array_slice(explode('\\\\', \$class), $levels)).'.php';
31521             if (!\$path = stream_resolve_include_path(\$path)) {
31522                 return false;
31523             }
31524             require \$path;
31525
31526             return true;
31527         }
31528     }
31529
31530 EOF;
31531 }
31532
31533
31534  $classMap = array();
31535 if ($scanPsr0Packages) {
31536
31537  foreach (array('psr-0', 'psr-4') as $psrType) {
31538 foreach ($autoloads[$psrType] as $namespace => $paths) {
31539 foreach ($paths as $dir) {
31540 $dir = $filesystem->normalizePath($filesystem->isAbsolutePath($dir) ? $dir : $basePath.'/'.$dir);
31541 if (!is_dir($dir)) {
31542 continue;
31543 }
31544 $whitelist = sprintf(
31545 '{%s/%s.+(?<!(?<!/)Test\.php)$}',
31546 preg_quote($dir),
31547 ($psrType === 'psr-0' && strpos($namespace, '_') === false) ? preg_quote(strtr($namespace, '\\', '/')) : ''
31548 );
31549
31550 $namespaceFilter = $namespace === '' ? null : $namespace;
31551 foreach (ClassMapGenerator::createMap($dir, $whitelist, $this->io, $namespaceFilter) as $class => $path) {
31552 if (!isset($classMap[$class])) {
31553 $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
31554 $classMap[$class] = $path.",\n";
31555 }
31556 }
31557 }
31558 }
31559 }
31560 }
31561
31562 foreach ($autoloads['classmap'] as $dir) {
31563 foreach (ClassMapGenerator::createMap($dir, null, $this->io) as $class => $path) {
31564 $path = $this->getPathCode($filesystem, $basePath, $vendorPath, $path);
31565 $classMap[$class] = $path.",\n";
31566 }
31567 }
31568
31569 ksort($classMap);
31570 foreach ($classMap as $class => $code) {
31571 $classmapFile .= '    '.var_export($class, true).' => '.$code;
31572 }
31573 $classmapFile .= ");\n";
31574
31575 if (!$suffix) {
31576 $suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true));
31577 }
31578
31579 file_put_contents($targetDir.'/autoload_namespaces.php', $namespacesFile);
31580 file_put_contents($targetDir.'/autoload_psr4.php', $psr4File);
31581 file_put_contents($targetDir.'/autoload_classmap.php', $classmapFile);
31582 if ($includePathFile = $this->getIncludePathsFile($packageMap, $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
31583 file_put_contents($targetDir.'/include_paths.php', $includePathFile);
31584 }
31585 if ($includeFilesFile = $this->getIncludeFilesFile($autoloads['files'], $filesystem, $basePath, $vendorPath, $vendorPathCode52, $appBaseDirCode)) {
31586 file_put_contents($targetDir.'/autoload_files.php', $includeFilesFile);
31587 }
31588 file_put_contents($vendorPath.'/autoload.php', $this->getAutoloadFile($vendorPathToTargetDirCode, $suffix));
31589 file_put_contents($targetDir.'/autoload_real.php', $this->getAutoloadRealFile(true, (bool) $includePathFile, $targetDirLoader, (bool) $includeFilesFile, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader));
31590
31591
31592  
31593  $sourceLoader = fopen(__DIR__.'/ClassLoader.php', 'r');
31594 $targetLoader = fopen($targetDir.'/ClassLoader.php', 'w+');
31595 stream_copy_to_stream($sourceLoader, $targetLoader);
31596 fclose($sourceLoader);
31597 fclose($targetLoader);
31598 unset($sourceLoader, $targetLoader);
31599
31600 $this->eventDispatcher->dispatchScript(ScriptEvents::POST_AUTOLOAD_DUMP, $this->devMode, array(), array(
31601 'optimize' => (bool) $scanPsr0Packages,
31602 ));
31603 }
31604
31605 public function buildPackageMap(InstallationManager $installationManager, PackageInterface $mainPackage, array $packages)
31606 {
31607
31608  $packageMap = array(array($mainPackage, ''));
31609
31610 foreach ($packages as $package) {
31611 if ($package instanceof AliasPackage) {
31612 continue;
31613 }
31614 $this->validatePackage($package);
31615
31616 $packageMap[] = array(
31617 $package,
31618 $installationManager->getInstallPath($package),
31619 );
31620 }
31621
31622 return $packageMap;
31623 }
31624
31625
31626
31627
31628
31629
31630 protected function validatePackage(PackageInterface $package)
31631 {
31632 $autoload = $package->getAutoload();
31633 if (!empty($autoload['psr-4']) && null !== $package->getTargetDir()) {
31634 $name = $package->getName();
31635 $package->getTargetDir();
31636 throw new \InvalidArgumentException("PSR-4 autoloading is incompatible with the target-dir property, remove the target-dir in package '$name'.");
31637 }
31638 if (!empty($autoload['psr-4'])) {
31639 foreach ($autoload['psr-4'] as $namespace => $dirs) {
31640 if ($namespace !== '' && '\\' !== substr($namespace, -1)) {
31641 throw new \InvalidArgumentException("psr-4 namespaces must end with a namespace separator, '$namespace' does not, use '$namespace\\'.");
31642 }
31643 }
31644 }
31645 }
31646
31647
31648
31649
31650
31651
31652
31653
31654 public function parseAutoloads(array $packageMap, PackageInterface $mainPackage)
31655 {
31656 $mainPackageMap = array_shift($packageMap);
31657 $sortedPackageMap = $this->sortPackageMap($packageMap);
31658 $sortedPackageMap[] = $mainPackageMap;
31659 array_unshift($packageMap, $mainPackageMap);
31660
31661 $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $mainPackage);
31662 $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $mainPackage);
31663 $classmap = $this->parseAutoloadsType($sortedPackageMap, 'classmap', $mainPackage);
31664 $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $mainPackage);
31665
31666 krsort($psr0);
31667 krsort($psr4);
31668
31669 return array('psr-0' => $psr0, 'psr-4' => $psr4, 'classmap' => $classmap, 'files' => $files);
31670 }
31671
31672
31673
31674
31675
31676
31677
31678 public function createLoader(array $autoloads)
31679 {
31680 $loader = new ClassLoader();
31681
31682 if (isset($autoloads['psr-0'])) {
31683 foreach ($autoloads['psr-0'] as $namespace => $path) {
31684 $loader->add($namespace, $path);
31685 }
31686 }
31687
31688 if (isset($autoloads['psr-4'])) {
31689 foreach ($autoloads['psr-4'] as $namespace => $path) {
31690 $loader->addPsr4($namespace, $path);
31691 }
31692 }
31693
31694 return $loader;
31695 }
31696
31697 protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)
31698 {
31699 $includePaths = array();
31700
31701 foreach ($packageMap as $item) {
31702 list($package, $installPath) = $item;
31703
31704 if (null !== $package->getTargetDir() && strlen($package->getTargetDir()) > 0) {
31705 $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
31706 }
31707
31708 foreach ($package->getIncludePaths() as $includePath) {
31709 $includePath = trim($includePath, '/');
31710 $includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath;
31711 }
31712 }
31713
31714 if (!$includePaths) {
31715 return;
31716 }
31717
31718 $includePathsCode = '';
31719 foreach ($includePaths as $path) {
31720 $includePathsCode .= "    " . $this->getPathCode($filesystem, $basePath, $vendorPath, $path) . ",\n";
31721 }
31722
31723 return <<<EOF
31724 <?php
31725
31726 // include_paths.php @generated by Composer
31727
31728 \$vendorDir = $vendorPathCode;
31729 \$baseDir = $appBaseDirCode;
31730
31731 return array(
31732 $includePathsCode);
31733
31734 EOF;
31735 }
31736
31737 protected function getIncludeFilesFile(array $files, Filesystem $filesystem, $basePath, $vendorPath, $vendorPathCode, $appBaseDirCode)
31738 {
31739 $filesCode = '';
31740 foreach ($files as $functionFile) {
31741 $filesCode .= '    '.$this->getPathCode($filesystem, $basePath, $vendorPath, $functionFile).",\n";
31742 }
31743
31744 if (!$filesCode) {
31745 return FALSE;
31746 }
31747
31748 return <<<EOF
31749 <?php
31750
31751 // autoload_files.php @generated by Composer
31752
31753 \$vendorDir = $vendorPathCode;
31754 \$baseDir = $appBaseDirCode;
31755
31756 return array(
31757 $filesCode);
31758
31759 EOF;
31760 }
31761
31762 protected function getPathCode(Filesystem $filesystem, $basePath, $vendorPath, $path)
31763 {
31764 if (!$filesystem->isAbsolutePath($path)) {
31765 $path = $basePath . '/' . $path;
31766 }
31767 $path = $filesystem->normalizePath($path);
31768
31769 $baseDir = '';
31770 if (strpos($path.'/', $vendorPath.'/') === 0) {
31771 $path = substr($path, strlen($vendorPath));
31772 $baseDir = '$vendorDir';
31773
31774 if ($path !== false) {
31775 $baseDir .= " . ";
31776 }
31777 } else {
31778 $path = $filesystem->normalizePath($filesystem->findShortestPath($basePath, $path, true));
31779 if (!$filesystem->isAbsolutePath($path)) {
31780 $baseDir = '$baseDir . ';
31781 $path = '/' . $path;
31782 }
31783 }
31784
31785 if (preg_match('/\.phar$/', $path)) {
31786 $baseDir = "'phar://' . " . $baseDir;
31787 }
31788
31789 return $baseDir . (($path !== false) ? var_export($path, true) : "");
31790 }
31791
31792 protected function getAutoloadFile($vendorPathToTargetDirCode, $suffix)
31793 {
31794 return <<<AUTOLOAD
31795 <?php
31796
31797 // autoload.php @generated by Composer
31798
31799 require_once $vendorPathToTargetDirCode . '/autoload_real.php';
31800
31801 return ComposerAutoloaderInit$suffix::getLoader();
31802
31803 AUTOLOAD;
31804 }
31805
31806 protected function getAutoloadRealFile($useClassMap, $useIncludePath, $targetDirLoader, $useIncludeFiles, $vendorPathCode, $appBaseDirCode, $suffix, $useGlobalIncludePath, $prependAutoloader)
31807 {
31808
31809  
31810  
31811  
31812  
31813  
31814
31815 $file = <<<HEADER
31816 <?php
31817
31818 // autoload_real.php @generated by Composer
31819
31820 class ComposerAutoloaderInit$suffix
31821 {
31822     private static \$loader;
31823
31824     public static function loadClassLoader(\$class)
31825     {
31826         if ('Composer\\Autoload\\ClassLoader' === \$class) {
31827             require __DIR__ . '/ClassLoader.php';
31828         }
31829     }
31830
31831     public static function getLoader()
31832     {
31833         if (null !== self::\$loader) {
31834             return self::\$loader;
31835         }
31836
31837         spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'), true, $prependAutoloader);
31838         self::\$loader = \$loader = new \\Composer\\Autoload\\ClassLoader();
31839         spl_autoload_unregister(array('ComposerAutoloaderInit$suffix', 'loadClassLoader'));
31840
31841
31842 HEADER;
31843
31844 if ($useIncludePath) {
31845 $file .= <<<'INCLUDE_PATH'
31846         $includePaths = require __DIR__ . '/include_paths.php';
31847         array_push($includePaths, get_include_path());
31848         set_include_path(join(PATH_SEPARATOR, $includePaths));
31849
31850
31851 INCLUDE_PATH;
31852 }
31853
31854 $file .= <<<'PSR0'
31855         $map = require __DIR__ . '/autoload_namespaces.php';
31856         foreach ($map as $namespace => $path) {
31857             $loader->set($namespace, $path);
31858         }
31859
31860
31861 PSR0;
31862
31863 $file .= <<<'PSR4'
31864         $map = require __DIR__ . '/autoload_psr4.php';
31865         foreach ($map as $namespace => $path) {
31866             $loader->setPsr4($namespace, $path);
31867         }
31868
31869
31870 PSR4;
31871
31872 if ($useClassMap) {
31873 $file .= <<<'CLASSMAP'
31874         $classMap = require __DIR__ . '/autoload_classmap.php';
31875         if ($classMap) {
31876             $loader->addClassMap($classMap);
31877         }
31878
31879
31880 CLASSMAP;
31881 }
31882
31883 if ($useGlobalIncludePath) {
31884 $file .= <<<'INCLUDEPATH'
31885         $loader->setUseIncludePath(true);
31886
31887 INCLUDEPATH;
31888 }
31889
31890 if ($targetDirLoader) {
31891 $file .= <<<REGISTER_AUTOLOAD
31892         spl_autoload_register(array('ComposerAutoloaderInit$suffix', 'autoload'), true, true);
31893
31894
31895 REGISTER_AUTOLOAD;
31896 }
31897
31898 $file .= <<<REGISTER_LOADER
31899         \$loader->register($prependAutoloader);
31900
31901
31902 REGISTER_LOADER;
31903
31904 if ($useIncludeFiles) {
31905 $file .= <<<INCLUDE_FILES
31906         \$includeFiles = require __DIR__ . '/autoload_files.php';
31907         foreach (\$includeFiles as \$file) {
31908             composerRequire$suffix(\$file);
31909         }
31910
31911
31912 INCLUDE_FILES;
31913 }
31914
31915 $file .= <<<METHOD_FOOTER
31916         return \$loader;
31917     }
31918
31919 METHOD_FOOTER;
31920
31921 $file .= $targetDirLoader;
31922
31923 return $file . <<<FOOTER
31924 }
31925
31926 function composerRequire$suffix(\$file)
31927 {
31928     require \$file;
31929 }
31930
31931 FOOTER;
31932 }
31933
31934 protected function parseAutoloadsType(array $packageMap, $type, PackageInterface $mainPackage)
31935 {
31936 $autoloads = array();
31937
31938 foreach ($packageMap as $item) {
31939 list($package, $installPath) = $item;
31940
31941 $autoload = $package->getAutoload();
31942 if ($this->devMode && $package === $mainPackage) {
31943 $autoload = array_merge_recursive($autoload, $package->getDevAutoload());
31944 }
31945
31946
31947  if (!isset($autoload[$type]) || !is_array($autoload[$type])) {
31948 continue;
31949 }
31950 if (null !== $package->getTargetDir() && $package !== $mainPackage) {
31951 $installPath = substr($installPath, 0, -strlen('/'.$package->getTargetDir()));
31952 }
31953
31954 foreach ($autoload[$type] as $namespace => $paths) {
31955 foreach ((array) $paths as $path) {
31956 if (($type === 'files' || $type === 'classmap') && $package->getTargetDir() && !is_readable($installPath.'/'.$path)) {
31957
31958  if ($package === $mainPackage) {
31959 $targetDir = str_replace('\\<dirsep\\>', '[\\\\/]', preg_quote(str_replace(array('/', '\\'), '<dirsep>', $package->getTargetDir())));
31960 $path = ltrim(preg_replace('{^'.$targetDir.'}', '', ltrim($path, '\\/')), '\\/');
31961 } else {
31962
31963  $path = $package->getTargetDir() . '/' . $path;
31964 }
31965 }
31966
31967 $relativePath = empty($installPath) ? (empty($path) ? '.' : $path) : $installPath.'/'.$path;
31968
31969 if ($type === 'files' || $type === 'classmap') {
31970 $autoloads[] = $relativePath;
31971 continue;
31972 }
31973
31974 $autoloads[$namespace][] = $relativePath;
31975 }
31976 }
31977 }
31978
31979 return $autoloads;
31980 }
31981
31982
31983
31984
31985
31986
31987
31988
31989
31990 protected function sortPackageMap(array $packageMap)
31991 {
31992 $packages = array();
31993 $paths = array();
31994 $usageList = array();
31995
31996 foreach ($packageMap as $item) {
31997 list($package, $path) = $item;
31998 $name = $package->getName();
31999 $packages[$name] = $package;
32000 $paths[$name] = $path;
32001
32002 foreach (array_merge($package->getRequires(), $package->getDevRequires()) as $link) {
32003 $target = $link->getTarget();
32004 $usageList[$target][] = $name;
32005 }
32006 }
32007
32008 $computing = array();
32009 $computed = array();
32010 $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList) {
32011
32012  if (isset($computed[$name])) {
32013 return $computed[$name];
32014 }
32015
32016
32017  if (isset($computing[$name])) {
32018 return 0;
32019 }
32020
32021 $computing[$name] = true;
32022 $weight = 0;
32023
32024 if (isset($usageList[$name])) {
32025 foreach ($usageList[$name] as $user) {
32026 $weight -= 1 - $computeImportance($user);
32027 }
32028 }
32029
32030 unset($computing[$name]);
32031 $computed[$name] = $weight;
32032
32033 return $weight;
32034 };
32035
32036 $weightList = array();
32037
32038 foreach ($packages as $name => $package) {
32039 $weight = $computeImportance($name);
32040 $weightList[$name] = $weight;
32041 }
32042
32043 $stable_sort = function (&$array) {
32044 static $transform, $restore;
32045
32046 $i = 0;
32047
32048 if (!$transform) {
32049 $transform = function (&$v, $k) use (&$i) {
32050 $v = array($v, ++$i, $k, $v);
32051 };
32052
32053 $restore = function (&$v, $k) {
32054 $v = $v[3];
32055 };
32056 }
32057
32058 array_walk($array, $transform);
32059 asort($array);
32060 array_walk($array, $restore);
32061 };
32062
32063 $stable_sort($weightList);
32064
32065 $sortedPackageMap = array();
32066
32067 foreach (array_keys($weightList) as $name) {
32068 $sortedPackageMap[] = array($packages[$name], $paths[$name]);
32069 }
32070
32071 return $sortedPackageMap;
32072 }
32073 }
32074 <?php
32075
32076
32077
32078
32079
32080
32081
32082
32083
32084
32085
32086
32087 namespace Composer\Autoload;
32088
32089 use Symfony\Component\Finder\Finder;
32090 use Composer\IO\IOInterface;
32091
32092
32093
32094
32095
32096
32097
32098 class ClassMapGenerator
32099 {
32100
32101
32102
32103
32104
32105
32106 public static function dump($dirs, $file)
32107 {
32108 $maps = array();
32109
32110 foreach ($dirs as $dir) {
32111 $maps = array_merge($maps, static::createMap($dir));
32112 }
32113
32114 file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
32115 }
32116
32117
32118
32119
32120
32121
32122
32123
32124
32125
32126
32127
32128
32129 public static function createMap($path, $whitelist = null, IOInterface $io = null, $namespace = null)
32130 {
32131 if (is_string($path)) {
32132 if (is_file($path)) {
32133 $path = array(new \SplFileInfo($path));
32134 } elseif (is_dir($path)) {
32135 $path = Finder::create()->files()->followLinks()->name('/\.(php|inc|hh)$/')->in($path);
32136 } else {
32137 throw new \RuntimeException(
32138 'Could not scan for classes inside "'.$path.
32139 '" which does not appear to be a file nor a folder'
32140 );
32141 }
32142 }
32143
32144 $map = array();
32145
32146 foreach ($path as $file) {
32147 $filePath = $file->getRealPath();
32148
32149 if (!in_array(pathinfo($filePath, PATHINFO_EXTENSION), array('php', 'inc', 'hh'))) {
32150 continue;
32151 }
32152
32153 if ($whitelist && !preg_match($whitelist, strtr($filePath, '\\', '/'))) {
32154 continue;
32155 }
32156
32157 $classes = self::findClasses($filePath);
32158
32159 foreach ($classes as $class) {
32160
32161  if (null !== $namespace && 0 !== strpos($class, $namespace)) {
32162 continue;
32163 }
32164
32165 if (!isset($map[$class])) {
32166 $map[$class] = $filePath;
32167 } elseif ($io && $map[$class] !== $filePath && !preg_match('{/(test|fixture|example)s?/}i', strtr($map[$class].' '.$filePath, '\\', '/'))) {
32168 $io->write(
32169 '<warning>Warning: Ambiguous class resolution, "'.$class.'"'.
32170 ' was found in both "'.$map[$class].'" and "'.$filePath.'", the first will be used.</warning>'
32171 );
32172 }
32173 }
32174 }
32175
32176 return $map;
32177 }
32178
32179
32180
32181
32182
32183
32184
32185
32186 private static function findClasses($path)
32187 {
32188 $traits = version_compare(PHP_VERSION, '5.4', '<') ? '' : '|trait';
32189
32190 try {
32191 $contents = @php_strip_whitespace($path);
32192 if (!$contents) {
32193 if (!file_exists($path)) {
32194 throw new \Exception('File does not exist');
32195 }
32196 if (!is_readable($path)) {
32197 throw new \Exception('File is not readable');
32198 }
32199 }
32200 } catch (\Exception $e) {
32201 throw new \RuntimeException('Could not scan for classes inside '.$path.": \n".$e->getMessage(), 0, $e);
32202 }
32203
32204
32205  if (!preg_match('{\b(?:class|interface'.$traits.')\s}i', $contents)) {
32206 return array();
32207 }
32208
32209
32210  $contents = preg_replace('{<<<\s*(\'?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)\\2(?=\r\n|\n|\r|;)}s', 'null', $contents);
32211
32212  $contents = preg_replace('{"[^"\\\\]*(\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(\\\\.[^\'\\\\]*)*\'}s', 'null', $contents);
32213
32214  if (substr($contents, 0, 2) !== '<?') {
32215 $contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
32216 if ($replacements === 0) {
32217 return array();
32218 }
32219 }
32220
32221  $contents = preg_replace('{\?>.+<\?}s', '?><?', $contents);
32222
32223  $pos = strrpos($contents, '?>');
32224 if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
32225 $contents = substr($contents, 0, $pos);
32226 }
32227
32228 preg_match_all('{
32229             (?:
32230                  \b(?<![\$:>])(?P<type>class|interface'.$traits.') \s+ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*)
32231                | \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*[\{;]
32232             )
32233         }ix', $contents, $matches);
32234
32235 $classes = array();
32236 $namespace = '';
32237
32238 for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
32239 if (!empty($matches['ns'][$i])) {
32240 $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\';
32241 } else {
32242 $name = $matches['name'][$i];
32243 if ($name[0] === ':') {
32244
32245  $name = 'xhp'.substr(str_replace(array('-', ':'), array('_', '__'), $name), 1);
32246 }
32247 $classes[] = ltrim($namespace . $name, '\\');
32248 }
32249 }
32250
32251 return $classes;
32252 }
32253 }
32254 <?php
32255
32256
32257
32258
32259
32260
32261
32262
32263
32264
32265
32266 namespace Composer;
32267
32268 use Composer\Autoload\AutoloadGenerator;
32269 use Composer\DependencyResolver\DefaultPolicy;
32270 use Composer\DependencyResolver\Operation\UpdateOperation;
32271 use Composer\DependencyResolver\Operation\InstallOperation;
32272 use Composer\DependencyResolver\Operation\UninstallOperation;
32273 use Composer\DependencyResolver\Operation\OperationInterface;
32274 use Composer\DependencyResolver\Pool;
32275 use Composer\DependencyResolver\Request;
32276 use Composer\DependencyResolver\Rule;
32277 use Composer\DependencyResolver\Solver;
32278 use Composer\DependencyResolver\SolverProblemsException;
32279 use Composer\Downloader\DownloadManager;
32280 use Composer\EventDispatcher\EventDispatcher;
32281 use Composer\Installer\InstallationManager;
32282 use Composer\Installer\InstallerEvents;
32283 use Composer\Installer\NoopInstaller;
32284 use Composer\IO\IOInterface;
32285 use Composer\Json\JsonFile;
32286 use Composer\Package\AliasPackage;
32287 use Composer\Package\CompletePackage;
32288 use Composer\Package\Link;
32289 use Composer\Package\LinkConstraint\VersionConstraint;
32290 use Composer\Package\Locker;
32291 use Composer\Package\PackageInterface;
32292 use Composer\Package\RootPackageInterface;
32293 use Composer\Repository\CompositeRepository;
32294 use Composer\Repository\InstalledArrayRepository;
32295 use Composer\Repository\InstalledFilesystemRepository;
32296 use Composer\Repository\PlatformRepository;
32297 use Composer\Repository\RepositoryInterface;
32298 use Composer\Repository\RepositoryManager;
32299 use Composer\Script\ScriptEvents;
32300
32301
32302
32303
32304
32305
32306
32307 class Installer
32308 {
32309
32310
32311
32312 protected $io;
32313
32314
32315
32316
32317 protected $config;
32318
32319
32320
32321
32322 protected $package;
32323
32324
32325
32326
32327 protected $downloadManager;
32328
32329
32330
32331
32332 protected $repositoryManager;
32333
32334
32335
32336
32337 protected $locker;
32338
32339
32340
32341
32342 protected $installationManager;
32343
32344
32345
32346
32347 protected $eventDispatcher;
32348
32349
32350
32351
32352 protected $autoloadGenerator;
32353
32354 protected $preferSource = false;
32355 protected $preferDist = false;
32356 protected $optimizeAutoloader = false;
32357 protected $devMode = false;
32358 protected $dryRun = false;
32359 protected $verbose = false;
32360 protected $update = false;
32361 protected $dumpAutoloader = true;
32362 protected $runScripts = true;
32363 protected $ignorePlatformReqs = false;
32364 protected $preferStable = false;
32365 protected $preferLowest = false;
32366
32367
32368
32369
32370
32371 protected $updateWhitelist = null;
32372 protected $whitelistDependencies = false;
32373
32374
32375
32376
32377 protected $suggestedPackages;
32378
32379
32380
32381
32382 protected $additionalInstalledRepository;
32383
32384
32385
32386
32387
32388
32389
32390
32391
32392
32393
32394
32395
32396
32397 public function __construct(IOInterface $io, Config $config, RootPackageInterface $package, DownloadManager $downloadManager, RepositoryManager $repositoryManager, Locker $locker, InstallationManager $installationManager, EventDispatcher $eventDispatcher, AutoloadGenerator $autoloadGenerator)
32398 {
32399 $this->io = $io;
32400 $this->config = $config;
32401 $this->package = $package;
32402 $this->downloadManager = $downloadManager;
32403 $this->repositoryManager = $repositoryManager;
32404 $this->locker = $locker;
32405 $this->installationManager = $installationManager;
32406 $this->eventDispatcher = $eventDispatcher;
32407 $this->autoloadGenerator = $autoloadGenerator;
32408 }
32409
32410
32411
32412
32413
32414
32415
32416
32417 public function run()
32418 {
32419 gc_collect_cycles();
32420 gc_disable();
32421
32422 if ($this->dryRun) {
32423 $this->verbose = true;
32424 $this->runScripts = false;
32425 $this->installationManager->addInstaller(new NoopInstaller);
32426 $this->mockLocalRepositories($this->repositoryManager);
32427 }
32428
32429
32430  
32431  $devRepo = new InstalledFilesystemRepository(new JsonFile($this->config->get('vendor-dir').'/composer/installed_dev.json'));
32432 if ($devRepo->getPackages()) {
32433 $this->io->write('<warning>BC Notice: Removing old dev packages to migrate to the new require-dev handling.</warning>');
32434 foreach ($devRepo->getPackages() as $package) {
32435 if ($this->installationManager->isPackageInstalled($devRepo, $package)) {
32436 $this->installationManager->uninstall($devRepo, new UninstallOperation($package));
32437 }
32438 }
32439 unlink($this->config->get('vendor-dir').'/composer/installed_dev.json');
32440 }
32441 unset($devRepo, $package);
32442
32443
32444 if ($this->runScripts) {
32445
32446  $eventName = $this->update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD;
32447 $this->eventDispatcher->dispatchCommandEvent($eventName, $this->devMode);
32448 }
32449
32450 $this->downloadManager->setPreferSource($this->preferSource);
32451 $this->downloadManager->setPreferDist($this->preferDist);
32452
32453
32454  
32455  
32456  $installedRootPackage = clone $this->package;
32457 $installedRootPackage->setRequires(array());
32458 $installedRootPackage->setDevRequires(array());
32459
32460
32461  $localRepo = $this->repositoryManager->getLocalRepository();
32462 $platformRepo = new PlatformRepository();
32463 $repos = array(
32464 $localRepo,
32465 new InstalledArrayRepository(array($installedRootPackage)),
32466 $platformRepo,
32467 );
32468 $installedRepo = new CompositeRepository($repos);
32469 if ($this->additionalInstalledRepository) {
32470 $installedRepo->addRepository($this->additionalInstalledRepository);
32471 }
32472
32473 $aliases = $this->getRootAliases();
32474 $this->aliasPlatformPackages($platformRepo, $aliases);
32475
32476 try {
32477 $this->suggestedPackages = array();
32478 $res = $this->doInstall($localRepo, $installedRepo, $platformRepo, $aliases, $this->devMode);
32479 if ($res !== 0) {
32480 return $res;
32481 }
32482 } catch (\Exception $e) {
32483 $this->installationManager->notifyInstalls();
32484
32485 throw $e;
32486 }
32487 $this->installationManager->notifyInstalls();
32488
32489
32490  if ($this->devMode) {
32491 foreach ($this->suggestedPackages as $suggestion) {
32492 $target = $suggestion['target'];
32493 foreach ($installedRepo->getPackages() as $package) {
32494 if (in_array($target, $package->getNames())) {
32495 continue 2;
32496 }
32497 }
32498
32499 $this->io->write($suggestion['source'].' suggests installing '.$suggestion['target'].' ('.$suggestion['reason'].')');
32500 }
32501 }
32502
32503
32504  foreach ($localRepo->getPackages() as $package) {
32505 if (!$package instanceof CompletePackage || !$package->isAbandoned()) {
32506 continue;
32507 }
32508
32509 $replacement = (is_string($package->getReplacementPackage()))
32510 ? 'Use ' . $package->getReplacementPackage() . ' instead'
32511 : 'No replacement was suggested';
32512
32513 $this->io->write(
32514 sprintf(
32515 "<error>Package %s is abandoned, you should avoid using it. %s.</error>",
32516 $package->getPrettyName(),
32517 $replacement
32518 )
32519 );
32520 }
32521
32522 if (!$this->dryRun) {
32523
32524  if ($this->update || !$this->locker->isLocked()) {
32525 $localRepo->reload();
32526
32527
32528  
32529  $devPackages = ($this->devMode || !$this->package->getDevRequires()) ? array() : null;
32530
32531
32532  if ($this->devMode && $this->package->getDevRequires()) {
32533 $policy = $this->createPolicy();
32534 $pool = $this->createPool(true);
32535 $pool->addRepository($installedRepo, $aliases);
32536
32537
32538  $request = $this->createRequest($pool, $this->package, $platformRepo);
32539 $request->updateAll();
32540 foreach ($this->package->getRequires() as $link) {
32541 $request->install($link->getTarget(), $link->getConstraint());
32542 }
32543
32544 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request);
32545 $solver = new Solver($policy, $pool, $installedRepo);
32546 $ops = $solver->solve($request, $this->ignorePlatformReqs);
32547 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $ops);
32548 foreach ($ops as $op) {
32549 if ($op->getJobType() === 'uninstall') {
32550 $devPackages[] = $op->getPackage();
32551 }
32552 }
32553 }
32554
32555 $platformReqs = $this->extractPlatformRequirements($this->package->getRequires());
32556 $platformDevReqs = $this->devMode ? $this->extractPlatformRequirements($this->package->getDevRequires()) : array();
32557
32558 $updatedLock = $this->locker->setLockData(
32559 array_diff($localRepo->getCanonicalPackages(), (array) $devPackages),
32560 $devPackages,
32561 $platformReqs,
32562 $platformDevReqs,
32563 $aliases,
32564 $this->package->getMinimumStability(),
32565 $this->package->getStabilityFlags(),
32566 $this->preferStable || $this->package->getPreferStable(),
32567 $this->preferLowest
32568 );
32569 if ($updatedLock) {
32570 $this->io->write('<info>Writing lock file</info>');
32571 }
32572 }
32573
32574 if ($this->dumpAutoloader) {
32575
32576  if ($this->optimizeAutoloader) {
32577 $this->io->write('<info>Generating optimized autoload files</info>');
32578 } else {
32579 $this->io->write('<info>Generating autoload files</info>');
32580 }
32581
32582 $this->autoloadGenerator->setDevMode($this->devMode);
32583 $this->autoloadGenerator->dump($this->config, $localRepo, $this->package, $this->installationManager, 'composer', $this->optimizeAutoloader);
32584 }
32585
32586 if ($this->runScripts) {
32587
32588  $eventName = $this->update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD;
32589 $this->eventDispatcher->dispatchCommandEvent($eventName, $this->devMode);
32590 }
32591
32592 $vendorDir = $this->config->get('vendor-dir');
32593 if (is_dir($vendorDir)) {
32594 touch($vendorDir);
32595 }
32596 }
32597
32598 return 0;
32599 }
32600
32601 protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases, $withDevReqs)
32602 {
32603
32604  $lockedRepository = null;
32605 $repositories = null;
32606
32607
32608  $installFromLock = false;
32609 if (!$this->update && $this->locker->isLocked()) {
32610 $installFromLock = true;
32611 try {
32612 $lockedRepository = $this->locker->getLockedRepository($withDevReqs);
32613 } catch (\RuntimeException $e) {
32614
32615  if ($this->package->getDevRequires()) {
32616 throw $e;
32617 }
32618
32619  $lockedRepository = $this->locker->getLockedRepository();
32620 }
32621 }
32622
32623 $this->whitelistUpdateDependencies(
32624 $localRepo,
32625 $withDevReqs,
32626 $this->package->getRequires(),
32627 $this->package->getDevRequires()
32628 );
32629
32630 $this->io->write('<info>Loading composer repositories with package information</info>');
32631
32632
32633  $policy = $this->createPolicy();
32634 $pool = $this->createPool($withDevReqs);
32635 $pool->addRepository($installedRepo, $aliases);
32636 if ($installFromLock) {
32637 $pool->addRepository($lockedRepository, $aliases);
32638 }
32639
32640 if (!$installFromLock) {
32641 $repositories = $this->repositoryManager->getRepositories();
32642 foreach ($repositories as $repository) {
32643 $pool->addRepository($repository, $aliases);
32644 }
32645 }
32646
32647
32648  $request = $this->createRequest($pool, $this->package, $platformRepo);
32649
32650 if (!$installFromLock) {
32651
32652  $removedUnstablePackages = array();
32653 foreach ($localRepo->getPackages() as $package) {
32654 if (
32655 !$pool->isPackageAcceptable($package->getNames(), $package->getStability())
32656 && $this->installationManager->isPackageInstalled($localRepo, $package)
32657 ) {
32658 $removedUnstablePackages[$package->getName()] = true;
32659 $request->remove($package->getName(), new VersionConstraint('=', $package->getVersion()));
32660 }
32661 }
32662 }
32663
32664 if ($this->update) {
32665 $this->io->write('<info>Updating dependencies'.($withDevReqs ? ' (including require-dev)' : '').'</info>');
32666
32667 $request->updateAll();
32668
32669 if ($withDevReqs) {
32670 $links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
32671 } else {
32672 $links = $this->package->getRequires();
32673 }
32674
32675 foreach ($links as $link) {
32676 $request->install($link->getTarget(), $link->getConstraint());
32677 }
32678
32679
32680  
32681  if ($this->updateWhitelist) {
32682 if ($this->locker->isLocked()) {
32683 try {
32684 $currentPackages = $this->locker->getLockedRepository($withDevReqs)->getPackages();
32685 } catch (\RuntimeException $e) {
32686
32687  $currentPackages = $this->locker->getLockedRepository()->getPackages();
32688 }
32689 } else {
32690 $currentPackages = $installedRepo->getPackages();
32691 }
32692
32693
32694  $candidates = array();
32695 foreach ($links as $link) {
32696 $candidates[$link->getTarget()] = true;
32697 }
32698 foreach ($localRepo->getPackages() as $package) {
32699 $candidates[$package->getName()] = true;
32700 }
32701
32702
32703  foreach ($candidates as $candidate => $dummy) {
32704 foreach ($currentPackages as $curPackage) {
32705 if ($curPackage->getName() === $candidate) {
32706 if (!$this->isUpdateable($curPackage) && !isset($removedUnstablePackages[$curPackage->getName()])) {
32707 $constraint = new VersionConstraint('=', $curPackage->getVersion());
32708 $request->install($curPackage->getName(), $constraint);
32709 }
32710 break;
32711 }
32712 }
32713 }
32714 }
32715 } elseif ($installFromLock) {
32716 $this->io->write('<info>Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').' from lock file</info>');
32717
32718 if (!$this->locker->isFresh()) {
32719 $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>');
32720 }
32721
32722 foreach ($lockedRepository->getPackages() as $package) {
32723 $version = $package->getVersion();
32724 if (isset($aliases[$package->getName()][$version])) {
32725 $version = $aliases[$package->getName()][$version]['alias_normalized'];
32726 }
32727 $constraint = new VersionConstraint('=', $version);
32728 $constraint->setPrettyString($package->getPrettyVersion());
32729 $request->install($package->getName(), $constraint);
32730 }
32731
32732 foreach ($this->locker->getPlatformRequirements($withDevReqs) as $link) {
32733 $request->install($link->getTarget(), $link->getConstraint());
32734 }
32735 } else {
32736 $this->io->write('<info>Installing dependencies'.($withDevReqs ? ' (including require-dev)' : '').'</info>');
32737
32738 if ($withDevReqs) {
32739 $links = array_merge($this->package->getRequires(), $this->package->getDevRequires());
32740 } else {
32741 $links = $this->package->getRequires();
32742 }
32743
32744 foreach ($links as $link) {
32745 $request->install($link->getTarget(), $link->getConstraint());
32746 }
32747 }
32748
32749
32750  $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links');
32751
32752
32753  $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request);
32754 $solver = new Solver($policy, $pool, $installedRepo);
32755 try {
32756 $operations = $solver->solve($request, $this->ignorePlatformReqs);
32757 $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $policy, $pool, $installedRepo, $request, $operations);
32758 } catch (SolverProblemsException $e) {
32759 $this->io->write('<error>Your requirements could not be resolved to an installable set of packages.</error>');
32760 $this->io->write($e->getMessage());
32761
32762 return max(1, $e->getCode());
32763 }
32764
32765
32766  $operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-updates', $operations);
32767
32768
32769  if (!$operations) {
32770 $this->io->write('Nothing to install or update');
32771 }
32772
32773 $operations = $this->movePluginsToFront($operations);
32774 $operations = $this->moveUninstallsToFront($operations);
32775
32776 foreach ($operations as $operation) {
32777
32778  if ('install' === $operation->getJobType()) {
32779 foreach ($operation->getPackage()->getSuggests() as $target => $reason) {
32780 $this->suggestedPackages[] = array(
32781 'source' => $operation->getPackage()->getPrettyName(),
32782 'target' => $target,
32783 'reason' => $reason,
32784 );
32785 }
32786 }
32787
32788
32789  if (!$installFromLock) {
32790 $package = null;
32791 if ('update' === $operation->getJobType()) {
32792 $package = $operation->getTargetPackage();
32793 } elseif ('install' === $operation->getJobType()) {
32794 $package = $operation->getPackage();
32795 }
32796 if ($package && $package->isDev()) {
32797 $references = $this->package->getReferences();
32798 if (isset($references[$package->getName()])) {
32799 $package->setSourceReference($references[$package->getName()]);
32800 $package->setDistReference($references[$package->getName()]);
32801 }
32802 }
32803 if ('update' === $operation->getJobType()
32804 && $operation->getTargetPackage()->isDev()
32805 && $operation->getTargetPackage()->getVersion() === $operation->getInitialPackage()->getVersion()
32806 && $operation->getTargetPackage()->getSourceReference() === $operation->getInitialPackage()->getSourceReference()
32807 ) {
32808 if ($this->io->isDebug()) {
32809 $this->io->write('  - Skipping update of '. $operation->getTargetPackage()->getPrettyName().' to the same reference-locked version');
32810 $this->io->write('');
32811 }
32812
32813 continue;
32814 }
32815 }
32816
32817 $event = 'Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType());
32818 if (defined($event) && $this->runScripts) {
32819 $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
32820 }
32821
32822
32823  if ($this->dryRun && false === strpos($operation->getJobType(), 'Alias')) {
32824 $this->io->write('  - ' . $operation);
32825 $this->io->write('');
32826 } elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) {
32827 $this->io->write('  - ' . $operation);
32828 $this->io->write('');
32829 }
32830
32831 $this->installationManager->execute($localRepo, $operation);
32832
32833
32834  if ($this->verbose && $this->io->isVeryVerbose() && in_array($operation->getJobType(), array('install', 'update'))) {
32835 $reason = $operation->getReason();
32836 if ($reason instanceof Rule) {
32837 switch ($reason->getReason()) {
32838 case Rule::RULE_JOB_INSTALL:
32839 $this->io->write('    REASON: Required by root: '.$reason->getPrettyString($pool));
32840 $this->io->write('');
32841 break;
32842 case Rule::RULE_PACKAGE_REQUIRES:
32843 $this->io->write('    REASON: '.$reason->getPrettyString($pool));
32844 $this->io->write('');
32845 break;
32846 }
32847 }
32848 }
32849
32850 $event = 'Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType());
32851 if (defined($event) && $this->runScripts) {
32852 $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
32853 }
32854
32855 if (!$this->dryRun) {
32856 $localRepo->write();
32857 }
32858 }
32859
32860 return 0;
32861 }
32862
32863
32864
32865
32866
32867
32868
32869
32870
32871
32872
32873
32874
32875
32876 private function movePluginsToFront(array $operations)
32877 {
32878 $installerOps = array();
32879 foreach ($operations as $idx => $op) {
32880 if ($op instanceof InstallOperation) {
32881 $package = $op->getPackage();
32882 } elseif ($op instanceof UpdateOperation) {
32883 $package = $op->getTargetPackage();
32884 } else {
32885 continue;
32886 }
32887
32888 if ($package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer') {
32889
32890  $requires = array_keys($package->getRequires());
32891 foreach ($requires as $index => $req) {
32892 if ($req === 'composer-plugin-api' || preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) {
32893 unset($requires[$index]);
32894 }
32895 }
32896
32897  if (!count($requires)) {
32898 $installerOps[] = $op;
32899 unset($operations[$idx]);
32900 }
32901 }
32902 }
32903
32904 return array_merge($installerOps, $operations);
32905 }
32906
32907
32908
32909
32910
32911
32912
32913
32914 private function moveUninstallsToFront(array $operations)
32915 {
32916 $uninstOps = array();
32917 foreach ($operations as $idx => $op) {
32918 if ($op instanceof UninstallOperation) {
32919 $uninstOps[] = $op;
32920 unset($operations[$idx]);
32921 }
32922 }
32923
32924 return array_merge($uninstOps, $operations);
32925 }
32926
32927 private function createPool($withDevReqs)
32928 {
32929 $minimumStability = $this->package->getMinimumStability();
32930 $stabilityFlags = $this->package->getStabilityFlags();
32931
32932 if (!$this->update && $this->locker->isLocked()) {
32933 $minimumStability = $this->locker->getMinimumStability();
32934 $stabilityFlags = $this->locker->getStabilityFlags();
32935 }
32936
32937 $requires = $this->package->getRequires();
32938 if ($withDevReqs) {
32939 $requires = array_merge($requires, $this->package->getDevRequires());
32940 }
32941 $rootConstraints = array();
32942 foreach ($requires as $req => $constraint) {
32943
32944  if ($this->ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req)) {
32945 continue;
32946 }
32947 $rootConstraints[$req] = $constraint->getConstraint();
32948 }
32949
32950 return new Pool($minimumStability, $stabilityFlags, $rootConstraints);
32951 }
32952
32953 private function createPolicy()
32954 {
32955 $preferStable = null;
32956 $preferLowest = null;
32957 if (!$this->update && $this->locker->isLocked()) {
32958 $preferStable = $this->locker->getPreferStable();
32959 $preferLowest = $this->locker->getPreferLowest();
32960 }
32961
32962  
32963  if (null === $preferStable) {
32964 $preferStable = $this->preferStable || $this->package->getPreferStable();
32965 }
32966 if (null === $preferLowest) {
32967 $preferLowest = $this->preferLowest;
32968 }
32969
32970 return new DefaultPolicy($preferStable, $preferLowest);
32971 }
32972
32973 private function createRequest(Pool $pool, RootPackageInterface $rootPackage, PlatformRepository $platformRepo)
32974 {
32975 $request = new Request($pool);
32976
32977 $constraint = new VersionConstraint('=', $rootPackage->getVersion());
32978 $constraint->setPrettyString($rootPackage->getPrettyVersion());
32979 $request->install($rootPackage->getName(), $constraint);
32980
32981 $fixedPackages = $platformRepo->getPackages();
32982 if ($this->additionalInstalledRepository) {
32983 $additionalFixedPackages = $this->additionalInstalledRepository->getPackages();
32984 $fixedPackages = array_merge($fixedPackages, $additionalFixedPackages);
32985 }
32986
32987
32988  
32989  $provided = $rootPackage->getProvides();
32990 foreach ($fixedPackages as $package) {
32991 $constraint = new VersionConstraint('=', $package->getVersion());
32992 $constraint->setPrettyString($package->getPrettyVersion());
32993
32994
32995  if ($package->getRepository() !== $platformRepo
32996 || !isset($provided[$package->getName()])
32997 || !$provided[$package->getName()]->getConstraint()->matches($constraint)
32998 ) {
32999 $request->fix($package->getName(), $constraint);
33000 }
33001 }
33002
33003 return $request;
33004 }
33005
33006 private function processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, $task, array $operations = null)
33007 {
33008 if ($task === 'force-updates' && null === $operations) {
33009 throw new \InvalidArgumentException('Missing operations argument');
33010 }
33011 if ($task === 'force-links') {
33012 $operations = array();
33013 }
33014
33015 foreach ($localRepo->getCanonicalPackages() as $package) {
33016
33017  if (!$package->isDev()) {
33018 continue;
33019 }
33020
33021
33022  foreach ($operations as $operation) {
33023 if (('update' === $operation->getJobType() && $operation->getInitialPackage()->equals($package))
33024 || ('uninstall' === $operation->getJobType() && $operation->getPackage()->equals($package))
33025 ) {
33026 continue 2;
33027 }
33028 }
33029
33030
33031  if ($installFromLock) {
33032 foreach ($lockedRepository->findPackages($package->getName()) as $lockedPackage) {
33033 if ($lockedPackage->isDev() && $lockedPackage->getVersion() === $package->getVersion()) {
33034 if ($task === 'force-links') {
33035 $package->setRequires($lockedPackage->getRequires());
33036 $package->setConflicts($lockedPackage->getConflicts());
33037 $package->setProvides($lockedPackage->getProvides());
33038 $package->setReplaces($lockedPackage->getReplaces());
33039 } elseif ($task === 'force-updates') {
33040 if (($lockedPackage->getSourceReference() && $lockedPackage->getSourceReference() !== $package->getSourceReference())
33041 || ($lockedPackage->getDistReference() && $lockedPackage->getDistReference() !== $package->getDistReference())
33042 ) {
33043 $operations[] = new UpdateOperation($package, $lockedPackage);
33044 }
33045 }
33046
33047 break;
33048 }
33049 }
33050 } else {
33051
33052  if ($this->update) {
33053
33054  if ($this->updateWhitelist && !$this->isUpdateable($package)) {
33055 continue;
33056 }
33057
33058
33059  $matches = $pool->whatProvides($package->getName(), new VersionConstraint('=', $package->getVersion()));
33060 foreach ($matches as $index => $match) {
33061
33062  if (!in_array($match->getRepository(), $repositories, true)) {
33063 unset($matches[$index]);
33064 continue;
33065 }
33066
33067
33068  if ($match->getName() !== $package->getName()) {
33069 unset($matches[$index]);
33070 continue;
33071 }
33072
33073 $matches[$index] = $match->getId();
33074 }
33075
33076
33077  if ($matches && $matches = $policy->selectPreferedPackages($pool, array(), $matches)) {
33078 $newPackage = $pool->literalToPackage($matches[0]);
33079
33080 if ($task === 'force-links' && $newPackage) {
33081 $package->setRequires($newPackage->getRequires());
33082 $package->setConflicts($newPackage->getConflicts());
33083 $package->setProvides($newPackage->getProvides());
33084 $package->setReplaces($newPackage->getReplaces());
33085 }
33086
33087 if ($task === 'force-updates' && $newPackage && (
33088 (($newPackage->getSourceReference() && $newPackage->getSourceReference() !== $package->getSourceReference())
33089 || ($newPackage->getDistReference() && $newPackage->getDistReference() !== $package->getDistReference())
33090 )
33091 )) {
33092 $operations[] = new UpdateOperation($package, $newPackage);
33093 }
33094 }
33095 }
33096
33097 if ($task === 'force-updates') {
33098
33099  $references = $this->package->getReferences();
33100
33101 if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) {
33102
33103  $operations[] = new UpdateOperation($package, clone $package);
33104 }
33105 }
33106 }
33107 }
33108
33109 return $operations;
33110 }
33111
33112 private function getRootAliases()
33113 {
33114 if (!$this->update && $this->locker->isLocked()) {
33115 $aliases = $this->locker->getAliases();
33116 } else {
33117 $aliases = $this->package->getAliases();
33118 }
33119
33120 $normalizedAliases = array();
33121
33122 foreach ($aliases as $alias) {
33123 $normalizedAliases[$alias['package']][$alias['version']] = array(
33124 'alias' => $alias['alias'],
33125 'alias_normalized' => $alias['alias_normalized']
33126 );
33127 }
33128
33129 return $normalizedAliases;
33130 }
33131
33132 private function aliasPlatformPackages(PlatformRepository $platformRepo, $aliases)
33133 {
33134 foreach ($aliases as $package => $versions) {
33135 foreach ($versions as $version => $alias) {
33136 $packages = $platformRepo->findPackages($package, $version);
33137 foreach ($packages as $package) {
33138 $aliasPackage = new AliasPackage($package, $alias['alias_normalized'], $alias['alias']);
33139 $aliasPackage->setRootPackageAlias(true);
33140 $platformRepo->addPackage($aliasPackage);
33141 }
33142 }
33143 }
33144 }
33145
33146 private function isUpdateable(PackageInterface $package)
33147 {
33148 if (!$this->updateWhitelist) {
33149 throw new \LogicException('isUpdateable should only be called when a whitelist is present');
33150 }
33151
33152 foreach ($this->updateWhitelist as $whiteListedPattern => $void) {
33153 $patternRegexp = $this->packageNameToRegexp($whiteListedPattern);
33154 if (preg_match($patternRegexp, $package->getName())) {
33155 return true;
33156 }
33157 }
33158
33159 return false;
33160 }
33161
33162
33163
33164
33165
33166
33167
33168 private function packageNameToRegexp($whiteListedPattern)
33169 {
33170 $cleanedWhiteListedPattern = str_replace('\\*', '.*', preg_quote($whiteListedPattern));
33171
33172 return "{^" . $cleanedWhiteListedPattern . "$}i";
33173 }
33174
33175 private function extractPlatformRequirements($links)
33176 {
33177 $platformReqs = array();
33178 foreach ($links as $link) {
33179 if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) {
33180 $platformReqs[$link->getTarget()] = $link->getPrettyConstraint();
33181 }
33182 }
33183
33184 return $platformReqs;
33185 }
33186
33187
33188
33189
33190
33191
33192
33193
33194
33195
33196
33197
33198
33199 private function whitelistUpdateDependencies($localRepo, $devMode, array $rootRequires, array $rootDevRequires)
33200 {
33201 if (!$this->updateWhitelist) {
33202 return;
33203 }
33204
33205 $requiredPackageNames = array();
33206 foreach (array_merge($rootRequires, $rootDevRequires) as $require) {
33207 $requiredPackageNames[] = $require->getTarget();
33208 }
33209
33210 if ($devMode) {
33211 $rootRequires = array_merge($rootRequires, $rootDevRequires);
33212 }
33213
33214 $skipPackages = array();
33215 foreach ($rootRequires as $require) {
33216 $skipPackages[$require->getTarget()] = true;
33217 }
33218
33219 $pool = new Pool;
33220 $pool->addRepository($localRepo);
33221
33222 $seen = array();
33223
33224 $rootRequiredPackageNames = array_keys($rootRequires);
33225
33226 foreach ($this->updateWhitelist as $packageName => $void) {
33227 $packageQueue = new \SplQueue;
33228
33229 $depPackages = $pool->whatProvides($packageName);
33230
33231 $nameMatchesRequiredPackage = in_array($packageName, $requiredPackageNames, true);
33232
33233
33234  if (!$nameMatchesRequiredPackage) {
33235 $whitelistPatternRegexp = $this->packageNameToRegexp($packageName);
33236 foreach ($rootRequiredPackageNames as $rootRequiredPackageName) {
33237 if (preg_match($whitelistPatternRegexp, $rootRequiredPackageName)) {
33238 $nameMatchesRequiredPackage = true;
33239 break;
33240 }
33241 }
33242 }
33243
33244 if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock'))) {
33245 $this->io->write('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>');
33246 }
33247
33248 foreach ($depPackages as $depPackage) {
33249 $packageQueue->enqueue($depPackage);
33250 }
33251
33252 while (!$packageQueue->isEmpty()) {
33253 $package = $packageQueue->dequeue();
33254 if (isset($seen[$package->getId()])) {
33255 continue;
33256 }
33257
33258 $seen[$package->getId()] = true;
33259 $this->updateWhitelist[$package->getName()] = true;
33260
33261 if (!$this->whitelistDependencies) {
33262 continue;
33263 }
33264
33265 $requires = $package->getRequires();
33266
33267 foreach ($requires as $require) {
33268 $requirePackages = $pool->whatProvides($require->getTarget());
33269
33270 foreach ($requirePackages as $requirePackage) {
33271 if (isset($skipPackages[$requirePackage->getName()])) {
33272 continue;
33273 }
33274 $packageQueue->enqueue($requirePackage);
33275 }
33276 }
33277 }
33278 }
33279 }
33280
33281
33282
33283
33284
33285
33286
33287
33288 private function mockLocalRepositories(RepositoryManager $rm)
33289 {
33290 $packages = array();
33291 foreach ($rm->getLocalRepository()->getPackages() as $package) {
33292 $packages[(string) $package] = clone $package;
33293 }
33294 foreach ($packages as $key => $package) {
33295 if ($package instanceof AliasPackage) {
33296 $alias = (string) $package->getAliasOf();
33297 $packages[$key] = new AliasPackage($packages[$alias], $package->getVersion(), $package->getPrettyVersion());
33298 }
33299 }
33300 $rm->setLocalRepository(
33301 new InstalledArrayRepository($packages)
33302 );
33303 }
33304
33305
33306
33307
33308
33309
33310
33311
33312 public static function create(IOInterface $io, Composer $composer)
33313 {
33314 return new static(
33315 $io,
33316 $composer->getConfig(),
33317 $composer->getPackage(),
33318 $composer->getDownloadManager(),
33319 $composer->getRepositoryManager(),
33320 $composer->getLocker(),
33321 $composer->getInstallationManager(),
33322 $composer->getEventDispatcher(),
33323 $composer->getAutoloadGenerator()
33324 );
33325 }
33326
33327 public function setAdditionalInstalledRepository(RepositoryInterface $additionalInstalledRepository)
33328 {
33329 $this->additionalInstalledRepository = $additionalInstalledRepository;
33330
33331 return $this;
33332 }
33333
33334
33335
33336
33337
33338
33339
33340 public function setDryRun($dryRun = true)
33341 {
33342 $this->dryRun = (boolean) $dryRun;
33343
33344 return $this;
33345 }
33346
33347
33348
33349
33350
33351
33352 public function isDryRun()
33353 {
33354 return $this->dryRun;
33355 }
33356
33357
33358
33359
33360
33361
33362
33363 public function setPreferSource($preferSource = true)
33364 {
33365 $this->preferSource = (boolean) $preferSource;
33366
33367 return $this;
33368 }
33369
33370
33371
33372
33373
33374
33375
33376 public function setPreferDist($preferDist = true)
33377 {
33378 $this->preferDist = (boolean) $preferDist;
33379
33380 return $this;
33381 }
33382
33383
33384
33385
33386
33387
33388
33389 public function setOptimizeAutoloader($optimizeAutoloader = false)
33390 {
33391 $this->optimizeAutoloader = (boolean) $optimizeAutoloader;
33392
33393 return $this;
33394 }
33395
33396
33397
33398
33399
33400
33401
33402 public function setUpdate($update = true)
33403 {
33404 $this->update = (boolean) $update;
33405
33406 return $this;
33407 }
33408
33409
33410
33411
33412
33413
33414
33415 public function setDevMode($devMode = true)
33416 {
33417 $this->devMode = (boolean) $devMode;
33418
33419 return $this;
33420 }
33421
33422
33423
33424
33425
33426
33427
33428
33429 public function setDumpAutoloader($dumpAutoloader = true)
33430 {
33431 $this->dumpAutoloader = (boolean) $dumpAutoloader;
33432
33433 return $this;
33434 }
33435
33436
33437
33438
33439
33440
33441
33442
33443 public function setRunScripts($runScripts = true)
33444 {
33445 $this->runScripts = (boolean) $runScripts;
33446
33447 return $this;
33448 }
33449
33450
33451
33452
33453
33454
33455
33456 public function setConfig(Config $config)
33457 {
33458 $this->config = $config;
33459
33460 return $this;
33461 }
33462
33463
33464
33465
33466
33467
33468
33469 public function setVerbose($verbose = true)
33470 {
33471 $this->verbose = (boolean) $verbose;
33472
33473 return $this;
33474 }
33475
33476
33477
33478
33479
33480
33481 public function isVerbose()
33482 {
33483 return $this->verbose;
33484 }
33485
33486
33487
33488
33489
33490
33491
33492 public function setIgnorePlatformRequirements($ignorePlatformReqs = false)
33493 {
33494 $this->ignorePlatformReqs = (boolean) $ignorePlatformReqs;
33495
33496 return $this;
33497 }
33498
33499
33500
33501
33502
33503
33504
33505
33506 public function setUpdateWhitelist(array $packages)
33507 {
33508 $this->updateWhitelist = array_flip(array_map('strtolower', $packages));
33509
33510 return $this;
33511 }
33512
33513
33514
33515
33516
33517
33518
33519 public function setWhitelistDependencies($updateDependencies = true)
33520 {
33521 $this->whitelistDependencies = (boolean) $updateDependencies;
33522
33523 return $this;
33524 }
33525
33526
33527
33528
33529
33530
33531
33532 public function setPreferStable($preferStable = true)
33533 {
33534 $this->preferStable = (boolean) $preferStable;
33535
33536 return $this;
33537 }
33538
33539
33540
33541
33542
33543
33544
33545 public function setPreferLowest($preferLowest = true)
33546 {
33547 $this->preferLowest = (boolean) $preferLowest;
33548
33549 return $this;
33550 }
33551
33552
33553
33554
33555
33556
33557
33558
33559
33560
33561 public function disablePlugins()
33562 {
33563 $this->installationManager->disablePlugins();
33564
33565 return $this;
33566 }
33567 }
33568 <?php
33569
33570 /*
33571  * This file is part of Composer.
33572  *
33573  * (c) Nils Adermann <naderman@naderman.de>
33574  *     Jordi Boggiano <j.boggiano@seld.be>
33575  *
33576  * For the full copyright and license information, please view the LICENSE
33577  * file that was distributed with this source code.
33578  */
33579
33580 namespace Composer\Autoload;
33581
33582 /**
33583  * ClassLoader implements a PSR-0 class loader
33584  *
33585  * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
33586  *
33587  *     $loader = new \Composer\Autoload\ClassLoader();
33588  *
33589  *     // register classes with namespaces
33590  *     $loader->add('Symfony\Component', __DIR__.'/component');
33591  *     $loader->add('Symfony',           __DIR__.'/framework');
33592  *
33593  *     // activate the autoloader
33594  *     $loader->register();
33595  *
33596  *     // to enable searching the include path (eg. for PEAR packages)
33597  *     $loader->setUseIncludePath(true);
33598  *
33599  * In this example, if you try to use a class in the Symfony\Component
33600  * namespace or one of its children (Symfony\Component\Console for instance),
33601  * the autoloader will first look for the class under the component/
33602  * directory, and it will then fallback to the framework/ directory if not
33603  * found before giving up.
33604  *
33605  * This class is loosely based on the Symfony UniversalClassLoader.
33606  *
33607  * @author Fabien Potencier <fabien@symfony.com>
33608  * @author Jordi Boggiano <j.boggiano@seld.be>
33609  */
33610 class ClassLoader
33611 {
33612     // PSR-4
33613     private $prefixLengthsPsr4 = array();
33614     private $prefixDirsPsr4 = array();
33615     private $fallbackDirsPsr4 = array();
33616
33617     // PSR-0
33618     private $prefixesPsr0 = array();
33619     private $fallbackDirsPsr0 = array();
33620
33621     private $useIncludePath = false;
33622     private $classMap = array();
33623
33624     public function getPrefixes()
33625     {
33626         if (!empty($this->prefixesPsr0)) {
33627             return call_user_func_array('array_merge', $this->prefixesPsr0);
33628         }
33629
33630         return array();
33631     }
33632
33633     public function getPrefixesPsr4()
33634     {
33635         return $this->prefixDirsPsr4;
33636     }
33637
33638     public function getFallbackDirs()
33639     {
33640         return $this->fallbackDirsPsr0;
33641     }
33642
33643     public function getFallbackDirsPsr4()
33644     {
33645         return $this->fallbackDirsPsr4;
33646     }
33647
33648     public function getClassMap()
33649     {
33650         return $this->classMap;
33651     }
33652
33653     /**
33654      * @param array $classMap Class to filename map
33655      */
33656     public function addClassMap(array $classMap)
33657     {
33658         if ($this->classMap) {
33659             $this->classMap = array_merge($this->classMap, $classMap);
33660         } else {
33661             $this->classMap = $classMap;
33662         }
33663     }
33664
33665     /**
33666      * Registers a set of PSR-0 directories for a given prefix, either
33667      * appending or prepending to the ones previously set for this prefix.
33668      *
33669      * @param string       $prefix  The prefix
33670      * @param array|string $paths   The PSR-0 root directories
33671      * @param bool         $prepend Whether to prepend the directories
33672      */
33673     public function add($prefix, $paths, $prepend = false)
33674     {
33675         if (!$prefix) {
33676             if ($prepend) {
33677                 $this->fallbackDirsPsr0 = array_merge(
33678                     (array) $paths,
33679                     $this->fallbackDirsPsr0
33680                 );
33681             } else {
33682                 $this->fallbackDirsPsr0 = array_merge(
33683                     $this->fallbackDirsPsr0,
33684                     (array) $paths
33685                 );
33686             }
33687
33688             return;
33689         }
33690
33691         $first = $prefix[0];
33692         if (!isset($this->prefixesPsr0[$first][$prefix])) {
33693             $this->prefixesPsr0[$first][$prefix] = (array) $paths;
33694
33695             return;
33696         }
33697         if ($prepend) {
33698             $this->prefixesPsr0[$first][$prefix] = array_merge(
33699                 (array) $paths,
33700                 $this->prefixesPsr0[$first][$prefix]
33701             );
33702         } else {
33703             $this->prefixesPsr0[$first][$prefix] = array_merge(
33704                 $this->prefixesPsr0[$first][$prefix],
33705                 (array) $paths
33706             );
33707         }
33708     }
33709
33710     /**
33711      * Registers a set of PSR-4 directories for a given namespace, either
33712      * appending or prepending to the ones previously set for this namespace.
33713      *
33714      * @param string       $prefix  The prefix/namespace, with trailing '\\'
33715      * @param array|string $paths   The PSR-0 base directories
33716      * @param bool         $prepend Whether to prepend the directories
33717      *
33718      * @throws \InvalidArgumentException
33719      */
33720     public function addPsr4($prefix, $paths, $prepend = false)
33721     {
33722         if (!$prefix) {
33723             // Register directories for the root namespace.
33724             if ($prepend) {
33725                 $this->fallbackDirsPsr4 = array_merge(
33726                     (array) $paths,
33727                     $this->fallbackDirsPsr4
33728                 );
33729             } else {
33730                 $this->fallbackDirsPsr4 = array_merge(
33731                     $this->fallbackDirsPsr4,
33732                     (array) $paths
33733                 );
33734             }
33735         } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
33736             // Register directories for a new namespace.
33737             $length = strlen($prefix);
33738             if ('\\' !== $prefix[$length - 1]) {
33739                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
33740             }
33741             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
33742             $this->prefixDirsPsr4[$prefix] = (array) $paths;
33743         } elseif ($prepend) {
33744             // Prepend directories for an already registered namespace.
33745             $this->prefixDirsPsr4[$prefix] = array_merge(
33746                 (array) $paths,
33747                 $this->prefixDirsPsr4[$prefix]
33748             );
33749         } else {
33750             // Append directories for an already registered namespace.
33751             $this->prefixDirsPsr4[$prefix] = array_merge(
33752                 $this->prefixDirsPsr4[$prefix],
33753                 (array) $paths
33754             );
33755         }
33756     }
33757
33758     /**
33759      * Registers a set of PSR-0 directories for a given prefix,
33760      * replacing any others previously set for this prefix.
33761      *
33762      * @param string       $prefix The prefix
33763      * @param array|string $paths  The PSR-0 base directories
33764      */
33765     public function set($prefix, $paths)
33766     {
33767         if (!$prefix) {
33768             $this->fallbackDirsPsr0 = (array) $paths;
33769         } else {
33770             $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
33771         }
33772     }
33773
33774     /**
33775      * Registers a set of PSR-4 directories for a given namespace,
33776      * replacing any others previously set for this namespace.
33777      *
33778      * @param string       $prefix The prefix/namespace, with trailing '\\'
33779      * @param array|string $paths  The PSR-4 base directories
33780      *
33781      * @throws \InvalidArgumentException
33782      */
33783     public function setPsr4($prefix, $paths)
33784     {
33785         if (!$prefix) {
33786             $this->fallbackDirsPsr4 = (array) $paths;
33787         } else {
33788             $length = strlen($prefix);
33789             if ('\\' !== $prefix[$length - 1]) {
33790                 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
33791             }
33792             $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
33793             $this->prefixDirsPsr4[$prefix] = (array) $paths;
33794         }
33795     }
33796
33797     /**
33798      * Turns on searching the include path for class files.
33799      *
33800      * @param bool $useIncludePath
33801      */
33802     public function setUseIncludePath($useIncludePath)
33803     {
33804         $this->useIncludePath = $useIncludePath;
33805     }
33806
33807     /**
33808      * Can be used to check if the autoloader uses the include path to check
33809      * for classes.
33810      *
33811      * @return bool
33812      */
33813     public function getUseIncludePath()
33814     {
33815         return $this->useIncludePath;
33816     }
33817
33818     /**
33819      * Registers this instance as an autoloader.
33820      *
33821      * @param bool $prepend Whether to prepend the autoloader or not
33822      */
33823     public function register($prepend = false)
33824     {
33825         spl_autoload_register(array($this, 'loadClass'), true, $prepend);
33826     }
33827
33828     /**
33829      * Unregisters this instance as an autoloader.
33830      */
33831     public function unregister()
33832     {
33833         spl_autoload_unregister(array($this, 'loadClass'));
33834     }
33835
33836     /**
33837      * Loads the given class or interface.
33838      *
33839      * @param  string    $class The name of the class
33840      * @return bool|null True if loaded, null otherwise
33841      */
33842     public function loadClass($class)
33843     {
33844         if ($file = $this->findFile($class)) {
33845             includeFile($file);
33846
33847             return true;
33848         }
33849     }
33850
33851     /**
33852      * Finds the path to the file where the class is defined.
33853      *
33854      * @param string $class The name of the class
33855      *
33856      * @return string|false The path if found, false otherwise
33857      */
33858     public function findFile($class)
33859     {
33860         // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
33861         if ('\\' == $class[0]) {
33862             $class = substr($class, 1);
33863         }
33864
33865         // class map lookup
33866         if (isset($this->classMap[$class])) {
33867             return $this->classMap[$class];
33868         }
33869
33870         $file = $this->findFileWithExtension($class, '.php');
33871
33872         // Search for Hack files if we are running on HHVM
33873         if ($file === null && defined('HHVM_VERSION')) {
33874             $file = $this->findFileWithExtension($class, '.hh');
33875         }
33876
33877         if ($file === null) {
33878             // Remember that this class does not exist.
33879             return $this->classMap[$class] = false;
33880         }
33881
33882         return $file;
33883     }
33884
33885     private function findFileWithExtension($class, $ext)
33886     {
33887         // PSR-4 lookup
33888         $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
33889
33890         $first = $class[0];
33891         if (isset($this->prefixLengthsPsr4[$first])) {
33892             foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
33893                 if (0 === strpos($class, $prefix)) {
33894                     foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
33895                         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
33896                             return $file;
33897                         }
33898                     }
33899                 }
33900             }
33901         }
33902
33903         // PSR-4 fallback dirs
33904         foreach ($this->fallbackDirsPsr4 as $dir) {
33905             if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
33906                 return $file;
33907             }
33908         }
33909
33910         // PSR-0 lookup
33911         if (false !== $pos = strrpos($class, '\\')) {
33912             // namespaced class name
33913             $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
33914                 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
33915         } else {
33916             // PEAR-like class name
33917             $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
33918         }
33919
33920         if (isset($this->prefixesPsr0[$first])) {
33921             foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
33922                 if (0 === strpos($class, $prefix)) {
33923                     foreach ($dirs as $dir) {
33924                         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
33925                             return $file;
33926                         }
33927                     }
33928                 }
33929             }
33930         }
33931
33932         // PSR-0 fallback dirs
33933         foreach ($this->fallbackDirsPsr0 as $dir) {
33934             if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
33935                 return $file;
33936             }
33937         }
33938
33939         // PSR-0 include paths.
33940         if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
33941             return $file;
33942         }
33943     }
33944 }
33945
33946 /**
33947  * Scope isolated include.
33948  *
33949  * Prevents access to $this/self from included files.
33950  */
33951 function includeFile($file)
33952 {
33953     include $file;
33954 }
33955 [
33956     "Glide", "Abstyles", "AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0",
33957     "AMPAS", "APL-1.0", "Adobe-Glyph", "APAFML", "Adobe-2006", "AGPL-1.0",
33958     "Afmparse", "Aladdin", "ADSL", "AMDPLPA", "ANTLR-PD", "Apache-1.0",
33959     "Apache-1.1", "Apache-2.0", "AML", "APSL-1.0", "APSL-1.1", "APSL-1.2",
33960     "APSL-2.0", "Artistic-1.0", "Artistic-1.0-Perl", "Artistic-1.0-cl8",
33961     "Artistic-2.0", "AAL", "Bahyph", "Barr", "Beerware", "BitTorrent-1.0",
33962     "BitTorrent-1.1", "BSL-1.0", "Borceux", "BSD-2-Clause",
33963     "BSD-2-Clause-FreeBSD", "BSD-2-Clause-NetBSD", "BSD-3-Clause",
33964     "BSD-3-Clause-Clear", "BSD-4-Clause", "BSD-Protection",
33965     "BSD-3-Clause-Attribution", "BSD-4-Clause-UC", "bzip2-1.0.5", "bzip2-1.0.6",
33966     "Caldera", "CECILL-1.0", "CECILL-1.1", "CECILL-2.0", "CECILL-B", "CECILL-C",
33967     "ClArtistic", "MIT-CMU", "CNRI-Python", "CNRI-Python-GPL-Compatible",
33968     "CPOL-1.02", "CDDL-1.0", "CDDL-1.1", "CPAL-1.0", "CPL-1.0", "CATOSL-1.1",
33969     "Condor-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5", "CC-BY-3.0",
33970     "CC-BY-4.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0",
33971     "CC-BY-ND-4.0", "CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5",
33972     "CC-BY-NC-3.0", "CC-BY-NC-4.0", "CC-BY-NC-ND-1.0", "CC-BY-NC-ND-2.0",
33973     "CC-BY-NC-ND-2.5", "CC-BY-NC-ND-3.0", "CC-BY-NC-ND-4.0", "CC-BY-NC-SA-1.0",
33974     "CC-BY-NC-SA-2.0", "CC-BY-NC-SA-2.5", "CC-BY-NC-SA-3.0", "CC-BY-NC-SA-4.0",
33975     "CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.5", "CC-BY-SA-3.0",
33976     "CC-BY-SA-4.0", "CC0-1.0", "Crossword", "CUA-OPL-1.0", "Cube", "D-FSL-1.0",
33977     "diffmark", "WTFPL", "DOC", "Dotseqn", "DSDP", "dvipdfm", "EPL-1.0",
33978     "eCos-2.0", "ECL-1.0", "ECL-2.0", "eGenix", "EFL-1.0", "EFL-2.0",
33979     "MIT-advertising", "MIT-enna", "Entessa", "ErlPL-1.1", "EUDatagrid",
33980     "EUPL-1.0", "EUPL-1.1", "Eurosym", "Fair", "MIT-feh", "Frameworx-1.0",
33981     "FTL", "FSFUL", "FSFULLR", "Giftware", "GL2PS", "Glulxe", "AGPL-3.0",
33982     "GFDL-1.1", "GFDL-1.2", "GFDL-1.3", "GPL-1.0", "GPL-1.0+", "GPL-2.0",
33983     "GPL-2.0+", "GPL-2.0-with-autoconf-exception",
33984     "GPL-2.0-with-bison-exception", "GPL-2.0-with-classpath-exception",
33985     "GPL-2.0-with-font-exception", "GPL-2.0-with-GCC-exception", "GPL-3.0",
33986     "GPL-3.0+", "GPL-3.0-with-autoconf-exception", "GPL-3.0-with-GCC-exception",
33987     "LGPL-2.1", "LGPL-2.1+", "LGPL-3.0", "LGPL-3.0+", "LGPL-2.0", "LGPL-2.0+",
33988     "gnuplot", "gSOAP-1.3b", "HaskellReport", "HPND", "IBM-pibs", "IPL-1.0",
33989     "ImageMagick", "iMatix", "Imlib2", "IJG", "Intel-ACPI", "Intel", "IPA",
33990     "ISC", "JasPer-2.0", "JSON", "LPPL-1.3a", "LPPL-1.0", "LPPL-1.1",
33991     "LPPL-1.2", "LPPL-1.3c", "Latex2e", "BSD-3-Clause-LBNL", "Leptonica",
33992     "Libpng", "libtiff", "LPL-1.02", "LPL-1.0", "MakeIndex", "MTLL", "MS-PL",
33993     "MS-RL", "MirOS", "MITNFA", "MIT", "Motosoto", "MPL-1.0", "MPL-1.1",
33994     "MPL-2.0", "MPL-2.0-no-copyleft-exception", "mpich2", "Multics", "Mup",
33995     "NASA-1.3", "Naumen", "NBPL-1.0", "NetCDF", "NGPL", "NOSL", "NPL-1.0",
33996     "NPL-1.1", "Newsletr", "NLPL", "Nokia", "NPOSL-3.0", "Noweb", "NRL", "NTP",
33997     "Nunit", "OCLC-2.0", "ODbL-1.0", "PDDL-1.0", "OGTSL", "OLDAP-2.2.2",
33998     "OLDAP-1.1", "OLDAP-1.2", "OLDAP-1.3", "OLDAP-1.4", "OLDAP-2.0",
33999     "OLDAP-2.0.1", "OLDAP-2.1", "OLDAP-2.2", "OLDAP-2.2.1", "OLDAP-2.3",
34000     "OLDAP-2.4", "OLDAP-2.5", "OLDAP-2.6", "OLDAP-2.7", "OML", "OPL-1.0",
34001     "OSL-1.0", "OSL-1.1", "OSL-2.0", "OSL-2.1", "OSL-3.0", "OLDAP-2.8",
34002     "OpenSSL", "PHP-3.0", "PHP-3.01", "Plexus", "PostgreSQL", "psfrag",
34003     "psutils", "Python-2.0", "QPL-1.0", "Qhull", "Rdisc", "RPSL-1.0", "RPL-1.1",
34004     "RPL-1.5", "RHeCos-1.1", "RSCPL", "Ruby", "SAX-PD", "Saxpath", "SCEA",
34005     "SWL", "SGI-B-1.0", "SGI-B-1.1", "SGI-B-2.0", "OFL-1.0", "OFL-1.1",
34006     "SimPL-2.0", "Sleepycat", "SNIA", "SMLNJ", "StandardML-NJ",
34007     "SugarCRM-1.1.3", "SISSL", "SISSL-1.2", "SPL-1.0", "Watcom-1.0", "TCL",
34008     "Unlicense", "TMate", "TORQUE-1.1", "TOSL", "Unicode-TOU", "NCSA", "Vim",
34009     "VOSTROM", "VSL-1.0", "W3C", "Wsuipa", "WXwindows", "Xnet", "X11", "Xerox",
34010     "XFree86-1.1", "xinetd", "xpp", "XSkat", "YPL-1.0", "YPL-1.1", "Zed",
34011     "Zend-2.0", "Zimbra-1.3", "Zlib", "zlib-acknowledgement", "ZPL-1.1",
34012     "ZPL-2.0", "ZPL-2.1"
34013 ]
34014 {
34015     "$schema": "http://json-schema.org/draft-04/schema#",
34016     "name": "Package",
34017     "type": "object",
34018     "additionalProperties": false,
34019     "required": [ "name", "description" ],
34020     "properties": {
34021         "name": {
34022             "type": "string",
34023             "description": "Package name, including 'vendor-name/' prefix."
34024         },
34025         "type": {
34026             "description": "Package type, either 'library' for common packages, 'composer-plugin' for plugins, 'metapackage' for empty packages, or a custom type ([a-z0-9-]+) defined by whatever project this package applies to.",
34027             "type": "string"
34028         },
34029         "target-dir": {
34030             "description": "DEPRECATED: Forces the package to be installed into the given subdirectory path. This is used for autoloading PSR-0 packages that do not contain their full path. Use forward slashes for cross-platform compatibility.",
34031             "type": "string"
34032         },
34033         "description": {
34034             "type": "string",
34035             "description": "Short package description."
34036         },
34037         "keywords": {
34038             "type": "array",
34039             "items": {
34040                 "type": "string",
34041                 "description": "A tag/keyword that this package relates to."
34042             }
34043         },
34044         "homepage": {
34045             "type": "string",
34046             "description": "Homepage URL for the project.",
34047             "format": "uri"
34048         },
34049         "version": {
34050             "type": "string",
34051             "description": "Package version, see http://getcomposer.org/doc/04-schema.md#version for more info on valid schemes."
34052         },
34053         "time": {
34054             "type": "string",
34055             "description": "Package release date, in 'YYYY-MM-DD', 'YYYY-MM-DD HH:MM:SS' or 'YYYY-MM-DDTHH:MM:SSZ' format."
34056         },
34057         "license": {
34058             "type": ["string", "array"],
34059             "description": "License name. Or an array of license names."
34060         },
34061         "authors": {
34062             "type": "array",
34063             "description": "List of authors that contributed to the package. This is typically the main maintainers, not the full list.",
34064             "items": {
34065                 "type": "object",
34066                 "additionalProperties": false,
34067                 "required": [ "name"],
34068                 "properties": {
34069                     "name": {
34070                         "type": "string",
34071                         "description": "Full name of the author."
34072                     },
34073                     "email": {
34074                         "type": "string",
34075                         "description": "Email address of the author.",
34076                         "format": "email"
34077                     },
34078                     "homepage": {
34079                         "type": "string",
34080                         "description": "Homepage URL for the author.",
34081                         "format": "uri"
34082                     },
34083                     "role": {
34084                         "type": "string",
34085                         "description": "Author's role in the project."
34086                     }
34087                 }
34088             }
34089         },
34090         "require": {
34091             "type": "object",
34092             "description": "This is a hash of package name (keys) and version constraints (values) that are required to run this package.",
34093             "additionalProperties": true
34094         },
34095         "replace": {
34096             "type": "object",
34097             "description": "This is a hash of package name (keys) and version constraints (values) that can be replaced by this package.",
34098             "additionalProperties": true
34099         },
34100         "conflict": {
34101             "type": "object",
34102             "description": "This is a hash of package name (keys) and version constraints (values) that conflict with this package.",
34103             "additionalProperties": true
34104         },
34105         "provide": {
34106             "type": "object",
34107             "description": "This is a hash of package name (keys) and version constraints (values) that this package provides in addition to this package's name.",
34108             "additionalProperties": true
34109         },
34110         "require-dev": {
34111             "type": "object",
34112             "description": "This is a hash of package name (keys) and version constraints (values) that this package requires for developing it (testing tools and such).",
34113             "additionalProperties": true
34114         },
34115         "suggest": {
34116             "type": "object",
34117             "description": "This is a hash of package name (keys) and descriptions (values) that this package suggests work well with it (this will be suggested to the user during installation).",
34118             "additionalProperties": true
34119         },
34120         "config": {
34121             "type": "object",
34122             "description": "Composer options.",
34123             "properties": {
34124                 "process-timeout": {
34125                     "type": "integer",
34126                     "description": "The timeout in seconds for process executions, defaults to 300 (5mins)."
34127                 },
34128                 "use-include-path": {
34129                     "type": "boolean",
34130                     "description": "If true, the Composer autoloader will also look for classes in the PHP include path."
34131                 },
34132                 "preferred-install": {
34133                     "type": "string",
34134                     "description": "The install method Composer will prefer to use, defaults to auto and can be any of source, dist or auto."
34135                 },
34136                 "notify-on-install": {
34137                     "type": "boolean",
34138                     "description": "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, defaults to true."
34139                 },
34140                 "github-protocols": {
34141                     "type": "array",
34142                     "description": "A list of protocols to use for github.com clones, in priority order, defaults to [\"git\", \"https\", \"http\"].",
34143                     "items": {
34144                         "type": "string"
34145                     }
34146                 },
34147                 "github-oauth": {
34148                     "type": "object",
34149                     "description": "A hash of domain name => github API oauth tokens, typically {\"github.com\":\"<token>\"}.",
34150                     "additionalProperties": true
34151                 },
34152                 "http-basic": {
34153                     "type": "object",
34154                     "description": "A hash of domain name => {\"username\": \"...\", \"password\": \"...\"}.",
34155                     "additionalProperties": true
34156                 },
34157                 "store-auths": {
34158                     "type": ["string", "boolean"],
34159                     "description": "What to do after prompting for authentication, one of: true (store), false (do not store) or \"prompt\" (ask every time), defaults to prompt."
34160                 },
34161                 "vendor-dir": {
34162                     "type": "string",
34163                     "description": "The location where all packages are installed, defaults to \"vendor\"."
34164                 },
34165                 "bin-dir": {
34166                     "type": "string",
34167                     "description": "The location where all binaries are linked, defaults to \"vendor/bin\"."
34168                 },
34169                 "cache-dir": {
34170                     "type": "string",
34171                     "description": "The location where all caches are located, defaults to \"~/.composer/cache\" on *nix and \"%LOCALAPPDATA%\\Composer\" on windows."
34172                 },
34173                 "cache-files-dir": {
34174                     "type": "string",
34175                     "description": "The location where files (zip downloads) are cached, defaults to \"{$cache-dir}/files\"."
34176                 },
34177                 "cache-repo-dir": {
34178                     "type": "string",
34179                     "description": "The location where repo (git/hg repo clones) are cached, defaults to \"{$cache-dir}/repo\"."
34180                 },
34181                 "cache-vcs-dir": {
34182                     "type": "string",
34183                     "description": "The location where vcs infos (git clones, github api calls, etc. when reading vcs repos) are cached, defaults to \"{$cache-dir}/vcs\"."
34184                 },
34185                 "cache-ttl": {
34186                     "type": "integer",
34187                     "description": "The default cache time-to-live, defaults to 15552000 (6 months)."
34188                 },
34189                 "cache-files-ttl": {
34190                     "type": "integer",
34191                     "description": "The cache time-to-live for files, defaults to the value of cache-ttl."
34192                 },
34193                 "cache-files-maxsize": {
34194                     "type": ["string", "integer"],
34195                     "description": "The cache max size for the files cache, defaults to \"300MiB\"."
34196                 },
34197                 "discard-changes": {
34198                     "type": ["string", "boolean"],
34199                     "description": "The default style of handling dirty updates, defaults to false and can be any of true, false or \"stash\"."
34200                 },
34201                 "autoloader-suffix": {
34202                     "type": "string",
34203                     "description": "Optional string to be used as a suffix for the generated Composer autoloader. When null a random one will be generated."
34204                 },
34205                 "optimize-autoloader": {
34206                     "type": "boolean",
34207                     "description": "Always optimize when dumping the autoloader."
34208                 },
34209                 "prepend-autoloader": {
34210                     "type": "boolean",
34211                     "description": "If false, the composer autoloader will not be prepended to existing autoloaders, defaults to true."
34212                 },
34213                 "github-domains": {
34214                     "type": "array",
34215                     "description": "A list of domains to use in github mode. This is used for GitHub Enterprise setups, defaults to [\"github.com\"].",
34216                     "items": {
34217                         "type": "string"
34218                     }
34219                 },
34220                 "github-expose-hostname": {
34221                     "type": "boolean",
34222                     "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."
34223                 }
34224             }
34225         },
34226         "extra": {
34227             "type": ["object", "array"],
34228             "description": "Arbitrary extra data that can be used by plugins, for example, package of type composer-plugin may have a 'class' key defining an installer class name.",
34229             "additionalProperties": true
34230         },
34231         "autoload": {
34232             "type": "object",
34233             "description": "Description of how the package can be autoloaded.",
34234             "properties": {
34235                 "psr-0": {
34236                     "type": "object",
34237                     "description": "This is a hash of namespaces (keys) and the directories they can be found into (values, can be arrays of paths) by the autoloader.",
34238                     "additionalProperties": true
34239                 },
34240                 "psr-4": {
34241                     "type": "object",
34242                     "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
34243                     "additionalProperties": true
34244                 },
34245                 "classmap": {
34246                     "type": "array",
34247                     "description": "This is an array of directories that contain classes to be included in the class-map generation process."
34248                 },
34249                 "files": {
34250                     "type": "array",
34251                     "description": "This is an array of files that are always required on every request."
34252                 }
34253             }
34254         },
34255         "autoload-dev": {
34256             "type": "object",
34257             "description": "Description of additional autoload rules for development purpose (eg. a test suite).",
34258             "properties": {
34259                 "psr-0": {
34260                     "type": "object",
34261                     "description": "This is a hash of namespaces (keys) and the directories they can be found into (values, can be arrays of paths) by the autoloader.",
34262                     "additionalProperties": true
34263                 },
34264                 "psr-4": {
34265                     "type": "object",
34266                     "description": "This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
34267                     "additionalProperties": true
34268                 },
34269                 "classmap": {
34270                     "type": "array",
34271                     "description": "This is an array of directories that contain classes to be included in the class-map generation process."
34272                 },
34273                 "files": {
34274                     "type": "array",
34275                     "description": "This is an array of files that are always required on every request."
34276                 }
34277             }
34278         },
34279         "archive": {
34280             "type": ["object"],
34281             "description": "Options for creating package archives for distribution.",
34282             "properties": {
34283                 "exclude": {
34284                     "type": "array",
34285                     "description": "A list of patterns for paths to exclude or include if prefixed with an exclamation mark."
34286                 }
34287             }
34288         },
34289         "repositories": {
34290             "type": ["object", "array"],
34291             "description": "A set of additional repositories where packages can be found.",
34292             "additionalProperties": true
34293         },
34294         "minimum-stability": {
34295             "type": ["string"],
34296             "description": "The minimum stability the packages must have to be install-able. Possible values are: dev, alpha, beta, RC, stable."
34297         },
34298         "prefer-stable": {
34299             "type": ["boolean"],
34300             "description": "If set to true, stable packages will be prefered to dev packages when possible, even if the minimum-stability allows unstable packages."
34301         },
34302         "bin": {
34303             "type": ["array"],
34304             "description": "A set of files that should be treated as binaries and symlinked into bin-dir (from config).",
34305             "items": {
34306                 "type": "string"
34307             }
34308         },
34309         "include-path": {
34310             "type": ["array"],
34311             "description": "DEPRECATED: A list of directories which should get added to PHP's include path. This is only present to support legacy projects, and all new code should preferably use autoloading.",
34312             "items": {
34313                 "type": "string"
34314             }
34315         },
34316         "scripts": {
34317             "type": ["object"],
34318             "description": "Scripts listeners that will be executed before/after some events.",
34319             "properties": {
34320                 "pre-install-cmd": {
34321                     "type": ["array", "string"],
34322                     "description": "Occurs before the install command is executed, contains one or more Class::method callables or shell commands."
34323                 },
34324                 "post-install-cmd": {
34325                     "type": ["array", "string"],
34326                     "description": "Occurs after the install command is executed, contains one or more Class::method callables or shell commands."
34327                 },
34328                 "pre-update-cmd": {
34329                     "type": ["array", "string"],
34330                     "description": "Occurs before the update command is executed, contains one or more Class::method callables or shell commands."
34331                 },
34332                 "post-update-cmd": {
34333                     "type": ["array", "string"],
34334                     "description": "Occurs after the update command is executed, contains one or more Class::method callables or shell commands."
34335                 },
34336                 "pre-status-cmd": {
34337                     "type": ["array", "string"],
34338                     "description": "Occurs before the status command is executed, contains one or more Class::method callables or shell commands."
34339                 },
34340                 "post-status-cmd": {
34341                     "type": ["array", "string"],
34342                     "description": "Occurs after the status command is executed, contains one or more Class::method callables or shell commands."
34343                 },
34344                 "pre-package-install": {
34345                     "type": ["array", "string"],
34346                     "description": "Occurs before a package is installed, contains one or more Class::method callables or shell commands."
34347                 },
34348                 "post-package-install": {
34349                     "type": ["array", "string"],
34350                     "description": "Occurs after a package is installed, contains one or more Class::method callables or shell commands."
34351                 },
34352                 "pre-package-update": {
34353                     "type": ["array", "string"],
34354                     "description": "Occurs before a package is updated, contains one or more Class::method callables or shell commands."
34355                 },
34356                 "post-package-update": {
34357                     "type": ["array", "string"],
34358                     "description": "Occurs after a package is updated, contains one or more Class::method callables or shell commands."
34359                 },
34360                 "pre-package-uninstall": {
34361                     "type": ["array", "string"],
34362                     "description": "Occurs before a package has been uninstalled, contains one or more Class::method callables or shell commands."
34363                 },
34364                 "post-package-uninstall": {
34365                     "type": ["array", "string"],
34366                     "description": "Occurs after a package has been uninstalled, contains one or more Class::method callables or shell commands."
34367                 },
34368                 "pre-autoload-dump": {
34369                     "type": ["array", "string"],
34370                     "description": "Occurs before the autoloader is dumped, contains one or more Class::method callables or shell commands."
34371                 },
34372                 "post-autoload-dump": {
34373                     "type": ["array", "string"],
34374                     "description": "Occurs after the autoloader is dumped, contains one or more Class::method callables or shell commands."
34375                 },
34376                 "post-root-package-install": {
34377                     "type": ["array", "string"],
34378                     "description": "Occurs after the root-package is installed, contains one or more Class::method callables or shell commands."
34379                 },
34380                 "post-create-project-cmd": {
34381                     "type": ["array", "string"],
34382                     "description": "Occurs after the create-project command is executed, contains one or more Class::method callables or shell commands."
34383                 }
34384             }
34385         },
34386         "support": {
34387             "type": "object",
34388             "properties": {
34389                 "email": {
34390                     "type": "string",
34391                     "description": "Email address for support.",
34392                     "format": "email"
34393                 },
34394                 "issues": {
34395                     "type": "string",
34396                     "description": "URL to the Issue Tracker.",
34397                     "format": "uri"
34398                 },
34399                 "forum": {
34400                     "type": "string",
34401                     "description": "URL to the Forum.",
34402                     "format": "uri"
34403                 },
34404                 "wiki": {
34405                     "type": "string",
34406                     "description": "URL to the Wiki.",
34407                     "format": "uri"
34408                 },
34409                 "irc": {
34410                     "type": "string",
34411                     "description": "IRC channel for support, as irc://server/channel.",
34412                     "format": "uri"
34413                 },
34414                 "source": {
34415                     "type": "string",
34416                     "description": "URL to browse or download the sources.",
34417                     "format": "uri"
34418                 }
34419             }
34420         }
34421     }
34422 }
34423 MZ\90\0\ 3\0\0\0\ 4\0\0\0ÿÿ\0\0¸\0\0\0\0\0\0\0@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0è\0\0\0\ e\1fº\ e\0´  Í!¸\ 1LÍ!This program cannot be run in DOS mode.\r\r
34424 $\0\0\0\0\0\0\0\7fÆ,Í;§B\9e;§B\9e;§B\9e2ß×\9e:§B\9e2ßÁ\9e-§B\9e2ßÆ\9e9§B\9e2ßÑ\9e?§B\9e\1ca9\9e8§B\9e;§C\9e\b§B\9e2ßÈ\9e:§B\9e2ßÖ\9e:§B\9e2ßÓ\9e:§B\9eRich;§B\9e\0\0\0\0\0\0\0\0PE\0\0L\ 1\ 5\0¬MoO\0\0\0\0\0\0\0\0à\0\ 2\ 1\v\ 1      \0\0
34425 \0\0\0\16\0\0\0\0\0\08\13\0\0\0\10\0\0\0 \0\0\0\0@\0\0\10\0\0\0\ 2\0\0\ 5\0\0\0\0\0\0\0\ 5\0\0\0\0\0\0\0\0`\0\0\0\ 4\0\0?\9c\0\0\ 3\0@\81\0\0\10\0\0\10\0\0\0\0\10\0\0\10\0\0\0\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\90"\0\0P\0\0\0\0@\0\0 \ 6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0P\0\0p\ 1\0\0\0!\0\0\1c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\08!\0\0@\0\0\0\0\0\0\0\0\0\0\0\0 \0\0Ø\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0.text\0\0\0\v     \0\0\0\10\0\0\0
34426 \0\0\0\ 4\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0`.rdata\0\0Π\0\0\0 \0\0\0
34427 \0\0\0\ e\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0@.data\0\0\0\90\ 3\0\0\00\0\0\0\ 2\0\0\0\18\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0À.rsrc\0\0\0 \ 6\0\0\0@\0\0\0\b\0\0\0\1a\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0@.reloc\0\0Ì\ 1\0\0\0P\0\0\0\ 2\0\0\0"\0\0\0\0\0\0\0\0\0\0\0\0\0\0@\0\0B\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0j$¸æ\18@\0èx\b\0\0jöÿ\15\b @\0\83\0\8bð\8dEÐPVÿ\15\0 @\0\8b\83àûPVÿ\15\ 4 @\0\8dMÔÿ\15X @\0\83\0\8dEÔPÿ5H @\0ÿ\15L @\0YYÿ5\ @\0\8dEÔPÿ5` @\0ÿ\15D @\0YY\8bÈÿ\15P @\0\83Müÿ\8dMÔÿ\15T @\03ÀèH\b\0\0Ã;\r\00@\0u\ 2óÃé¬\ 2\0\0h\80\15@\0è£\ 4\0\0¡l3@\0Ç\ 4$40@\0ÿ5h3@\0£40@\0h$0@\0h(0@\0h 0@\0ÿ\15  @\0\83Ä\14£00@\0\85À}\bj\bè¹\ 3\0\0YÃj\10h\b"@\0è\1f\ 6\0\0\89]üd¡\18\0\0\0\8bp\ 4\89]ä¿\803@\0SVWÿ\150 @\0;Ãt\19;Æu\b3öF\89uäë\10\ 3\0\0ÿ\154 @\0ëÚ3öF¡|3@\0;Æu
34428 j\1fè\\ 3\0\0Yë;¡|3@\0\85Àu,\895|3@\0hð @\0hä @\0è§\ 5\0\0YY\85Àt\17ÇEüþÿÿÿ¸ÿ\0\0\0éÝ\0\0\0\895<0@\0¡|3@\0;Æu\ehà @\0hØ @\0èl\ 5\0\0YYÇ\ 5|3@\0\ 2\0\0\09]äu\bSWÿ\158 @\09\1d\8c3@\0t\19h\8c3@\0è\83\ 4\0\0Y\85Àt
34429 Sj\ 2Sÿ\15\8c3@\0¡$0@\0\8b\r¼ @\0\89\ 1ÿ5$0@\0ÿ5(0@\0ÿ5 0@\0è\10þÿÿ\83Ä\f£80@\09\1d,0@\0u7Pÿ\15À @\0\8b\8b\b\8b     \89MàPQè\8e\ 3\0\0YYÃ\8b\8bEà£80@\03Û9\1d,0@\0u\aPÿ\15h @\09\1d<0@\0u\ 6ÿ\15\9c @\0ÇEüþÿÿÿ¡80@\0èû\ 4\0\0øMZ\0\0f9\ 5\0\0@\0t\ 43ÀëM¡<\0@\0\8d\80\0\0@\0\818PE\0\0\ f·H\18\81ù\v\ 1\0\0t\e\81ù\v\ 2\0\0\83¸\84\0\0\0\ evÌ3É9\88ø\0\0\0ë\ e\83xt\ ev¼3É9\88è\0\0\0\ f\95Á\8bÁj\ 1£,0@\0ÿ\15p @\0jÿÿ\15l @\0YY£\843@\0£\883@\0ÿ\15Ì @\0\8b\rt3@\0\89\bÿ\15\88 @\0\8b\rp3@\0\89\b¡¨ @\0\8b\0£x3@\0èV\ 2\0\0è¬\ 4\0\0\83=\140@\0\0u\f\17@\0ÿ\15¬ @\0Yèg\ 4\0\0\83=\100@\0ÿu   jÿÿ\15° @\0Y3ÀÃè{\ 4\0\0é\9fýÿÿ\8bÿU\8bì\81ì(\ 3\0\0£H1@\0\89\rD1@\0\89\15@1@\0\89\1d<1@\0\89581@\0\89=41@\0f\8c\15`1@\0f\8c\rT1@\0f\8c\1d01@\0f\8c\ 5,1@\0f\8c%(1@\0f\8c-$1@\0\9c\8f\ 5X1@\0\8bE\0£L1@\0\8bE\ 4£P1@\0\8dE\b£\1@\0\8b\85àüÿÿÇ\ 5\980@\0\ 1\0\ 1\0¡P1@\0£L0@\0Ç\ 5@0@\0   \ 4\0ÀÇ\ 5D0@\0\ 1\0\0\0¡\00@\0\89\85Øüÿÿ¡\ 40@\0\89\85Üüÿÿÿ\15\1c @\0£\900@\0j\ 1è?\ 4\0\0Yj\0ÿ\15  @\0h\1c!@\0ÿ\15$ @\0\83=\900@\0\0u\bj\ 1è\e\ 4\0\0Yh     \ 4\0Àÿ\15( @\0Pÿ\15, @\0ÉÃ\8bÿU\8bì\8bE\b\8b\0\818csmàu*\83x\10\ 3u$\8b@\14\ 5\93\19t\15=!\ 5\93\19t\ e="\ 5\93\19t\a=\0@\99\ 1u\ 5èÐ\ 3\0\03À]Â\ 4\0hH\14@\0ÿ\15  @\03ÀÃÿ%¤ @\0j\14h("@\0èb\ 2\0\0ÿ5\883@\0\8b5\8c @\0ÿÖY\89\83øÿu\fÿu\bÿ\15Ä @\0Yëgj\bè\92\ 3\0\0Y\83\0ÿ5\883@\0ÿÖ\89Eäÿ5\843@\0ÿÖYY\89\8dEàP\8dEäPÿu\b\8b5l @\0ÿÖYPèU\ 3\0\0\89EÜÿuäÿÖ£\883@\0ÿuàÿÖ\83Ä\14£\843@\0ÇEüþÿÿÿè \0\0\0\8bEÜè\18\ 2\0\0Ãj\bè\19\ 3\0\0\8bÿU\8bìÿu\bèNÿÿÿ÷Ø\eÀ÷ØYH]Ã\8bÿV¸ü!@\0¾ü!@\0W\8bø;Æs\ f\8b\a\85Àt\ 2ÿÐ\83Ç\ 4;þrñ_^Ã\8bÿV¸\ 4"@\0¾\ 4"@\0W\8bø;Æs\ f\8b\a\85Àt\ 2ÿÐ\83Ç\ 4;þrñ_^Ãÿ%È @\0ÌÌÌÌ\8bÿU\8bì\8bM\b¸MZ\0\0f9\ 1t\ 43À]Ã\8bA<\ 3Á\818PE\0\0uï3Ò¹\v\ 1\0\0f9H\18\ f\94Â\8bÂ]ÃÌÌÌÌÌÌÌÌÌÌÌ\8bÿU\8bì\8bE\b\8bH<\ 3È\ f·A\14SV\ f·q\ 63ÒW\8dD\b\18\85öv\e\8b}\f\8bH\f;ùr   \8bX\b\ 3Ù;ûr
34430 B\83À(;Örè3À_^[]ÃÌÌÌÌÌÌÌÌÌÌÌÌ\8bÿU\8bìjþhH"@\0he\17@\0\0\0\0\0P\83ì\bSVW¡\00@\01Eø3ÅP\8dEðd£\0\0\0\0\89eèÇEü\0\0\0\0h\0\0@\0è*ÿÿÿ\83Ä\ 4\85ÀtU\8bE\b-\0\0@\0Ph\0\0@\0èPÿÿÿ\83Ä\b\85Àt;\8b@$Áè\1f÷Ð\83à\ 1ÇEüþÿÿÿ\8bMðd\89\r\0\0\0\0Y_^[\8bå]Ã\8b\8b\b\8b\ 13Ò=\ 5\0\0À\ f\94Â\8bÂÃ\8beèÇEüþÿÿÿ3À\8bMðd\89\r\0\0\0\0Y_^[\8bå]ÃÌÿ%¸ @\0ÿ%´ @\0ÌÌhe\17@\0dÿ5\0\0\0\0\8bD$\10\89l$\10\8dl$\10+àSVW¡\00@\01Eü3ÅP\89eèÿuø\8bEüÇEüþÿÿÿ\89\8dEðd£\0\0\0\0Ã\8bMðd\89\r\0\0\0\0Y__^[\8bå]QÃ\8bÿU\8bìÿu\14ÿu\10ÿu\fÿu\bh\87\10@\0h\00@\0èç\0\0\0\83Ä\18\8bÿVh\0\0\ 3\0h\0\0\ 1\03öVèÙ\0\0\0\83Ä\f\85Àt\rVVVVVèÂ\0\0\0\83Ä\14^Ã3ÀÃ\8bÿU\8bì\83ì\10¡\00@\0\83\0\83\0SW¿Næ@»»\0\0ÿÿ;Çt\r\85Ãt     ÷У\ 40@\0ë`V\8dEøPÿ\15< @\0\8buü3uøÿ\15\f @\03ðÿ\15\10 @\03ðÿ\15\14 @\0\8dEðPÿ\15\18 @\0\8bEô3Eð3ð;÷u\a¾Oæ@»ë\v\85óu\a\8bÆÁà\10\vð\895\00@\0÷Ö\895\ 40@\0^_[ÉÃÿ%t @\0ÿ%x @\0ÿ%| @\0ÿ%\80 @\0ÿ%\84 @\0ÿ%\90 @\0ÿ%\94 @\0ÿ%\98 @\0ÿ%Р@\0Pdÿ5\0\0\0\0\8dD$\f+d$\fSVW\89(\8bè¡\00@\03ÅP\89EðÿuüÇEüÿÿÿÿ\8dEôd£\0\0\0\0Ã\8bMôd\89\r\0\0\0\0Y__^[\8bå]QÃ\8bMð3Íè¯÷ÿÿéÝÿÿÿ\8dMÔÿ%T @\0\8bT$\b\8dB\f\8bJÌ3Èè\90÷ÿÿ\8bJü3Èè\86÷ÿÿ¸l"@\0ésÿÿÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0¸#\0\0Ê#\0\0Ü#\0\0\88)\0\0r)\0\0b)\0\0H)\0\04)\0\0\16)\0\0ú(\0\0æ(\0\0Ò(\0\0´(\0\0¬(\0\0\96(\0\0\9e)\0\0\0\0\0\0ú#\0\0à$\0\0\1a%\0\0Ê%\0\0\1a&\0\0d&\0\0®&\0\0¤$\0\0\0\0\0\0('\0\0Ä'\0\0Ö'\0\0è'\0\0þ'\0\0\1e(\0\0((\0\06(\0\0¦'\0\0H(\0\0Z(\0\0t(\0\0\86(\0\0\1e'\0\0\ e'\0\0\0'\0\0\96'\0\0\82'\0\0l'\0\0^'\0\0R'\0\0F'\0\0>'\0\0>(\0\00'\0\0¶'\0\0¸)\0\0\0\0\0\0\0\0\0\0\96\10@\0\0\0\0\0\0\0\0\0W\12@\0\8a\14@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0¬MoO\0\0\0\0\ 2\0\0\0l\0\0\0\80!\0\0\80\ f\0\0@0@\0\980@\0bad allocation\0\0\0\0\0\0H\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00@\0ð!@\0\ 2\0\0\0RSDSÑ\8c³\10´\8f\ 1J¨!öÌëLZ\0\ 1\0\0\0c:\users\seld\documents\visual studio 2010\Projects\hiddeninp\Release\hiddeninp.pdb\0\0\0\0\0e\17\0\0æ\18\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0þÿÿÿ\0\0\0\0Ðÿÿÿ\0\0\0\0þÿÿÿ\a\12@\0\e\12@\0\0\0\0\0þÿÿÿ\0\0\0\0Ìÿÿÿ\0\0\0\0þÿÿÿ\0\0\0\0:\15@\0\0\0\0\0þÿÿÿ\0\0\0\0Øÿÿÿ\0\0\0\0þÿÿÿË\16@\0ß\16@\0ÿÿÿÿÝ\18@\0"\ 5\93\19\ 1\0\0\0d"@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 1\0\0\0à"\0\0\0\0\0\0\0\0\0\0ì#\0\0\0 \0\0$#\0\0\0\0\0\0\0\0\0\0ô&\0\0\0\0H#\0\0\0\0\0\0\0\0\0\0\12(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0¸#\0\0Ê#\0\0Ü#\0\0\88)\0\0r)\0\0b)\0\0H)\0\04)\0\0\16)\0\0ú(\0\0æ(\0\0Ò(\0\0´(\0\0¬(\0\0\96(\0\0\9e)\0\0\0\0\0\0ú#\0\0à$\0\0\1a%\0\0Ê%\0\0\1a&\0\0d&\0\0®&\0\0¤$\0\0\0\0\0\0('\0\0Ä'\0\0Ö'\0\0è'\0\0þ'\0\0\1e(\0\0((\0\06(\0\0¦'\0\0H(\0\0Z(\0\0t(\0\0\86(\0\0\1e'\0\0\ e'\0\0\0'\0\0\96'\0\0\82'\0\0l'\0\0^'\0\0R'\0\0F'\0\0>'\0\0>(\0\00'\0\0¶'\0\0¸)\0\0\0\0\0\0\95\ 1GetConsoleMode\0\0·\ 3SetConsoleMode\0\0;\ 2GetStdHandle\0\0KERNEL32.dll\0\0\16\0??$?6DU?$char_traits@D@std@@V?$allocator@D@1@@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z\0\91\ 6?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A\0\0J\ 6?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A\0Â\0??$getline@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@YAAAV?$basic_istream@DU?$char_traits@D@std@@@0@AAV10@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@0@@Z\0\1d\ 3??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z\0\0_\ 2??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ\0\0{\ 1??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ\0\0³\a?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z\0\0MSVCP90.dll\0\15\ 1_amsg_exit\0\0\9f\0__getmainargs\0,\ 1_cexit\0\0|\ 1_exit\0f\0_XcptFilter\0Ì\ 4exit\0\0 \0__initenv\0\ 4\ 2_initterm\0\ 5\ 2_initterm_e\0<\ 1_configthreadlocale\0ã\0__setusermatherr\0\0\v\ 1_adjust_fdiv\0\0Ë\0__p__commode\0\0Ï\0__p__fmode\0\0j\ 1_encode_pointer\0à\0__set_app_type\0\0K\ 1_crt_debugger_hook\0\0C\0?terminate@@YAXXZ\0MSVCR90.dll\0æ\ 3_unlock\0\96\0__dllonexit\0v\ 2_lock\0\1c\ 3_onexit\0`\ 1_decode_pointer\0s\ 1_except_handler4_common\0\v\ 2_invoke_watson\0\0?\ 1_controlfp_s\0\0½\ 2InterlockedExchange\0!\ 4Sleep\0º\ 2InterlockedCompareExchange\0\0-\ 4TerminateProcess\0\0©\ 1GetCurrentProcess\0>\ 4UnhandledExceptionFilter\0\0\15\ 4SetUnhandledExceptionFilter\0Ñ\ 2IsDebuggerPresent\0T\ 3QueryPerformanceCounter\0f\ 2GetTickCount\0\0­\ 1GetCurrentThreadId\0\0ª\ 1GetCurrentProcessId\0O\ 2GetSystemTimeAsFileTime\0s\0__CxxFrameHandler3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Næ@»±\19¿Dÿÿÿÿÿÿÿÿþÿÿÿ\ 1\0\0\0$!@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 2\0\10\0\0\0 \0\0\80\18\0\0\08\0\0\80\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0\ 1\0\0\0P\0\0\80\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0\ 1\0\0\0h\0\0\80\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0 \ 4\0\0\80\0\0\0\0\0\0\0\0\0\0\0\ 4\0\0\0\0\0\ 1\0 \ 4\0\0\90\0\0\0 @\0\0(\ 3\0\0ä\ 4\0\0\0\0\0\0ÈC\0\0V\ 2\0\0ä\ 4\0\0\0\0\0\0(\ 34\0\0\0V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0\0\0½\ 4ïþ\0\0\ 1\0\0\0\ 1\0\0\0\0\0\0\0\ 1\0\0\0\0\0\17\0\0\0\0\0\0\0\ 4\0\0\0\ 1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\86\ 2\0\0\ 1\0S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0b\ 2\0\0\ 1\00\04\00\09\00\04\0b\00\0\0\0Ê\0Q\0\ 1\0F\0i\0l\0e\0D\0e\0s\0c\0r\0i\0p\0t\0i\0o\0n\0\0\0\0\0R\0e\0a\0d\0s\0 \0f\0r\0o\0m\0 \0s\0t\0d\0i\0n\0 \0w\0i\0t\0h\0o\0u\0t\0 \0l\0e\0a\0k\0i\0n\0g\0 \0i\0n\0f\0o\0 \0t\0o\0 \0t\0h\0e\0 \0t\0e\0r\0m\0i\0n\0a\0l\0 \0a\0n\0d\0 \0o\0u\0t\0p\0u\0t\0s\0 \0b\0a\0c\0k\0 \0t\0o\0 \0s\0t\0d\0o\0u\0t\0\0\0\0\06\0\v\0\ 1\0F\0i\0l\0e\0V\0e\0r\0s\0i\0o\0n\0\0\0\0\01\0,\0 \00\0,\0 \00\0,\0 \00\0\0\0\0\08\0\f\0\ 1\0I\0n\0t\0e\0r\0n\0a\0l\0N\0a\0m\0e\0\0\0h\0i\0d\0d\0e\0n\0i\0n\0p\0u\0t\0\0\0P\0\16\0\ 1\0L\0e\0g\0a\0l\0C\0o\0p\0y\0r\0i\0g\0h\0t\0\0\0J\0o\0r\0d\0i\0 \0B\0o\0g\0g\0i\0a\0n\0o\0 \0-\0 \02\00\01\02\0\0\0H\0\10\0\ 1\0O\0r\0i\0g\0i\0n\0a\0l\0F\0i\0l\0e\0n\0a\0m\0e\0\0\0h\0i\0d\0d\0e\0n\0i\0n\0p\0u\0t\0.\0e\0x\0e\0\0\0:\0\r\0\ 1\0P\0r\0o\0d\0u\0c\0t\0N\0a\0m\0e\0\0\0\0\0H\0i\0d\0d\0e\0n\0 \0I\0n\0p\0u\0t\0\0\0\0\0:\0\v\0\ 1\0P\0r\0o\0d\0u\0c\0t\0V\0e\0r\0s\0i\0o\0n\0\0\01\0,\0 \00\0,\0 \00\0,\0 \00\0\0\0\0\0D\0\0\0\ 1\0V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0\0$\0\ 4\0\0\0T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0\0     \ 4°\ 4<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
34431   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\r
34432     <security>\r
34433       <requestedPrivileges>\r
34434         <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>\r
34435       </requestedPrivileges>\r
34436     </security>\r
34437   </trustInfo>\r
34438   <dependency>\r
34439     <dependentAssembly>\r
34440       <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>\r
34441     </dependentAssembly>\r
34442   </dependency>\r
34443 </assembly>PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDING\0\10\0\0@\ 1\0\0\ 30\100!0/080F0L0T0^0d0n0{0\890\970¡0¨0®0³0¸0½0Â0È0Ð0ä0ÿ0\b1#1-1@1J1O1T1v1{1\841\891\961§1­1´1È1Í1Ó1Û1á1ç1ô1ú1\ 32"2*23292A2M2_2j2p2¹2¿2Ç2Î2Ó2Ù2ß2ç2í2ô2û2\v3\133\193%303N3T3Z3`3f3l3s3z3\813\883\8f3\963\9d3¥3­3µ3Á3Ê3Ï3Õ3ß3è3ó3ÿ3\ 44\144\194\1f4%4;4B4\8b4\914\9a4¡4¬4²4Æ4Û4æ4þ4\145!5^5c5\845\895¨5H6M6_6}6\916\976\07\ 67\r7*7w7|7Á7ä7ñ7ý7\ 58\r8\198=8E8P8V8\8b8h8n8t8z8\808\9c8â8\ 29\0\0\0 \0\0$\0\0\0Ü0è0ì0\1c1 1t1x1\1c2 2@2\2`2h2t2\00\0\0\f\0\0\0\180\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php
34444
34445
34446
34447
34448
34449
34450
34451
34452
34453
34454 namespace Symfony\Component\Process;
34455
34456 use Symfony\Component\Process\Exception\RuntimeException;
34457
34458
34459
34460
34461
34462
34463
34464
34465
34466
34467
34468
34469 class PhpProcess extends Process
34470 {
34471 private $executableFinder;
34472
34473
34474
34475
34476
34477
34478
34479
34480
34481
34482
34483
34484 public function __construct($script, $cwd = null, array $env = array(), $timeout = 60, array $options = array())
34485 {
34486 parent::__construct(null, $cwd, $env, $script, $timeout, $options);
34487
34488 $this->executableFinder = new PhpExecutableFinder();
34489 }
34490
34491
34492
34493
34494
34495
34496 public function setPhpBinary($php)
34497 {
34498 $this->setCommandLine($php);
34499 }
34500
34501
34502
34503
34504 public function start($callback = null)
34505 {
34506 if (null === $this->getCommandLine()) {
34507 if (false === $php = $this->executableFinder->find()) {
34508 throw new RuntimeException('Unable to find the PHP executable.');
34509 }
34510 $this->setCommandLine($php);
34511 }
34512
34513 parent::start($callback);
34514 }
34515 }
34516 <?php
34517
34518
34519
34520
34521
34522
34523
34524
34525
34526
34527 namespace Symfony\Component\Process;
34528
34529
34530
34531
34532
34533
34534
34535 class ExecutableFinder
34536 {
34537 private $suffixes = array('.exe', '.bat', '.cmd', '.com');
34538
34539
34540
34541
34542
34543
34544 public function setSuffixes(array $suffixes)
34545 {
34546 $this->suffixes = $suffixes;
34547 }
34548
34549
34550
34551
34552
34553
34554 public function addSuffix($suffix)
34555 {
34556 $this->suffixes[] = $suffix;
34557 }
34558
34559
34560
34561
34562
34563
34564
34565
34566
34567
34568 public function find($name, $default = null, array $extraDirs = array())
34569 {
34570 if (ini_get('open_basedir')) {
34571 $searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir'));
34572 $dirs = array();
34573 foreach ($searchPath as $path) {
34574 if (is_dir($path)) {
34575 $dirs[] = $path;
34576 } else {
34577 if (basename($path) == $name && is_executable($path)) {
34578 return $path;
34579 }
34580 }
34581 }
34582 } else {
34583 $dirs = array_merge(
34584 explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
34585 $extraDirs
34586 );
34587 }
34588
34589 $suffixes = array('');
34590 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
34591 $pathExt = getenv('PATHEXT');
34592 $suffixes = $pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes;
34593 }
34594 foreach ($suffixes as $suffix) {
34595 foreach ($dirs as $dir) {
34596 if (is_file($file = $dir.DIRECTORY_SEPARATOR.$name.$suffix) && (defined('PHP_WINDOWS_VERSION_BUILD') || is_executable($file))) {
34597 return $file;
34598 }
34599 }
34600 }
34601
34602 return $default;
34603 }
34604 }
34605 <?php
34606
34607
34608
34609
34610
34611
34612
34613
34614
34615
34616 namespace Symfony\Component\Process;
34617
34618 use Symfony\Component\Process\Exception\InvalidArgumentException;
34619 use Symfony\Component\Process\Exception\LogicException;
34620 use Symfony\Component\Process\Exception\ProcessFailedException;
34621 use Symfony\Component\Process\Exception\ProcessTimedOutException;
34622 use Symfony\Component\Process\Exception\RuntimeException;
34623 use Symfony\Component\Process\Pipes\PipesInterface;
34624 use Symfony\Component\Process\Pipes\UnixPipes;
34625 use Symfony\Component\Process\Pipes\WindowsPipes;
34626
34627
34628
34629
34630
34631
34632
34633
34634
34635
34636 class Process
34637 {
34638 const ERR = 'err';
34639 const OUT = 'out';
34640
34641 const STATUS_READY = 'ready';
34642 const STATUS_STARTED = 'started';
34643 const STATUS_TERMINATED = 'terminated';
34644
34645 const STDIN = 0;
34646 const STDOUT = 1;
34647 const STDERR = 2;
34648
34649
34650  const TIMEOUT_PRECISION = 0.2;
34651
34652 private $callback;
34653 private $commandline;
34654 private $cwd;
34655 private $env;
34656 private $input;
34657 private $starttime;
34658 private $lastOutputTime;
34659 private $timeout;
34660 private $idleTimeout;
34661 private $options;
34662 private $exitcode;
34663 private $fallbackExitcode;
34664 private $processInformation;
34665 private $outputDisabled = false;
34666 private $stdout;
34667 private $stderr;
34668 private $enhanceWindowsCompatibility = true;
34669 private $enhanceSigchildCompatibility;
34670 private $process;
34671 private $status = self::STATUS_READY;
34672 private $incrementalOutputOffset = 0;
34673 private $incrementalErrorOutputOffset = 0;
34674 private $tty;
34675 private $pty;
34676
34677 private $useFileHandles = false;
34678
34679 private $processPipes;
34680
34681 private $latestSignal;
34682
34683 private static $sigchild;
34684
34685
34686
34687
34688
34689
34690
34691
34692 public static $exitCodes = array(
34693 0 => 'OK',
34694 1 => 'General error',
34695 2 => 'Misuse of shell builtins',
34696
34697 126 => 'Invoked command cannot execute',
34698 127 => 'Command not found',
34699 128 => 'Invalid exit argument',
34700
34701
34702  129 => 'Hangup',
34703 130 => 'Interrupt',
34704 131 => 'Quit and dump core',
34705 132 => 'Illegal instruction',
34706 133 => 'Trace/breakpoint trap',
34707 134 => 'Process aborted',
34708 135 => 'Bus error: "access to undefined portion of memory object"',
34709 136 => 'Floating point exception: "erroneous arithmetic operation"',
34710 137 => 'Kill (terminate immediately)',
34711 138 => 'User-defined 1',
34712 139 => 'Segmentation violation',
34713 140 => 'User-defined 2',
34714 141 => 'Write to pipe with no one reading',
34715 142 => 'Signal raised by alarm',
34716 143 => 'Termination (request to terminate)',
34717
34718  145 => 'Child process terminated, stopped (or continued*)',
34719 146 => 'Continue if stopped',
34720 147 => 'Stop executing temporarily',
34721 148 => 'Terminal stop signal',
34722 149 => 'Background process attempting to read from tty ("in")',
34723 150 => 'Background process attempting to write to tty ("out")',
34724 151 => 'Urgent data available on socket',
34725 152 => 'CPU time limit exceeded',
34726 153 => 'File size limit exceeded',
34727 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"',
34728 155 => 'Profiling timer expired',
34729
34730  157 => 'Pollable event',
34731
34732  159 => 'Bad syscall',
34733 );
34734
34735
34736
34737
34738
34739
34740
34741
34742
34743
34744
34745
34746
34747
34748
34749 public function __construct($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array())
34750 {
34751 if (!function_exists('proc_open')) {
34752 throw new RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
34753 }
34754
34755 $this->commandline = $commandline;
34756 $this->cwd = $cwd;
34757
34758
34759  
34760  
34761  
34762  if (null === $this->cwd && (defined('ZEND_THREAD_SAFE') || defined('PHP_WINDOWS_VERSION_BUILD'))) {
34763 $this->cwd = getcwd();
34764 }
34765 if (null !== $env) {
34766 $this->setEnv($env);
34767 }
34768
34769 $this->input = $input;
34770 $this->setTimeout($timeout);
34771 $this->useFileHandles = defined('PHP_WINDOWS_VERSION_BUILD');
34772 $this->pty = false;
34773 $this->enhanceWindowsCompatibility = true;
34774 $this->enhanceSigchildCompatibility = !defined('PHP_WINDOWS_VERSION_BUILD') && $this->isSigchildEnabled();
34775 $this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
34776 }
34777
34778 public function __destruct()
34779 {
34780
34781  $this->stop();
34782 }
34783
34784 public function __clone()
34785 {
34786 $this->resetProcessData();
34787 }
34788
34789
34790
34791
34792
34793
34794
34795
34796
34797
34798
34799
34800
34801
34802
34803
34804
34805
34806
34807
34808
34809
34810 public function run($callback = null)
34811 {
34812 $this->start($callback);
34813
34814 return $this->wait();
34815 }
34816
34817
34818
34819
34820
34821
34822
34823
34824
34825
34826
34827
34828
34829
34830 public function mustRun($callback = null)
34831 {
34832 if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {
34833 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
34834 }
34835
34836 if (0 !== $this->run($callback)) {
34837 throw new ProcessFailedException($this);
34838 }
34839
34840 return $this;
34841 }
34842
34843
34844
34845
34846
34847
34848
34849
34850
34851
34852
34853
34854
34855
34856
34857
34858
34859
34860
34861
34862
34863
34864
34865
34866
34867 public function start($callback = null)
34868 {
34869 if ($this->isRunning()) {
34870 throw new RuntimeException('Process is already running');
34871 }
34872 if ($this->outputDisabled && null !== $callback) {
34873 throw new LogicException('Output has been disabled, enable it to allow the use of a callback.');
34874 }
34875
34876 $this->resetProcessData();
34877 $this->starttime = $this->lastOutputTime = microtime(true);
34878 $this->callback = $this->buildCallback($callback);
34879 $descriptors = $this->getDescriptors();
34880
34881 $commandline = $this->commandline;
34882
34883 if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->enhanceWindowsCompatibility) {
34884 $commandline = 'cmd /V:ON /E:ON /C "('.$commandline.')';
34885 foreach ($this->processPipes->getFiles() as $offset => $filename) {
34886 $commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
34887 }
34888 $commandline .= '"';
34889
34890 if (!isset($this->options['bypass_shell'])) {
34891 $this->options['bypass_shell'] = true;
34892 }
34893 }
34894
34895 $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
34896
34897 if (!is_resource($this->process)) {
34898 throw new RuntimeException('Unable to launch a new process.');
34899 }
34900 $this->status = self::STATUS_STARTED;
34901
34902 if ($this->tty) {
34903 return;
34904 }
34905
34906 $this->updateStatus(false);
34907 $this->checkTimeout();
34908 }
34909
34910
34911
34912
34913
34914
34915
34916
34917
34918
34919
34920
34921
34922
34923
34924
34925 public function restart($callback = null)
34926 {
34927 if ($this->isRunning()) {
34928 throw new RuntimeException('Process is already running');
34929 }
34930
34931 $process = clone $this;
34932 $process->start($callback);
34933
34934 return $process;
34935 }
34936
34937
34938
34939
34940
34941
34942
34943
34944
34945
34946
34947
34948
34949
34950
34951
34952 public function wait($callback = null)
34953 {
34954 $this->requireProcessIsStarted(__FUNCTION__);
34955
34956 $this->updateStatus(false);
34957 if (null !== $callback) {
34958 $this->callback = $this->buildCallback($callback);
34959 }
34960
34961 do {
34962 $this->checkTimeout();
34963 $running = defined('PHP_WINDOWS_VERSION_BUILD') ? $this->isRunning() : $this->processPipes->areOpen();
34964 $close = !defined('PHP_WINDOWS_VERSION_BUILD') || !$running;
34965 $this->readPipes(true, $close);
34966 } while ($running);
34967
34968 while ($this->isRunning()) {
34969 usleep(1000);
34970 }
34971
34972 if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
34973 throw new RuntimeException(sprintf('The process has been signaled with signal "%s".', $this->processInformation['termsig']));
34974 }
34975
34976 return $this->exitcode;
34977 }
34978
34979
34980
34981
34982
34983
34984
34985
34986 public function getPid()
34987 {
34988 if ($this->isSigchildEnabled()) {
34989 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process identifier can not be retrieved.');
34990 }
34991
34992 $this->updateStatus(false);
34993
34994 return $this->isRunning() ? $this->processInformation['pid'] : null;
34995 }
34996
34997
34998
34999
35000
35001
35002
35003
35004
35005
35006
35007
35008 public function signal($signal)
35009 {
35010 $this->doSignal($signal, true);
35011
35012 return $this;
35013 }
35014
35015
35016
35017
35018
35019
35020
35021
35022
35023 public function disableOutput()
35024 {
35025 if ($this->isRunning()) {
35026 throw new RuntimeException('Disabling output while the process is running is not possible.');
35027 }
35028 if (null !== $this->idleTimeout) {
35029 throw new LogicException('Output can not be disabled while an idle timeout is set.');
35030 }
35031
35032 $this->outputDisabled = true;
35033
35034 return $this;
35035 }
35036
35037
35038
35039
35040
35041
35042
35043
35044 public function enableOutput()
35045 {
35046 if ($this->isRunning()) {
35047 throw new RuntimeException('Enabling output while the process is running is not possible.');
35048 }
35049
35050 $this->outputDisabled = false;
35051
35052 return $this;
35053 }
35054
35055
35056
35057
35058
35059
35060 public function isOutputDisabled()
35061 {
35062 return $this->outputDisabled;
35063 }
35064
35065
35066
35067
35068
35069
35070
35071
35072
35073
35074
35075 public function getOutput()
35076 {
35077 if ($this->outputDisabled) {
35078 throw new LogicException('Output has been disabled.');
35079 }
35080
35081 $this->requireProcessIsStarted(__FUNCTION__);
35082
35083 $this->readPipes(false, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
35084
35085 return $this->stdout;
35086 }
35087
35088
35089
35090
35091
35092
35093
35094
35095
35096
35097
35098
35099 public function getIncrementalOutput()
35100 {
35101 $this->requireProcessIsStarted(__FUNCTION__);
35102
35103 $data = $this->getOutput();
35104
35105 $latest = substr($data, $this->incrementalOutputOffset);
35106 $this->incrementalOutputOffset = strlen($data);
35107
35108 return $latest;
35109 }
35110
35111
35112
35113
35114
35115
35116 public function clearOutput()
35117 {
35118 $this->stdout = '';
35119 $this->incrementalOutputOffset = 0;
35120
35121 return $this;
35122 }
35123
35124
35125
35126
35127
35128
35129
35130
35131
35132
35133
35134 public function getErrorOutput()
35135 {
35136 if ($this->outputDisabled) {
35137 throw new LogicException('Output has been disabled.');
35138 }
35139
35140 $this->requireProcessIsStarted(__FUNCTION__);
35141
35142 $this->readPipes(false, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
35143
35144 return $this->stderr;
35145 }
35146
35147
35148
35149
35150
35151
35152
35153
35154
35155
35156
35157
35158
35159 public function getIncrementalErrorOutput()
35160 {
35161 $this->requireProcessIsStarted(__FUNCTION__);
35162
35163 $data = $this->getErrorOutput();
35164
35165 $latest = substr($data, $this->incrementalErrorOutputOffset);
35166 $this->incrementalErrorOutputOffset = strlen($data);
35167
35168 return $latest;
35169 }
35170
35171
35172
35173
35174
35175
35176 public function clearErrorOutput()
35177 {
35178 $this->stderr = '';
35179 $this->incrementalErrorOutputOffset = 0;
35180
35181 return $this;
35182 }
35183
35184
35185
35186
35187
35188
35189
35190
35191
35192
35193 public function getExitCode()
35194 {
35195 if ($this->isSigchildEnabled() && !$this->enhanceSigchildCompatibility) {
35196 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.');
35197 }
35198
35199 $this->updateStatus(false);
35200
35201 return $this->exitcode;
35202 }
35203
35204
35205
35206
35207
35208
35209
35210
35211
35212
35213
35214
35215
35216
35217 public function getExitCodeText()
35218 {
35219 if (null === $exitcode = $this->getExitCode()) {
35220 return;
35221 }
35222
35223 return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error';
35224 }
35225
35226
35227
35228
35229
35230
35231
35232
35233 public function isSuccessful()
35234 {
35235 return 0 === $this->getExitCode();
35236 }
35237
35238
35239
35240
35241
35242
35243
35244
35245
35246
35247
35248
35249
35250 public function hasBeenSignaled()
35251 {
35252 $this->requireProcessIsTerminated(__FUNCTION__);
35253
35254 if ($this->isSigchildEnabled()) {
35255 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
35256 }
35257
35258 $this->updateStatus(false);
35259
35260 return $this->processInformation['signaled'];
35261 }
35262
35263
35264
35265
35266
35267
35268
35269
35270
35271
35272
35273
35274
35275 public function getTermSignal()
35276 {
35277 $this->requireProcessIsTerminated(__FUNCTION__);
35278
35279 if ($this->isSigchildEnabled()) {
35280 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.');
35281 }
35282
35283 $this->updateStatus(false);
35284
35285 return $this->processInformation['termsig'];
35286 }
35287
35288
35289
35290
35291
35292
35293
35294
35295
35296
35297
35298
35299 public function hasBeenStopped()
35300 {
35301 $this->requireProcessIsTerminated(__FUNCTION__);
35302
35303 $this->updateStatus(false);
35304
35305 return $this->processInformation['stopped'];
35306 }
35307
35308
35309
35310
35311
35312
35313
35314
35315
35316
35317
35318
35319 public function getStopSignal()
35320 {
35321 $this->requireProcessIsTerminated(__FUNCTION__);
35322
35323 $this->updateStatus(false);
35324
35325 return $this->processInformation['stopsig'];
35326 }
35327
35328
35329
35330
35331
35332
35333 public function isRunning()
35334 {
35335 if (self::STATUS_STARTED !== $this->status) {
35336 return false;
35337 }
35338
35339 $this->updateStatus(false);
35340
35341 return $this->processInformation['running'];
35342 }
35343
35344
35345
35346
35347
35348
35349 public function isStarted()
35350 {
35351 return $this->status != self::STATUS_READY;
35352 }
35353
35354
35355
35356
35357
35358
35359 public function isTerminated()
35360 {
35361 $this->updateStatus(false);
35362
35363 return $this->status == self::STATUS_TERMINATED;
35364 }
35365
35366
35367
35368
35369
35370
35371
35372
35373 public function getStatus()
35374 {
35375 $this->updateStatus(false);
35376
35377 return $this->status;
35378 }
35379
35380
35381
35382
35383
35384
35385
35386
35387
35388
35389
35390 public function stop($timeout = 10, $signal = null)
35391 {
35392 $timeoutMicro = microtime(true) + $timeout;
35393 if ($this->isRunning()) {
35394 if (defined('PHP_WINDOWS_VERSION_BUILD') && !$this->isSigchildEnabled()) {
35395 exec(sprintf("taskkill /F /T /PID %d 2>&1", $this->getPid()), $output, $exitCode);
35396 if ($exitCode > 0) {
35397 throw new RuntimeException('Unable to kill the process');
35398 }
35399 }
35400
35401  $this->doSignal(15, false);
35402 do {
35403 usleep(1000);
35404 } while ($this->isRunning() && microtime(true) < $timeoutMicro);
35405
35406 if ($this->isRunning() && !$this->isSigchildEnabled()) {
35407 if (null !== $signal || defined('SIGKILL')) {
35408
35409  
35410  
35411  
35412  $this->doSignal($signal ?: SIGKILL, false);
35413 }
35414 }
35415 }
35416
35417 $this->updateStatus(false);
35418 if ($this->processInformation['running']) {
35419 $this->close();
35420 }
35421
35422 return $this->exitcode;
35423 }
35424
35425
35426
35427
35428
35429
35430 public function addOutput($line)
35431 {
35432 $this->lastOutputTime = microtime(true);
35433 $this->stdout .= $line;
35434 }
35435
35436
35437
35438
35439
35440
35441 public function addErrorOutput($line)
35442 {
35443 $this->lastOutputTime = microtime(true);
35444 $this->stderr .= $line;
35445 }
35446
35447
35448
35449
35450
35451
35452 public function getCommandLine()
35453 {
35454 return $this->commandline;
35455 }
35456
35457
35458
35459
35460
35461
35462
35463
35464 public function setCommandLine($commandline)
35465 {
35466 $this->commandline = $commandline;
35467
35468 return $this;
35469 }
35470
35471
35472
35473
35474
35475
35476 public function getTimeout()
35477 {
35478 return $this->timeout;
35479 }
35480
35481
35482
35483
35484
35485
35486 public function getIdleTimeout()
35487 {
35488 return $this->idleTimeout;
35489 }
35490
35491
35492
35493
35494
35495
35496
35497
35498
35499
35500
35501
35502 public function setTimeout($timeout)
35503 {
35504 $this->timeout = $this->validateTimeout($timeout);
35505
35506 return $this;
35507 }
35508
35509
35510
35511
35512
35513
35514
35515
35516
35517
35518
35519
35520
35521 public function setIdleTimeout($timeout)
35522 {
35523 if (null !== $timeout && $this->outputDisabled) {
35524 throw new LogicException('Idle timeout can not be set while the output is disabled.');
35525 }
35526
35527 $this->idleTimeout = $this->validateTimeout($timeout);
35528
35529 return $this;
35530 }
35531
35532
35533
35534
35535
35536
35537
35538
35539
35540
35541 public function setTty($tty)
35542 {
35543 if (defined('PHP_WINDOWS_VERSION_BUILD') && $tty) {
35544 throw new RuntimeException('TTY mode is not supported on Windows platform.');
35545 }
35546
35547 $this->tty = (bool) $tty;
35548
35549 return $this;
35550 }
35551
35552
35553
35554
35555
35556
35557 public function isTty()
35558 {
35559 return $this->tty;
35560 }
35561
35562
35563
35564
35565
35566
35567
35568
35569 public function setPty($bool)
35570 {
35571 $this->pty = (bool) $bool;
35572
35573 return $this;
35574 }
35575
35576
35577
35578
35579
35580
35581 public function isPty()
35582 {
35583 return $this->pty;
35584 }
35585
35586
35587
35588
35589
35590
35591 public function getWorkingDirectory()
35592 {
35593 if (null === $this->cwd) {
35594
35595  
35596  return getcwd() ?: null;
35597 }
35598
35599 return $this->cwd;
35600 }
35601
35602
35603
35604
35605
35606
35607
35608
35609 public function setWorkingDirectory($cwd)
35610 {
35611 $this->cwd = $cwd;
35612
35613 return $this;
35614 }
35615
35616
35617
35618
35619
35620
35621 public function getEnv()
35622 {
35623 return $this->env;
35624 }
35625
35626
35627
35628
35629
35630
35631
35632
35633
35634
35635
35636
35637
35638
35639 public function setEnv(array $env)
35640 {
35641
35642  $env = array_filter($env, function ($value) {
35643 return !is_array($value);
35644 });
35645
35646 $this->env = array();
35647 foreach ($env as $key => $value) {
35648 $this->env[(binary) $key] = (binary) $value;
35649 }
35650
35651 return $this;
35652 }
35653
35654
35655
35656
35657
35658
35659
35660
35661
35662 public function getStdin()
35663 {
35664 return $this->getInput();
35665 }
35666
35667
35668
35669
35670
35671
35672 public function getInput()
35673 {
35674 return $this->input;
35675 }
35676
35677
35678
35679
35680
35681
35682
35683
35684
35685
35686
35687
35688
35689
35690 public function setStdin($stdin)
35691 {
35692 return $this->setInput($stdin);
35693 }
35694
35695
35696
35697
35698
35699
35700
35701
35702
35703
35704
35705
35706 public function setInput($input)
35707 {
35708 if ($this->isRunning()) {
35709 throw new LogicException('Input can not be set while the process is running.');
35710 }
35711
35712 $this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
35713
35714 return $this;
35715 }
35716
35717
35718
35719
35720
35721
35722 public function getOptions()
35723 {
35724 return $this->options;
35725 }
35726
35727
35728
35729
35730
35731
35732
35733
35734 public function setOptions(array $options)
35735 {
35736 $this->options = $options;
35737
35738 return $this;
35739 }
35740
35741
35742
35743
35744
35745
35746
35747
35748 public function getEnhanceWindowsCompatibility()
35749 {
35750 return $this->enhanceWindowsCompatibility;
35751 }
35752
35753
35754
35755
35756
35757
35758
35759
35760 public function setEnhanceWindowsCompatibility($enhance)
35761 {
35762 $this->enhanceWindowsCompatibility = (bool) $enhance;
35763
35764 return $this;
35765 }
35766
35767
35768
35769
35770
35771
35772 public function getEnhanceSigchildCompatibility()
35773 {
35774 return $this->enhanceSigchildCompatibility;
35775 }
35776
35777
35778
35779
35780
35781
35782
35783
35784
35785
35786
35787
35788 public function setEnhanceSigchildCompatibility($enhance)
35789 {
35790 $this->enhanceSigchildCompatibility = (bool) $enhance;
35791
35792 return $this;
35793 }
35794
35795
35796
35797
35798
35799
35800
35801
35802
35803 public function checkTimeout()
35804 {
35805 if ($this->status !== self::STATUS_STARTED) {
35806 return;
35807 }
35808
35809 if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
35810 $this->stop(0);
35811
35812 throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL);
35813 }
35814
35815 if (null !== $this->idleTimeout && $this->idleTimeout < microtime(true) - $this->lastOutputTime) {
35816 $this->stop(0);
35817
35818 throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE);
35819 }
35820 }
35821
35822
35823
35824
35825
35826
35827 public static function isPtySupported()
35828 {
35829 static $result;
35830
35831 if (null !== $result) {
35832 return $result;
35833 }
35834
35835 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
35836 return $result = false;
35837 }
35838
35839 $proc = @proc_open('echo 1', array(array('pty'), array('pty'), array('pty')), $pipes);
35840 if (is_resource($proc)) {
35841 proc_close($proc);
35842
35843 return $result = true;
35844 }
35845
35846 return $result = false;
35847 }
35848
35849
35850
35851
35852
35853
35854 private function getDescriptors()
35855 {
35856 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
35857 $this->processPipes = WindowsPipes::create($this, $this->input);
35858 } else {
35859 $this->processPipes = UnixPipes::create($this, $this->input);
35860 }
35861 $descriptors = $this->processPipes->getDescriptors($this->outputDisabled);
35862
35863 if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) {
35864
35865  $descriptors = array_merge($descriptors, array(array('pipe', 'w')));
35866
35867 $this->commandline = '('.$this->commandline.') 3>/dev/null; code=$?; echo $code >&3; exit $code';
35868 }
35869
35870 return $descriptors;
35871 }
35872
35873
35874
35875
35876
35877
35878
35879
35880
35881
35882
35883 protected function buildCallback($callback)
35884 {
35885 $that = $this;
35886 $out = self::OUT;
35887 $err = self::ERR;
35888 $callback = function ($type, $data) use ($that, $callback, $out, $err) {
35889 if ($out == $type) {
35890 $that->addOutput($data);
35891 } else {
35892 $that->addErrorOutput($data);
35893 }
35894
35895 if (null !== $callback) {
35896 call_user_func($callback, $type, $data);
35897 }
35898 };
35899
35900 return $callback;
35901 }
35902
35903
35904
35905
35906
35907
35908 protected function updateStatus($blocking)
35909 {
35910 if (self::STATUS_STARTED !== $this->status) {
35911 return;
35912 }
35913
35914 $this->processInformation = proc_get_status($this->process);
35915 $this->captureExitCode();
35916
35917 $this->readPipes($blocking, defined('PHP_WINDOWS_VERSION_BUILD') ? !$this->processInformation['running'] : true);
35918
35919 if (!$this->processInformation['running']) {
35920 $this->close();
35921 }
35922 }
35923
35924
35925
35926
35927
35928
35929 protected function isSigchildEnabled()
35930 {
35931 if (null !== self::$sigchild) {
35932 return self::$sigchild;
35933 }
35934
35935 if (!function_exists('phpinfo')) {
35936 return self::$sigchild = false;
35937 }
35938
35939 ob_start();
35940 phpinfo(INFO_GENERAL);
35941
35942 return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild');
35943 }
35944
35945
35946
35947
35948
35949
35950
35951
35952
35953
35954 private function validateTimeout($timeout)
35955 {
35956 $timeout = (float) $timeout;
35957
35958 if (0.0 === $timeout) {
35959 $timeout = null;
35960 } elseif ($timeout < 0) {
35961 throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
35962 }
35963
35964 return $timeout;
35965 }
35966
35967
35968
35969
35970
35971
35972
35973 private function readPipes($blocking, $close)
35974 {
35975 $result = $this->processPipes->readAndWrite($blocking, $close);
35976
35977 foreach ($result as $type => $data) {
35978 if (3 == $type) {
35979 $this->fallbackExitcode = (int) $data;
35980 } else {
35981 call_user_func($this->callback, $type === self::STDOUT ? self::OUT : self::ERR, $data);
35982 }
35983 }
35984 }
35985
35986
35987
35988
35989 private function captureExitCode()
35990 {
35991 if (isset($this->processInformation['exitcode']) && -1 != $this->processInformation['exitcode']) {
35992 $this->exitcode = $this->processInformation['exitcode'];
35993 }
35994 }
35995
35996
35997
35998
35999
36000
36001 private function close()
36002 {
36003 $this->processPipes->close();
36004 if (is_resource($this->process)) {
36005 $exitcode = proc_close($this->process);
36006 } else {
36007 $exitcode = -1;
36008 }
36009
36010 $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1);
36011 $this->status = self::STATUS_TERMINATED;
36012
36013 if (-1 === $this->exitcode && null !== $this->fallbackExitcode) {
36014 $this->exitcode = $this->fallbackExitcode;
36015 } elseif (-1 === $this->exitcode && $this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) {
36016
36017  $this->exitcode = 128 + $this->processInformation['termsig'];
36018 }
36019
36020 return $this->exitcode;
36021 }
36022
36023
36024
36025
36026 private function resetProcessData()
36027 {
36028 $this->starttime = null;
36029 $this->callback = null;
36030 $this->exitcode = null;
36031 $this->fallbackExitcode = null;
36032 $this->processInformation = null;
36033 $this->stdout = null;
36034 $this->stderr = null;
36035 $this->process = null;
36036 $this->latestSignal = null;
36037 $this->status = self::STATUS_READY;
36038 $this->incrementalOutputOffset = 0;
36039 $this->incrementalErrorOutputOffset = 0;
36040 }
36041
36042
36043
36044
36045
36046
36047
36048
36049
36050
36051
36052
36053
36054 private function doSignal($signal, $throwException)
36055 {
36056 if (!$this->isRunning()) {
36057 if ($throwException) {
36058 throw new LogicException('Can not send signal on a non running process.');
36059 }
36060
36061 return false;
36062 }
36063
36064 if ($this->isSigchildEnabled()) {
36065 if ($throwException) {
36066 throw new RuntimeException('This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
36067 }
36068
36069 return false;
36070 }
36071
36072 if (true !== @proc_terminate($this->process, $signal)) {
36073 if ($throwException) {
36074 throw new RuntimeException(sprintf('Error while sending signal `%s`.', $signal));
36075 }
36076
36077 return false;
36078 }
36079
36080 $this->latestSignal = $signal;
36081
36082 return true;
36083 }
36084
36085
36086
36087
36088
36089
36090
36091
36092 private function requireProcessIsStarted($functionName)
36093 {
36094 if (!$this->isStarted()) {
36095 throw new LogicException(sprintf('Process must be started before calling %s.', $functionName));
36096 }
36097 }
36098
36099
36100
36101
36102
36103
36104
36105
36106 private function requireProcessIsTerminated($functionName)
36107 {
36108 if (!$this->isTerminated()) {
36109 throw new LogicException(sprintf('Process must be terminated before calling %s.', $functionName));
36110 }
36111 }
36112 }
36113 <?php
36114
36115
36116
36117
36118
36119
36120
36121
36122
36123
36124 namespace Symfony\Component\Process;
36125
36126 use Symfony\Component\Process\Exception\InvalidArgumentException;
36127 use Symfony\Component\Process\Exception\LogicException;
36128
36129
36130
36131
36132
36133
36134 class ProcessBuilder
36135 {
36136 private $arguments;
36137 private $cwd;
36138 private $env = array();
36139 private $input;
36140 private $timeout = 60;
36141 private $options = array();
36142 private $inheritEnv = true;
36143 private $prefix = array();
36144 private $outputDisabled = false;
36145
36146
36147
36148
36149
36150
36151 public function __construct(array $arguments = array())
36152 {
36153 $this->arguments = $arguments;
36154 }
36155
36156
36157
36158
36159
36160
36161
36162
36163 public static function create(array $arguments = array())
36164 {
36165 return new static($arguments);
36166 }
36167
36168
36169
36170
36171
36172
36173
36174
36175 public function add($argument)
36176 {
36177 $this->arguments[] = $argument;
36178
36179 return $this;
36180 }
36181
36182
36183
36184
36185
36186
36187
36188
36189
36190
36191 public function setPrefix($prefix)
36192 {
36193 $this->prefix = is_array($prefix) ? $prefix : array($prefix);
36194
36195 return $this;
36196 }
36197
36198
36199
36200
36201
36202
36203
36204
36205
36206
36207
36208 public function setArguments(array $arguments)
36209 {
36210 $this->arguments = $arguments;
36211
36212 return $this;
36213 }
36214
36215
36216
36217
36218
36219
36220
36221
36222 public function setWorkingDirectory($cwd)
36223 {
36224 $this->cwd = $cwd;
36225
36226 return $this;
36227 }
36228
36229
36230
36231
36232
36233
36234
36235
36236 public function inheritEnvironmentVariables($inheritEnv = true)
36237 {
36238 $this->inheritEnv = $inheritEnv;
36239
36240 return $this;
36241 }
36242
36243
36244
36245
36246
36247
36248
36249
36250
36251
36252
36253
36254 public function setEnv($name, $value)
36255 {
36256 $this->env[$name] = $value;
36257
36258 return $this;
36259 }
36260
36261
36262
36263
36264
36265
36266
36267
36268
36269
36270
36271
36272 public function addEnvironmentVariables(array $variables)
36273 {
36274 $this->env = array_replace($this->env, $variables);
36275
36276 return $this;
36277 }
36278
36279
36280
36281
36282
36283
36284
36285
36286
36287
36288
36289
36290 public function setInput($input)
36291 {
36292 $this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
36293
36294 return $this;
36295 }
36296
36297
36298
36299
36300
36301
36302
36303
36304
36305
36306
36307
36308 public function setTimeout($timeout)
36309 {
36310 if (null === $timeout) {
36311 $this->timeout = null;
36312
36313 return $this;
36314 }
36315
36316 $timeout = (float) $timeout;
36317
36318 if ($timeout < 0) {
36319 throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
36320 }
36321
36322 $this->timeout = $timeout;
36323
36324 return $this;
36325 }
36326
36327
36328
36329
36330
36331
36332
36333
36334
36335 public function setOption($name, $value)
36336 {
36337 $this->options[$name] = $value;
36338
36339 return $this;
36340 }
36341
36342
36343
36344
36345
36346
36347 public function disableOutput()
36348 {
36349 $this->outputDisabled = true;
36350
36351 return $this;
36352 }
36353
36354
36355
36356
36357
36358
36359 public function enableOutput()
36360 {
36361 $this->outputDisabled = false;
36362
36363 return $this;
36364 }
36365
36366
36367
36368
36369
36370
36371
36372
36373 public function getProcess()
36374 {
36375 if (0 === count($this->prefix) && 0 === count($this->arguments)) {
36376 throw new LogicException('You must add() command arguments before calling getProcess().');
36377 }
36378
36379 $options = $this->options;
36380
36381 $arguments = array_merge($this->prefix, $this->arguments);
36382 $script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
36383
36384 if ($this->inheritEnv) {
36385
36386  $env = array_replace($_ENV, $_SERVER, $this->env);
36387 } else {
36388 $env = $this->env;
36389 }
36390
36391 $process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options);
36392
36393 if ($this->outputDisabled) {
36394 $process->disableOutput();
36395 }
36396
36397 return $process;
36398 }
36399 }
36400 <?php
36401
36402
36403
36404
36405
36406
36407
36408
36409
36410
36411 namespace Symfony\Component\Process;
36412
36413 use Symfony\Component\Process\Exception\InvalidArgumentException;
36414
36415
36416
36417
36418
36419
36420
36421
36422 class ProcessUtils
36423 {
36424
36425
36426
36427 private function __construct()
36428 {
36429 }
36430
36431
36432
36433
36434
36435
36436
36437
36438 public static function escapeArgument($argument)
36439 {
36440
36441  
36442  
36443  
36444  if (defined('PHP_WINDOWS_VERSION_BUILD')) {
36445 if ('' === $argument) {
36446 return escapeshellarg($argument);
36447 }
36448
36449 $escapedArgument = '';
36450 $quote = false;
36451 foreach (preg_split('/(")/i', $argument, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE) as $part) {
36452 if ('"' === $part) {
36453 $escapedArgument .= '\\"';
36454 } elseif (self::isSurroundedBy($part, '%')) {
36455
36456  $escapedArgument .= '^%"'.substr($part, 1, -1).'"^%';
36457 } else {
36458
36459  if ('\\' === substr($part, -1)) {
36460 $part .= '\\';
36461 }
36462 $quote = true;
36463 $escapedArgument .= $part;
36464 }
36465 }
36466 if ($quote) {
36467 $escapedArgument = '"'.$escapedArgument.'"';
36468 }
36469
36470 return $escapedArgument;
36471 }
36472
36473 return escapeshellarg($argument);
36474 }
36475
36476
36477
36478
36479
36480
36481
36482
36483
36484
36485
36486 public static function validateInput($caller, $input)
36487 {
36488 if (null !== $input) {
36489 if (is_resource($input)) {
36490 return $input;
36491 }
36492 if (is_scalar($input)) {
36493 return (string) $input;
36494 }
36495
36496  if (is_object($input) && method_exists($input, '__toString')) {
36497 return (string) $input;
36498 }
36499
36500 throw new InvalidArgumentException(sprintf('%s only accepts strings or stream resources.', $caller));
36501 }
36502
36503 return $input;
36504 }
36505
36506 private static function isSurroundedBy($arg, $char)
36507 {
36508 return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
36509 }
36510 }
36511 <?php
36512
36513
36514
36515
36516
36517
36518
36519
36520
36521
36522 namespace Symfony\Component\Process\Exception;
36523
36524 use Symfony\Component\Process\Process;
36525
36526
36527
36528
36529
36530
36531 class ProcessTimedOutException extends RuntimeException
36532 {
36533 const TYPE_GENERAL = 1;
36534 const TYPE_IDLE = 2;
36535
36536 private $process;
36537 private $timeoutType;
36538
36539 public function __construct(Process $process, $timeoutType)
36540 {
36541 $this->process = $process;
36542 $this->timeoutType = $timeoutType;
36543
36544 parent::__construct(sprintf(
36545 'The process "%s" exceeded the timeout of %s seconds.',
36546 $process->getCommandLine(),
36547 $this->getExceededTimeout()
36548 ));
36549 }
36550
36551 public function getProcess()
36552 {
36553 return $this->process;
36554 }
36555
36556 public function isGeneralTimeout()
36557 {
36558 return $this->timeoutType === self::TYPE_GENERAL;
36559 }
36560
36561 public function isIdleTimeout()
36562 {
36563 return $this->timeoutType === self::TYPE_IDLE;
36564 }
36565
36566 public function getExceededTimeout()
36567 {
36568 switch ($this->timeoutType) {
36569 case self::TYPE_GENERAL:
36570 return $this->process->getTimeout();
36571
36572 case self::TYPE_IDLE:
36573 return $this->process->getIdleTimeout();
36574
36575 default:
36576 throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
36577 }
36578 }
36579 }
36580 <?php
36581
36582
36583
36584
36585
36586
36587
36588
36589
36590
36591 namespace Symfony\Component\Process\Exception;
36592
36593
36594
36595
36596
36597
36598 interface ExceptionInterface
36599 {
36600 }
36601 <?php
36602
36603
36604
36605
36606
36607
36608
36609
36610
36611
36612 namespace Symfony\Component\Process\Exception;
36613
36614
36615
36616
36617
36618
36619 class RuntimeException extends \RuntimeException implements ExceptionInterface
36620 {
36621 }
36622 <?php
36623
36624
36625
36626
36627
36628
36629
36630
36631
36632
36633 namespace Symfony\Component\Process\Exception;
36634
36635
36636
36637
36638
36639
36640 class LogicException extends \LogicException implements ExceptionInterface
36641 {
36642 }
36643 <?php
36644
36645
36646
36647
36648
36649
36650
36651
36652
36653
36654 namespace Symfony\Component\Process\Exception;
36655
36656 use Symfony\Component\Process\Process;
36657
36658
36659
36660
36661
36662
36663 class ProcessFailedException extends RuntimeException
36664 {
36665 private $process;
36666
36667 public function __construct(Process $process)
36668 {
36669 if ($process->isSuccessful()) {
36670 throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
36671 }
36672
36673 $error = sprintf('The command "%s" failed.'."\nExit Code: %s(%s)",
36674 $process->getCommandLine(),
36675 $process->getExitCode(),
36676 $process->getExitCodeText()
36677 );
36678
36679 if (!$process->isOutputDisabled()) {
36680 $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
36681 $process->getOutput(),
36682 $process->getErrorOutput()
36683 );
36684 }
36685
36686 parent::__construct($error);
36687
36688 $this->process = $process;
36689 }
36690
36691 public function getProcess()
36692 {
36693 return $this->process;
36694 }
36695 }
36696 <?php
36697
36698
36699
36700
36701
36702
36703
36704
36705
36706
36707 namespace Symfony\Component\Process\Exception;
36708
36709
36710
36711
36712
36713
36714 class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
36715 {
36716 }
36717 <?php
36718
36719
36720
36721
36722
36723
36724
36725
36726
36727
36728 namespace Symfony\Component\Process;
36729
36730
36731
36732
36733
36734
36735
36736 class PhpExecutableFinder
36737 {
36738 private $executableFinder;
36739
36740 public function __construct()
36741 {
36742 $this->executableFinder = new ExecutableFinder();
36743 }
36744
36745
36746
36747
36748
36749
36750
36751
36752 public function find($includeArgs = true)
36753 {
36754
36755  if (defined('HHVM_VERSION')) {
36756 return (false !== ($hhvm = getenv('PHP_BINARY')) ? $hhvm : PHP_BINARY).($includeArgs ? ' '.implode(' ', $this->findArguments()) : '');
36757 }
36758
36759
36760  if (defined('PHP_BINARY') && PHP_BINARY && in_array(PHP_SAPI, array('cli', 'cli-server')) && is_file(PHP_BINARY)) {
36761 return PHP_BINARY;
36762 }
36763
36764 if ($php = getenv('PHP_PATH')) {
36765 if (!is_executable($php)) {
36766 return false;
36767 }
36768
36769 return $php;
36770 }
36771
36772 if ($php = getenv('PHP_PEAR_PHP_BIN')) {
36773 if (is_executable($php)) {
36774 return $php;
36775 }
36776 }
36777
36778 $dirs = array(PHP_BINDIR);
36779 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
36780 $dirs[] = 'C:\xampp\php\\';
36781 }
36782
36783 return $this->executableFinder->find('php', false, $dirs);
36784 }
36785
36786
36787
36788
36789
36790
36791 public function findArguments()
36792 {
36793 $arguments = array();
36794
36795
36796  if (defined('HHVM_VERSION')) {
36797 $arguments[] = '--php';
36798 }
36799
36800 return $arguments;
36801 }
36802 }
36803 <?php
36804
36805
36806
36807
36808
36809
36810
36811
36812
36813
36814 namespace Symfony\Component\Process\Pipes;
36815
36816
36817
36818
36819
36820
36821
36822
36823 interface PipesInterface
36824 {
36825 const CHUNK_SIZE = 16384;
36826
36827
36828
36829
36830
36831
36832 public function getDescriptors();
36833
36834
36835
36836
36837
36838
36839 public function getFiles();
36840
36841
36842
36843
36844
36845
36846
36847
36848
36849 public function readAndWrite($blocking, $close = false);
36850
36851
36852
36853
36854
36855
36856 public function areOpen();
36857
36858
36859
36860
36861 public function close();
36862 }
36863 <?php
36864
36865
36866
36867
36868
36869
36870
36871
36872
36873
36874 namespace Symfony\Component\Process\Pipes;
36875
36876
36877
36878
36879
36880
36881 abstract class AbstractPipes implements PipesInterface
36882 {
36883
36884 public $pipes = array();
36885
36886
36887 protected $inputBuffer = '';
36888
36889 protected $input;
36890
36891
36892 private $blocked = true;
36893
36894
36895
36896
36897 public function close()
36898 {
36899 foreach ($this->pipes as $pipe) {
36900 fclose($pipe);
36901 }
36902 $this->pipes = array();
36903 }
36904
36905
36906
36907
36908
36909
36910 protected function hasSystemCallBeenInterrupted()
36911 {
36912 $lastError = error_get_last();
36913
36914
36915  return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
36916 }
36917
36918
36919
36920
36921 protected function unblock()
36922 {
36923 if (!$this->blocked) {
36924 return;
36925 }
36926
36927 foreach ($this->pipes as $pipe) {
36928 stream_set_blocking($pipe, 0);
36929 }
36930 if (null !== $this->input) {
36931 stream_set_blocking($this->input, 0);
36932 }
36933
36934 $this->blocked = false;
36935 }
36936 }
36937 <?php
36938
36939
36940
36941
36942
36943
36944
36945
36946
36947
36948 namespace Symfony\Component\Process\Pipes;
36949
36950 use Symfony\Component\Process\Process;
36951 use Symfony\Component\Process\Exception\RuntimeException;
36952
36953
36954
36955
36956
36957
36958
36959
36960
36961
36962
36963 class WindowsPipes extends AbstractPipes
36964 {
36965
36966 private $files = array();
36967
36968 private $fileHandles = array();
36969
36970 private $readBytes = array(
36971 Process::STDOUT => 0,
36972 Process::STDERR => 0,
36973 );
36974
36975 private $disableOutput;
36976
36977 public function __construct($disableOutput, $input)
36978 {
36979 $this->disableOutput = (bool) $disableOutput;
36980
36981 if (!$this->disableOutput) {
36982
36983  
36984  
36985  
36986  $this->files = array(
36987 Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'),
36988 Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'),
36989 );
36990 foreach ($this->files as $offset => $file) {
36991 $this->fileHandles[$offset] = fopen($this->files[$offset], 'rb');
36992 if (false === $this->fileHandles[$offset]) {
36993 throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');
36994 }
36995 }
36996 }
36997
36998 if (is_resource($input)) {
36999 $this->input = $input;
37000 } else {
37001 $this->inputBuffer = $input;
37002 }
37003 }
37004
37005 public function __destruct()
37006 {
37007 $this->close();
37008 $this->removeFiles();
37009 }
37010
37011
37012
37013
37014 public function getDescriptors()
37015 {
37016 if ($this->disableOutput) {
37017 $nullstream = fopen('NUL', 'c');
37018
37019 return array(
37020 array('pipe', 'r'),
37021 $nullstream,
37022 $nullstream,
37023 );
37024 }
37025
37026
37027  
37028  
37029  return array(
37030 array('pipe', 'r'),
37031 array('file', 'NUL', 'w'),
37032 array('file', 'NUL', 'w'),
37033 );
37034 }
37035
37036
37037
37038
37039 public function getFiles()
37040 {
37041 return $this->files;
37042 }
37043
37044
37045
37046
37047 public function readAndWrite($blocking, $close = false)
37048 {
37049 $this->write($blocking, $close);
37050
37051 $read = array();
37052 $fh = $this->fileHandles;
37053 foreach ($fh as $type => $fileHandle) {
37054 if (0 !== fseek($fileHandle, $this->readBytes[$type])) {
37055 continue;
37056 }
37057 $data = '';
37058 $dataread = null;
37059 while (!feof($fileHandle)) {
37060 if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) {
37061 $data .= $dataread;
37062 }
37063 }
37064 if (0 < $length = strlen($data)) {
37065 $this->readBytes[$type] += $length;
37066 $read[$type] = $data;
37067 }
37068
37069 if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) {
37070 fclose($this->fileHandles[$type]);
37071 unset($this->fileHandles[$type]);
37072 }
37073 }
37074
37075 return $read;
37076 }
37077
37078
37079
37080
37081 public function areOpen()
37082 {
37083 return (bool) $this->pipes && (bool) $this->fileHandles;
37084 }
37085
37086
37087
37088
37089 public function close()
37090 {
37091 parent::close();
37092 foreach ($this->fileHandles as $handle) {
37093 fclose($handle);
37094 }
37095 $this->fileHandles = array();
37096 }
37097
37098
37099
37100
37101
37102
37103
37104
37105
37106 public static function create(Process $process, $input)
37107 {
37108 return new static($process->isOutputDisabled(), $input);
37109 }
37110
37111
37112
37113
37114 private function removeFiles()
37115 {
37116 foreach ($this->files as $filename) {
37117 if (file_exists($filename)) {
37118 @unlink($filename);
37119 }
37120 }
37121 $this->files = array();
37122 }
37123
37124
37125
37126
37127
37128
37129
37130 private function write($blocking, $close)
37131 {
37132 if (empty($this->pipes)) {
37133 return;
37134 }
37135
37136 $this->unblock();
37137
37138 $r = null !== $this->input ? array('input' => $this->input) : null;
37139 $w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
37140 $e = null;
37141
37142
37143  if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
37144
37145  
37146  if (!$this->hasSystemCallBeenInterrupted()) {
37147 $this->pipes = array();
37148 }
37149
37150 return;
37151 }
37152
37153
37154  if (0 === $n) {
37155 return;
37156 }
37157
37158 if (null !== $w && 0 < count($r)) {
37159 $data = '';
37160 while ($dataread = fread($r['input'], self::CHUNK_SIZE)) {
37161 $data .= $dataread;
37162 }
37163
37164 $this->inputBuffer .= $data;
37165
37166 if (false === $data || (true === $close && feof($r['input']) && '' === $data)) {
37167
37168  
37169  unset($this->input);
37170 }
37171 }
37172
37173 if (null !== $w && 0 < count($w)) {
37174 while ($len = strlen($this->inputBuffer)) {
37175 $written = fwrite($w[0], $this->inputBuffer, 2 << 18);
37176 if ($written > 0) {
37177 $this->inputBuffer = (string) substr($this->inputBuffer, $written);
37178 } else {
37179 break;
37180 }
37181 }
37182 }
37183
37184
37185  if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
37186 fclose($this->pipes[0]);
37187 unset($this->pipes[0]);
37188 }
37189 }
37190 }
37191 <?php
37192
37193
37194
37195
37196
37197
37198
37199
37200
37201
37202 namespace Symfony\Component\Process\Pipes;
37203
37204 use Symfony\Component\Process\Process;
37205
37206
37207
37208
37209
37210
37211
37212
37213 class UnixPipes extends AbstractPipes
37214 {
37215
37216 private $ttyMode;
37217
37218 private $ptyMode;
37219
37220 private $disableOutput;
37221
37222 public function __construct($ttyMode, $ptyMode, $input, $disableOutput)
37223 {
37224 $this->ttyMode = (bool) $ttyMode;
37225 $this->ptyMode = (bool) $ptyMode;
37226 $this->disableOutput = (bool) $disableOutput;
37227
37228 if (is_resource($input)) {
37229 $this->input = $input;
37230 } else {
37231 $this->inputBuffer = (string) $input;
37232 }
37233 }
37234
37235 public function __destruct()
37236 {
37237 $this->close();
37238 }
37239
37240
37241
37242
37243 public function getDescriptors()
37244 {
37245 if ($this->disableOutput) {
37246 $nullstream = fopen('/dev/null', 'c');
37247
37248 return array(
37249 array('pipe', 'r'),
37250 $nullstream,
37251 $nullstream,
37252 );
37253 }
37254
37255 if ($this->ttyMode) {
37256 return array(
37257 array('file', '/dev/tty', 'r'),
37258 array('file', '/dev/tty', 'w'),
37259 array('file', '/dev/tty', 'w'),
37260 );
37261 }
37262
37263 if ($this->ptyMode && Process::isPtySupported()) {
37264 return array(
37265 array('pty'),
37266 array('pty'),
37267 array('pty'),
37268 );
37269 }
37270
37271 return array(
37272 array('pipe', 'r'),
37273 array('pipe', 'w'), 
37274  array('pipe', 'w'), 
37275  );
37276 }
37277
37278
37279
37280
37281 public function getFiles()
37282 {
37283 return array();
37284 }
37285
37286
37287
37288
37289 public function readAndWrite($blocking, $close = false)
37290 {
37291
37292  
37293  if (1 === count($this->pipes) && array(0) === array_keys($this->pipes)) {
37294 fclose($this->pipes[0]);
37295 unset($this->pipes[0]);
37296 }
37297
37298 if (empty($this->pipes)) {
37299 return array();
37300 }
37301
37302 $this->unblock();
37303
37304 $read = array();
37305
37306 if (null !== $this->input) {
37307
37308  
37309  $r = array_merge($this->pipes, array('input' => $this->input));
37310 } else {
37311 $r = $this->pipes;
37312 }
37313
37314  unset ($r[0]);
37315
37316 $w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
37317 $e = null;
37318
37319
37320  if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
37321
37322  
37323  if (!$this->hasSystemCallBeenInterrupted()) {
37324 $this->pipes = array();
37325 }
37326
37327 return $read;
37328 }
37329
37330
37331  if (0 === $n) {
37332 return $read;
37333 }
37334
37335 foreach ($r as $pipe) {
37336
37337  
37338  $type = (false !== $found = array_search($pipe, $this->pipes)) ? $found : 'input';
37339 $data = '';
37340 while ('' !== $dataread = (string) fread($pipe, self::CHUNK_SIZE)) {
37341 $data .= $dataread;
37342 }
37343
37344 if ('' !== $data) {
37345 if ($type === 'input') {
37346 $this->inputBuffer .= $data;
37347 } else {
37348 $read[$type] = $data;
37349 }
37350 }
37351
37352 if (false === $data || (true === $close && feof($pipe) && '' === $data)) {
37353 if ($type === 'input') {
37354
37355  
37356  $this->input = null;
37357 } else {
37358 fclose($this->pipes[$type]);
37359 unset($this->pipes[$type]);
37360 }
37361 }
37362 }
37363
37364 if (null !== $w && 0 < count($w)) {
37365 while ($len = strlen($this->inputBuffer)) {
37366 $written = fwrite($w[0], $this->inputBuffer, 2 << 18); 
37367  if ($written > 0) {
37368 $this->inputBuffer = (string) substr($this->inputBuffer, $written);
37369 } else {
37370 break;
37371 }
37372 }
37373 }
37374
37375
37376  if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
37377 fclose($this->pipes[0]);
37378 unset($this->pipes[0]);
37379 }
37380
37381 return $read;
37382 }
37383
37384
37385
37386
37387 public function areOpen()
37388 {
37389 return (bool) $this->pipes;
37390 }
37391
37392
37393
37394
37395
37396
37397
37398
37399
37400 public static function create(Process $process, $input)
37401 {
37402 return new static($process->isTty(), $process->isPty(), $input, $process->isOutputDisabled());
37403 }
37404 }
37405 <?php
37406
37407
37408
37409
37410
37411
37412
37413
37414
37415
37416 namespace Symfony\Component\Console\Command;
37417
37418 use Symfony\Component\Console\Helper\DescriptorHelper;
37419 use Symfony\Component\Console\Input\InputArgument;
37420 use Symfony\Component\Console\Input\InputOption;
37421 use Symfony\Component\Console\Input\InputInterface;
37422 use Symfony\Component\Console\Output\OutputInterface;
37423
37424
37425
37426
37427
37428
37429 class HelpCommand extends Command
37430 {
37431 private $command;
37432
37433
37434
37435
37436 protected function configure()
37437 {
37438 $this->ignoreValidationErrors();
37439
37440 $this
37441 ->setName('help')
37442 ->setDefinition(array(
37443 new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
37444 new InputOption('xml', null, InputOption::VALUE_NONE, 'To output help as XML'),
37445 new InputOption('format', null, InputOption::VALUE_REQUIRED, 'To output help in other formats', 'txt'),
37446 new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
37447 ))
37448 ->setDescription('Displays help for a command')
37449 ->setHelp(<<<EOF
37450 The <info>%command.name%</info> command displays help for a given command:
37451
37452   <info>php %command.full_name% list</info>
37453
37454 You can also output the help in other formats by using the <comment>--format</comment> option:
37455
37456   <info>php %command.full_name% --format=xml list</info>
37457
37458 To display the list of available commands, please use the <info>list</info> command.
37459 EOF
37460 )
37461 ;
37462 }
37463
37464
37465
37466
37467
37468
37469 public function setCommand(Command $command)
37470 {
37471 $this->command = $command;
37472 }
37473
37474
37475
37476
37477 protected function execute(InputInterface $input, OutputInterface $output)
37478 {
37479 if (null === $this->command) {
37480 $this->command = $this->getApplication()->find($input->getArgument('command_name'));
37481 }
37482
37483 if ($input->getOption('xml')) {
37484 $input->setOption('format', 'xml');
37485 }
37486
37487 $helper = new DescriptorHelper();
37488 $helper->describe($output, $this->command, array(
37489 'format' => $input->getOption('format'),
37490 'raw' => $input->getOption('raw'),
37491 ));
37492
37493 $this->command = null;
37494 }
37495 }
37496 <?php
37497
37498
37499
37500
37501
37502
37503
37504
37505
37506
37507 namespace Symfony\Component\Console\Command;
37508
37509 use Symfony\Component\Console\Descriptor\TextDescriptor;
37510 use Symfony\Component\Console\Descriptor\XmlDescriptor;
37511 use Symfony\Component\Console\Input\InputDefinition;
37512 use Symfony\Component\Console\Input\InputOption;
37513 use Symfony\Component\Console\Input\InputArgument;
37514 use Symfony\Component\Console\Input\InputInterface;
37515 use Symfony\Component\Console\Output\BufferedOutput;
37516 use Symfony\Component\Console\Output\OutputInterface;
37517 use Symfony\Component\Console\Application;
37518 use Symfony\Component\Console\Helper\HelperSet;
37519
37520
37521
37522
37523
37524
37525
37526
37527 class Command
37528 {
37529 private $application;
37530 private $name;
37531 private $processTitle;
37532 private $aliases = array();
37533 private $definition;
37534 private $help;
37535 private $description;
37536 private $ignoreValidationErrors = false;
37537 private $applicationDefinitionMerged = false;
37538 private $applicationDefinitionMergedWithArgs = false;
37539 private $code;
37540 private $synopsis;
37541 private $helperSet;
37542
37543
37544
37545
37546
37547
37548
37549
37550
37551
37552 public function __construct($name = null)
37553 {
37554 $this->definition = new InputDefinition();
37555
37556 if (null !== $name) {
37557 $this->setName($name);
37558 }
37559
37560 $this->configure();
37561
37562 if (!$this->name) {
37563 throw new \LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_class($this)));
37564 }
37565 }
37566
37567
37568
37569
37570
37571
37572 public function ignoreValidationErrors()
37573 {
37574 $this->ignoreValidationErrors = true;
37575 }
37576
37577
37578
37579
37580
37581
37582
37583
37584 public function setApplication(Application $application = null)
37585 {
37586 $this->application = $application;
37587 if ($application) {
37588 $this->setHelperSet($application->getHelperSet());
37589 } else {
37590 $this->helperSet = null;
37591 }
37592 }
37593
37594
37595
37596
37597
37598
37599 public function setHelperSet(HelperSet $helperSet)
37600 {
37601 $this->helperSet = $helperSet;
37602 }
37603
37604
37605
37606
37607
37608
37609 public function getHelperSet()
37610 {
37611 return $this->helperSet;
37612 }
37613
37614
37615
37616
37617
37618
37619
37620
37621 public function getApplication()
37622 {
37623 return $this->application;
37624 }
37625
37626
37627
37628
37629
37630
37631
37632
37633
37634 public function isEnabled()
37635 {
37636 return true;
37637 }
37638
37639
37640
37641
37642 protected function configure()
37643 {
37644 }
37645
37646
37647
37648
37649
37650
37651
37652
37653
37654
37655
37656
37657
37658
37659
37660
37661
37662 protected function execute(InputInterface $input, OutputInterface $output)
37663 {
37664 throw new \LogicException('You must override the execute() method in the concrete command class.');
37665 }
37666
37667
37668
37669
37670
37671
37672
37673 protected function interact(InputInterface $input, OutputInterface $output)
37674 {
37675 }
37676
37677
37678
37679
37680
37681
37682
37683
37684
37685
37686 protected function initialize(InputInterface $input, OutputInterface $output)
37687 {
37688 }
37689
37690
37691
37692
37693
37694
37695
37696
37697
37698
37699
37700
37701
37702
37703
37704
37705
37706
37707
37708
37709 public function run(InputInterface $input, OutputInterface $output)
37710 {
37711
37712  $this->getSynopsis();
37713
37714
37715  $this->mergeApplicationDefinition();
37716
37717
37718  try {
37719 $input->bind($this->definition);
37720 } catch (\Exception $e) {
37721 if (!$this->ignoreValidationErrors) {
37722 throw $e;
37723 }
37724 }
37725
37726 $this->initialize($input, $output);
37727
37728 if (null !== $this->processTitle) {
37729 if (function_exists('cli_set_process_title')) {
37730 cli_set_process_title($this->processTitle);
37731 } elseif (function_exists('setproctitle')) {
37732 setproctitle($this->processTitle);
37733 } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
37734 $output->writeln('<comment>Install the proctitle PECL to be able to change the process title.</comment>');
37735 }
37736 }
37737
37738 if ($input->isInteractive()) {
37739 $this->interact($input, $output);
37740 }
37741
37742 $input->validate();
37743
37744 if ($this->code) {
37745 $statusCode = call_user_func($this->code, $input, $output);
37746 } else {
37747 $statusCode = $this->execute($input, $output);
37748 }
37749
37750 return is_numeric($statusCode) ? (int) $statusCode : 0;
37751 }
37752
37753
37754
37755
37756
37757
37758
37759
37760
37761
37762
37763
37764
37765
37766
37767
37768
37769 public function setCode($code)
37770 {
37771 if (!is_callable($code)) {
37772 throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
37773 }
37774
37775 $this->code = $code;
37776
37777 return $this;
37778 }
37779
37780
37781
37782
37783
37784
37785
37786
37787 public function mergeApplicationDefinition($mergeArgs = true)
37788 {
37789 if (null === $this->application || (true === $this->applicationDefinitionMerged && ($this->applicationDefinitionMergedWithArgs || !$mergeArgs))) {
37790 return;
37791 }
37792
37793 if ($mergeArgs) {
37794 $currentArguments = $this->definition->getArguments();
37795 $this->definition->setArguments($this->application->getDefinition()->getArguments());
37796 $this->definition->addArguments($currentArguments);
37797 }
37798
37799 $this->definition->addOptions($this->application->getDefinition()->getOptions());
37800
37801 $this->applicationDefinitionMerged = true;
37802 if ($mergeArgs) {
37803 $this->applicationDefinitionMergedWithArgs = true;
37804 }
37805 }
37806
37807
37808
37809
37810
37811
37812
37813
37814
37815
37816 public function setDefinition($definition)
37817 {
37818 if ($definition instanceof InputDefinition) {
37819 $this->definition = $definition;
37820 } else {
37821 $this->definition->setDefinition($definition);
37822 }
37823
37824 $this->applicationDefinitionMerged = false;
37825
37826 return $this;
37827 }
37828
37829
37830
37831
37832
37833
37834
37835
37836 public function getDefinition()
37837 {
37838 return $this->definition;
37839 }
37840
37841
37842
37843
37844
37845
37846
37847
37848
37849
37850
37851 public function getNativeDefinition()
37852 {
37853 return $this->getDefinition();
37854 }
37855
37856
37857
37858
37859
37860
37861
37862
37863
37864
37865
37866
37867
37868 public function addArgument($name, $mode = null, $description = '', $default = null)
37869 {
37870 $this->definition->addArgument(new InputArgument($name, $mode, $description, $default));
37871
37872 return $this;
37873 }
37874
37875
37876
37877
37878
37879
37880
37881
37882
37883
37884
37885
37886
37887
37888 public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null)
37889 {
37890 $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default));
37891
37892 return $this;
37893 }
37894
37895
37896
37897
37898
37899
37900
37901
37902
37903
37904
37905
37906
37907
37908
37909
37910
37911 public function setName($name)
37912 {
37913 $this->validateName($name);
37914
37915 $this->name = $name;
37916
37917 return $this;
37918 }
37919
37920
37921
37922
37923
37924
37925
37926
37927
37928
37929
37930
37931
37932 public function setProcessTitle($title)
37933 {
37934 $this->processTitle = $title;
37935
37936 return $this;
37937 }
37938
37939
37940
37941
37942
37943
37944
37945
37946 public function getName()
37947 {
37948 return $this->name;
37949 }
37950
37951
37952
37953
37954
37955
37956
37957
37958
37959
37960 public function setDescription($description)
37961 {
37962 $this->description = $description;
37963
37964 return $this;
37965 }
37966
37967
37968
37969
37970
37971
37972
37973
37974 public function getDescription()
37975 {
37976 return $this->description;
37977 }
37978
37979
37980
37981
37982
37983
37984
37985
37986
37987
37988 public function setHelp($help)
37989 {
37990 $this->help = $help;
37991
37992 return $this;
37993 }
37994
37995
37996
37997
37998
37999
38000
38001
38002 public function getHelp()
38003 {
38004 return $this->help;
38005 }
38006
38007
38008
38009
38010
38011
38012
38013 public function getProcessedHelp()
38014 {
38015 $name = $this->name;
38016
38017 $placeholders = array(
38018 '%command.name%',
38019 '%command.full_name%',
38020 );
38021 $replacements = array(
38022 $name,
38023 $_SERVER['PHP_SELF'].' '.$name,
38024 );
38025
38026 return str_replace($placeholders, $replacements, $this->getHelp());
38027 }
38028
38029
38030
38031
38032
38033
38034
38035
38036
38037
38038
38039
38040 public function setAliases($aliases)
38041 {
38042 if (!is_array($aliases) && !$aliases instanceof \Traversable) {
38043 throw new \InvalidArgumentException('$aliases must be an array or an instance of \Traversable');
38044 }
38045
38046 foreach ($aliases as $alias) {
38047 $this->validateName($alias);
38048 }
38049
38050 $this->aliases = $aliases;
38051
38052 return $this;
38053 }
38054
38055
38056
38057
38058
38059
38060
38061
38062 public function getAliases()
38063 {
38064 return $this->aliases;
38065 }
38066
38067
38068
38069
38070
38071
38072 public function getSynopsis()
38073 {
38074 if (null === $this->synopsis) {
38075 $this->synopsis = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis()));
38076 }
38077
38078 return $this->synopsis;
38079 }
38080
38081
38082
38083
38084
38085
38086
38087
38088
38089
38090
38091
38092 public function getHelper($name)
38093 {
38094 return $this->helperSet->get($name);
38095 }
38096
38097
38098
38099
38100
38101
38102
38103
38104 public function asText()
38105 {
38106 $descriptor = new TextDescriptor();
38107 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
38108 $descriptor->describe($output, $this, array('raw_output' => true));
38109
38110 return $output->fetch();
38111 }
38112
38113
38114
38115
38116
38117
38118
38119
38120
38121
38122 public function asXml($asDom = false)
38123 {
38124 $descriptor = new XmlDescriptor();
38125
38126 if ($asDom) {
38127 return $descriptor->getCommandDocument($this);
38128 }
38129
38130 $output = new BufferedOutput();
38131 $descriptor->describe($output, $this);
38132
38133 return $output->fetch();
38134 }
38135
38136
38137
38138
38139
38140
38141
38142
38143
38144
38145 private function validateName($name)
38146 {
38147 if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) {
38148 throw new \InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name));
38149 }
38150 }
38151 }
38152 <?php
38153
38154
38155
38156
38157
38158
38159
38160
38161
38162
38163 namespace Symfony\Component\Console\Command;
38164
38165 use Symfony\Component\Console\Helper\DescriptorHelper;
38166 use Symfony\Component\Console\Input\InputArgument;
38167 use Symfony\Component\Console\Input\InputOption;
38168 use Symfony\Component\Console\Input\InputInterface;
38169 use Symfony\Component\Console\Output\OutputInterface;
38170 use Symfony\Component\Console\Input\InputDefinition;
38171
38172
38173
38174
38175
38176
38177 class ListCommand extends Command
38178 {
38179
38180
38181
38182 protected function configure()
38183 {
38184 $this
38185 ->setName('list')
38186 ->setDefinition($this->createDefinition())
38187 ->setDescription('Lists commands')
38188 ->setHelp(<<<EOF
38189 The <info>%command.name%</info> command lists all commands:
38190
38191   <info>php %command.full_name%</info>
38192
38193 You can also display the commands for a specific namespace:
38194
38195   <info>php %command.full_name% test</info>
38196
38197 You can also output the information in other formats by using the <comment>--format</comment> option:
38198
38199   <info>php %command.full_name% --format=xml</info>
38200
38201 It's also possible to get raw list of commands (useful for embedding command runner):
38202
38203   <info>php %command.full_name% --raw</info>
38204 EOF
38205 )
38206 ;
38207 }
38208
38209
38210
38211
38212 public function getNativeDefinition()
38213 {
38214 return $this->createDefinition();
38215 }
38216
38217
38218
38219
38220 protected function execute(InputInterface $input, OutputInterface $output)
38221 {
38222 if ($input->getOption('xml')) {
38223 $input->setOption('format', 'xml');
38224 }
38225
38226 $helper = new DescriptorHelper();
38227 $helper->describe($output, $this->getApplication(), array(
38228 'format' => $input->getOption('format'),
38229 'raw_text' => $input->getOption('raw'),
38230 'namespace' => $input->getArgument('namespace'),
38231 ));
38232 }
38233
38234
38235
38236
38237 private function createDefinition()
38238 {
38239 return new InputDefinition(array(
38240 new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
38241 new InputOption('xml', null, InputOption::VALUE_NONE, 'To output list as XML'),
38242 new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
38243 new InputOption('format', null, InputOption::VALUE_REQUIRED, 'To output list in other formats', 'txt'),
38244 ));
38245 }
38246 }
38247 <?php
38248
38249
38250
38251
38252
38253
38254
38255
38256
38257
38258 namespace Symfony\Component\Console\Tester;
38259
38260 use Symfony\Component\Console\Application;
38261 use Symfony\Component\Console\Input\ArrayInput;
38262 use Symfony\Component\Console\Input\InputInterface;
38263 use Symfony\Component\Console\Output\OutputInterface;
38264 use Symfony\Component\Console\Output\StreamOutput;
38265
38266
38267
38268
38269
38270
38271
38272
38273
38274
38275
38276 class ApplicationTester
38277 {
38278 private $application;
38279 private $input;
38280 private $output;
38281 private $statusCode;
38282
38283
38284
38285
38286
38287
38288 public function __construct(Application $application)
38289 {
38290 $this->application = $application;
38291 }
38292
38293
38294
38295
38296
38297
38298
38299
38300
38301
38302
38303
38304
38305
38306
38307 public function run(array $input, $options = array())
38308 {
38309 $this->input = new ArrayInput($input);
38310 if (isset($options['interactive'])) {
38311 $this->input->setInteractive($options['interactive']);
38312 }
38313
38314 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
38315 if (isset($options['decorated'])) {
38316 $this->output->setDecorated($options['decorated']);
38317 }
38318 if (isset($options['verbosity'])) {
38319 $this->output->setVerbosity($options['verbosity']);
38320 }
38321
38322 return $this->statusCode = $this->application->run($this->input, $this->output);
38323 }
38324
38325
38326
38327
38328
38329
38330
38331
38332 public function getDisplay($normalize = false)
38333 {
38334 rewind($this->output->getStream());
38335
38336 $display = stream_get_contents($this->output->getStream());
38337
38338 if ($normalize) {
38339 $display = str_replace(PHP_EOL, "\n", $display);
38340 }
38341
38342 return $display;
38343 }
38344
38345
38346
38347
38348
38349
38350 public function getInput()
38351 {
38352 return $this->input;
38353 }
38354
38355
38356
38357
38358
38359
38360 public function getOutput()
38361 {
38362 return $this->output;
38363 }
38364
38365
38366
38367
38368
38369
38370 public function getStatusCode()
38371 {
38372 return $this->statusCode;
38373 }
38374 }
38375 <?php
38376
38377
38378
38379
38380
38381
38382
38383
38384
38385
38386 namespace Symfony\Component\Console\Tester;
38387
38388 use Symfony\Component\Console\Command\Command;
38389 use Symfony\Component\Console\Input\ArrayInput;
38390 use Symfony\Component\Console\Output\StreamOutput;
38391 use Symfony\Component\Console\Input\InputInterface;
38392 use Symfony\Component\Console\Output\OutputInterface;
38393
38394
38395
38396
38397
38398
38399 class CommandTester
38400 {
38401 private $command;
38402 private $input;
38403 private $output;
38404 private $statusCode;
38405
38406
38407
38408
38409
38410
38411 public function __construct(Command $command)
38412 {
38413 $this->command = $command;
38414 }
38415
38416
38417
38418
38419
38420
38421
38422
38423
38424
38425
38426
38427
38428
38429
38430 public function execute(array $input, array $options = array())
38431 {
38432
38433  
38434  if (!isset($input['command'])
38435 && (null !== $application = $this->command->getApplication())
38436 && $application->getDefinition()->hasArgument('command')
38437 ) {
38438 $input['command'] = $this->command->getName();
38439 }
38440
38441 $this->input = new ArrayInput($input);
38442 if (isset($options['interactive'])) {
38443 $this->input->setInteractive($options['interactive']);
38444 }
38445
38446 $this->output = new StreamOutput(fopen('php://memory', 'w', false));
38447 if (isset($options['decorated'])) {
38448 $this->output->setDecorated($options['decorated']);
38449 }
38450 if (isset($options['verbosity'])) {
38451 $this->output->setVerbosity($options['verbosity']);
38452 }
38453
38454 return $this->statusCode = $this->command->run($this->input, $this->output);
38455 }
38456
38457
38458
38459
38460
38461
38462
38463
38464 public function getDisplay($normalize = false)
38465 {
38466 rewind($this->output->getStream());
38467
38468 $display = stream_get_contents($this->output->getStream());
38469
38470 if ($normalize) {
38471 $display = str_replace(PHP_EOL, "\n", $display);
38472 }
38473
38474 return $display;
38475 }
38476
38477
38478
38479
38480
38481
38482 public function getInput()
38483 {
38484 return $this->input;
38485 }
38486
38487
38488
38489
38490
38491
38492 public function getOutput()
38493 {
38494 return $this->output;
38495 }
38496
38497
38498
38499
38500
38501
38502 public function getStatusCode()
38503 {
38504 return $this->statusCode;
38505 }
38506 }
38507 <?php
38508
38509
38510
38511
38512
38513
38514
38515
38516
38517
38518 namespace Symfony\Component\Console\Formatter;
38519
38520
38521
38522
38523 class OutputFormatterStyleStack
38524 {
38525
38526
38527
38528 private $styles;
38529
38530
38531
38532
38533 private $emptyStyle;
38534
38535
38536
38537
38538
38539
38540 public function __construct(OutputFormatterStyleInterface $emptyStyle = null)
38541 {
38542 $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle();
38543 $this->reset();
38544 }
38545
38546
38547
38548
38549 public function reset()
38550 {
38551 $this->styles = array();
38552 }
38553
38554
38555
38556
38557
38558
38559 public function push(OutputFormatterStyleInterface $style)
38560 {
38561 $this->styles[] = $style;
38562 }
38563
38564
38565
38566
38567
38568
38569
38570
38571
38572
38573 public function pop(OutputFormatterStyleInterface $style = null)
38574 {
38575 if (empty($this->styles)) {
38576 return $this->emptyStyle;
38577 }
38578
38579 if (null === $style) {
38580 return array_pop($this->styles);
38581 }
38582
38583 foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
38584 if ($style->apply('') === $stackedStyle->apply('')) {
38585 $this->styles = array_slice($this->styles, 0, $index);
38586
38587 return $stackedStyle;
38588 }
38589 }
38590
38591 throw new \InvalidArgumentException('Incorrectly nested style tag found.');
38592 }
38593
38594
38595
38596
38597
38598
38599 public function getCurrent()
38600 {
38601 if (empty($this->styles)) {
38602 return $this->emptyStyle;
38603 }
38604
38605 return $this->styles[count($this->styles)-1];
38606 }
38607
38608
38609
38610
38611
38612
38613 public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle)
38614 {
38615 $this->emptyStyle = $emptyStyle;
38616
38617 return $this;
38618 }
38619
38620
38621
38622
38623 public function getEmptyStyle()
38624 {
38625 return $this->emptyStyle;
38626 }
38627 }
38628 <?php
38629
38630
38631
38632
38633
38634
38635
38636
38637
38638
38639 namespace Symfony\Component\Console\Formatter;
38640
38641
38642
38643
38644
38645
38646
38647
38648 class OutputFormatterStyle implements OutputFormatterStyleInterface
38649 {
38650 private static $availableForegroundColors = array(
38651 'black' => array('set' => 30, 'unset' => 39),
38652 'red' => array('set' => 31, 'unset' => 39),
38653 'green' => array('set' => 32, 'unset' => 39),
38654 'yellow' => array('set' => 33, 'unset' => 39),
38655 'blue' => array('set' => 34, 'unset' => 39),
38656 'magenta' => array('set' => 35, 'unset' => 39),
38657 'cyan' => array('set' => 36, 'unset' => 39),
38658 'white' => array('set' => 37, 'unset' => 39),
38659 );
38660 private static $availableBackgroundColors = array(
38661 'black' => array('set' => 40, 'unset' => 49),
38662 'red' => array('set' => 41, 'unset' => 49),
38663 'green' => array('set' => 42, 'unset' => 49),
38664 'yellow' => array('set' => 43, 'unset' => 49),
38665 'blue' => array('set' => 44, 'unset' => 49),
38666 'magenta' => array('set' => 45, 'unset' => 49),
38667 'cyan' => array('set' => 46, 'unset' => 49),
38668 'white' => array('set' => 47, 'unset' => 49),
38669 );
38670 private static $availableOptions = array(
38671 'bold' => array('set' => 1, 'unset' => 22),
38672 'underscore' => array('set' => 4, 'unset' => 24),
38673 'blink' => array('set' => 5, 'unset' => 25),
38674 'reverse' => array('set' => 7, 'unset' => 27),
38675 'conceal' => array('set' => 8, 'unset' => 28),
38676 );
38677
38678 private $foreground;
38679 private $background;
38680 private $options = array();
38681
38682
38683
38684
38685
38686
38687
38688
38689
38690
38691 public function __construct($foreground = null, $background = null, array $options = array())
38692 {
38693 if (null !== $foreground) {
38694 $this->setForeground($foreground);
38695 }
38696 if (null !== $background) {
38697 $this->setBackground($background);
38698 }
38699 if (count($options)) {
38700 $this->setOptions($options);
38701 }
38702 }
38703
38704
38705
38706
38707
38708
38709
38710
38711
38712
38713 public function setForeground($color = null)
38714 {
38715 if (null === $color) {
38716 $this->foreground = null;
38717
38718 return;
38719 }
38720
38721 if (!isset(static::$availableForegroundColors[$color])) {
38722 throw new \InvalidArgumentException(sprintf(
38723 'Invalid foreground color specified: "%s". Expected one of (%s)',
38724 $color,
38725 implode(', ', array_keys(static::$availableForegroundColors))
38726 ));
38727 }
38728
38729 $this->foreground = static::$availableForegroundColors[$color];
38730 }
38731
38732
38733
38734
38735
38736
38737
38738
38739
38740
38741 public function setBackground($color = null)
38742 {
38743 if (null === $color) {
38744 $this->background = null;
38745
38746 return;
38747 }
38748
38749 if (!isset(static::$availableBackgroundColors[$color])) {
38750 throw new \InvalidArgumentException(sprintf(
38751 'Invalid background color specified: "%s". Expected one of (%s)',
38752 $color,
38753 implode(', ', array_keys(static::$availableBackgroundColors))
38754 ));
38755 }
38756
38757 $this->background = static::$availableBackgroundColors[$color];
38758 }
38759
38760
38761
38762
38763
38764
38765
38766
38767
38768
38769 public function setOption($option)
38770 {
38771 if (!isset(static::$availableOptions[$option])) {
38772 throw new \InvalidArgumentException(sprintf(
38773 'Invalid option specified: "%s". Expected one of (%s)',
38774 $option,
38775 implode(', ', array_keys(static::$availableOptions))
38776 ));
38777 }
38778
38779 if (false === array_search(static::$availableOptions[$option], $this->options)) {
38780 $this->options[] = static::$availableOptions[$option];
38781 }
38782 }
38783
38784
38785
38786
38787
38788
38789
38790
38791
38792 public function unsetOption($option)
38793 {
38794 if (!isset(static::$availableOptions[$option])) {
38795 throw new \InvalidArgumentException(sprintf(
38796 'Invalid option specified: "%s". Expected one of (%s)',
38797 $option,
38798 implode(', ', array_keys(static::$availableOptions))
38799 ));
38800 }
38801
38802 $pos = array_search(static::$availableOptions[$option], $this->options);
38803 if (false !== $pos) {
38804 unset($this->options[$pos]);
38805 }
38806 }
38807
38808
38809
38810
38811
38812
38813 public function setOptions(array $options)
38814 {
38815 $this->options = array();
38816
38817 foreach ($options as $option) {
38818 $this->setOption($option);
38819 }
38820 }
38821
38822
38823
38824
38825
38826
38827
38828
38829 public function apply($text)
38830 {
38831 $setCodes = array();
38832 $unsetCodes = array();
38833
38834 if (null !== $this->foreground) {
38835 $setCodes[] = $this->foreground['set'];
38836 $unsetCodes[] = $this->foreground['unset'];
38837 }
38838 if (null !== $this->background) {
38839 $setCodes[] = $this->background['set'];
38840 $unsetCodes[] = $this->background['unset'];
38841 }
38842 if (count($this->options)) {
38843 foreach ($this->options as $option) {
38844 $setCodes[] = $option['set'];
38845 $unsetCodes[] = $option['unset'];
38846 }
38847 }
38848
38849 if (0 === count($setCodes)) {
38850 return $text;
38851 }
38852
38853 return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
38854 }
38855 }
38856 <?php
38857
38858
38859
38860
38861
38862
38863
38864
38865
38866
38867 namespace Symfony\Component\Console\Formatter;
38868
38869
38870
38871
38872
38873
38874
38875
38876 interface OutputFormatterStyleInterface
38877 {
38878
38879
38880
38881
38882
38883
38884
38885 public function setForeground($color = null);
38886
38887
38888
38889
38890
38891
38892
38893
38894 public function setBackground($color = null);
38895
38896
38897
38898
38899
38900
38901
38902
38903 public function setOption($option);
38904
38905
38906
38907
38908
38909
38910 public function unsetOption($option);
38911
38912
38913
38914
38915
38916
38917 public function setOptions(array $options);
38918
38919
38920
38921
38922
38923
38924
38925
38926 public function apply($text);
38927 }
38928 <?php
38929
38930
38931
38932
38933
38934
38935
38936
38937
38938
38939 namespace Symfony\Component\Console\Formatter;
38940
38941
38942
38943
38944
38945
38946
38947
38948 class OutputFormatter implements OutputFormatterInterface
38949 {
38950 private $decorated;
38951 private $styles = array();
38952 private $styleStack;
38953
38954
38955
38956
38957
38958
38959
38960
38961 public static function escape($text)
38962 {
38963 return preg_replace('/([^\\\\]?)</is', '$1\\<', $text);
38964 }
38965
38966
38967
38968
38969
38970
38971
38972
38973
38974 public function __construct($decorated = false, array $styles = array())
38975 {
38976 $this->decorated = (bool) $decorated;
38977
38978 $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
38979 $this->setStyle('info', new OutputFormatterStyle('green'));
38980 $this->setStyle('comment', new OutputFormatterStyle('yellow'));
38981 $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
38982
38983 foreach ($styles as $name => $style) {
38984 $this->setStyle($name, $style);
38985 }
38986
38987 $this->styleStack = new OutputFormatterStyleStack();
38988 }
38989
38990
38991
38992
38993
38994
38995
38996
38997 public function setDecorated($decorated)
38998 {
38999 $this->decorated = (bool) $decorated;
39000 }
39001
39002
39003
39004
39005
39006
39007
39008
39009 public function isDecorated()
39010 {
39011 return $this->decorated;
39012 }
39013
39014
39015
39016
39017
39018
39019
39020
39021
39022 public function setStyle($name, OutputFormatterStyleInterface $style)
39023 {
39024 $this->styles[strtolower($name)] = $style;
39025 }
39026
39027
39028
39029
39030
39031
39032
39033
39034
39035
39036 public function hasStyle($name)
39037 {
39038 return isset($this->styles[strtolower($name)]);
39039 }
39040
39041
39042
39043
39044
39045
39046
39047
39048
39049
39050
39051
39052 public function getStyle($name)
39053 {
39054 if (!$this->hasStyle($name)) {
39055 throw new \InvalidArgumentException(sprintf('Undefined style: %s', $name));
39056 }
39057
39058 return $this->styles[strtolower($name)];
39059 }
39060
39061
39062
39063
39064
39065
39066
39067
39068
39069
39070 public function format($message)
39071 {
39072 $offset = 0;
39073 $output = '';
39074 $tagRegex = '[a-z][a-z0-9_=;-]*';
39075 preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#isx", $message, $matches, PREG_OFFSET_CAPTURE);
39076 foreach ($matches[0] as $i => $match) {
39077 $pos = $match[1];
39078 $text = $match[0];
39079
39080
39081  $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
39082 $offset = $pos + strlen($text);
39083
39084
39085  if ($open = '/' != $text[1]) {
39086 $tag = $matches[1][$i][0];
39087 } else {
39088 $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
39089 }
39090
39091 if (!$open && !$tag) {
39092
39093  $this->styleStack->pop();
39094 } elseif ($pos && '\\' == $message[$pos - 1]) {
39095
39096  $output .= $this->applyCurrentStyle($text);
39097 } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
39098 $output .= $this->applyCurrentStyle($text);
39099 } elseif ($open) {
39100 $this->styleStack->push($style);
39101 } else {
39102 $this->styleStack->pop($style);
39103 }
39104 }
39105
39106 $output .= $this->applyCurrentStyle(substr($message, $offset));
39107
39108 return str_replace('\\<', '<', $output);
39109 }
39110
39111
39112
39113
39114 public function getStyleStack()
39115 {
39116 return $this->styleStack;
39117 }
39118
39119
39120
39121
39122
39123
39124
39125
39126 private function createStyleFromString($string)
39127 {
39128 if (isset($this->styles[$string])) {
39129 return $this->styles[$string];
39130 }
39131
39132 if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
39133 return false;
39134 }
39135
39136 $style = new OutputFormatterStyle();
39137 foreach ($matches as $match) {
39138 array_shift($match);
39139
39140 if ('fg' == $match[0]) {
39141 $style->setForeground($match[1]);
39142 } elseif ('bg' == $match[0]) {
39143 $style->setBackground($match[1]);
39144 } else {
39145 try {
39146 $style->setOption($match[1]);
39147 } catch (\InvalidArgumentException $e) {
39148 return false;
39149 }
39150 }
39151 }
39152
39153 return $style;
39154 }
39155
39156
39157
39158
39159
39160
39161
39162
39163 private function applyCurrentStyle($text)
39164 {
39165 return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
39166 }
39167 }
39168 <?php
39169
39170
39171
39172
39173
39174
39175
39176
39177
39178
39179 namespace Symfony\Component\Console\Formatter;
39180
39181
39182
39183
39184
39185
39186
39187
39188 interface OutputFormatterInterface
39189 {
39190
39191
39192
39193
39194
39195
39196
39197 public function setDecorated($decorated);
39198
39199
39200
39201
39202
39203
39204
39205
39206 public function isDecorated();
39207
39208
39209
39210
39211
39212
39213
39214
39215
39216 public function setStyle($name, OutputFormatterStyleInterface $style);
39217
39218
39219
39220
39221
39222
39223
39224
39225
39226
39227 public function hasStyle($name);
39228
39229
39230
39231
39232
39233
39234
39235
39236
39237
39238 public function getStyle($name);
39239
39240
39241
39242
39243
39244
39245
39246
39247
39248
39249 public function format($message);
39250 }
39251 <?php
39252
39253
39254
39255
39256
39257
39258
39259
39260
39261
39262 namespace Symfony\Component\Console;
39263
39264 use Symfony\Component\Console\Descriptor\TextDescriptor;
39265 use Symfony\Component\Console\Descriptor\XmlDescriptor;
39266 use Symfony\Component\Console\Helper\DebugFormatterHelper;
39267 use Symfony\Component\Console\Helper\ProcessHelper;
39268 use Symfony\Component\Console\Helper\QuestionHelper;
39269 use Symfony\Component\Console\Input\InputInterface;
39270 use Symfony\Component\Console\Input\ArgvInput;
39271 use Symfony\Component\Console\Input\ArrayInput;
39272 use Symfony\Component\Console\Input\InputDefinition;
39273 use Symfony\Component\Console\Input\InputOption;
39274 use Symfony\Component\Console\Input\InputArgument;
39275 use Symfony\Component\Console\Input\InputAwareInterface;
39276 use Symfony\Component\Console\Output\BufferedOutput;
39277 use Symfony\Component\Console\Output\OutputInterface;
39278 use Symfony\Component\Console\Output\ConsoleOutput;
39279 use Symfony\Component\Console\Output\ConsoleOutputInterface;
39280 use Symfony\Component\Console\Command\Command;
39281 use Symfony\Component\Console\Command\HelpCommand;
39282 use Symfony\Component\Console\Command\ListCommand;
39283 use Symfony\Component\Console\Helper\HelperSet;
39284 use Symfony\Component\Console\Helper\FormatterHelper;
39285 use Symfony\Component\Console\Helper\DialogHelper;
39286 use Symfony\Component\Console\Helper\ProgressHelper;
39287 use Symfony\Component\Console\Helper\TableHelper;
39288 use Symfony\Component\Console\Event\ConsoleCommandEvent;
39289 use Symfony\Component\Console\Event\ConsoleExceptionEvent;
39290 use Symfony\Component\Console\Event\ConsoleTerminateEvent;
39291 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
39292
39293
39294
39295
39296
39297
39298
39299
39300
39301
39302
39303
39304
39305
39306
39307
39308
39309
39310 class Application
39311 {
39312 private $commands = array();
39313 private $wantHelps = false;
39314 private $runningCommand;
39315 private $name;
39316 private $version;
39317 private $catchExceptions = true;
39318 private $autoExit = true;
39319 private $definition;
39320 private $helperSet;
39321 private $dispatcher;
39322 private $terminalDimensions;
39323 private $defaultCommand;
39324
39325
39326
39327
39328
39329
39330
39331
39332
39333 public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
39334 {
39335 $this->name = $name;
39336 $this->version = $version;
39337 $this->defaultCommand = 'list';
39338 $this->helperSet = $this->getDefaultHelperSet();
39339 $this->definition = $this->getDefaultInputDefinition();
39340
39341 foreach ($this->getDefaultCommands() as $command) {
39342 $this->add($command);
39343 }
39344 }
39345
39346 public function setDispatcher(EventDispatcherInterface $dispatcher)
39347 {
39348 $this->dispatcher = $dispatcher;
39349 }
39350
39351
39352
39353
39354
39355
39356
39357
39358
39359
39360
39361
39362
39363 public function run(InputInterface $input = null, OutputInterface $output = null)
39364 {
39365 if (null === $input) {
39366 $input = new ArgvInput();
39367 }
39368
39369 if (null === $output) {
39370 $output = new ConsoleOutput();
39371 }
39372
39373 $this->configureIO($input, $output);
39374
39375 try {
39376 $exitCode = $this->doRun($input, $output);
39377 } catch (\Exception $e) {
39378 if (!$this->catchExceptions) {
39379 throw $e;
39380 }
39381
39382 if ($output instanceof ConsoleOutputInterface) {
39383 $this->renderException($e, $output->getErrorOutput());
39384 } else {
39385 $this->renderException($e, $output);
39386 }
39387
39388 $exitCode = $e->getCode();
39389 if (is_numeric($exitCode)) {
39390 $exitCode = (int) $exitCode;
39391 if (0 === $exitCode) {
39392 $exitCode = 1;
39393 }
39394 } else {
39395 $exitCode = 1;
39396 }
39397 }
39398
39399 if ($this->autoExit) {
39400 if ($exitCode > 255) {
39401 $exitCode = 255;
39402 }
39403
39404 exit($exitCode);
39405 }
39406
39407 return $exitCode;
39408 }
39409
39410
39411
39412
39413
39414
39415
39416
39417
39418 public function doRun(InputInterface $input, OutputInterface $output)
39419 {
39420 if (true === $input->hasParameterOption(array('--version', '-V'))) {
39421 $output->writeln($this->getLongVersion());
39422
39423 return 0;
39424 }
39425
39426 $name = $this->getCommandName($input);
39427 if (true === $input->hasParameterOption(array('--help', '-h'))) {
39428 if (!$name) {
39429 $name = 'help';
39430 $input = new ArrayInput(array('command' => 'help'));
39431 } else {
39432 $this->wantHelps = true;
39433 }
39434 }
39435
39436 if (!$name) {
39437 $name = $this->defaultCommand;
39438 $input = new ArrayInput(array('command' => $this->defaultCommand));
39439 }
39440
39441
39442  $command = $this->find($name);
39443
39444 $this->runningCommand = $command;
39445 $exitCode = $this->doRunCommand($command, $input, $output);
39446 $this->runningCommand = null;
39447
39448 return $exitCode;
39449 }
39450
39451
39452
39453
39454
39455
39456
39457
39458 public function setHelperSet(HelperSet $helperSet)
39459 {
39460 $this->helperSet = $helperSet;
39461 }
39462
39463
39464
39465
39466
39467
39468
39469
39470 public function getHelperSet()
39471 {
39472 return $this->helperSet;
39473 }
39474
39475
39476
39477
39478
39479
39480
39481
39482 public function setDefinition(InputDefinition $definition)
39483 {
39484 $this->definition = $definition;
39485 }
39486
39487
39488
39489
39490
39491
39492 public function getDefinition()
39493 {
39494 return $this->definition;
39495 }
39496
39497
39498
39499
39500
39501
39502 public function getHelp()
39503 {
39504 return $this->getLongVersion();
39505 }
39506
39507
39508
39509
39510
39511
39512
39513
39514 public function setCatchExceptions($boolean)
39515 {
39516 $this->catchExceptions = (bool) $boolean;
39517 }
39518
39519
39520
39521
39522
39523
39524
39525
39526 public function setAutoExit($boolean)
39527 {
39528 $this->autoExit = (bool) $boolean;
39529 }
39530
39531
39532
39533
39534
39535
39536
39537
39538 public function getName()
39539 {
39540 return $this->name;
39541 }
39542
39543
39544
39545
39546
39547
39548
39549
39550 public function setName($name)
39551 {
39552 $this->name = $name;
39553 }
39554
39555
39556
39557
39558
39559
39560
39561
39562 public function getVersion()
39563 {
39564 return $this->version;
39565 }
39566
39567
39568
39569
39570
39571
39572
39573
39574 public function setVersion($version)
39575 {
39576 $this->version = $version;
39577 }
39578
39579
39580
39581
39582
39583
39584
39585
39586 public function getLongVersion()
39587 {
39588 if ('UNKNOWN' !== $this->getName() && 'UNKNOWN' !== $this->getVersion()) {
39589 return sprintf('<info>%s</info> version <comment>%s</comment>', $this->getName(), $this->getVersion());
39590 }
39591
39592 return '<info>Console Tool</info>';
39593 }
39594
39595
39596
39597
39598
39599
39600
39601
39602
39603
39604 public function register($name)
39605 {
39606 return $this->add(new Command($name));
39607 }
39608
39609
39610
39611
39612
39613
39614
39615
39616 public function addCommands(array $commands)
39617 {
39618 foreach ($commands as $command) {
39619 $this->add($command);
39620 }
39621 }
39622
39623
39624
39625
39626
39627
39628
39629
39630
39631
39632
39633
39634 public function add(Command $command)
39635 {
39636 $command->setApplication($this);
39637
39638 if (!$command->isEnabled()) {
39639 $command->setApplication(null);
39640
39641 return;
39642 }
39643
39644 if (null === $command->getDefinition()) {
39645 throw new \LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', get_class($command)));
39646 }
39647
39648 $this->commands[$command->getName()] = $command;
39649
39650 foreach ($command->getAliases() as $alias) {
39651 $this->commands[$alias] = $command;
39652 }
39653
39654 return $command;
39655 }
39656
39657
39658
39659
39660
39661
39662
39663
39664
39665
39666
39667
39668 public function get($name)
39669 {
39670 if (!isset($this->commands[$name])) {
39671 throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
39672 }
39673
39674 $command = $this->commands[$name];
39675
39676 if ($this->wantHelps) {
39677 $this->wantHelps = false;
39678
39679 $helpCommand = $this->get('help');
39680 $helpCommand->setCommand($command);
39681
39682 return $helpCommand;
39683 }
39684
39685 return $command;
39686 }
39687
39688
39689
39690
39691
39692
39693
39694
39695
39696
39697 public function has($name)
39698 {
39699 return isset($this->commands[$name]);
39700 }
39701
39702
39703
39704
39705
39706
39707
39708
39709 public function getNamespaces()
39710 {
39711 $namespaces = array();
39712 foreach ($this->commands as $command) {
39713 $namespaces[] = $this->extractNamespace($command->getName());
39714
39715 foreach ($command->getAliases() as $alias) {
39716 $namespaces[] = $this->extractNamespace($alias);
39717 }
39718 }
39719
39720 return array_values(array_unique(array_filter($namespaces)));
39721 }
39722
39723
39724
39725
39726
39727
39728
39729
39730
39731
39732 public function findNamespace($namespace)
39733 {
39734 $allNamespaces = $this->getNamespaces();
39735 $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $namespace);
39736 $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces);
39737
39738 if (empty($namespaces)) {
39739 $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);
39740
39741 if ($alternatives = $this->findAlternatives($namespace, $allNamespaces, array())) {
39742 if (1 == count($alternatives)) {
39743 $message .= "\n\nDid you mean this?\n    ";
39744 } else {
39745 $message .= "\n\nDid you mean one of these?\n    ";
39746 }
39747
39748 $message .= implode("\n    ", $alternatives);
39749 }
39750
39751 throw new \InvalidArgumentException($message);
39752 }
39753
39754 $exact = in_array($namespace, $namespaces, true);
39755 if (count($namespaces) > 1 && !$exact) {
39756 throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))));
39757 }
39758
39759 return $exact ? $namespace : reset($namespaces);
39760 }
39761
39762
39763
39764
39765
39766
39767
39768
39769
39770
39771
39772
39773
39774
39775
39776 public function find($name)
39777 {
39778 $allCommands = array_keys($this->commands);
39779 $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
39780 $commands = preg_grep('{^'.$expr.'}', $allCommands);
39781
39782 if (empty($commands) || count(preg_grep('{^'.$expr.'$}', $commands)) < 1) {
39783 if (false !== $pos = strrpos($name, ':')) {
39784
39785  $this->findNamespace(substr($name, 0, $pos));
39786 }
39787
39788 $message = sprintf('Command "%s" is not defined.', $name);
39789
39790 if ($alternatives = $this->findAlternatives($name, $allCommands, array())) {
39791 if (1 == count($alternatives)) {
39792 $message .= "\n\nDid you mean this?\n    ";
39793 } else {
39794 $message .= "\n\nDid you mean one of these?\n    ";
39795 }
39796 $message .= implode("\n    ", $alternatives);
39797 }
39798
39799 throw new \InvalidArgumentException($message);
39800 }
39801
39802
39803  if (count($commands) > 1) {
39804 $commandList = $this->commands;
39805 $commands = array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
39806 $commandName = $commandList[$nameOrAlias]->getName();
39807
39808 return $commandName === $nameOrAlias || !in_array($commandName, $commands);
39809 });
39810 }
39811
39812 $exact = in_array($name, $commands, true);
39813 if (count($commands) > 1 && !$exact) {
39814 $suggestions = $this->getAbbreviationSuggestions(array_values($commands));
39815
39816 throw new \InvalidArgumentException(sprintf('Command "%s" is ambiguous (%s).', $name, $suggestions));
39817 }
39818
39819 return $this->get($exact ? $name : reset($commands));
39820 }
39821
39822
39823
39824
39825
39826
39827
39828
39829
39830
39831
39832
39833 public function all($namespace = null)
39834 {
39835 if (null === $namespace) {
39836 return $this->commands;
39837 }
39838
39839 $commands = array();
39840 foreach ($this->commands as $name => $command) {
39841 if ($namespace === $this->extractNamespace($name, substr_count($namespace, ':') + 1)) {
39842 $commands[$name] = $command;
39843 }
39844 }
39845
39846 return $commands;
39847 }
39848
39849
39850
39851
39852
39853
39854
39855
39856 public static function getAbbreviations($names)
39857 {
39858 $abbrevs = array();
39859 foreach ($names as $name) {
39860 for ($len = strlen($name); $len > 0; --$len) {
39861 $abbrev = substr($name, 0, $len);
39862 $abbrevs[$abbrev][] = $name;
39863 }
39864 }
39865
39866 return $abbrevs;
39867 }
39868
39869
39870
39871
39872
39873
39874
39875
39876
39877
39878
39879 public function asText($namespace = null, $raw = false)
39880 {
39881 $descriptor = new TextDescriptor();
39882 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, !$raw);
39883 $descriptor->describe($output, $this, array('namespace' => $namespace, 'raw_output' => true));
39884
39885 return $output->fetch();
39886 }
39887
39888
39889
39890
39891
39892
39893
39894
39895
39896
39897
39898 public function asXml($namespace = null, $asDom = false)
39899 {
39900 $descriptor = new XmlDescriptor();
39901
39902 if ($asDom) {
39903 return $descriptor->getApplicationDocument($this, $namespace);
39904 }
39905
39906 $output = new BufferedOutput();
39907 $descriptor->describe($output, $this, array('namespace' => $namespace));
39908
39909 return $output->fetch();
39910 }
39911
39912
39913
39914
39915
39916
39917
39918 public function renderException($e, $output)
39919 {
39920 do {
39921 $title = sprintf('  [%s]  ', get_class($e));
39922
39923 $len = $this->stringWidth($title);
39924
39925 $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
39926
39927  if (defined('HHVM_VERSION') && $width > 1 << 31) {
39928 $width = 1 << 31;
39929 }
39930 $formatter = $output->getFormatter();
39931 $lines = array();
39932 foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) {
39933 foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
39934
39935  $lineLength = $this->stringWidth(preg_replace('/\e\[[^m]*m/', '', $formatter->format($line))) + 4;
39936 $lines[] = array($line, $lineLength);
39937
39938 $len = max($lineLength, $len);
39939 }
39940 }
39941
39942 $messages = array('', '');
39943 $messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len)));
39944 $messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))));
39945 foreach ($lines as $line) {
39946 $messages[] = $formatter->format(sprintf('<error>  %s  %s</error>', $line[0], str_repeat(' ', $len - $line[1])));
39947 }
39948 $messages[] = $emptyLine;
39949 $messages[] = '';
39950 $messages[] = '';
39951
39952 $output->writeln($messages, OutputInterface::OUTPUT_RAW);
39953
39954 if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
39955 $output->writeln('<comment>Exception trace:</comment>');
39956
39957
39958  $trace = $e->getTrace();
39959 array_unshift($trace, array(
39960 'function' => '',
39961 'file' => $e->getFile() != null ? $e->getFile() : 'n/a',
39962 'line' => $e->getLine() != null ? $e->getLine() : 'n/a',
39963 'args' => array(),
39964 ));
39965
39966 for ($i = 0, $count = count($trace); $i < $count; $i++) {
39967 $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : '';
39968 $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : '';
39969 $function = $trace[$i]['function'];
39970 $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a';
39971 $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a';
39972
39973 $output->writeln(sprintf(' %s%s%s() at <info>%s:%s</info>', $class, $type, $function, $file, $line));
39974 }
39975
39976 $output->writeln("");
39977 $output->writeln("");
39978 }
39979 } while ($e = $e->getPrevious());
39980
39981 if (null !== $this->runningCommand) {
39982 $output->writeln(sprintf('<info>%s</info>', sprintf($this->runningCommand->getSynopsis(), $this->getName())));
39983 $output->writeln("");
39984 $output->writeln("");
39985 }
39986 }
39987
39988
39989
39990
39991
39992
39993 protected function getTerminalWidth()
39994 {
39995 $dimensions = $this->getTerminalDimensions();
39996
39997 return $dimensions[0];
39998 }
39999
40000
40001
40002
40003
40004
40005 protected function getTerminalHeight()
40006 {
40007 $dimensions = $this->getTerminalDimensions();
40008
40009 return $dimensions[1];
40010 }
40011
40012
40013
40014
40015
40016
40017 public function getTerminalDimensions()
40018 {
40019 if ($this->terminalDimensions) {
40020 return $this->terminalDimensions;
40021 }
40022
40023 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
40024
40025  if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
40026 return array((int) $matches[1], (int) $matches[2]);
40027 }
40028
40029  if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) {
40030 return array((int) $matches[1], (int) $matches[2]);
40031 }
40032 }
40033
40034 if ($sttyString = $this->getSttyColumns()) {
40035
40036  if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
40037 return array((int) $matches[2], (int) $matches[1]);
40038 }
40039
40040  if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
40041 return array((int) $matches[2], (int) $matches[1]);
40042 }
40043 }
40044
40045 return array(null, null);
40046 }
40047
40048
40049
40050
40051
40052
40053
40054
40055
40056
40057
40058 public function setTerminalDimensions($width, $height)
40059 {
40060 $this->terminalDimensions = array($width, $height);
40061
40062 return $this;
40063 }
40064
40065
40066
40067
40068
40069
40070
40071 protected function configureIO(InputInterface $input, OutputInterface $output)
40072 {
40073 if (true === $input->hasParameterOption(array('--ansi'))) {
40074 $output->setDecorated(true);
40075 } elseif (true === $input->hasParameterOption(array('--no-ansi'))) {
40076 $output->setDecorated(false);
40077 }
40078
40079 if (true === $input->hasParameterOption(array('--no-interaction', '-n'))) {
40080 $input->setInteractive(false);
40081 } elseif (function_exists('posix_isatty') && $this->getHelperSet()->has('question')) {
40082 $inputStream = $this->getHelperSet()->get('question')->getInputStream();
40083 if (!@posix_isatty($inputStream)) {
40084 $input->setInteractive(false);
40085 }
40086 }
40087
40088 if (true === $input->hasParameterOption(array('--quiet', '-q'))) {
40089 $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
40090 } else {
40091 if ($input->hasParameterOption('-vvv') || $input->hasParameterOption('--verbose=3') || $input->getParameterOption('--verbose') === 3) {
40092 $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG);
40093 } elseif ($input->hasParameterOption('-vv') || $input->hasParameterOption('--verbose=2') || $input->getParameterOption('--verbose') === 2) {
40094 $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE);
40095 } elseif ($input->hasParameterOption('-v') || $input->hasParameterOption('--verbose=1') || $input->hasParameterOption('--verbose') || $input->getParameterOption('--verbose')) {
40096 $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
40097 }
40098 }
40099 }
40100
40101
40102
40103
40104
40105
40106
40107
40108
40109
40110
40111
40112
40113
40114
40115 protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output)
40116 {
40117 foreach ($command->getHelperSet() as $helper) {
40118 if ($helper instanceof InputAwareInterface) {
40119 $helper->setInput($input);
40120 }
40121 }
40122
40123 if (null === $this->dispatcher) {
40124 return $command->run($input, $output);
40125 }
40126
40127 $event = new ConsoleCommandEvent($command, $input, $output);
40128 $this->dispatcher->dispatch(ConsoleEvents::COMMAND, $event);
40129
40130 if ($event->commandShouldRun()) {
40131 try {
40132 $exitCode = $command->run($input, $output);
40133 } catch (\Exception $e) {
40134 $event = new ConsoleTerminateEvent($command, $input, $output, $e->getCode());
40135 $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
40136
40137 $event = new ConsoleExceptionEvent($command, $input, $output, $e, $event->getExitCode());
40138 $this->dispatcher->dispatch(ConsoleEvents::EXCEPTION, $event);
40139
40140 throw $event->getException();
40141 }
40142 } else {
40143 $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED;
40144 }
40145
40146 $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
40147 $this->dispatcher->dispatch(ConsoleEvents::TERMINATE, $event);
40148
40149 return $event->getExitCode();
40150 }
40151
40152
40153
40154
40155
40156
40157
40158
40159 protected function getCommandName(InputInterface $input)
40160 {
40161 return $input->getFirstArgument();
40162 }
40163
40164
40165
40166
40167
40168
40169 protected function getDefaultInputDefinition()
40170 {
40171 return new InputDefinition(array(
40172 new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
40173
40174 new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display this help message.'),
40175 new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message.'),
40176 new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug.'),
40177 new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version.'),
40178 new InputOption('--ansi', '', InputOption::VALUE_NONE, 'Force ANSI output.'),
40179 new InputOption('--no-ansi', '', InputOption::VALUE_NONE, 'Disable ANSI output.'),
40180 new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question.'),
40181 ));
40182 }
40183
40184
40185
40186
40187
40188
40189 protected function getDefaultCommands()
40190 {
40191 return array(new HelpCommand(), new ListCommand());
40192 }
40193
40194
40195
40196
40197
40198
40199 protected function getDefaultHelperSet()
40200 {
40201 return new HelperSet(array(
40202 new FormatterHelper(),
40203 new DialogHelper(),
40204 new ProgressHelper(),
40205 new TableHelper(),
40206 new DebugFormatterHelper(),
40207 new ProcessHelper(),
40208 new QuestionHelper(),
40209 ));
40210 }
40211
40212
40213
40214
40215
40216
40217 private function getSttyColumns()
40218 {
40219 if (!function_exists('proc_open')) {
40220 return;
40221 }
40222
40223 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
40224 $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
40225 if (is_resource($process)) {
40226 $info = stream_get_contents($pipes[1]);
40227 fclose($pipes[1]);
40228 fclose($pipes[2]);
40229 proc_close($process);
40230
40231 return $info;
40232 }
40233 }
40234
40235
40236
40237
40238
40239
40240 private function getConsoleMode()
40241 {
40242 if (!function_exists('proc_open')) {
40243 return;
40244 }
40245
40246 $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
40247 $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
40248 if (is_resource($process)) {
40249 $info = stream_get_contents($pipes[1]);
40250 fclose($pipes[1]);
40251 fclose($pipes[2]);
40252 proc_close($process);
40253
40254 if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
40255 return $matches[2].'x'.$matches[1];
40256 }
40257 }
40258 }
40259
40260
40261
40262
40263
40264
40265
40266
40267 private function getAbbreviationSuggestions($abbrevs)
40268 {
40269 return sprintf('%s, %s%s', $abbrevs[0], $abbrevs[1], count($abbrevs) > 2 ? sprintf(' and %d more', count($abbrevs) - 2) : '');
40270 }
40271
40272
40273
40274
40275
40276
40277
40278
40279
40280
40281
40282 public function extractNamespace($name, $limit = null)
40283 {
40284 $parts = explode(':', $name);
40285 array_pop($parts);
40286
40287 return implode(':', null === $limit ? $parts : array_slice($parts, 0, $limit));
40288 }
40289
40290
40291
40292
40293
40294
40295
40296
40297
40298
40299 private function findAlternatives($name, $collection)
40300 {
40301 $threshold = 1e3;
40302 $alternatives = array();
40303
40304 $collectionParts = array();
40305 foreach ($collection as $item) {
40306 $collectionParts[$item] = explode(':', $item);
40307 }
40308
40309 foreach (explode(':', $name) as $i => $subname) {
40310 foreach ($collectionParts as $collectionName => $parts) {
40311 $exists = isset($alternatives[$collectionName]);
40312 if (!isset($parts[$i]) && $exists) {
40313 $alternatives[$collectionName] += $threshold;
40314 continue;
40315 } elseif (!isset($parts[$i])) {
40316 continue;
40317 }
40318
40319 $lev = levenshtein($subname, $parts[$i]);
40320 if ($lev <= strlen($subname) / 3 || '' !== $subname && false !== strpos($parts[$i], $subname)) {
40321 $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev;
40322 } elseif ($exists) {
40323 $alternatives[$collectionName] += $threshold;
40324 }
40325 }
40326 }
40327
40328 foreach ($collection as $item) {
40329 $lev = levenshtein($name, $item);
40330 if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
40331 $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev;
40332 }
40333 }
40334
40335 $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2*$threshold; });
40336 asort($alternatives);
40337
40338 return array_keys($alternatives);
40339 }
40340
40341
40342
40343
40344
40345
40346 public function setDefaultCommand($commandName)
40347 {
40348 $this->defaultCommand = $commandName;
40349 }
40350
40351 private function stringWidth($string)
40352 {
40353 if (!function_exists('mb_strwidth')) {
40354 return strlen($string);
40355 }
40356
40357 if (false === $encoding = mb_detect_encoding($string)) {
40358 return strlen($string);
40359 }
40360
40361 return mb_strwidth($string, $encoding);
40362 }
40363
40364 private function splitStringByWidth($string, $width)
40365 {
40366
40367  
40368  
40369
40370 if (!function_exists('mb_strwidth')) {
40371 return str_split($string, $width);
40372 }
40373
40374 if (false === $encoding = mb_detect_encoding($string)) {
40375 return str_split($string, $width);
40376 }
40377
40378 $utf8String = mb_convert_encoding($string, 'utf8', $encoding);
40379 $lines = array();
40380 $line = '';
40381 foreach (preg_split('//u', $utf8String) as $char) {
40382
40383  if (mb_strwidth($line.$char, 'utf8') <= $width) {
40384 $line .= $char;
40385 continue;
40386 }
40387
40388  $lines[] = str_pad($line, $width);
40389 $line = $char;
40390 }
40391 if (strlen($line)) {
40392 $lines[] = count($lines) ? str_pad($line, $width) : $line;
40393 }
40394
40395 mb_convert_variables($encoding, 'utf8', $lines);
40396
40397 return $lines;
40398 }
40399 }
40400 <?php
40401
40402
40403
40404
40405
40406
40407
40408
40409
40410
40411 namespace Symfony\Component\Console\Input;
40412
40413
40414
40415
40416
40417
40418
40419
40420 class InputArgument
40421 {
40422 const REQUIRED = 1;
40423 const OPTIONAL = 2;
40424 const IS_ARRAY = 4;
40425
40426 private $name;
40427 private $mode;
40428 private $default;
40429 private $description;
40430
40431
40432
40433
40434
40435
40436
40437
40438
40439
40440
40441
40442
40443 public function __construct($name, $mode = null, $description = '', $default = null)
40444 {
40445 if (null === $mode) {
40446 $mode = self::OPTIONAL;
40447 } elseif (!is_int($mode) || $mode > 7 || $mode < 1) {
40448 throw new \InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode));
40449 }
40450
40451 $this->name = $name;
40452 $this->mode = $mode;
40453 $this->description = $description;
40454
40455 $this->setDefault($default);
40456 }
40457
40458
40459
40460
40461
40462
40463 public function getName()
40464 {
40465 return $this->name;
40466 }
40467
40468
40469
40470
40471
40472
40473 public function isRequired()
40474 {
40475 return self::REQUIRED === (self::REQUIRED & $this->mode);
40476 }
40477
40478
40479
40480
40481
40482
40483 public function isArray()
40484 {
40485 return self::IS_ARRAY === (self::IS_ARRAY & $this->mode);
40486 }
40487
40488
40489
40490
40491
40492
40493
40494
40495 public function setDefault($default = null)
40496 {
40497 if (self::REQUIRED === $this->mode && null !== $default) {
40498 throw new \LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
40499 }
40500
40501 if ($this->isArray()) {
40502 if (null === $default) {
40503 $default = array();
40504 } elseif (!is_array($default)) {
40505 throw new \LogicException('A default value for an array argument must be an array.');
40506 }
40507 }
40508
40509 $this->default = $default;
40510 }
40511
40512
40513
40514
40515
40516
40517 public function getDefault()
40518 {
40519 return $this->default;
40520 }
40521
40522
40523
40524
40525
40526
40527 public function getDescription()
40528 {
40529 return $this->description;
40530 }
40531 }
40532 <?php
40533
40534
40535
40536
40537
40538
40539
40540
40541
40542
40543 namespace Symfony\Component\Console\Input;
40544
40545
40546
40547
40548
40549
40550
40551
40552
40553
40554
40555
40556 abstract class Input implements InputInterface
40557 {
40558
40559
40560
40561 protected $definition;
40562 protected $options = array();
40563 protected $arguments = array();
40564 protected $interactive = true;
40565
40566
40567
40568
40569
40570
40571 public function __construct(InputDefinition $definition = null)
40572 {
40573 if (null === $definition) {
40574 $this->definition = new InputDefinition();
40575 } else {
40576 $this->bind($definition);
40577 $this->validate();
40578 }
40579 }
40580
40581
40582
40583
40584
40585
40586 public function bind(InputDefinition $definition)
40587 {
40588 $this->arguments = array();
40589 $this->options = array();
40590 $this->definition = $definition;
40591
40592 $this->parse();
40593 }
40594
40595
40596
40597
40598 abstract protected function parse();
40599
40600
40601
40602
40603
40604
40605 public function validate()
40606 {
40607 if (count($this->arguments) < $this->definition->getArgumentRequiredCount()) {
40608 throw new \RuntimeException('Not enough arguments.');
40609 }
40610 }
40611
40612
40613
40614
40615
40616
40617 public function isInteractive()
40618 {
40619 return $this->interactive;
40620 }
40621
40622
40623
40624
40625
40626
40627 public function setInteractive($interactive)
40628 {
40629 $this->interactive = (bool) $interactive;
40630 }
40631
40632
40633
40634
40635
40636
40637 public function getArguments()
40638 {
40639 return array_merge($this->definition->getArgumentDefaults(), $this->arguments);
40640 }
40641
40642
40643
40644
40645
40646
40647
40648
40649
40650
40651 public function getArgument($name)
40652 {
40653 if (!$this->definition->hasArgument($name)) {
40654 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
40655 }
40656
40657 return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault();
40658 }
40659
40660
40661
40662
40663
40664
40665
40666
40667
40668 public function setArgument($name, $value)
40669 {
40670 if (!$this->definition->hasArgument($name)) {
40671 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
40672 }
40673
40674 $this->arguments[$name] = $value;
40675 }
40676
40677
40678
40679
40680
40681
40682
40683
40684 public function hasArgument($name)
40685 {
40686 return $this->definition->hasArgument($name);
40687 }
40688
40689
40690
40691
40692
40693
40694 public function getOptions()
40695 {
40696 return array_merge($this->definition->getOptionDefaults(), $this->options);
40697 }
40698
40699
40700
40701
40702
40703
40704
40705
40706
40707
40708 public function getOption($name)
40709 {
40710 if (!$this->definition->hasOption($name)) {
40711 throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
40712 }
40713
40714 return isset($this->options[$name]) ? $this->options[$name] : $this->definition->getOption($name)->getDefault();
40715 }
40716
40717
40718
40719
40720
40721
40722
40723
40724
40725 public function setOption($name, $value)
40726 {
40727 if (!$this->definition->hasOption($name)) {
40728 throw new \InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
40729 }
40730
40731 $this->options[$name] = $value;
40732 }
40733
40734
40735
40736
40737
40738
40739
40740
40741 public function hasOption($name)
40742 {
40743 return $this->definition->hasOption($name);
40744 }
40745
40746
40747
40748
40749
40750
40751
40752
40753 public function escapeToken($token)
40754 {
40755 return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
40756 }
40757 }
40758 <?php
40759
40760
40761
40762
40763
40764
40765
40766
40767
40768
40769 namespace Symfony\Component\Console\Input;
40770
40771
40772
40773
40774
40775
40776
40777
40778
40779
40780
40781
40782 class StringInput extends ArgvInput
40783 {
40784 const REGEX_STRING = '([^\s]+?)(?:\s|(?<!\\\\)"|(?<!\\\\)\'|$)';
40785 const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\')';
40786
40787
40788
40789
40790
40791
40792
40793
40794
40795
40796
40797 public function __construct($input, InputDefinition $definition = null)
40798 {
40799 parent::__construct(array(), null);
40800
40801 $this->setTokens($this->tokenize($input));
40802
40803 if (null !== $definition) {
40804 $this->bind($definition);
40805 }
40806 }
40807
40808
40809
40810
40811
40812
40813
40814
40815
40816
40817 private function tokenize($input)
40818 {
40819 $tokens = array();
40820 $length = strlen($input);
40821 $cursor = 0;
40822 while ($cursor < $length) {
40823 if (preg_match('/\s+/A', $input, $match, null, $cursor)) {
40824 } elseif (preg_match('/([^="\'\s]+?)(=?)('.self::REGEX_QUOTED_STRING.'+)/A', $input, $match, null, $cursor)) {
40825 $tokens[] = $match[1].$match[2].stripcslashes(str_replace(array('"\'', '\'"', '\'\'', '""'), '', substr($match[3], 1, strlen($match[3]) - 2)));
40826 } elseif (preg_match('/'.self::REGEX_QUOTED_STRING.'/A', $input, $match, null, $cursor)) {
40827 $tokens[] = stripcslashes(substr($match[0], 1, strlen($match[0]) - 2));
40828 } elseif (preg_match('/'.self::REGEX_STRING.'/A', $input, $match, null, $cursor)) {
40829 $tokens[] = stripcslashes($match[1]);
40830 } else {
40831
40832  throw new \InvalidArgumentException(sprintf('Unable to parse input near "... %s ..."', substr($input, $cursor, 10)));
40833 }
40834
40835 $cursor += strlen($match[0]);
40836 }
40837
40838 return $tokens;
40839 }
40840 }
40841 <?php
40842
40843
40844
40845
40846
40847
40848
40849
40850
40851
40852 namespace Symfony\Component\Console\Input;
40853
40854
40855
40856
40857
40858
40859
40860
40861 class InputOption
40862 {
40863 const VALUE_NONE = 1;
40864 const VALUE_REQUIRED = 2;
40865 const VALUE_OPTIONAL = 4;
40866 const VALUE_IS_ARRAY = 8;
40867
40868 private $name;
40869 private $shortcut;
40870 private $mode;
40871 private $default;
40872 private $description;
40873
40874
40875
40876
40877
40878
40879
40880
40881
40882
40883
40884
40885
40886
40887 public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null)
40888 {
40889 if (0 === strpos($name, '--')) {
40890 $name = substr($name, 2);
40891 }
40892
40893 if (empty($name)) {
40894 throw new \InvalidArgumentException('An option name cannot be empty.');
40895 }
40896
40897 if (empty($shortcut)) {
40898 $shortcut = null;
40899 }
40900
40901 if (null !== $shortcut) {
40902 if (is_array($shortcut)) {
40903 $shortcut = implode('|', $shortcut);
40904 }
40905 $shortcuts = preg_split('{(\|)-?}', ltrim($shortcut, '-'));
40906 $shortcuts = array_filter($shortcuts);
40907 $shortcut = implode('|', $shortcuts);
40908
40909 if (empty($shortcut)) {
40910 throw new \InvalidArgumentException('An option shortcut cannot be empty.');
40911 }
40912 }
40913
40914 if (null === $mode) {
40915 $mode = self::VALUE_NONE;
40916 } elseif (!is_int($mode) || $mode > 15 || $mode < 1) {
40917 throw new \InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
40918 }
40919
40920 $this->name = $name;
40921 $this->shortcut = $shortcut;
40922 $this->mode = $mode;
40923 $this->description = $description;
40924
40925 if ($this->isArray() && !$this->acceptValue()) {
40926 throw new \InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
40927 }
40928
40929 $this->setDefault($default);
40930 }
40931
40932
40933
40934
40935
40936
40937 public function getShortcut()
40938 {
40939 return $this->shortcut;
40940 }
40941
40942
40943
40944
40945
40946
40947 public function getName()
40948 {
40949 return $this->name;
40950 }
40951
40952
40953
40954
40955
40956
40957 public function acceptValue()
40958 {
40959 return $this->isValueRequired() || $this->isValueOptional();
40960 }
40961
40962
40963
40964
40965
40966
40967 public function isValueRequired()
40968 {
40969 return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode);
40970 }
40971
40972
40973
40974
40975
40976
40977 public function isValueOptional()
40978 {
40979 return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode);
40980 }
40981
40982
40983
40984
40985
40986
40987 public function isArray()
40988 {
40989 return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
40990 }
40991
40992
40993
40994
40995
40996
40997
40998
40999 public function setDefault($default = null)
41000 {
41001 if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) {
41002 throw new \LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.');
41003 }
41004
41005 if ($this->isArray()) {
41006 if (null === $default) {
41007 $default = array();
41008 } elseif (!is_array($default)) {
41009 throw new \LogicException('A default value for an array option must be an array.');
41010 }
41011 }
41012
41013 $this->default = $this->acceptValue() ? $default : false;
41014 }
41015
41016
41017
41018
41019
41020
41021 public function getDefault()
41022 {
41023 return $this->default;
41024 }
41025
41026
41027
41028
41029
41030
41031 public function getDescription()
41032 {
41033 return $this->description;
41034 }
41035
41036
41037
41038
41039
41040
41041
41042
41043 public function equals(InputOption $option)
41044 {
41045 return $option->getName() === $this->getName()
41046 && $option->getShortcut() === $this->getShortcut()
41047 && $option->getDefault() === $this->getDefault()
41048 && $option->isArray() === $this->isArray()
41049 && $option->isValueRequired() === $this->isValueRequired()
41050 && $option->isValueOptional() === $this->isValueOptional()
41051 ;
41052 }
41053 }
41054 <?php
41055
41056
41057
41058
41059
41060
41061
41062
41063
41064
41065 namespace Symfony\Component\Console\Input;
41066
41067
41068
41069
41070
41071
41072
41073
41074
41075
41076
41077
41078
41079
41080
41081
41082
41083
41084
41085
41086
41087
41088
41089
41090
41091
41092
41093
41094 class ArgvInput extends Input
41095 {
41096 private $tokens;
41097 private $parsed;
41098
41099
41100
41101
41102
41103
41104
41105
41106
41107 public function __construct(array $argv = null, InputDefinition $definition = null)
41108 {
41109 if (null === $argv) {
41110 $argv = $_SERVER['argv'];
41111 }
41112
41113
41114  array_shift($argv);
41115
41116 $this->tokens = $argv;
41117
41118 parent::__construct($definition);
41119 }
41120
41121 protected function setTokens(array $tokens)
41122 {
41123 $this->tokens = $tokens;
41124 }
41125
41126
41127
41128
41129 protected function parse()
41130 {
41131 $parseOptions = true;
41132 $this->parsed = $this->tokens;
41133 while (null !== $token = array_shift($this->parsed)) {
41134 if ($parseOptions && '' == $token) {
41135 $this->parseArgument($token);
41136 } elseif ($parseOptions && '--' == $token) {
41137 $parseOptions = false;
41138 } elseif ($parseOptions && 0 === strpos($token, '--')) {
41139 $this->parseLongOption($token);
41140 } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
41141 $this->parseShortOption($token);
41142 } else {
41143 $this->parseArgument($token);
41144 }
41145 }
41146 }
41147
41148
41149
41150
41151
41152
41153 private function parseShortOption($token)
41154 {
41155 $name = substr($token, 1);
41156
41157 if (strlen($name) > 1) {
41158 if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) {
41159
41160  $this->addShortOption($name[0], substr($name, 1));
41161 } else {
41162 $this->parseShortOptionSet($name);
41163 }
41164 } else {
41165 $this->addShortOption($name, null);
41166 }
41167 }
41168
41169
41170
41171
41172
41173
41174
41175
41176 private function parseShortOptionSet($name)
41177 {
41178 $len = strlen($name);
41179 for ($i = 0; $i < $len; $i++) {
41180 if (!$this->definition->hasShortcut($name[$i])) {
41181 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $name[$i]));
41182 }
41183
41184 $option = $this->definition->getOptionForShortcut($name[$i]);
41185 if ($option->acceptValue()) {
41186 $this->addLongOption($option->getName(), $i === $len - 1 ? null : substr($name, $i + 1));
41187
41188 break;
41189 } else {
41190 $this->addLongOption($option->getName(), null);
41191 }
41192 }
41193 }
41194
41195
41196
41197
41198
41199
41200 private function parseLongOption($token)
41201 {
41202 $name = substr($token, 2);
41203
41204 if (false !== $pos = strpos($name, '=')) {
41205 $this->addLongOption(substr($name, 0, $pos), substr($name, $pos + 1));
41206 } else {
41207 $this->addLongOption($name, null);
41208 }
41209 }
41210
41211
41212
41213
41214
41215
41216
41217
41218 private function parseArgument($token)
41219 {
41220 $c = count($this->arguments);
41221
41222
41223  if ($this->definition->hasArgument($c)) {
41224 $arg = $this->definition->getArgument($c);
41225 $this->arguments[$arg->getName()] = $arg->isArray() ? array($token) : $token;
41226
41227
41228  } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) {
41229 $arg = $this->definition->getArgument($c - 1);
41230 $this->arguments[$arg->getName()][] = $token;
41231
41232
41233  } else {
41234 throw new \RuntimeException('Too many arguments.');
41235 }
41236 }
41237
41238
41239
41240
41241
41242
41243
41244
41245
41246 private function addShortOption($shortcut, $value)
41247 {
41248 if (!$this->definition->hasShortcut($shortcut)) {
41249 throw new \RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut));
41250 }
41251
41252 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
41253 }
41254
41255
41256
41257
41258
41259
41260
41261
41262
41263 private function addLongOption($name, $value)
41264 {
41265 if (!$this->definition->hasOption($name)) {
41266 throw new \RuntimeException(sprintf('The "--%s" option does not exist.', $name));
41267 }
41268
41269 $option = $this->definition->getOption($name);
41270
41271
41272  if (false === $value) {
41273 $value = null;
41274 }
41275
41276 if (null !== $value && !$option->acceptValue()) {
41277 throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name, $value));
41278 }
41279
41280 if (null === $value && $option->acceptValue() && count($this->parsed)) {
41281
41282  
41283  $next = array_shift($this->parsed);
41284 if (isset($next[0]) && '-' !== $next[0]) {
41285 $value = $next;
41286 } elseif (empty($next)) {
41287 $value = '';
41288 } else {
41289 array_unshift($this->parsed, $next);
41290 }
41291 }
41292
41293 if (null === $value) {
41294 if ($option->isValueRequired()) {
41295 throw new \RuntimeException(sprintf('The "--%s" option requires a value.', $name));
41296 }
41297
41298 if (!$option->isArray()) {
41299 $value = $option->isValueOptional() ? $option->getDefault() : true;
41300 }
41301 }
41302
41303 if ($option->isArray()) {
41304 $this->options[$name][] = $value;
41305 } else {
41306 $this->options[$name] = $value;
41307 }
41308 }
41309
41310
41311
41312
41313
41314
41315 public function getFirstArgument()
41316 {
41317 foreach ($this->tokens as $token) {
41318 if ($token && '-' === $token[0]) {
41319 continue;
41320 }
41321
41322 return $token;
41323 }
41324 }
41325
41326
41327
41328
41329
41330
41331
41332
41333
41334
41335
41336 public function hasParameterOption($values)
41337 {
41338 $values = (array) $values;
41339
41340 foreach ($this->tokens as $token) {
41341 foreach ($values as $value) {
41342 if ($token === $value || 0 === strpos($token, $value.'=')) {
41343 return true;
41344 }
41345 }
41346 }
41347
41348 return false;
41349 }
41350
41351
41352
41353
41354
41355
41356
41357
41358
41359
41360
41361
41362 public function getParameterOption($values, $default = false)
41363 {
41364 $values = (array) $values;
41365
41366 $tokens = $this->tokens;
41367 while ($token = array_shift($tokens)) {
41368 foreach ($values as $value) {
41369 if ($token === $value || 0 === strpos($token, $value.'=')) {
41370 if (false !== $pos = strpos($token, '=')) {
41371 return substr($token, $pos + 1);
41372 }
41373
41374 return array_shift($tokens);
41375 }
41376 }
41377 }
41378
41379 return $default;
41380 }
41381
41382
41383
41384
41385
41386
41387 public function __toString()
41388 {
41389 $self = $this;
41390 $tokens = array_map(function ($token) use ($self) {
41391 if (preg_match('{^(-[^=]+=)(.+)}', $token, $match)) {
41392 return $match[1].$self->escapeToken($match[2]);
41393 }
41394
41395 if ($token && $token[0] !== '-') {
41396 return $self->escapeToken($token);
41397 }
41398
41399 return $token;
41400 }, $this->tokens);
41401
41402 return implode(' ', $tokens);
41403 }
41404 }
41405 <?php
41406
41407
41408
41409
41410
41411
41412
41413
41414
41415
41416 namespace Symfony\Component\Console\Input;
41417
41418
41419
41420
41421
41422
41423 interface InputInterface
41424 {
41425
41426
41427
41428
41429
41430 public function getFirstArgument();
41431
41432
41433
41434
41435
41436
41437
41438
41439
41440
41441
41442 public function hasParameterOption($values);
41443
41444
41445
41446
41447
41448
41449
41450
41451
41452
41453
41454
41455 public function getParameterOption($values, $default = false);
41456
41457
41458
41459
41460
41461
41462 public function bind(InputDefinition $definition);
41463
41464
41465
41466
41467
41468
41469
41470
41471 public function validate();
41472
41473
41474
41475
41476
41477
41478 public function getArguments();
41479
41480
41481
41482
41483
41484
41485
41486
41487 public function getArgument($name);
41488
41489
41490
41491
41492
41493
41494
41495
41496
41497 public function setArgument($name, $value);
41498
41499
41500
41501
41502
41503
41504
41505
41506 public function hasArgument($name);
41507
41508
41509
41510
41511
41512
41513 public function getOptions();
41514
41515
41516
41517
41518
41519
41520
41521
41522 public function getOption($name);
41523
41524
41525
41526
41527
41528
41529
41530
41531
41532 public function setOption($name, $value);
41533
41534
41535
41536
41537
41538
41539
41540
41541 public function hasOption($name);
41542
41543
41544
41545
41546
41547
41548 public function isInteractive();
41549
41550
41551
41552
41553
41554
41555 public function setInteractive($interactive);
41556 }
41557 <?php
41558
41559
41560
41561
41562
41563
41564
41565
41566
41567
41568 namespace Symfony\Component\Console\Input;
41569
41570
41571
41572
41573
41574
41575
41576
41577
41578
41579
41580
41581 class ArrayInput extends Input
41582 {
41583 private $parameters;
41584
41585
41586
41587
41588
41589
41590
41591
41592
41593 public function __construct(array $parameters, InputDefinition $definition = null)
41594 {
41595 $this->parameters = $parameters;
41596
41597 parent::__construct($definition);
41598 }
41599
41600
41601
41602
41603
41604
41605 public function getFirstArgument()
41606 {
41607 foreach ($this->parameters as $key => $value) {
41608 if ($key && '-' === $key[0]) {
41609 continue;
41610 }
41611
41612 return $value;
41613 }
41614 }
41615
41616
41617
41618
41619
41620
41621
41622
41623
41624
41625
41626 public function hasParameterOption($values)
41627 {
41628 $values = (array) $values;
41629
41630 foreach ($this->parameters as $k => $v) {
41631 if (!is_int($k)) {
41632 $v = $k;
41633 }
41634
41635 if (in_array($v, $values)) {
41636 return true;
41637 }
41638 }
41639
41640 return false;
41641 }
41642
41643
41644
41645
41646
41647
41648
41649
41650
41651
41652
41653
41654 public function getParameterOption($values, $default = false)
41655 {
41656 $values = (array) $values;
41657
41658 foreach ($this->parameters as $k => $v) {
41659 if (is_int($k) && in_array($v, $values)) {
41660 return true;
41661 } elseif (in_array($k, $values)) {
41662 return $v;
41663 }
41664 }
41665
41666 return $default;
41667 }
41668
41669
41670
41671
41672
41673
41674 public function __toString()
41675 {
41676 $params = array();
41677 foreach ($this->parameters as $param => $val) {
41678 if ($param && '-' === $param[0]) {
41679 $params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
41680 } else {
41681 $params[] = $this->escapeToken($val);
41682 }
41683 }
41684
41685 return implode(' ', $params);
41686 }
41687
41688
41689
41690
41691 protected function parse()
41692 {
41693 foreach ($this->parameters as $key => $value) {
41694 if (0 === strpos($key, '--')) {
41695 $this->addLongOption(substr($key, 2), $value);
41696 } elseif ('-' === $key[0]) {
41697 $this->addShortOption(substr($key, 1), $value);
41698 } else {
41699 $this->addArgument($key, $value);
41700 }
41701 }
41702 }
41703
41704
41705
41706
41707
41708
41709
41710
41711
41712 private function addShortOption($shortcut, $value)
41713 {
41714 if (!$this->definition->hasShortcut($shortcut)) {
41715 throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
41716 }
41717
41718 $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value);
41719 }
41720
41721
41722
41723
41724
41725
41726
41727
41728
41729
41730 private function addLongOption($name, $value)
41731 {
41732 if (!$this->definition->hasOption($name)) {
41733 throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
41734 }
41735
41736 $option = $this->definition->getOption($name);
41737
41738 if (null === $value) {
41739 if ($option->isValueRequired()) {
41740 throw new \InvalidArgumentException(sprintf('The "--%s" option requires a value.', $name));
41741 }
41742
41743 $value = $option->isValueOptional() ? $option->getDefault() : true;
41744 }
41745
41746 $this->options[$name] = $value;
41747 }
41748
41749
41750
41751
41752
41753
41754
41755
41756
41757 private function addArgument($name, $value)
41758 {
41759 if (!$this->definition->hasArgument($name)) {
41760 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
41761 }
41762
41763 $this->arguments[$name] = $value;
41764 }
41765 }
41766 <?php
41767
41768
41769
41770
41771
41772
41773
41774
41775
41776
41777 namespace Symfony\Component\Console\Input;
41778
41779
41780
41781
41782
41783
41784
41785 interface InputAwareInterface
41786 {
41787
41788
41789
41790
41791
41792 public function setInput(InputInterface $input);
41793 }
41794 <?php
41795
41796
41797
41798
41799
41800
41801
41802
41803
41804
41805 namespace Symfony\Component\Console\Input;
41806
41807 use Symfony\Component\Console\Descriptor\TextDescriptor;
41808 use Symfony\Component\Console\Descriptor\XmlDescriptor;
41809 use Symfony\Component\Console\Output\BufferedOutput;
41810
41811
41812
41813
41814
41815
41816
41817
41818
41819
41820
41821
41822
41823
41824
41825 class InputDefinition
41826 {
41827 private $arguments;
41828 private $requiredCount;
41829 private $hasAnArrayArgument = false;
41830 private $hasOptional;
41831 private $options;
41832 private $shortcuts;
41833
41834
41835
41836
41837
41838
41839
41840
41841 public function __construct(array $definition = array())
41842 {
41843 $this->setDefinition($definition);
41844 }
41845
41846
41847
41848
41849
41850
41851
41852
41853 public function setDefinition(array $definition)
41854 {
41855 $arguments = array();
41856 $options = array();
41857 foreach ($definition as $item) {
41858 if ($item instanceof InputOption) {
41859 $options[] = $item;
41860 } else {
41861 $arguments[] = $item;
41862 }
41863 }
41864
41865 $this->setArguments($arguments);
41866 $this->setOptions($options);
41867 }
41868
41869
41870
41871
41872
41873
41874
41875
41876 public function setArguments($arguments = array())
41877 {
41878 $this->arguments = array();
41879 $this->requiredCount = 0;
41880 $this->hasOptional = false;
41881 $this->hasAnArrayArgument = false;
41882 $this->addArguments($arguments);
41883 }
41884
41885
41886
41887
41888
41889
41890
41891
41892 public function addArguments($arguments = array())
41893 {
41894 if (null !== $arguments) {
41895 foreach ($arguments as $argument) {
41896 $this->addArgument($argument);
41897 }
41898 }
41899 }
41900
41901
41902
41903
41904
41905
41906
41907
41908
41909
41910 public function addArgument(InputArgument $argument)
41911 {
41912 if (isset($this->arguments[$argument->getName()])) {
41913 throw new \LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
41914 }
41915
41916 if ($this->hasAnArrayArgument) {
41917 throw new \LogicException('Cannot add an argument after an array argument.');
41918 }
41919
41920 if ($argument->isRequired() && $this->hasOptional) {
41921 throw new \LogicException('Cannot add a required argument after an optional one.');
41922 }
41923
41924 if ($argument->isArray()) {
41925 $this->hasAnArrayArgument = true;
41926 }
41927
41928 if ($argument->isRequired()) {
41929 ++$this->requiredCount;
41930 } else {
41931 $this->hasOptional = true;
41932 }
41933
41934 $this->arguments[$argument->getName()] = $argument;
41935 }
41936
41937
41938
41939
41940
41941
41942
41943
41944
41945
41946
41947
41948 public function getArgument($name)
41949 {
41950 if (!$this->hasArgument($name)) {
41951 throw new \InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
41952 }
41953
41954 $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
41955
41956 return $arguments[$name];
41957 }
41958
41959
41960
41961
41962
41963
41964
41965
41966
41967
41968 public function hasArgument($name)
41969 {
41970 $arguments = is_int($name) ? array_values($this->arguments) : $this->arguments;
41971
41972 return isset($arguments[$name]);
41973 }
41974
41975
41976
41977
41978
41979
41980
41981
41982 public function getArguments()
41983 {
41984 return $this->arguments;
41985 }
41986
41987
41988
41989
41990
41991
41992 public function getArgumentCount()
41993 {
41994 return $this->hasAnArrayArgument ? PHP_INT_MAX : count($this->arguments);
41995 }
41996
41997
41998
41999
42000
42001
42002 public function getArgumentRequiredCount()
42003 {
42004 return $this->requiredCount;
42005 }
42006
42007
42008
42009
42010
42011
42012 public function getArgumentDefaults()
42013 {
42014 $values = array();
42015 foreach ($this->arguments as $argument) {
42016 $values[$argument->getName()] = $argument->getDefault();
42017 }
42018
42019 return $values;
42020 }
42021
42022
42023
42024
42025
42026
42027
42028
42029 public function setOptions($options = array())
42030 {
42031 $this->options = array();
42032 $this->shortcuts = array();
42033 $this->addOptions($options);
42034 }
42035
42036
42037
42038
42039
42040
42041
42042
42043 public function addOptions($options = array())
42044 {
42045 foreach ($options as $option) {
42046 $this->addOption($option);
42047 }
42048 }
42049
42050
42051
42052
42053
42054
42055
42056
42057
42058
42059 public function addOption(InputOption $option)
42060 {
42061 if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
42062 throw new \LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
42063 }
42064
42065 if ($option->getShortcut()) {
42066 foreach (explode('|', $option->getShortcut()) as $shortcut) {
42067 if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) {
42068 throw new \LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut));
42069 }
42070 }
42071 }
42072
42073 $this->options[$option->getName()] = $option;
42074 if ($option->getShortcut()) {
42075 foreach (explode('|', $option->getShortcut()) as $shortcut) {
42076 $this->shortcuts[$shortcut] = $option->getName();
42077 }
42078 }
42079 }
42080
42081
42082
42083
42084
42085
42086
42087
42088
42089
42090
42091
42092 public function getOption($name)
42093 {
42094 if (!$this->hasOption($name)) {
42095 throw new \InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
42096 }
42097
42098 return $this->options[$name];
42099 }
42100
42101
42102
42103
42104
42105
42106
42107
42108
42109
42110 public function hasOption($name)
42111 {
42112 return isset($this->options[$name]);
42113 }
42114
42115
42116
42117
42118
42119
42120
42121
42122 public function getOptions()
42123 {
42124 return $this->options;
42125 }
42126
42127
42128
42129
42130
42131
42132
42133
42134 public function hasShortcut($name)
42135 {
42136 return isset($this->shortcuts[$name]);
42137 }
42138
42139
42140
42141
42142
42143
42144
42145
42146 public function getOptionForShortcut($shortcut)
42147 {
42148 return $this->getOption($this->shortcutToName($shortcut));
42149 }
42150
42151
42152
42153
42154
42155
42156 public function getOptionDefaults()
42157 {
42158 $values = array();
42159 foreach ($this->options as $option) {
42160 $values[$option->getName()] = $option->getDefault();
42161 }
42162
42163 return $values;
42164 }
42165
42166
42167
42168
42169
42170
42171
42172
42173
42174
42175 private function shortcutToName($shortcut)
42176 {
42177 if (!isset($this->shortcuts[$shortcut])) {
42178 throw new \InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));
42179 }
42180
42181 return $this->shortcuts[$shortcut];
42182 }
42183
42184
42185
42186
42187
42188
42189 public function getSynopsis()
42190 {
42191 $elements = array();
42192 foreach ($this->getOptions() as $option) {
42193 $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
42194 $elements[] = sprintf('['.($option->isValueRequired() ? '%s--%s="..."' : ($option->isValueOptional() ? '%s--%s[="..."]' : '%s--%s')).']', $shortcut, $option->getName());
42195 }
42196
42197 foreach ($this->getArguments() as $argument) {
42198 $elements[] = sprintf($argument->isRequired() ? '%s' : '[%s]', $argument->getName().($argument->isArray() ? '1' : ''));
42199
42200 if ($argument->isArray()) {
42201 $elements[] = sprintf('... [%sN]', $argument->getName());
42202 }
42203 }
42204
42205 return implode(' ', $elements);
42206 }
42207
42208
42209
42210
42211
42212
42213
42214
42215 public function asText()
42216 {
42217 $descriptor = new TextDescriptor();
42218 $output = new BufferedOutput(BufferedOutput::VERBOSITY_NORMAL, true);
42219 $descriptor->describe($output, $this, array('raw_output' => true));
42220
42221 return $output->fetch();
42222 }
42223
42224
42225
42226
42227
42228
42229
42230
42231
42232
42233 public function asXml($asDom = false)
42234 {
42235 $descriptor = new XmlDescriptor();
42236
42237 if ($asDom) {
42238 return $descriptor->getInputDefinitionDocument($this);
42239 }
42240
42241 $output = new BufferedOutput();
42242 $descriptor->describe($output, $this);
42243
42244 return $output->fetch();
42245 }
42246 }
42247 <?php
42248
42249
42250
42251
42252
42253
42254
42255
42256
42257
42258 namespace Symfony\Component\Console;
42259
42260 use Symfony\Component\Console\Input\StringInput;
42261 use Symfony\Component\Console\Output\ConsoleOutput;
42262 use Symfony\Component\Process\ProcessBuilder;
42263 use Symfony\Component\Process\PhpExecutableFinder;
42264
42265
42266
42267
42268
42269
42270
42271
42272
42273
42274 class Shell
42275 {
42276 private $application;
42277 private $history;
42278 private $output;
42279 private $hasReadline;
42280 private $processIsolation = false;
42281
42282
42283
42284
42285
42286
42287
42288
42289
42290 public function __construct(Application $application)
42291 {
42292 $this->hasReadline = function_exists('readline');
42293 $this->application = $application;
42294 $this->history = getenv('HOME').'/.history_'.$application->getName();
42295 $this->output = new ConsoleOutput();
42296 }
42297
42298
42299
42300
42301 public function run()
42302 {
42303 $this->application->setAutoExit(false);
42304 $this->application->setCatchExceptions(true);
42305
42306 if ($this->hasReadline) {
42307 readline_read_history($this->history);
42308 readline_completion_function(array($this, 'autocompleter'));
42309 }
42310
42311 $this->output->writeln($this->getHeader());
42312 $php = null;
42313 if ($this->processIsolation) {
42314 $finder = new PhpExecutableFinder();
42315 $php = $finder->find();
42316 $this->output->writeln(<<<EOF
42317 <info>Running with process isolation, you should consider this:</info>
42318   * each command is executed as separate process,
42319   * commands don't support interactivity, all params must be passed explicitly,
42320   * commands output is not colorized.
42321
42322 EOF
42323 );
42324 }
42325
42326 while (true) {
42327 $command = $this->readline();
42328
42329 if (false === $command) {
42330 $this->output->writeln("\n");
42331
42332 break;
42333 }
42334
42335 if ($this->hasReadline) {
42336 readline_add_history($command);
42337 readline_write_history($this->history);
42338 }
42339
42340 if ($this->processIsolation) {
42341 $pb = new ProcessBuilder();
42342
42343 $process = $pb
42344 ->add($php)
42345 ->add($_SERVER['argv'][0])
42346 ->add($command)
42347 ->inheritEnvironmentVariables(true)
42348 ->getProcess()
42349 ;
42350
42351 $output = $this->output;
42352 $process->run(function ($type, $data) use ($output) {
42353 $output->writeln($data);
42354 });
42355
42356 $ret = $process->getExitCode();
42357 } else {
42358 $ret = $this->application->run(new StringInput($command), $this->output);
42359 }
42360
42361 if (0 !== $ret) {
42362 $this->output->writeln(sprintf('<error>The command terminated with an error status (%s)</error>', $ret));
42363 }
42364 }
42365 }
42366
42367
42368
42369
42370
42371
42372 protected function getHeader()
42373 {
42374 return <<<EOF
42375
42376 Welcome to the <info>{$this->application->getName()}</info> shell (<comment>{$this->application->getVersion()}</comment>).
42377
42378 At the prompt, type <comment>help</comment> for some help,
42379 or <comment>list</comment> to get a list of available commands.
42380
42381 To exit the shell, type <comment>^D</comment>.
42382
42383 EOF;
42384 }
42385
42386
42387
42388
42389
42390
42391 protected function getPrompt()
42392 {
42393
42394  return $this->output->getFormatter()->format($this->application->getName().' > ');
42395 }
42396
42397 protected function getOutput()
42398 {
42399 return $this->output;
42400 }
42401
42402 protected function getApplication()
42403 {
42404 return $this->application;
42405 }
42406
42407
42408
42409
42410
42411
42412
42413
42414 private function autocompleter($text)
42415 {
42416 $info = readline_info();
42417 $text = substr($info['line_buffer'], 0, $info['end']);
42418
42419 if ($info['point'] !== $info['end']) {
42420 return true;
42421 }
42422
42423
42424  if (false === strpos($text, ' ') || !$text) {
42425 return array_keys($this->application->all());
42426 }
42427
42428
42429  try {
42430 $command = $this->application->find(substr($text, 0, strpos($text, ' ')));
42431 } catch (\Exception $e) {
42432 return true;
42433 }
42434
42435 $list = array('--help');
42436 foreach ($command->getDefinition()->getOptions() as $option) {
42437 $list[] = '--'.$option->getName();
42438 }
42439
42440 return $list;
42441 }
42442
42443
42444
42445
42446
42447
42448 private function readline()
42449 {
42450 if ($this->hasReadline) {
42451 $line = readline($this->getPrompt());
42452 } else {
42453 $this->output->write($this->getPrompt());
42454 $line = fgets(STDIN, 1024);
42455 $line = (!$line && strlen($line) == 0) ? false : rtrim($line);
42456 }
42457
42458 return $line;
42459 }
42460
42461 public function getProcessIsolation()
42462 {
42463 return $this->processIsolation;
42464 }
42465
42466 public function setProcessIsolation($processIsolation)
42467 {
42468 $this->processIsolation = (bool) $processIsolation;
42469
42470 if ($this->processIsolation && !class_exists('Symfony\\Component\\Process\\Process')) {
42471 throw new \RuntimeException('Unable to isolate processes as the Symfony Process Component is not installed.');
42472 }
42473 }
42474 }
42475 <?php
42476
42477
42478
42479
42480
42481
42482
42483
42484
42485
42486 namespace Symfony\Component\Console\Question;
42487
42488
42489
42490
42491
42492
42493 class ChoiceQuestion extends Question
42494 {
42495 private $choices;
42496 private $multiselect = false;
42497 private $prompt = ' > ';
42498 private $errorMessage = 'Value "%s" is invalid';
42499
42500 public function __construct($question, array $choices, $default = null)
42501 {
42502 parent::__construct($question, $default);
42503
42504 $this->choices = $choices;
42505 $this->setValidator($this->getDefaultValidator());
42506 $this->setAutocompleterValues(array_keys($choices));
42507 }
42508
42509
42510
42511
42512
42513
42514 public function getChoices()
42515 {
42516 return $this->choices;
42517 }
42518
42519
42520
42521
42522
42523
42524
42525
42526
42527
42528 public function setMultiselect($multiselect)
42529 {
42530 $this->multiselect = $multiselect;
42531 $this->setValidator($this->getDefaultValidator());
42532
42533 return $this;
42534 }
42535
42536
42537
42538
42539
42540
42541 public function getPrompt()
42542 {
42543 return $this->prompt;
42544 }
42545
42546
42547
42548
42549
42550
42551
42552
42553 public function setPrompt($prompt)
42554 {
42555 $this->prompt = $prompt;
42556
42557 return $this;
42558 }
42559
42560
42561
42562
42563
42564
42565
42566
42567
42568
42569 public function setErrorMessage($errorMessage)
42570 {
42571 $this->errorMessage = $errorMessage;
42572 $this->setValidator($this->getDefaultValidator());
42573
42574 return $this;
42575 }
42576
42577 private function getDefaultValidator()
42578 {
42579 $choices = $this->choices;
42580 $errorMessage = $this->errorMessage;
42581 $multiselect = $this->multiselect;
42582
42583 return function ($selected) use ($choices, $errorMessage, $multiselect) {
42584
42585  $selectedChoices = str_replace(' ', '', $selected);
42586
42587 if ($multiselect) {
42588
42589  if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
42590 throw new \InvalidArgumentException(sprintf($errorMessage, $selected));
42591 }
42592 $selectedChoices = explode(',', $selectedChoices);
42593 } else {
42594 $selectedChoices = array($selected);
42595 }
42596
42597 $multiselectChoices = array();
42598 foreach ($selectedChoices as $value) {
42599 if (empty($choices[$value])) {
42600 throw new \InvalidArgumentException(sprintf($errorMessage, $value));
42601 }
42602 array_push($multiselectChoices, $choices[$value]);
42603 }
42604
42605 if ($multiselect) {
42606 return $multiselectChoices;
42607 }
42608
42609 return $choices[$selected];
42610 };
42611 }
42612 }
42613 <?php
42614
42615
42616
42617
42618
42619
42620
42621
42622
42623
42624 namespace Symfony\Component\Console\Question;
42625
42626
42627
42628
42629
42630
42631 class ConfirmationQuestion extends Question
42632 {
42633 public function __construct($question, $default = true)
42634 {
42635 parent::__construct($question, (bool) $default);
42636
42637 $this->setNormalizer($this->getDefaultNormalizer());
42638 }
42639
42640 private function getDefaultNormalizer()
42641 {
42642 $default = $this->getDefault();
42643
42644 return function ($answer) use ($default) {
42645 if (is_bool($answer)) {
42646 return $answer;
42647 }
42648
42649 if (false === $default) {
42650 return $answer && 'y' === strtolower($answer[0]);
42651 }
42652
42653 return !$answer || 'y' === strtolower($answer[0]);
42654 };
42655 }
42656 }
42657 <?php
42658
42659
42660
42661
42662
42663
42664
42665
42666
42667
42668 namespace Symfony\Component\Console\Question;
42669
42670
42671
42672
42673
42674
42675 class Question
42676 {
42677 private $question;
42678 private $attempts;
42679 private $hidden = false;
42680 private $hiddenFallback = true;
42681 private $autocompleterValues;
42682 private $validator;
42683 private $default;
42684 private $normalizer;
42685
42686
42687
42688
42689
42690
42691
42692 public function __construct($question, $default = null)
42693 {
42694 $this->question = $question;
42695 $this->default = $default;
42696 }
42697
42698
42699
42700
42701
42702
42703 public function getQuestion()
42704 {
42705 return $this->question;
42706 }
42707
42708
42709
42710
42711
42712
42713 public function getDefault()
42714 {
42715 return $this->default;
42716 }
42717
42718
42719
42720
42721
42722
42723 public function isHidden()
42724 {
42725 return $this->hidden;
42726 }
42727
42728
42729
42730
42731
42732
42733
42734
42735
42736
42737 public function setHidden($hidden)
42738 {
42739 if ($this->autocompleterValues) {
42740 throw new \LogicException('A hidden question cannot use the autocompleter.');
42741 }
42742
42743 $this->hidden = (bool) $hidden;
42744
42745 return $this;
42746 }
42747
42748
42749
42750
42751
42752
42753 public function isHiddenFallback()
42754 {
42755 return $this->hiddenFallback;
42756 }
42757
42758
42759
42760
42761
42762
42763
42764
42765 public function setHiddenFallback($fallback)
42766 {
42767 $this->hiddenFallback = (bool) $fallback;
42768
42769 return $this;
42770 }
42771
42772
42773
42774
42775
42776
42777 public function getAutocompleterValues()
42778 {
42779 return $this->autocompleterValues;
42780 }
42781
42782
42783
42784
42785
42786
42787
42788
42789
42790
42791
42792 public function setAutocompleterValues($values)
42793 {
42794 if (null !== $values && !is_array($values)) {
42795 if (!$values instanceof \Traversable || $values instanceof \Countable) {
42796 throw new \InvalidArgumentException('Autocompleter values can be either an array, `null` or an object implementing both `Countable` and `Traversable` interfaces.');
42797 }
42798 }
42799
42800 if ($this->hidden) {
42801 throw new \LogicException('A hidden question cannot use the autocompleter.');
42802 }
42803
42804 $this->autocompleterValues = $values;
42805
42806 return $this;
42807 }
42808
42809
42810
42811
42812
42813
42814
42815
42816 public function setValidator($validator)
42817 {
42818 $this->validator = $validator;
42819
42820 return $this;
42821 }
42822
42823
42824
42825
42826
42827
42828 public function getValidator()
42829 {
42830 return $this->validator;
42831 }
42832
42833
42834
42835
42836
42837
42838
42839
42840
42841
42842
42843
42844 public function setMaxAttempts($attempts)
42845 {
42846 if (null !== $attempts && $attempts < 1) {
42847 throw new \InvalidArgumentException('Maximum number of attempts must be a positive value.');
42848 }
42849
42850 $this->attempts = $attempts;
42851
42852 return $this;
42853 }
42854
42855
42856
42857
42858
42859
42860
42861
42862 public function getMaxAttempts()
42863 {
42864 return $this->attempts;
42865 }
42866
42867
42868
42869
42870
42871
42872
42873
42874
42875
42876 public function setNormalizer($normalizer)
42877 {
42878 $this->normalizer = $normalizer;
42879
42880 return $this;
42881 }
42882
42883
42884
42885
42886
42887
42888
42889
42890 public function getNormalizer()
42891 {
42892 return $this->normalizer;
42893 }
42894 }
42895 <?php
42896
42897
42898
42899
42900
42901
42902
42903
42904
42905
42906 namespace Symfony\Component\Console\Output;
42907
42908 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
42909 use Symfony\Component\Console\Formatter\OutputFormatter;
42910
42911
42912
42913
42914
42915
42916
42917
42918
42919
42920
42921
42922
42923
42924
42925
42926 abstract class Output implements OutputInterface
42927 {
42928 private $verbosity;
42929 private $formatter;
42930
42931
42932
42933
42934
42935
42936
42937
42938
42939
42940 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = false, OutputFormatterInterface $formatter = null)
42941 {
42942 $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
42943 $this->formatter = $formatter ?: new OutputFormatter();
42944 $this->formatter->setDecorated($decorated);
42945 }
42946
42947
42948
42949
42950 public function setFormatter(OutputFormatterInterface $formatter)
42951 {
42952 $this->formatter = $formatter;
42953 }
42954
42955
42956
42957
42958 public function getFormatter()
42959 {
42960 return $this->formatter;
42961 }
42962
42963
42964
42965
42966 public function setDecorated($decorated)
42967 {
42968 $this->formatter->setDecorated($decorated);
42969 }
42970
42971
42972
42973
42974 public function isDecorated()
42975 {
42976 return $this->formatter->isDecorated();
42977 }
42978
42979
42980
42981
42982 public function setVerbosity($level)
42983 {
42984 $this->verbosity = (int) $level;
42985 }
42986
42987
42988
42989
42990 public function getVerbosity()
42991 {
42992 return $this->verbosity;
42993 }
42994
42995 public function isQuiet()
42996 {
42997 return self::VERBOSITY_QUIET === $this->verbosity;
42998 }
42999
43000 public function isVerbose()
43001 {
43002 return self::VERBOSITY_VERBOSE <= $this->verbosity;
43003 }
43004
43005 public function isVeryVerbose()
43006 {
43007 return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
43008 }
43009
43010 public function isDebug()
43011 {
43012 return self::VERBOSITY_DEBUG <= $this->verbosity;
43013 }
43014
43015
43016
43017
43018 public function writeln($messages, $type = self::OUTPUT_NORMAL)
43019 {
43020 $this->write($messages, true, $type);
43021 }
43022
43023
43024
43025
43026 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
43027 {
43028 if (self::VERBOSITY_QUIET === $this->verbosity) {
43029 return;
43030 }
43031
43032 $messages = (array) $messages;
43033
43034 foreach ($messages as $message) {
43035 switch ($type) {
43036 case OutputInterface::OUTPUT_NORMAL:
43037 $message = $this->formatter->format($message);
43038 break;
43039 case OutputInterface::OUTPUT_RAW:
43040 break;
43041 case OutputInterface::OUTPUT_PLAIN:
43042 $message = strip_tags($this->formatter->format($message));
43043 break;
43044 default:
43045 throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
43046 }
43047
43048 $this->doWrite($message, $newline);
43049 }
43050 }
43051
43052
43053
43054
43055
43056
43057
43058 abstract protected function doWrite($message, $newline);
43059 }
43060 <?php
43061
43062
43063
43064
43065
43066
43067
43068
43069
43070
43071 namespace Symfony\Component\Console\Output;
43072
43073 use Symfony\Component\Console\Formatter\OutputFormatter;
43074 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
43075
43076
43077
43078
43079
43080
43081
43082
43083
43084
43085
43086 class NullOutput implements OutputInterface
43087 {
43088
43089
43090
43091 public function setFormatter(OutputFormatterInterface $formatter)
43092 {
43093
43094  }
43095
43096
43097
43098
43099 public function getFormatter()
43100 {
43101
43102  return new OutputFormatter();
43103 }
43104
43105
43106
43107
43108 public function setDecorated($decorated)
43109 {
43110
43111  }
43112
43113
43114
43115
43116 public function isDecorated()
43117 {
43118 return false;
43119 }
43120
43121
43122
43123
43124 public function setVerbosity($level)
43125 {
43126
43127  }
43128
43129
43130
43131
43132 public function getVerbosity()
43133 {
43134 return self::VERBOSITY_QUIET;
43135 }
43136
43137 public function isQuiet()
43138 {
43139 return true;
43140 }
43141
43142 public function isVerbose()
43143 {
43144 return false;
43145 }
43146
43147 public function isVeryVerbose()
43148 {
43149 return false;
43150 }
43151
43152 public function isDebug()
43153 {
43154 return false;
43155 }
43156
43157
43158
43159
43160 public function writeln($messages, $type = self::OUTPUT_NORMAL)
43161 {
43162
43163  }
43164
43165
43166
43167
43168 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
43169 {
43170
43171  }
43172 }
43173 <?php
43174
43175
43176
43177
43178
43179
43180
43181
43182
43183
43184 namespace Symfony\Component\Console\Output;
43185
43186
43187
43188
43189
43190
43191
43192 interface ConsoleOutputInterface extends OutputInterface
43193 {
43194
43195
43196
43197
43198
43199 public function getErrorOutput();
43200
43201
43202
43203
43204
43205
43206 public function setErrorOutput(OutputInterface $error);
43207 }
43208 <?php
43209
43210
43211
43212
43213
43214
43215
43216
43217
43218
43219 namespace Symfony\Component\Console\Output;
43220
43221 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
43222
43223
43224
43225
43226
43227
43228
43229
43230
43231
43232
43233
43234
43235
43236
43237
43238 class StreamOutput extends Output
43239 {
43240 private $stream;
43241
43242
43243
43244
43245
43246
43247
43248
43249
43250
43251
43252
43253
43254 public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
43255 {
43256 if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
43257 throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
43258 }
43259
43260 $this->stream = $stream;
43261
43262 if (null === $decorated) {
43263 $decorated = $this->hasColorSupport();
43264 }
43265
43266 parent::__construct($verbosity, $decorated, $formatter);
43267 }
43268
43269
43270
43271
43272
43273
43274 public function getStream()
43275 {
43276 return $this->stream;
43277 }
43278
43279
43280
43281
43282 protected function doWrite($message, $newline)
43283 {
43284 if (false === @fwrite($this->stream, $message.($newline ? PHP_EOL : ''))) {
43285
43286  throw new \RuntimeException('Unable to write output.');
43287 }
43288
43289 fflush($this->stream);
43290 }
43291
43292
43293
43294
43295
43296
43297
43298
43299
43300
43301
43302 protected function hasColorSupport()
43303 {
43304 if (DIRECTORY_SEPARATOR == '\\') {
43305 return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
43306 }
43307
43308 return function_exists('posix_isatty') && @posix_isatty($this->stream);
43309 }
43310 }
43311 <?php
43312
43313
43314
43315
43316
43317
43318
43319
43320
43321
43322 namespace Symfony\Component\Console\Output;
43323
43324
43325
43326
43327 class BufferedOutput extends Output
43328 {
43329
43330
43331
43332 private $buffer = '';
43333
43334
43335
43336
43337
43338
43339 public function fetch()
43340 {
43341 $content = $this->buffer;
43342 $this->buffer = '';
43343
43344 return $content;
43345 }
43346
43347
43348
43349
43350 protected function doWrite($message, $newline)
43351 {
43352 $this->buffer .= $message;
43353
43354 if ($newline) {
43355 $this->buffer .= "\n";
43356 }
43357 }
43358 }
43359 <?php
43360
43361
43362
43363
43364
43365
43366
43367
43368
43369
43370 namespace Symfony\Component\Console\Output;
43371
43372 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
43373
43374
43375
43376
43377
43378
43379
43380
43381 interface OutputInterface
43382 {
43383 const VERBOSITY_QUIET = 0;
43384 const VERBOSITY_NORMAL = 1;
43385 const VERBOSITY_VERBOSE = 2;
43386 const VERBOSITY_VERY_VERBOSE = 3;
43387 const VERBOSITY_DEBUG = 4;
43388
43389 const OUTPUT_NORMAL = 0;
43390 const OUTPUT_RAW = 1;
43391 const OUTPUT_PLAIN = 2;
43392
43393
43394
43395
43396
43397
43398
43399
43400
43401
43402
43403
43404 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL);
43405
43406
43407
43408
43409
43410
43411
43412
43413
43414
43415
43416 public function writeln($messages, $type = self::OUTPUT_NORMAL);
43417
43418
43419
43420
43421
43422
43423
43424
43425 public function setVerbosity($level);
43426
43427
43428
43429
43430
43431
43432
43433
43434 public function getVerbosity();
43435
43436
43437
43438
43439
43440
43441
43442
43443 public function setDecorated($decorated);
43444
43445
43446
43447
43448
43449
43450
43451
43452 public function isDecorated();
43453
43454
43455
43456
43457
43458
43459
43460
43461 public function setFormatter(OutputFormatterInterface $formatter);
43462
43463
43464
43465
43466
43467
43468
43469
43470 public function getFormatter();
43471 }
43472 <?php
43473
43474
43475
43476
43477
43478
43479
43480
43481
43482
43483 namespace Symfony\Component\Console\Output;
43484
43485 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
43486
43487
43488
43489
43490
43491
43492
43493
43494
43495
43496
43497
43498
43499
43500
43501
43502 class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
43503 {
43504 private $stderr;
43505
43506
43507
43508
43509
43510
43511
43512
43513
43514
43515 public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
43516 {
43517 $outputStream = 'php://stdout';
43518 if (!$this->hasStdoutSupport()) {
43519 $outputStream = 'php://output';
43520 }
43521
43522 parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter);
43523
43524 $this->stderr = new StreamOutput(fopen('php://stderr', 'w'), $verbosity, $decorated, $this->getFormatter());
43525 }
43526
43527
43528
43529
43530 public function setDecorated($decorated)
43531 {
43532 parent::setDecorated($decorated);
43533 $this->stderr->setDecorated($decorated);
43534 }
43535
43536
43537
43538
43539 public function setFormatter(OutputFormatterInterface $formatter)
43540 {
43541 parent::setFormatter($formatter);
43542 $this->stderr->setFormatter($formatter);
43543 }
43544
43545
43546
43547
43548 public function setVerbosity($level)
43549 {
43550 parent::setVerbosity($level);
43551 $this->stderr->setVerbosity($level);
43552 }
43553
43554
43555
43556
43557 public function getErrorOutput()
43558 {
43559 return $this->stderr;
43560 }
43561
43562
43563
43564
43565 public function setErrorOutput(OutputInterface $error)
43566 {
43567 $this->stderr = $error;
43568 }
43569
43570
43571
43572
43573
43574
43575
43576
43577
43578
43579
43580 protected function hasStdoutSupport()
43581 {
43582 return ('OS400' != php_uname('s'));
43583 }
43584 }
43585 <?php
43586
43587
43588
43589
43590
43591
43592
43593
43594
43595
43596 namespace Symfony\Component\Console\Logger;
43597
43598 use Psr\Log\AbstractLogger;
43599 use Psr\Log\InvalidArgumentException;
43600 use Psr\Log\LogLevel;
43601 use Symfony\Component\Console\Output\OutputInterface;
43602 use Symfony\Component\Console\Output\ConsoleOutputInterface;
43603
43604
43605
43606
43607
43608
43609
43610 class ConsoleLogger extends AbstractLogger
43611 {
43612 const INFO = 'info';
43613 const ERROR = 'error';
43614
43615
43616
43617
43618 private $output;
43619
43620
43621
43622 private $verbosityLevelMap = array(
43623 LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL,
43624 LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL,
43625 LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL,
43626 LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL,
43627 LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL,
43628 LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE,
43629 LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE,
43630 LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG,
43631 );
43632
43633
43634
43635 private $formatLevelMap = array(
43636 LogLevel::EMERGENCY => self::ERROR,
43637 LogLevel::ALERT => self::ERROR,
43638 LogLevel::CRITICAL => self::ERROR,
43639 LogLevel::ERROR => self::ERROR,
43640 LogLevel::WARNING => self::INFO,
43641 LogLevel::NOTICE => self::INFO,
43642 LogLevel::INFO => self::INFO,
43643 LogLevel::DEBUG => self::INFO,
43644 );
43645
43646
43647
43648
43649
43650
43651 public function __construct(OutputInterface $output, array $verbosityLevelMap = array(), array $formatLevelMap = array())
43652 {
43653 $this->output = $output;
43654 $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap;
43655 $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap;
43656 }
43657
43658
43659
43660
43661 public function log($level, $message, array $context = array())
43662 {
43663 if (!isset($this->verbosityLevelMap[$level])) {
43664 throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level));
43665 }
43666
43667
43668  if ($this->formatLevelMap[$level] === self::ERROR && $this->output instanceof ConsoleOutputInterface) {
43669 $output = $this->output->getErrorOutput();
43670 } else {
43671 $output = $this->output;
43672 }
43673
43674 if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) {
43675 $output->writeln(sprintf('<%1$s>[%2$s] %3$s</%1$s>', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)));
43676 }
43677 }
43678
43679
43680
43681
43682
43683
43684
43685
43686
43687 private function interpolate($message, array $context)
43688 {
43689
43690  $replace = array();
43691 foreach ($context as $key => $val) {
43692 if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
43693 $replace[sprintf('{%s}', $key)] = $val;
43694 }
43695 }
43696
43697
43698  return strtr($message, $replace);
43699 }
43700 }
43701 <?php
43702
43703
43704
43705
43706
43707
43708
43709
43710
43711
43712 namespace Symfony\Component\Console\Descriptor;
43713
43714 use Symfony\Component\Console\Output\OutputInterface;
43715
43716
43717
43718
43719
43720
43721 interface DescriptorInterface
43722 {
43723
43724
43725
43726
43727
43728
43729
43730 public function describe(OutputInterface $output, $object, array $options = array());
43731 }
43732 <?php
43733
43734
43735
43736
43737
43738
43739
43740
43741
43742
43743 namespace Symfony\Component\Console\Descriptor;
43744
43745 use Symfony\Component\Console\Application;
43746 use Symfony\Component\Console\Command\Command;
43747 use Symfony\Component\Console\Input\InputArgument;
43748 use Symfony\Component\Console\Input\InputDefinition;
43749 use Symfony\Component\Console\Input\InputOption;
43750
43751
43752
43753
43754
43755
43756 class TextDescriptor extends Descriptor
43757 {
43758
43759
43760
43761 protected function describeInputArgument(InputArgument $argument, array $options = array())
43762 {
43763 if (null !== $argument->getDefault() && (!is_array($argument->getDefault()) || count($argument->getDefault()))) {
43764 $default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($argument->getDefault()));
43765 } else {
43766 $default = '';
43767 }
43768
43769 $nameWidth = isset($options['name_width']) ? $options['name_width'] : strlen($argument->getName());
43770
43771 $this->writeText(sprintf(" <info>%-${nameWidth}s</info> %s%s",
43772 $argument->getName(),
43773 str_replace("\n", "\n".str_repeat(' ', $nameWidth + 2), $argument->getDescription()),
43774 $default
43775 ), $options);
43776 }
43777
43778
43779
43780
43781 protected function describeInputOption(InputOption $option, array $options = array())
43782 {
43783 if ($option->acceptValue() && null !== $option->getDefault() && (!is_array($option->getDefault()) || count($option->getDefault()))) {
43784 $default = sprintf('<comment> (default: %s)</comment>', $this->formatDefaultValue($option->getDefault()));
43785 } else {
43786 $default = '';
43787 }
43788
43789 $nameWidth = isset($options['name_width']) ? $options['name_width'] : strlen($option->getName());
43790 $nameWithShortcutWidth = $nameWidth - strlen($option->getName()) - 2;
43791
43792 $this->writeText(sprintf(" <info>%s</info> %-${nameWithShortcutWidth}s%s%s%s",
43793 '--'.$option->getName(),
43794 $option->getShortcut() ? sprintf('(-%s) ', $option->getShortcut()) : '',
43795 str_replace("\n", "\n".str_repeat(' ', $nameWidth + 2), $option->getDescription()),
43796 $default,
43797 $option->isArray() ? '<comment> (multiple values allowed)</comment>' : ''
43798 ), $options);
43799 }
43800
43801
43802
43803
43804 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
43805 {
43806 $nameWidth = 0;
43807 foreach ($definition->getOptions() as $option) {
43808 $nameLength = strlen($option->getName()) + 2;
43809 if ($option->getShortcut()) {
43810 $nameLength += strlen($option->getShortcut()) + 3;
43811 }
43812 $nameWidth = max($nameWidth, $nameLength);
43813 }
43814 foreach ($definition->getArguments() as $argument) {
43815 $nameWidth = max($nameWidth, strlen($argument->getName()));
43816 }
43817 ++$nameWidth;
43818
43819 if ($definition->getArguments()) {
43820 $this->writeText('<comment>Arguments:</comment>', $options);
43821 $this->writeText("\n");
43822 foreach ($definition->getArguments() as $argument) {
43823 $this->describeInputArgument($argument, array_merge($options, array('name_width' => $nameWidth)));
43824 $this->writeText("\n");
43825 }
43826 }
43827
43828 if ($definition->getArguments() && $definition->getOptions()) {
43829 $this->writeText("\n");
43830 }
43831
43832 if ($definition->getOptions()) {
43833 $this->writeText('<comment>Options:</comment>', $options);
43834 $this->writeText("\n");
43835 foreach ($definition->getOptions() as $option) {
43836 $this->describeInputOption($option, array_merge($options, array('name_width' => $nameWidth)));
43837 $this->writeText("\n");
43838 }
43839 }
43840 }
43841
43842
43843
43844
43845 protected function describeCommand(Command $command, array $options = array())
43846 {
43847 $command->getSynopsis();
43848 $command->mergeApplicationDefinition(false);
43849
43850 $this->writeText('<comment>Usage:</comment>', $options);
43851 $this->writeText("\n");
43852 $this->writeText(' '.$command->getSynopsis(), $options);
43853 $this->writeText("\n");
43854
43855 if (count($command->getAliases()) > 0) {
43856 $this->writeText("\n");
43857 $this->writeText('<comment>Aliases:</comment> <info>'.implode(', ', $command->getAliases()).'</info>', $options);
43858 }
43859
43860 if ($definition = $command->getNativeDefinition()) {
43861 $this->writeText("\n");
43862 $this->describeInputDefinition($definition, $options);
43863 }
43864
43865 $this->writeText("\n");
43866
43867 if ($help = $command->getProcessedHelp()) {
43868 $this->writeText('<comment>Help:</comment>', $options);
43869 $this->writeText("\n");
43870 $this->writeText(' '.str_replace("\n", "\n ", $help), $options);
43871 $this->writeText("\n");
43872 }
43873 }
43874
43875
43876
43877
43878 protected function describeApplication(Application $application, array $options = array())
43879 {
43880 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
43881 $description = new ApplicationDescription($application, $describedNamespace);
43882
43883 if (isset($options['raw_text']) && $options['raw_text']) {
43884 $width = $this->getColumnWidth($description->getCommands());
43885
43886 foreach ($description->getCommands() as $command) {
43887 $this->writeText(sprintf("%-${width}s %s", $command->getName(), $command->getDescription()), $options);
43888 $this->writeText("\n");
43889 }
43890 } else {
43891 if ('' != $help = $application->getHelp()) {
43892 $this->writeText("$help\n\n", $options);
43893 }
43894
43895 $this->writeText("<comment>Usage:</comment>\n", $options);
43896 $this->writeText(" [options] command [arguments]\n\n", $options);
43897 $this->writeText('<comment>Options:</comment>', $options);
43898
43899 $inputOptions = $application->getDefinition()->getOptions();
43900
43901 $width = 0;
43902 foreach ($inputOptions as $option) {
43903 $nameLength = strlen($option->getName()) + 2;
43904 if ($option->getShortcut()) {
43905 $nameLength += strlen($option->getShortcut()) + 3;
43906 }
43907 $width = max($width, $nameLength);
43908 }
43909 ++$width;
43910
43911 foreach ($inputOptions as $option) {
43912 $this->writeText("\n", $options);
43913 $this->describeInputOption($option, array_merge($options, array('name_width' => $width)));
43914 }
43915
43916 $this->writeText("\n\n", $options);
43917
43918 $width = $this->getColumnWidth($description->getCommands());
43919
43920 if ($describedNamespace) {
43921 $this->writeText(sprintf("<comment>Available commands for the \"%s\" namespace:</comment>", $describedNamespace), $options);
43922 } else {
43923 $this->writeText('<comment>Available commands:</comment>', $options);
43924 }
43925
43926
43927  foreach ($description->getNamespaces() as $namespace) {
43928 if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
43929 $this->writeText("\n");
43930 $this->writeText('<comment>'.$namespace['id'].'</comment>', $options);
43931 }
43932
43933 foreach ($namespace['commands'] as $name) {
43934 $this->writeText("\n");
43935 $this->writeText(sprintf(" <info>%-${width}s</info> %s", $name, $description->getCommand($name)->getDescription()), $options);
43936 }
43937 }
43938
43939 $this->writeText("\n");
43940 }
43941 }
43942
43943
43944
43945
43946 private function writeText($content, array $options = array())
43947 {
43948 $this->write(
43949 isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
43950 isset($options['raw_output']) ? !$options['raw_output'] : true
43951 );
43952 }
43953
43954
43955
43956
43957
43958
43959
43960
43961 private function formatDefaultValue($default)
43962 {
43963 if (PHP_VERSION_ID < 50400) {
43964 return str_replace('\/', '/', json_encode($default));
43965 }
43966
43967 return json_encode($default, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
43968 }
43969
43970
43971
43972
43973
43974
43975 private function getColumnWidth(array $commands)
43976 {
43977 $width = 0;
43978 foreach ($commands as $command) {
43979 $width = strlen($command->getName()) > $width ? strlen($command->getName()) : $width;
43980 }
43981
43982 return $width + 2;
43983 }
43984 }
43985 <?php
43986
43987
43988
43989
43990
43991
43992
43993
43994
43995
43996 namespace Symfony\Component\Console\Descriptor;
43997
43998 use Symfony\Component\Console\Application;
43999 use Symfony\Component\Console\Command\Command;
44000 use Symfony\Component\Console\Input\InputArgument;
44001 use Symfony\Component\Console\Input\InputDefinition;
44002 use Symfony\Component\Console\Input\InputOption;
44003
44004
44005
44006
44007
44008
44009 class XmlDescriptor extends Descriptor
44010 {
44011
44012
44013
44014
44015
44016 public function getInputDefinitionDocument(InputDefinition $definition)
44017 {
44018 $dom = new \DOMDocument('1.0', 'UTF-8');
44019 $dom->appendChild($definitionXML = $dom->createElement('definition'));
44020
44021 $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments'));
44022 foreach ($definition->getArguments() as $argument) {
44023 $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument));
44024 }
44025
44026 $definitionXML->appendChild($optionsXML = $dom->createElement('options'));
44027 foreach ($definition->getOptions() as $option) {
44028 $this->appendDocument($optionsXML, $this->getInputOptionDocument($option));
44029 }
44030
44031 return $dom;
44032 }
44033
44034
44035
44036
44037
44038
44039 public function getCommandDocument(Command $command)
44040 {
44041 $dom = new \DOMDocument('1.0', 'UTF-8');
44042 $dom->appendChild($commandXML = $dom->createElement('command'));
44043
44044 $command->getSynopsis();
44045 $command->mergeApplicationDefinition(false);
44046
44047 $commandXML->setAttribute('id', $command->getName());
44048 $commandXML->setAttribute('name', $command->getName());
44049
44050 $commandXML->appendChild($usageXML = $dom->createElement('usage'));
44051 $usageXML->appendChild($dom->createTextNode(sprintf($command->getSynopsis(), '')));
44052
44053 $commandXML->appendChild($descriptionXML = $dom->createElement('description'));
44054 $descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
44055
44056 $commandXML->appendChild($helpXML = $dom->createElement('help'));
44057 $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
44058
44059 $commandXML->appendChild($aliasesXML = $dom->createElement('aliases'));
44060 foreach ($command->getAliases() as $alias) {
44061 $aliasesXML->appendChild($aliasXML = $dom->createElement('alias'));
44062 $aliasXML->appendChild($dom->createTextNode($alias));
44063 }
44064
44065 $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
44066 $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
44067
44068 return $dom;
44069 }
44070
44071
44072
44073
44074
44075
44076
44077 public function getApplicationDocument(Application $application, $namespace = null)
44078 {
44079 $dom = new \DOMDocument('1.0', 'UTF-8');
44080 $dom->appendChild($rootXml = $dom->createElement('symfony'));
44081
44082 if ($application->getName() !== 'UNKNOWN') {
44083 $rootXml->setAttribute('name', $application->getName());
44084 if ($application->getVersion() !== 'UNKNOWN') {
44085 $rootXml->setAttribute('version', $application->getVersion());
44086 }
44087 }
44088
44089 $rootXml->appendChild($commandsXML = $dom->createElement('commands'));
44090
44091 $description = new ApplicationDescription($application, $namespace);
44092
44093 if ($namespace) {
44094 $commandsXML->setAttribute('namespace', $namespace);
44095 }
44096
44097 foreach ($description->getCommands() as $command) {
44098 $this->appendDocument($commandsXML, $this->getCommandDocument($command));
44099 }
44100
44101 if (!$namespace) {
44102 $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces'));
44103
44104 foreach ($description->getNamespaces() as $namespaceDescription) {
44105 $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace'));
44106 $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']);
44107
44108 foreach ($namespaceDescription['commands'] as $name) {
44109 $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command'));
44110 $commandXML->appendChild($dom->createTextNode($name));
44111 }
44112 }
44113 }
44114
44115 return $dom;
44116 }
44117
44118
44119
44120
44121 protected function describeInputArgument(InputArgument $argument, array $options = array())
44122 {
44123 $this->writeDocument($this->getInputArgumentDocument($argument));
44124 }
44125
44126
44127
44128
44129 protected function describeInputOption(InputOption $option, array $options = array())
44130 {
44131 $this->writeDocument($this->getInputOptionDocument($option));
44132 }
44133
44134
44135
44136
44137 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
44138 {
44139 $this->writeDocument($this->getInputDefinitionDocument($definition));
44140 }
44141
44142
44143
44144
44145 protected function describeCommand(Command $command, array $options = array())
44146 {
44147 $this->writeDocument($this->getCommandDocument($command));
44148 }
44149
44150
44151
44152
44153 protected function describeApplication(Application $application, array $options = array())
44154 {
44155 $this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null));
44156 }
44157
44158
44159
44160
44161
44162
44163
44164 private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent)
44165 {
44166 foreach ($importedParent->childNodes as $childNode) {
44167 $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, true));
44168 }
44169 }
44170
44171
44172
44173
44174
44175
44176
44177
44178 private function writeDocument(\DOMDocument $dom)
44179 {
44180 $dom->formatOutput = true;
44181 $this->write($dom->saveXML());
44182 }
44183
44184
44185
44186
44187
44188
44189 private function getInputArgumentDocument(InputArgument $argument)
44190 {
44191 $dom = new \DOMDocument('1.0', 'UTF-8');
44192
44193 $dom->appendChild($objectXML = $dom->createElement('argument'));
44194 $objectXML->setAttribute('name', $argument->getName());
44195 $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0);
44196 $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0);
44197 $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
44198 $descriptionXML->appendChild($dom->createTextNode($argument->getDescription()));
44199
44200 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
44201 $defaults = is_array($argument->getDefault()) ? $argument->getDefault() : (is_bool($argument->getDefault()) ? array(var_export($argument->getDefault(), true)) : ($argument->getDefault() ? array($argument->getDefault()) : array()));
44202 foreach ($defaults as $default) {
44203 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
44204 $defaultXML->appendChild($dom->createTextNode($default));
44205 }
44206
44207 return $dom;
44208 }
44209
44210
44211
44212
44213
44214
44215 private function getInputOptionDocument(InputOption $option)
44216 {
44217 $dom = new \DOMDocument('1.0', 'UTF-8');
44218
44219 $dom->appendChild($objectXML = $dom->createElement('option'));
44220 $objectXML->setAttribute('name', '--'.$option->getName());
44221 $pos = strpos($option->getShortcut(), '|');
44222 if (false !== $pos) {
44223 $objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
44224 $objectXML->setAttribute('shortcuts', '-'.implode('|-', explode('|', $option->getShortcut())));
44225 } else {
44226 $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
44227 }
44228 $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0);
44229 $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0);
44230 $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0);
44231 $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
44232 $descriptionXML->appendChild($dom->createTextNode($option->getDescription()));
44233
44234 if ($option->acceptValue()) {
44235 $defaults = is_array($option->getDefault()) ? $option->getDefault() : (is_bool($option->getDefault()) ? array(var_export($option->getDefault(), true)) : ($option->getDefault() ? array($option->getDefault()) : array()));
44236 $objectXML->appendChild($defaultsXML = $dom->createElement('defaults'));
44237
44238 if (!empty($defaults)) {
44239 foreach ($defaults as $default) {
44240 $defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
44241 $defaultXML->appendChild($dom->createTextNode($default));
44242 }
44243 }
44244 }
44245
44246 return $dom;
44247 }
44248 }
44249 <?php
44250
44251
44252
44253
44254
44255
44256
44257
44258
44259
44260 namespace Symfony\Component\Console\Descriptor;
44261
44262 use Symfony\Component\Console\Application;
44263 use Symfony\Component\Console\Command\Command;
44264 use Symfony\Component\Console\Input\InputArgument;
44265 use Symfony\Component\Console\Input\InputDefinition;
44266 use Symfony\Component\Console\Input\InputOption;
44267
44268
44269
44270
44271
44272
44273 class MarkdownDescriptor extends Descriptor
44274 {
44275
44276
44277
44278 protected function describeInputArgument(InputArgument $argument, array $options = array())
44279 {
44280 $this->write(
44281 '**'.$argument->getName().':**'."\n\n"
44282 .'* Name: '.($argument->getName() ?: '<none>')."\n"
44283 .'* Is required: '.($argument->isRequired() ? 'yes' : 'no')."\n"
44284 .'* Is array: '.($argument->isArray() ? 'yes' : 'no')."\n"
44285 .'* Description: '.($argument->getDescription() ?: '<none>')."\n"
44286 .'* Default: `'.str_replace("\n", '', var_export($argument->getDefault(), true)).'`'
44287 );
44288 }
44289
44290
44291
44292
44293 protected function describeInputOption(InputOption $option, array $options = array())
44294 {
44295 $this->write(
44296 '**'.$option->getName().':**'."\n\n"
44297 .'* Name: `--'.$option->getName().'`'."\n"
44298 .'* Shortcut: '.($option->getShortcut() ? '`-'.implode('|-', explode('|', $option->getShortcut())).'`' : '<none>')."\n"
44299 .'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
44300 .'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
44301 .'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
44302 .'* Description: '.($option->getDescription() ?: '<none>')."\n"
44303 .'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
44304 );
44305 }
44306
44307
44308
44309
44310 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
44311 {
44312 if ($showArguments = count($definition->getArguments()) > 0) {
44313 $this->write('### Arguments:');
44314 foreach ($definition->getArguments() as $argument) {
44315 $this->write("\n\n");
44316 $this->write($this->describeInputArgument($argument));
44317 }
44318 }
44319
44320 if (count($definition->getOptions()) > 0) {
44321 if ($showArguments) {
44322 $this->write("\n\n");
44323 }
44324
44325 $this->write('### Options:');
44326 foreach ($definition->getOptions() as $option) {
44327 $this->write("\n\n");
44328 $this->write($this->describeInputOption($option));
44329 }
44330 }
44331 }
44332
44333
44334
44335
44336 protected function describeCommand(Command $command, array $options = array())
44337 {
44338 $command->getSynopsis();
44339 $command->mergeApplicationDefinition(false);
44340
44341 $this->write(
44342 $command->getName()."\n"
44343 .str_repeat('-', strlen($command->getName()))."\n\n"
44344 .'* Description: '.($command->getDescription() ?: '<none>')."\n"
44345 .'* Usage: `'.$command->getSynopsis().'`'."\n"
44346 .'* Aliases: '.(count($command->getAliases()) ? '`'.implode('`, `', $command->getAliases()).'`' : '<none>')
44347 );
44348
44349 if ($help = $command->getProcessedHelp()) {
44350 $this->write("\n\n");
44351 $this->write($help);
44352 }
44353
44354 if ($definition = $command->getNativeDefinition()) {
44355 $this->write("\n\n");
44356 $this->describeInputDefinition($command->getNativeDefinition());
44357 }
44358 }
44359
44360
44361
44362
44363 protected function describeApplication(Application $application, array $options = array())
44364 {
44365 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
44366 $description = new ApplicationDescription($application, $describedNamespace);
44367
44368 $this->write($application->getName()."\n".str_repeat('=', strlen($application->getName())));
44369
44370 foreach ($description->getNamespaces() as $namespace) {
44371 if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
44372 $this->write("\n\n");
44373 $this->write('**'.$namespace['id'].':**');
44374 }
44375
44376 $this->write("\n\n");
44377 $this->write(implode("\n", array_map(function ($commandName) {
44378 return '* '.$commandName;
44379 }, $namespace['commands'])));
44380 }
44381
44382 foreach ($description->getCommands() as $command) {
44383 $this->write("\n\n");
44384 $this->write($this->describeCommand($command));
44385 }
44386 }
44387 }
44388 <?php
44389
44390
44391
44392
44393
44394
44395
44396
44397
44398
44399 namespace Symfony\Component\Console\Descriptor;
44400
44401 use Symfony\Component\Console\Application;
44402 use Symfony\Component\Console\Command\Command;
44403
44404
44405
44406
44407 class ApplicationDescription
44408 {
44409 const GLOBAL_NAMESPACE = '_global';
44410
44411
44412
44413
44414 private $application;
44415
44416
44417
44418
44419 private $namespace;
44420
44421
44422
44423
44424 private $namespaces;
44425
44426
44427
44428
44429 private $commands;
44430
44431
44432
44433
44434 private $aliases;
44435
44436
44437
44438
44439
44440
44441
44442 public function __construct(Application $application, $namespace = null)
44443 {
44444 $this->application = $application;
44445 $this->namespace = $namespace;
44446 }
44447
44448
44449
44450
44451 public function getNamespaces()
44452 {
44453 if (null === $this->namespaces) {
44454 $this->inspectApplication();
44455 }
44456
44457 return $this->namespaces;
44458 }
44459
44460
44461
44462
44463 public function getCommands()
44464 {
44465 if (null === $this->commands) {
44466 $this->inspectApplication();
44467 }
44468
44469 return $this->commands;
44470 }
44471
44472
44473
44474
44475
44476
44477
44478
44479 public function getCommand($name)
44480 {
44481 if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) {
44482 throw new \InvalidArgumentException(sprintf('Command %s does not exist.', $name));
44483 }
44484
44485 return isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name];
44486 }
44487
44488 private function inspectApplication()
44489 {
44490 $this->commands = array();
44491 $this->namespaces = array();
44492
44493 $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null);
44494 foreach ($this->sortCommands($all) as $namespace => $commands) {
44495 $names = array();
44496
44497
44498 foreach ($commands as $name => $command) {
44499 if (!$command->getName()) {
44500 continue;
44501 }
44502
44503 if ($command->getName() === $name) {
44504 $this->commands[$name] = $command;
44505 } else {
44506 $this->aliases[$name] = $command;
44507 }
44508
44509 $names[] = $name;
44510 }
44511
44512 $this->namespaces[$namespace] = array('id' => $namespace, 'commands' => $names);
44513 }
44514 }
44515
44516
44517
44518
44519
44520
44521 private function sortCommands(array $commands)
44522 {
44523 $namespacedCommands = array();
44524 foreach ($commands as $name => $command) {
44525 $key = $this->application->extractNamespace($name, 1);
44526 if (!$key) {
44527 $key = '_global';
44528 }
44529
44530 $namespacedCommands[$key][$name] = $command;
44531 }
44532 ksort($namespacedCommands);
44533
44534 foreach ($namespacedCommands as &$commands) {
44535 ksort($commands);
44536 }
44537
44538 return $namespacedCommands;
44539 }
44540 }
44541 <?php
44542
44543
44544
44545
44546
44547
44548
44549
44550
44551
44552 namespace Symfony\Component\Console\Descriptor;
44553
44554 use Symfony\Component\Console\Application;
44555 use Symfony\Component\Console\Command\Command;
44556 use Symfony\Component\Console\Input\InputArgument;
44557 use Symfony\Component\Console\Input\InputDefinition;
44558 use Symfony\Component\Console\Input\InputOption;
44559 use Symfony\Component\Console\Output\OutputInterface;
44560
44561
44562
44563
44564 abstract class Descriptor implements DescriptorInterface
44565 {
44566
44567
44568
44569 private $output;
44570
44571
44572
44573
44574 public function describe(OutputInterface $output, $object, array $options = array())
44575 {
44576 $this->output = $output;
44577
44578 switch (true) {
44579 case $object instanceof InputArgument:
44580 $this->describeInputArgument($object, $options);
44581 break;
44582 case $object instanceof InputOption:
44583 $this->describeInputOption($object, $options);
44584 break;
44585 case $object instanceof InputDefinition:
44586 $this->describeInputDefinition($object, $options);
44587 break;
44588 case $object instanceof Command:
44589 $this->describeCommand($object, $options);
44590 break;
44591 case $object instanceof Application:
44592 $this->describeApplication($object, $options);
44593 break;
44594 default:
44595 throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_class($object)));
44596 }
44597 }
44598
44599
44600
44601
44602
44603
44604
44605 protected function write($content, $decorated = false)
44606 {
44607 $this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
44608 }
44609
44610
44611
44612
44613
44614
44615
44616
44617
44618 abstract protected function describeInputArgument(InputArgument $argument, array $options = array());
44619
44620
44621
44622
44623
44624
44625
44626
44627
44628 abstract protected function describeInputOption(InputOption $option, array $options = array());
44629
44630
44631
44632
44633
44634
44635
44636
44637
44638 abstract protected function describeInputDefinition(InputDefinition $definition, array $options = array());
44639
44640
44641
44642
44643
44644
44645
44646
44647
44648 abstract protected function describeCommand(Command $command, array $options = array());
44649
44650
44651
44652
44653
44654
44655
44656
44657
44658 abstract protected function describeApplication(Application $application, array $options = array());
44659 }
44660 <?php
44661
44662
44663
44664
44665
44666
44667
44668
44669
44670
44671 namespace Symfony\Component\Console\Descriptor;
44672
44673 use Symfony\Component\Console\Application;
44674 use Symfony\Component\Console\Command\Command;
44675 use Symfony\Component\Console\Input\InputArgument;
44676 use Symfony\Component\Console\Input\InputDefinition;
44677 use Symfony\Component\Console\Input\InputOption;
44678
44679
44680
44681
44682
44683
44684 class JsonDescriptor extends Descriptor
44685 {
44686
44687
44688
44689 protected function describeInputArgument(InputArgument $argument, array $options = array())
44690 {
44691 $this->writeData($this->getInputArgumentData($argument), $options);
44692 }
44693
44694
44695
44696
44697 protected function describeInputOption(InputOption $option, array $options = array())
44698 {
44699 $this->writeData($this->getInputOptionData($option), $options);
44700 }
44701
44702
44703
44704
44705 protected function describeInputDefinition(InputDefinition $definition, array $options = array())
44706 {
44707 $this->writeData($this->getInputDefinitionData($definition), $options);
44708 }
44709
44710
44711
44712
44713 protected function describeCommand(Command $command, array $options = array())
44714 {
44715 $this->writeData($this->getCommandData($command), $options);
44716 }
44717
44718
44719
44720
44721 protected function describeApplication(Application $application, array $options = array())
44722 {
44723 $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null;
44724 $description = new ApplicationDescription($application, $describedNamespace);
44725 $commands = array();
44726
44727 foreach ($description->getCommands() as $command) {
44728 $commands[] = $this->getCommandData($command);
44729 }
44730
44731 $data = $describedNamespace
44732 ? array('commands' => $commands, 'namespace' => $describedNamespace)
44733 : array('commands' => $commands, 'namespaces' => array_values($description->getNamespaces()));
44734
44735 $this->writeData($data, $options);
44736 }
44737
44738
44739
44740
44741
44742
44743
44744
44745
44746 private function writeData(array $data, array $options)
44747 {
44748 $this->write(json_encode($data, isset($options['json_encoding']) ? $options['json_encoding'] : 0));
44749 }
44750
44751
44752
44753
44754
44755
44756 private function getInputArgumentData(InputArgument $argument)
44757 {
44758 return array(
44759 'name' => $argument->getName(),
44760 'is_required' => $argument->isRequired(),
44761 'is_array' => $argument->isArray(),
44762 'description' => $argument->getDescription(),
44763 'default' => $argument->getDefault(),
44764 );
44765 }
44766
44767
44768
44769
44770
44771
44772 private function getInputOptionData(InputOption $option)
44773 {
44774 return array(
44775 'name' => '--'.$option->getName(),
44776 'shortcut' => $option->getShortcut() ? '-'.implode('|-', explode('|', $option->getShortcut())) : '',
44777 'accept_value' => $option->acceptValue(),
44778 'is_value_required' => $option->isValueRequired(),
44779 'is_multiple' => $option->isArray(),
44780 'description' => $option->getDescription(),
44781 'default' => $option->getDefault(),
44782 );
44783 }
44784
44785
44786
44787
44788
44789
44790 private function getInputDefinitionData(InputDefinition $definition)
44791 {
44792 $inputArguments = array();
44793 foreach ($definition->getArguments() as $name => $argument) {
44794 $inputArguments[$name] = $this->getInputArgumentData($argument);
44795 }
44796
44797 $inputOptions = array();
44798 foreach ($definition->getOptions() as $name => $option) {
44799 $inputOptions[$name] = $this->getInputOptionData($option);
44800 }
44801
44802 return array('arguments' => $inputArguments, 'options' => $inputOptions);
44803 }
44804
44805
44806
44807
44808
44809
44810 private function getCommandData(Command $command)
44811 {
44812 $command->getSynopsis();
44813 $command->mergeApplicationDefinition(false);
44814
44815 return array(
44816 'name' => $command->getName(),
44817 'usage' => $command->getSynopsis(),
44818 'description' => $command->getDescription(),
44819 'help' => $command->getProcessedHelp(),
44820 'aliases' => $command->getAliases(),
44821 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
44822 );
44823 }
44824 }
44825 <?php
44826
44827
44828
44829
44830
44831
44832
44833
44834
44835
44836 namespace Symfony\Component\Console\Helper;
44837
44838
44839
44840
44841
44842
44843
44844
44845 interface HelperInterface
44846 {
44847
44848
44849
44850
44851
44852
44853
44854 public function setHelperSet(HelperSet $helperSet = null);
44855
44856
44857
44858
44859
44860
44861
44862
44863 public function getHelperSet();
44864
44865
44866
44867
44868
44869
44870
44871
44872 public function getName();
44873 }
44874 <?php
44875
44876
44877
44878
44879
44880
44881
44882
44883
44884
44885 namespace Symfony\Component\Console\Helper;
44886
44887 use Symfony\Component\Console\Output\OutputInterface;
44888 use Symfony\Component\Console\Output\NullOutput;
44889
44890
44891
44892
44893
44894
44895
44896
44897
44898 class TableHelper extends Helper
44899 {
44900 const LAYOUT_DEFAULT = 0;
44901 const LAYOUT_BORDERLESS = 1;
44902 const LAYOUT_COMPACT = 2;
44903
44904
44905
44906
44907 private $table;
44908
44909 public function __construct()
44910 {
44911 $this->table = new Table(new NullOutput());
44912 }
44913
44914
44915
44916
44917
44918
44919
44920
44921
44922
44923 public function setLayout($layout)
44924 {
44925 switch ($layout) {
44926 case self::LAYOUT_BORDERLESS:
44927 $this->table->setStyle('borderless');
44928 break;
44929
44930 case self::LAYOUT_COMPACT:
44931 $this->table->setStyle('compact');
44932 break;
44933
44934 case self::LAYOUT_DEFAULT:
44935 $this->table->setStyle('default');
44936 break;
44937
44938 default:
44939 throw new \InvalidArgumentException(sprintf('Invalid table layout "%s".', $layout));
44940 break;
44941 };
44942
44943 return $this;
44944 }
44945
44946 public function setHeaders(array $headers)
44947 {
44948 $this->table->setHeaders($headers);
44949
44950 return $this;
44951 }
44952
44953 public function setRows(array $rows)
44954 {
44955 $this->table->setRows($rows);
44956
44957 return $this;
44958 }
44959
44960 public function addRows(array $rows)
44961 {
44962 $this->table->addRows($rows);
44963
44964 return $this;
44965 }
44966
44967 public function addRow(array $row)
44968 {
44969 $this->table->addRow($row);
44970
44971 return $this;
44972 }
44973
44974 public function setRow($column, array $row)
44975 {
44976 $this->table->setRow($column, $row);
44977
44978 return $this;
44979 }
44980
44981
44982
44983
44984
44985
44986
44987
44988 public function setPaddingChar($paddingChar)
44989 {
44990 $this->table->getStyle()->setPaddingChar($paddingChar);
44991
44992 return $this;
44993 }
44994
44995
44996
44997
44998
44999
45000
45001
45002 public function setHorizontalBorderChar($horizontalBorderChar)
45003 {
45004 $this->table->getStyle()->setHorizontalBorderChar($horizontalBorderChar);
45005
45006 return $this;
45007 }
45008
45009
45010
45011
45012
45013
45014
45015
45016 public function setVerticalBorderChar($verticalBorderChar)
45017 {
45018 $this->table->getStyle()->setVerticalBorderChar($verticalBorderChar);
45019
45020 return $this;
45021 }
45022
45023
45024
45025
45026
45027
45028
45029
45030 public function setCrossingChar($crossingChar)
45031 {
45032 $this->table->getStyle()->setCrossingChar($crossingChar);
45033
45034 return $this;
45035 }
45036
45037
45038
45039
45040
45041
45042
45043
45044 public function setCellHeaderFormat($cellHeaderFormat)
45045 {
45046 $this->table->getStyle()->setCellHeaderFormat($cellHeaderFormat);
45047
45048 return $this;
45049 }
45050
45051
45052
45053
45054
45055
45056
45057
45058 public function setCellRowFormat($cellRowFormat)
45059 {
45060 $this->table->getStyle()->setCellHeaderFormat($cellRowFormat);
45061
45062 return $this;
45063 }
45064
45065
45066
45067
45068
45069
45070
45071
45072 public function setCellRowContentFormat($cellRowContentFormat)
45073 {
45074 $this->table->getStyle()->setCellRowContentFormat($cellRowContentFormat);
45075
45076 return $this;
45077 }
45078
45079
45080
45081
45082
45083
45084
45085
45086 public function setBorderFormat($borderFormat)
45087 {
45088 $this->table->getStyle()->setBorderFormat($borderFormat);
45089
45090 return $this;
45091 }
45092
45093
45094
45095
45096
45097
45098
45099
45100 public function setPadType($padType)
45101 {
45102 $this->table->getStyle()->setPadType($padType);
45103
45104 return $this;
45105 }
45106
45107
45108
45109
45110
45111
45112
45113
45114
45115
45116
45117
45118
45119
45120
45121 public function render(OutputInterface $output)
45122 {
45123 $p = new \ReflectionProperty($this->table, 'output');
45124 $p->setAccessible(true);
45125 $p->setValue($this->table, $output);
45126
45127 $this->table->render();
45128 }
45129
45130
45131
45132
45133 public function getName()
45134 {
45135 return 'table';
45136 }
45137 }
45138 <?php
45139
45140
45141
45142
45143
45144
45145
45146
45147
45148
45149 namespace Symfony\Component\Console\Helper;
45150
45151 use Symfony\Component\Console\Output\OutputInterface;
45152
45153
45154
45155
45156
45157
45158
45159 class Table
45160 {
45161
45162
45163
45164
45165
45166 private $headers = array();
45167
45168
45169
45170
45171
45172
45173 private $rows = array();
45174
45175
45176
45177
45178
45179
45180 private $columnWidths = array();
45181
45182
45183
45184
45185
45186
45187 private $numberOfColumns;
45188
45189
45190
45191
45192 private $output;
45193
45194
45195
45196
45197 private $style;
45198
45199 private static $styles;
45200
45201 public function __construct(OutputInterface $output)
45202 {
45203 $this->output = $output;
45204
45205 if (!self::$styles) {
45206 self::$styles = self::initStyles();
45207 }
45208
45209 $this->setStyle('default');
45210 }
45211
45212
45213
45214
45215
45216
45217
45218 public static function setStyleDefinition($name, TableStyle $style)
45219 {
45220 if (!self::$styles) {
45221 self::$styles = self::initStyles();
45222 }
45223
45224 self::$styles[$name] = $style;
45225 }
45226
45227
45228
45229
45230
45231
45232
45233
45234 public static function getStyleDefinition($name)
45235 {
45236 if (!self::$styles) {
45237 self::$styles = self::initStyles();
45238 }
45239
45240 if (!self::$styles[$name]) {
45241 throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
45242 }
45243
45244 return self::$styles[$name];
45245 }
45246
45247
45248
45249
45250
45251
45252
45253
45254 public function setStyle($name)
45255 {
45256 if ($name instanceof TableStyle) {
45257 $this->style = $name;
45258 } elseif (isset(self::$styles[$name])) {
45259 $this->style = self::$styles[$name];
45260 } else {
45261 throw new \InvalidArgumentException(sprintf('Style "%s" is not defined.', $name));
45262 }
45263
45264 return $this;
45265 }
45266
45267
45268
45269
45270
45271
45272 public function getStyle()
45273 {
45274 return $this->style;
45275 }
45276
45277 public function setHeaders(array $headers)
45278 {
45279 $this->headers = array_values($headers);
45280
45281 return $this;
45282 }
45283
45284 public function setRows(array $rows)
45285 {
45286 $this->rows = array();
45287
45288 return $this->addRows($rows);
45289 }
45290
45291 public function addRows(array $rows)
45292 {
45293 foreach ($rows as $row) {
45294 $this->addRow($row);
45295 }
45296
45297 return $this;
45298 }
45299
45300 public function addRow($row)
45301 {
45302 if ($row instanceof TableSeparator) {
45303 $this->rows[] = $row;
45304
45305 return;
45306 }
45307
45308 if (!is_array($row)) {
45309 throw new \InvalidArgumentException('A row must be an array or a TableSeparator instance.');
45310 }
45311
45312 $this->rows[] = array_values($row);
45313
45314 $keys = array_keys($this->rows);
45315 $rowKey = array_pop($keys);
45316
45317 foreach ($row as $key => $cellValue) {
45318 if (!strstr($cellValue, "\n")) {
45319 continue;
45320 }
45321
45322 $lines = explode("\n", $cellValue);
45323 $this->rows[$rowKey][$key] = $lines[0];
45324 unset($lines[0]);
45325
45326 foreach ($lines as $lineKey => $line) {
45327 $nextRowKey = $rowKey + $lineKey + 1;
45328
45329 if (isset($this->rows[$nextRowKey])) {
45330 $this->rows[$nextRowKey][$key] = $line;
45331 } else {
45332 $this->rows[$nextRowKey] = array($key => $line);
45333 }
45334 }
45335 }
45336
45337 return $this;
45338 }
45339
45340 public function setRow($column, array $row)
45341 {
45342 $this->rows[$column] = $row;
45343
45344 return $this;
45345 }
45346
45347
45348
45349
45350
45351
45352
45353
45354
45355
45356
45357
45358
45359 public function render()
45360 {
45361 $this->renderRowSeparator();
45362 $this->renderRow($this->headers, $this->style->getCellHeaderFormat());
45363 if (!empty($this->headers)) {
45364 $this->renderRowSeparator();
45365 }
45366 foreach ($this->rows as $row) {
45367 if ($row instanceof TableSeparator) {
45368 $this->renderRowSeparator();
45369 } else {
45370 $this->renderRow($row, $this->style->getCellRowFormat());
45371 }
45372 }
45373 if (!empty($this->rows)) {
45374 $this->renderRowSeparator();
45375 }
45376
45377 $this->cleanup();
45378 }
45379
45380
45381
45382
45383
45384
45385 private function renderRowSeparator()
45386 {
45387 if (0 === $count = $this->getNumberOfColumns()) {
45388 return;
45389 }
45390
45391 if (!$this->style->getHorizontalBorderChar() && !$this->style->getCrossingChar()) {
45392 return;
45393 }
45394
45395 $markup = $this->style->getCrossingChar();
45396 for ($column = 0; $column < $count; $column++) {
45397 $markup .= str_repeat($this->style->getHorizontalBorderChar(), $this->getColumnWidth($column)).$this->style->getCrossingChar();
45398 }
45399
45400 $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup));
45401 }
45402
45403
45404
45405
45406 private function renderColumnSeparator()
45407 {
45408 $this->output->write(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
45409 }
45410
45411
45412
45413
45414
45415
45416
45417
45418
45419 private function renderRow(array $row, $cellFormat)
45420 {
45421 if (empty($row)) {
45422 return;
45423 }
45424
45425 $this->renderColumnSeparator();
45426 for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) {
45427 $this->renderCell($row, $column, $cellFormat);
45428 $this->renderColumnSeparator();
45429 }
45430 $this->output->writeln('');
45431 }
45432
45433
45434
45435
45436
45437
45438
45439
45440 private function renderCell(array $row, $column, $cellFormat)
45441 {
45442 $cell = isset($row[$column]) ? $row[$column] : '';
45443 $width = $this->getColumnWidth($column);
45444
45445
45446  if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($cell)) {
45447 $width += strlen($cell) - mb_strlen($cell, $encoding);
45448 }
45449
45450 $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
45451
45452 $content = sprintf($this->style->getCellRowContentFormat(), $cell);
45453
45454 $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType())));
45455 }
45456
45457
45458
45459
45460
45461
45462 private function getNumberOfColumns()
45463 {
45464 if (null !== $this->numberOfColumns) {
45465 return $this->numberOfColumns;
45466 }
45467
45468 $columns = array(count($this->headers));
45469 foreach ($this->rows as $row) {
45470 $columns[] = count($row);
45471 }
45472
45473 return $this->numberOfColumns = max($columns);
45474 }
45475
45476
45477
45478
45479
45480
45481
45482
45483 private function getColumnWidth($column)
45484 {
45485 if (isset($this->columnWidths[$column])) {
45486 return $this->columnWidths[$column];
45487 }
45488
45489 $lengths = array($this->getCellWidth($this->headers, $column));
45490 foreach ($this->rows as $row) {
45491 if ($row instanceof TableSeparator) {
45492 continue;
45493 }
45494
45495 $lengths[] = $this->getCellWidth($row, $column);
45496 }
45497
45498 return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
45499 }
45500
45501
45502
45503
45504
45505
45506
45507
45508
45509 private function getCellWidth(array $row, $column)
45510 {
45511 return isset($row[$column]) ? Helper::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0;
45512 }
45513
45514
45515
45516
45517 private function cleanup()
45518 {
45519 $this->columnWidths = array();
45520 $this->numberOfColumns = null;
45521 }
45522
45523 private static function initStyles()
45524 {
45525 $borderless = new TableStyle();
45526 $borderless
45527 ->setHorizontalBorderChar('=')
45528 ->setVerticalBorderChar(' ')
45529 ->setCrossingChar(' ')
45530 ;
45531
45532 $compact = new TableStyle();
45533 $compact
45534 ->setHorizontalBorderChar('')
45535 ->setVerticalBorderChar(' ')
45536 ->setCrossingChar('')
45537 ->setCellRowContentFormat('%s')
45538 ;
45539
45540 return array(
45541 'default' => new TableStyle(),
45542 'borderless' => $borderless,
45543 'compact' => $compact,
45544 );
45545 }
45546 }
45547 <?php
45548
45549
45550
45551
45552
45553
45554
45555
45556
45557
45558 namespace Symfony\Component\Console\Helper;
45559
45560 use Symfony\Component\Console\Output\OutputInterface;
45561
45562
45563
45564
45565
45566
45567
45568 class ProgressBar
45569 {
45570
45571  private $barWidth = 28;
45572 private $barChar;
45573 private $emptyBarChar = '-';
45574 private $progressChar = '>';
45575 private $format = null;
45576 private $redrawFreq = 1;
45577
45578
45579
45580
45581 private $output;
45582 private $step = 0;
45583 private $max;
45584 private $startTime;
45585 private $stepWidth;
45586 private $percent = 0.0;
45587 private $lastMessagesLength = 0;
45588 private $formatLineCount;
45589 private $messages;
45590 private $overwrite = true;
45591
45592 private static $formatters;
45593 private static $formats;
45594
45595
45596
45597
45598
45599
45600
45601 public function __construct(OutputInterface $output, $max = 0)
45602 {
45603 $this->output = $output;
45604 $this->setMaxSteps($max);
45605
45606 if (!$this->output->isDecorated()) {
45607
45608  $this->overwrite = false;
45609
45610 if ($this->max > 10) {
45611
45612  $this->setRedrawFrequency($max / 10);
45613 }
45614 }
45615
45616 $this->setFormat($this->determineBestFormat());
45617
45618 $this->startTime = time();
45619 }
45620
45621
45622
45623
45624
45625
45626
45627
45628
45629 public static function setPlaceholderFormatterDefinition($name, $callable)
45630 {
45631 if (!self::$formatters) {
45632 self::$formatters = self::initPlaceholderFormatters();
45633 }
45634
45635 self::$formatters[$name] = $callable;
45636 }
45637
45638
45639
45640
45641
45642
45643
45644
45645 public static function getPlaceholderFormatterDefinition($name)
45646 {
45647 if (!self::$formatters) {
45648 self::$formatters = self::initPlaceholderFormatters();
45649 }
45650
45651 return isset(self::$formatters[$name]) ? self::$formatters[$name] : null;
45652 }
45653
45654
45655
45656
45657
45658
45659
45660
45661
45662 public static function setFormatDefinition($name, $format)
45663 {
45664 if (!self::$formats) {
45665 self::$formats = self::initFormats();
45666 }
45667
45668 self::$formats[$name] = $format;
45669 }
45670
45671
45672
45673
45674
45675
45676
45677
45678 public static function getFormatDefinition($name)
45679 {
45680 if (!self::$formats) {
45681 self::$formats = self::initFormats();
45682 }
45683
45684 return isset(self::$formats[$name]) ? self::$formats[$name] : null;
45685 }
45686
45687 public function setMessage($message, $name = 'message')
45688 {
45689 $this->messages[$name] = $message;
45690 }
45691
45692 public function getMessage($name = 'message')
45693 {
45694 return $this->messages[$name];
45695 }
45696
45697
45698
45699
45700
45701
45702 public function getStartTime()
45703 {
45704 return $this->startTime;
45705 }
45706
45707
45708
45709
45710
45711
45712 public function getMaxSteps()
45713 {
45714 return $this->max;
45715 }
45716
45717
45718
45719
45720
45721
45722
45723
45724 public function getStep()
45725 {
45726 return $this->getProgress();
45727 }
45728
45729
45730
45731
45732
45733
45734 public function getProgress()
45735 {
45736 return $this->step;
45737 }
45738
45739
45740
45741
45742
45743
45744
45745
45746 public function getStepWidth()
45747 {
45748 return $this->stepWidth;
45749 }
45750
45751
45752
45753
45754
45755
45756 public function getProgressPercent()
45757 {
45758 return $this->percent;
45759 }
45760
45761
45762
45763
45764
45765
45766 public function setBarWidth($size)
45767 {
45768 $this->barWidth = (int) $size;
45769 }
45770
45771
45772
45773
45774
45775
45776 public function getBarWidth()
45777 {
45778 return $this->barWidth;
45779 }
45780
45781
45782
45783
45784
45785
45786 public function setBarCharacter($char)
45787 {
45788 $this->barChar = $char;
45789 }
45790
45791
45792
45793
45794
45795
45796 public function getBarCharacter()
45797 {
45798 if (null === $this->barChar) {
45799 return $this->max ? '=' : $this->emptyBarChar;
45800 }
45801
45802 return $this->barChar;
45803 }
45804
45805
45806
45807
45808
45809
45810 public function setEmptyBarCharacter($char)
45811 {
45812 $this->emptyBarChar = $char;
45813 }
45814
45815
45816
45817
45818
45819
45820 public function getEmptyBarCharacter()
45821 {
45822 return $this->emptyBarChar;
45823 }
45824
45825
45826
45827
45828
45829
45830 public function setProgressCharacter($char)
45831 {
45832 $this->progressChar = $char;
45833 }
45834
45835
45836
45837
45838
45839
45840 public function getProgressCharacter()
45841 {
45842 return $this->progressChar;
45843 }
45844
45845
45846
45847
45848
45849
45850 public function setFormat($format)
45851 {
45852
45853  if (!$this->max && null !== self::getFormatDefinition($format.'_nomax')) {
45854 $this->format = self::getFormatDefinition($format.'_nomax');
45855 } elseif (null !== self::getFormatDefinition($format)) {
45856 $this->format = self::getFormatDefinition($format);
45857 } else {
45858 $this->format = $format;
45859 }
45860
45861 $this->formatLineCount = substr_count($this->format, "\n");
45862 }
45863
45864
45865
45866
45867
45868
45869 public function setRedrawFrequency($freq)
45870 {
45871 $this->redrawFreq = (int) $freq;
45872 }
45873
45874
45875
45876
45877
45878
45879 public function start($max = null)
45880 {
45881 $this->startTime = time();
45882 $this->step = 0;
45883 $this->percent = 0.0;
45884
45885 if (null !== $max) {
45886 $this->setMaxSteps($max);
45887 }
45888
45889 $this->display();
45890 }
45891
45892
45893
45894
45895
45896
45897
45898
45899 public function advance($step = 1)
45900 {
45901 $this->setProgress($this->step + $step);
45902 }
45903
45904
45905
45906
45907
45908
45909
45910
45911
45912
45913 public function setCurrent($step)
45914 {
45915 $this->setProgress($step);
45916 }
45917
45918
45919
45920
45921
45922
45923 public function setOverwrite($overwrite)
45924 {
45925 $this->overwrite = (bool) $overwrite;
45926 }
45927
45928
45929
45930
45931
45932
45933
45934
45935 public function setProgress($step)
45936 {
45937 $step = (int) $step;
45938 if ($step < $this->step) {
45939 throw new \LogicException('You can\'t regress the progress bar.');
45940 }
45941
45942 if ($this->max && $step > $this->max) {
45943 $this->max = $step;
45944 }
45945
45946 $prevPeriod = intval($this->step / $this->redrawFreq);
45947 $currPeriod = intval($step / $this->redrawFreq);
45948 $this->step = $step;
45949 $this->percent = $this->max ? (float) $this->step / $this->max : 0;
45950 if ($prevPeriod !== $currPeriod || $this->max === $step) {
45951 $this->display();
45952 }
45953 }
45954
45955
45956
45957
45958 public function finish()
45959 {
45960 if (!$this->max) {
45961 $this->max = $this->step;
45962 }
45963
45964 if ($this->step === $this->max && !$this->overwrite) {
45965
45966  return;
45967 }
45968
45969 $this->setProgress($this->max);
45970 }
45971
45972
45973
45974
45975 public function display()
45976 {
45977 if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
45978 return;
45979 }
45980
45981
45982  $self = $this;
45983 $output = $this->output;
45984 $messages = $this->messages;
45985 $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) {
45986 if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
45987 $text = call_user_func($formatter, $self, $output);
45988 } elseif (isset($messages[$matches[1]])) {
45989 $text = $messages[$matches[1]];
45990 } else {
45991 return $matches[0];
45992 }
45993
45994 if (isset($matches[2])) {
45995 $text = sprintf('%'.$matches[2], $text);
45996 }
45997
45998 return $text;
45999 }, $this->format));
46000 }
46001
46002
46003
46004
46005
46006
46007
46008
46009 public function clear()
46010 {
46011 if (!$this->overwrite) {
46012 return;
46013 }
46014
46015 $this->overwrite(str_repeat("\n", $this->formatLineCount));
46016 }
46017
46018
46019
46020
46021
46022
46023 private function setMaxSteps($max)
46024 {
46025 $this->max = max(0, (int) $max);
46026 $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4;
46027 }
46028
46029
46030
46031
46032
46033
46034 private function overwrite($message)
46035 {
46036 $lines = explode("\n", $message);
46037
46038
46039  if (null !== $this->lastMessagesLength) {
46040 foreach ($lines as $i => $line) {
46041 if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $line)) {
46042 $lines[$i] = str_pad($line, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
46043 }
46044 }
46045 }
46046
46047 if ($this->overwrite) {
46048
46049  $this->output->write("\x0D");
46050 } elseif ($this->step > 0) {
46051
46052  $this->output->writeln('');
46053 }
46054
46055 if ($this->formatLineCount) {
46056 $this->output->write(sprintf("\033[%dA", $this->formatLineCount));
46057 }
46058 $this->output->write(implode("\n", $lines));
46059
46060 $this->lastMessagesLength = 0;
46061 foreach ($lines as $line) {
46062 $len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line);
46063 if ($len > $this->lastMessagesLength) {
46064 $this->lastMessagesLength = $len;
46065 }
46066 }
46067 }
46068
46069 private function determineBestFormat()
46070 {
46071 switch ($this->output->getVerbosity()) {
46072
46073  case OutputInterface::VERBOSITY_VERBOSE:
46074 return $this->max ? 'verbose' : 'verbose_nomax';
46075 case OutputInterface::VERBOSITY_VERY_VERBOSE:
46076 return $this->max ? 'very_verbose' : 'very_verbose_nomax';
46077 case OutputInterface::VERBOSITY_DEBUG:
46078 return $this->max ? 'debug' : 'debug_nomax';
46079 default:
46080 return $this->max ? 'normal' : 'normal_nomax';
46081 }
46082 }
46083
46084 private static function initPlaceholderFormatters()
46085 {
46086 return array(
46087 'bar' => function (ProgressBar $bar, OutputInterface $output) {
46088 $completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getProgress() % $bar->getBarWidth());
46089 $display = str_repeat($bar->getBarCharacter(), $completeBars);
46090 if ($completeBars < $bar->getBarWidth()) {
46091 $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
46092 $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
46093 }
46094
46095 return $display;
46096 },
46097 'elapsed' => function (ProgressBar $bar) {
46098 return Helper::formatTime(time() - $bar->getStartTime());
46099 },
46100 'remaining' => function (ProgressBar $bar) {
46101 if (!$bar->getMaxSteps()) {
46102 throw new \LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
46103 }
46104
46105 if (!$bar->getProgress()) {
46106 $remaining = 0;
46107 } else {
46108 $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
46109 }
46110
46111 return Helper::formatTime($remaining);
46112 },
46113 'estimated' => function (ProgressBar $bar) {
46114 if (!$bar->getMaxSteps()) {
46115 throw new \LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
46116 }
46117
46118 if (!$bar->getProgress()) {
46119 $estimated = 0;
46120 } else {
46121 $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
46122 }
46123
46124 return Helper::formatTime($estimated);
46125 },
46126 'memory' => function (ProgressBar $bar) {
46127 return Helper::formatMemory(memory_get_usage(true));
46128 },
46129 'current' => function (ProgressBar $bar) {
46130 return str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', STR_PAD_LEFT);
46131 },
46132 'max' => function (ProgressBar $bar) {
46133 return $bar->getMaxSteps();
46134 },
46135 'percent' => function (ProgressBar $bar) {
46136 return floor($bar->getProgressPercent() * 100);
46137 },
46138 );
46139 }
46140
46141 private static function initFormats()
46142 {
46143 return array(
46144 'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
46145 'normal_nomax' => ' %current% [%bar%]',
46146
46147 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
46148 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
46149
46150 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
46151 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
46152
46153 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
46154 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
46155 );
46156 }
46157 }
46158 <?php
46159
46160
46161
46162
46163
46164
46165
46166
46167
46168
46169 namespace Symfony\Component\Console\Helper;
46170
46171 use Symfony\Component\Console\Descriptor\DescriptorInterface;
46172 use Symfony\Component\Console\Descriptor\JsonDescriptor;
46173 use Symfony\Component\Console\Descriptor\MarkdownDescriptor;
46174 use Symfony\Component\Console\Descriptor\TextDescriptor;
46175 use Symfony\Component\Console\Descriptor\XmlDescriptor;
46176 use Symfony\Component\Console\Output\OutputInterface;
46177
46178
46179
46180
46181
46182
46183 class DescriptorHelper extends Helper
46184 {
46185
46186
46187
46188 private $descriptors = array();
46189
46190
46191
46192
46193 public function __construct()
46194 {
46195 $this
46196 ->register('txt', new TextDescriptor())
46197 ->register('xml', new XmlDescriptor())
46198 ->register('json', new JsonDescriptor())
46199 ->register('md', new MarkdownDescriptor())
46200 ;
46201 }
46202
46203
46204
46205
46206
46207
46208
46209
46210
46211
46212
46213
46214
46215
46216 public function describe(OutputInterface $output, $object, array $options = array())
46217 {
46218 $options = array_merge(array(
46219 'raw_text' => false,
46220 'format' => 'txt',
46221 ), $options);
46222
46223 if (!isset($this->descriptors[$options['format']])) {
46224 throw new \InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format']));
46225 }
46226
46227 $descriptor = $this->descriptors[$options['format']];
46228 $descriptor->describe($output, $object, $options);
46229 }
46230
46231
46232
46233
46234
46235
46236
46237
46238
46239 public function register($format, DescriptorInterface $descriptor)
46240 {
46241 $this->descriptors[$format] = $descriptor;
46242
46243 return $this;
46244 }
46245
46246
46247
46248
46249 public function getName()
46250 {
46251 return 'descriptor';
46252 }
46253 }
46254 <?php
46255
46256
46257
46258
46259
46260
46261
46262
46263
46264
46265 namespace Symfony\Component\Console\Helper;
46266
46267 use Symfony\Component\Console\Formatter\OutputFormatter;
46268
46269
46270
46271
46272
46273
46274 class FormatterHelper extends Helper
46275 {
46276
46277
46278
46279
46280
46281
46282
46283
46284
46285 public function formatSection($section, $message, $style = 'info')
46286 {
46287 return sprintf('<%s>[%s]</%s> %s', $style, $section, $style, $message);
46288 }
46289
46290
46291
46292
46293
46294
46295
46296
46297
46298
46299 public function formatBlock($messages, $style, $large = false)
46300 {
46301 $messages = (array) $messages;
46302
46303 $len = 0;
46304 $lines = array();
46305 foreach ($messages as $message) {
46306 $message = OutputFormatter::escape($message);
46307 $lines[] = sprintf($large ? '  %s  ' : ' %s ', $message);
46308 $len = max($this->strlen($message) + ($large ? 4 : 2), $len);
46309 }
46310
46311 $messages = $large ? array(str_repeat(' ', $len)) : array();
46312 foreach ($lines as $line) {
46313 $messages[] = $line.str_repeat(' ', $len - $this->strlen($line));
46314 }
46315 if ($large) {
46316 $messages[] = str_repeat(' ', $len);
46317 }
46318
46319 foreach ($messages as &$message) {
46320 $message = sprintf('<%s>%s</%s>', $style, $message, $style);
46321 }
46322
46323 return implode("\n", $messages);
46324 }
46325
46326
46327
46328
46329 public function getName()
46330 {
46331 return 'formatter';
46332 }
46333 }
46334 <?php
46335
46336
46337
46338
46339
46340
46341
46342
46343
46344
46345 namespace Symfony\Component\Console\Helper;
46346
46347
46348
46349
46350
46351
46352
46353
46354 class DebugFormatterHelper extends Helper
46355 {
46356 private $colors = array('black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white');
46357 private $started = array();
46358 private $count = -1;
46359
46360
46361
46362
46363
46364
46365
46366
46367
46368
46369 public function start($id, $message, $prefix = 'RUN')
46370 {
46371 $this->started[$id] = array('border' => ++$this->count % count($this->colors));
46372
46373 return sprintf("%s<bg=blue;fg=white> %s </> <fg=blue>%s</>\n", $this->getBorder($id), $prefix, $message);
46374 }
46375
46376
46377
46378
46379
46380
46381
46382
46383
46384
46385
46386
46387 public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
46388 {
46389 $message = '';
46390
46391 if ($error) {
46392 if (isset($this->started[$id]['out'])) {
46393 $message .= "\n";
46394 unset($this->started[$id]['out']);
46395 }
46396 if (!isset($this->started[$id]['err'])) {
46397 $message .= sprintf("%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix);
46398 $this->started[$id]['err'] = true;
46399 }
46400
46401 $message .= str_replace("\n", sprintf("\n%s<bg=red;fg=white> %s </> ", $this->getBorder($id), $errorPrefix), $buffer);
46402 } else {
46403 if (isset($this->started[$id]['err'])) {
46404 $message .= "\n";
46405 unset($this->started[$id]['err']);
46406 }
46407 if (!isset($this->started[$id]['out'])) {
46408 $message .= sprintf("%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix);
46409 $this->started[$id]['out'] = true;
46410 }
46411
46412 $message .= str_replace("\n", sprintf("\n%s<bg=green;fg=white> %s </> ", $this->getBorder($id), $prefix), $buffer);
46413 }
46414
46415 return $message;
46416 }
46417
46418
46419
46420
46421
46422
46423
46424
46425
46426
46427
46428 public function stop($id, $message, $successful, $prefix = 'RES')
46429 {
46430 $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
46431
46432 if ($successful) {
46433 return sprintf("%s%s<bg=green;fg=white> %s </> <fg=green>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
46434 }
46435
46436 $message = sprintf("%s%s<bg=red;fg=white> %s </> <fg=red>%s</>\n", $trailingEOL, $this->getBorder($id), $prefix, $message);
46437
46438 unset($this->started[$id]['out'], $this->started[$id]['err']);
46439
46440 return $message;
46441 }
46442
46443
46444
46445
46446
46447
46448 private function getBorder($id)
46449 {
46450 return sprintf('<bg=%s> </>', $this->colors[$this->started[$id]['border']]);
46451 }
46452
46453
46454
46455
46456 public function getName()
46457 {
46458 return 'debug_formatter';
46459 }
46460 }
46461 <?php
46462
46463
46464
46465
46466
46467
46468
46469
46470
46471
46472 namespace Symfony\Component\Console\Helper;
46473
46474 use Symfony\Component\Console\Output\OutputInterface;
46475 use Symfony\Component\Process\Exception\ProcessFailedException;
46476 use Symfony\Component\Process\Process;
46477 use Symfony\Component\Process\ProcessBuilder;
46478
46479
46480
46481
46482
46483
46484 class ProcessHelper extends Helper
46485 {
46486
46487
46488
46489
46490
46491
46492
46493
46494
46495
46496
46497
46498 public function run(OutputInterface $output, $cmd, $error = null, $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
46499 {
46500 $formatter = $this->getHelperSet()->get('debug_formatter');
46501
46502 if (is_array($cmd)) {
46503 $process = ProcessBuilder::create($cmd)->getProcess();
46504 } elseif ($cmd instanceof Process) {
46505 $process = $cmd;
46506 } else {
46507 $process = new Process($cmd);
46508 }
46509
46510 if ($verbosity <= $output->getVerbosity()) {
46511 $output->write($formatter->start(spl_object_hash($process), $this->escapeString($process->getCommandLine())));
46512 }
46513
46514 if ($output->isDebug()) {
46515 $callback = $this->wrapCallback($output, $process, $callback);
46516 }
46517
46518 $process->run($callback);
46519
46520 if ($verbosity <= $output->getVerbosity()) {
46521 $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode());
46522 $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful()));
46523 }
46524
46525 if (!$process->isSuccessful() && null !== $error) {
46526 $output->writeln(sprintf('<error>%s</error>', $this->escapeString($error)));
46527 }
46528
46529 return $process;
46530 }
46531
46532
46533
46534
46535
46536
46537
46538
46539
46540
46541
46542
46543
46544
46545
46546
46547
46548
46549
46550 public function mustRun(OutputInterface $output, $cmd, $error = null, $callback = null)
46551 {
46552 $process = $this->run($output, $cmd, $error, $callback);
46553
46554 if (!$process->isSuccessful()) {
46555 throw new ProcessFailedException($process);
46556 }
46557
46558 return $process;
46559 }
46560
46561
46562
46563
46564
46565
46566
46567
46568
46569
46570 public function wrapCallback(OutputInterface $output, Process $process, $callback = null)
46571 {
46572 $formatter = $this->getHelperSet()->get('debug_formatter');
46573
46574 $that = $this;
46575
46576 return function ($type, $buffer) use ($output, $process, $callback, $formatter, $that) {
46577 $output->write($formatter->progress(spl_object_hash($process), $that->escapeString($buffer), Process::ERR === $type));
46578
46579 if (null !== $callback) {
46580 call_user_func($callback, $type, $buffer);
46581 }
46582 };
46583 }
46584
46585
46586
46587
46588
46589
46590 public function escapeString($str)
46591 {
46592 return str_replace('<', '\\<', $str);
46593 }
46594
46595
46596
46597
46598 public function getName()
46599 {
46600 return 'process';
46601 }
46602 }
46603 <?php
46604
46605
46606
46607
46608
46609
46610
46611
46612
46613
46614 namespace Symfony\Component\Console\Helper;
46615
46616 use Symfony\Component\Console\Command\Command;
46617
46618
46619
46620
46621
46622
46623 class HelperSet implements \IteratorAggregate
46624 {
46625 private $helpers = array();
46626 private $command;
46627
46628
46629
46630
46631
46632
46633 public function __construct(array $helpers = array())
46634 {
46635 foreach ($helpers as $alias => $helper) {
46636 $this->set($helper, is_int($alias) ? null : $alias);
46637 }
46638 }
46639
46640
46641
46642
46643
46644
46645
46646 public function set(HelperInterface $helper, $alias = null)
46647 {
46648 $this->helpers[$helper->getName()] = $helper;
46649 if (null !== $alias) {
46650 $this->helpers[$alias] = $helper;
46651 }
46652
46653 $helper->setHelperSet($this);
46654 }
46655
46656
46657
46658
46659
46660
46661
46662
46663 public function has($name)
46664 {
46665 return isset($this->helpers[$name]);
46666 }
46667
46668
46669
46670
46671
46672
46673
46674
46675
46676
46677 public function get($name)
46678 {
46679 if (!$this->has($name)) {
46680 throw new \InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
46681 }
46682
46683 return $this->helpers[$name];
46684 }
46685
46686
46687
46688
46689
46690
46691 public function setCommand(Command $command = null)
46692 {
46693 $this->command = $command;
46694 }
46695
46696
46697
46698
46699
46700
46701 public function getCommand()
46702 {
46703 return $this->command;
46704 }
46705
46706 public function getIterator()
46707 {
46708 return new \ArrayIterator($this->helpers);
46709 }
46710 }
46711 <?php
46712
46713
46714
46715
46716
46717
46718
46719
46720
46721
46722 namespace Symfony\Component\Console\Helper;
46723
46724 use Symfony\Component\Console\Output\OutputInterface;
46725 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
46726
46727
46728
46729
46730
46731
46732
46733
46734
46735 class DialogHelper extends InputAwareHelper
46736 {
46737 private $inputStream;
46738 private static $shell;
46739 private static $stty;
46740
46741
46742
46743
46744
46745
46746
46747
46748
46749
46750
46751
46752
46753
46754
46755
46756 public function select(OutputInterface $output, $question, $choices, $default = null, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false)
46757 {
46758 $width = max(array_map('strlen', array_keys($choices)));
46759
46760 $messages = (array) $question;
46761 foreach ($choices as $key => $value) {
46762 $messages[] = sprintf("  [<info>%-${width}s</info>] %s", $key, $value);
46763 }
46764
46765 $output->writeln($messages);
46766
46767 $result = $this->askAndValidate($output, '> ', function ($picked) use ($choices, $errorMessage, $multiselect) {
46768
46769  $selectedChoices = str_replace(" ", "", $picked);
46770
46771 if ($multiselect) {
46772
46773  if (!preg_match('/^[a-zA-Z0-9_-]+(?:,[a-zA-Z0-9_-]+)*$/', $selectedChoices, $matches)) {
46774 throw new \InvalidArgumentException(sprintf($errorMessage, $picked));
46775 }
46776 $selectedChoices = explode(",", $selectedChoices);
46777 } else {
46778 $selectedChoices = array($picked);
46779 }
46780
46781 $multiselectChoices = array();
46782
46783 foreach ($selectedChoices as $value) {
46784 if (empty($choices[$value])) {
46785 throw new \InvalidArgumentException(sprintf($errorMessage, $value));
46786 }
46787 array_push($multiselectChoices, $value);
46788 }
46789
46790 if ($multiselect) {
46791 return $multiselectChoices;
46792 }
46793
46794 return $picked;
46795 }, $attempts, $default);
46796
46797 return $result;
46798 }
46799
46800
46801
46802
46803
46804
46805
46806
46807
46808
46809
46810
46811
46812 public function ask(OutputInterface $output, $question, $default = null, array $autocomplete = null)
46813 {
46814 if ($this->input && !$this->input->isInteractive()) {
46815 return $default;
46816 }
46817
46818 $output->write($question);
46819
46820 $inputStream = $this->inputStream ?: STDIN;
46821
46822 if (null === $autocomplete || !$this->hasSttyAvailable()) {
46823 $ret = fgets($inputStream, 4096);
46824 if (false === $ret) {
46825 throw new \RuntimeException('Aborted');
46826 }
46827 $ret = trim($ret);
46828 } else {
46829 $ret = '';
46830
46831 $i = 0;
46832 $ofs = -1;
46833 $matches = $autocomplete;
46834 $numMatches = count($matches);
46835
46836 $sttyMode = shell_exec('stty -g');
46837
46838
46839  shell_exec('stty -icanon -echo');
46840
46841
46842  $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
46843
46844
46845  while (!feof($inputStream)) {
46846 $c = fread($inputStream, 1);
46847
46848
46849  if ("\177" === $c) {
46850 if (0 === $numMatches && 0 !== $i) {
46851 $i--;
46852
46853  $output->write("\033[1D");
46854 }
46855
46856 if ($i === 0) {
46857 $ofs = -1;
46858 $matches = $autocomplete;
46859 $numMatches = count($matches);
46860 } else {
46861 $numMatches = 0;
46862 }
46863
46864
46865  $ret = substr($ret, 0, $i);
46866 } elseif ("\033" === $c) {
46867
46868  $c .= fread($inputStream, 2);
46869
46870
46871  if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
46872 if ('A' === $c[2] && -1 === $ofs) {
46873 $ofs = 0;
46874 }
46875
46876 if (0 === $numMatches) {
46877 continue;
46878 }
46879
46880 $ofs += ('A' === $c[2]) ? -1 : 1;
46881 $ofs = ($numMatches + $ofs) % $numMatches;
46882 }
46883 } elseif (ord($c) < 32) {
46884 if ("\t" === $c || "\n" === $c) {
46885 if ($numMatches > 0 && -1 !== $ofs) {
46886 $ret = $matches[$ofs];
46887
46888  $output->write(substr($ret, $i));
46889 $i = strlen($ret);
46890 }
46891
46892 if ("\n" === $c) {
46893 $output->write($c);
46894 break;
46895 }
46896
46897 $numMatches = 0;
46898 }
46899
46900 continue;
46901 } else {
46902 $output->write($c);
46903 $ret .= $c;
46904 $i++;
46905
46906 $numMatches = 0;
46907 $ofs = 0;
46908
46909 foreach ($autocomplete as $value) {
46910
46911  if (0 === strpos($value, $ret) && $i !== strlen($value)) {
46912 $matches[$numMatches++] = $value;
46913 }
46914 }
46915 }
46916
46917
46918  $output->write("\033[K");
46919
46920 if ($numMatches > 0 && -1 !== $ofs) {
46921
46922  $output->write("\0337");
46923
46924  $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');
46925
46926  $output->write("\0338");
46927 }
46928 }
46929
46930
46931  shell_exec(sprintf('stty %s', $sttyMode));
46932 }
46933
46934 return strlen($ret) > 0 ? $ret : $default;
46935 }
46936
46937
46938
46939
46940
46941
46942
46943
46944
46945
46946
46947
46948 public function askConfirmation(OutputInterface $output, $question, $default = true)
46949 {
46950 $answer = 'z';
46951 while ($answer && !in_array(strtolower($answer[0]), array('y', 'n'))) {
46952 $answer = $this->ask($output, $question);
46953 }
46954
46955 if (false === $default) {
46956 return $answer && 'y' == strtolower($answer[0]);
46957 }
46958
46959 return !$answer || 'y' == strtolower($answer[0]);
46960 }
46961
46962
46963
46964
46965
46966
46967
46968
46969
46970
46971
46972
46973 public function askHiddenResponse(OutputInterface $output, $question, $fallback = true)
46974 {
46975 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
46976 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
46977
46978
46979  if ('phar:' === substr(__FILE__, 0, 5)) {
46980 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
46981 copy($exe, $tmpExe);
46982 $exe = $tmpExe;
46983 }
46984
46985 $output->write($question);
46986 $value = rtrim(shell_exec($exe));
46987 $output->writeln('');
46988
46989 if (isset($tmpExe)) {
46990 unlink($tmpExe);
46991 }
46992
46993 return $value;
46994 }
46995
46996 if ($this->hasSttyAvailable()) {
46997 $output->write($question);
46998
46999 $sttyMode = shell_exec('stty -g');
47000
47001 shell_exec('stty -echo');
47002 $value = fgets($this->inputStream ?: STDIN, 4096);
47003 shell_exec(sprintf('stty %s', $sttyMode));
47004
47005 if (false === $value) {
47006 throw new \RuntimeException('Aborted');
47007 }
47008
47009 $value = trim($value);
47010 $output->writeln('');
47011
47012 return $value;
47013 }
47014
47015 if (false !== $shell = $this->getShell()) {
47016 $output->write($question);
47017 $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';
47018 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
47019 $value = rtrim(shell_exec($command));
47020 $output->writeln('');
47021
47022 return $value;
47023 }
47024
47025 if ($fallback) {
47026 return $this->ask($output, $question);
47027 }
47028
47029 throw new \RuntimeException('Unable to hide the response');
47030 }
47031
47032
47033
47034
47035
47036
47037
47038
47039
47040
47041
47042
47043
47044
47045
47046
47047
47048
47049
47050 public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null, array $autocomplete = null)
47051 {
47052 $that = $this;
47053
47054 $interviewer = function () use ($output, $question, $default, $autocomplete, $that) {
47055 return $that->ask($output, $question, $default, $autocomplete);
47056 };
47057
47058 return $this->validateAttempts($interviewer, $output, $validator, $attempts);
47059 }
47060
47061
47062
47063
47064
47065
47066
47067
47068
47069
47070
47071
47072
47073
47074
47075
47076
47077
47078
47079
47080 public function askHiddenResponseAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $fallback = true)
47081 {
47082 $that = $this;
47083
47084 $interviewer = function () use ($output, $question, $fallback, $that) {
47085 return $that->askHiddenResponse($output, $question, $fallback);
47086 };
47087
47088 return $this->validateAttempts($interviewer, $output, $validator, $attempts);
47089 }
47090
47091
47092
47093
47094
47095
47096
47097
47098 public function setInputStream($stream)
47099 {
47100 $this->inputStream = $stream;
47101 }
47102
47103
47104
47105
47106
47107
47108 public function getInputStream()
47109 {
47110 return $this->inputStream;
47111 }
47112
47113
47114
47115
47116 public function getName()
47117 {
47118 return 'dialog';
47119 }
47120
47121
47122
47123
47124
47125
47126 private function getShell()
47127 {
47128 if (null !== self::$shell) {
47129 return self::$shell;
47130 }
47131
47132 self::$shell = false;
47133
47134 if (file_exists('/usr/bin/env')) {
47135
47136  $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
47137 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
47138 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
47139 self::$shell = $sh;
47140 break;
47141 }
47142 }
47143 }
47144
47145 return self::$shell;
47146 }
47147
47148 private function hasSttyAvailable()
47149 {
47150 if (null !== self::$stty) {
47151 return self::$stty;
47152 }
47153
47154 exec('stty 2>&1', $output, $exitcode);
47155
47156 return self::$stty = $exitcode === 0;
47157 }
47158
47159
47160
47161
47162
47163
47164
47165
47166
47167
47168
47169
47170
47171 private function validateAttempts($interviewer, OutputInterface $output, $validator, $attempts)
47172 {
47173 $error = null;
47174 while (false === $attempts || $attempts--) {
47175 if (null !== $error) {
47176 $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
47177 }
47178
47179 try {
47180 return call_user_func($validator, $interviewer());
47181 } catch (\Exception $error) {
47182 }
47183 }
47184
47185 throw $error;
47186 }
47187 }
47188 <?php
47189
47190
47191
47192
47193
47194
47195
47196
47197
47198
47199 namespace Symfony\Component\Console\Helper;
47200
47201 use Symfony\Component\Console\Input\InputInterface;
47202 use Symfony\Component\Console\Output\OutputInterface;
47203 use Symfony\Component\Console\Formatter\OutputFormatterStyle;
47204 use Symfony\Component\Console\Question\Question;
47205 use Symfony\Component\Console\Question\ChoiceQuestion;
47206
47207
47208
47209
47210
47211
47212 class QuestionHelper extends Helper
47213 {
47214 private $inputStream;
47215 private static $shell;
47216 private static $stty;
47217
47218
47219
47220
47221
47222
47223
47224
47225
47226
47227
47228
47229 public function ask(InputInterface $input, OutputInterface $output, Question $question)
47230 {
47231 if (!$input->isInteractive()) {
47232 return $question->getDefault();
47233 }
47234
47235 if (!$question->getValidator()) {
47236 return $this->doAsk($output, $question);
47237 }
47238
47239 $that = $this;
47240
47241 $interviewer = function () use ($output, $question, $that) {
47242 return $that->doAsk($output, $question);
47243 };
47244
47245 return $this->validateAttempts($interviewer, $output, $question);
47246 }
47247
47248
47249
47250
47251
47252
47253
47254
47255
47256
47257 public function setInputStream($stream)
47258 {
47259 if (!is_resource($stream)) {
47260 throw new \InvalidArgumentException('Input stream must be a valid resource.');
47261 }
47262
47263 $this->inputStream = $stream;
47264 }
47265
47266
47267
47268
47269
47270
47271 public function getInputStream()
47272 {
47273 return $this->inputStream;
47274 }
47275
47276
47277
47278
47279 public function getName()
47280 {
47281 return 'question';
47282 }
47283
47284
47285
47286
47287
47288
47289
47290
47291
47292
47293
47294
47295
47296
47297 public function doAsk(OutputInterface $output, Question $question)
47298 {
47299 $inputStream = $this->inputStream ?: STDIN;
47300
47301 $message = $question->getQuestion();
47302 if ($question instanceof ChoiceQuestion) {
47303 $width = max(array_map('strlen', array_keys($question->getChoices())));
47304
47305 $messages = (array) $question->getQuestion();
47306 foreach ($question->getChoices() as $key => $value) {
47307 $messages[] = sprintf("  [<info>%-${width}s</info>] %s", $key, $value);
47308 }
47309
47310 $output->writeln($messages);
47311
47312 $message = $question->getPrompt();
47313 }
47314
47315 $output->write($message);
47316
47317 $autocomplete = $question->getAutocompleterValues();
47318 if (null === $autocomplete || !$this->hasSttyAvailable()) {
47319 $ret = false;
47320 if ($question->isHidden()) {
47321 try {
47322 $ret = trim($this->getHiddenResponse($output, $inputStream));
47323 } catch (\RuntimeException $e) {
47324 if (!$question->isHiddenFallback()) {
47325 throw $e;
47326 }
47327 }
47328 }
47329
47330 if (false === $ret) {
47331 $ret = fgets($inputStream, 4096);
47332 if (false === $ret) {
47333 throw new \RuntimeException('Aborted');
47334 }
47335 $ret = trim($ret);
47336 }
47337 } else {
47338 $ret = trim($this->autocomplete($output, $question, $inputStream));
47339 }
47340
47341 $ret = strlen($ret) > 0 ? $ret : $question->getDefault();
47342
47343 if ($normalizer = $question->getNormalizer()) {
47344 return $normalizer($ret);
47345 }
47346
47347 return $ret;
47348 }
47349
47350
47351
47352
47353
47354
47355
47356
47357
47358 private function autocomplete(OutputInterface $output, Question $question, $inputStream)
47359 {
47360 $autocomplete = $question->getAutocompleterValues();
47361 $ret = '';
47362
47363 $i = 0;
47364 $ofs = -1;
47365 $matches = $autocomplete;
47366 $numMatches = count($matches);
47367
47368 $sttyMode = shell_exec('stty -g');
47369
47370
47371  shell_exec('stty -icanon -echo');
47372
47373
47374  $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
47375
47376
47377  while (!feof($inputStream)) {
47378 $c = fread($inputStream, 1);
47379
47380
47381  if ("\177" === $c) {
47382 if (0 === $numMatches && 0 !== $i) {
47383 $i--;
47384
47385  $output->write("\033[1D");
47386 }
47387
47388 if ($i === 0) {
47389 $ofs = -1;
47390 $matches = $autocomplete;
47391 $numMatches = count($matches);
47392 } else {
47393 $numMatches = 0;
47394 }
47395
47396
47397  $ret = substr($ret, 0, $i);
47398 } elseif ("\033" === $c) {
47399
47400  $c .= fread($inputStream, 2);
47401
47402
47403  if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
47404 if ('A' === $c[2] && -1 === $ofs) {
47405 $ofs = 0;
47406 }
47407
47408 if (0 === $numMatches) {
47409 continue;
47410 }
47411
47412 $ofs += ('A' === $c[2]) ? -1 : 1;
47413 $ofs = ($numMatches + $ofs) % $numMatches;
47414 }
47415 } elseif (ord($c) < 32) {
47416 if ("\t" === $c || "\n" === $c) {
47417 if ($numMatches > 0 && -1 !== $ofs) {
47418 $ret = $matches[$ofs];
47419
47420  $output->write(substr($ret, $i));
47421 $i = strlen($ret);
47422 }
47423
47424 if ("\n" === $c) {
47425 $output->write($c);
47426 break;
47427 }
47428
47429 $numMatches = 0;
47430 }
47431
47432 continue;
47433 } else {
47434 $output->write($c);
47435 $ret .= $c;
47436 $i++;
47437
47438 $numMatches = 0;
47439 $ofs = 0;
47440
47441 foreach ($autocomplete as $value) {
47442
47443  if (0 === strpos($value, $ret) && $i !== strlen($value)) {
47444 $matches[$numMatches++] = $value;
47445 }
47446 }
47447 }
47448
47449
47450  $output->write("\033[K");
47451
47452 if ($numMatches > 0 && -1 !== $ofs) {
47453
47454  $output->write("\0337");
47455
47456  $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');
47457
47458  $output->write("\0338");
47459 }
47460 }
47461
47462
47463  shell_exec(sprintf('stty %s', $sttyMode));
47464
47465 return $ret;
47466 }
47467
47468
47469
47470
47471
47472
47473
47474
47475
47476
47477 private function getHiddenResponse(OutputInterface $output, $inputStream)
47478 {
47479 if (defined('PHP_WINDOWS_VERSION_BUILD')) {
47480 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
47481
47482
47483  if ('phar:' === substr(__FILE__, 0, 5)) {
47484 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
47485 copy($exe, $tmpExe);
47486 $exe = $tmpExe;
47487 }
47488
47489 $value = rtrim(shell_exec($exe));
47490 $output->writeln('');
47491
47492 if (isset($tmpExe)) {
47493 unlink($tmpExe);
47494 }
47495
47496 return $value;
47497 }
47498
47499 if ($this->hasSttyAvailable()) {
47500 $sttyMode = shell_exec('stty -g');
47501
47502 shell_exec('stty -echo');
47503 $value = fgets($inputStream, 4096);
47504 shell_exec(sprintf('stty %s', $sttyMode));
47505
47506 if (false === $value) {
47507 throw new \RuntimeException('Aborted');
47508 }
47509
47510 $value = trim($value);
47511 $output->writeln('');
47512
47513 return $value;
47514 }
47515
47516 if (false !== $shell = $this->getShell()) {
47517 $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';
47518 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
47519 $value = rtrim(shell_exec($command));
47520 $output->writeln('');
47521
47522 return $value;
47523 }
47524
47525 throw new \RuntimeException('Unable to hide the response.');
47526 }
47527
47528
47529
47530
47531
47532
47533
47534
47535
47536
47537
47538
47539 private function validateAttempts($interviewer, OutputInterface $output, Question $question)
47540 {
47541 $error = null;
47542 $attempts = $question->getMaxAttempts();
47543 while (null === $attempts || $attempts--) {
47544 if (null !== $error) {
47545 $output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
47546 }
47547
47548 try {
47549 return call_user_func($question->getValidator(), $interviewer());
47550 } catch (\Exception $error) {
47551 }
47552 }
47553
47554 throw $error;
47555 }
47556
47557
47558
47559
47560
47561
47562 private function getShell()
47563 {
47564 if (null !== self::$shell) {
47565 return self::$shell;
47566 }
47567
47568 self::$shell = false;
47569
47570 if (file_exists('/usr/bin/env')) {
47571
47572  $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
47573 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
47574 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
47575 self::$shell = $sh;
47576 break;
47577 }
47578 }
47579 }
47580
47581 return self::$shell;
47582 }
47583
47584
47585
47586
47587
47588
47589 private function hasSttyAvailable()
47590 {
47591 if (null !== self::$stty) {
47592 return self::$stty;
47593 }
47594
47595 exec('stty 2>&1', $output, $exitcode);
47596
47597 return self::$stty = $exitcode === 0;
47598 }
47599 }
47600 <?php
47601
47602
47603
47604
47605
47606
47607
47608
47609
47610
47611 namespace Symfony\Component\Console\Helper;
47612
47613
47614
47615
47616
47617
47618 class TableSeparator
47619 {
47620 }
47621 <?php
47622
47623
47624
47625
47626
47627
47628
47629
47630
47631
47632 namespace Symfony\Component\Console\Helper;
47633
47634 use Symfony\Component\Console\Formatter\OutputFormatterInterface;
47635
47636
47637
47638
47639
47640
47641 abstract class Helper implements HelperInterface
47642 {
47643 protected $helperSet = null;
47644
47645
47646
47647
47648
47649
47650 public function setHelperSet(HelperSet $helperSet = null)
47651 {
47652 $this->helperSet = $helperSet;
47653 }
47654
47655
47656
47657
47658
47659
47660 public function getHelperSet()
47661 {
47662 return $this->helperSet;
47663 }
47664
47665
47666
47667
47668
47669
47670
47671
47672 public static function strlen($string)
47673 {
47674 if (!function_exists('mb_strwidth')) {
47675 return strlen($string);
47676 }
47677
47678 if (false === $encoding = mb_detect_encoding($string)) {
47679 return strlen($string);
47680 }
47681
47682 return mb_strwidth($string, $encoding);
47683 }
47684
47685 public static function formatTime($secs)
47686 {
47687 static $timeFormats = array(
47688 array(0, '< 1 sec'),
47689 array(2, '1 sec'),
47690 array(59, 'secs', 1),
47691 array(60, '1 min'),
47692 array(3600, 'mins', 60),
47693 array(5400, '1 hr'),
47694 array(86400, 'hrs', 3600),
47695 array(129600, '1 day'),
47696 array(604800, 'days', 86400),
47697 );
47698
47699 foreach ($timeFormats as $format) {
47700 if ($secs >= $format[0]) {
47701 continue;
47702 }
47703
47704 if (2 == count($format)) {
47705 return $format[1];
47706 }
47707
47708 return ceil($secs / $format[2]).' '.$format[1];
47709 }
47710 }
47711
47712 public static function formatMemory($memory)
47713 {
47714 if ($memory >= 1024 * 1024 * 1024) {
47715 return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
47716 }
47717
47718 if ($memory >= 1024 * 1024) {
47719 return sprintf('%.1f MiB', $memory / 1024 / 1024);
47720 }
47721
47722 if ($memory >= 1024) {
47723 return sprintf('%d KiB', $memory / 1024);
47724 }
47725
47726 return sprintf('%d B', $memory);
47727 }
47728
47729 public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
47730 {
47731 $isDecorated = $formatter->isDecorated();
47732 $formatter->setDecorated(false);
47733
47734  $string = $formatter->format($string);
47735
47736  $string = preg_replace("/\033\[[^m]*m/", '', $string);
47737 $formatter->setDecorated($isDecorated);
47738
47739 return self::strlen($string);
47740 }
47741 }
47742 <?php
47743
47744
47745
47746
47747
47748
47749
47750
47751
47752
47753 namespace Symfony\Component\Console\Helper;
47754
47755 use Symfony\Component\Console\Output\NullOutput;
47756 use Symfony\Component\Console\Output\OutputInterface;
47757
47758
47759
47760
47761
47762
47763
47764
47765
47766 class ProgressHelper extends Helper
47767 {
47768 const FORMAT_QUIET = ' %percent%%';
47769 const FORMAT_NORMAL = ' %current%/%max% [%bar%] %percent%%';
47770 const FORMAT_VERBOSE = ' %current%/%max% [%bar%] %percent%% Elapsed: %elapsed%';
47771 const FORMAT_QUIET_NOMAX = ' %current%';
47772 const FORMAT_NORMAL_NOMAX = ' %current% [%bar%]';
47773 const FORMAT_VERBOSE_NOMAX = ' %current% [%bar%] Elapsed: %elapsed%';
47774
47775
47776  private $barWidth = 28;
47777 private $barChar = '=';
47778 private $emptyBarChar = '-';
47779 private $progressChar = '>';
47780 private $format = null;
47781 private $redrawFreq = 1;
47782
47783 private $lastMessagesLength;
47784 private $barCharOriginal;
47785
47786
47787
47788
47789 private $output;
47790
47791
47792
47793
47794
47795
47796 private $current;
47797
47798
47799
47800
47801
47802
47803 private $max;
47804
47805
47806
47807
47808
47809
47810 private $startTime;
47811
47812
47813
47814
47815
47816
47817 private $defaultFormatVars = array(
47818 'current',
47819 'max',
47820 'bar',
47821 'percent',
47822 'elapsed',
47823 );
47824
47825
47826
47827
47828
47829
47830 private $formatVars;
47831
47832
47833
47834
47835
47836
47837 private $widths = array(
47838 'current' => 4,
47839 'max' => 4,
47840 'percent' => 3,
47841 'elapsed' => 6,
47842 );
47843
47844
47845
47846
47847
47848
47849 private $timeFormats = array(
47850 array(0, '???'),
47851 array(2, '1 sec'),
47852 array(59, 'secs', 1),
47853 array(60, '1 min'),
47854 array(3600, 'mins', 60),
47855 array(5400, '1 hr'),
47856 array(86400, 'hrs', 3600),
47857 array(129600, '1 day'),
47858 array(604800, 'days', 86400),
47859 );
47860
47861
47862
47863
47864
47865
47866 public function setBarWidth($size)
47867 {
47868 $this->barWidth = (int) $size;
47869 }
47870
47871
47872
47873
47874
47875
47876 public function setBarCharacter($char)
47877 {
47878 $this->barChar = $char;
47879 }
47880
47881
47882
47883
47884
47885
47886 public function setEmptyBarCharacter($char)
47887 {
47888 $this->emptyBarChar = $char;
47889 }
47890
47891
47892
47893
47894
47895
47896 public function setProgressCharacter($char)
47897 {
47898 $this->progressChar = $char;
47899 }
47900
47901
47902
47903
47904
47905
47906 public function setFormat($format)
47907 {
47908 $this->format = $format;
47909 }
47910
47911
47912
47913
47914
47915
47916 public function setRedrawFrequency($freq)
47917 {
47918 $this->redrawFreq = (int) $freq;
47919 }
47920
47921
47922
47923
47924
47925
47926
47927 public function start(OutputInterface $output, $max = null)
47928 {
47929 $this->startTime = time();
47930 $this->current = 0;
47931 $this->max = (int) $max;
47932
47933
47934  $this->output = $output->isDecorated() ? $output : new NullOutput();
47935 $this->lastMessagesLength = 0;
47936 $this->barCharOriginal = '';
47937
47938 if (null === $this->format) {
47939 switch ($output->getVerbosity()) {
47940 case OutputInterface::VERBOSITY_QUIET:
47941 $this->format = self::FORMAT_QUIET_NOMAX;
47942 if ($this->max > 0) {
47943 $this->format = self::FORMAT_QUIET;
47944 }
47945 break;
47946 case OutputInterface::VERBOSITY_VERBOSE:
47947 case OutputInterface::VERBOSITY_VERY_VERBOSE:
47948 case OutputInterface::VERBOSITY_DEBUG:
47949 $this->format = self::FORMAT_VERBOSE_NOMAX;
47950 if ($this->max > 0) {
47951 $this->format = self::FORMAT_VERBOSE;
47952 }
47953 break;
47954 default:
47955 $this->format = self::FORMAT_NORMAL_NOMAX;
47956 if ($this->max > 0) {
47957 $this->format = self::FORMAT_NORMAL;
47958 }
47959 break;
47960 }
47961 }
47962
47963 $this->initialize();
47964 }
47965
47966
47967
47968
47969
47970
47971
47972
47973
47974 public function advance($step = 1, $redraw = false)
47975 {
47976 $this->setCurrent($this->current + $step, $redraw);
47977 }
47978
47979
47980
47981
47982
47983
47984
47985
47986
47987 public function setCurrent($current, $redraw = false)
47988 {
47989 if (null === $this->startTime) {
47990 throw new \LogicException('You must start the progress bar before calling setCurrent().');
47991 }
47992
47993 $current = (int) $current;
47994
47995 if ($current < $this->current) {
47996 throw new \LogicException('You can\'t regress the progress bar');
47997 }
47998
47999 if (0 === $this->current) {
48000 $redraw = true;
48001 }
48002
48003 $prevPeriod = intval($this->current / $this->redrawFreq);
48004
48005 $this->current = $current;
48006
48007 $currPeriod = intval($this->current / $this->redrawFreq);
48008 if ($redraw || $prevPeriod !== $currPeriod || $this->max === $this->current) {
48009 $this->display();
48010 }
48011 }
48012
48013
48014
48015
48016
48017
48018
48019
48020 public function display($finish = false)
48021 {
48022 if (null === $this->startTime) {
48023 throw new \LogicException('You must start the progress bar before calling display().');
48024 }
48025
48026 $message = $this->format;
48027 foreach ($this->generate($finish) as $name => $value) {
48028 $message = str_replace("%{$name}%", $value, $message);
48029 }
48030 $this->overwrite($this->output, $message);
48031 }
48032
48033
48034
48035
48036
48037
48038
48039
48040 public function clear()
48041 {
48042 $this->overwrite($this->output, '');
48043 }
48044
48045
48046
48047
48048 public function finish()
48049 {
48050 if (null === $this->startTime) {
48051 throw new \LogicException('You must start the progress bar before calling finish().');
48052 }
48053
48054 if (null !== $this->startTime) {
48055 if (!$this->max) {
48056 $this->barChar = $this->barCharOriginal;
48057 $this->display(true);
48058 }
48059 $this->startTime = null;
48060 $this->output->writeln('');
48061 $this->output = null;
48062 }
48063 }
48064
48065
48066
48067
48068 private function initialize()
48069 {
48070 $this->formatVars = array();
48071 foreach ($this->defaultFormatVars as $var) {
48072 if (false !== strpos($this->format, "%{$var}%")) {
48073 $this->formatVars[$var] = true;
48074 }
48075 }
48076
48077 if ($this->max > 0) {
48078 $this->widths['max'] = $this->strlen($this->max);
48079 $this->widths['current'] = $this->widths['max'];
48080 } else {
48081 $this->barCharOriginal = $this->barChar;
48082 $this->barChar = $this->emptyBarChar;
48083 }
48084 }
48085
48086
48087
48088
48089
48090
48091
48092
48093 private function generate($finish = false)
48094 {
48095 $vars = array();
48096 $percent = 0;
48097 if ($this->max > 0) {
48098 $percent = (float) $this->current / $this->max;
48099 }
48100
48101 if (isset($this->formatVars['bar'])) {
48102 $completeBars = 0;
48103
48104 if ($this->max > 0) {
48105 $completeBars = floor($percent * $this->barWidth);
48106 } else {
48107 if (!$finish) {
48108 $completeBars = floor($this->current % $this->barWidth);
48109 } else {
48110 $completeBars = $this->barWidth;
48111 }
48112 }
48113
48114 $emptyBars = $this->barWidth - $completeBars - $this->strlen($this->progressChar);
48115 $bar = str_repeat($this->barChar, $completeBars);
48116 if ($completeBars < $this->barWidth) {
48117 $bar .= $this->progressChar;
48118 $bar .= str_repeat($this->emptyBarChar, $emptyBars);
48119 }
48120
48121 $vars['bar'] = $bar;
48122 }
48123
48124 if (isset($this->formatVars['elapsed'])) {
48125 $elapsed = time() - $this->startTime;
48126 $vars['elapsed'] = str_pad($this->humaneTime($elapsed), $this->widths['elapsed'], ' ', STR_PAD_LEFT);
48127 }
48128
48129 if (isset($this->formatVars['current'])) {
48130 $vars['current'] = str_pad($this->current, $this->widths['current'], ' ', STR_PAD_LEFT);
48131 }
48132
48133 if (isset($this->formatVars['max'])) {
48134 $vars['max'] = $this->max;
48135 }
48136
48137 if (isset($this->formatVars['percent'])) {
48138 $vars['percent'] = str_pad(floor($percent * 100), $this->widths['percent'], ' ', STR_PAD_LEFT);
48139 }
48140
48141 return $vars;
48142 }
48143
48144
48145
48146
48147
48148
48149
48150
48151 private function humaneTime($secs)
48152 {
48153 $text = '';
48154 foreach ($this->timeFormats as $format) {
48155 if ($secs < $format[0]) {
48156 if (count($format) == 2) {
48157 $text = $format[1];
48158 break;
48159 } else {
48160 $text = ceil($secs / $format[2]).' '.$format[1];
48161 break;
48162 }
48163 }
48164 }
48165
48166 return $text;
48167 }
48168
48169
48170
48171
48172
48173
48174
48175 private function overwrite(OutputInterface $output, $message)
48176 {
48177 $length = $this->strlen($message);
48178
48179
48180  if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
48181 $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
48182 }
48183
48184
48185  $output->write("\x0D");
48186 $output->write($message);
48187
48188 $this->lastMessagesLength = $this->strlen($message);
48189 }
48190
48191
48192
48193
48194 public function getName()
48195 {
48196 return 'progress';
48197 }
48198 }
48199 <?php
48200
48201
48202
48203
48204
48205
48206
48207
48208
48209
48210 namespace Symfony\Component\Console\Helper;
48211
48212 use Symfony\Component\Console\Input\InputInterface;
48213 use Symfony\Component\Console\Input\InputAwareInterface;
48214
48215
48216
48217
48218
48219
48220 abstract class InputAwareHelper extends Helper implements InputAwareInterface
48221 {
48222 protected $input;
48223
48224
48225
48226
48227 public function setInput(InputInterface $input)
48228 {
48229 $this->input = $input;
48230 }
48231 }
48232 <?php
48233
48234
48235
48236
48237
48238
48239
48240
48241
48242
48243 namespace Symfony\Component\Console\Helper;
48244
48245
48246
48247
48248
48249
48250
48251 class TableStyle
48252 {
48253 private $paddingChar = ' ';
48254 private $horizontalBorderChar = '-';
48255 private $verticalBorderChar = '|';
48256 private $crossingChar = '+';
48257 private $cellHeaderFormat = '<info>%s</info>';
48258 private $cellRowFormat = '%s';
48259 private $cellRowContentFormat = ' %s ';
48260 private $borderFormat = '%s';
48261 private $padType = STR_PAD_RIGHT;
48262
48263
48264
48265
48266
48267
48268
48269
48270 public function setPaddingChar($paddingChar)
48271 {
48272 if (!$paddingChar) {
48273 throw new \LogicException('The padding char must not be empty');
48274 }
48275
48276 $this->paddingChar = $paddingChar;
48277
48278 return $this;
48279 }
48280
48281
48282
48283
48284
48285
48286 public function getPaddingChar()
48287 {
48288 return $this->paddingChar;
48289 }
48290
48291
48292
48293
48294
48295
48296
48297
48298 public function setHorizontalBorderChar($horizontalBorderChar)
48299 {
48300 $this->horizontalBorderChar = $horizontalBorderChar;
48301
48302 return $this;
48303 }
48304
48305
48306
48307
48308
48309
48310 public function getHorizontalBorderChar()
48311 {
48312 return $this->horizontalBorderChar;
48313 }
48314
48315
48316
48317
48318
48319
48320
48321
48322 public function setVerticalBorderChar($verticalBorderChar)
48323 {
48324 $this->verticalBorderChar = $verticalBorderChar;
48325
48326 return $this;
48327 }
48328
48329
48330
48331
48332
48333
48334 public function getVerticalBorderChar()
48335 {
48336 return $this->verticalBorderChar;
48337 }
48338
48339
48340
48341
48342
48343
48344
48345
48346 public function setCrossingChar($crossingChar)
48347 {
48348 $this->crossingChar = $crossingChar;
48349
48350 return $this;
48351 }
48352
48353
48354
48355
48356
48357
48358 public function getCrossingChar()
48359 {
48360 return $this->crossingChar;
48361 }
48362
48363
48364
48365
48366
48367
48368
48369
48370 public function setCellHeaderFormat($cellHeaderFormat)
48371 {
48372 $this->cellHeaderFormat = $cellHeaderFormat;
48373
48374 return $this;
48375 }
48376
48377
48378
48379
48380
48381
48382 public function getCellHeaderFormat()
48383 {
48384 return $this->cellHeaderFormat;
48385 }
48386
48387
48388
48389
48390
48391
48392
48393
48394 public function setCellRowFormat($cellRowFormat)
48395 {
48396 $this->cellRowFormat = $cellRowFormat;
48397
48398 return $this;
48399 }
48400
48401
48402
48403
48404
48405
48406 public function getCellRowFormat()
48407 {
48408 return $this->cellRowFormat;
48409 }
48410
48411
48412
48413
48414
48415
48416
48417
48418 public function setCellRowContentFormat($cellRowContentFormat)
48419 {
48420 $this->cellRowContentFormat = $cellRowContentFormat;
48421
48422 return $this;
48423 }
48424
48425
48426
48427
48428
48429
48430 public function getCellRowContentFormat()
48431 {
48432 return $this->cellRowContentFormat;
48433 }
48434
48435
48436
48437
48438
48439
48440
48441
48442 public function setBorderFormat($borderFormat)
48443 {
48444 $this->borderFormat = $borderFormat;
48445
48446 return $this;
48447 }
48448
48449
48450
48451
48452
48453
48454 public function getBorderFormat()
48455 {
48456 return $this->borderFormat;
48457 }
48458
48459
48460
48461
48462
48463
48464
48465
48466 public function setPadType($padType)
48467 {
48468 $this->padType = $padType;
48469
48470 return $this;
48471 }
48472
48473
48474
48475
48476
48477
48478 public function getPadType()
48479 {
48480 return $this->padType;
48481 }
48482 }
48483 <?php
48484
48485
48486
48487
48488
48489
48490
48491
48492
48493
48494 namespace Symfony\Component\Console\Event;
48495
48496 use Symfony\Component\Console\Command\Command;
48497 use Symfony\Component\Console\Input\InputInterface;
48498 use Symfony\Component\Console\Output\OutputInterface;
48499 use Symfony\Component\EventDispatcher\Event;
48500
48501
48502
48503
48504
48505
48506 class ConsoleEvent extends Event
48507 {
48508 protected $command;
48509
48510 private $input;
48511 private $output;
48512
48513 public function __construct(Command $command, InputInterface $input, OutputInterface $output)
48514 {
48515 $this->command = $command;
48516 $this->input = $input;
48517 $this->output = $output;
48518 }
48519
48520
48521
48522
48523
48524
48525 public function getCommand()
48526 {
48527 return $this->command;
48528 }
48529
48530
48531
48532
48533
48534
48535 public function getInput()
48536 {
48537 return $this->input;
48538 }
48539
48540
48541
48542
48543
48544
48545 public function getOutput()
48546 {
48547 return $this->output;
48548 }
48549 }
48550 <?php
48551
48552
48553
48554
48555
48556
48557
48558
48559
48560
48561 namespace Symfony\Component\Console\Event;
48562
48563 use Symfony\Component\Console\Command\Command;
48564 use Symfony\Component\Console\Input\InputInterface;
48565 use Symfony\Component\Console\Output\OutputInterface;
48566
48567
48568
48569
48570
48571
48572 class ConsoleTerminateEvent extends ConsoleEvent
48573 {
48574
48575
48576
48577
48578
48579 private $exitCode;
48580
48581 public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode)
48582 {
48583 parent::__construct($command, $input, $output);
48584
48585 $this->setExitCode($exitCode);
48586 }
48587
48588
48589
48590
48591
48592
48593 public function setExitCode($exitCode)
48594 {
48595 $this->exitCode = (int) $exitCode;
48596 }
48597
48598
48599
48600
48601
48602
48603 public function getExitCode()
48604 {
48605 return $this->exitCode;
48606 }
48607 }
48608 <?php
48609
48610
48611
48612
48613
48614
48615
48616
48617
48618
48619 namespace Symfony\Component\Console\Event;
48620
48621 use Symfony\Component\Console\Command\Command;
48622 use Symfony\Component\Console\Input\InputInterface;
48623 use Symfony\Component\Console\Output\OutputInterface;
48624
48625
48626
48627
48628
48629
48630 class ConsoleExceptionEvent extends ConsoleEvent
48631 {
48632 private $exception;
48633 private $exitCode;
48634
48635 public function __construct(Command $command, InputInterface $input, OutputInterface $output, \Exception $exception, $exitCode)
48636 {
48637 parent::__construct($command, $input, $output);
48638
48639 $this->setException($exception);
48640 $this->exitCode = (int) $exitCode;
48641 }
48642
48643
48644
48645
48646
48647
48648 public function getException()
48649 {
48650 return $this->exception;
48651 }
48652
48653
48654
48655
48656
48657
48658
48659
48660 public function setException(\Exception $exception)
48661 {
48662 $this->exception = $exception;
48663 }
48664
48665
48666
48667
48668
48669
48670 public function getExitCode()
48671 {
48672 return $this->exitCode;
48673 }
48674 }
48675 <?php
48676
48677
48678
48679
48680
48681
48682
48683
48684
48685
48686 namespace Symfony\Component\Console\Event;
48687
48688
48689
48690
48691
48692
48693 class ConsoleCommandEvent extends ConsoleEvent
48694 {
48695
48696
48697
48698 const RETURN_CODE_DISABLED = 113;
48699
48700
48701
48702
48703
48704
48705 private $commandShouldRun = true;
48706
48707
48708
48709
48710
48711
48712 public function disableCommand()
48713 {
48714 return $this->commandShouldRun = false;
48715 }
48716
48717
48718
48719
48720
48721
48722 public function enableCommand()
48723 {
48724 return $this->commandShouldRun = true;
48725 }
48726
48727
48728
48729
48730
48731
48732 public function commandShouldRun()
48733 {
48734 return $this->commandShouldRun;
48735 }
48736 }
48737 <?php
48738
48739
48740
48741
48742
48743
48744
48745
48746
48747
48748 namespace Symfony\Component\Console;
48749
48750
48751
48752
48753
48754
48755 final class ConsoleEvents
48756 {
48757
48758
48759
48760
48761
48762
48763
48764
48765
48766
48767
48768
48769 const COMMAND = 'console.command';
48770
48771
48772
48773
48774
48775
48776
48777
48778
48779
48780
48781
48782 const TERMINATE = 'console.terminate';
48783
48784
48785
48786
48787
48788
48789
48790
48791
48792
48793
48794
48795
48796 const EXCEPTION = 'console.exception';
48797 }
48798 <?php
48799
48800
48801
48802
48803
48804
48805
48806
48807
48808
48809 namespace Symfony\Component\Finder;
48810
48811 use Symfony\Component\Finder\Adapter\AdapterInterface;
48812 use Symfony\Component\Finder\Adapter\GnuFindAdapter;
48813 use Symfony\Component\Finder\Adapter\BsdFindAdapter;
48814 use Symfony\Component\Finder\Adapter\PhpAdapter;
48815 use Symfony\Component\Finder\Exception\ExceptionInterface;
48816
48817
48818
48819
48820
48821
48822
48823
48824
48825
48826
48827
48828
48829
48830
48831
48832 class Finder implements \IteratorAggregate, \Countable
48833 {
48834 const IGNORE_VCS_FILES = 1;
48835 const IGNORE_DOT_FILES = 2;
48836
48837 private $mode = 0;
48838 private $names = array();
48839 private $notNames = array();
48840 private $exclude = array();
48841 private $filters = array();
48842 private $depths = array();
48843 private $sizes = array();
48844 private $followLinks = false;
48845 private $sort = false;
48846 private $ignore = 0;
48847 private $dirs = array();
48848 private $dates = array();
48849 private $iterators = array();
48850 private $contains = array();
48851 private $notContains = array();
48852 private $adapters = array();
48853 private $paths = array();
48854 private $notPaths = array();
48855 private $ignoreUnreadableDirs = false;
48856
48857 private static $vcsPatterns = array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg');
48858
48859
48860
48861
48862 public function __construct()
48863 {
48864 $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES;
48865
48866 $this
48867 ->addAdapter(new GnuFindAdapter())
48868 ->addAdapter(new BsdFindAdapter())
48869 ->addAdapter(new PhpAdapter(), -50)
48870 ->setAdapter('php')
48871 ;
48872 }
48873
48874
48875
48876
48877
48878
48879
48880
48881 public static function create()
48882 {
48883 return new static();
48884 }
48885
48886
48887
48888
48889
48890
48891
48892
48893
48894 public function addAdapter(AdapterInterface $adapter, $priority = 0)
48895 {
48896 $this->adapters[$adapter->getName()] = array(
48897 'adapter' => $adapter,
48898 'priority' => $priority,
48899 'selected' => false,
48900 );
48901
48902 return $this->sortAdapters();
48903 }
48904
48905
48906
48907
48908
48909
48910 public function useBestAdapter()
48911 {
48912 $this->resetAdapterSelection();
48913
48914 return $this->sortAdapters();
48915 }
48916
48917
48918
48919
48920
48921
48922
48923
48924
48925
48926 public function setAdapter($name)
48927 {
48928 if (!isset($this->adapters[$name])) {
48929 throw new \InvalidArgumentException(sprintf('Adapter "%s" does not exist.', $name));
48930 }
48931
48932 $this->resetAdapterSelection();
48933 $this->adapters[$name]['selected'] = true;
48934
48935 return $this->sortAdapters();
48936 }
48937
48938
48939
48940
48941
48942
48943 public function removeAdapters()
48944 {
48945 $this->adapters = array();
48946
48947 return $this;
48948 }
48949
48950
48951
48952
48953
48954
48955 public function getAdapters()
48956 {
48957 return array_values(array_map(function (array $adapter) {
48958 return $adapter['adapter'];
48959 }, $this->adapters));
48960 }
48961
48962
48963
48964
48965
48966
48967
48968
48969 public function directories()
48970 {
48971 $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES;
48972
48973 return $this;
48974 }
48975
48976
48977
48978
48979
48980
48981
48982
48983 public function files()
48984 {
48985 $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
48986
48987 return $this;
48988 }
48989
48990
48991
48992
48993
48994
48995
48996
48997
48998
48999
49000
49001
49002
49003
49004
49005
49006
49007 public function depth($level)
49008 {
49009 $this->depths[] = new Comparator\NumberComparator($level);
49010
49011 return $this;
49012 }
49013
49014
49015
49016
49017
49018
49019
49020
49021
49022
49023
49024
49025
49026
49027
49028
49029
49030
49031
49032
49033
49034 public function date($date)
49035 {
49036 $this->dates[] = new Comparator\DateComparator($date);
49037
49038 return $this;
49039 }
49040
49041
49042
49043
49044
49045
49046
49047
49048
49049
49050
49051
49052
49053
49054
49055
49056
49057
49058 public function name($pattern)
49059 {
49060 $this->names[] = $pattern;
49061
49062 return $this;
49063 }
49064
49065
49066
49067
49068
49069
49070
49071
49072
49073
49074
49075
49076 public function notName($pattern)
49077 {
49078 $this->notNames[] = $pattern;
49079
49080 return $this;
49081 }
49082
49083
49084
49085
49086
49087
49088
49089
49090
49091
49092
49093
49094
49095
49096
49097 public function contains($pattern)
49098 {
49099 $this->contains[] = $pattern;
49100
49101 return $this;
49102 }
49103
49104
49105
49106
49107
49108
49109
49110
49111
49112
49113
49114
49115
49116
49117
49118 public function notContains($pattern)
49119 {
49120 $this->notContains[] = $pattern;
49121
49122 return $this;
49123 }
49124
49125
49126
49127
49128
49129
49130
49131
49132
49133
49134
49135
49136
49137
49138
49139
49140
49141 public function path($pattern)
49142 {
49143 $this->paths[] = $pattern;
49144
49145 return $this;
49146 }
49147
49148
49149
49150
49151
49152
49153
49154
49155
49156
49157
49158
49159
49160
49161
49162
49163
49164 public function notPath($pattern)
49165 {
49166 $this->notPaths[] = $pattern;
49167
49168 return $this;
49169 }
49170
49171
49172
49173
49174
49175
49176
49177
49178
49179
49180
49181
49182
49183
49184
49185
49186
49187 public function size($size)
49188 {
49189 $this->sizes[] = new Comparator\NumberComparator($size);
49190
49191 return $this;
49192 }
49193
49194
49195
49196
49197
49198
49199
49200
49201
49202
49203
49204
49205 public function exclude($dirs)
49206 {
49207 $this->exclude = array_merge($this->exclude, (array) $dirs);
49208
49209 return $this;
49210 }
49211
49212
49213
49214
49215
49216
49217
49218
49219
49220
49221
49222
49223 public function ignoreDotFiles($ignoreDotFiles)
49224 {
49225 if ($ignoreDotFiles) {
49226 $this->ignore = $this->ignore | static::IGNORE_DOT_FILES;
49227 } else {
49228 $this->ignore = $this->ignore & ~static::IGNORE_DOT_FILES;
49229 }
49230
49231 return $this;
49232 }
49233
49234
49235
49236
49237
49238
49239
49240
49241
49242
49243
49244
49245 public function ignoreVCS($ignoreVCS)
49246 {
49247 if ($ignoreVCS) {
49248 $this->ignore = $this->ignore | static::IGNORE_VCS_FILES;
49249 } else {
49250 $this->ignore = $this->ignore & ~static::IGNORE_VCS_FILES;
49251 }
49252
49253 return $this;
49254 }
49255
49256
49257
49258
49259
49260
49261
49262
49263 public static function addVCSPattern($pattern)
49264 {
49265 foreach ((array) $pattern as $p) {
49266 self::$vcsPatterns[] = $p;
49267 }
49268
49269 self::$vcsPatterns = array_unique(self::$vcsPatterns);
49270 }
49271
49272
49273
49274
49275
49276
49277
49278
49279
49280
49281
49282
49283
49284
49285
49286
49287 public function sort(\Closure $closure)
49288 {
49289 $this->sort = $closure;
49290
49291 return $this;
49292 }
49293
49294
49295
49296
49297
49298
49299
49300
49301
49302
49303
49304
49305 public function sortByName()
49306 {
49307 $this->sort = Iterator\SortableIterator::SORT_BY_NAME;
49308
49309 return $this;
49310 }
49311
49312
49313
49314
49315
49316
49317
49318
49319
49320
49321
49322
49323 public function sortByType()
49324 {
49325 $this->sort = Iterator\SortableIterator::SORT_BY_TYPE;
49326
49327 return $this;
49328 }
49329
49330
49331
49332
49333
49334
49335
49336
49337
49338
49339
49340
49341
49342
49343 public function sortByAccessedTime()
49344 {
49345 $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME;
49346
49347 return $this;
49348 }
49349
49350
49351
49352
49353
49354
49355
49356
49357
49358
49359
49360
49361
49362
49363
49364
49365 public function sortByChangedTime()
49366 {
49367 $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME;
49368
49369 return $this;
49370 }
49371
49372
49373
49374
49375
49376
49377
49378
49379
49380
49381
49382
49383
49384
49385 public function sortByModifiedTime()
49386 {
49387 $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME;
49388
49389 return $this;
49390 }
49391
49392
49393
49394
49395
49396
49397
49398
49399
49400
49401
49402
49403
49404
49405
49406 public function filter(\Closure $closure)
49407 {
49408 $this->filters[] = $closure;
49409
49410 return $this;
49411 }
49412
49413
49414
49415
49416
49417
49418
49419
49420 public function followLinks()
49421 {
49422 $this->followLinks = true;
49423
49424 return $this;
49425 }
49426
49427
49428
49429
49430
49431
49432
49433
49434
49435
49436 public function ignoreUnreadableDirs($ignore = true)
49437 {
49438 $this->ignoreUnreadableDirs = (bool) $ignore;
49439
49440 return $this;
49441 }
49442
49443
49444
49445
49446
49447
49448
49449
49450
49451
49452
49453
49454 public function in($dirs)
49455 {
49456 $resolvedDirs = array();
49457
49458 foreach ((array) $dirs as $dir) {
49459 if (is_dir($dir)) {
49460 $resolvedDirs[] = $dir;
49461 } elseif ($glob = glob($dir, GLOB_BRACE | GLOB_ONLYDIR)) {
49462 $resolvedDirs = array_merge($resolvedDirs, $glob);
49463 } else {
49464 throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir));
49465 }
49466 }
49467
49468 $this->dirs = array_merge($this->dirs, $resolvedDirs);
49469
49470 return $this;
49471 }
49472
49473
49474
49475
49476
49477
49478
49479
49480
49481
49482 public function getIterator()
49483 {
49484 if (0 === count($this->dirs) && 0 === count($this->iterators)) {
49485 throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.');
49486 }
49487
49488 if (1 === count($this->dirs) && 0 === count($this->iterators)) {
49489 return $this->searchInDirectory($this->dirs[0]);
49490 }
49491
49492 $iterator = new \AppendIterator();
49493 foreach ($this->dirs as $dir) {
49494 $iterator->append($this->searchInDirectory($dir));
49495 }
49496
49497 foreach ($this->iterators as $it) {
49498 $iterator->append($it);
49499 }
49500
49501 return $iterator;
49502 }
49503
49504
49505
49506
49507
49508
49509
49510
49511
49512
49513
49514
49515 public function append($iterator)
49516 {
49517 if ($iterator instanceof \IteratorAggregate) {
49518 $this->iterators[] = $iterator->getIterator();
49519 } elseif ($iterator instanceof \Iterator) {
49520 $this->iterators[] = $iterator;
49521 } elseif ($iterator instanceof \Traversable || is_array($iterator)) {
49522 $it = new \ArrayIterator();
49523 foreach ($iterator as $file) {
49524 $it->append($file instanceof \SplFileInfo ? $file : new \SplFileInfo($file));
49525 }
49526 $this->iterators[] = $it;
49527 } else {
49528 throw new \InvalidArgumentException('Finder::append() method wrong argument type.');
49529 }
49530
49531 return $this;
49532 }
49533
49534
49535
49536
49537
49538
49539 public function count()
49540 {
49541 return iterator_count($this->getIterator());
49542 }
49543
49544
49545
49546
49547 private function sortAdapters()
49548 {
49549 uasort($this->adapters, function (array $a, array $b) {
49550 if ($a['selected'] || $b['selected']) {
49551 return $a['selected'] ? -1 : 1;
49552 }
49553
49554 return $a['priority'] > $b['priority'] ? -1 : 1;
49555 });
49556
49557 return $this;
49558 }
49559
49560
49561
49562
49563
49564
49565
49566
49567 private function searchInDirectory($dir)
49568 {
49569 if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
49570 $this->exclude = array_merge($this->exclude, self::$vcsPatterns);
49571 }
49572
49573 if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
49574 $this->notPaths[] = '#(^|/)\..+(/|$)#';
49575 }
49576
49577 foreach ($this->adapters as $adapter) {
49578 if ($adapter['adapter']->isSupported()) {
49579 try {
49580 return $this
49581 ->buildAdapter($adapter['adapter'])
49582 ->searchInDirectory($dir);
49583 } catch (ExceptionInterface $e) {
49584 }
49585 }
49586 }
49587
49588 throw new \RuntimeException('No supported adapter found.');
49589 }
49590
49591
49592
49593
49594
49595
49596 private function buildAdapter(AdapterInterface $adapter)
49597 {
49598 return $adapter
49599 ->setFollowLinks($this->followLinks)
49600 ->setDepths($this->depths)
49601 ->setMode($this->mode)
49602 ->setExclude($this->exclude)
49603 ->setNames($this->names)
49604 ->setNotNames($this->notNames)
49605 ->setContains($this->contains)
49606 ->setNotContains($this->notContains)
49607 ->setSizes($this->sizes)
49608 ->setDates($this->dates)
49609 ->setFilters($this->filters)
49610 ->setSort($this->sort)
49611 ->setPath($this->paths)
49612 ->setNotPath($this->notPaths)
49613 ->ignoreUnreadableDirs($this->ignoreUnreadableDirs);
49614 }
49615
49616
49617
49618
49619 private function resetAdapterSelection()
49620 {
49621 $this->adapters = array_map(function (array $properties) {
49622 $properties['selected'] = false;
49623
49624 return $properties;
49625 }, $this->adapters);
49626 }
49627 }
49628 <?php
49629
49630
49631
49632
49633
49634
49635
49636
49637
49638
49639 namespace Symfony\Component\Finder\Shell;
49640
49641
49642
49643
49644 class Command
49645 {
49646
49647
49648
49649 private $parent;
49650
49651
49652
49653
49654 private $bits = array();
49655
49656
49657
49658
49659 private $labels = array();
49660
49661
49662
49663
49664 private $errorHandler;
49665
49666
49667
49668
49669
49670
49671 public function __construct(Command $parent = null)
49672 {
49673 $this->parent = $parent;
49674 }
49675
49676
49677
49678
49679
49680
49681 public function __toString()
49682 {
49683 return $this->join();
49684 }
49685
49686
49687
49688
49689
49690
49691
49692
49693 public static function create(Command $parent = null)
49694 {
49695 return new self($parent);
49696 }
49697
49698
49699
49700
49701
49702
49703
49704
49705 public static function escape($input)
49706 {
49707 return escapeshellcmd($input);
49708 }
49709
49710
49711
49712
49713
49714
49715
49716
49717 public static function quote($input)
49718 {
49719 return escapeshellarg($input);
49720 }
49721
49722
49723
49724
49725
49726
49727
49728
49729 public function add($bit)
49730 {
49731 $this->bits[] = $bit;
49732
49733 return $this;
49734 }
49735
49736
49737
49738
49739
49740
49741
49742
49743 public function top($bit)
49744 {
49745 array_unshift($this->bits, $bit);
49746
49747 foreach ($this->labels as $label => $index) {
49748 $this->labels[$label] += 1;
49749 }
49750
49751 return $this;
49752 }
49753
49754
49755
49756
49757
49758
49759
49760
49761 public function arg($arg)
49762 {
49763 $this->bits[] = self::quote($arg);
49764
49765 return $this;
49766 }
49767
49768
49769
49770
49771
49772
49773
49774
49775 public function cmd($esc)
49776 {
49777 $this->bits[] = self::escape($esc);
49778
49779 return $this;
49780 }
49781
49782
49783
49784
49785
49786
49787
49788
49789
49790
49791 public function ins($label)
49792 {
49793 if (isset($this->labels[$label])) {
49794 throw new \RuntimeException(sprintf('Label "%s" already exists.', $label));
49795 }
49796
49797 $this->bits[] = self::create($this);
49798 $this->labels[$label] = count($this->bits)-1;
49799
49800 return $this->bits[$this->labels[$label]];
49801 }
49802
49803
49804
49805
49806
49807
49808
49809
49810
49811
49812 public function get($label)
49813 {
49814 if (!isset($this->labels[$label])) {
49815 throw new \RuntimeException(sprintf('Label "%s" does not exist.', $label));
49816 }
49817
49818 return $this->bits[$this->labels[$label]];
49819 }
49820
49821
49822
49823
49824
49825
49826
49827
49828 public function end()
49829 {
49830 if (null === $this->parent) {
49831 throw new \RuntimeException('Calling end on root command doesn\'t make sense.');
49832 }
49833
49834 return $this->parent;
49835 }
49836
49837
49838
49839
49840
49841
49842 public function length()
49843 {
49844 return count($this->bits);
49845 }
49846
49847
49848
49849
49850
49851
49852 public function setErrorHandler(\Closure $errorHandler)
49853 {
49854 $this->errorHandler = $errorHandler;
49855
49856 return $this;
49857 }
49858
49859
49860
49861
49862 public function getErrorHandler()
49863 {
49864 return $this->errorHandler;
49865 }
49866
49867
49868
49869
49870
49871
49872
49873
49874 public function execute()
49875 {
49876 if (null === $this->errorHandler) {
49877 exec($this->join(), $output);
49878 } else {
49879 $process = proc_open($this->join(), array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes);
49880 $output = preg_split('~(\r\n|\r|\n)~', stream_get_contents($pipes[1]), -1, PREG_SPLIT_NO_EMPTY);
49881
49882 if ($error = stream_get_contents($pipes[2])) {
49883 call_user_func($this->errorHandler, $error);
49884 }
49885
49886 proc_close($process);
49887 }
49888
49889 return $output ?: array();
49890 }
49891
49892
49893
49894
49895
49896
49897 public function join()
49898 {
49899 return implode(' ', array_filter(
49900 array_map(function ($bit) {
49901 return $bit instanceof Command ? $bit->join() : ($bit ?: null);
49902 }, $this->bits),
49903 function ($bit) { return null !== $bit; }
49904 ));
49905 }
49906
49907
49908
49909
49910
49911
49912
49913
49914
49915 public function addAtIndex($bit, $index)
49916 {
49917 array_splice($this->bits, $index, 0, $bit);
49918
49919 return $this;
49920 }
49921 }
49922 <?php
49923
49924
49925
49926
49927
49928
49929
49930
49931
49932
49933 namespace Symfony\Component\Finder\Shell;
49934
49935
49936
49937
49938 class Shell
49939 {
49940 const TYPE_UNIX = 1;
49941 const TYPE_DARWIN = 2;
49942 const TYPE_CYGWIN = 3;
49943 const TYPE_WINDOWS = 4;
49944 const TYPE_BSD = 5;
49945
49946
49947
49948
49949 private $type;
49950
49951
49952
49953
49954
49955
49956 public function getType()
49957 {
49958 if (null === $this->type) {
49959 $this->type = $this->guessType();
49960 }
49961
49962 return $this->type;
49963 }
49964
49965
49966
49967
49968
49969
49970
49971
49972 public function testCommand($command)
49973 {
49974 if (!function_exists('exec')) {
49975 return false;
49976 }
49977
49978
49979  $testCommand = 'which ';
49980 if (self::TYPE_WINDOWS === $this->type) {
49981 $testCommand = 'where ';
49982 }
49983
49984 $command = escapeshellcmd($command);
49985
49986 exec($testCommand.$command, $output, $code);
49987
49988 return 0 === $code && count($output) > 0;
49989 }
49990
49991
49992
49993
49994
49995
49996 private function guessType()
49997 {
49998 $os = strtolower(PHP_OS);
49999
50000 if (false !== strpos($os, 'cygwin')) {
50001 return self::TYPE_CYGWIN;
50002 }
50003
50004 if (false !== strpos($os, 'darwin')) {
50005 return self::TYPE_DARWIN;
50006 }
50007
50008 if (false !== strpos($os, 'bsd')) {
50009 return self::TYPE_BSD;
50010 }
50011
50012 if (0 === strpos($os, 'win')) {
50013 return self::TYPE_WINDOWS;
50014 }
50015
50016 return self::TYPE_UNIX;
50017 }
50018 }
50019 <?php
50020
50021
50022
50023
50024
50025
50026
50027
50028
50029
50030 namespace Symfony\Component\Finder\Expression;
50031
50032
50033
50034
50035 class Regex implements ValueInterface
50036 {
50037 const START_FLAG = '^';
50038 const END_FLAG = '$';
50039 const BOUNDARY = '~';
50040 const JOKER = '.*';
50041 const ESCAPING = '\\';
50042
50043
50044
50045
50046 private $pattern;
50047
50048
50049
50050
50051 private $options;
50052
50053
50054
50055
50056 private $startFlag;
50057
50058
50059
50060
50061 private $endFlag;
50062
50063
50064
50065
50066 private $startJoker;
50067
50068
50069
50070
50071 private $endJoker;
50072
50073
50074
50075
50076
50077
50078
50079
50080 public static function create($expr)
50081 {
50082 if (preg_match('/^(.{3,}?)([imsxuADU]*)$/', $expr, $m)) {
50083 $start = substr($m[1], 0, 1);
50084 $end = substr($m[1], -1);
50085
50086 if (
50087 ($start === $end && !preg_match('/[*?[:alnum:] \\\\]/', $start))
50088 || ($start === '{' && $end === '}')
50089 || ($start === '(' && $end === ')')
50090 ) {
50091 return new self(substr($m[1], 1, -1), $m[2], $end);
50092 }
50093 }
50094
50095 throw new \InvalidArgumentException('Given expression is not a regex.');
50096 }
50097
50098
50099
50100
50101
50102
50103 public function __construct($pattern, $options = '', $delimiter = null)
50104 {
50105 if (null !== $delimiter) {
50106
50107  $pattern = str_replace('\\'.$delimiter, $delimiter, $pattern);
50108 }
50109
50110 $this->parsePattern($pattern);
50111 $this->options = $options;
50112 }
50113
50114
50115
50116
50117 public function __toString()
50118 {
50119 return $this->render();
50120 }
50121
50122
50123
50124
50125 public function render()
50126 {
50127 return self::BOUNDARY
50128 .$this->renderPattern()
50129 .self::BOUNDARY
50130 .$this->options;
50131 }
50132
50133
50134
50135
50136 public function renderPattern()
50137 {
50138 return ($this->startFlag ? self::START_FLAG : '')
50139 .($this->startJoker ? self::JOKER : '')
50140 .str_replace(self::BOUNDARY, '\\'.self::BOUNDARY, $this->pattern)
50141 .($this->endJoker ? self::JOKER : '')
50142 .($this->endFlag ? self::END_FLAG : '');
50143 }
50144
50145
50146
50147
50148 public function isCaseSensitive()
50149 {
50150 return !$this->hasOption('i');
50151 }
50152
50153
50154
50155
50156 public function getType()
50157 {
50158 return Expression::TYPE_REGEX;
50159 }
50160
50161
50162
50163
50164 public function prepend($expr)
50165 {
50166 $this->pattern = $expr.$this->pattern;
50167
50168 return $this;
50169 }
50170
50171
50172
50173
50174 public function append($expr)
50175 {
50176 $this->pattern .= $expr;
50177
50178 return $this;
50179 }
50180
50181
50182
50183
50184
50185
50186 public function hasOption($option)
50187 {
50188 return false !== strpos($this->options, $option);
50189 }
50190
50191
50192
50193
50194
50195
50196 public function addOption($option)
50197 {
50198 if (!$this->hasOption($option)) {
50199 $this->options .= $option;
50200 }
50201
50202 return $this;
50203 }
50204
50205
50206
50207
50208
50209
50210 public function removeOption($option)
50211 {
50212 $this->options = str_replace($option, '', $this->options);
50213
50214 return $this;
50215 }
50216
50217
50218
50219
50220
50221
50222 public function setStartFlag($startFlag)
50223 {
50224 $this->startFlag = $startFlag;
50225
50226 return $this;
50227 }
50228
50229
50230
50231
50232 public function hasStartFlag()
50233 {
50234 return $this->startFlag;
50235 }
50236
50237
50238
50239
50240
50241
50242 public function setEndFlag($endFlag)
50243 {
50244 $this->endFlag = (bool) $endFlag;
50245
50246 return $this;
50247 }
50248
50249
50250
50251
50252 public function hasEndFlag()
50253 {
50254 return $this->endFlag;
50255 }
50256
50257
50258
50259
50260
50261
50262 public function setStartJoker($startJoker)
50263 {
50264 $this->startJoker = $startJoker;
50265
50266 return $this;
50267 }
50268
50269
50270
50271
50272 public function hasStartJoker()
50273 {
50274 return $this->startJoker;
50275 }
50276
50277
50278
50279
50280
50281
50282 public function setEndJoker($endJoker)
50283 {
50284 $this->endJoker = (bool) $endJoker;
50285
50286 return $this;
50287 }
50288
50289
50290
50291
50292 public function hasEndJoker()
50293 {
50294 return $this->endJoker;
50295 }
50296
50297
50298
50299
50300
50301
50302 public function replaceJokers($replacement)
50303 {
50304 $replace = function ($subject) use ($replacement) {
50305 $subject = $subject[0];
50306 $replace = 0 === substr_count($subject, '\\') % 2;
50307
50308 return $replace ? str_replace('.', $replacement, $subject) : $subject;
50309 };
50310
50311 $this->pattern = preg_replace_callback('~[\\\\]*\\.~', $replace, $this->pattern);
50312
50313 return $this;
50314 }
50315
50316
50317
50318
50319 private function parsePattern($pattern)
50320 {
50321 if ($this->startFlag = self::START_FLAG === substr($pattern, 0, 1)) {
50322 $pattern = substr($pattern, 1);
50323 }
50324
50325 if ($this->startJoker = self::JOKER === substr($pattern, 0, 2)) {
50326 $pattern = substr($pattern, 2);
50327 }
50328
50329 if ($this->endFlag = (self::END_FLAG === substr($pattern, -1) && self::ESCAPING !== substr($pattern, -2, -1))) {
50330 $pattern = substr($pattern, 0, -1);
50331 }
50332
50333 if ($this->endJoker = (self::JOKER === substr($pattern, -2) && self::ESCAPING !== substr($pattern, -3, -2))) {
50334 $pattern = substr($pattern, 0, -2);
50335 }
50336
50337 $this->pattern = $pattern;
50338 }
50339 }
50340 <?php
50341
50342
50343
50344
50345
50346
50347
50348
50349
50350
50351 namespace Symfony\Component\Finder\Expression;
50352
50353
50354
50355
50356 class Glob implements ValueInterface
50357 {
50358
50359
50360
50361 private $pattern;
50362
50363
50364
50365
50366 public function __construct($pattern)
50367 {
50368 $this->pattern = $pattern;
50369 }
50370
50371
50372
50373
50374 public function render()
50375 {
50376 return $this->pattern;
50377 }
50378
50379
50380
50381
50382 public function renderPattern()
50383 {
50384 return $this->pattern;
50385 }
50386
50387
50388
50389
50390 public function getType()
50391 {
50392 return Expression::TYPE_GLOB;
50393 }
50394
50395
50396
50397
50398 public function isCaseSensitive()
50399 {
50400 return true;
50401 }
50402
50403
50404
50405
50406 public function prepend($expr)
50407 {
50408 $this->pattern = $expr.$this->pattern;
50409
50410 return $this;
50411 }
50412
50413
50414
50415
50416 public function append($expr)
50417 {
50418 $this->pattern .= $expr;
50419
50420 return $this;
50421 }
50422
50423
50424
50425
50426
50427
50428 public function isExpandable()
50429 {
50430 return false !== strpos($this->pattern, '{')
50431 && false !== strpos($this->pattern, '}');
50432 }
50433
50434
50435
50436
50437
50438
50439
50440 public function toRegex($strictLeadingDot = true, $strictWildcardSlash = true)
50441 {
50442 $firstByte = true;
50443 $escaping = false;
50444 $inCurlies = 0;
50445 $regex = '';
50446 $sizeGlob = strlen($this->pattern);
50447 for ($i = 0; $i < $sizeGlob; $i++) {
50448 $car = $this->pattern[$i];
50449 if ($firstByte) {
50450 if ($strictLeadingDot && '.' !== $car) {
50451 $regex .= '(?=[^\.])';
50452 }
50453
50454 $firstByte = false;
50455 }
50456
50457 if ('/' === $car) {
50458 $firstByte = true;
50459 }
50460
50461 if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
50462 $regex .= "\\$car";
50463 } elseif ('*' === $car) {
50464 $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
50465 } elseif ('?' === $car) {
50466 $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
50467 } elseif ('{' === $car) {
50468 $regex .= $escaping ? '\\{' : '(';
50469 if (!$escaping) {
50470 ++$inCurlies;
50471 }
50472 } elseif ('}' === $car && $inCurlies) {
50473 $regex .= $escaping ? '}' : ')';
50474 if (!$escaping) {
50475 --$inCurlies;
50476 }
50477 } elseif (',' === $car && $inCurlies) {
50478 $regex .= $escaping ? ',' : '|';
50479 } elseif ('\\' === $car) {
50480 if ($escaping) {
50481 $regex .= '\\\\';
50482 $escaping = false;
50483 } else {
50484 $escaping = true;
50485 }
50486
50487 continue;
50488 } else {
50489 $regex .= $car;
50490 }
50491 $escaping = false;
50492 }
50493
50494 return new Regex('^'.$regex.'$');
50495 }
50496 }
50497 <?php
50498
50499
50500
50501
50502
50503
50504
50505
50506
50507
50508 namespace Symfony\Component\Finder\Expression;
50509
50510
50511
50512
50513 class Expression implements ValueInterface
50514 {
50515 const TYPE_REGEX = 1;
50516 const TYPE_GLOB = 2;
50517
50518
50519
50520
50521 private $value;
50522
50523
50524
50525
50526
50527
50528 public static function create($expr)
50529 {
50530 return new self($expr);
50531 }
50532
50533
50534
50535
50536 public function __construct($expr)
50537 {
50538 try {
50539 $this->value = Regex::create($expr);
50540 } catch (\InvalidArgumentException $e) {
50541 $this->value = new Glob($expr);
50542 }
50543 }
50544
50545
50546
50547
50548 public function __toString()
50549 {
50550 return $this->render();
50551 }
50552
50553
50554
50555
50556 public function render()
50557 {
50558 return $this->value->render();
50559 }
50560
50561
50562
50563
50564 public function renderPattern()
50565 {
50566 return $this->value->renderPattern();
50567 }
50568
50569
50570
50571
50572 public function isCaseSensitive()
50573 {
50574 return $this->value->isCaseSensitive();
50575 }
50576
50577
50578
50579
50580 public function getType()
50581 {
50582 return $this->value->getType();
50583 }
50584
50585
50586
50587
50588 public function prepend($expr)
50589 {
50590 $this->value->prepend($expr);
50591
50592 return $this;
50593 }
50594
50595
50596
50597
50598 public function append($expr)
50599 {
50600 $this->value->append($expr);
50601
50602 return $this;
50603 }
50604
50605
50606
50607
50608 public function isRegex()
50609 {
50610 return self::TYPE_REGEX === $this->value->getType();
50611 }
50612
50613
50614
50615
50616 public function isGlob()
50617 {
50618 return self::TYPE_GLOB === $this->value->getType();
50619 }
50620
50621
50622
50623
50624
50625
50626 public function getGlob()
50627 {
50628 if (self::TYPE_GLOB !== $this->value->getType()) {
50629 throw new \LogicException('Regex can\'t be transformed to glob.');
50630 }
50631
50632 return $this->value;
50633 }
50634
50635
50636
50637
50638 public function getRegex()
50639 {
50640 return self::TYPE_REGEX === $this->value->getType() ? $this->value : $this->value->toRegex();
50641 }
50642 }
50643 <?php
50644
50645
50646
50647
50648
50649
50650
50651
50652
50653
50654 namespace Symfony\Component\Finder\Expression;
50655
50656
50657
50658
50659 interface ValueInterface
50660 {
50661
50662
50663
50664
50665
50666 public function render();
50667
50668
50669
50670
50671
50672
50673 public function renderPattern();
50674
50675
50676
50677
50678
50679
50680 public function isCaseSensitive();
50681
50682
50683
50684
50685
50686
50687 public function getType();
50688
50689
50690
50691
50692
50693
50694 public function prepend($expr);
50695
50696
50697
50698
50699
50700
50701 public function append($expr);
50702 }
50703 <?php
50704
50705
50706
50707
50708
50709
50710
50711
50712
50713
50714 namespace Symfony\Component\Finder\Adapter;
50715
50716
50717
50718
50719 interface AdapterInterface
50720 {
50721
50722
50723
50724
50725
50726 public function setFollowLinks($followLinks);
50727
50728
50729
50730
50731
50732
50733 public function setMode($mode);
50734
50735
50736
50737
50738
50739
50740 public function setExclude(array $exclude);
50741
50742
50743
50744
50745
50746
50747 public function setDepths(array $depths);
50748
50749
50750
50751
50752
50753
50754 public function setNames(array $names);
50755
50756
50757
50758
50759
50760
50761 public function setNotNames(array $notNames);
50762
50763
50764
50765
50766
50767
50768 public function setContains(array $contains);
50769
50770
50771
50772
50773
50774
50775 public function setNotContains(array $notContains);
50776
50777
50778
50779
50780
50781
50782 public function setSizes(array $sizes);
50783
50784
50785
50786
50787
50788
50789 public function setDates(array $dates);
50790
50791
50792
50793
50794
50795
50796 public function setFilters(array $filters);
50797
50798
50799
50800
50801
50802
50803 public function setSort($sort);
50804
50805
50806
50807
50808
50809
50810 public function setPath(array $paths);
50811
50812
50813
50814
50815
50816
50817 public function setNotPath(array $notPaths);
50818
50819
50820
50821
50822
50823
50824 public function ignoreUnreadableDirs($ignore = true);
50825
50826
50827
50828
50829
50830
50831 public function searchInDirectory($dir);
50832
50833
50834
50835
50836
50837
50838 public function isSupported();
50839
50840
50841
50842
50843
50844
50845 public function getName();
50846 }
50847 <?php
50848
50849
50850
50851
50852
50853
50854
50855
50856
50857
50858 namespace Symfony\Component\Finder\Adapter;
50859
50860 use Symfony\Component\Finder\Shell\Shell;
50861 use Symfony\Component\Finder\Shell\Command;
50862 use Symfony\Component\Finder\Iterator\SortableIterator;
50863 use Symfony\Component\Finder\Expression\Expression;
50864
50865
50866
50867
50868
50869
50870 class BsdFindAdapter extends AbstractFindAdapter
50871 {
50872
50873
50874
50875 public function getName()
50876 {
50877 return 'bsd_find';
50878 }
50879
50880
50881
50882
50883 protected function canBeUsed()
50884 {
50885 return in_array($this->shell->getType(), array(Shell::TYPE_BSD, Shell::TYPE_DARWIN)) && parent::canBeUsed();
50886 }
50887
50888
50889
50890
50891 protected function buildFormatSorting(Command $command, $sort)
50892 {
50893 switch ($sort) {
50894 case SortableIterator::SORT_BY_NAME:
50895 $command->ins('sort')->add('| sort');
50896
50897 return;
50898 case SortableIterator::SORT_BY_TYPE:
50899 $format = '%HT';
50900 break;
50901 case SortableIterator::SORT_BY_ACCESSED_TIME:
50902 $format = '%a';
50903 break;
50904 case SortableIterator::SORT_BY_CHANGED_TIME:
50905 $format = '%c';
50906 break;
50907 case SortableIterator::SORT_BY_MODIFIED_TIME:
50908 $format = '%m';
50909 break;
50910 default:
50911 throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
50912 }
50913
50914 $command
50915 ->add('-print0 | xargs -0 stat -f')
50916 ->arg($format.'%t%N')
50917 ->add('| sort | cut -f 2');
50918 }
50919
50920
50921
50922
50923 protected function buildFindCommand(Command $command, $dir)
50924 {
50925 parent::buildFindCommand($command, $dir)->addAtIndex('-E', 1);
50926
50927 return $command;
50928 }
50929
50930
50931
50932
50933 protected function buildContentFiltering(Command $command, array $contains, $not = false)
50934 {
50935 foreach ($contains as $contain) {
50936 $expr = Expression::create($contain);
50937
50938
50939  $command
50940 ->add('| grep -v \'^$\'')
50941 ->add('| xargs -I{} grep -I')
50942 ->add($expr->isCaseSensitive() ? null : '-i')
50943 ->add($not ? '-L' : '-l')
50944 ->add('-Ee')->arg($expr->renderPattern())
50945 ->add('{}')
50946 ;
50947 }
50948 }
50949 }
50950 <?php
50951
50952
50953
50954
50955
50956
50957
50958
50959
50960
50961 namespace Symfony\Component\Finder\Adapter;
50962
50963 use Symfony\Component\Finder\Shell\Shell;
50964 use Symfony\Component\Finder\Shell\Command;
50965 use Symfony\Component\Finder\Iterator\SortableIterator;
50966 use Symfony\Component\Finder\Expression\Expression;
50967
50968
50969
50970
50971
50972
50973 class GnuFindAdapter extends AbstractFindAdapter
50974 {
50975
50976
50977
50978 public function getName()
50979 {
50980 return 'gnu_find';
50981 }
50982
50983
50984
50985
50986 protected function buildFormatSorting(Command $command, $sort)
50987 {
50988 switch ($sort) {
50989 case SortableIterator::SORT_BY_NAME:
50990 $command->ins('sort')->add('| sort');
50991
50992 return;
50993 case SortableIterator::SORT_BY_TYPE:
50994 $format = '%y';
50995 break;
50996 case SortableIterator::SORT_BY_ACCESSED_TIME:
50997 $format = '%A@';
50998 break;
50999 case SortableIterator::SORT_BY_CHANGED_TIME:
51000 $format = '%C@';
51001 break;
51002 case SortableIterator::SORT_BY_MODIFIED_TIME:
51003 $format = '%T@';
51004 break;
51005 default:
51006 throw new \InvalidArgumentException(sprintf('Unknown sort options: %s.', $sort));
51007 }
51008
51009 $command
51010 ->get('find')
51011 ->add('-printf')
51012 ->arg($format.' %h/%f\\n')
51013 ->add('| sort | cut')
51014 ->arg('-d ')
51015 ->arg('-f2-')
51016 ;
51017 }
51018
51019
51020
51021
51022 protected function canBeUsed()
51023 {
51024 return $this->shell->getType() === Shell::TYPE_UNIX && parent::canBeUsed();
51025 }
51026
51027
51028
51029
51030 protected function buildFindCommand(Command $command, $dir)
51031 {
51032 return parent::buildFindCommand($command, $dir)->add('-regextype posix-extended');
51033 }
51034
51035
51036
51037
51038 protected function buildContentFiltering(Command $command, array $contains, $not = false)
51039 {
51040 foreach ($contains as $contain) {
51041 $expr = Expression::create($contain);
51042
51043
51044  $command
51045 ->add('| xargs -I{} -r grep -I')
51046 ->add($expr->isCaseSensitive() ? null : '-i')
51047 ->add($not ? '-L' : '-l')
51048 ->add('-Ee')->arg($expr->renderPattern())
51049 ->add('{}')
51050 ;
51051 }
51052 }
51053 }
51054 <?php
51055
51056
51057
51058
51059
51060
51061
51062
51063
51064
51065 namespace Symfony\Component\Finder\Adapter;
51066
51067
51068
51069
51070
51071
51072 abstract class AbstractAdapter implements AdapterInterface
51073 {
51074 protected $followLinks = false;
51075 protected $mode = 0;
51076 protected $minDepth = 0;
51077 protected $maxDepth = PHP_INT_MAX;
51078 protected $exclude = array();
51079 protected $names = array();
51080 protected $notNames = array();
51081 protected $contains = array();
51082 protected $notContains = array();
51083 protected $sizes = array();
51084 protected $dates = array();
51085 protected $filters = array();
51086 protected $sort = false;
51087 protected $paths = array();
51088 protected $notPaths = array();
51089 protected $ignoreUnreadableDirs = false;
51090
51091 private static $areSupported = array();
51092
51093
51094
51095
51096 public function isSupported()
51097 {
51098 $name = $this->getName();
51099
51100 if (!array_key_exists($name, self::$areSupported)) {
51101 self::$areSupported[$name] = $this->canBeUsed();
51102 }
51103
51104 return self::$areSupported[$name];
51105 }
51106
51107
51108
51109
51110 public function setFollowLinks($followLinks)
51111 {
51112 $this->followLinks = $followLinks;
51113
51114 return $this;
51115 }
51116
51117
51118
51119
51120 public function setMode($mode)
51121 {
51122 $this->mode = $mode;
51123
51124 return $this;
51125 }
51126
51127
51128
51129
51130 public function setDepths(array $depths)
51131 {
51132 $this->minDepth = 0;
51133 $this->maxDepth = PHP_INT_MAX;
51134
51135 foreach ($depths as $comparator) {
51136 switch ($comparator->getOperator()) {
51137 case '>':
51138 $this->minDepth = $comparator->getTarget() + 1;
51139 break;
51140 case '>=':
51141 $this->minDepth = $comparator->getTarget();
51142 break;
51143 case '<':
51144 $this->maxDepth = $comparator->getTarget() - 1;
51145 break;
51146 case '<=':
51147 $this->maxDepth = $comparator->getTarget();
51148 break;
51149 default:
51150 $this->minDepth = $this->maxDepth = $comparator->getTarget();
51151 }
51152 }
51153
51154 return $this;
51155 }
51156
51157
51158
51159
51160 public function setExclude(array $exclude)
51161 {
51162 $this->exclude = $exclude;
51163
51164 return $this;
51165 }
51166
51167
51168
51169
51170 public function setNames(array $names)
51171 {
51172 $this->names = $names;
51173
51174 return $this;
51175 }
51176
51177
51178
51179
51180 public function setNotNames(array $notNames)
51181 {
51182 $this->notNames = $notNames;
51183
51184 return $this;
51185 }
51186
51187
51188
51189
51190 public function setContains(array $contains)
51191 {
51192 $this->contains = $contains;
51193
51194 return $this;
51195 }
51196
51197
51198
51199
51200 public function setNotContains(array $notContains)
51201 {
51202 $this->notContains = $notContains;
51203
51204 return $this;
51205 }
51206
51207
51208
51209
51210 public function setSizes(array $sizes)
51211 {
51212 $this->sizes = $sizes;
51213
51214 return $this;
51215 }
51216
51217
51218
51219
51220 public function setDates(array $dates)
51221 {
51222 $this->dates = $dates;
51223
51224 return $this;
51225 }
51226
51227
51228
51229
51230 public function setFilters(array $filters)
51231 {
51232 $this->filters = $filters;
51233
51234 return $this;
51235 }
51236
51237
51238
51239
51240 public function setSort($sort)
51241 {
51242 $this->sort = $sort;
51243
51244 return $this;
51245 }
51246
51247
51248
51249
51250 public function setPath(array $paths)
51251 {
51252 $this->paths = $paths;
51253
51254 return $this;
51255 }
51256
51257
51258
51259
51260 public function setNotPath(array $notPaths)
51261 {
51262 $this->notPaths = $notPaths;
51263
51264 return $this;
51265 }
51266
51267
51268
51269
51270 public function ignoreUnreadableDirs($ignore = true)
51271 {
51272 $this->ignoreUnreadableDirs = (bool) $ignore;
51273
51274 return $this;
51275 }
51276
51277
51278
51279
51280
51281
51282
51283
51284
51285
51286
51287
51288 abstract protected function canBeUsed();
51289 }
51290 <?php
51291
51292
51293
51294
51295
51296
51297
51298
51299
51300
51301 namespace Symfony\Component\Finder\Adapter;
51302
51303 use Symfony\Component\Finder\Exception\AccessDeniedException;
51304 use Symfony\Component\Finder\Iterator;
51305 use Symfony\Component\Finder\Shell\Shell;
51306 use Symfony\Component\Finder\Expression\Expression;
51307 use Symfony\Component\Finder\Shell\Command;
51308 use Symfony\Component\Finder\Comparator\NumberComparator;
51309 use Symfony\Component\Finder\Comparator\DateComparator;
51310
51311
51312
51313
51314
51315
51316 abstract class AbstractFindAdapter extends AbstractAdapter
51317 {
51318
51319
51320
51321 protected $shell;
51322
51323
51324
51325
51326 public function __construct()
51327 {
51328 $this->shell = new Shell();
51329 }
51330
51331
51332
51333
51334 public function searchInDirectory($dir)
51335 {
51336
51337  $dir = realpath($dir);
51338
51339
51340  if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode && ($this->contains || $this->notContains)) {
51341 return new Iterator\FilePathsIterator(array(), $dir);
51342 }
51343
51344 $command = Command::create();
51345 $find = $this->buildFindCommand($command, $dir);
51346
51347 if ($this->followLinks) {
51348 $find->add('-follow');
51349 }
51350
51351 $find->add('-mindepth')->add($this->minDepth + 1);
51352
51353 if (PHP_INT_MAX !== $this->maxDepth) {
51354 $find->add('-maxdepth')->add($this->maxDepth + 1);
51355 }
51356
51357 if (Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES === $this->mode) {
51358 $find->add('-type d');
51359 } elseif (Iterator\FileTypeFilterIterator::ONLY_FILES === $this->mode) {
51360 $find->add('-type f');
51361 }
51362
51363 $this->buildNamesFiltering($find, $this->names);
51364 $this->buildNamesFiltering($find, $this->notNames, true);
51365 $this->buildPathsFiltering($find, $dir, $this->paths);
51366 $this->buildPathsFiltering($find, $dir, $this->notPaths, true);
51367 $this->buildSizesFiltering($find, $this->sizes);
51368 $this->buildDatesFiltering($find, $this->dates);
51369
51370 $useGrep = $this->shell->testCommand('grep') && $this->shell->testCommand('xargs');
51371 $useSort = is_int($this->sort) && $this->shell->testCommand('sort') && $this->shell->testCommand('cut');
51372
51373 if ($useGrep && ($this->contains || $this->notContains)) {
51374 $grep = $command->ins('grep');
51375 $this->buildContentFiltering($grep, $this->contains);
51376 $this->buildContentFiltering($grep, $this->notContains, true);
51377 }
51378
51379 if ($useSort) {
51380 $this->buildSorting($command, $this->sort);
51381 }
51382
51383 $command->setErrorHandler(
51384 $this->ignoreUnreadableDirs
51385
51386  ? function ($stderr) { return; }
51387 : function ($stderr) { throw new AccessDeniedException($stderr); }
51388 );
51389
51390 $paths = $this->shell->testCommand('uniq') ? $command->add('| uniq')->execute() : array_unique($command->execute());
51391 $iterator = new Iterator\FilePathsIterator($paths, $dir);
51392
51393 if ($this->exclude) {
51394 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
51395 }
51396
51397 if (!$useGrep && ($this->contains || $this->notContains)) {
51398 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
51399 }
51400
51401 if ($this->filters) {
51402 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
51403 }
51404
51405 if (!$useSort && $this->sort) {
51406 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
51407 $iterator = $iteratorAggregate->getIterator();
51408 }
51409
51410 return $iterator;
51411 }
51412
51413
51414
51415
51416 protected function canBeUsed()
51417 {
51418 return $this->shell->testCommand('find');
51419 }
51420
51421
51422
51423
51424
51425
51426
51427 protected function buildFindCommand(Command $command, $dir)
51428 {
51429 return $command
51430 ->ins('find')
51431 ->add('find ')
51432 ->arg($dir)
51433 ->add('-noleaf'); 
51434  }
51435
51436
51437
51438
51439
51440
51441 private function buildNamesFiltering(Command $command, array $names, $not = false)
51442 {
51443 if (0 === count($names)) {
51444 return;
51445 }
51446
51447 $command->add($not ? '-not' : null)->cmd('(');
51448
51449 foreach ($names as $i => $name) {
51450 $expr = Expression::create($name);
51451
51452
51453  if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
51454 $expr = Expression::create($expr->getGlob()->toRegex(false));
51455 }
51456
51457
51458  
51459  
51460  if ($expr->isRegex()) {
51461 $regex = $expr->getRegex();
51462 $regex->prepend($regex->hasStartFlag() ? '/' : '/[^/]*')
51463 ->setStartFlag(false)
51464 ->setStartJoker(true)
51465 ->replaceJokers('[^/]');
51466 if (!$regex->hasEndFlag() || $regex->hasEndJoker()) {
51467 $regex->setEndJoker(false)->append('[^/]*');
51468 }
51469 }
51470
51471 $command
51472 ->add($i > 0 ? '-or' : null)
51473 ->add($expr->isRegex()
51474 ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
51475 : ($expr->isCaseSensitive() ? '-name' : '-iname')
51476 )
51477 ->arg($expr->renderPattern());
51478 }
51479
51480 $command->cmd(')');
51481 }
51482
51483
51484
51485
51486
51487
51488
51489 private function buildPathsFiltering(Command $command, $dir, array $paths, $not = false)
51490 {
51491 if (0 === count($paths)) {
51492 return;
51493 }
51494
51495 $command->add($not ? '-not' : null)->cmd('(');
51496
51497 foreach ($paths as $i => $path) {
51498 $expr = Expression::create($path);
51499
51500
51501  if ($expr->isGlob() && $expr->getGlob()->isExpandable()) {
51502 $expr = Expression::create($expr->getGlob()->toRegex(false));
51503 }
51504
51505
51506  if ($expr->isRegex()) {
51507 $regex = $expr->getRegex();
51508 $regex->prepend($regex->hasStartFlag() ? preg_quote($dir).DIRECTORY_SEPARATOR : '.*')->setEndJoker(!$regex->hasEndFlag());
51509 } else {
51510 $expr->prepend('*')->append('*');
51511 }
51512
51513 $command
51514 ->add($i > 0 ? '-or' : null)
51515 ->add($expr->isRegex()
51516 ? ($expr->isCaseSensitive() ? '-regex' : '-iregex')
51517 : ($expr->isCaseSensitive() ? '-path' : '-ipath')
51518 )
51519 ->arg($expr->renderPattern());
51520 }
51521
51522 $command->cmd(')');
51523 }
51524
51525
51526
51527
51528
51529 private function buildSizesFiltering(Command $command, array $sizes)
51530 {
51531 foreach ($sizes as $i => $size) {
51532 $command->add($i > 0 ? '-and' : null);
51533
51534 switch ($size->getOperator()) {
51535 case '<=':
51536 $command->add('-size -'.($size->getTarget() + 1).'c');
51537 break;
51538 case '>=':
51539 $command->add('-size +'.($size->getTarget() - 1).'c');
51540 break;
51541 case '>':
51542 $command->add('-size +'.$size->getTarget().'c');
51543 break;
51544 case '!=':
51545 $command->add('-size -'.$size->getTarget().'c');
51546 $command->add('-size +'.$size->getTarget().'c');
51547 break;
51548 case '<':
51549 default:
51550 $command->add('-size -'.$size->getTarget().'c');
51551 }
51552 }
51553 }
51554
51555
51556
51557
51558
51559 private function buildDatesFiltering(Command $command, array $dates)
51560 {
51561 foreach ($dates as $i => $date) {
51562 $command->add($i > 0 ? '-and' : null);
51563
51564 $mins = (int) round((time()-$date->getTarget()) / 60);
51565
51566 if (0 > $mins) {
51567
51568  $command->add(' -mmin -0');
51569
51570  return;
51571 }
51572
51573 switch ($date->getOperator()) {
51574 case '<=':
51575 $command->add('-mmin +'.($mins - 1));
51576 break;
51577 case '>=':
51578 $command->add('-mmin -'.($mins + 1));
51579 break;
51580 case '>':
51581 $command->add('-mmin -'.$mins);
51582 break;
51583 case '!=':
51584 $command->add('-mmin +'.$mins.' -or -mmin -'.$mins);
51585 break;
51586 case '<':
51587 default:
51588 $command->add('-mmin +'.$mins);
51589 }
51590 }
51591 }
51592
51593
51594
51595
51596
51597
51598
51599 private function buildSorting(Command $command, $sort)
51600 {
51601 $this->buildFormatSorting($command, $sort);
51602 }
51603
51604
51605
51606
51607
51608 abstract protected function buildFormatSorting(Command $command, $sort);
51609
51610
51611
51612
51613
51614
51615 abstract protected function buildContentFiltering(Command $command, array $contains, $not = false);
51616 }
51617 <?php
51618
51619
51620
51621
51622
51623
51624
51625
51626
51627
51628 namespace Symfony\Component\Finder\Adapter;
51629
51630 use Symfony\Component\Finder\Iterator;
51631
51632
51633
51634
51635
51636
51637 class PhpAdapter extends AbstractAdapter
51638 {
51639
51640
51641
51642 public function searchInDirectory($dir)
51643 {
51644 $flags = \RecursiveDirectoryIterator::SKIP_DOTS;
51645
51646 if ($this->followLinks) {
51647 $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS;
51648 }
51649
51650 $iterator = new \RecursiveIteratorIterator(
51651 new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs),
51652 \RecursiveIteratorIterator::SELF_FIRST
51653 );
51654
51655 if ($this->minDepth > 0 || $this->maxDepth < PHP_INT_MAX) {
51656 $iterator = new Iterator\DepthRangeFilterIterator($iterator, $this->minDepth, $this->maxDepth);
51657 }
51658
51659 if ($this->mode) {
51660 $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
51661 }
51662
51663 if ($this->exclude) {
51664 $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude);
51665 }
51666
51667 if ($this->names || $this->notNames) {
51668 $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
51669 }
51670
51671 if ($this->contains || $this->notContains) {
51672 $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains);
51673 }
51674
51675 if ($this->sizes) {
51676 $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes);
51677 }
51678
51679 if ($this->dates) {
51680 $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates);
51681 }
51682
51683 if ($this->filters) {
51684 $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters);
51685 }
51686
51687 if ($this->sort) {
51688 $iteratorAggregate = new Iterator\SortableIterator($iterator, $this->sort);
51689 $iterator = $iteratorAggregate->getIterator();
51690 }
51691
51692 if ($this->paths || $this->notPaths) {
51693 $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths);
51694 }
51695
51696 return $iterator;
51697 }
51698
51699
51700
51701
51702 public function getName()
51703 {
51704 return 'php';
51705 }
51706
51707
51708
51709
51710 protected function canBeUsed()
51711 {
51712 return true;
51713 }
51714 }
51715 <?php
51716
51717
51718
51719
51720
51721
51722
51723
51724
51725
51726 namespace Symfony\Component\Finder;
51727
51728
51729
51730
51731
51732
51733
51734
51735
51736
51737
51738
51739
51740
51741
51742
51743
51744
51745
51746
51747
51748
51749
51750 class Glob
51751 {
51752
51753
51754
51755
51756
51757
51758
51759
51760
51761 public static function toRegex($glob, $strictLeadingDot = true, $strictWildcardSlash = true)
51762 {
51763 $firstByte = true;
51764 $escaping = false;
51765 $inCurlies = 0;
51766 $regex = '';
51767 $sizeGlob = strlen($glob);
51768 for ($i = 0; $i < $sizeGlob; $i++) {
51769 $car = $glob[$i];
51770 if ($firstByte) {
51771 if ($strictLeadingDot && '.' !== $car) {
51772 $regex .= '(?=[^\.])';
51773 }
51774
51775 $firstByte = false;
51776 }
51777
51778 if ('/' === $car) {
51779 $firstByte = true;
51780 }
51781
51782 if ('.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) {
51783 $regex .= "\\$car";
51784 } elseif ('*' === $car) {
51785 $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*');
51786 } elseif ('?' === $car) {
51787 $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.');
51788 } elseif ('{' === $car) {
51789 $regex .= $escaping ? '\\{' : '(';
51790 if (!$escaping) {
51791 ++$inCurlies;
51792 }
51793 } elseif ('}' === $car && $inCurlies) {
51794 $regex .= $escaping ? '}' : ')';
51795 if (!$escaping) {
51796 --$inCurlies;
51797 }
51798 } elseif (',' === $car && $inCurlies) {
51799 $regex .= $escaping ? ',' : '|';
51800 } elseif ('\\' === $car) {
51801 if ($escaping) {
51802 $regex .= '\\\\';
51803 $escaping = false;
51804 } else {
51805 $escaping = true;
51806 }
51807
51808 continue;
51809 } else {
51810 $regex .= $car;
51811 }
51812 $escaping = false;
51813 }
51814
51815 return '#^'.$regex.'$#';
51816 }
51817 }
51818 <?php
51819
51820
51821
51822
51823
51824
51825
51826
51827
51828
51829 namespace Symfony\Component\Finder\Iterator;
51830
51831
51832
51833
51834
51835
51836 class DepthRangeFilterIterator extends FilterIterator
51837 {
51838 private $minDepth = 0;
51839
51840
51841
51842
51843
51844
51845
51846
51847 public function __construct(\RecursiveIteratorIterator $iterator, $minDepth = 0, $maxDepth = PHP_INT_MAX)
51848 {
51849 $this->minDepth = $minDepth;
51850 $iterator->setMaxDepth(PHP_INT_MAX === $maxDepth ? -1 : $maxDepth);
51851
51852 parent::__construct($iterator);
51853 }
51854
51855
51856
51857
51858
51859
51860 public function accept()
51861 {
51862 return $this->getInnerIterator()->getDepth() >= $this->minDepth;
51863 }
51864 }
51865 <?php
51866
51867
51868
51869
51870
51871
51872
51873
51874
51875
51876 namespace Symfony\Component\Finder\Iterator;
51877
51878
51879
51880
51881
51882
51883 class SortableIterator implements \IteratorAggregate
51884 {
51885 const SORT_BY_NAME = 1;
51886 const SORT_BY_TYPE = 2;
51887 const SORT_BY_ACCESSED_TIME = 3;
51888 const SORT_BY_CHANGED_TIME = 4;
51889 const SORT_BY_MODIFIED_TIME = 5;
51890
51891 private $iterator;
51892 private $sort;
51893
51894
51895
51896
51897
51898
51899
51900
51901
51902 public function __construct(\Traversable $iterator, $sort)
51903 {
51904 $this->iterator = $iterator;
51905
51906 if (self::SORT_BY_NAME === $sort) {
51907 $this->sort = function ($a, $b) {
51908 return strcmp($a->getRealpath(), $b->getRealpath());
51909 };
51910 } elseif (self::SORT_BY_TYPE === $sort) {
51911 $this->sort = function ($a, $b) {
51912 if ($a->isDir() && $b->isFile()) {
51913 return -1;
51914 } elseif ($a->isFile() && $b->isDir()) {
51915 return 1;
51916 }
51917
51918 return strcmp($a->getRealpath(), $b->getRealpath());
51919 };
51920 } elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
51921 $this->sort = function ($a, $b) {
51922 return ($a->getATime() - $b->getATime());
51923 };
51924 } elseif (self::SORT_BY_CHANGED_TIME === $sort) {
51925 $this->sort = function ($a, $b) {
51926 return ($a->getCTime() - $b->getCTime());
51927 };
51928 } elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
51929 $this->sort = function ($a, $b) {
51930 return ($a->getMTime() - $b->getMTime());
51931 };
51932 } elseif (is_callable($sort)) {
51933 $this->sort = $sort;
51934 } else {
51935 throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
51936 }
51937 }
51938
51939 public function getIterator()
51940 {
51941 $array = iterator_to_array($this->iterator, true);
51942 uasort($array, $this->sort);
51943
51944 return new \ArrayIterator($array);
51945 }
51946 }
51947 <?php
51948
51949
51950
51951
51952
51953
51954
51955
51956
51957
51958 namespace Symfony\Component\Finder\Iterator;
51959
51960
51961
51962
51963
51964
51965
51966 class FilecontentFilterIterator extends MultiplePcreFilterIterator
51967 {
51968
51969
51970
51971
51972
51973 public function accept()
51974 {
51975 if (!$this->matchRegexps && !$this->noMatchRegexps) {
51976 return true;
51977 }
51978
51979 $fileinfo = $this->current();
51980
51981 if ($fileinfo->isDir() || !$fileinfo->isReadable()) {
51982 return false;
51983 }
51984
51985 $content = $fileinfo->getContents();
51986 if (!$content) {
51987 return false;
51988 }
51989
51990
51991  foreach ($this->noMatchRegexps as $regex) {
51992 if (preg_match($regex, $content)) {
51993 return false;
51994 }
51995 }
51996
51997
51998  $match = true;
51999 if ($this->matchRegexps) {
52000 $match = false;
52001 foreach ($this->matchRegexps as $regex) {
52002 if (preg_match($regex, $content)) {
52003 return true;
52004 }
52005 }
52006 }
52007
52008 return $match;
52009 }
52010
52011
52012
52013
52014
52015
52016
52017
52018 protected function toRegex($str)
52019 {
52020 return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
52021 }
52022 }
52023 <?php
52024
52025
52026
52027
52028
52029
52030
52031
52032
52033
52034 namespace Symfony\Component\Finder\Iterator;
52035
52036 use Symfony\Component\Finder\SplFileInfo;
52037
52038
52039
52040
52041
52042
52043 class FilePathsIterator extends \ArrayIterator
52044 {
52045
52046
52047
52048 private $baseDir;
52049
52050
52051
52052
52053 private $baseDirLength;
52054
52055
52056
52057
52058 private $subPath;
52059
52060
52061
52062
52063 private $subPathname;
52064
52065
52066
52067
52068 private $current;
52069
52070
52071
52072
52073
52074 public function __construct(array $paths, $baseDir)
52075 {
52076 $this->baseDir = $baseDir;
52077 $this->baseDirLength = strlen($baseDir);
52078
52079 parent::__construct($paths);
52080 }
52081
52082
52083
52084
52085
52086
52087
52088 public function __call($name, array $arguments)
52089 {
52090 return call_user_func_array(array($this->current(), $name), $arguments);
52091 }
52092
52093
52094
52095
52096
52097
52098 public function current()
52099 {
52100 return $this->current;
52101 }
52102
52103
52104
52105
52106 public function key()
52107 {
52108 return $this->current->getPathname();
52109 }
52110
52111 public function next()
52112 {
52113 parent::next();
52114 $this->buildProperties();
52115 }
52116
52117 public function rewind()
52118 {
52119 parent::rewind();
52120 $this->buildProperties();
52121 }
52122
52123
52124
52125
52126 public function getSubPath()
52127 {
52128 return $this->subPath;
52129 }
52130
52131
52132
52133
52134 public function getSubPathname()
52135 {
52136 return $this->subPathname;
52137 }
52138
52139 private function buildProperties()
52140 {
52141 $absolutePath = parent::current();
52142
52143 if ($this->baseDir === substr($absolutePath, 0, $this->baseDirLength)) {
52144 $this->subPathname = ltrim(substr($absolutePath, $this->baseDirLength), '/\\');
52145 $dir = dirname($this->subPathname);
52146 $this->subPath = '.' === $dir ? '' : $dir;
52147 } else {
52148 $this->subPath = $this->subPathname = '';
52149 }
52150
52151 $this->current = new SplFileInfo(parent::current(), $this->subPath, $this->subPathname);
52152 }
52153 }
52154 <?php
52155
52156
52157
52158
52159
52160
52161
52162
52163
52164
52165 namespace Symfony\Component\Finder\Iterator;
52166
52167 use Symfony\Component\Finder\Comparator\NumberComparator;
52168
52169
52170
52171
52172
52173
52174 class SizeRangeFilterIterator extends FilterIterator
52175 {
52176 private $comparators = array();
52177
52178
52179
52180
52181
52182
52183
52184 public function __construct(\Iterator $iterator, array $comparators)
52185 {
52186 $this->comparators = $comparators;
52187
52188 parent::__construct($iterator);
52189 }
52190
52191
52192
52193
52194
52195
52196 public function accept()
52197 {
52198 $fileinfo = $this->current();
52199 if (!$fileinfo->isFile()) {
52200 return true;
52201 }
52202
52203 $filesize = $fileinfo->getSize();
52204 foreach ($this->comparators as $compare) {
52205 if (!$compare->test($filesize)) {
52206 return false;
52207 }
52208 }
52209
52210 return true;
52211 }
52212 }
52213 <?php
52214
52215
52216
52217
52218
52219
52220
52221
52222
52223
52224 namespace Symfony\Component\Finder\Iterator;
52225
52226
52227
52228
52229
52230
52231 class ExcludeDirectoryFilterIterator extends FilterIterator
52232 {
52233 private $patterns = array();
52234
52235
52236
52237
52238
52239
52240
52241 public function __construct(\Iterator $iterator, array $directories)
52242 {
52243 foreach ($directories as $directory) {
52244 $this->patterns[] = '#(^|/)'.preg_quote($directory, '#').'(/|$)#';
52245 }
52246
52247 parent::__construct($iterator);
52248 }
52249
52250
52251
52252
52253
52254
52255 public function accept()
52256 {
52257 $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath();
52258 $path = strtr($path, '\\', '/');
52259 foreach ($this->patterns as $pattern) {
52260 if (preg_match($pattern, $path)) {
52261 return false;
52262 }
52263 }
52264
52265 return true;
52266 }
52267 }
52268 <?php
52269
52270
52271
52272
52273
52274
52275
52276
52277
52278
52279 namespace Symfony\Component\Finder\Iterator;
52280
52281
52282
52283
52284
52285
52286
52287
52288 abstract class FilterIterator extends \FilterIterator
52289 {
52290
52291
52292
52293
52294
52295
52296 public function rewind()
52297 {
52298 $iterator = $this;
52299 while ($iterator instanceof \OuterIterator) {
52300 $innerIterator = $iterator->getInnerIterator();
52301
52302 if ($innerIterator instanceof RecursiveDirectoryIterator) {
52303 if ($innerIterator->isRewindable()) {
52304 $innerIterator->next();
52305 $innerIterator->rewind();
52306 }
52307 } elseif ($iterator->getInnerIterator() instanceof \FilesystemIterator) {
52308 $iterator->getInnerIterator()->next();
52309 $iterator->getInnerIterator()->rewind();
52310 }
52311 $iterator = $iterator->getInnerIterator();
52312 }
52313
52314 parent::rewind();
52315 }
52316 }
52317 <?php
52318
52319
52320
52321
52322
52323
52324
52325
52326
52327
52328 namespace Symfony\Component\Finder\Iterator;
52329
52330 use Symfony\Component\Finder\Expression\Expression;
52331
52332
52333
52334
52335
52336
52337 abstract class MultiplePcreFilterIterator extends FilterIterator
52338 {
52339 protected $matchRegexps = array();
52340 protected $noMatchRegexps = array();
52341
52342
52343
52344
52345
52346
52347
52348
52349 public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns)
52350 {
52351 foreach ($matchPatterns as $pattern) {
52352 $this->matchRegexps[] = $this->toRegex($pattern);
52353 }
52354
52355 foreach ($noMatchPatterns as $pattern) {
52356 $this->noMatchRegexps[] = $this->toRegex($pattern);
52357 }
52358
52359 parent::__construct($iterator);
52360 }
52361
52362
52363
52364
52365
52366
52367
52368
52369 protected function isRegex($str)
52370 {
52371 return Expression::create($str)->isRegex();
52372 }
52373
52374
52375
52376
52377
52378
52379
52380
52381 abstract protected function toRegex($str);
52382 }
52383 <?php
52384
52385
52386
52387
52388
52389
52390
52391
52392
52393
52394 namespace Symfony\Component\Finder\Iterator;
52395
52396
52397
52398
52399
52400
52401
52402
52403
52404 class CustomFilterIterator extends FilterIterator
52405 {
52406 private $filters = array();
52407
52408
52409
52410
52411
52412
52413
52414
52415
52416 public function __construct(\Iterator $iterator, array $filters)
52417 {
52418 foreach ($filters as $filter) {
52419 if (!is_callable($filter)) {
52420 throw new \InvalidArgumentException('Invalid PHP callback.');
52421 }
52422 }
52423 $this->filters = $filters;
52424
52425 parent::__construct($iterator);
52426 }
52427
52428
52429
52430
52431
52432
52433 public function accept()
52434 {
52435 $fileinfo = $this->current();
52436
52437 foreach ($this->filters as $filter) {
52438 if (false === call_user_func($filter, $fileinfo)) {
52439 return false;
52440 }
52441 }
52442
52443 return true;
52444 }
52445 }
52446 <?php
52447
52448
52449
52450
52451
52452
52453
52454
52455
52456
52457 namespace Symfony\Component\Finder\Iterator;
52458
52459 use Symfony\Component\Finder\Expression\Expression;
52460
52461
52462
52463
52464
52465
52466 class FilenameFilterIterator extends MultiplePcreFilterIterator
52467 {
52468
52469
52470
52471
52472
52473 public function accept()
52474 {
52475 $filename = $this->current()->getFilename();
52476
52477
52478  foreach ($this->noMatchRegexps as $regex) {
52479 if (preg_match($regex, $filename)) {
52480 return false;
52481 }
52482 }
52483
52484
52485  $match = true;
52486 if ($this->matchRegexps) {
52487 $match = false;
52488 foreach ($this->matchRegexps as $regex) {
52489 if (preg_match($regex, $filename)) {
52490 return true;
52491 }
52492 }
52493 }
52494
52495 return $match;
52496 }
52497
52498
52499
52500
52501
52502
52503
52504
52505
52506
52507
52508 protected function toRegex($str)
52509 {
52510 return Expression::create($str)->getRegex()->render();
52511 }
52512 }
52513 <?php
52514
52515
52516
52517
52518
52519
52520
52521
52522
52523
52524 namespace Symfony\Component\Finder\Iterator;
52525
52526 use Symfony\Component\Finder\Comparator\DateComparator;
52527
52528
52529
52530
52531
52532
52533 class DateRangeFilterIterator extends FilterIterator
52534 {
52535 private $comparators = array();
52536
52537
52538
52539
52540
52541
52542
52543 public function __construct(\Iterator $iterator, array $comparators)
52544 {
52545 $this->comparators = $comparators;
52546
52547 parent::__construct($iterator);
52548 }
52549
52550
52551
52552
52553
52554
52555 public function accept()
52556 {
52557 $fileinfo = $this->current();
52558
52559 if (!file_exists($fileinfo->getRealPath())) {
52560 return false;
52561 }
52562
52563 $filedate = $fileinfo->getMTime();
52564 foreach ($this->comparators as $compare) {
52565 if (!$compare->test($filedate)) {
52566 return false;
52567 }
52568 }
52569
52570 return true;
52571 }
52572 }
52573 <?php
52574
52575
52576
52577
52578
52579
52580
52581
52582
52583
52584 namespace Symfony\Component\Finder\Iterator;
52585
52586
52587
52588
52589
52590
52591 class FileTypeFilterIterator extends FilterIterator
52592 {
52593 const ONLY_FILES = 1;
52594 const ONLY_DIRECTORIES = 2;
52595
52596 private $mode;
52597
52598
52599
52600
52601
52602
52603
52604 public function __construct(\Iterator $iterator, $mode)
52605 {
52606 $this->mode = $mode;
52607
52608 parent::__construct($iterator);
52609 }
52610
52611
52612
52613
52614
52615
52616 public function accept()
52617 {
52618 $fileinfo = $this->current();
52619 if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) {
52620 return false;
52621 } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) {
52622 return false;
52623 }
52624
52625 return true;
52626 }
52627 }
52628 <?php
52629
52630
52631
52632
52633
52634
52635
52636
52637
52638
52639 namespace Symfony\Component\Finder\Iterator;
52640
52641 use Symfony\Component\Finder\Exception\AccessDeniedException;
52642 use Symfony\Component\Finder\SplFileInfo;
52643
52644
52645
52646
52647
52648
52649 class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator
52650 {
52651
52652
52653
52654 private $ignoreUnreadableDirs;
52655
52656
52657
52658
52659 private $rewindable;
52660
52661
52662
52663
52664
52665
52666
52667
52668
52669
52670 public function __construct($path, $flags, $ignoreUnreadableDirs = false)
52671 {
52672 if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) {
52673 throw new \RuntimeException('This iterator only support returning current as fileinfo.');
52674 }
52675
52676 parent::__construct($path, $flags);
52677 $this->ignoreUnreadableDirs = $ignoreUnreadableDirs;
52678 }
52679
52680
52681
52682
52683
52684
52685 public function current()
52686 {
52687 return new SplFileInfo(parent::current()->getPathname(), $this->getSubPath(), $this->getSubPathname());
52688 }
52689
52690
52691
52692
52693
52694
52695 public function getChildren()
52696 {
52697 try {
52698 $children = parent::getChildren();
52699
52700 if ($children instanceof self) {
52701
52702  $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs;
52703 }
52704
52705 return $children;
52706 } catch (\UnexpectedValueException $e) {
52707 if ($this->ignoreUnreadableDirs) {
52708
52709  return new \RecursiveArrayIterator(array());
52710 } else {
52711 throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e);
52712 }
52713 }
52714 }
52715
52716
52717
52718
52719 public function rewind()
52720 {
52721 if (false === $this->isRewindable()) {
52722 return;
52723 }
52724
52725
52726  parent::next();
52727
52728 parent::rewind();
52729 }
52730
52731
52732
52733
52734
52735
52736 public function isRewindable()
52737 {
52738 if (null !== $this->rewindable) {
52739 return $this->rewindable;
52740 }
52741
52742 if (false !== $stream = @opendir($this->getPath())) {
52743 $infos = stream_get_meta_data($stream);
52744 closedir($stream);
52745
52746 if ($infos['seekable']) {
52747 return $this->rewindable = true;
52748 }
52749 }
52750
52751 return $this->rewindable = false;
52752 }
52753 }
52754 <?php
52755
52756
52757
52758
52759
52760
52761
52762
52763
52764
52765 namespace Symfony\Component\Finder\Iterator;
52766
52767
52768
52769
52770
52771
52772
52773 class PathFilterIterator extends MultiplePcreFilterIterator
52774 {
52775
52776
52777
52778
52779
52780 public function accept()
52781 {
52782 $filename = $this->current()->getRelativePathname();
52783
52784 if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
52785 $filename = strtr($filename, '\\', '/');
52786 }
52787
52788
52789  foreach ($this->noMatchRegexps as $regex) {
52790 if (preg_match($regex, $filename)) {
52791 return false;
52792 }
52793 }
52794
52795
52796  $match = true;
52797 if ($this->matchRegexps) {
52798 $match = false;
52799 foreach ($this->matchRegexps as $regex) {
52800 if (preg_match($regex, $filename)) {
52801 return true;
52802 }
52803 }
52804 }
52805
52806 return $match;
52807 }
52808
52809
52810
52811
52812
52813
52814
52815
52816
52817
52818
52819
52820
52821
52822
52823 protected function toRegex($str)
52824 {
52825 return $this->isRegex($str) ? $str : '/'.preg_quote($str, '/').'/';
52826 }
52827 }
52828 <?php
52829
52830
52831
52832
52833
52834
52835
52836
52837
52838
52839 namespace Symfony\Component\Finder\Comparator;
52840
52841
52842
52843
52844
52845
52846 class DateComparator extends Comparator
52847 {
52848
52849
52850
52851
52852
52853
52854
52855 public function __construct($test)
52856 {
52857 if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) {
52858 throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test));
52859 }
52860
52861 try {
52862 $date = new \DateTime($matches[2]);
52863 $target = $date->format('U');
52864 } catch (\Exception $e) {
52865 throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2]));
52866 }
52867
52868 $operator = isset($matches[1]) ? $matches[1] : '==';
52869 if ('since' === $operator || 'after' === $operator) {
52870 $operator = '>';
52871 }
52872
52873 if ('until' === $operator || 'before' === $operator) {
52874 $operator = '<';
52875 }
52876
52877 $this->setOperator($operator);
52878 $this->setTarget($target);
52879 }
52880 }
52881 <?php
52882
52883
52884
52885
52886
52887
52888
52889
52890
52891
52892 namespace Symfony\Component\Finder\Comparator;
52893
52894
52895
52896
52897
52898
52899
52900
52901
52902
52903
52904
52905
52906
52907
52908
52909
52910
52911
52912
52913
52914
52915
52916 class NumberComparator extends Comparator
52917 {
52918
52919
52920
52921
52922
52923
52924
52925 public function __construct($test)
52926 {
52927 if (!preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) {
52928 throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test));
52929 }
52930
52931 $target = $matches[2];
52932 if (!is_numeric($target)) {
52933 throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target));
52934 }
52935 if (isset($matches[3])) {
52936
52937  switch (strtolower($matches[3])) {
52938 case 'k':
52939 $target *= 1000;
52940 break;
52941 case 'ki':
52942 $target *= 1024;
52943 break;
52944 case 'm':
52945 $target *= 1000000;
52946 break;
52947 case 'mi':
52948 $target *= 1024*1024;
52949 break;
52950 case 'g':
52951 $target *= 1000000000;
52952 break;
52953 case 'gi':
52954 $target *= 1024*1024*1024;
52955 break;
52956 }
52957 }
52958
52959 $this->setTarget($target);
52960 $this->setOperator(isset($matches[1]) ? $matches[1] : '==');
52961 }
52962 }
52963 <?php
52964
52965
52966
52967
52968
52969
52970
52971
52972
52973
52974 namespace Symfony\Component\Finder\Comparator;
52975
52976
52977
52978
52979
52980
52981 class Comparator
52982 {
52983 private $target;
52984 private $operator = '==';
52985
52986
52987
52988
52989
52990
52991 public function getTarget()
52992 {
52993 return $this->target;
52994 }
52995
52996
52997
52998
52999
53000
53001 public function setTarget($target)
53002 {
53003 $this->target = $target;
53004 }
53005
53006
53007
53008
53009
53010
53011 public function getOperator()
53012 {
53013 return $this->operator;
53014 }
53015
53016
53017
53018
53019
53020
53021
53022
53023 public function setOperator($operator)
53024 {
53025 if (!$operator) {
53026 $operator = '==';
53027 }
53028
53029 if (!in_array($operator, array('>', '<', '>=', '<=', '==', '!='))) {
53030 throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator));
53031 }
53032
53033 $this->operator = $operator;
53034 }
53035
53036
53037
53038
53039
53040
53041
53042
53043 public function test($test)
53044 {
53045 switch ($this->operator) {
53046 case '>':
53047 return $test > $this->target;
53048 case '>=':
53049 return $test >= $this->target;
53050 case '<':
53051 return $test < $this->target;
53052 case '<=':
53053 return $test <= $this->target;
53054 case '!=':
53055 return $test != $this->target;
53056 }
53057
53058 return $test == $this->target;
53059 }
53060 }
53061 <?php
53062
53063
53064
53065
53066
53067
53068
53069
53070
53071
53072 namespace Symfony\Component\Finder\Exception;
53073
53074
53075
53076
53077 class AccessDeniedException extends \UnexpectedValueException
53078 {
53079 }
53080 <?php
53081
53082
53083
53084
53085
53086
53087
53088
53089
53090
53091 namespace Symfony\Component\Finder\Exception;
53092
53093
53094
53095
53096 interface ExceptionInterface
53097 {
53098
53099
53100
53101 public function getAdapter();
53102 }
53103 <?php
53104
53105
53106
53107
53108
53109
53110
53111
53112
53113
53114 namespace Symfony\Component\Finder\Exception;
53115
53116
53117
53118
53119 class OperationNotPermitedException extends AdapterFailureException
53120 {
53121 }
53122 <?php
53123
53124
53125
53126
53127
53128
53129
53130
53131
53132
53133 namespace Symfony\Component\Finder\Exception;
53134
53135 use Symfony\Component\Finder\Adapter\AdapterInterface;
53136
53137
53138
53139
53140
53141
53142 class AdapterFailureException extends \RuntimeException implements ExceptionInterface
53143 {
53144
53145
53146
53147 private $adapter;
53148
53149
53150
53151
53152
53153
53154 public function __construct(AdapterInterface $adapter, $message = null, \Exception $previous = null)
53155 {
53156 $this->adapter = $adapter;
53157 parent::__construct($message ?: 'Search failed with "'.$adapter->getName().'" adapter.', $previous);
53158 }
53159
53160
53161
53162
53163 public function getAdapter()
53164 {
53165 return $this->adapter;
53166 }
53167 }
53168 <?php
53169
53170
53171
53172
53173
53174
53175
53176
53177
53178
53179 namespace Symfony\Component\Finder\Exception;
53180
53181 use Symfony\Component\Finder\Adapter\AdapterInterface;
53182 use Symfony\Component\Finder\Shell\Command;
53183
53184
53185
53186
53187 class ShellCommandFailureException extends AdapterFailureException
53188 {
53189
53190
53191
53192 private $command;
53193
53194
53195
53196
53197
53198
53199 public function __construct(AdapterInterface $adapter, Command $command, \Exception $previous = null)
53200 {
53201 $this->command = $command;
53202 parent::__construct($adapter, 'Shell command failed: "'.$command->join().'".', $previous);
53203 }
53204
53205
53206
53207
53208 public function getCommand()
53209 {
53210 return $this->command;
53211 }
53212 }
53213 <?php
53214
53215
53216
53217
53218
53219
53220
53221
53222
53223
53224 namespace Symfony\Component\Finder;
53225
53226
53227
53228
53229
53230
53231 class SplFileInfo extends \SplFileInfo
53232 {
53233 private $relativePath;
53234 private $relativePathname;
53235
53236
53237
53238
53239
53240
53241
53242
53243 public function __construct($file, $relativePath, $relativePathname)
53244 {
53245 parent::__construct($file);
53246 $this->relativePath = $relativePath;
53247 $this->relativePathname = $relativePathname;
53248 }
53249
53250
53251
53252
53253
53254
53255 public function getRelativePath()
53256 {
53257 return $this->relativePath;
53258 }
53259
53260
53261
53262
53263
53264
53265 public function getRelativePathname()
53266 {
53267 return $this->relativePathname;
53268 }
53269
53270
53271
53272
53273
53274
53275
53276
53277 public function getContents()
53278 {
53279 $level = error_reporting(0);
53280 $content = file_get_contents($this->getPathname());
53281 error_reporting($level);
53282 if (false === $content) {
53283 $error = error_get_last();
53284 throw new \RuntimeException($error['message']);
53285 }
53286
53287 return $content;
53288 }
53289 }
53290 <?php
53291
53292
53293
53294
53295
53296
53297
53298
53299
53300
53301 namespace Seld\JsonLint;
53302
53303 class Undefined
53304 {
53305 }
53306 <?php
53307
53308
53309
53310
53311
53312
53313
53314
53315
53316
53317 namespace Seld\JsonLint;
53318 use stdClass;
53319
53320
53321
53322
53323
53324
53325
53326
53327
53328
53329
53330
53331
53332
53333 class JsonParser
53334 {
53335 const DETECT_KEY_CONFLICTS = 1;
53336 const ALLOW_DUPLICATE_KEYS = 2;
53337 const PARSE_TO_ASSOC = 4;
53338
53339 private $lexer;
53340
53341 private $flags;
53342 private $stack;
53343 private $vstack; 
53344  private $lstack; 
53345
53346 private $symbols = array(
53347 'error' => 2,
53348 'JSONString' => 3,
53349 'STRING' => 4,
53350 'JSONNumber' => 5,
53351 'NUMBER' => 6,
53352 'JSONNullLiteral' => 7,
53353 'NULL' => 8,
53354 'JSONBooleanLiteral' => 9,
53355 'TRUE' => 10,
53356 'FALSE' => 11,
53357 'JSONText' => 12,
53358 'JSONValue' => 13,
53359 'EOF' => 14,
53360 'JSONObject' => 15,
53361 'JSONArray' => 16,
53362 '{' => 17,
53363 '}' => 18,
53364 'JSONMemberList' => 19,
53365 'JSONMember' => 20,
53366 ':' => 21,
53367 ',' => 22,
53368 '[' => 23,
53369 ']' => 24,
53370 'JSONElementList' => 25,
53371 '$accept' => 0,
53372 '$end' => 1,
53373 );
53374
53375 private $terminals_ = array(
53376 2 => "error",
53377 4 => "STRING",
53378 6 => "NUMBER",
53379 8 => "NULL",
53380 10 => "TRUE",
53381 11 => "FALSE",
53382 14 => "EOF",
53383 17 => "{",
53384 18 => "}",
53385 21 => ":",
53386 22 => ",",
53387 23 => "[",
53388 24 => "]",
53389 );
53390
53391 private $productions_ = array(
53392 0,
53393 array(3, 1),
53394 array(5, 1),
53395 array(7, 1),
53396 array(9, 1),
53397 array(9, 1),
53398 array(12, 2),
53399 array(13, 1),
53400 array(13, 1),
53401 array(13, 1),
53402 array(13, 1),
53403 array(13, 1),
53404 array(13, 1),
53405 array(15, 2),
53406 array(15, 3),
53407 array(20, 3),
53408 array(19, 1),
53409 array(19, 3),
53410 array(16, 2),
53411 array(16, 3),
53412 array(25, 1),
53413 array(25, 3)
53414 );
53415
53416 private $table = array(array(3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 12 => 1, 13 => 2, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15)), array( 1 => array(3)), array( 14 => array(1,16)), array( 14 => array(2,7), 18 => array(2,7), 22 => array(2,7), 24 => array(2,7)), array( 14 => array(2,8), 18 => array(2,8), 22 => array(2,8), 24 => array(2,8)), array( 14 => array(2,9), 18 => array(2,9), 22 => array(2,9), 24 => array(2,9)), array( 14 => array(2,10), 18 => array(2,10), 22 => array(2,10), 24 => array(2,10)), array( 14 => array(2,11), 18 => array(2,11), 22 => array(2,11), 24 => array(2,11)), array( 14 => array(2,12), 18 => array(2,12), 22 => array(2,12), 24 => array(2,12)), array( 14 => array(2,3), 18 => array(2,3), 22 => array(2,3), 24 => array(2,3)), array( 14 => array(2,4), 18 => array(2,4), 22 => array(2,4), 24 => array(2,4)), array( 14 => array(2,5), 18 => array(2,5), 22 => array(2,5), 24 => array(2,5)), array( 14 => array(2,1), 18 => array(2,1), 21 => array(2,1), 22 => array(2,1), 24 => array(2,1)), array( 14 => array(2,2), 18 => array(2,2), 22 => array(2,2), 24 => array(2,2)), array( 3 => 20, 4 => array(1,12), 18 => array(1,17), 19 => 18, 20 => 19 ), array( 3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 13 => 23, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15), 24 => array(1,21), 25 => 22 ), array( 1 => array(2,6)), array( 14 => array(2,13), 18 => array(2,13), 22 => array(2,13), 24 => array(2,13)), array( 18 => array(1,24), 22 => array(1,25)), array( 18 => array(2,16), 22 => array(2,16)), array( 21 => array(1,26)), array( 14 => array(2,18), 18 => array(2,18), 22 => array(2,18), 24 => array(2,18)), array( 22 => array(1,28), 24 => array(1,27)), array( 22 => array(2,20), 24 => array(2,20)), array( 14 => array(2,14), 18 => array(2,14), 22 => array(2,14), 24 => array(2,14)), array( 3 => 20, 4 => array(1,12), 20 => 29 ), array( 3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 13 => 30, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15)), array( 14 => array(2,19), 18 => array(2,19), 22 => array(2,19), 24 => array(2,19)), array( 3 => 5, 4 => array(1,12), 5 => 6, 6 => array(1,13), 7 => 3, 8 => array(1,9), 9 => 4, 10 => array(1,10), 11 => array(1,11), 13 => 31, 15 => 7, 16 => 8, 17 => array(1,14), 23 => array(1,15)), array( 18 => array(2,17), 22 => array(2,17)), array( 18 => array(2,15), 22 => array(2,15)), array( 22 => array(2,21), 24 => array(2,21)),
53417 );
53418
53419 private $defaultActions = array(
53420 16 => array(2, 6)
53421 );
53422
53423
53424
53425
53426
53427 public function lint($input)
53428 {
53429 try {
53430 $this->parse($input);
53431 } catch (ParsingException $e) {
53432 return $e;
53433 }
53434 }
53435
53436
53437
53438
53439
53440
53441 public function parse($input, $flags = 0)
53442 {
53443 $this->failOnBOM($input);
53444
53445 $this->flags = $flags;
53446
53447 $this->stack = array(0);
53448 $this->vstack = array(null);
53449 $this->lstack = array();
53450
53451 $yytext = '';
53452 $yylineno = 0;
53453 $yyleng = 0;
53454 $recovering = 0;
53455 $TERROR = 2;
53456 $EOF = 1;
53457
53458 $this->lexer = new Lexer();
53459 $this->lexer->setInput($input);
53460
53461 $yyloc = $this->lexer->yylloc;
53462 $this->lstack[] = $yyloc;
53463
53464 $symbol = null;
53465 $preErrorSymbol = null;
53466 $state = null;
53467 $action = null;
53468 $a = null;
53469 $r = null;
53470 $yyval = new stdClass;
53471 $p = null;
53472 $len = null;
53473 $newState = null;
53474 $expected = null;
53475 $errStr = null;
53476
53477 while (true) {
53478
53479  $state = $this->stack[count($this->stack)-1];
53480
53481
53482  if (isset($this->defaultActions[$state])) {
53483 $action = $this->defaultActions[$state];
53484 } else {
53485 if ($symbol == null) {
53486 $symbol = $this->lex();
53487 }
53488
53489  $action = isset($this->table[$state][$symbol]) ? $this->table[$state][$symbol] : false;
53490 }
53491
53492
53493  if (!$action || !$action[0]) {
53494 if (!$recovering) {
53495
53496  $expected = array();
53497 foreach ($this->table[$state] as $p => $ignore) {
53498 if (isset($this->terminals_[$p]) && $p > 2) {
53499 $expected[] = "'" . $this->terminals_[$p] . "'";
53500 }
53501 }
53502
53503 $message = null;
53504 if (in_array("'STRING'", $expected) && in_array(substr($this->lexer->match, 0, 1), array('"', "'"))) {
53505 $message = "Invalid string";
53506 if ("'" === substr($this->lexer->match, 0, 1)) {
53507 $message .= ", it appears you used single quotes instead of double quotes";
53508 } elseif (preg_match('{".+?(\\\\[^"bfnrt/\\\\u])}', $this->lexer->getUpcomingInput(), $match)) {
53509 $message .= ", it appears you have an unescaped backslash at: ".$match[1];
53510 } elseif (preg_match('{"(?:[^"]+|\\\\")*$}m', $this->lexer->getUpcomingInput())) {
53511 $message .= ", it appears you forgot to terminated the string, or attempted to write a multiline string which is invalid";
53512 }
53513 }
53514
53515 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
53516 $errStr .= $this->lexer->showPosition() . "\n";
53517 if ($message) {
53518 $errStr .= $message;
53519 } else {
53520 $errStr .= (count($expected) > 1) ? "Expected one of: " : "Expected: ";
53521 $errStr .= implode(', ', $expected);
53522 }
53523
53524 if (',' === substr(trim($this->lexer->getPastInput()), -1)) {
53525 $errStr .= " - It appears you have an extra trailing comma";
53526 }
53527
53528 $this->parseError($errStr, array(
53529 'text' => $this->lexer->match,
53530 'token' => !empty($this->terminals_[$symbol]) ? $this->terminals_[$symbol] : $symbol,
53531 'line' => $this->lexer->yylineno,
53532 'loc' => $yyloc,
53533 'expected' => $expected,
53534 ));
53535 }
53536
53537
53538  if ($recovering == 3) {
53539 if ($symbol == $EOF) {
53540 throw new ParsingException($errStr ?: 'Parsing halted.');
53541 }
53542
53543
53544  $yyleng = $this->lexer->yyleng;
53545 $yytext = $this->lexer->yytext;
53546 $yylineno = $this->lexer->yylineno;
53547 $yyloc = $this->lexer->yylloc;
53548 $symbol = $this->lex();
53549 }
53550
53551
53552  while (true) {
53553
53554  if (array_key_exists($TERROR, $this->table[$state])) {
53555 break;
53556 }
53557 if ($state == 0) {
53558 throw new ParsingException($errStr ?: 'Parsing halted.');
53559 }
53560 $this->popStack(1);
53561 $state = $this->stack[count($this->stack)-1];
53562 }
53563
53564 $preErrorSymbol = $symbol; 
53565  $symbol = $TERROR; 
53566  $state = $this->stack[count($this->stack)-1];
53567 $action = isset($this->table[$state][$TERROR]) ? $this->table[$state][$TERROR] : false;
53568 $recovering = 3; 
53569  }
53570
53571
53572  if (is_array($action[0]) && count($action) > 1) {
53573 throw new ParsingException('Parse Error: multiple actions possible at state: ' . $state . ', token: ' . $symbol);
53574 }
53575
53576 switch ($action[0]) {
53577 case 1: 
53578  $this->stack[] = $symbol;
53579 $this->vstack[] = $this->lexer->yytext;
53580 $this->lstack[] = $this->lexer->yylloc;
53581 $this->stack[] = $action[1]; 
53582  $symbol = null;
53583 if (!$preErrorSymbol) { 
53584  $yyleng = $this->lexer->yyleng;
53585 $yytext = $this->lexer->yytext;
53586 $yylineno = $this->lexer->yylineno;
53587 $yyloc = $this->lexer->yylloc;
53588 if ($recovering > 0) {
53589 $recovering--;
53590 }
53591 } else { 
53592  $symbol = $preErrorSymbol;
53593 $preErrorSymbol = null;
53594 }
53595 break;
53596
53597 case 2: 
53598  $len = $this->productions_[$action[1]][1];
53599
53600
53601  $yyval->token = $this->vstack[count($this->vstack) - $len]; 
53602  
53603  $yyval->store = array( 
53604  'first_line' => $this->lstack[count($this->lstack) - ($len ?: 1)]['first_line'],
53605 'last_line' => $this->lstack[count($this->lstack) - 1]['last_line'],
53606 'first_column' => $this->lstack[count($this->lstack) - ($len ?: 1)]['first_column'],
53607 'last_column' => $this->lstack[count($this->lstack) - 1]['last_column'],
53608 );
53609 $r = $this->performAction($yyval, $yytext, $yyleng, $yylineno, $action[1], $this->vstack, $this->lstack);
53610
53611 if (!$r instanceof Undefined) {
53612 return $r;
53613 }
53614
53615 if ($len) {
53616 $this->popStack($len);
53617 }
53618
53619 $this->stack[] = $this->productions_[$action[1]][0]; 
53620  $this->vstack[] = $yyval->token;
53621 $this->lstack[] = $yyval->store;
53622 $newState = $this->table[$this->stack[count($this->stack)-2]][$this->stack[count($this->stack)-1]];
53623 $this->stack[] = $newState;
53624 break;
53625
53626 case 3: 
53627
53628 return true;
53629 }
53630 }
53631
53632 return true;
53633 }
53634
53635 protected function parseError($str, $hash)
53636 {
53637 throw new ParsingException($str, $hash);
53638 }
53639
53640
53641  
53642  
53643  private function performAction(stdClass $yyval, $yytext, $yyleng, $yylineno, $yystate, &$tokens)
53644 {
53645
53646  $len = count($tokens) - 1;
53647 switch ($yystate) {
53648 case 1:
53649 $yytext = preg_replace_callback('{(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4})}', array($this, 'stringInterpolation'), $yytext);
53650 $yyval->token = $yytext;
53651 break;
53652 case 2:
53653 if (strpos($yytext, 'e') !== false || strpos($yytext, 'E') !== false) {
53654 $yyval->token = floatval($yytext);
53655 } else {
53656 $yyval->token = strpos($yytext, '.') === false ? intval($yytext) : floatval($yytext);
53657 }
53658 break;
53659 case 3:
53660 $yyval->token = null;
53661 break;
53662 case 4:
53663 $yyval->token = true;
53664 break;
53665 case 5:
53666 $yyval->token = false;
53667 break;
53668 case 6:
53669 return $yyval->token = $tokens[$len-1];
53670 case 13:
53671 if ($this->flags & self::PARSE_TO_ASSOC) {
53672 $yyval->token = array();
53673 } else {
53674 $yyval->token = new stdClass;
53675 }
53676 break;
53677 case 14:
53678 $yyval->token = $tokens[$len-1];
53679 break;
53680 case 15:
53681 $yyval->token = array($tokens[$len-2], $tokens[$len]);
53682 break;
53683 case 16:
53684 $property = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0];
53685 if ($this->flags & self::PARSE_TO_ASSOC) {
53686 $yyval->token = array();
53687 $yyval->token[$property] = $tokens[$len][1];
53688 } else {
53689 $yyval->token = new stdClass;
53690 $yyval->token->$property = $tokens[$len][1];
53691 }
53692 break;
53693 case 17:
53694 if ($this->flags & self::PARSE_TO_ASSOC) {
53695 $yyval->token =& $tokens[$len-2];
53696 $key = $tokens[$len][0];
53697 if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len-2][$key])) {
53698 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
53699 $errStr .= $this->lexer->showPosition() . "\n";
53700 $errStr .= "Duplicate key: ".$tokens[$len][0];
53701 throw new ParsingException($errStr);
53702 } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len-2][$key])) {
53703 $duplicateCount = 1;
53704 do {
53705 $duplicateKey = $key . '.' . $duplicateCount++;
53706 } while (isset($tokens[$len-2][$duplicateKey]));
53707 $key = $duplicateKey;
53708 }
53709 $tokens[$len-2][$key] = $tokens[$len][1];
53710 } else {
53711 $yyval->token = $tokens[$len-2];
53712 $key = $tokens[$len][0] === '' ? '_empty_' : $tokens[$len][0];
53713 if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($tokens[$len-2]->{$key})) {
53714 $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
53715 $errStr .= $this->lexer->showPosition() . "\n";
53716 $errStr .= "Duplicate key: ".$tokens[$len][0];
53717 throw new ParsingException($errStr);
53718 } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($tokens[$len-2]->{$key})) {
53719 $duplicateCount = 1;
53720 do {
53721 $duplicateKey = $key . '.' . $duplicateCount++;
53722 } while (isset($tokens[$len-2]->$duplicateKey));
53723 $key = $duplicateKey;
53724 }
53725 $tokens[$len-2]->$key = $tokens[$len][1];
53726 }
53727 break;
53728 case 18:
53729 $yyval->token = array();
53730 break;
53731 case 19:
53732 $yyval->token = $tokens[$len-1];
53733 break;
53734 case 20:
53735 $yyval->token = array($tokens[$len]);
53736 break;
53737 case 21:
53738 $tokens[$len-2][] = $tokens[$len];
53739 $yyval->token = $tokens[$len-2];
53740 break;
53741 }
53742
53743 return new Undefined();
53744 }
53745
53746 private function stringInterpolation($match)
53747 {
53748 switch ($match[0]) {
53749 case '\\\\':
53750 return '\\';
53751 case '\"':
53752 return '"';
53753 case '\b':
53754 return chr(8);
53755 case '\f':
53756 return chr(12);
53757 case '\n':
53758 return "\n";
53759 case '\r':
53760 return "\r";
53761 case '\t':
53762 return "\t";
53763 case '\/':
53764 return "/";
53765 default:
53766 return html_entity_decode('&#x'.ltrim(substr($match[0], 2), '0').';', 0, 'UTF-8');
53767 }
53768 }
53769
53770 private function popStack($n)
53771 {
53772 $this->stack = array_slice($this->stack, 0, - (2 * $n));
53773 $this->vstack = array_slice($this->vstack, 0, - $n);
53774 $this->lstack = array_slice($this->lstack, 0, - $n);
53775 }
53776
53777 private function lex()
53778 {
53779 $token = $this->lexer->lex() ?: 1; 
53780  
53781  if (!is_numeric($token)) {
53782 $token = isset($this->symbols[$token]) ? $this->symbols[$token] : $token;
53783 }
53784
53785 return $token;
53786 }
53787
53788 private function failOnBOM($input)
53789 {
53790
53791  $bom = "\xEF\xBB\xBF";
53792
53793 if (substr($input, 0, 3) === $bom) {
53794 $this->parseError("BOM detected, make sure your input does not include a Unicode Byte-Order-Mark", array());
53795 }
53796 }
53797 }
53798 <?php
53799
53800
53801
53802
53803
53804
53805
53806
53807
53808
53809 namespace Seld\JsonLint;
53810
53811
53812
53813
53814
53815
53816 class Lexer
53817 {
53818 private $EOF = 1;
53819 private $rules = array(
53820 0 => '/^\s+/',
53821 1 => '/^-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][+-]?[0-9]+)?\b/',
53822 2 => '{^"(\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f\\\\"])*"}',
53823 3 => '/^\{/',
53824 4 => '/^\}/',
53825 5 => '/^\[/',
53826 6 => '/^\]/',
53827 7 => '/^,/',
53828 8 => '/^:/',
53829 9 => '/^true\b/',
53830 10 => '/^false\b/',
53831 11 => '/^null\b/',
53832 12 => '/^$/',
53833 13 => '/^./',
53834 );
53835
53836 private $conditions = array(
53837 "INITIAL" => array(
53838 "rules" => array(0,1,2,3,4,5,6,7,8,9,10,11,12,13),
53839 "inclusive" => true,
53840 ),
53841 );
53842
53843 private $conditionStack;
53844 private $input;
53845 private $more;
53846 private $done;
53847 private $matched;
53848
53849 public $match;
53850 public $yylineno;
53851 public $yyleng;
53852 public $yytext;
53853 public $yylloc;
53854
53855 public function lex()
53856 {
53857 $r = $this->next();
53858 if (!$r instanceof Undefined) {
53859 return $r;
53860 }
53861
53862 return $this->lex();
53863 }
53864
53865 public function setInput($input)
53866 {
53867 $this->input = $input;
53868 $this->more = false;
53869 $this->done = false;
53870 $this->yylineno = $this->yyleng = 0;
53871 $this->yytext = $this->matched = $this->match = '';
53872 $this->conditionStack = array('INITIAL');
53873 $this->yylloc = array('first_line' => 1, 'first_column' => 0, 'last_line' => 1, 'last_column' => 0);
53874
53875 return $this;
53876 }
53877
53878 public function showPosition()
53879 {
53880 $pre = str_replace("\n", '', $this->getPastInput());
53881 $c = str_repeat('-', max(0, strlen($pre) - 1)); 
53882
53883 return $pre . str_replace("\n", '', $this->getUpcomingInput()) . "\n" . $c . "^";
53884 }
53885
53886 public function getPastInput()
53887 {
53888 $past = substr($this->matched, 0, strlen($this->matched) - strlen($this->match));
53889
53890 return (strlen($past) > 20 ? '...' : '') . substr($past, -20);
53891 }
53892
53893 public function getUpcomingInput()
53894 {
53895 $next = $this->match;
53896 if (strlen($next) < 20) {
53897 $next .= substr($this->input, 0, 20 - strlen($next));
53898 }
53899
53900 return substr($next, 0, 20) . (strlen($next) > 20 ? '...' : '');
53901 }
53902
53903 protected function parseError($str, $hash)
53904 {
53905 throw new \Exception($str);
53906 }
53907
53908 private function next()
53909 {
53910 if ($this->done) {
53911 return $this->EOF;
53912 }
53913 if (!$this->input) {
53914 $this->done = true;
53915 }
53916
53917 $token = null;
53918 $match = null;
53919 $col = null;
53920 $lines = null;
53921
53922 if (!$this->more) {
53923 $this->yytext = '';
53924 $this->match = '';
53925 }
53926
53927 $rules = $this->getCurrentRules();
53928 $rulesLen = count($rules);
53929
53930 for ($i=0; $i < $rulesLen; $i++) {
53931 if (preg_match($this->rules[$rules[$i]], $this->input, $match)) {
53932 preg_match_all('/\n.*/', $match[0], $lines);
53933 $lines = $lines[0];
53934 if ($lines) {
53935 $this->yylineno += count($lines);
53936 }
53937
53938 $this->yylloc = array(
53939 'first_line' => $this->yylloc['last_line'],
53940 'last_line' => $this->yylineno+1,
53941 'first_column' => $this->yylloc['last_column'],
53942 'last_column' => $lines ? strlen($lines[count($lines) - 1]) - 1 : $this->yylloc['last_column'] + strlen($match[0]),
53943 );
53944 $this->yytext .= $match[0];
53945 $this->match .= $match[0];
53946 $this->yyleng = strlen($this->yytext);
53947 $this->more = false;
53948 $this->input = substr($this->input, strlen($match[0]));
53949 $this->matched .= $match[0];
53950 $token = $this->performAction($rules[$i], $this->conditionStack[count($this->conditionStack)-1]);
53951 if ($token) {
53952 return $token;
53953 }
53954
53955 return new Undefined();
53956 }
53957 }
53958
53959 if ($this->input === "") {
53960 return $this->EOF;
53961 }
53962
53963 $this->parseError(
53964 'Lexical error on line ' . ($this->yylineno+1) . ". Unrecognized text.\n" . $this->showPosition(),
53965 array(
53966 'text' => "",
53967 'token' => null,
53968 'line' => $this->yylineno,
53969 )
53970 );
53971 }
53972
53973 private function getCurrentRules()
53974 {
53975 return $this->conditions[$this->conditionStack[count($this->conditionStack)-1]]['rules'];
53976 }
53977
53978 private function performAction($avoiding_name_collisions, $YY_START)
53979 {
53980 switch ($avoiding_name_collisions) {
53981 case 0:
53982 break;
53983 case 1:
53984 return 6;
53985 break;
53986 case 2:
53987 $this->yytext = substr($this->yytext, 1, $this->yyleng-2);
53988
53989 return 4;
53990 case 3:
53991 return 17;
53992 case 4:
53993 return 18;
53994 case 5:
53995 return 23;
53996 case 6:
53997 return 24;
53998 case 7:
53999 return 22;
54000 case 8:
54001 return 21;
54002 case 9:
54003 return 10;
54004 case 10:
54005 return 11;
54006 case 11:
54007 return 8;
54008 case 12:
54009 return 14;
54010 case 13:
54011 return 'INVALID';
54012 }
54013 }
54014 }
54015 <?php
54016
54017
54018
54019
54020
54021
54022
54023
54024
54025
54026 namespace Seld\JsonLint;
54027
54028 class ParsingException extends \Exception
54029 {
54030 protected $details;
54031
54032 public function __construct($message, $details = array())
54033 {
54034 $this->details = $details;
54035 parent::__construct($message);
54036 }
54037
54038 public function getDetails()
54039 {
54040 return $this->details;
54041 }
54042 }
54043 <?php
54044
54045
54046
54047
54048
54049
54050
54051
54052 namespace JsonSchema;
54053
54054 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
54055 use JsonSchema\Uri\UriRetriever;
54056
54057
54058
54059
54060
54061
54062
54063 class RefResolver
54064 {
54065
54066
54067
54068
54069
54070
54071
54072 protected static $depth = 0;
54073
54074
54075
54076
54077
54078 public static $maxDepth = 7;
54079
54080
54081
54082
54083 protected $uriRetriever = null;
54084
54085
54086
54087
54088 public function __construct($retriever = null)
54089 {
54090 $this->uriRetriever = $retriever;
54091 }
54092
54093
54094
54095
54096
54097
54098
54099
54100 public function fetchRef($ref, $sourceUri)
54101 {
54102 $retriever = $this->getUriRetriever();
54103 $jsonSchema = $retriever->retrieve($ref, $sourceUri);
54104 $this->resolve($jsonSchema);
54105
54106 return $jsonSchema;
54107 }
54108
54109
54110
54111
54112
54113
54114
54115 public function getUriRetriever()
54116 {
54117 if (is_null($this->uriRetriever)) {
54118 $this->setUriRetriever(new UriRetriever);
54119 }
54120
54121 return $this->uriRetriever;
54122 }
54123
54124
54125
54126
54127
54128
54129
54130
54131
54132
54133
54134
54135
54136
54137
54138 public function resolve($schema, $sourceUri = null)
54139 {
54140 if (self::$depth > self::$maxDepth) {
54141 return;
54142 }
54143 ++self::$depth;
54144
54145 if (! is_object($schema)) {
54146 --self::$depth;
54147 return;
54148 }
54149
54150 if (null === $sourceUri && ! empty($schema->id)) {
54151 $sourceUri = $schema->id;
54152 }
54153
54154
54155  $this->resolveRef($schema, $sourceUri);
54156
54157
54158  
54159  foreach (array('additionalItems', 'additionalProperties', 'extends', 'items') as $propertyName) {
54160 $this->resolveProperty($schema, $propertyName, $sourceUri);
54161 }
54162
54163
54164  
54165  
54166  foreach (array('disallow', 'extends', 'items', 'type', 'allOf', 'anyOf', 'oneOf') as $propertyName) {
54167 $this->resolveArrayOfSchemas($schema, $propertyName, $sourceUri);
54168 }
54169
54170
54171  foreach (array('dependencies', 'patternProperties', 'properties') as $propertyName) {
54172 $this->resolveObjectOfSchemas($schema, $propertyName, $sourceUri);
54173 }
54174
54175 --self::$depth;
54176 }
54177
54178
54179
54180
54181
54182
54183
54184
54185
54186 public function resolveArrayOfSchemas($schema, $propertyName, $sourceUri)
54187 {
54188 if (! isset($schema->$propertyName) || ! is_array($schema->$propertyName)) {
54189 return;
54190 }
54191
54192 foreach ($schema->$propertyName as $possiblySchema) {
54193 $this->resolve($possiblySchema, $sourceUri);
54194 }
54195 }
54196
54197
54198
54199
54200
54201
54202
54203
54204
54205 public function resolveObjectOfSchemas($schema, $propertyName, $sourceUri)
54206 {
54207 if (! isset($schema->$propertyName) || ! is_object($schema->$propertyName)) {
54208 return;
54209 }
54210
54211 foreach (get_object_vars($schema->$propertyName) as $possiblySchema) {
54212 $this->resolve($possiblySchema, $sourceUri);
54213 }
54214 }
54215
54216
54217
54218
54219
54220
54221
54222
54223
54224 public function resolveProperty($schema, $propertyName, $sourceUri)
54225 {
54226 if (! isset($schema->$propertyName)) {
54227 return;
54228 }
54229
54230 $this->resolve($schema->$propertyName, $sourceUri);
54231 }
54232
54233
54234
54235
54236
54237
54238
54239
54240
54241 public function resolveRef($schema, $sourceUri)
54242 {
54243 $ref = '$ref';
54244
54245 if (empty($schema->$ref)) {
54246 return;
54247 }
54248
54249 $refSchema = $this->fetchRef($schema->$ref, $sourceUri);
54250 unset($schema->$ref);
54251
54252
54253  foreach (get_object_vars($refSchema) as $prop => $value) {
54254 $schema->$prop = $value;
54255 }
54256 }
54257
54258
54259
54260
54261
54262
54263
54264 public function setUriRetriever(UriRetriever $retriever)
54265 {
54266 $this->uriRetriever = $retriever;
54267
54268 return $this;
54269 }
54270 }
54271 <?php
54272
54273
54274
54275
54276
54277
54278
54279
54280 namespace JsonSchema\Constraints;
54281
54282 use JsonSchema\Exception\InvalidArgumentException;
54283 use JsonSchema\Uri\UriResolver;
54284
54285
54286
54287
54288
54289
54290
54291 class Undefined extends Constraint
54292 {
54293
54294
54295
54296 public function check($value, $schema = null, $path = null, $i = null)
54297 {
54298 if (is_null($schema)) {
54299 return;
54300 }
54301
54302 if (!is_object($schema)) {
54303 throw new InvalidArgumentException(
54304 'Given schema must be an object in ' . $path
54305 . ' but is a ' . gettype($schema)
54306 );
54307 }
54308
54309 $i = is_null($i) ? "" : $i;
54310 $path = $this->incrementPath($path, $i);
54311
54312
54313  $this->validateCommonProperties($value, $schema, $path);
54314
54315
54316  $this->validateOfProperties($value, $schema, $path);
54317
54318
54319  $this->validateTypes($value, $schema, $path, $i);
54320 }
54321
54322
54323
54324
54325
54326
54327
54328
54329
54330 public function validateTypes($value, $schema = null, $path = null, $i = null)
54331 {
54332
54333  if (is_array($value)) {
54334 $this->checkArray($value, $schema, $path, $i);
54335 }
54336
54337
54338  if (is_object($value) && (isset($schema->properties) || isset($schema->patternProperties))) {
54339 $this->checkObject(
54340 $value,
54341 isset($schema->properties) ? $schema->properties : null,
54342 $path,
54343 isset($schema->additionalProperties) ? $schema->additionalProperties : null,
54344 isset($schema->patternProperties) ? $schema->patternProperties : null
54345 );
54346 }
54347
54348
54349  if (is_string($value)) {
54350 $this->checkString($value, $schema, $path, $i);
54351 }
54352
54353
54354  if (is_numeric($value)) {
54355 $this->checkNumber($value, $schema, $path, $i);
54356 }
54357
54358
54359  if (isset($schema->enum)) {
54360 $this->checkEnum($value, $schema, $path, $i);
54361 }
54362 }
54363
54364
54365
54366
54367
54368
54369
54370
54371
54372 protected function validateCommonProperties($value, $schema = null, $path = null, $i = "")
54373 {
54374
54375  if (isset($schema->extends)) {
54376 if (is_string($schema->extends)) {
54377 $schema->extends = $this->validateUri($schema, $schema->extends);
54378 }
54379 if (is_array($schema->extends)) {
54380 foreach ($schema->extends as $extends) {
54381 $this->checkUndefined($value, $extends, $path, $i);
54382 }
54383 } else {
54384 $this->checkUndefined($value, $schema->extends, $path, $i);
54385 }
54386 }
54387
54388
54389  if (is_object($value)) {
54390
54391 if (!($value instanceof Undefined) && isset($schema->required) && is_array($schema->required) ) {
54392
54393  foreach ($schema->required as $required) {
54394 if (!property_exists($value, $required)) {
54395 $this->addError($path, "the property " . $required . " is required");
54396 }
54397 }
54398 } else if (isset($schema->required) && !is_array($schema->required)) {
54399
54400  if ( $schema->required && $value instanceof Undefined) {
54401 $this->addError($path, "is missing and it is required");
54402 }
54403 }
54404 }
54405
54406
54407  if (!($value instanceof Undefined)) {
54408 $this->checkType($value, $schema, $path);
54409 }
54410
54411
54412  if (isset($schema->disallow)) {
54413 $initErrors = $this->getErrors();
54414
54415 $typeSchema = new \stdClass();
54416 $typeSchema->type = $schema->disallow;
54417 $this->checkType($value, $typeSchema, $path);
54418
54419
54420  if (count($this->getErrors()) == count($initErrors)) {
54421 $this->addError($path, "disallowed value was matched");
54422 } else {
54423 $this->errors = $initErrors;
54424 }
54425 }
54426
54427 if (isset($schema->not)) {
54428 $initErrors = $this->getErrors();
54429 $this->checkUndefined($value, $schema->not, $path, $i);
54430
54431
54432  if (count($this->getErrors()) == count($initErrors)) {
54433 $this->addError($path, "matched a schema which it should not");
54434 } else {
54435 $this->errors = $initErrors;
54436 }
54437 }
54438
54439
54440  if (is_object($value)) {
54441 if (isset($schema->minProperties)) {
54442 if (count(get_object_vars($value)) < $schema->minProperties) {
54443 $this->addError($path, "must contain a minimum of " . $schema->minProperties . " properties");
54444 }
54445 }
54446 if (isset($schema->maxProperties)) {
54447 if (count(get_object_vars($value)) > $schema->maxProperties) {
54448 $this->addError($path, "must contain no more than " . $schema->maxProperties . " properties");
54449 }
54450 }
54451 }
54452
54453
54454  if (is_object($value) && isset($schema->dependencies)) {
54455 $this->validateDependencies($value, $schema->dependencies, $path);
54456 }
54457 }
54458
54459
54460
54461
54462
54463
54464
54465
54466
54467 protected function validateOfProperties($value, $schema, $path, $i = "")
54468 {
54469
54470  if ($value instanceof Undefined) {
54471 return;
54472 }
54473
54474 if (isset($schema->allOf)) {
54475 $isValid = true;
54476 foreach ($schema->allOf as $allOf) {
54477 $initErrors = $this->getErrors();
54478 $this->checkUndefined($value, $allOf, $path, $i);
54479 $isValid = $isValid && (count($this->getErrors()) == count($initErrors));
54480 }
54481 if (!$isValid) {
54482 $this->addError($path, "failed to match all schemas");
54483 }
54484 }
54485
54486 if (isset($schema->anyOf)) {
54487 $isValid = false;
54488 $startErrors = $this->getErrors();
54489 foreach ($schema->anyOf as $anyOf) {
54490 $initErrors = $this->getErrors();
54491 $this->checkUndefined($value, $anyOf, $path, $i);
54492 if ($isValid = (count($this->getErrors()) == count($initErrors))) {
54493 break;
54494 }
54495 }
54496 if (!$isValid) {
54497 $this->addError($path, "failed to match at least one schema");
54498 } else {
54499 $this->errors = $startErrors;
54500 }
54501 }
54502
54503 if (isset($schema->oneOf)) {
54504 $allErrors = array();
54505 $matchedSchemas = 0;
54506 $startErrors = $this->getErrors();
54507 foreach ($schema->oneOf as $oneOf) {
54508 $this->errors = array();
54509 $this->checkUndefined($value, $oneOf, $path, $i);
54510 if (count($this->getErrors()) == 0) {
54511 $matchedSchemas++;
54512 }
54513 $allErrors = array_merge($allErrors, array_values($this->getErrors()));
54514 }
54515 if ($matchedSchemas !== 1) {
54516 $this->addErrors(
54517 array_merge(
54518 $allErrors,
54519 array(array(
54520 'property' => $path,
54521 'message' => "failed to match exactly one schema"
54522 ),),
54523 $startErrors
54524 )
54525 );
54526 } else {
54527 $this->errors = $startErrors;
54528 }
54529 }
54530 }
54531
54532
54533
54534
54535
54536
54537
54538
54539
54540 protected function validateDependencies($value, $dependencies, $path, $i = "")
54541 {
54542 foreach ($dependencies as $key => $dependency) {
54543 if (property_exists($value, $key)) {
54544 if (is_string($dependency)) {
54545
54546  if (!property_exists($value, $dependency)) {
54547 $this->addError($path, "$key depends on $dependency and $dependency is missing");
54548 }
54549 } else if (is_array($dependency)) {
54550
54551  foreach ($dependency as $d) {
54552 if (!property_exists($value, $d)) {
54553 $this->addError($path, "$key depends on $d and $d is missing");
54554 }
54555 }
54556 } else if (is_object($dependency)) {
54557
54558  $this->checkUndefined($value, $dependency, $path, $i);
54559 }
54560 }
54561 }
54562 }
54563
54564 protected function validateUri($schema, $schemaUri = null)
54565 {
54566 $resolver = new UriResolver();
54567 $retriever = $this->getUriRetriever();
54568
54569 $jsonSchema = null;
54570 if ($resolver->isValid($schemaUri)) {
54571 $schemaId = property_exists($schema, 'id') ? $schema->id : null;
54572 $jsonSchema = $retriever->retrieve($schemaId, $schemaUri);
54573 }
54574
54575 return $jsonSchema;
54576 }
54577 }
54578 <?php
54579
54580
54581
54582
54583
54584
54585
54586
54587 namespace JsonSchema\Constraints;
54588
54589 use JsonSchema\Exception\InvalidArgumentException;
54590 use UnexpectedValueException as StandardUnexpectedValueException;
54591
54592
54593
54594
54595
54596
54597
54598 class Type extends Constraint
54599 {
54600
54601
54602
54603 static $wording = array(
54604 'integer' => 'an integer',
54605 'number' => 'a number',
54606 'boolean' => 'a boolean',
54607 'object' => 'an object',
54608 'array' => 'an array',
54609 'string' => 'a string',
54610 'null' => 'a null',
54611 'any' => NULL, 
54612  0 => NULL, 
54613  );
54614
54615
54616
54617
54618 public function check($value = null, $schema = null, $path = null, $i = null)
54619 {
54620 $type = isset($schema->type) ? $schema->type : null;
54621 $isValid = true;
54622
54623 if (is_array($type)) {
54624
54625  $validatedOneType = false;
54626 $errors = array();
54627 foreach ($type as $tp) {
54628 $validator = new Type($this->checkMode);
54629 $subSchema = new \stdClass();
54630 $subSchema->type = $tp;
54631 $validator->check($value, $subSchema, $path, null);
54632 $error = $validator->getErrors();
54633
54634 if (!count($error)) {
54635 $validatedOneType = true;
54636 break;
54637 }
54638
54639 $errors = $error;
54640 }
54641
54642 if (!$validatedOneType) {
54643 return $this->addErrors($errors);
54644 }
54645 } elseif (is_object($type)) {
54646 $this->checkUndefined($value, $type, $path);
54647 } else {
54648 $isValid = $this->validateType($value, $type);
54649 }
54650
54651 if ($isValid === false) {
54652 if (!isset(self::$wording[$type])) {
54653 throw new StandardUnexpectedValueException(
54654 sprintf(
54655 "No wording for %s available, expected wordings are: [%s]",
54656 var_export($type, true),
54657 implode(', ', array_filter(self::$wording)))
54658 );
54659 }
54660 $this->addError($path, gettype($value) . " value found, but " . self::$wording[$type] . " is required");
54661 }
54662 }
54663
54664
54665
54666
54667
54668
54669
54670
54671
54672
54673
54674 protected function validateType($value, $type)
54675 {
54676
54677  if (!$type) {
54678 return true;
54679 }
54680
54681 if ('integer' === $type) {
54682 return is_int($value);
54683 }
54684
54685 if ('number' === $type) {
54686 return is_numeric($value) && !is_string($value);
54687 }
54688
54689 if ('boolean' === $type) {
54690 return is_bool($value);
54691 }
54692
54693 if ('object' === $type) {
54694 return is_object($value);
54695
54696  }
54697
54698 if ('array' === $type) {
54699 return is_array($value);
54700 }
54701
54702 if ('string' === $type) {
54703 return is_string($value);
54704 }
54705
54706 if ('null' === $type) {
54707 return is_null($value);
54708 }
54709
54710 if ('any' === $type) {
54711 return true;
54712 }
54713
54714 throw new InvalidArgumentException((is_object($value) ? 'object' : $value) . ' is an invalid type for ' . $type);
54715 }
54716 }<?php
54717
54718
54719
54720
54721
54722
54723
54724
54725 namespace JsonSchema\Constraints;
54726
54727 use JsonSchema\Exception\InvalidArgumentException;
54728
54729
54730
54731
54732
54733
54734
54735 class Schema extends Constraint
54736 {
54737
54738
54739
54740 public function check($element, $schema = null, $path = null, $i = null)
54741 {
54742 if ($schema !== null) {
54743
54744  $this->checkUndefined($element, $schema, '', '');
54745 } elseif (property_exists($element, $this->inlineSchemaProperty)) {
54746
54747  $this->checkUndefined($element, $element->{$this->inlineSchemaProperty}, '', '');
54748 } else {
54749 throw new InvalidArgumentException('no schema found to verify against');
54750 }
54751 }
54752 }<?php
54753
54754
54755
54756
54757
54758
54759
54760
54761 namespace JsonSchema\Constraints;
54762
54763
54764
54765
54766
54767
54768
54769 class Number extends Constraint
54770 {
54771
54772
54773
54774 public function check($element, $schema = null, $path = null, $i = null)
54775 {
54776
54777  if (isset($schema->exclusiveMinimum)) {
54778 if (isset($schema->minimum)) {
54779 if ($schema->exclusiveMinimum && $element === $schema->minimum) {
54780 $this->addError($path, "must have a minimum value greater than boundary value of " . $schema->minimum);
54781 } else if ($element < $schema->minimum) {
54782 $this->addError($path, "must have a minimum value of " . $schema->minimum);
54783 }
54784 } else {
54785 $this->addError($path, "use of exclusiveMinimum requires presence of minimum");
54786 }
54787 } else if (isset($schema->minimum) && $element < $schema->minimum) {
54788 $this->addError($path, "must have a minimum value of " . $schema->minimum);
54789 }
54790
54791
54792  if (isset($schema->exclusiveMaximum)) {
54793 if (isset($schema->maximum)) {
54794 if ($schema->exclusiveMaximum && $element === $schema->maximum) {
54795 $this->addError($path, "must have a maximum value less than boundary value of " . $schema->maximum);
54796 } else if ($element > $schema->maximum) {
54797 $this->addError($path, "must have a maximum value of " . $schema->maximum);
54798 }
54799 } else {
54800 $this->addError($path, "use of exclusiveMaximum requires presence of maximum");
54801 }
54802 } else if (isset($schema->maximum) && $element > $schema->maximum) {
54803 $this->addError($path, "must have a maximum value of " . $schema->maximum);
54804 }
54805
54806
54807  if (isset($schema->divisibleBy) && $this->fmod($element, $schema->divisibleBy) != 0) {
54808 $this->addError($path, "is not divisible by " . $schema->divisibleBy);
54809 }
54810
54811
54812  if (isset($schema->multipleOf) && $this->fmod($element, $schema->multipleOf) != 0) {
54813 $this->addError($path, "must be a multiple of " . $schema->multipleOf);
54814 }
54815
54816 $this->checkFormat($element, $schema, $path, $i);
54817 }
54818
54819 private function fmod($number1, $number2)
54820 {
54821 $modulus = fmod($number1, $number2);
54822 $precision = abs(0.0000000001);
54823 $diff = (float)($modulus - $number2);
54824
54825 if (-$precision < $diff && $diff < $precision) {
54826 return 0.0;
54827 }
54828
54829 $decimals1 = mb_strpos($number1, ".") ? mb_strlen($number1) - mb_strpos($number1, ".") - 1 : 0;
54830 $decimals2 = mb_strpos($number2, ".") ? mb_strlen($number2) - mb_strpos($number2, ".") - 1 : 0;
54831
54832 return (float)round($modulus, max($decimals1, $decimals2));
54833 }
54834 }
54835 <?php
54836
54837
54838
54839
54840
54841
54842
54843
54844 namespace JsonSchema\Constraints;
54845
54846
54847
54848
54849
54850
54851
54852 class Object extends Constraint
54853 {
54854
54855
54856
54857 function check($element, $definition = null, $path = null, $additionalProp = null, $patternProperties = null)
54858 {
54859 if ($element instanceof Undefined) {
54860 return;
54861 }
54862
54863 $matches = array();
54864 if ($patternProperties) {
54865 $matches = $this->validatePatternProperties($element, $path, $patternProperties);
54866 }
54867
54868 if ($definition) {
54869
54870  $this->validateDefinition($element, $definition, $path);
54871 }
54872
54873
54874  $this->validateElement($element, $matches, $definition, $path, $additionalProp);
54875 }
54876
54877 public function validatePatternProperties($element, $path, $patternProperties)
54878 {
54879 $matches = array();
54880 foreach ($patternProperties as $pregex => $schema) {
54881
54882  if (@preg_match('/'. $pregex . '/', '') === false) {
54883 $this->addError($path, 'The pattern "' . $pregex . '" is invalid');
54884 continue;
54885 }
54886 foreach ($element as $i => $value) {
54887 if (preg_match('/' . $pregex . '/', $i)) {
54888 $matches[] = $i;
54889 $this->checkUndefined($value, $schema ? : new \stdClass(), $path, $i);
54890 }
54891 }
54892 }
54893 return $matches;
54894 }
54895
54896
54897
54898
54899
54900
54901
54902
54903
54904
54905 public function validateElement($element, $matches, $objectDefinition = null, $path = null, $additionalProp = null)
54906 {
54907 foreach ($element as $i => $value) {
54908
54909 $property = $this->getProperty($element, $i, new Undefined());
54910 $definition = $this->getProperty($objectDefinition, $i);
54911
54912
54913  if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
54914 $this->addError($path, "The property " . $i . " is not defined and the definition does not allow additional properties");
54915 }
54916
54917
54918  if (!in_array($i, $matches) && $additionalProp && !$definition) {
54919 if ($additionalProp === true) {
54920 $this->checkUndefined($value, null, $path, $i);
54921 } else {
54922 $this->checkUndefined($value, $additionalProp, $path, $i);
54923 }
54924 }
54925
54926
54927  $require = $this->getProperty($definition, 'requires');
54928 if ($require && !$this->getProperty($element, $require)) {
54929 $this->addError($path, "the presence of the property " . $i . " requires that " . $require . " also be present");
54930 }
54931
54932 if (!$definition) {
54933
54934  $this->checkUndefined($value, new \stdClass(), $path, $i);
54935 }
54936 }
54937 }
54938
54939
54940
54941
54942
54943
54944
54945
54946 public function validateDefinition($element, $objectDefinition = null, $path = null)
54947 {
54948 foreach ($objectDefinition as $i => $value) {
54949 $property = $this->getProperty($element, $i, new Undefined());
54950 $definition = $this->getProperty($objectDefinition, $i);
54951 $this->checkUndefined($property, $definition, $path, $i);
54952 }
54953 }
54954
54955
54956
54957
54958
54959
54960
54961
54962
54963
54964 protected function getProperty($element, $property, $fallback = null)
54965 {
54966 if (is_array($element) ) {
54967 return array_key_exists($property, $element) ? $element[$property] : $fallback;
54968 } elseif (is_object($element)) {
54969 return property_exists($element, $property) ? $element->$property : $fallback;
54970 }
54971
54972 return $fallback;
54973 }
54974 }<?php
54975
54976
54977
54978
54979
54980
54981
54982
54983 namespace JsonSchema\Constraints;
54984
54985
54986
54987
54988
54989
54990 interface ConstraintInterface
54991 {
54992
54993
54994
54995
54996
54997 public function getErrors();
54998
54999
55000
55001
55002
55003
55004 public function addErrors(array $errors);
55005
55006
55007
55008
55009
55010
55011
55012 public function addError($path, $message);
55013
55014
55015
55016
55017
55018
55019 public function isValid();
55020
55021
55022
55023
55024
55025
55026
55027
55028
55029
55030 public function check($value, $schema = null, $path = null, $i = null);
55031 }<?php
55032
55033
55034
55035
55036
55037
55038
55039
55040 namespace JsonSchema\Constraints;
55041
55042 use JsonSchema\Uri\UriRetriever;
55043
55044
55045
55046
55047
55048
55049
55050 abstract class Constraint implements ConstraintInterface
55051 {
55052 protected $checkMode = self::CHECK_MODE_NORMAL;
55053 protected $uriRetriever;
55054 protected $errors = array();
55055 protected $inlineSchemaProperty = '$schema';
55056
55057 const CHECK_MODE_NORMAL = 1;
55058 const CHECK_MODE_TYPE_CAST = 2;
55059
55060
55061
55062
55063
55064 public function __construct($checkMode = self::CHECK_MODE_NORMAL, UriRetriever $uriRetriever = null)
55065 {
55066 $this->checkMode = $checkMode;
55067 $this->uriRetriever = $uriRetriever;
55068 }
55069
55070
55071
55072
55073 public function getUriRetriever()
55074 {
55075 if (is_null($this->uriRetriever))
55076 {
55077 $this->setUriRetriever(new UriRetriever);
55078 }
55079
55080 return $this->uriRetriever;
55081 }
55082
55083
55084
55085
55086 public function setUriRetriever(UriRetriever $uriRetriever)
55087 {
55088 $this->uriRetriever = $uriRetriever;
55089 }
55090
55091
55092
55093
55094 public function addError($path, $message)
55095 {
55096 $this->errors[] = array(
55097 'property' => $path,
55098 'message' => $message
55099 );
55100 }
55101
55102
55103
55104
55105 public function addErrors(array $errors)
55106 {
55107 $this->errors = array_merge($this->errors, $errors);
55108 }
55109
55110
55111
55112
55113 public function getErrors()
55114 {
55115 return $this->errors;
55116 }
55117
55118
55119
55120
55121 public function isValid()
55122 {
55123 return !$this->getErrors();
55124 }
55125
55126
55127
55128
55129
55130 public function reset()
55131 {
55132 $this->errors = array();
55133 }
55134
55135
55136
55137
55138
55139
55140
55141
55142
55143 protected function incrementPath($path, $i)
55144 {
55145 if ($path !== '') {
55146 if (is_int($i)) {
55147 $path .= '[' . $i . ']';
55148 } elseif ($i == '') {
55149 $path .= '';
55150 } else {
55151 $path .= '.' . $i;
55152 }
55153 } else {
55154 $path = $i;
55155 }
55156
55157 return $path;
55158 }
55159
55160
55161
55162
55163
55164
55165
55166
55167
55168 protected function checkArray($value, $schema = null, $path = null, $i = null)
55169 {
55170 $validator = new Collection($this->checkMode, $this->uriRetriever);
55171 $validator->check($value, $schema, $path, $i);
55172
55173 $this->addErrors($validator->getErrors());
55174 }
55175
55176
55177
55178
55179
55180
55181
55182
55183
55184
55185 protected function checkObject($value, $schema = null, $path = null, $i = null, $patternProperties = null)
55186 {
55187 $validator = new Object($this->checkMode, $this->uriRetriever);
55188 $validator->check($value, $schema, $path, $i, $patternProperties);
55189
55190 $this->addErrors($validator->getErrors());
55191 }
55192
55193
55194
55195
55196
55197
55198
55199
55200
55201 protected function checkType($value, $schema = null, $path = null, $i = null)
55202 {
55203 $validator = new Type($this->checkMode, $this->uriRetriever);
55204 $validator->check($value, $schema, $path, $i);
55205
55206 $this->addErrors($validator->getErrors());
55207 }
55208
55209
55210
55211
55212
55213
55214
55215
55216
55217 protected function checkUndefined($value, $schema = null, $path = null, $i = null)
55218 {
55219 $validator = new Undefined($this->checkMode, $this->uriRetriever);
55220 $validator->check($value, $schema, $path, $i);
55221
55222 $this->addErrors($validator->getErrors());
55223 }
55224
55225
55226
55227
55228
55229
55230
55231
55232
55233 protected function checkString($value, $schema = null, $path = null, $i = null)
55234 {
55235 $validator = new String($this->checkMode, $this->uriRetriever);
55236 $validator->check($value, $schema, $path, $i);
55237
55238 $this->addErrors($validator->getErrors());
55239 }
55240
55241
55242
55243
55244
55245
55246
55247
55248
55249 protected function checkNumber($value, $schema = null, $path = null, $i = null)
55250 {
55251 $validator = new Number($this->checkMode, $this->uriRetriever);
55252 $validator->check($value, $schema, $path, $i);
55253
55254 $this->addErrors($validator->getErrors());
55255 }
55256
55257
55258
55259
55260
55261
55262
55263
55264
55265 protected function checkEnum($value, $schema = null, $path = null, $i = null)
55266 {
55267 $validator = new Enum($this->checkMode, $this->uriRetriever);
55268 $validator->check($value, $schema, $path, $i);
55269
55270 $this->addErrors($validator->getErrors());
55271 }
55272
55273 protected function checkFormat($value, $schema = null, $path = null, $i = null)
55274 {
55275 $validator = new Format($this->checkMode, $this->uriRetriever);
55276 $validator->check($value, $schema, $path, $i);
55277
55278 $this->addErrors($validator->getErrors());
55279 }
55280
55281
55282
55283
55284
55285 protected function retrieveUri($uri)
55286 {
55287 if (null === $this->uriRetriever) {
55288 $this->setUriRetriever(new UriRetriever);
55289 }
55290 $jsonSchema = $this->uriRetriever->retrieve($uri);
55291
55292  return $jsonSchema;
55293 }
55294 }
55295 <?php
55296
55297
55298
55299
55300
55301
55302
55303
55304 namespace JsonSchema\Constraints;
55305
55306
55307
55308
55309
55310
55311
55312 class Collection extends Constraint
55313 {
55314
55315
55316
55317 public function check($value, $schema = null, $path = null, $i = null)
55318 {
55319
55320  if (isset($schema->minItems) && count($value) < $schema->minItems) {
55321 $this->addError($path, "There must be a minimum of " . $schema->minItems . " in the array");
55322 }
55323
55324
55325  if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
55326 $this->addError($path, "There must be a maximum of " . $schema->maxItems . " in the array");
55327 }
55328
55329
55330  if (isset($schema->uniqueItems)) {
55331 $unique = $value;
55332 if (is_array($value) && count($value)) {
55333 $unique = array_map(function($e) { return var_export($e, true); }, $value);
55334 }
55335 if (count(array_unique($unique)) != count($value)) {
55336 $this->addError($path, "There are no duplicates allowed in the array");
55337 }
55338 }
55339
55340
55341  if (isset($schema->items)) {
55342 $this->validateItems($value, $schema, $path, $i);
55343 }
55344 }
55345
55346
55347
55348
55349
55350
55351
55352
55353
55354 protected function validateItems($value, $schema = null, $path = null, $i = null)
55355 {
55356 if (is_object($schema->items)) {
55357
55358  foreach ($value as $k => $v) {
55359 $initErrors = $this->getErrors();
55360
55361
55362  $this->checkUndefined($v, $schema->items, $path, $k);
55363
55364
55365  if (count($initErrors) < count($this->getErrors()) && (isset($schema->additionalItems) && $schema->additionalItems !== false)) {
55366 $secondErrors = $this->getErrors();
55367 $this->checkUndefined($v, $schema->additionalItems, $path, $k);
55368 }
55369
55370
55371  if (isset($secondErrors) && count($secondErrors) < count($this->getErrors())) {
55372 $this->errors = $secondErrors;
55373 } else if (isset($secondErrors) && count($secondErrors) === count($this->getErrors())) {
55374 $this->errors = $initErrors;
55375 }
55376 }
55377 } else {
55378
55379  foreach ($value as $k => $v) {
55380 if (array_key_exists($k, $schema->items)) {
55381 $this->checkUndefined($v, $schema->items[$k], $path, $k);
55382 } else {
55383
55384  if (property_exists($schema, 'additionalItems')) {
55385 if ($schema->additionalItems !== false) {
55386 $this->checkUndefined($v, $schema->additionalItems, $path, $k);
55387 } else {
55388 $this->addError(
55389 $path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items');
55390 }
55391 } else {
55392
55393  $this->checkUndefined($v, new \stdClass(), $path, $k);
55394 }
55395 }
55396 }
55397
55398
55399  if(count($value) > 0) {
55400 for ($k = count($value); $k < count($schema->items); $k++) {
55401 $this->checkUndefined(new Undefined(), $schema->items[$k], $path, $k);
55402 }
55403 }
55404 }
55405 }
55406 }<?php
55407
55408
55409
55410
55411
55412
55413
55414
55415 namespace JsonSchema\Constraints;
55416
55417
55418
55419
55420
55421
55422
55423 class Enum extends Constraint
55424 {
55425
55426
55427
55428 public function check($element, $schema = null, $path = null, $i = null)
55429 {
55430
55431  if ($element instanceof Undefined && (!isset($schema->required) || !$schema->required)) {
55432 return;
55433 }
55434
55435 foreach ($schema->enum as $enum) {
55436 if ((gettype($element) === gettype($enum)) && ($element == $enum)) {
55437 return;
55438 }
55439 }
55440
55441 $this->addError($path, "does not have a value in the enumeration " . print_r($schema->enum, true));
55442 }
55443 }<?php
55444
55445
55446
55447
55448
55449
55450
55451
55452 namespace JsonSchema\Constraints;
55453
55454
55455
55456
55457
55458
55459
55460 class Format extends Constraint
55461 {
55462
55463
55464
55465 public function check($element, $schema = null, $path = null, $i = null)
55466 {
55467 if (!isset($schema->format)) {
55468 return;
55469 }
55470
55471 switch ($schema->format) {
55472 case 'date':
55473 if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
55474 $this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)));
55475 }
55476 break;
55477
55478 case 'time':
55479 if (!$this->validateDateTime($element, 'H:i:s')) {
55480 $this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)));
55481 }
55482 break;
55483
55484 case 'date-time':
55485 if (!$this->validateDateTime($element, 'Y-m-d\TH:i:s\Z') &&
55486 !$this->validateDateTime($element, 'Y-m-d\TH:i:s.u\Z') &&
55487 !$this->validateDateTime($element, 'Y-m-d\TH:i:sP') &&
55488 !$this->validateDateTime($element, 'Y-m-d\TH:i:sO')
55489 ) {
55490 $this->addError($path, sprintf('Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm', json_encode($element)));
55491 }
55492 break;
55493
55494 case 'utc-millisec':
55495 if (!$this->validateDateTime($element, 'U')) {
55496 $this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)));
55497 }
55498 break;
55499
55500 case 'regex':
55501 if (!$this->validateRegex($element)) {
55502 $this->addError($path, 'Invalid regex format ' . $element);
55503 }
55504 break;
55505
55506 case 'color':
55507 if (!$this->validateColor($element)) {
55508 $this->addError($path, "Invalid color");
55509 }
55510 break;
55511
55512 case 'style':
55513 if (!$this->validateStyle($element)) {
55514 $this->addError($path, "Invalid style");
55515 }
55516 break;
55517
55518 case 'phone':
55519 if (!$this->validatePhone($element)) {
55520 $this->addError($path, "Invalid phone number");
55521 }
55522 break;
55523
55524 case 'uri':
55525 if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
55526 $this->addError($path, "Invalid URL format");
55527 }
55528 break;
55529
55530 case 'email':
55531 if (null === filter_var($element, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE)) {
55532 $this->addError($path, "Invalid email");
55533 }
55534 break;
55535
55536 case 'ip-address':
55537 case 'ipv4':
55538 if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
55539 $this->addError($path, "Invalid IP address");
55540 }
55541 break;
55542
55543 case 'ipv6':
55544 if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
55545 $this->addError($path, "Invalid IP address");
55546 }
55547 break;
55548
55549 case 'host-name':
55550 case 'hostname':
55551 if (!$this->validateHostname($element)) {
55552 $this->addError($path, "Invalid hostname");
55553 }
55554 break;
55555
55556 default:
55557 $this->addError($path, "Unknown format: " . json_encode($schema->format));
55558 break;
55559 }
55560 }
55561
55562 protected function validateDateTime($datetime, $format)
55563 {
55564 $dt = \DateTime::createFromFormat($format, $datetime);
55565
55566 if (!$dt) {
55567 return false;
55568 }
55569
55570 return $datetime === $dt->format($format);
55571 }
55572
55573 protected function validateRegex($regex)
55574 {
55575 return false !== @preg_match('/' . $regex . '/', '');
55576 }
55577
55578 protected function validateColor($color)
55579 {
55580 if (in_array(strtolower($color), array('aqua', 'black', 'blue', 'fuchsia',
55581 'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange', 'purple',
55582 'red', 'silver', 'teal', 'white', 'yellow'))) {
55583 return true;
55584 }
55585
55586 return preg_match('/^#([a-f0-9]{3}|[a-f0-9]{6})$/i', $color);
55587 }
55588
55589 protected function validateStyle($style)
55590 {
55591 $properties = explode(';', rtrim($style, ';'));
55592 $invalidEntries = preg_grep('/^\s*[-a-z]+\s*:\s*.+$/i', $properties, PREG_GREP_INVERT);
55593
55594 return empty($invalidEntries);
55595 }
55596
55597 protected function validatePhone($phone)
55598 {
55599 return preg_match('/^\+?(\(\d{3}\)|\d{3}) \d{3} \d{4}$/', $phone);
55600 }
55601
55602 protected function validateHostname($host)
55603 {
55604 return preg_match('/^[_a-z]+\.([_a-z]+\.?)+$/i', $host);
55605 }
55606 }
55607 <?php
55608
55609
55610
55611
55612
55613
55614
55615
55616 namespace JsonSchema\Constraints;
55617
55618
55619
55620
55621
55622
55623
55624 class String extends Constraint
55625 {
55626
55627
55628
55629 public function check($element, $schema = null, $path = null, $i = null)
55630 {
55631
55632  if (isset($schema->maxLength) && $this->strlen($element) > $schema->maxLength) {
55633 $this->addError($path, "must be at most " . $schema->maxLength . " characters long");
55634 }
55635
55636
55637  if (isset($schema->minLength) && $this->strlen($element) < $schema->minLength) {
55638 $this->addError($path, "must be at least " . $schema->minLength . " characters long");
55639 }
55640
55641
55642  if (isset($schema->pattern) && !preg_match('#' . str_replace('#', '\\#', $schema->pattern) . '#', $element)) {
55643 $this->addError($path, "does not match the regex pattern " . $schema->pattern);
55644 }
55645
55646 $this->checkFormat($element, $schema, $path, $i);
55647 }
55648
55649 private function strlen($string)
55650 {
55651 if (extension_loaded('mbstring')) {
55652 return mb_strlen($string, mb_detect_encoding($string));
55653 } else {
55654 return strlen($string);
55655 }
55656 }
55657 }
55658 <?php
55659
55660
55661
55662
55663
55664
55665
55666
55667 namespace JsonSchema\Exception;
55668
55669
55670
55671
55672 class UriResolverException extends \RuntimeException
55673 {
55674 }<?php
55675
55676
55677
55678
55679
55680
55681
55682
55683 namespace JsonSchema\Exception;
55684
55685
55686
55687
55688 class ResourceNotFoundException extends \RuntimeException
55689 {
55690 }<?php
55691
55692
55693
55694
55695
55696
55697
55698
55699 namespace JsonSchema\Exception;
55700
55701
55702
55703
55704 class InvalidSchemaMediaTypeException extends \RuntimeException
55705
55706 }<?php
55707
55708
55709
55710
55711
55712
55713
55714
55715 namespace JsonSchema\Exception;
55716
55717
55718
55719
55720 class InvalidSourceUriException extends InvalidArgumentException
55721 {
55722 }
55723 <?php
55724
55725
55726
55727
55728
55729
55730
55731
55732 namespace JsonSchema\Exception;
55733
55734
55735
55736
55737 class JsonDecodingException extends \RuntimeException
55738 {
55739 public function __construct($code = JSON_ERROR_NONE, \Exception $previous = null)
55740 {
55741 switch ($code) {
55742 case JSON_ERROR_DEPTH:
55743 $message = 'The maximum stack depth has been exceeded';
55744 break;
55745 case JSON_ERROR_STATE_MISMATCH:
55746 $message = 'Invalid or malformed JSON';
55747 break;
55748 case JSON_ERROR_CTRL_CHAR:
55749 $message = 'Control character error, possibly incorrectly encoded';
55750 break;
55751 case JSON_ERROR_UTF8:
55752 $message = 'Malformed UTF-8 characters, possibly incorrectly encoded';
55753 break;
55754 case JSON_ERROR_SYNTAX:
55755 $message = 'JSON syntax is malformed';
55756 break;
55757 default:
55758 $message = 'Syntax error';
55759 }
55760 parent::__construct($message, $code, $previous);
55761 }
55762 }<?php
55763
55764
55765
55766
55767
55768
55769
55770
55771 namespace JsonSchema\Exception;
55772
55773
55774
55775
55776 class InvalidArgumentException extends \InvalidArgumentException
55777 {
55778 }<?php
55779
55780
55781
55782
55783
55784
55785
55786
55787 namespace JsonSchema\Uri;
55788
55789 use JsonSchema\Exception\UriResolverException;
55790
55791
55792
55793
55794
55795
55796 class UriResolver
55797 {
55798
55799
55800
55801
55802
55803
55804 public function parse($uri)
55805 {
55806 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
55807
55808 $components = array();
55809 if (5 < count($match)) {
55810 $components = array(
55811 'scheme' => $match[2],
55812 'authority' => $match[4],
55813 'path' => $match[5]
55814 );
55815
55816 if (7 < count($match)) {
55817 $components['query'] = $match[7];
55818 }
55819 if (9 < count($match)) {
55820 $components['fragment'] = $match[9];
55821 }
55822
55823 return $components;
55824 }
55825
55826
55827
55828
55829
55830
55831
55832 public function generate(array $components)
55833 {
55834 $uri = $components['scheme'] . '://' 
55835 . $components['authority']
55836 . $components['path'];
55837
55838 if (array_key_exists('query', $components)) {
55839 $uri .= $components['query'];
55840 }
55841 if (array_key_exists('fragment', $components)) {
55842 $uri .= '#' . $components['fragment'];
55843 }
55844
55845 return $uri;
55846 }
55847
55848
55849
55850
55851
55852
55853
55854
55855 public function resolve($uri, $baseUri = null)
55856 {
55857 if ($uri == '') {
55858 return $baseUri;
55859 }
55860
55861 $components = $this->parse($uri);
55862 $path = $components['path'];
55863
55864 if (! empty($components['scheme'])) {
55865 return $uri;
55866 }
55867 $baseComponents = $this->parse($baseUri);
55868 $basePath = $baseComponents['path'];
55869
55870 $baseComponents['path'] = self::combineRelativePathWithBasePath($path, $basePath);
55871 if (isset($components['fragment'])) {
55872 $baseComponents['fragment'] = $components['fragment'];
55873 }
55874
55875 return $this->generate($baseComponents);
55876 }
55877
55878
55879
55880
55881
55882
55883
55884
55885
55886 public static function combineRelativePathWithBasePath($relativePath, $basePath)
55887 {
55888 $relativePath = self::normalizePath($relativePath);
55889 if ($relativePath == '') {
55890 return $basePath;
55891 }
55892 if ($relativePath{0} == '/') {
55893 return $relativePath;
55894 }
55895
55896 $basePathSegments = self::getPathSegments($basePath);
55897
55898 preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
55899 $numLevelUp = strlen($match[0]) /3 + 1;
55900 if ($numLevelUp >= count($basePathSegments)) {
55901 throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
55902 }
55903 $basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
55904 $path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);
55905
55906 return implode('/', $basePathSegments) . '/' . $path;
55907 }
55908
55909
55910
55911
55912
55913
55914
55915 private static function normalizePath($path)
55916 {
55917 $path = preg_replace('|((?<!\.)\./)*|', '', $path);
55918 $path = preg_replace('|//|', '/', $path);
55919
55920 return $path;
55921 }
55922
55923
55924
55925
55926 private static function getPathSegments($path) {
55927
55928 return explode('/', $path);
55929 }
55930
55931
55932
55933
55934
55935 public function isValid($uri)
55936 {
55937 $components = $this->parse($uri);
55938
55939 return !empty($components);
55940 }
55941 }
55942 <?php
55943
55944
55945
55946
55947
55948
55949
55950
55951 namespace JsonSchema\Uri;
55952
55953 use JsonSchema\Uri\Retrievers\FileGetContents;
55954 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
55955 use JsonSchema\Validator;
55956 use JsonSchema\Exception\InvalidSchemaMediaTypeException;
55957 use JsonSchema\Exception\JsonDecodingException;
55958
55959
55960
55961
55962
55963
55964 class UriRetriever
55965 {
55966 protected $uriRetriever = null;
55967
55968
55969
55970
55971
55972
55973 public function confirmMediaType($uriRetriever, $uri)
55974 {
55975 $contentType = $uriRetriever->getContentType();
55976
55977 if (is_null($contentType)) {
55978
55979  return;
55980 }
55981
55982 if (Validator::SCHEMA_MEDIA_TYPE === $contentType) {
55983 return;
55984 }
55985
55986 if (substr($uri, 0, 23) == 'http://json-schema.org/') {
55987
55988  return true;
55989 }
55990
55991 throw new InvalidSchemaMediaTypeException(sprintf('Media type %s expected', Validator::SCHEMA_MEDIA_TYPE));
55992 }
55993
55994
55995
55996
55997
55998
55999
56000
56001
56002 public function getUriRetriever()
56003 {
56004 if (is_null($this->uriRetriever)) {
56005 $this->setUriRetriever(new FileGetContents);
56006 }
56007
56008 return $this->uriRetriever;
56009 }
56010
56011
56012
56013
56014
56015
56016
56017
56018
56019
56020
56021
56022
56023
56024 public function resolvePointer($jsonSchema, $uri)
56025 {
56026 $resolver = new UriResolver();
56027 $parsed = $resolver->parse($uri);
56028 if (empty($parsed['fragment'])) {
56029 return $jsonSchema;
56030 }
56031
56032 $path = explode('/', $parsed['fragment']);
56033 while ($path) {
56034 $pathElement = array_shift($path);
56035 if (! empty($pathElement)) {
56036 $pathElement = str_replace('~1', '/', $pathElement);
56037 $pathElement = str_replace('~0', '~', $pathElement);
56038 if (! empty($jsonSchema->$pathElement)) {
56039 $jsonSchema = $jsonSchema->$pathElement;
56040 } else {
56041 throw new \JsonSchema\Exception\ResourceNotFoundException(
56042 'Fragment "' . $parsed['fragment'] . '" not found'
56043 . ' in ' . $uri
56044 );
56045 }
56046
56047 if (! is_object($jsonSchema)) {
56048 throw new \JsonSchema\Exception\ResourceNotFoundException(
56049 'Fragment part "' . $pathElement . '" is no object '
56050 . ' in ' . $uri
56051 );
56052 }
56053 }
56054 }
56055
56056 return $jsonSchema;
56057 }
56058
56059
56060
56061
56062
56063
56064
56065
56066 public function retrieve($uri, $baseUri = null)
56067 {
56068 $resolver = new UriResolver();
56069 $resolvedUri = $fetchUri = $resolver->resolve($uri, $baseUri);
56070
56071
56072  $arParts = $resolver->parse($resolvedUri);
56073 if (isset($arParts['fragment'])) {
56074 unset($arParts['fragment']);
56075 $fetchUri = $resolver->generate($arParts);
56076 }
56077
56078 $jsonSchema = $this->loadSchema($fetchUri);
56079
56080
56081  $jsonSchema = $this->resolvePointer($jsonSchema, $resolvedUri);
56082 $jsonSchema->id = $resolvedUri;
56083
56084 return $jsonSchema;
56085 }
56086
56087
56088
56089
56090
56091
56092
56093
56094
56095 protected function loadSchema($fetchUri)
56096 {
56097 if (isset($this->schemaCache[$fetchUri])) {
56098 return $this->schemaCache[$fetchUri];
56099 }
56100
56101 $uriRetriever = $this->getUriRetriever();
56102 $contents = $this->uriRetriever->retrieve($fetchUri);
56103 $this->confirmMediaType($uriRetriever, $fetchUri);
56104 $jsonSchema = json_decode($contents);
56105
56106 if (JSON_ERROR_NONE < $error = json_last_error()) {
56107 throw new JsonDecodingException($error);
56108 }
56109
56110 $this->schemaCache[$fetchUri] = $jsonSchema;
56111 return $jsonSchema;
56112 }
56113
56114
56115
56116
56117
56118
56119
56120 public function setUriRetriever(UriRetrieverInterface $uriRetriever)
56121 {
56122 $this->uriRetriever = $uriRetriever;
56123
56124 return $this;
56125 }
56126
56127
56128
56129
56130
56131
56132
56133 public function parse($uri)
56134 {
56135 preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
56136
56137 $components = array();
56138 if (5 < count($match)) {
56139 $components = array(
56140 'scheme' => $match[2],
56141 'authority' => $match[4],
56142 'path' => $match[5]
56143 );
56144 }
56145
56146 if (7 < count($match)) {
56147 $components['query'] = $match[7];
56148 }
56149
56150 if (9 < count($match)) {
56151 $components['fragment'] = $match[9];
56152 }
56153
56154 return $components;
56155 }
56156
56157
56158
56159
56160
56161
56162
56163 public function generate(array $components)
56164 {
56165 $uri = $components['scheme'] . '://'
56166 . $components['authority']
56167 . $components['path'];
56168
56169 if (array_key_exists('query', $components)) {
56170 $uri .= $components['query'];
56171 }
56172
56173 if (array_key_exists('fragment', $components)) {
56174 $uri .= $components['fragment'];
56175 }
56176
56177 return $uri;
56178 }
56179
56180
56181
56182
56183
56184
56185
56186
56187 public function resolve($uri, $baseUri = null)
56188 {
56189 $components = $this->parse($uri);
56190 $path = $components['path'];
56191
56192 if ((array_key_exists('scheme', $components)) && ('http' === $components['scheme'])) {
56193 return $uri;
56194 }
56195
56196 $baseComponents = $this->parse($baseUri);
56197 $basePath = $baseComponents['path'];
56198
56199 $baseComponents['path'] = self::combineRelativePathWithBasePath($path, $basePath);
56200
56201 return $this->generate($baseComponents);
56202 }
56203
56204
56205
56206
56207
56208
56209
56210
56211
56212 private static function combineRelativePathWithBasePath($relativePath, $basePath)
56213 {
56214 $relativePath = self::normalizePath($relativePath);
56215 $basePathSegments = self::getPathSegments($basePath);
56216
56217 preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
56218 $numLevelUp = strlen($match[0]) /3 + 1;
56219 if ($numLevelUp >= count($basePathSegments)) {
56220 throw new \JsonSchema\Exception\UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
56221 }
56222
56223 $basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
56224 $path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);
56225
56226 return implode('/', $basePathSegments) . '/' . $path;
56227 }
56228
56229
56230
56231
56232
56233
56234
56235 private static function normalizePath($path)
56236 {
56237 $path = preg_replace('|((?<!\.)\./)*|', '', $path);
56238 $path = preg_replace('|//|', '/', $path);
56239
56240 return $path;
56241 }
56242
56243
56244
56245
56246 private static function getPathSegments($path)
56247 {
56248 return explode('/', $path);
56249 }
56250
56251
56252
56253
56254
56255 public function isValid($uri)
56256 {
56257 $components = $this->parse($uri);
56258
56259 return !empty($components);
56260 }
56261 }
56262 <?php
56263
56264
56265
56266
56267 namespace JsonSchema\Uri\Retrievers;
56268
56269
56270
56271
56272
56273
56274 abstract class AbstractRetriever implements UriRetrieverInterface
56275 {
56276
56277
56278
56279
56280 protected $contentType;
56281
56282
56283
56284
56285
56286 public function getContentType()
56287 {
56288 return $this->contentType;
56289 }
56290 }
56291 <?php
56292
56293
56294
56295
56296
56297
56298
56299
56300 namespace JsonSchema\Uri\Retrievers;
56301
56302 use JsonSchema\Exception\ResourceNotFoundException;
56303 use JsonSchema\Validator;
56304
56305
56306
56307
56308
56309
56310 class FileGetContents extends AbstractRetriever
56311 {
56312 protected $messageBody;
56313
56314
56315
56316
56317
56318 public function retrieve($uri)
56319 {
56320 $context = stream_context_create(array(
56321 'http' => array(
56322 'method' => 'GET',
56323 'header' => "Accept: " . Validator::SCHEMA_MEDIA_TYPE
56324 )));
56325
56326 $response = file_get_contents($uri);
56327 if (false === $response) {
56328 throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
56329 }
56330 if ($response == ''
56331 && substr($uri, 0, 7) == 'file://' && substr($uri, -1) == '/'
56332 ) {
56333 throw new ResourceNotFoundException('JSON schema not found at ' . $uri);
56334 }
56335
56336 $this->messageBody = $response;
56337 if (! empty($http_response_header)) {
56338 $this->fetchContentType($http_response_header);
56339 } else {
56340
56341  $this->contentType = null;
56342 }
56343
56344 return $this->messageBody;
56345 }
56346
56347
56348
56349
56350
56351 private function fetchContentType(array $headers)
56352 {
56353 foreach ($headers as $header) {
56354 if ($this->contentType = self::getContentTypeMatchInHeader($header)) {
56355 return true;
56356 }
56357 }
56358
56359 return false;
56360 }
56361
56362
56363
56364
56365
56366 protected static function getContentTypeMatchInHeader($header)
56367 {
56368 if (0 < preg_match("/Content-Type:(\V*)/ims", $header, $match)) {
56369 return trim($match[1]);
56370 }
56371 }
56372 }
56373 <?php
56374
56375
56376
56377
56378
56379
56380
56381
56382 namespace JsonSchema\Uri\Retrievers;
56383
56384
56385
56386
56387
56388
56389 interface UriRetrieverInterface
56390 {
56391
56392
56393
56394
56395
56396
56397 public function retrieve($uri);
56398
56399
56400
56401
56402
56403 public function getContentType();
56404 }<?php
56405
56406
56407
56408
56409
56410
56411
56412
56413 namespace JsonSchema\Uri\Retrievers;
56414
56415 use JsonSchema\Validator;
56416
56417
56418
56419
56420
56421
56422 class Curl extends AbstractRetriever
56423 {
56424 protected $messageBody;
56425
56426 public function __construct()
56427 {
56428 if (!function_exists('curl_init')) {
56429 throw new \RuntimeException("cURL not installed");
56430 }
56431 }
56432
56433
56434
56435
56436
56437 public function retrieve($uri)
56438 {
56439 $ch = curl_init();
56440
56441 curl_setopt($ch, CURLOPT_URL, $uri);
56442 curl_setopt($ch, CURLOPT_HEADER, true);
56443 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
56444 curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: ' . Validator::SCHEMA_MEDIA_TYPE));
56445
56446 $response = curl_exec($ch);
56447 if (false === $response) {
56448 throw new \JsonSchema\Exception\ResourceNotFoundException('JSON schema not found');
56449 }
56450
56451 $this->fetchMessageBody($response);
56452 $this->fetchContentType($response);
56453
56454 curl_close($ch);
56455
56456 return $this->messageBody;
56457 }
56458
56459
56460
56461
56462 private function fetchMessageBody($response)
56463 {
56464 preg_match("/(?:\r\n){2}(.*)$/ms", $response, $match);
56465 $this->messageBody = $match[1];
56466 }
56467
56468
56469
56470
56471
56472 protected function fetchContentType($response)
56473 {
56474 if (0 < preg_match("/Content-Type:(\V*)/ims", $response, $match)) {
56475 $this->contentType = trim($match[1]);
56476
56477 return true;
56478 }
56479
56480 return false;
56481 }
56482 }<?php
56483
56484 namespace JsonSchema\Uri\Retrievers;
56485
56486 use JsonSchema\Validator;
56487 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
56488
56489
56490
56491
56492
56493
56494
56495
56496
56497
56498
56499
56500
56501 class PredefinedArray extends AbstractRetriever
56502 {
56503
56504
56505
56506
56507 private $schemas;
56508
56509
56510
56511
56512
56513
56514
56515 public function __construct(array $schemas, $contentType = Validator::SCHEMA_MEDIA_TYPE)
56516 {
56517 $this->schemas = $schemas;
56518 $this->contentType = $contentType;
56519 }
56520
56521
56522
56523
56524
56525 public function retrieve($uri)
56526 {
56527 if (!array_key_exists($uri, $this->schemas)) {
56528 throw new \JsonSchema\Exception\ResourceNotFoundException(sprintf(
56529 'The JSON schema "%s" was not found.',
56530 $uri
56531 ));
56532 }
56533
56534 return $this->schemas[$uri];
56535 }
56536 }<?php
56537
56538
56539
56540
56541
56542
56543
56544
56545 namespace JsonSchema;
56546
56547 use JsonSchema\Constraints\Schema;
56548 use JsonSchema\Constraints\Constraint;
56549
56550 use JsonSchema\Exception\InvalidSchemaMediaTypeException;
56551 use JsonSchema\Exception\JsonDecodingException;
56552
56553 use JsonSchema\Uri\Retrievers\UriRetrieverInterface;
56554
56555
56556
56557
56558
56559
56560
56561
56562 class Validator extends Constraint
56563 {
56564 const SCHEMA_MEDIA_TYPE = 'application/schema+json';
56565
56566
56567
56568
56569
56570
56571
56572
56573 public function check($value, $schema = null, $path = null, $i = null)
56574 {
56575 $validator = new Schema($this->checkMode, $this->uriRetriever);
56576 $validator->check($value, $schema);
56577
56578 $this->addErrors(array_unique($validator->getErrors(), SORT_REGULAR));
56579 }
56580 }
56581 <?php
56582
56583
56584
56585 require_once __DIR__ . '/composer' . '/autoload_real.php';
56586
56587 return ComposerAutoloaderInit4fedf8bd1e8f37fa27ee584fd8eec2a5::getLoader();
56588 <?php
56589
56590
56591
56592 $vendorDir = dirname(dirname(__FILE__));
56593 $baseDir = dirname($vendorDir);
56594
56595 return array(
56596 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'),
56597 'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
56598 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'),
56599 'JsonSchema' => array($vendorDir . '/justinrainbow/json-schema/src'),
56600 'Composer' => array($baseDir . '/src'),
56601 );
56602 <?php
56603
56604
56605
56606 $vendorDir = dirname(dirname(__FILE__));
56607 $baseDir = dirname($vendorDir);
56608
56609 return array(
56610 'Seld\\JsonLint\\' => array($vendorDir . '/seld/jsonlint/src/Seld/JsonLint'),
56611 );
56612 <?php
56613
56614
56615
56616 $vendorDir = dirname(dirname(__FILE__));
56617 $baseDir = dirname($vendorDir);
56618
56619 return array(
56620 );
56621 <?php
56622
56623
56624
56625 class ComposerAutoloaderInit4fedf8bd1e8f37fa27ee584fd8eec2a5
56626 {
56627 private static $loader;
56628
56629 public static function loadClassLoader($class)
56630 {
56631 if ('Composer\Autoload\ClassLoader' === $class) {
56632 require __DIR__ . '/ClassLoader.php';
56633 }
56634 }
56635
56636 public static function getLoader()
56637 {
56638 if (null !== self::$loader) {
56639 return self::$loader;
56640 }
56641
56642 spl_autoload_register(array('ComposerAutoloaderInit4fedf8bd1e8f37fa27ee584fd8eec2a5', 'loadClassLoader'), true, true);
56643 self::$loader = $loader = new \Composer\Autoload\ClassLoader();
56644 spl_autoload_unregister(array('ComposerAutoloaderInit4fedf8bd1e8f37fa27ee584fd8eec2a5', 'loadClassLoader'));
56645
56646 $vendorDir = dirname(__DIR__);
56647 $baseDir = dirname($vendorDir);
56648
56649 $map = require __DIR__ . '/autoload_namespaces.php';
56650 foreach ($map as $namespace => $path) {
56651 $loader->set($namespace, $path);
56652 }
56653
56654 $map = require __DIR__ . '/autoload_psr4.php';
56655 foreach ($map as $namespace => $path) {
56656 $loader->setPsr4($namespace, $path);
56657 }
56658
56659 $classMap = require __DIR__ . '/autoload_classmap.php';
56660 if ($classMap) {
56661 $loader->addClassMap($classMap);
56662 }
56663
56664 $loader->register(true);
56665
56666 return $loader;
56667 }
56668 }
56669 <?php
56670
56671
56672
56673 $vendorDir = dirname(dirname(__FILE__));
56674 $baseDir = dirname($vendorDir);
56675
56676 return array(
56677 $vendorDir . '/phpunit/phpunit-mock-objects',
56678 $vendorDir . '/phpunit/php-timer',
56679 $vendorDir . '/phpunit/php-token-stream',
56680 $vendorDir . '/phpunit/php-file-iterator',
56681 $vendorDir . '/phpunit/php-text-template',
56682 $vendorDir . '/phpunit/php-code-coverage',
56683 $vendorDir . '/phpunit/phpunit',
56684 $vendorDir . '/symfony/yaml',
56685 );
56686 <?php
56687
56688
56689
56690
56691
56692
56693
56694
56695
56696
56697
56698 namespace Composer\Autoload;
56699
56700
56701
56702
56703
56704
56705
56706
56707
56708
56709
56710
56711
56712
56713
56714
56715
56716
56717
56718
56719
56720
56721
56722
56723
56724
56725
56726
56727
56728 class ClassLoader
56729 {
56730
56731  private $prefixLengthsPsr4 = array();
56732 private $prefixDirsPsr4 = array();
56733 private $fallbackDirsPsr4 = array();
56734
56735
56736  private $prefixesPsr0 = array();
56737 private $fallbackDirsPsr0 = array();
56738
56739 private $useIncludePath = false;
56740 private $classMap = array();
56741
56742 public function getPrefixes()
56743 {
56744 return call_user_func_array('array_merge', $this->prefixesPsr0);
56745 }
56746
56747 public function getPrefixesPsr4()
56748 {
56749 return $this->prefixDirsPsr4;
56750 }
56751
56752 public function getFallbackDirs()
56753 {
56754 return $this->fallbackDirsPsr0;
56755 }
56756
56757 public function getFallbackDirsPsr4()
56758 {
56759 return $this->fallbackDirsPsr4;
56760 }
56761
56762 public function getClassMap()
56763 {
56764 return $this->classMap;
56765 }
56766
56767
56768
56769
56770 public function addClassMap(array $classMap)
56771 {
56772 if ($this->classMap) {
56773 $this->classMap = array_merge($this->classMap, $classMap);
56774 } else {
56775 $this->classMap = $classMap;
56776 }
56777 }
56778
56779
56780
56781
56782
56783
56784
56785
56786
56787 public function add($prefix, $paths, $prepend = false)
56788 {
56789 if (!$prefix) {
56790 if ($prepend) {
56791 $this->fallbackDirsPsr0 = array_merge(
56792 (array) $paths,
56793 $this->fallbackDirsPsr0
56794 );
56795 } else {
56796 $this->fallbackDirsPsr0 = array_merge(
56797 $this->fallbackDirsPsr0,
56798 (array) $paths
56799 );
56800 }
56801
56802 return;
56803 }
56804
56805 $first = $prefix[0];
56806 if (!isset($this->prefixesPsr0[$first][$prefix])) {
56807 $this->prefixesPsr0[$first][$prefix] = (array) $paths;
56808
56809 return;
56810 }
56811 if ($prepend) {
56812 $this->prefixesPsr0[$first][$prefix] = array_merge(
56813 (array) $paths,
56814 $this->prefixesPsr0[$first][$prefix]
56815 );
56816 } else {
56817 $this->prefixesPsr0[$first][$prefix] = array_merge(
56818 $this->prefixesPsr0[$first][$prefix],
56819 (array) $paths
56820 );
56821 }
56822 }
56823
56824
56825
56826
56827
56828
56829
56830
56831
56832 public function addPsr4($prefix, $paths, $prepend = false)
56833 {
56834 if (!$prefix) {
56835
56836  if ($prepend) {
56837 $this->fallbackDirsPsr4 = array_merge(
56838 (array) $paths,
56839 $this->fallbackDirsPsr4
56840 );
56841 } else {
56842 $this->fallbackDirsPsr4 = array_merge(
56843 $this->fallbackDirsPsr4,
56844 (array) $paths
56845 );
56846 }
56847 } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
56848
56849  $length = strlen($prefix);
56850 if ('\\' !== $prefix[$length - 1]) {
56851 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
56852 }
56853 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
56854 $this->prefixDirsPsr4[$prefix] = (array) $paths;
56855 } elseif ($prepend) {
56856
56857  $this->prefixDirsPsr4[$prefix] = array_merge(
56858 (array) $paths,
56859 $this->prefixDirsPsr4[$prefix]
56860 );
56861 } else {
56862
56863  $this->prefixDirsPsr4[$prefix] = array_merge(
56864 $this->prefixDirsPsr4[$prefix],
56865 (array) $paths
56866 );
56867 }
56868 }
56869
56870
56871
56872
56873
56874
56875
56876
56877 public function set($prefix, $paths)
56878 {
56879 if (!$prefix) {
56880 $this->fallbackDirsPsr0 = (array) $paths;
56881 } else {
56882 $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
56883 }
56884 }
56885
56886
56887
56888
56889
56890
56891
56892
56893 public function setPsr4($prefix, $paths) {
56894 if (!$prefix) {
56895 $this->fallbackDirsPsr4 = (array) $paths;
56896 } else {
56897 $length = strlen($prefix);
56898 if ('\\' !== $prefix[$length - 1]) {
56899 throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
56900 }
56901 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
56902 $this->prefixDirsPsr4[$prefix] = (array) $paths;
56903 }
56904 }
56905
56906
56907
56908
56909
56910
56911 public function setUseIncludePath($useIncludePath)
56912 {
56913 $this->useIncludePath = $useIncludePath;
56914 }
56915
56916
56917
56918
56919
56920
56921
56922 public function getUseIncludePath()
56923 {
56924 return $this->useIncludePath;
56925 }
56926
56927
56928
56929
56930
56931
56932 public function register($prepend = false)
56933 {
56934 spl_autoload_register(array($this, 'loadClass'), true, $prepend);
56935 }
56936
56937
56938
56939
56940 public function unregister()
56941 {
56942 spl_autoload_unregister(array($this, 'loadClass'));
56943 }
56944
56945
56946
56947
56948
56949
56950
56951 public function loadClass($class)
56952 {
56953 if ($file = $this->findFile($class)) {
56954 include $file;
56955
56956 return true;
56957 }
56958 }
56959
56960
56961
56962
56963
56964
56965
56966
56967 public function findFile($class)
56968 {
56969
56970  if ('\\' == $class[0]) {
56971 $class = substr($class, 1);
56972 }
56973
56974
56975  if (isset($this->classMap[$class])) {
56976 return $this->classMap[$class];
56977 }
56978
56979
56980  $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php';
56981
56982 $first = $class[0];
56983 if (isset($this->prefixLengthsPsr4[$first])) {
56984 foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
56985 if (0 === strpos($class, $prefix)) {
56986 foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
56987 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
56988 return $file;
56989 }
56990 }
56991 }
56992 }
56993 }
56994
56995
56996  foreach ($this->fallbackDirsPsr4 as $dir) {
56997 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
56998 return $file;
56999 }
57000 }
57001
57002
57003  if (false !== $pos = strrpos($class, '\\')) {
57004
57005  $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
57006 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
57007 } else {
57008
57009  $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php';
57010 }
57011
57012 if (isset($this->prefixesPsr0[$first])) {
57013 foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
57014 if (0 === strpos($class, $prefix)) {
57015 foreach ($dirs as $dir) {
57016 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
57017 return $file;
57018 }
57019 }
57020 }
57021 }
57022 }
57023
57024
57025  foreach ($this->fallbackDirsPsr0 as $dir) {
57026 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
57027 return $file;
57028 }
57029 }
57030
57031
57032  if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
57033 return $file;
57034 }
57035
57036
57037  return $this->classMap[$class] = false;
57038 }
57039 }
57040 <?php
57041
57042 if (PHP_SAPI !== 'cli') {
57043     echo 'Warning: Composer should be invoked via the CLI version of PHP, not the '.PHP_SAPI.' SAPI'.PHP_EOL;
57044 }
57045
57046 require __DIR__.'/../src/bootstrap.php';
57047
57048 use Composer\Console\Application;
57049
57050 error_reporting(-1);
57051
57052 if (function_exists('ini_set')) {
57053     @ini_set('display_errors', 1);
57054
57055     $memoryInBytes = function ($value) {
57056         $unit = strtolower(substr($value, -1, 1));
57057         $value = (int) $value;
57058         switch($unit) {
57059             case 'g':
57060                 $value *= 1024;
57061                 // no break (cumulative multiplier)
57062             case 'm':
57063                 $value *= 1024;
57064                 // no break (cumulative multiplier)
57065             case 'k':
57066                 $value *= 1024;
57067         }
57068
57069         return $value;
57070     };
57071
57072     $memoryLimit = trim(ini_get('memory_limit'));
57073     // Increase memory_limit if it is lower than 512M
57074     if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 512 * 1024 * 1024) {
57075         @ini_set('memory_limit', '512M');
57076     }
57077     unset($memoryInBytes, $memoryLimit);
57078 }
57079
57080 // run the command application
57081 $application = new Application();
57082 $application->run();
57083
57084 Copyright (c) 2011 Nils Adermann, Jordi Boggiano
57085
57086 Permission is hereby granted, free of charge, to any person obtaining a copy
57087 of this software and associated documentation files (the "Software"), to deal
57088 in the Software without restriction, including without limitation the rights
57089 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
57090 copies of the Software, and to permit persons to whom the Software is furnished
57091 to do so, subject to the following conditions:
57092
57093 The above copyright notice and this permission notice shall be included in all
57094 copies or substantial portions of the Software.
57095
57096 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
57097 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57098 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57099 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57100 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57101 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
57102 THE SOFTWARE.
57103
57104 \b.ãØi¥¦§ùP\95ó[UR\88ËÄi»\ 2\0\0\0GBMB