├── .gitignore ├── .editorconfig ├── doc ├── faqs │ ├── which-version-numbering-system-does-composer-itself-use.md │ ├── why-are-version-constraints-combining-comparisons-and-wildcards-a-bad-idea.md │ ├── why-are-unbound-version-constraints-a-bad-idea.md │ ├── how-to-install-untrusted-packages-safely.md │ ├── how-to-install-composer-programmatically.md │ ├── should-i-commit-the-dependencies-in-my-vendor-directory.md │ ├── why-can't-composer-load-repositories-recursively.md │ └── how-do-i-install-a-package-to-a-custom-path-for-my-framework.md ├── fixtures │ ├── repo-composer-with-providers │ │ ├── packages.json │ │ └── p │ │ │ ├── provider-active$1893a061e579543822389ecd12d791c612db0c05e22d90e9286e233cacd86ed8.json │ │ │ ├── qux │ │ │ └── quux$c142d1a07ca354be46b613f59f1d601923a5a00ccc5fcce50a77ecdd461eb72d.json │ │ │ ├── gar │ │ │ └── nix$5d210670cb46c8364c8e3fb449967b9bea558b971e5b082f330ae4f1d484c321.json │ │ │ ├── bar │ │ │ └── baz$923363b3c22e73abb2e3fd891c8156dd4d0821a97fd3e428bc910833e3e46dbe.json │ │ │ └── foo │ │ │ └── bar$4baabb3303afa3e34a4d3af18fb138e5f3b79029c1f8d9ab5b477ea15776ba0a.json │ └── fixtures.md ├── 08-community.md ├── dev │ └── DefaultPolicy.md └── articles │ └── resolving-merge-conflicts.md ├── src ├── Composer │ ├── Filter │ │ └── PlatformRequirementFilter │ │ │ ├── PlatformRequirementFilterInterface.php │ │ │ ├── IgnoreNothingPlatformRequirementFilter.php │ │ │ ├── IgnoreAllPlatformRequirementFilter.php │ │ │ ├── PlatformRequirementFilterFactory.php │ │ │ └── IgnoreListPlatformRequirementFilter.php │ ├── Downloader │ │ ├── MaxFileSizeExceededException.php │ │ ├── ChangeReportInterface.php │ │ ├── DvcsDownloaderInterface.php │ │ ├── FilesystemException.php │ │ ├── VcsCapableDownloaderInterface.php │ │ ├── TarDownloader.php │ │ ├── XzDownloader.php │ │ ├── PharDownloader.php │ │ ├── TransportException.php │ │ ├── GzipDownloader.php │ │ └── RarDownloader.php │ ├── EventDispatcher │ │ ├── ScriptExecutionException.php │ │ ├── EventSubscriberInterface.php │ │ └── Event.php │ ├── Exception │ │ ├── IrrecoverableDownloadException.php │ │ └── NoSslException.php │ ├── Plugin │ │ ├── Capability │ │ │ ├── Capability.php │ │ │ └── CommandProvider.php │ │ ├── Capable.php │ │ ├── PreCommandRunEvent.php │ │ ├── PluginInterface.php │ │ ├── CommandEvent.php │ │ └── PluginEvents.php │ ├── Repository │ │ ├── InvalidRepositoryException.php │ │ ├── RepositorySecurityException.php │ │ ├── ConfigurableRepositoryInterface.php │ │ ├── LockArrayRepository.php │ │ ├── VersionCacheInterface.php │ │ ├── InstalledFilesystemRepository.php │ │ ├── RootPackageRepository.php │ │ ├── PearRepository.php │ │ ├── InstalledRepositoryInterface.php │ │ ├── InstalledArrayRepository.php │ │ ├── PackageRepository.php │ │ ├── WritableRepositoryInterface.php │ │ └── WritableArrayRepository.php │ ├── Util │ │ ├── MetadataMinifier.php │ │ ├── Http │ │ │ ├── CurlResponse.php │ │ │ └── RequestProxy.php │ │ ├── IniHelper.php │ │ ├── Tar.php │ │ ├── Silencer.php │ │ ├── SyncHelper.php │ │ ├── ComposerMirror.php │ │ ├── ErrorHandler.php │ │ └── PackageSorter.php │ ├── Installer │ │ ├── InstallerEvents.php │ │ ├── BinaryPresenceInterface.php │ │ ├── PackageEvents.php │ │ ├── InstallerEvent.php │ │ ├── PackageEvent.php │ │ └── NoopInstaller.php │ ├── DependencyResolver │ │ ├── LocalRepoTransaction.php │ │ ├── SolverBugException.php │ │ ├── Operation │ │ │ ├── SolverOperation.php │ │ │ ├── OperationInterface.php │ │ │ ├── MarkAliasInstalledOperation.php │ │ │ ├── MarkAliasUninstalledOperation.php │ │ │ ├── UninstallOperation.php │ │ │ ├── InstallOperation.php │ │ │ └── UpdateOperation.php │ │ ├── PolicyInterface.php │ │ ├── RuleWatchChain.php │ │ ├── GenericRule.php │ │ ├── MultiConflictRule.php │ │ └── Rule2Literals.php │ ├── Package │ │ ├── Archiver │ │ │ ├── ComposerExcludeFilter.php │ │ │ ├── ArchivableFilesFilter.php │ │ │ ├── ArchiverInterface.php │ │ │ ├── GitExcludeFilter.php │ │ │ ├── ZipArchiver.php │ │ │ └── ArchivableFilesFinder.php │ │ ├── Loader │ │ │ ├── LoaderInterface.php │ │ │ ├── InvalidPackageException.php │ │ │ └── JsonLoader.php │ │ ├── Version │ │ │ └── StabilityFilter.php │ │ └── RootPackage.php │ ├── Json │ │ └── JsonValidationException.php │ ├── SelfUpdate │ │ └── Keys.php │ ├── Command │ │ ├── AboutCommand.php │ │ ├── DependsCommand.php │ │ ├── ProhibitsCommand.php │ │ ├── ScriptAliasCommand.php │ │ └── ClearCacheCommand.php │ ├── Platform │ │ ├── HhvmDetector.php │ │ ├── Runtime.php │ │ └── Version.php │ ├── Console │ │ └── GithubActionError.php │ ├── Config │ │ └── ConfigSourceInterface.php │ ├── IO │ │ ├── NullIO.php │ │ └── BufferIO.php │ └── Question │ │ └── StrictConfirmationQuestion.php └── bootstrap.php ├── .gitattributes ├── bin ├── compile └── composer ├── LICENSE ├── PORTING_INFO └── .php-cs-fixer.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings 2 | /.project 3 | /.buildpath 4 | /composer.phar 5 | /vendor 6 | /nbproject 7 | .phpunit.result.cache 8 | phpunit.xml 9 | .vagrant 10 | Vagrantfile 11 | .idea 12 | .php-cs-fixer.cache 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_size = 4 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.yml] 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /doc/faqs/which-version-numbering-system-does-composer-itself-use.md: -------------------------------------------------------------------------------- 1 | # Which version numbering system does Composer itself use? 2 | 3 | Composer uses [Semantic Versioning (aka SemVer) 4 | 2.0.0](https://semver.org/spec/v2.0.0.html). 5 | -------------------------------------------------------------------------------- /src/Composer/Filter/PlatformRequirementFilter/PlatformRequirementFilterInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | class MaxFileSizeExceededException extends TransportException 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/Composer/Filter/PlatformRequirementFilter/IgnoreAllPlatformRequirementFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\EventDispatcher; 14 | 15 | /** 16 | * @author Jordi Boggiano 17 | */ 18 | class ScriptExecutionException extends \RuntimeException 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /src/Composer/Exception/IrrecoverableDownloadException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Exception; 14 | 15 | /** 16 | * @author Jordi Boggiano 17 | */ 18 | class IrrecoverableDownloadException extends \RuntimeException 19 | { 20 | } 21 | -------------------------------------------------------------------------------- /src/Composer/Exception/NoSslException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Exception; 14 | 15 | /** 16 | * Specific exception for Composer\Util\HttpDownloader creation. 17 | * 18 | * @author Jordi Boggiano 19 | */ 20 | class NoSslException extends \RuntimeException 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Composer/Plugin/Capability/Capability.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin\Capability; 14 | 15 | /** 16 | * Marker interface for Plugin capabilities. 17 | * Every new Capability which is added to the Plugin API must implement this interface. 18 | * 19 | * @api 20 | */ 21 | interface Capability 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /src/Composer/Repository/InvalidRepositoryException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Exception thrown when a package repository is utterly broken 17 | * 18 | * @author Jordi Boggiano 19 | */ 20 | class InvalidRepositoryException extends \Exception 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Composer/Repository/RepositorySecurityException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Thrown when a security problem, like a broken or missing signature 17 | * 18 | * @author Eric Daspet 19 | */ 20 | class RepositorySecurityException extends \Exception 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Composer/Repository/ConfigurableRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Configurable repository interface. 17 | * 18 | * @author Lukas Homza 19 | */ 20 | interface ConfigurableRepositoryInterface 21 | { 22 | /** 23 | * @return mixed[] 24 | */ 25 | public function getRepoConfig(); 26 | } 27 | -------------------------------------------------------------------------------- /doc/fixtures/repo-composer-with-providers/p/provider-active$1893a061e579543822389ecd12d791c612db0c05e22d90e9286e233cacd86ed8.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": { 3 | "bar\/baz": { 4 | "sha256": "923363b3c22e73abb2e3fd891c8156dd4d0821a97fd3e428bc910833e3e46dbe" 5 | }, 6 | "foo\/bar": { 7 | "sha256": "4baabb3303afa3e34a4d3af18fb138e5f3b79029c1f8d9ab5b477ea15776ba0a" 8 | }, 9 | "gar\/nix": { 10 | "sha256": "5d210670cb46c8364c8e3fb449967b9bea558b971e5b082f330ae4f1d484c321" 11 | }, 12 | "qux\/quux": { 13 | "sha256": "c142d1a07ca354be46b613f59f1d601923a5a00ccc5fcce50a77ecdd461eb72d" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Composer/Util/MetadataMinifier.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | @trigger_error('Composer\Util\MetadataMinifier is deprecated, use Composer\MetadataMinifier\MetadataMinifier from composer/metadata-minifier instead.', E_USER_DEPRECATED); 16 | 17 | /** 18 | * @deprecated Use Composer\MetadataMinifier\MetadataMinifier instead 19 | */ 20 | class MetadataMinifier extends \Composer\MetadataMinifier\MetadataMinifier 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /src/Composer/Installer/InstallerEvents.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Installer; 14 | 15 | class InstallerEvents 16 | { 17 | /** 18 | * The PRE_OPERATIONS_EXEC event occurs before the lock file gets 19 | * installed and operations are executed. 20 | * 21 | * The event listener method receives an Composer\Installer\InstallerEvent instance. 22 | * 23 | * @var string 24 | */ 25 | const PRE_OPERATIONS_EXEC = 'pre-operations-exec'; 26 | } 27 | -------------------------------------------------------------------------------- /src/Composer/Repository/LockArrayRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Lock array repository. 17 | * 18 | * Regular array repository, only uses a different type to identify the lock file as the source of info 19 | * 20 | * @author Nils Adermann 21 | */ 22 | class LockArrayRepository extends ArrayRepository 23 | { 24 | public function getRepoName() 25 | { 26 | return 'lock repo'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Composer/Repository/VersionCacheInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | interface VersionCacheInterface 16 | { 17 | /** 18 | * @param string $version 19 | * @param string $identifier 20 | * @return mixed[]|null|false Package version data if found, false to indicate the identifier is known but has no package, null for an unknown identifier 21 | */ 22 | public function getVersionPackage($version, $identifier); 23 | } 24 | -------------------------------------------------------------------------------- /doc/fixtures/repo-composer-with-providers/p/qux/quux$c142d1a07ca354be46b613f59f1d601923a5a00ccc5fcce50a77ecdd461eb72d.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | "qux\/quux": { 4 | "dev-default": { 5 | "name": "qux\/quux", 6 | "version": "dev-default", 7 | "version_normalized": "9999999-dev", 8 | "source": { 9 | "type": "hg", 10 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 11 | "reference": "4a10a567baa5" 12 | }, 13 | "replace": { 14 | "gar\/nix": "1.0.*" 15 | }, 16 | "time": "2014-10-11 15:48:15", 17 | "type": "library", 18 | "uid": 10 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto-detect text files, ensure they use LF. 2 | * text=auto eol=lf 3 | 4 | # These files are always considered text and should use LF. 5 | # See core.whitespace @ https://git-scm.com/docs/git-config for whitespace flags. 6 | *.php text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 diff=php 7 | *.json text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 8 | *.test text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=4 9 | *.yml text eol=lf whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,tabwidth=2 10 | 11 | # Exclude non-essential files from dist 12 | /tests export-ignore 13 | .github export-ignore 14 | .php_cs export-ignore 15 | .travis.yml export-ignore 16 | appveyor.yml export-ignore 17 | phpunit.xml.dist export-ignore 18 | /phpstan/ export-ignore 19 | -------------------------------------------------------------------------------- /src/Composer/Repository/InstalledFilesystemRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Installed filesystem repository. 17 | * 18 | * @author Jordi Boggiano 19 | */ 20 | class InstalledFilesystemRepository extends FilesystemRepository implements InstalledRepositoryInterface 21 | { 22 | public function getRepoName() 23 | { 24 | return 'installed '.parent::getRepoName(); 25 | } 26 | 27 | /** 28 | * @inheritDoc 29 | */ 30 | public function isFresh() 31 | { 32 | return !$this->file->exists(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | /** 14 | * @param string $file 15 | * @return ?\Composer\Autoload\ClassLoader 16 | */ 17 | function includeIfExists($file) 18 | { 19 | return file_exists($file) ? include $file : null; 20 | } 21 | 22 | if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../autoload.php'))) { 23 | echo 'You must set up the project dependencies using `composer install`'.PHP_EOL. 24 | 'See https://getcomposer.org/download/ for instructions on installing Composer'.PHP_EOL; 25 | exit(1); 26 | } 27 | 28 | return $loader; 29 | -------------------------------------------------------------------------------- /src/Composer/Installer/BinaryPresenceInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Installer; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * Interface for the package installation manager that handle binary installation. 19 | * 20 | * @author Jordi Boggiano 21 | */ 22 | interface BinaryPresenceInterface 23 | { 24 | /** 25 | * Make sure binaries are installed for a given package. 26 | * 27 | * @param PackageInterface $package package instance 28 | * 29 | * @return void 30 | */ 31 | public function ensureBinariesPresence(PackageInterface $package); 32 | } 33 | -------------------------------------------------------------------------------- /src/Composer/Downloader/ChangeReportInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * ChangeReport interface. 19 | * 20 | * @author Sascha Egerer 21 | */ 22 | interface ChangeReportInterface 23 | { 24 | /** 25 | * Checks for changes to the local copy 26 | * 27 | * @param PackageInterface $package package instance 28 | * @param string $path package directory 29 | * @return string|null changes or null 30 | */ 31 | public function getLocalChanges(PackageInterface $package, $path); 32 | } 33 | -------------------------------------------------------------------------------- /src/Composer/Downloader/DvcsDownloaderInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * DVCS Downloader interface. 19 | * 20 | * @author James Titcumb 21 | */ 22 | interface DvcsDownloaderInterface 23 | { 24 | /** 25 | * Checks for unpushed changes to a current branch 26 | * 27 | * @param PackageInterface $package package directory 28 | * @param string $path package directory 29 | * @return string|null changes or null 30 | */ 31 | public function getUnpushedChanges(PackageInterface $package, $path); 32 | } 33 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/LocalRepoTransaction.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | use Composer\Repository\InstalledRepositoryInterface; 16 | use Composer\Repository\RepositoryInterface; 17 | 18 | /** 19 | * @author Nils Adermann 20 | * @internal 21 | */ 22 | class LocalRepoTransaction extends Transaction 23 | { 24 | public function __construct(RepositoryInterface $lockedRepository, InstalledRepositoryInterface $localRepository) 25 | { 26 | parent::__construct( 27 | $localRepository->getPackages(), 28 | $lockedRepository->getPackages() 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Composer/Repository/RootPackageRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | use Composer\Package\RootPackageInterface; 16 | 17 | /** 18 | * Root package repository. 19 | * 20 | * This is used for serving the RootPackage inside an in-memory InstalledRepository 21 | * 22 | * @author Jordi Boggiano 23 | */ 24 | class RootPackageRepository extends ArrayRepository 25 | { 26 | public function __construct(RootPackageInterface $package) 27 | { 28 | parent::__construct(array($package)); 29 | } 30 | 31 | public function getRepoName() 32 | { 33 | return 'root package repo'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Composer/Downloader/FilesystemException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | /** 16 | * Exception thrown when issues exist on local filesystem 17 | * 18 | * @author Javier Spagnoletti 19 | */ 20 | class FilesystemException extends \Exception 21 | { 22 | /** 23 | * @param string $message 24 | * @param int $code 25 | * @param \Exception|null $previous 26 | */ 27 | public function __construct($message = '', $code = 0, \Exception $previous = null) 28 | { 29 | parent::__construct("Filesystem exception: \n".$message, $code, $previous); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Composer/Downloader/VcsCapableDownloaderInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * VCS Capable Downloader interface. 19 | * 20 | * @author Steve Buzonas 21 | */ 22 | interface VcsCapableDownloaderInterface 23 | { 24 | /** 25 | * Gets the VCS Reference for the package at path 26 | * 27 | * @param PackageInterface $package package directory 28 | * @param string $path package directory 29 | * @return string|null reference or null 30 | */ 31 | public function getVcsReference(PackageInterface $package, $path); 32 | } 33 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/SolverBugException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | /** 16 | * @author Nils Adermann 17 | */ 18 | class SolverBugException extends \RuntimeException 19 | { 20 | /** 21 | * @param string $message 22 | */ 23 | public function __construct($message) 24 | { 25 | parent::__construct( 26 | $message."\nThis exception was most likely caused by a bug in Composer.\n". 27 | "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" 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Composer/Downloader/TarDownloader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * Downloader for tar files: tar, tar.gz or tar.bz2 19 | * 20 | * @author Kirill chEbba Chebunin 21 | */ 22 | class TarDownloader extends ArchiveDownloader 23 | { 24 | /** 25 | * @inheritDoc 26 | */ 27 | protected function extract(PackageInterface $package, $file, $path) 28 | { 29 | // Can throw an UnexpectedValueException 30 | $archive = new \PharData($file); 31 | $archive->extractTo($path, null, true); 32 | 33 | return \React\Promise\resolve(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Composer/Repository/PearRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Builds list of package from PEAR channel. 17 | * 18 | * Packages read from channel are named as 'pear-{channelName}/{packageName}' 19 | * and has aliased as 'pear-{channelAlias}/{packageName}' 20 | * 21 | * @author Benjamin Eberlei 22 | * @author Jordi Boggiano 23 | * @deprecated 24 | * @private 25 | */ 26 | class PearRepository extends ArrayRepository 27 | { 28 | public function __construct() 29 | { 30 | throw new \InvalidArgumentException('The PEAR repository has been removed from Composer 2.x'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/SolverOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | /** 16 | * Abstract operation class. 17 | * 18 | * @author Aleksandr Bezpiatov 19 | */ 20 | abstract class SolverOperation implements OperationInterface 21 | { 22 | const TYPE = null; 23 | 24 | /** 25 | * Returns operation type. 26 | * 27 | * @return string 28 | */ 29 | public function getOperationType() 30 | { 31 | return static::TYPE; 32 | } 33 | 34 | /** 35 | * @inheritDoc 36 | */ 37 | public function __toString() 38 | { 39 | return $this->show(false); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Composer/Package/Archiver/ComposerExcludeFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Archiver; 14 | 15 | /** 16 | * An exclude filter which processes composer's own exclude rules 17 | * 18 | * @author Nils Adermann 19 | */ 20 | class ComposerExcludeFilter extends BaseExcludeFilter 21 | { 22 | /** 23 | * @param string $sourcePath Directory containing sources to be filtered 24 | * @param string[] $excludeRules An array of exclude rules from composer.json 25 | */ 26 | public function __construct($sourcePath, array $excludeRules) 27 | { 28 | parent::__construct($sourcePath); 29 | $this->excludePatterns = $this->generatePatterns($excludeRules); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Composer/Plugin/Capability/CommandProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin\Capability; 14 | 15 | /** 16 | * Commands Provider Interface 17 | * 18 | * This capability will receive an array with 'composer' and 'io' keys as 19 | * constructor argument. Those contain Composer\Composer and Composer\IO\IOInterface 20 | * instances. It also contains a 'plugin' key containing the plugin instance that 21 | * created the capability. 22 | * 23 | * @author Jérémy Derussé 24 | */ 25 | interface CommandProvider extends Capability 26 | { 27 | /** 28 | * Retrieves an array of commands 29 | * 30 | * @return \Composer\Command\BaseCommand[] 31 | */ 32 | public function getCommands(); 33 | } 34 | -------------------------------------------------------------------------------- /src/Composer/Repository/InstalledRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Installable repository interface. 17 | * 18 | * Just used to tag installed repositories so the base classes can act differently on Alias packages 19 | * 20 | * @author Jordi Boggiano 21 | */ 22 | interface InstalledRepositoryInterface extends WritableRepositoryInterface 23 | { 24 | /** 25 | * @return bool|null true if dev requirements were installed, false if --no-dev was used, null if yet unknown 26 | */ 27 | public function getDevMode(); 28 | 29 | /** 30 | * @return bool true if packages were never installed in this repository 31 | */ 32 | public function isFresh(); 33 | } 34 | -------------------------------------------------------------------------------- /bin/compile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | compile(); 28 | } catch (\Exception $e) { 29 | echo 'Failed to compile phar: ['.get_class($e).'] '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().PHP_EOL; 30 | exit(1); 31 | } 32 | -------------------------------------------------------------------------------- /src/Composer/Json/JsonValidationException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Json; 14 | 15 | use Exception; 16 | 17 | /** 18 | * @author Jordi Boggiano 19 | */ 20 | class JsonValidationException extends Exception 21 | { 22 | /** 23 | * @var string[] 24 | */ 25 | protected $errors; 26 | 27 | /** 28 | * @param string $message 29 | * @param string[] $errors 30 | */ 31 | public function __construct($message, $errors = array(), Exception $previous = null) 32 | { 33 | $this->errors = $errors; 34 | parent::__construct((string) $message, 0, $previous); 35 | } 36 | 37 | /** 38 | * @return string[] 39 | */ 40 | public function getErrors() 41 | { 42 | return $this->errors; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /doc/fixtures/fixtures.md: -------------------------------------------------------------------------------- 1 | # `Composer` type repository fixtures 2 | 3 | This directory contains some examples of what `composer` type repositories can 4 | look like. They serve as illustrating examples accompanying the docs, but can 5 | also be used as (initial) fixtures for tests. 6 | 7 | * `repo-composer-plain` is a basic, plain `packages.json` file 8 | * `repo-composer-with-includes` uses the `includes` mechanism 9 | * `repo-composer-with-providers` uses the `providers` mechanism 10 | 11 | ## Sample Packages used in these fixtures 12 | 13 | All these repositories contain the following packages. 14 | 15 | * `foo/bar` versions `1.0.0`, `1.0.1` and `1.1.0`; `dev-default` and `1.0.x-dev` branches. 16 | On `dev-default` and in `1.1.0`, `bar/baz` `~1.0` is required. 17 | * `qux/quux` only has a `dev-default` branch. It `replace`s `gar/nix`. 18 | * `gar/nix` has a `1.0.0` version and a `dev-default` branch. It is being replaced 19 | by `qux/quux`. 20 | * `bar/baz` has a `1.0.0` version and `1.0.x-dev` as well as `dev-default` branches. 21 | Additionally, `1.1.x-dev` is a branch alias for `dev-default`. 22 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/PolicyInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | use Composer\Package\PackageInterface; 16 | use Composer\Semver\Constraint\Constraint; 17 | 18 | /** 19 | * @author Nils Adermann 20 | */ 21 | interface PolicyInterface 22 | { 23 | /** 24 | * @param string $operator 25 | * @return bool 26 | * 27 | * @phpstan-param Constraint::STR_OP_* $operator 28 | */ 29 | public function versionCompare(PackageInterface $a, PackageInterface $b, $operator); 30 | 31 | /** 32 | * @param int[] $literals 33 | * @param ?string $requiredPackage 34 | * @return int[] 35 | */ 36 | public function selectPreferredPackages(Pool $pool, array $literals, $requiredPackage = null); 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Nils Adermann, Jordi Boggiano 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /doc/faqs/why-are-version-constraints-combining-comparisons-and-wildcards-a-bad-idea.md: -------------------------------------------------------------------------------- 1 | # Why are version constraints combining comparisons and wildcards a bad idea? 2 | 3 | This is a fairly common mistake people make, defining version constraints in 4 | their package requires like `>=2.*` or `>=1.1.*`. 5 | 6 | If you think about it and what it really means though, you will quickly 7 | realize that it does not make much sense. If we decompose `>=2.*`, you 8 | have two parts: 9 | 10 | - `>=2` which says the package should be in version 2.0.0 or above. 11 | - `2.*` which says the package should be between version 2.0.0 (inclusive) 12 | and 3.0.0 (exclusive). 13 | 14 | As you see, both rules agree on the fact that the package must be >=2.0.0, 15 | but it is not possible to determine if when you wrote that you were thinking 16 | of a package in version 3.0.0 or not. Should it match because you asked for 17 | `>=2` or should it not match because you asked for a `2.*`? 18 | 19 | For this reason, Composer throws an error and says that this is invalid. 20 | The way to fix it is to think about what you really mean, and use only 21 | one of those rules. 22 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/OperationInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | /** 16 | * Solver operation interface. 17 | * 18 | * @author Konstantin Kudryashov 19 | */ 20 | interface OperationInterface 21 | { 22 | /** 23 | * Returns operation type. 24 | * 25 | * @return string 26 | */ 27 | public function getOperationType(); 28 | 29 | /** 30 | * Serializes the operation in a human readable format 31 | * 32 | * @param bool $lock Whether this is an operation on the lock file 33 | * @return string 34 | */ 35 | public function show($lock); 36 | 37 | /** 38 | * Serializes the operation in a human readable format 39 | * 40 | * @return string 41 | */ 42 | public function __toString(); 43 | } 44 | -------------------------------------------------------------------------------- /src/Composer/Repository/InstalledArrayRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | /** 16 | * Installed array repository. 17 | * 18 | * This is used as an in-memory InstalledRepository mostly for testing purposes 19 | * 20 | * @author Jordi Boggiano 21 | */ 22 | class InstalledArrayRepository extends WritableArrayRepository implements InstalledRepositoryInterface 23 | { 24 | public function getRepoName() 25 | { 26 | return 'installed '.parent::getRepoName(); 27 | } 28 | 29 | /** 30 | * @inheritDoc 31 | */ 32 | public function isFresh() 33 | { 34 | // this is not a completely correct implementation but there is no way to 35 | // distinguish an empty repo and a newly created one given this is all in-memory 36 | return $this->count() === 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Composer/SelfUpdate/Keys.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\SelfUpdate; 14 | 15 | use Composer\Pcre\Preg; 16 | 17 | /** 18 | * @author Jordi Boggiano 19 | */ 20 | class Keys 21 | { 22 | /** 23 | * @param string $path 24 | * 25 | * @return string 26 | */ 27 | public static function fingerprint($path) 28 | { 29 | $hash = strtoupper(hash('sha256', Preg::replace('{\s}', '', file_get_contents($path)))); 30 | 31 | return implode(' ', array( 32 | substr($hash, 0, 8), 33 | substr($hash, 8, 8), 34 | substr($hash, 16, 8), 35 | substr($hash, 24, 8), 36 | '', // Extra space 37 | substr($hash, 32, 8), 38 | substr($hash, 40, 8), 39 | substr($hash, 48, 8), 40 | substr($hash, 56, 8), 41 | )); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /doc/faqs/why-are-unbound-version-constraints-a-bad-idea.md: -------------------------------------------------------------------------------- 1 | # Why are unbound version constraints a bad idea? 2 | 3 | A version constraint without an upper bound such as `*`, `>=3.4` or 4 | `dev-master` will allow updates to any future version of the dependency. 5 | This includes major versions breaking backward compatibility. 6 | 7 | Once a release of your package is tagged, you cannot tweak its dependencies 8 | anymore in case a dependency breaks BC - you have to do a new release, but the 9 | previous one stays broken. 10 | 11 | The only good alternative is to define an upper bound on your constraints, 12 | which you can increase in a new release after testing that your package is 13 | compatible with the new major version of your dependency. 14 | 15 | For example instead of using `>=3.4` you should use `~3.4` which allows all 16 | versions up to `3.999` but does not include `4.0` and above. The `^` operator 17 | works very well with libraries following [semantic versioning](https://semver.org). 18 | 19 | **Note:** As a package maintainer, you can help your users 20 | by providing an [alias version](../articles/aliases.md) for your development 21 | branch to allow it to match bound constraints. 22 | -------------------------------------------------------------------------------- /src/Composer/Downloader/XzDownloader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | use Composer\Util\ProcessExecutor; 17 | 18 | /** 19 | * Xz archive downloader. 20 | * 21 | * @author Pavel Puchkin 22 | * @author Pierre Rudloff 23 | */ 24 | class XzDownloader extends ArchiveDownloader 25 | { 26 | protected function extract(PackageInterface $package, $file, $path) 27 | { 28 | $command = 'tar -xJf ' . ProcessExecutor::escape($file) . ' -C ' . ProcessExecutor::escape($path); 29 | 30 | if (0 === $this->process->execute($command, $ignoredOutput)) { 31 | return \React\Promise\resolve(); 32 | } 33 | 34 | $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); 35 | 36 | throw new \RuntimeException($processError); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Composer/Downloader/PharDownloader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * Downloader for phar files 19 | * 20 | * @author Kirill chEbba Chebunin 21 | */ 22 | class PharDownloader extends ArchiveDownloader 23 | { 24 | /** 25 | * @inheritDoc 26 | */ 27 | protected function extract(PackageInterface $package, $file, $path) 28 | { 29 | // Can throw an UnexpectedValueException 30 | $archive = new \Phar($file); 31 | $archive->extractTo($path, null, true); 32 | /* TODO: handle openssl signed phars 33 | * https://github.com/composer/composer/pull/33#issuecomment-2250768 34 | * https://github.com/koto/phar-util 35 | * http://blog.kotowicz.net/2010/08/hardening-php-how-to-securely-include.html 36 | */ 37 | 38 | return \React\Promise\resolve(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Composer/Package/Loader/LoaderInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Loader; 14 | 15 | use Composer\Package\CompletePackageInterface; 16 | use Composer\Package\CompletePackage; 17 | use Composer\Package\CompleteAliasPackage; 18 | use Composer\Package\RootAliasPackage; 19 | use Composer\Package\RootPackage; 20 | 21 | /** 22 | * Defines a loader that takes an array to create package instances 23 | * 24 | * @author Jordi Boggiano 25 | */ 26 | interface LoaderInterface 27 | { 28 | /** 29 | * Converts a package from an array to a real instance 30 | * 31 | * @template PackageClass of CompletePackageInterface 32 | * 33 | * @param mixed[] $config package data 34 | * @param string $class FQCN to be instantiated 35 | * 36 | * @return CompletePackage|CompleteAliasPackage|RootPackage|RootAliasPackage 37 | * 38 | * @phpstan-param class-string $class 39 | */ 40 | public function load(array $config, $class = 'Composer\Package\CompletePackage'); 41 | } 42 | -------------------------------------------------------------------------------- /src/Composer/Package/Archiver/ArchivableFilesFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Archiver; 14 | 15 | use FilterIterator; 16 | use PharData; 17 | 18 | class ArchivableFilesFilter extends FilterIterator 19 | { 20 | /** @var string[] */ 21 | private $dirs = array(); 22 | 23 | /** 24 | * @return bool true if the current element is acceptable, otherwise false. 25 | */ 26 | #[\ReturnTypeWillChange] 27 | public function accept() 28 | { 29 | $file = $this->getInnerIterator()->current(); 30 | if ($file->isDir()) { 31 | $this->dirs[] = (string) $file; 32 | 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | /** 40 | * @param string $sources 41 | * 42 | * @return void 43 | */ 44 | public function addEmptyDir(PharData $phar, $sources) 45 | { 46 | foreach ($this->dirs as $filepath) { 47 | $localname = str_replace($sources . "/", '', $filepath); 48 | $phar->addEmptyDir($localname); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Composer/Plugin/Capable.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin; 14 | 15 | /** 16 | * Plugins which need to expose various implementations 17 | * of the Composer Plugin Capabilities must have their 18 | * declared Plugin class implementing this interface. 19 | * 20 | * @api 21 | */ 22 | interface Capable 23 | { 24 | /** 25 | * Method by which a Plugin announces its API implementations, through an array 26 | * with a special structure. 27 | * 28 | * The key must be a string, representing a fully qualified class/interface name 29 | * which Composer Plugin API exposes. 30 | * The value must be a string as well, representing the fully qualified class name 31 | * of the implementing class. 32 | * 33 | * @tutorial 34 | * 35 | * return array( 36 | * 'Composer\Plugin\Capability\CommandProvider' => 'My\CommandProvider', 37 | * 'Composer\Plugin\Capability\Validator' => 'My\Validator', 38 | * ); 39 | * 40 | * @return string[] 41 | */ 42 | public function getCapabilities(); 43 | } 44 | -------------------------------------------------------------------------------- /src/Composer/Filter/PlatformRequirementFilter/PlatformRequirementFilterFactory.php: -------------------------------------------------------------------------------- 1 | All code contributions - including those of people having commit access - must 16 | > go through a pull request and approved by a core developer before being 17 | > merged. This is to ensure proper review of all the code. 18 | > 19 | > Fork the project, create a feature branch, and send us a pull request. 20 | > 21 | > To ensure a consistent code base, you should make sure the code follows 22 | > the [PSR-2 Coding Standards](https://www.php-fig.org/psr/psr-2/). 23 | 24 | ## Support 25 | 26 | The IRC channel is on irc.libera.chat: [#composer](ircs://irc.libera.chat:6697/composer). 27 | 28 | [Stack Overflow](https://stackoverflow.com/questions/tagged/composer-php) and 29 | [GitHub Discussions](https://github.com/composer/composer/discussions) both have a 30 | collection of Composer related questions. 31 | 32 | For paid support, we do provide Composer-related support via chat and email to 33 | [Private Packagist](https://packagist.com) customers. 34 | 35 | 36 | ← [Config](07-runtime.md) 37 | -------------------------------------------------------------------------------- /doc/dev/DefaultPolicy.md: -------------------------------------------------------------------------------- 1 | # Default Solver Policy 2 | 3 | A solver policy defines behaviour variables of the dependency solver. It decides 4 | which versions are considered newer than others, which packages should be 5 | preferred over others and whether operations like downgrades or uninstall are 6 | allowed. 7 | 8 | ## Selection of preferred Packages 9 | 10 | The following describe package pool situations with user requests and the 11 | resulting order in which the solver will try to install them. 12 | 13 | The rules are to be applied in the order of these descriptions. 14 | 15 | ### Repository priorities 16 | 17 | Packages Repo1.Av1, Repo2.Av1 18 | 19 | * priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1) 20 | * priority(Repo1) < priority(Repo2) => (Repo2.Av1, Repo1.Av1) 21 | 22 | ### Package versions 23 | 24 | Packages: Av1, Av2, Av3 25 | 26 | * Installed: Av2 27 | 28 | Request: install A 29 | 30 | * (Av3) 31 | 32 | ### Virtual Packages (provides) 33 | 34 | Packages Av1, Bv1 35 | 36 | * Av1 provides Xv1 37 | * Bv1 provides Xv1 38 | 39 | Request: install X 40 | 41 | * priority(Av1.repo) >= priority(Bv1.repo) => (Av1, Bv1) 42 | * priority(Av1.repo) < priority(Bv1.repo) => (Bv1, Av1) 43 | 44 | ### Package replacements 45 | 46 | Packages: Av1, Bv2 47 | 48 | * Bv2 replaces Av1 49 | 50 | Request: install A 51 | 52 | * priority(Av1.repo) >= priority(Bv2.repo) => (Av1, Bv2) 53 | * priority(Av1.repo) < priority(Bv2.repo) => (Bv2, Av1) 54 | 55 | Bv2 version is ignored, only the replacement version for A matters. 56 | -------------------------------------------------------------------------------- /doc/faqs/how-to-install-untrusted-packages-safely.md: -------------------------------------------------------------------------------- 1 | # How do I install untrusted packages safely? Is it safe to run Composer as superuser or root? 2 | 3 | Certain Composer commands, including `exec`, `install`, and `update` allow third party code to 4 | execute on your system. This is from its "plugins" and "scripts" features. Plugins and scripts have 5 | full access to the user account which runs Composer. For this reason, it is strongly advised to 6 | **avoid running Composer as super-user/root**. All commands also dispatch events which can be 7 | caught by plugins so unless explicitly disabled installed plugins will be loaded/executed by **every** 8 | Composer command. 9 | 10 | You can disable plugins and scripts during package installation or updates with the following 11 | syntax so only Composer's code, and no third party code, will execute: 12 | 13 | ```sh 14 | php composer.phar install --no-plugins --no-scripts ... 15 | php composer.phar update --no-plugins --no-scripts ... 16 | ``` 17 | 18 | Depending on the operating system we have seen cases where it is possible to trigger execution 19 | of files in the repository using specially crafted `composer.json`. So in general if you do want 20 | to install untrusted dependencies you should sandbox them completely in a container or equivalent. 21 | 22 | Also note that the `exec` command will always run third party code as the user which runs `composer`. 23 | 24 | See [Environment variable - COMPOSER_ALLOW_SUPERUSER](../03-cli.md#composer-allow-superuser) 25 | for more info on how to disable warning 26 | -------------------------------------------------------------------------------- /src/Composer/Command/AboutCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Command; 14 | 15 | use Composer\Composer; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | /** 20 | * @author Jordi Boggiano 21 | */ 22 | class AboutCommand extends BaseCommand 23 | { 24 | /** 25 | * @return void 26 | */ 27 | protected function configure() 28 | { 29 | $this 30 | ->setName('about') 31 | ->setDescription('Shows a short information about Composer.') 32 | ->setHelp( 33 | <<php composer.phar about 35 | EOT 36 | ) 37 | ; 38 | } 39 | 40 | protected function execute(InputInterface $input, OutputInterface $output) 41 | { 42 | $composerVersion = Composer::getVersion(); 43 | 44 | $this->getIO()->write( 45 | <<Composer - Dependency Manager for PHP - version $composerVersion 47 | Composer is a dependency manager tracking local dependencies of your projects and libraries. 48 | See https://getcomposer.org/ for more information. 49 | EOT 50 | ); 51 | 52 | return 0; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/MarkAliasInstalledOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | use Composer\Package\AliasPackage; 16 | 17 | /** 18 | * Solver install operation. 19 | * 20 | * @author Nils Adermann 21 | */ 22 | class MarkAliasInstalledOperation extends SolverOperation implements OperationInterface 23 | { 24 | const TYPE = 'markAliasInstalled'; 25 | 26 | /** 27 | * @var AliasPackage 28 | */ 29 | protected $package; 30 | 31 | public function __construct(AliasPackage $package) 32 | { 33 | $this->package = $package; 34 | } 35 | 36 | /** 37 | * Returns package instance. 38 | * 39 | * @return AliasPackage 40 | */ 41 | public function getPackage() 42 | { 43 | return $this->package; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function show($lock) 50 | { 51 | return 'Marking '.$this->package->getPrettyName().' ('.$this->package->getFullPrettyVersion().') as installed, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->package->getAliasOf()->getFullPrettyVersion().')'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/MarkAliasUninstalledOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | use Composer\Package\AliasPackage; 16 | 17 | /** 18 | * Solver install operation. 19 | * 20 | * @author Nils Adermann 21 | */ 22 | class MarkAliasUninstalledOperation extends SolverOperation implements OperationInterface 23 | { 24 | const TYPE = 'markAliasUninstalled'; 25 | 26 | /** 27 | * @var AliasPackage 28 | */ 29 | protected $package; 30 | 31 | public function __construct(AliasPackage $package) 32 | { 33 | $this->package = $package; 34 | } 35 | 36 | /** 37 | * Returns package instance. 38 | * 39 | * @return AliasPackage 40 | */ 41 | public function getPackage() 42 | { 43 | return $this->package; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function show($lock) 50 | { 51 | return 'Marking '.$this->package->getPrettyName().' ('.$this->package->getFullPrettyVersion().') as uninstalled, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->package->getAliasOf()->getFullPrettyVersion().')'; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Composer/Package/Archiver/ArchiverInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Archiver; 14 | 15 | /** 16 | * @author Till Klampaeckel 17 | * @author Matthieu Moquet 18 | * @author Nils Adermann 19 | */ 20 | interface ArchiverInterface 21 | { 22 | /** 23 | * Create an archive from the sources. 24 | * 25 | * @param string $sources The sources directory 26 | * @param string $target The target file 27 | * @param string $format The format used for archive 28 | * @param string[] $excludes A list of patterns for files to exclude 29 | * @param bool $ignoreFilters Whether to ignore filters when looking for files 30 | * 31 | * @return string The path to the written archive file 32 | */ 33 | public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false); 34 | 35 | /** 36 | * Format supported by the archiver. 37 | * 38 | * @param string $format The archive format 39 | * @param string $sourceType The source type (git, svn, hg, etc.) 40 | * 41 | * @return bool true if the format is supported by the archiver 42 | */ 43 | public function supports($format, $sourceType); 44 | } 45 | -------------------------------------------------------------------------------- /src/Composer/Util/Http/CurlResponse.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util\Http; 14 | 15 | /** 16 | * @phpstan-type CurlInfo array{url: mixed, content_type: mixed, http_code: mixed, header_size: mixed, request_size: mixed, filetime: mixed, ssl_verify_result: mixed, redirect_count: mixed, total_time: mixed, namelookup_time: mixed, connect_time: mixed, pretransfer_time: mixed, size_upload: mixed, size_download: mixed, speed_download: mixed, speed_upload: mixed, download_content_length: mixed, upload_content_length: mixed, starttransfer_time: mixed, redirect_time: mixed, certinfo: mixed, primary_ip: mixed, primary_port: mixed, local_ip: mixed, local_port: mixed, redirect_url: mixed} 17 | */ 18 | class CurlResponse extends Response 19 | { 20 | /** 21 | * @see https://www.php.net/curl_getinfo 22 | * @var CurlInfo 23 | */ 24 | private $curlInfo; 25 | 26 | /** 27 | * @param CurlInfo $curlInfo 28 | */ 29 | public function __construct(array $request, $code, array $headers, $body, array $curlInfo) 30 | { 31 | parent::__construct($request, $code, $headers, $body); 32 | $this->curlInfo = $curlInfo; 33 | } 34 | 35 | /** 36 | * @return CurlInfo 37 | */ 38 | public function getCurlInfo() 39 | { 40 | return $this->curlInfo; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Composer/Package/Loader/InvalidPackageException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Loader; 14 | 15 | /** 16 | * @author Jordi Boggiano 17 | */ 18 | class InvalidPackageException extends \Exception 19 | { 20 | /** @var string[] */ 21 | private $errors; 22 | /** @var string[] */ 23 | private $warnings; 24 | /** @var mixed[] package config */ 25 | private $data; 26 | 27 | /** 28 | * @param string[] $errors 29 | * @param string[] $warnings 30 | * @param mixed[] $data 31 | */ 32 | public function __construct(array $errors, array $warnings, array $data) 33 | { 34 | $this->errors = $errors; 35 | $this->warnings = $warnings; 36 | $this->data = $data; 37 | parent::__construct("Invalid package information: \n".implode("\n", array_merge($errors, $warnings))); 38 | } 39 | 40 | /** 41 | * @return mixed[] 42 | */ 43 | public function getData() 44 | { 45 | return $this->data; 46 | } 47 | 48 | /** 49 | * @return string[] 50 | */ 51 | public function getErrors() 52 | { 53 | return $this->errors; 54 | } 55 | 56 | /** 57 | * @return string[] 58 | */ 59 | public function getWarnings() 60 | { 61 | return $this->warnings; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/UninstallOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * Solver uninstall operation. 19 | * 20 | * @author Konstantin Kudryashov 21 | */ 22 | class UninstallOperation extends SolverOperation implements OperationInterface 23 | { 24 | const TYPE = 'uninstall'; 25 | 26 | /** 27 | * @var PackageInterface 28 | */ 29 | protected $package; 30 | 31 | public function __construct(PackageInterface $package) 32 | { 33 | $this->package = $package; 34 | } 35 | 36 | /** 37 | * Returns package instance. 38 | * 39 | * @return PackageInterface 40 | */ 41 | public function getPackage() 42 | { 43 | return $this->package; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function show($lock) 50 | { 51 | return self::format($this->package, $lock); 52 | } 53 | 54 | /** 55 | * @param bool $lock 56 | * @return string 57 | */ 58 | public static function format(PackageInterface $package, $lock = false) 59 | { 60 | return 'Removing '.$package->getPrettyName().' ('.$package->getFullPrettyVersion().')'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /doc/faqs/how-to-install-composer-programmatically.md: -------------------------------------------------------------------------------- 1 | # How do I install Composer programmatically? 2 | 3 | As noted on the download page, the installer script contains a 4 | checksum which changes when the installer code changes and as such 5 | it should not be relied upon in the long term. 6 | 7 | An alternative is to use this script which only works with UNIX utilities: 8 | 9 | ```bash 10 | #!/bin/sh 11 | 12 | EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" 13 | php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 14 | ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" 15 | 16 | if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ] 17 | then 18 | >&2 echo 'ERROR: Invalid installer checksum' 19 | rm composer-setup.php 20 | exit 1 21 | fi 22 | 23 | php composer-setup.php --quiet 24 | RESULT=$? 25 | rm composer-setup.php 26 | exit $RESULT 27 | ``` 28 | 29 | The script will exit with 1 in case of failure, or 0 on success, and is quiet 30 | if no error occurs. 31 | 32 | Alternatively, if you want to rely on an exact copy of the installer, you can fetch 33 | a specific version from GitHub's history. The commit hash should be enough to 34 | give it uniqueness and authenticity as long as you can trust the GitHub servers. 35 | For example: 36 | 37 | ```bash 38 | wget https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -O - -q | php -- --quiet 39 | ``` 40 | 41 | You may replace the commit hash by whatever the last commit hash is on 42 | https://github.com/composer/getcomposer.org/commits/main 43 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/InstallOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | use Composer\Package\PackageInterface; 16 | 17 | /** 18 | * Solver install operation. 19 | * 20 | * @author Konstantin Kudryashov 21 | */ 22 | class InstallOperation extends SolverOperation implements OperationInterface 23 | { 24 | const TYPE = 'install'; 25 | 26 | /** 27 | * @var PackageInterface 28 | */ 29 | protected $package; 30 | 31 | public function __construct(PackageInterface $package) 32 | { 33 | $this->package = $package; 34 | } 35 | 36 | /** 37 | * Returns package instance. 38 | * 39 | * @return PackageInterface 40 | */ 41 | public function getPackage() 42 | { 43 | return $this->package; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function show($lock) 50 | { 51 | return self::format($this->package, $lock); 52 | } 53 | 54 | /** 55 | * @param bool $lock 56 | * @return string 57 | */ 58 | public static function format(PackageInterface $package, $lock = false) 59 | { 60 | return ($lock ? 'Locking ' : 'Installing ').''.$package->getPrettyName().' ('.$package->getFullPrettyVersion().')'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Composer/Plugin/PreCommandRunEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin; 14 | 15 | use Composer\EventDispatcher\Event; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | 18 | /** 19 | * The pre command run event. 20 | * 21 | * @author Jordi Boggiano 22 | */ 23 | class PreCommandRunEvent extends Event 24 | { 25 | /** 26 | * @var InputInterface 27 | */ 28 | private $input; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private $command; 34 | 35 | /** 36 | * Constructor. 37 | * 38 | * @param string $name The event name 39 | * @param InputInterface $input 40 | * @param string $command The command about to be executed 41 | */ 42 | public function __construct($name, InputInterface $input, $command) 43 | { 44 | parent::__construct($name); 45 | $this->input = $input; 46 | $this->command = $command; 47 | } 48 | 49 | /** 50 | * Returns the console input 51 | * 52 | * @return InputInterface 53 | */ 54 | public function getInput() 55 | { 56 | return $this->input; 57 | } 58 | 59 | /** 60 | * Returns the command about to be executed 61 | * 62 | * @return string 63 | */ 64 | public function getCommand() 65 | { 66 | return $this->command; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Composer/Package/Loader/JsonLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Loader; 14 | 15 | use Composer\Json\JsonFile; 16 | use Composer\Package\CompletePackage; 17 | use Composer\Package\CompleteAliasPackage; 18 | 19 | /** 20 | * @author Konstantin Kudryashiv 21 | */ 22 | class JsonLoader 23 | { 24 | /** @var LoaderInterface */ 25 | private $loader; 26 | 27 | public function __construct(LoaderInterface $loader) 28 | { 29 | $this->loader = $loader; 30 | } 31 | 32 | /** 33 | * @param string|JsonFile $json A filename, json string or JsonFile instance to load the package from 34 | * @return CompletePackage|CompleteAliasPackage 35 | */ 36 | public function load($json) 37 | { 38 | if ($json instanceof JsonFile) { 39 | $config = $json->read(); 40 | } elseif (file_exists($json)) { 41 | $config = JsonFile::parseJson(file_get_contents($json), $json); 42 | } elseif (is_string($json)) { 43 | $config = JsonFile::parseJson($json); 44 | } else { 45 | throw new \InvalidArgumentException(sprintf( 46 | "JsonLoader: Unknown \$json parameter %s. Please report at https://github.com/composer/composer/issues/new.", 47 | gettype($json) 48 | )); 49 | } 50 | 51 | return $this->loader->load($config); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/RuleWatchChain.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | /** 16 | * An extension of SplDoublyLinkedList with seek and removal of current element 17 | * 18 | * SplDoublyLinkedList only allows deleting a particular offset and has no 19 | * method to set the internal iterator to a particular offset. 20 | * 21 | * @author Nils Adermann 22 | * @extends \SplDoublyLinkedList 23 | */ 24 | class RuleWatchChain extends \SplDoublyLinkedList 25 | { 26 | /** 27 | * Moves the internal iterator to the specified offset 28 | * 29 | * @param int $offset The offset to seek to. 30 | * @return void 31 | */ 32 | public function seek($offset) 33 | { 34 | $this->rewind(); 35 | for ($i = 0; $i < $offset; $i++, $this->next()); 36 | } 37 | 38 | /** 39 | * Removes the current element from the list 40 | * 41 | * As SplDoublyLinkedList only allows deleting a particular offset and 42 | * incorrectly sets the internal iterator if you delete the current value 43 | * this method sets the internal iterator back to the following element 44 | * using the seek method. 45 | * 46 | * @return void 47 | */ 48 | public function remove() 49 | { 50 | $offset = $this->key(); 51 | $this->offsetUnset($offset); 52 | $this->seek($offset); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /PORTING_INFO: -------------------------------------------------------------------------------- 1 | * add rule 2 | * p = direct literal; always < 0 for installed rpm rules 3 | * d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only) 4 | * 5 | * 6 | * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3) 7 | * 8 | * p < 0 : pkg id of A 9 | * d > 0 : Offset in whatprovidesdata (list of providers of b) 10 | * 11 | * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3) 12 | * p < 0 : pkg id of A 13 | * d < 0 : Id of solvable (e.g. B1) 14 | * 15 | * d == 0: unary rule, assertion => (A) or (-A) 16 | * 17 | * Install: p > 0, d = 0 (A) user requested install 18 | * Remove: p < 0, d = 0 (-A) user requested remove (also: uninstallable) 19 | * Requires: p < 0, d > 0 (-A|B1|B2|...) d: 20 | * Updates: p > 0, d > 0 (A|B1|B2|...) d: 21 | * Conflicts: p < 0, d < 0 (-A|-B) either p (conflict issuer) or d (conflict provider) (binary rule) 22 | * also used for obsoletes 23 | * ?: p > 0, d < 0 (A|-B) 24 | * No-op ?: p = 0, d = 0 (null) (used as policy rule placeholder) 25 | * 26 | * resulting watches: 27 | * ------------------ 28 | * Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0 29 | * Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p 30 | * every other : w1 = p, w2 = whatprovidesdata[d]; 31 | * Disabled rule: w1 = 0 32 | * 33 | * always returns a rule for non-rpm rules 34 | 35 | 36 | 37 | p > 0, d = 0, (A), w1 = p, w2 = 0 38 | p < 0, d = 0, (-A), w1 = p, w2 = 0 39 | p !=0, d = 0, (p|q), w1 = p, w2 = q 40 | -------------------------------------------------------------------------------- /src/Composer/EventDispatcher/EventSubscriberInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\EventDispatcher; 14 | 15 | /** 16 | * An EventSubscriber knows which events it is interested in. 17 | * 18 | * If an EventSubscriber is added to an EventDispatcher, the manager invokes 19 | * {@link getSubscribedEvents} and registers the subscriber as a listener for all 20 | * returned events. 21 | * 22 | * @author Guilherme Blanco 23 | * @author Jonathan Wage 24 | * @author Roman Borschel 25 | * @author Bernhard Schussek 26 | */ 27 | interface EventSubscriberInterface 28 | { 29 | /** 30 | * Returns an array of event names this subscriber wants to listen to. 31 | * 32 | * The array keys are event names and the value can be: 33 | * 34 | * * The method name to call (priority defaults to 0) 35 | * * An array composed of the method name to call and the priority 36 | * * An array of arrays composed of the method names to call and respective 37 | * priorities, or 0 if unset 38 | * 39 | * For instance: 40 | * 41 | * * array('eventName' => 'methodName') 42 | * * array('eventName' => array('methodName', $priority)) 43 | * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) 44 | * 45 | * @return array> The event names to listen to 46 | */ 47 | public static function getSubscribedEvents(); 48 | } 49 | -------------------------------------------------------------------------------- /doc/faqs/should-i-commit-the-dependencies-in-my-vendor-directory.md: -------------------------------------------------------------------------------- 1 | # Should I commit the dependencies in my vendor directory? 2 | 3 | The general recommendation is **no**. The vendor directory (or wherever your 4 | dependencies are installed) should be added to `.gitignore`/`svn:ignore`/etc. 5 | 6 | The best practice is to then have all the developers use Composer to install 7 | the dependencies. Similarly, the build server, CI, deployment tools etc should 8 | be adapted to run Composer as part of their project bootstrapping. 9 | 10 | While it can be tempting to commit it in some environment, it leads to a few 11 | problems: 12 | 13 | - Large VCS repository size and diffs when you update code. 14 | - Duplication of the history of all your dependencies in your own VCS. 15 | - Adding dependencies installed via git to a git repo will show them as 16 | submodules. This is problematic because they are not real submodules, and you 17 | will run into issues. 18 | 19 | If you really feel like you must do this, you have a few options: 20 | 21 | 1. Limit yourself to installing tagged releases (no dev versions), so that you 22 | only get zipped installs, and avoid problems with the git "submodules". 23 | 2. Use --prefer-dist or set `preferred-install` to `dist` in your 24 | [config](../04-schema.md#config). 25 | 3. Remove the `.git` directory of every dependency after the installation, then 26 | you can add them to your git repo. You can do that with `rm -rf vendor/**/.git` 27 | in ZSH or `find vendor/ -type d -name ".git" -exec rm -rf {} \;` in Bash. 28 | But this means you will have to delete those dependencies from disk before 29 | running `composer update`. 30 | 4. Add a .gitignore rule (`/vendor/**/.git`) to ignore all the vendor `.git` folders. 31 | This approach does not require that you delete dependencies from disk prior to 32 | running a `composer update`. 33 | -------------------------------------------------------------------------------- /doc/fixtures/repo-composer-with-providers/p/gar/nix$5d210670cb46c8364c8e3fb449967b9bea558b971e5b082f330ae4f1d484c321.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | "qux\/quux": { 4 | "dev-default": { 5 | "name": "qux\/quux", 6 | "version": "dev-default", 7 | "version_normalized": "9999999-dev", 8 | "source": { 9 | "type": "hg", 10 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 11 | "reference": "4a10a567baa5" 12 | }, 13 | "replace": { 14 | "gar\/nix": "1.0.*" 15 | }, 16 | "time": "2014-10-11 15:48:15", 17 | "type": "library", 18 | "uid": 10 19 | } 20 | }, 21 | "gar\/nix": { 22 | "1.0.0": { 23 | "name": "gar\/nix", 24 | "version": "1.0.0", 25 | "version_normalized": "1.0.0.0", 26 | "source": { 27 | "type": "hg", 28 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 29 | "reference": "44977145d64e" 30 | }, 31 | "time": "2014-10-13 12:03:33", 32 | "type": "library", 33 | "uid": 8 34 | }, 35 | "dev-default": { 36 | "name": "gar\/nix", 37 | "version": "dev-default", 38 | "version_normalized": "9999999-dev", 39 | "source": { 40 | "type": "hg", 41 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 42 | "reference": "51cca95a31c2" 43 | }, 44 | "time": "2014-10-13 12:03:35", 45 | "type": "library", 46 | "uid": 9 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Composer/Util/IniHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | use Composer\XdebugHandler\XdebugHandler; 16 | 17 | /** 18 | * Provides ini file location functions that work with and without a restart. 19 | * When the process has restarted it uses a tmp ini and stores the original 20 | * ini locations in an environment variable. 21 | * 22 | * @author John Stevenson 23 | */ 24 | class IniHelper 25 | { 26 | /** 27 | * Returns an array of php.ini locations with at least one entry 28 | * 29 | * The equivalent of calling php_ini_loaded_file then php_ini_scanned_files. 30 | * The loaded ini location is the first entry and may be empty. 31 | * 32 | * @return string[] 33 | */ 34 | public static function getAll() 35 | { 36 | return XdebugHandler::getAllIniFiles(); 37 | } 38 | 39 | /** 40 | * Describes the location of the loaded php.ini file(s) 41 | * 42 | * @return string 43 | */ 44 | public static function getMessage() 45 | { 46 | $paths = self::getAll(); 47 | 48 | if (empty($paths[0])) { 49 | array_shift($paths); 50 | } 51 | 52 | $ini = array_shift($paths); 53 | 54 | if (empty($ini)) { 55 | return 'A php.ini file does not exist. You will have to create one.'; 56 | } 57 | 58 | if (!empty($paths)) { 59 | return 'Your command-line PHP is using multiple ini files. Run `php --ini` to show them.'; 60 | } 61 | 62 | return 'The php.ini used by your command-line PHP is: '.$ini; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /doc/fixtures/repo-composer-with-providers/p/bar/baz$923363b3c22e73abb2e3fd891c8156dd4d0821a97fd3e428bc910833e3e46dbe.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | "bar\/baz": { 4 | "1.0.0": { 5 | "name": "bar\/baz", 6 | "version": "1.0.0", 7 | "version_normalized": "1.0.0.0", 8 | "source": { 9 | "type": "hg", 10 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 11 | "reference": "35810817c14d" 12 | }, 13 | "time": "2014-10-13 12:04:55", 14 | "type": "library", 15 | "uid": 0 16 | }, 17 | "1.0.x-dev": { 18 | "name": "bar\/baz", 19 | "version": "1.0.x-dev", 20 | "version_normalized": "1.0.9999999.9999999-dev", 21 | "source": { 22 | "type": "hg", 23 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 24 | "reference": "ffff9aae6ed5" 25 | }, 26 | "time": "2014-10-13 12:05:37", 27 | "type": "library", 28 | "uid": 1 29 | }, 30 | "dev-default": { 31 | "name": "bar\/baz", 32 | "version": "dev-default", 33 | "version_normalized": "9999999-dev", 34 | "source": { 35 | "type": "hg", 36 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 37 | "reference": "f317e556f2e2" 38 | }, 39 | "time": "2014-10-13 12:06:45", 40 | "type": "library", 41 | "extra": { 42 | "branch-alias": { 43 | "dev-default": "1.1.x-dev" 44 | } 45 | }, 46 | "uid": 2 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Composer/Package/Archiver/GitExcludeFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Archiver; 14 | 15 | use Composer\Pcre\Preg; 16 | 17 | /** 18 | * An exclude filter that processes gitattributes 19 | * 20 | * It respects export-ignore git attributes 21 | * 22 | * @author Nils Adermann 23 | */ 24 | class GitExcludeFilter extends BaseExcludeFilter 25 | { 26 | /** 27 | * Parses .gitattributes if it exists 28 | * 29 | * @param string $sourcePath 30 | */ 31 | public function __construct($sourcePath) 32 | { 33 | parent::__construct($sourcePath); 34 | 35 | if (file_exists($sourcePath.'/.gitattributes')) { 36 | $this->excludePatterns = array_merge( 37 | $this->excludePatterns, 38 | $this->parseLines( 39 | file($sourcePath.'/.gitattributes'), 40 | array($this, 'parseGitAttributesLine') 41 | ) 42 | ); 43 | } 44 | } 45 | 46 | /** 47 | * Callback parser which finds export-ignore rules in git attribute lines 48 | * 49 | * @param string $line A line from .gitattributes 50 | * 51 | * @return array{0: string, 1: bool, 2: bool}|null An exclude pattern for filter() 52 | */ 53 | public function parseGitAttributesLine($line) 54 | { 55 | $parts = Preg::split('#\s+#', $line); 56 | 57 | if (count($parts) == 2 && $parts[1] === 'export-ignore') { 58 | return $this->generatePattern($parts[0]); 59 | } 60 | 61 | if (count($parts) == 2 && $parts[1] === '-export-ignore') { 62 | return $this->generatePattern('!'.$parts[0]); 63 | } 64 | 65 | return null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Composer/Package/Version/StabilityFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Version; 14 | 15 | use Composer\Package\BasePackage; 16 | 17 | /** 18 | * @author Jordi Boggiano 19 | */ 20 | class StabilityFilter 21 | { 22 | /** 23 | * Checks if any of the provided package names in the given stability match the configured acceptable stability and flags 24 | * 25 | * @param int[] $acceptableStabilities array of stability => BasePackage::STABILITY_* value 26 | * @phpstan-param array $acceptableStabilities 27 | * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value 28 | * @phpstan-param array $stabilityFlags 29 | * @param string[] $names The package name(s) to check for stability flags 30 | * @param string $stability one of 'stable', 'RC', 'beta', 'alpha' or 'dev' 31 | * @return bool true if any package name is acceptable 32 | */ 33 | public static function isPackageAcceptable(array $acceptableStabilities, array $stabilityFlags, array $names, $stability) 34 | { 35 | foreach ($names as $name) { 36 | // allow if package matches the package-specific stability flag 37 | if (isset($stabilityFlags[$name])) { 38 | if (BasePackage::$stabilities[$stability] <= $stabilityFlags[$name]) { 39 | return true; 40 | } 41 | } elseif (isset($acceptableStabilities[$stability])) { 42 | // allow if package matches the global stability requirement and has no exception 43 | return true; 44 | } 45 | } 46 | 47 | return false; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Composer/Command/DependsCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Command; 14 | 15 | use Symfony\Component\Console\Input\InputInterface; 16 | use Symfony\Component\Console\Output\OutputInterface; 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Input\InputOption; 19 | 20 | /** 21 | * @author Niels Keurentjes 22 | */ 23 | class DependsCommand extends BaseDependencyCommand 24 | { 25 | /** 26 | * Configure command metadata. 27 | * 28 | * @return void 29 | */ 30 | protected function configure() 31 | { 32 | $this 33 | ->setName('depends') 34 | ->setAliases(array('why')) 35 | ->setDescription('Shows which packages cause the given package to be installed.') 36 | ->setDefinition(array( 37 | new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect'), 38 | new InputOption(self::OPTION_RECURSIVE, 'r', InputOption::VALUE_NONE, 'Recursively resolves up to the root package'), 39 | new InputOption(self::OPTION_TREE, 't', InputOption::VALUE_NONE, 'Prints the results as a nested tree'), 40 | )) 41 | ->setHelp( 42 | <<php composer.phar depends composer/composer 46 | 47 | Read more at https://getcomposer.org/doc/03-cli.md#depends-why- 48 | EOT 49 | ) 50 | ; 51 | } 52 | 53 | /** 54 | * Execute the function. 55 | * 56 | * @return int 57 | */ 58 | protected function execute(InputInterface $input, OutputInterface $output) 59 | { 60 | return parent::doExecute($input, $output); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Composer/Plugin/PluginInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin; 14 | 15 | use Composer\Composer; 16 | use Composer\IO\IOInterface; 17 | 18 | /** 19 | * Plugin interface 20 | * 21 | * @author Nils Adermann 22 | */ 23 | interface PluginInterface 24 | { 25 | /** 26 | * Version number of the internal composer-plugin-api package 27 | * 28 | * This is used to denote the API version of Plugin specific 29 | * features, but is also bumped to a new major if Composer 30 | * includes a major break in internal APIs which are susceptible 31 | * to be used by plugins. 32 | * 33 | * @var string 34 | */ 35 | const PLUGIN_API_VERSION = '2.2.0'; 36 | 37 | /** 38 | * Apply plugin modifications to Composer 39 | * 40 | * @param Composer $composer 41 | * @param IOInterface $io 42 | * 43 | * @return void 44 | */ 45 | public function activate(Composer $composer, IOInterface $io); 46 | 47 | /** 48 | * Remove any hooks from Composer 49 | * 50 | * This will be called when a plugin is deactivated before being 51 | * uninstalled, but also before it gets upgraded to a new version 52 | * so the old one can be deactivated and the new one activated. 53 | * 54 | * @param Composer $composer 55 | * @param IOInterface $io 56 | * 57 | * @return void 58 | */ 59 | public function deactivate(Composer $composer, IOInterface $io); 60 | 61 | /** 62 | * Prepare the plugin to be uninstalled 63 | * 64 | * This will be called after deactivate. 65 | * 66 | * @param Composer $composer 67 | * @param IOInterface $io 68 | * 69 | * @return void 70 | */ 71 | public function uninstall(Composer $composer, IOInterface $io); 72 | } 73 | -------------------------------------------------------------------------------- /src/Composer/Repository/PackageRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | use Composer\Package\Loader\ArrayLoader; 16 | use Composer\Package\Loader\ValidatingArrayLoader; 17 | use Composer\Pcre\Preg; 18 | 19 | /** 20 | * Package repository. 21 | * 22 | * @author Jordi Boggiano 23 | */ 24 | class PackageRepository extends ArrayRepository 25 | { 26 | /** @var mixed[] */ 27 | private $config; 28 | 29 | /** 30 | * Initializes filesystem repository. 31 | * 32 | * @param array{package: mixed[]} $config package definition 33 | */ 34 | public function __construct(array $config) 35 | { 36 | parent::__construct(); 37 | $this->config = $config['package']; 38 | 39 | // make sure we have an array of package definitions 40 | if (!is_numeric(key($this->config))) { 41 | $this->config = array($this->config); 42 | } 43 | } 44 | 45 | /** 46 | * Initializes repository (reads file, or remote address). 47 | */ 48 | protected function initialize() 49 | { 50 | parent::initialize(); 51 | 52 | $loader = new ValidatingArrayLoader(new ArrayLoader(null, true), true); 53 | foreach ($this->config as $package) { 54 | try { 55 | $package = $loader->load($package); 56 | } catch (\Exception $e) { 57 | throw new InvalidRepositoryException('A repository of type "package" contains an invalid package definition: '.$e->getMessage()."\n\nInvalid package definition:\n".json_encode($package)); 58 | } 59 | 60 | $this->addPackage($package); 61 | } 62 | } 63 | 64 | public function getRepoName() 65 | { 66 | return Preg::replace('{^array }', 'package ', parent::getRepoName()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Composer/Repository/WritableRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | use Composer\Package\PackageInterface; 16 | use Composer\Installer\InstallationManager; 17 | 18 | /** 19 | * Writable repository interface. 20 | * 21 | * @author Konstantin Kudryashov 22 | */ 23 | interface WritableRepositoryInterface extends RepositoryInterface 24 | { 25 | /** 26 | * Writes repository (f.e. to the disc). 27 | * 28 | * @param bool $devMode Whether dev requirements were included or not in this installation 29 | * @return void 30 | */ 31 | public function write($devMode, InstallationManager $installationManager); 32 | 33 | /** 34 | * Adds package to the repository. 35 | * 36 | * @param PackageInterface $package package instance 37 | * @return void 38 | */ 39 | public function addPackage(PackageInterface $package); 40 | 41 | /** 42 | * Removes package from the repository. 43 | * 44 | * @param PackageInterface $package package instance 45 | * @return void 46 | */ 47 | public function removePackage(PackageInterface $package); 48 | 49 | /** 50 | * Get unique packages (at most one package of each name), with aliases resolved and removed. 51 | * 52 | * @return PackageInterface[] 53 | */ 54 | public function getCanonicalPackages(); 55 | 56 | /** 57 | * Forces a reload of all packages. 58 | * 59 | * @return void 60 | */ 61 | public function reload(); 62 | 63 | /** 64 | * @param string[] $devPackageNames 65 | * @return void 66 | */ 67 | public function setDevPackageNames(array $devPackageNames); 68 | 69 | /** 70 | * @return string[] Names of dependencies installed through require-dev 71 | */ 72 | public function getDevPackageNames(); 73 | } 74 | -------------------------------------------------------------------------------- /src/Composer/Util/Tar.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | /** 16 | * @author Wissem Riahi 17 | */ 18 | class Tar 19 | { 20 | /** 21 | * @param string $pathToArchive 22 | * 23 | * @return string|null 24 | */ 25 | public static function getComposerJson($pathToArchive) 26 | { 27 | $phar = new \PharData($pathToArchive); 28 | 29 | if (!$phar->valid()) { 30 | return null; 31 | } 32 | 33 | return self::extractComposerJsonFromFolder($phar); 34 | } 35 | 36 | /** 37 | * @param \PharData $phar 38 | * 39 | * @throws \RuntimeException 40 | * 41 | * @return string 42 | */ 43 | private static function extractComposerJsonFromFolder(\PharData $phar) 44 | { 45 | if (isset($phar['composer.json'])) { 46 | return $phar['composer.json']->getContent(); 47 | } 48 | 49 | $topLevelPaths = array(); 50 | foreach ($phar as $folderFile) { 51 | $name = $folderFile->getBasename(); 52 | 53 | if ($folderFile->isDir()) { 54 | $topLevelPaths[$name] = true; 55 | if (\count($topLevelPaths) > 1) { 56 | throw new \RuntimeException('Archive has more than one top level directories, and no composer.json was found on the top level, so it\'s an invalid archive. Top level paths found were: '.implode(',', array_keys($topLevelPaths))); 57 | } 58 | } 59 | } 60 | 61 | $composerJsonPath = key($topLevelPaths).'/composer.json'; 62 | if ($topLevelPaths && isset($phar[$composerJsonPath])) { 63 | return $phar[$composerJsonPath]->getContent(); 64 | } 65 | 66 | throw new \RuntimeException('No composer.json found either at the top level or within the topmost directory'); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /doc/faqs/why-can't-composer-load-repositories-recursively.md: -------------------------------------------------------------------------------- 1 | # Why can't Composer load repositories recursively? 2 | 3 | You may run into problems when using custom repositories because Composer does 4 | not load the repositories of your requirements, so you have to redefine those 5 | repositories in all your `composer.json` files. 6 | 7 | Before going into details as to why this is like that, you have to understand 8 | that the main use of custom VCS & package repositories is to temporarily try 9 | some things, or use a fork of a project until your pull request is merged, etc. 10 | You should not use them to keep track of private packages. For that you should 11 | rather look into [Private Packagist](https://packagist.com) which lets you 12 | configure all your private packages in one place, and avoids the slow-downs 13 | associated with inline VCS repositories. 14 | 15 | There are three ways the dependency solver could work with custom repositories: 16 | 17 | - Fetch the repositories of root package, get all the packages from the defined 18 | repositories, then resolve requirements. This is the current state and it works well 19 | except for the limitation of not loading repositories recursively. 20 | 21 | - Fetch the repositories of root package, while initializing packages from the 22 | defined repos, initialize recursively all repos found in those packages, and 23 | their package's packages, etc, then resolve requirements. It could work, but it 24 | slows down the initialization a lot since VCS repos can each take a few seconds, 25 | and it could end up in a completely broken state since many versions of a package 26 | could define the same packages inside a package repository, but with different 27 | dist/source. There are many ways this could go wrong. 28 | 29 | - Fetch the repositories of root package, then fetch the repositories of the 30 | first level dependencies, then fetch the repositories of their dependencies, etc, 31 | then resolve requirements. This sounds more efficient, but it suffers from the 32 | same problems as the second solution, because loading the repositories of the 33 | dependencies is not as easy as it sounds. You need to load all the repos of all 34 | the potential matches for a requirement, which again might have conflicting 35 | package definitions. 36 | -------------------------------------------------------------------------------- /src/Composer/Command/ProhibitsCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Command; 14 | 15 | use Symfony\Component\Console\Input\InputInterface; 16 | use Symfony\Component\Console\Output\OutputInterface; 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Input\InputOption; 19 | 20 | /** 21 | * @author Niels Keurentjes 22 | */ 23 | class ProhibitsCommand extends BaseDependencyCommand 24 | { 25 | /** 26 | * Configure command metadata. 27 | * 28 | * @return void 29 | */ 30 | protected function configure() 31 | { 32 | $this 33 | ->setName('prohibits') 34 | ->setAliases(array('why-not')) 35 | ->setDescription('Shows which packages prevent the given package from being installed.') 36 | ->setDefinition(array( 37 | new InputArgument(self::ARGUMENT_PACKAGE, InputArgument::REQUIRED, 'Package to inspect'), 38 | new InputArgument(self::ARGUMENT_CONSTRAINT, InputArgument::REQUIRED, 'Version constraint, which version you expected to be installed'), 39 | new InputOption(self::OPTION_RECURSIVE, 'r', InputOption::VALUE_NONE, 'Recursively resolves up to the root package'), 40 | new InputOption(self::OPTION_TREE, 't', InputOption::VALUE_NONE, 'Prints the results as a nested tree'), 41 | )) 42 | ->setHelp( 43 | <<php composer.phar prohibits composer/composer 47 | 48 | Read more at https://getcomposer.org/doc/03-cli.md#prohibits-why-not- 49 | EOT 50 | ) 51 | ; 52 | } 53 | 54 | /** 55 | * Execute the function. 56 | * 57 | * @return int 58 | */ 59 | protected function execute(InputInterface $input, OutputInterface $output) 60 | { 61 | return parent::doExecute($input, $output, true); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Composer/Installer/PackageEvents.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Installer; 14 | 15 | /** 16 | * Package Events. 17 | * 18 | * @author Jordi Boggiano 19 | */ 20 | class PackageEvents 21 | { 22 | /** 23 | * The PRE_PACKAGE_INSTALL event occurs before a package is installed. 24 | * 25 | * The event listener method receives a Composer\Installer\PackageEvent instance. 26 | * 27 | * @var string 28 | */ 29 | const PRE_PACKAGE_INSTALL = 'pre-package-install'; 30 | 31 | /** 32 | * The POST_PACKAGE_INSTALL event occurs after a package is installed. 33 | * 34 | * The event listener method receives a Composer\Installer\PackageEvent instance. 35 | * 36 | * @var string 37 | */ 38 | const POST_PACKAGE_INSTALL = 'post-package-install'; 39 | 40 | /** 41 | * The PRE_PACKAGE_UPDATE event occurs before a package is updated. 42 | * 43 | * The event listener method receives a Composer\Installer\PackageEvent instance. 44 | * 45 | * @var string 46 | */ 47 | const PRE_PACKAGE_UPDATE = 'pre-package-update'; 48 | 49 | /** 50 | * The POST_PACKAGE_UPDATE event occurs after a package is updated. 51 | * 52 | * The event listener method receives a Composer\Installer\PackageEvent instance. 53 | * 54 | * @var string 55 | */ 56 | const POST_PACKAGE_UPDATE = 'post-package-update'; 57 | 58 | /** 59 | * The PRE_PACKAGE_UNINSTALL event occurs before a package has been uninstalled. 60 | * 61 | * The event listener method receives a Composer\Installer\PackageEvent instance. 62 | * 63 | * @var string 64 | */ 65 | const PRE_PACKAGE_UNINSTALL = 'pre-package-uninstall'; 66 | 67 | /** 68 | * The POST_PACKAGE_UNINSTALL event occurs after a package has been uninstalled. 69 | * 70 | * The event listener method receives a Composer\Installer\PackageEvent instance. 71 | * 72 | * @var string 73 | */ 74 | const POST_PACKAGE_UNINSTALL = 'post-package-uninstall'; 75 | } 76 | -------------------------------------------------------------------------------- /src/Composer/Plugin/CommandEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin; 14 | 15 | use Composer\EventDispatcher\Event; 16 | use Symfony\Component\Console\Input\InputInterface; 17 | use Symfony\Component\Console\Output\OutputInterface; 18 | 19 | /** 20 | * An event for all commands. 21 | * 22 | * @author Nils Adermann 23 | */ 24 | class CommandEvent extends Event 25 | { 26 | /** 27 | * @var string 28 | */ 29 | private $commandName; 30 | 31 | /** 32 | * @var InputInterface 33 | */ 34 | private $input; 35 | 36 | /** 37 | * @var OutputInterface 38 | */ 39 | private $output; 40 | 41 | /** 42 | * Constructor. 43 | * 44 | * @param string $name The event name 45 | * @param string $commandName The command name 46 | * @param InputInterface $input 47 | * @param OutputInterface $output 48 | * @param mixed[] $args Arguments passed by the user 49 | * @param mixed[] $flags Optional flags to pass data not as argument 50 | */ 51 | public function __construct($name, $commandName, $input, $output, array $args = array(), array $flags = array()) 52 | { 53 | parent::__construct($name, $args, $flags); 54 | $this->commandName = $commandName; 55 | $this->input = $input; 56 | $this->output = $output; 57 | } 58 | 59 | /** 60 | * Returns the command input interface 61 | * 62 | * @return InputInterface 63 | */ 64 | public function getInput() 65 | { 66 | return $this->input; 67 | } 68 | 69 | /** 70 | * Retrieves the command output interface 71 | * 72 | * @return OutputInterface 73 | */ 74 | public function getOutput() 75 | { 76 | return $this->output; 77 | } 78 | 79 | /** 80 | * Retrieves the name of the command being run 81 | * 82 | * @return string 83 | */ 84 | public function getCommandName() 85 | { 86 | return $this->commandName; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Composer/Platform/HhvmDetector.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Platform; 14 | 15 | use Composer\Util\Platform; 16 | use Composer\Util\ProcessExecutor; 17 | use Symfony\Component\Process\ExecutableFinder; 18 | 19 | class HhvmDetector 20 | { 21 | /** @var string|false|null */ 22 | private static $hhvmVersion = null; 23 | /** @var ?ExecutableFinder */ 24 | private $executableFinder; 25 | /** @var ?ProcessExecutor */ 26 | private $processExecutor; 27 | 28 | public function __construct(ExecutableFinder $executableFinder = null, ProcessExecutor $processExecutor = null) 29 | { 30 | $this->executableFinder = $executableFinder; 31 | $this->processExecutor = $processExecutor; 32 | } 33 | 34 | /** 35 | * @return void 36 | */ 37 | public function reset() 38 | { 39 | self::$hhvmVersion = null; 40 | } 41 | 42 | /** 43 | * @return string|null 44 | */ 45 | public function getVersion() 46 | { 47 | if (null !== self::$hhvmVersion) { 48 | return self::$hhvmVersion ?: null; 49 | } 50 | 51 | self::$hhvmVersion = defined('HHVM_VERSION') ? HHVM_VERSION : null; 52 | if (self::$hhvmVersion === null && !Platform::isWindows()) { 53 | self::$hhvmVersion = false; 54 | $this->executableFinder = $this->executableFinder ?: new ExecutableFinder(); 55 | $hhvmPath = $this->executableFinder->find('hhvm'); 56 | if ($hhvmPath !== null) { 57 | $this->processExecutor = $this->processExecutor ?: new ProcessExecutor(); 58 | $exitCode = $this->processExecutor->execute( 59 | ProcessExecutor::escape($hhvmPath). 60 | ' --php -d hhvm.jit=0 -r "echo HHVM_VERSION;" 2>/dev/null', 61 | self::$hhvmVersion 62 | ); 63 | if ($exitCode !== 0) { 64 | self::$hhvmVersion = false; 65 | } 66 | } 67 | } 68 | 69 | return self::$hhvmVersion ?: null; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/GenericRule.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | /** 16 | * @author Nils Adermann 17 | */ 18 | class GenericRule extends Rule 19 | { 20 | /** @var int[] */ 21 | protected $literals; 22 | 23 | /** 24 | * @param int[] $literals 25 | */ 26 | public function __construct(array $literals, $reason, $reasonData) 27 | { 28 | parent::__construct($reason, $reasonData); 29 | 30 | // sort all packages ascending by id 31 | sort($literals); 32 | 33 | $this->literals = $literals; 34 | } 35 | 36 | /** 37 | * @return int[] 38 | */ 39 | public function getLiterals() 40 | { 41 | return $this->literals; 42 | } 43 | 44 | /** 45 | * @inheritDoc 46 | */ 47 | public function getHash() 48 | { 49 | $data = unpack('ihash', md5(implode(',', $this->literals), true)); 50 | 51 | return $data['hash']; 52 | } 53 | 54 | /** 55 | * Checks if this rule is equal to another one 56 | * 57 | * Ignores whether either of the rules is disabled. 58 | * 59 | * @param Rule $rule The rule to check against 60 | * @return bool Whether the rules are equal 61 | */ 62 | public function equals(Rule $rule) 63 | { 64 | return $this->literals === $rule->getLiterals(); 65 | } 66 | 67 | /** 68 | * @return bool 69 | */ 70 | public function isAssertion() 71 | { 72 | return 1 === \count($this->literals); 73 | } 74 | 75 | /** 76 | * Formats a rule as a string of the format (Literal1|Literal2|...) 77 | * 78 | * @return string 79 | */ 80 | public function __toString() 81 | { 82 | $result = $this->isDisabled() ? 'disabled(' : '('; 83 | 84 | foreach ($this->literals as $i => $literal) { 85 | if ($i != 0) { 86 | $result .= '|'; 87 | } 88 | $result .= $literal; 89 | } 90 | 91 | $result .= ')'; 92 | 93 | return $result; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Composer/Downloader/TransportException.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | /** 16 | * @author Jordi Boggiano 17 | */ 18 | class TransportException extends \RuntimeException 19 | { 20 | /** @var ?array */ 21 | protected $headers; 22 | /** @var ?string */ 23 | protected $response; 24 | /** @var ?int */ 25 | protected $statusCode; 26 | /** @var array */ 27 | protected $responseInfo = array(); 28 | 29 | /** 30 | * @param array $headers 31 | * 32 | * @return void 33 | */ 34 | public function setHeaders($headers) 35 | { 36 | $this->headers = $headers; 37 | } 38 | 39 | /** 40 | * @return ?array 41 | */ 42 | public function getHeaders() 43 | { 44 | return $this->headers; 45 | } 46 | 47 | /** 48 | * @param ?string $response 49 | * 50 | * @return void 51 | */ 52 | public function setResponse($response) 53 | { 54 | $this->response = $response; 55 | } 56 | 57 | /** 58 | * @return ?string 59 | */ 60 | public function getResponse() 61 | { 62 | return $this->response; 63 | } 64 | 65 | /** 66 | * @param ?int $statusCode 67 | * 68 | * @return void 69 | */ 70 | public function setStatusCode($statusCode) 71 | { 72 | $this->statusCode = $statusCode; 73 | } 74 | 75 | /** 76 | * @return ?int 77 | */ 78 | public function getStatusCode() 79 | { 80 | return $this->statusCode; 81 | } 82 | 83 | /** 84 | * @return array 85 | */ 86 | public function getResponseInfo() 87 | { 88 | return $this->responseInfo; 89 | } 90 | 91 | /** 92 | * @param array $responseInfo 93 | * 94 | * @return void 95 | */ 96 | public function setResponseInfo(array $responseInfo) 97 | { 98 | $this->responseInfo = $responseInfo; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Composer/Util/Http/RequestProxy.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util\Http; 14 | 15 | use Composer\Util\Url; 16 | 17 | /** 18 | * @internal 19 | * @author John Stevenson 20 | */ 21 | class RequestProxy 22 | { 23 | /** @var mixed[] */ 24 | private $contextOptions; 25 | /** @var bool */ 26 | private $isSecure; 27 | /** @var string */ 28 | private $formattedUrl; 29 | /** @var string */ 30 | private $url; 31 | 32 | /** 33 | * @param string $url 34 | * @param mixed[] $contextOptions 35 | * @param string $formattedUrl 36 | */ 37 | public function __construct($url, array $contextOptions, $formattedUrl) 38 | { 39 | $this->url = $url; 40 | $this->contextOptions = $contextOptions; 41 | $this->formattedUrl = $formattedUrl; 42 | $this->isSecure = 0 === strpos($url, 'https://'); 43 | } 44 | 45 | /** 46 | * Returns an array of context options 47 | * 48 | * @return mixed[] 49 | */ 50 | public function getContextOptions() 51 | { 52 | return $this->contextOptions; 53 | } 54 | 55 | /** 56 | * Returns the safe proxy url from the last request 57 | * 58 | * @param string|null $format Output format specifier 59 | * @return string Safe proxy, no proxy or empty 60 | */ 61 | public function getFormattedUrl($format = '') 62 | { 63 | $result = ''; 64 | if ($this->formattedUrl) { 65 | $format = $format ?: '%s'; 66 | $result = sprintf($format, $this->formattedUrl); 67 | } 68 | 69 | return $result; 70 | } 71 | 72 | /** 73 | * Returns the proxy url 74 | * 75 | * @return string Proxy url or empty 76 | */ 77 | public function getUrl() 78 | { 79 | return $this->url; 80 | } 81 | 82 | /** 83 | * Returns true if this is a secure-proxy 84 | * 85 | * @return bool False if not secure or there is no proxy 86 | */ 87 | public function isSecure() 88 | { 89 | return $this->isSecure; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Composer/Plugin/PluginEvents.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Plugin; 14 | 15 | /** 16 | * The Plugin Events. 17 | * 18 | * @author Nils Adermann 19 | */ 20 | class PluginEvents 21 | { 22 | /** 23 | * The INIT event occurs after a Composer instance is done being initialized 24 | * 25 | * The event listener method receives a 26 | * Composer\EventDispatcher\Event instance. 27 | * 28 | * @var string 29 | */ 30 | const INIT = 'init'; 31 | 32 | /** 33 | * The COMMAND event occurs as a command begins 34 | * 35 | * The event listener method receives a 36 | * Composer\Plugin\CommandEvent instance. 37 | * 38 | * @var string 39 | */ 40 | const COMMAND = 'command'; 41 | 42 | /** 43 | * The PRE_FILE_DOWNLOAD event occurs before downloading a file 44 | * 45 | * The event listener method receives a 46 | * Composer\Plugin\PreFileDownloadEvent instance. 47 | * 48 | * @var string 49 | */ 50 | const PRE_FILE_DOWNLOAD = 'pre-file-download'; 51 | 52 | /** 53 | * The POST_FILE_DOWNLOAD event occurs after downloading a package dist file 54 | * 55 | * The event listener method receives a 56 | * Composer\Plugin\PostFileDownloadEvent instance. 57 | * 58 | * @var string 59 | */ 60 | const POST_FILE_DOWNLOAD = 'post-file-download'; 61 | 62 | /** 63 | * The PRE_COMMAND_RUN event occurs before a command is executed and lets you modify the input arguments/options 64 | * 65 | * The event listener method receives a 66 | * Composer\Plugin\PreCommandRunEvent instance. 67 | * 68 | * @var string 69 | */ 70 | const PRE_COMMAND_RUN = 'pre-command-run'; 71 | 72 | /** 73 | * The PRE_POOL_CREATE event occurs before the Pool of packages is created, and lets 74 | * you filter the list of packages which is going to enter the Solver 75 | * 76 | * The event listener method receives a 77 | * Composer\Plugin\PrePoolCreateEvent instance. 78 | * 79 | * @var string 80 | */ 81 | const PRE_POOL_CREATE = 'pre-pool-create'; 82 | } 83 | -------------------------------------------------------------------------------- /doc/faqs/how-do-i-install-a-package-to-a-custom-path-for-my-framework.md: -------------------------------------------------------------------------------- 1 | # How do I install a package to a custom path for my framework? 2 | 3 | Each framework may have one or many different required package installation 4 | paths. Composer can be configured to install packages to a folder other than 5 | the default `vendor` folder by using 6 | [composer/installers](https://github.com/composer/installers). 7 | 8 | If you are a **package author** and want your package installed to a custom 9 | directory, require `composer/installers` and set the appropriate `type`. 10 | Specifying the package type, will override the default installer path. 11 | This is common if your package is intended for a specific framework such as 12 | CakePHP, Drupal or WordPress. Here is an example composer.json file for a 13 | WordPress theme: 14 | 15 | ```json 16 | { 17 | "name": "you/themename", 18 | "type": "wordpress-theme", 19 | "require": { 20 | "composer/installers": "~1.0" 21 | } 22 | } 23 | ``` 24 | 25 | Now when your theme is installed with Composer it will be placed into 26 | `wp-content/themes/themename/` folder. Check the 27 | [current supported types](https://github.com/composer/installers#current-supported-package-types) 28 | for your package. 29 | 30 | As a **package consumer** you can set or override the install path for a package 31 | that requires composer/installers by configuring the `installer-paths` extra. A 32 | useful example would be for a Drupal multisite setup where the package should be 33 | installed into your site's subdirectory. Here we are overriding the install path 34 | for a module that uses composer/installers, as well as putting all packages of type 35 | `drupal-theme` into a themes folder: 36 | 37 | ```json 38 | { 39 | "extra": { 40 | "installer-paths": { 41 | "sites/example.com/modules/{$name}": ["vendor/package"], 42 | "sites/example.com/themes/{$name}": ["type:drupal-theme"] 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | Now the package would be installed to your folder location, rather than the default 49 | composer/installers determined location. In addition, `installer-paths` is 50 | order-dependent, which means moving a package by name should come before the installer 51 | path of a `type:*` that matches the same package. 52 | 53 | > **Note:** You cannot use this to change the path of any package. This is only 54 | > applicable to packages that require `composer/installers` and use a custom type 55 | > that it handles. 56 | -------------------------------------------------------------------------------- /src/Composer/Downloader/GzipDownloader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Package\PackageInterface; 16 | use Composer\Util\Platform; 17 | use Composer\Util\ProcessExecutor; 18 | 19 | /** 20 | * GZip archive downloader. 21 | * 22 | * @author Pavel Puchkin 23 | */ 24 | class GzipDownloader extends ArchiveDownloader 25 | { 26 | protected function extract(PackageInterface $package, $file, $path) 27 | { 28 | $filename = pathinfo(parse_url($package->getDistUrl(), PHP_URL_PATH), PATHINFO_FILENAME); 29 | $targetFilepath = $path . DIRECTORY_SEPARATOR . $filename; 30 | 31 | // Try to use gunzip on *nix 32 | if (!Platform::isWindows()) { 33 | $command = 'gzip -cd -- ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath); 34 | 35 | if (0 === $this->process->execute($command, $ignoredOutput)) { 36 | return \React\Promise\resolve(); 37 | } 38 | 39 | if (extension_loaded('zlib')) { 40 | // Fallback to using the PHP extension. 41 | $this->extractUsingExt($file, $targetFilepath); 42 | 43 | return \React\Promise\resolve(); 44 | } 45 | 46 | $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); 47 | throw new \RuntimeException($processError); 48 | } 49 | 50 | // Windows version of PHP has built-in support of gzip functions 51 | $this->extractUsingExt($file, $targetFilepath); 52 | 53 | return \React\Promise\resolve(); 54 | } 55 | 56 | /** 57 | * @param string $file 58 | * @param string $targetFilepath 59 | * 60 | * @return void 61 | */ 62 | private function extractUsingExt($file, $targetFilepath) 63 | { 64 | $archiveFile = gzopen($file, 'rb'); 65 | $targetFile = fopen($targetFilepath, 'wb'); 66 | while ($string = gzread($archiveFile, 4096)) { 67 | fwrite($targetFile, $string, Platform::strlen($string)); 68 | } 69 | gzclose($archiveFile); 70 | fclose($targetFile); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | 7 | Jordi Boggiano 8 | 9 | For the full copyright and license information, please view the LICENSE 10 | file that was distributed with this source code. 11 | EOF; 12 | 13 | $finder = PhpCsFixer\Finder::create() 14 | ->files() 15 | ->in(__DIR__.'/src') 16 | ->in(__DIR__.'/tests') 17 | ->name('*.php') 18 | ->notPath('Fixtures') 19 | ; 20 | 21 | $config = new PhpCsFixer\Config(); 22 | return $config->setRules([ 23 | '@PSR2' => true, 24 | 'array_syntax' => array('syntax' => 'long'), 25 | 'binary_operator_spaces' => true, 26 | 'blank_line_before_statement' => array('statements' => array('declare', 'return')), 27 | 'cast_spaces' => array('space' => 'single'), 28 | 'header_comment' => array('header' => $header), 29 | 'include' => true, 30 | 31 | 'class_attributes_separation' => array('elements' => array('method' => 'one', 'trait_import' => 'none')), 32 | 'no_blank_lines_after_class_opening' => true, 33 | 'no_blank_lines_after_phpdoc' => true, 34 | 'no_empty_statement' => true, 35 | 'no_extra_blank_lines' => true, 36 | 'no_leading_namespace_whitespace' => true, 37 | 'no_trailing_comma_in_singleline_array' => true, 38 | 'no_whitespace_in_blank_line' => true, 39 | 'object_operator_without_whitespace' => true, 40 | //'phpdoc_align' => true, 41 | 'phpdoc_indent' => true, 42 | 'phpdoc_no_access' => true, 43 | 'phpdoc_no_package' => true, 44 | //'phpdoc_order' => true, 45 | 'phpdoc_scalar' => true, 46 | 'phpdoc_trim' => true, 47 | 'phpdoc_types' => true, 48 | 'psr_autoloading' => true, 49 | 'single_blank_line_before_namespace' => true, 50 | 'standardize_not_equals' => true, 51 | 'ternary_operator_spaces' => true, 52 | 'trailing_comma_in_multiline' => ['elements' => ['arrays']], 53 | 'unary_operator_spaces' => true, 54 | 55 | // imports 56 | 'no_unused_imports' => true, 57 | 'fully_qualified_strict_types' => true, 58 | 'single_line_after_imports' => true, 59 | //'global_namespace_import' => ['import_classes' => true], 60 | 'no_leading_import_slash' => true, 61 | 'single_import_per_statement' => true, 62 | ]) 63 | ->setUsingCache(true) 64 | ->setRiskyAllowed(true) 65 | ->setFinder($finder) 66 | ; 67 | -------------------------------------------------------------------------------- /src/Composer/Util/Silencer.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | /** 16 | * Temporarily suppress PHP error reporting, usually warnings and below. 17 | * 18 | * @author Niels Keurentjes 19 | */ 20 | class Silencer 21 | { 22 | /** 23 | * @var int[] Unpop stack 24 | */ 25 | private static $stack = array(); 26 | 27 | /** 28 | * Suppresses given mask or errors. 29 | * 30 | * @param int|null $mask Error levels to suppress, default value NULL indicates all warnings and below. 31 | * @return int The old error reporting level. 32 | */ 33 | public static function suppress($mask = null) 34 | { 35 | if (!isset($mask)) { 36 | $mask = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT; 37 | } 38 | $old = error_reporting(); 39 | self::$stack[] = $old; 40 | error_reporting($old & ~$mask); 41 | 42 | return $old; 43 | } 44 | 45 | /** 46 | * Restores a single state. 47 | * 48 | * @return void 49 | */ 50 | public static function restore() 51 | { 52 | if (!empty(self::$stack)) { 53 | error_reporting(array_pop(self::$stack)); 54 | } 55 | } 56 | 57 | /** 58 | * Calls a specified function while silencing warnings and below. 59 | * 60 | * Future improvement: when PHP requirements are raised add Callable type hint (5.4) and variadic parameters (5.6) 61 | * 62 | * @param callable $callable Function to execute. 63 | * @throws \Exception Any exceptions from the callback are rethrown. 64 | * @return mixed Return value of the callback. 65 | */ 66 | public static function call($callable /*, ...$parameters */) 67 | { 68 | try { 69 | self::suppress(); 70 | $result = call_user_func_array($callable, array_slice(func_get_args(), 1)); 71 | self::restore(); 72 | 73 | return $result; 74 | } catch (\Exception $e) { 75 | // Use a finally block for this when requirements are raised to PHP 5.5 76 | self::restore(); 77 | throw $e; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Composer/Command/ScriptAliasCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Command; 14 | 15 | use Symfony\Component\Console\Input\InputInterface; 16 | use Symfony\Component\Console\Input\InputOption; 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * @author Jordi Boggiano 22 | */ 23 | class ScriptAliasCommand extends BaseCommand 24 | { 25 | /** @var string */ 26 | private $script; 27 | /** @var string */ 28 | private $description; 29 | 30 | /** 31 | * @param string $script 32 | * @param string $description 33 | */ 34 | public function __construct($script, $description) 35 | { 36 | $this->script = $script; 37 | $this->description = empty($description) ? 'Runs the '.$script.' script as defined in composer.json.' : $description; 38 | 39 | parent::__construct(); 40 | } 41 | 42 | /** 43 | * @return void 44 | */ 45 | protected function configure() 46 | { 47 | $this 48 | ->setName($this->script) 49 | ->setDescription($this->description) 50 | ->setDefinition(array( 51 | new InputOption('dev', null, InputOption::VALUE_NONE, 'Sets the dev mode.'), 52 | new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables the dev mode.'), 53 | new InputArgument('args', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, ''), 54 | )) 55 | ->setHelp( 56 | <<run-script command runs scripts defined in composer.json: 58 | 59 | php composer.phar run-script post-update-cmd 60 | 61 | Read more at https://getcomposer.org/doc/03-cli.md#run-script 62 | EOT 63 | ) 64 | ; 65 | } 66 | 67 | /** 68 | * @return int 69 | */ 70 | protected function execute(InputInterface $input, OutputInterface $output) 71 | { 72 | $composer = $this->getComposer(); 73 | 74 | $args = $input->getArguments(); 75 | 76 | return $composer->getEventDispatcher()->dispatchScript($this->script, $input->getOption('dev') || !$input->getOption('no-dev'), $args['args']); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Composer/Installer/InstallerEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Installer; 14 | 15 | use Composer\Composer; 16 | use Composer\DependencyResolver\Transaction; 17 | use Composer\EventDispatcher\Event; 18 | use Composer\IO\IOInterface; 19 | 20 | class InstallerEvent extends Event 21 | { 22 | /** 23 | * @var Composer 24 | */ 25 | private $composer; 26 | 27 | /** 28 | * @var IOInterface 29 | */ 30 | private $io; 31 | 32 | /** 33 | * @var bool 34 | */ 35 | private $devMode; 36 | 37 | /** 38 | * @var bool 39 | */ 40 | private $executeOperations; 41 | 42 | /** 43 | * @var Transaction 44 | */ 45 | private $transaction; 46 | 47 | /** 48 | * Constructor. 49 | * 50 | * @param string $eventName 51 | * @param Composer $composer 52 | * @param IOInterface $io 53 | * @param bool $devMode 54 | * @param bool $executeOperations 55 | * @param Transaction $transaction 56 | */ 57 | public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, $executeOperations, Transaction $transaction) 58 | { 59 | parent::__construct($eventName); 60 | 61 | $this->composer = $composer; 62 | $this->io = $io; 63 | $this->devMode = $devMode; 64 | $this->executeOperations = $executeOperations; 65 | $this->transaction = $transaction; 66 | } 67 | 68 | /** 69 | * @return Composer 70 | */ 71 | public function getComposer() 72 | { 73 | return $this->composer; 74 | } 75 | 76 | /** 77 | * @return IOInterface 78 | */ 79 | public function getIO() 80 | { 81 | return $this->io; 82 | } 83 | 84 | /** 85 | * @return bool 86 | */ 87 | public function isDevMode() 88 | { 89 | return $this->devMode; 90 | } 91 | 92 | /** 93 | * @return bool 94 | */ 95 | public function isExecutingOperations() 96 | { 97 | return $this->executeOperations; 98 | } 99 | 100 | /** 101 | * @return Transaction|null 102 | */ 103 | public function getTransaction() 104 | { 105 | return $this->transaction; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Composer/Command/ClearCacheCommand.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Command; 14 | 15 | use Composer\Cache; 16 | use Composer\Factory; 17 | use Symfony\Component\Console\Input\InputInterface; 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | 20 | /** 21 | * @author David Neilsen 22 | */ 23 | class ClearCacheCommand extends BaseCommand 24 | { 25 | /** 26 | * @return void 27 | */ 28 | protected function configure() 29 | { 30 | $this 31 | ->setName('clear-cache') 32 | ->setAliases(array('clearcache', 'cc')) 33 | ->setDescription('Clears composer\'s internal package cache.') 34 | ->setHelp( 35 | <<clear-cache deletes all cached packages from composer's 37 | cache directory. 38 | 39 | Read more at https://getcomposer.org/doc/03-cli.md#clear-cache-clearcache-cc 40 | EOT 41 | ) 42 | ; 43 | } 44 | 45 | /** 46 | * @return int 47 | */ 48 | protected function execute(InputInterface $input, OutputInterface $output) 49 | { 50 | $config = Factory::createConfig(); 51 | $io = $this->getIO(); 52 | 53 | $cachePaths = array( 54 | 'cache-vcs-dir' => $config->get('cache-vcs-dir'), 55 | 'cache-repo-dir' => $config->get('cache-repo-dir'), 56 | 'cache-files-dir' => $config->get('cache-files-dir'), 57 | 'cache-dir' => $config->get('cache-dir'), 58 | ); 59 | 60 | foreach ($cachePaths as $key => $cachePath) { 61 | $cachePath = realpath($cachePath); 62 | if (!$cachePath) { 63 | $io->writeError("Cache directory does not exist ($key): $cachePath"); 64 | 65 | continue; 66 | } 67 | $cache = new Cache($io, $cachePath); 68 | $cache->setReadOnly($config->get('cache-read-only')); 69 | if (!$cache->isEnabled()) { 70 | $io->writeError("Cache is not enabled ($key): $cachePath"); 71 | 72 | continue; 73 | } 74 | 75 | $io->writeError("Clearing cache ($key): $cachePath"); 76 | $cache->clear(); 77 | } 78 | 79 | $io->writeError('All caches cleared.'); 80 | 81 | return 0; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Composer/Console/GithubActionError.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Console; 14 | 15 | use Composer\IO\IOInterface; 16 | use Composer\Util\Platform; 17 | 18 | final class GithubActionError 19 | { 20 | /** 21 | * @var IOInterface 22 | */ 23 | protected $io; 24 | 25 | public function __construct(IOInterface $io) 26 | { 27 | $this->io = $io; 28 | } 29 | 30 | /** 31 | * @param string $message 32 | * @param null|string $file 33 | * @param null|int $line 34 | * 35 | * @return void 36 | */ 37 | public function emit($message, $file = null, $line = null) 38 | { 39 | if (Platform::getEnv('GITHUB_ACTIONS') && !Platform::getEnv('COMPOSER_TESTS_ARE_RUNNING')) { 40 | $message = $this->escapeData($message); 41 | 42 | if ($file && $line) { 43 | $file = $this->escapeProperty($file); 44 | $this->io->write("::error file=". $file .",line=". $line ."::". $message); 45 | } elseif ($file) { 46 | $file = $this->escapeProperty($file); 47 | $this->io->write("::error file=". $file ."::". $message); 48 | } else { 49 | $this->io->write("::error ::". $message); 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * @param string $data 56 | * @return string 57 | */ 58 | private function escapeData($data) { 59 | // see https://github.com/actions/toolkit/blob/4f7fb6513a355689f69f0849edeb369a4dc81729/packages/core/src/command.ts#L80-L85 60 | $data = str_replace("%", '%25', $data); 61 | $data = str_replace("\r", '%0D', $data); 62 | $data = str_replace("\n", '%0A', $data); 63 | 64 | return $data; 65 | } 66 | 67 | /** 68 | * @param string $property 69 | * @return string 70 | */ 71 | private function escapeProperty($property) { 72 | // see https://github.com/actions/toolkit/blob/4f7fb6513a355689f69f0849edeb369a4dc81729/packages/core/src/command.ts#L87-L94 73 | $property = str_replace("%", '%25', $property); 74 | $property = str_replace("\r", '%0D', $property); 75 | $property = str_replace("\n", '%0A', $property); 76 | $property = str_replace(":", '%3A', $property); 77 | $property = str_replace(",", '%2C', $property); 78 | 79 | return $property; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Composer/Filter/PlatformRequirementFilter/IgnoreListPlatformRequirementFilter.php: -------------------------------------------------------------------------------- 1 | ignoreRegex = BasePackage::packageNamesToRegexp($ignoreAll); 41 | $this->ignoreUpperBoundRegex = BasePackage::packageNamesToRegexp($ignoreUpperBound); 42 | } 43 | 44 | /** 45 | * @param string $req 46 | * @return bool 47 | */ 48 | public function isIgnored($req) 49 | { 50 | if (!PlatformRepository::isPlatformPackage($req)) { 51 | return false; 52 | } 53 | 54 | return Preg::isMatch($this->ignoreRegex, $req); 55 | } 56 | 57 | /** 58 | * @param string $req 59 | * @return ConstraintInterface 60 | */ 61 | public function filterConstraint($req, ConstraintInterface $constraint) 62 | { 63 | if (!PlatformRepository::isPlatformPackage($req)) { 64 | return $constraint; 65 | } 66 | 67 | if (!Preg::isMatch($this->ignoreUpperBoundRegex, $req)) { 68 | return $constraint; 69 | } 70 | 71 | if (Preg::isMatch($this->ignoreRegex, $req)) { 72 | return new MatchAllConstraint; 73 | } 74 | 75 | $intervals = Intervals::get($constraint); 76 | $last = end($intervals['numeric']); 77 | if ($last !== false && (string) $last->getEnd() !== (string) Interval::untilPositiveInfinity()) { 78 | $constraint = new MultiConstraint(array($constraint, new Constraint('>=', $last->getEnd()->getVersion())), false); 79 | } 80 | 81 | return $constraint; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Composer/EventDispatcher/Event.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\EventDispatcher; 14 | 15 | /** 16 | * The base event class 17 | * 18 | * @author Nils Adermann 19 | */ 20 | class Event 21 | { 22 | /** 23 | * @var string This event's name 24 | */ 25 | protected $name; 26 | 27 | /** 28 | * @var string[] Arguments passed by the user, these will be forwarded to CLI script handlers 29 | */ 30 | protected $args; 31 | 32 | /** 33 | * @var mixed[] Flags usable in PHP script handlers 34 | */ 35 | protected $flags; 36 | 37 | /** 38 | * @var bool Whether the event should not be passed to more listeners 39 | */ 40 | private $propagationStopped = false; 41 | 42 | /** 43 | * Constructor. 44 | * 45 | * @param string $name The event name 46 | * @param string[] $args Arguments passed by the user 47 | * @param mixed[] $flags Optional flags to pass data not as argument 48 | */ 49 | public function __construct($name, array $args = array(), array $flags = array()) 50 | { 51 | $this->name = $name; 52 | $this->args = $args; 53 | $this->flags = $flags; 54 | } 55 | 56 | /** 57 | * Returns the event's name. 58 | * 59 | * @return string The event name 60 | */ 61 | public function getName() 62 | { 63 | return $this->name; 64 | } 65 | 66 | /** 67 | * Returns the event's arguments. 68 | * 69 | * @return string[] The event arguments 70 | */ 71 | public function getArguments() 72 | { 73 | return $this->args; 74 | } 75 | 76 | /** 77 | * Returns the event's flags. 78 | * 79 | * @return mixed[] The event flags 80 | */ 81 | public function getFlags() 82 | { 83 | return $this->flags; 84 | } 85 | 86 | /** 87 | * Checks if stopPropagation has been called 88 | * 89 | * @return bool Whether propagation has been stopped 90 | */ 91 | public function isPropagationStopped() 92 | { 93 | return $this->propagationStopped; 94 | } 95 | 96 | /** 97 | * Prevents the event from being passed to further listeners 98 | * 99 | * @return void 100 | */ 101 | public function stopPropagation() 102 | { 103 | $this->propagationStopped = true; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Composer/Util/SyncHelper.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | use Composer\Downloader\DownloaderInterface; 16 | use Composer\Package\PackageInterface; 17 | use React\Promise\PromiseInterface; 18 | 19 | class SyncHelper 20 | { 21 | /** 22 | * Helps you download + install a single package in a synchronous way 23 | * 24 | * This executes all the required steps and waits for promises to complete 25 | * 26 | * @param Loop $loop Loop instance which you can get from $composer->getLoop() 27 | * @param DownloaderInterface $downloader Downloader instance you can get from $composer->getDownloadManager()->getDownloader('zip') for example 28 | * @param string $path the installation path for the package 29 | * @param PackageInterface $package the package to install 30 | * @param PackageInterface|null $prevPackage the previous package if this is an update and not an initial installation 31 | * 32 | * @return void 33 | */ 34 | public static function downloadAndInstallPackageSync(Loop $loop, DownloaderInterface $downloader, $path, PackageInterface $package, PackageInterface $prevPackage = null) 35 | { 36 | $type = $prevPackage ? 'update' : 'install'; 37 | 38 | try { 39 | self::await($loop, $downloader->download($package, $path, $prevPackage)); 40 | 41 | self::await($loop, $downloader->prepare($type, $package, $path, $prevPackage)); 42 | 43 | if ($type === 'update') { 44 | self::await($loop, $downloader->update($package, $prevPackage, $path)); 45 | } else { 46 | self::await($loop, $downloader->install($package, $path)); 47 | } 48 | } catch (\Exception $e) { 49 | self::await($loop, $downloader->cleanup($type, $package, $path, $prevPackage)); 50 | throw $e; 51 | } 52 | 53 | self::await($loop, $downloader->cleanup($type, $package, $path, $prevPackage)); 54 | } 55 | 56 | /** 57 | * Waits for a promise to resolve 58 | * 59 | * @param Loop $loop Loop instance which you can get from $composer->getLoop() 60 | * @param PromiseInterface|null $promise 61 | * 62 | * @return void 63 | */ 64 | public static function await(Loop $loop, PromiseInterface $promise = null) 65 | { 66 | if ($promise) { 67 | $loop->wait(array($promise)); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Composer/Downloader/RarDownloader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Downloader; 14 | 15 | use Composer\Util\IniHelper; 16 | use Composer\Util\Platform; 17 | use Composer\Util\ProcessExecutor; 18 | use Composer\Package\PackageInterface; 19 | use RarArchive; 20 | 21 | /** 22 | * RAR archive downloader. 23 | * 24 | * Based on previous work by Jordi Boggiano ({@see ZipDownloader}). 25 | * 26 | * @author Derrick Nelson 27 | */ 28 | class RarDownloader extends ArchiveDownloader 29 | { 30 | protected function extract(PackageInterface $package, $file, $path) 31 | { 32 | $processError = null; 33 | 34 | // Try to use unrar on *nix 35 | if (!Platform::isWindows()) { 36 | $command = 'unrar x -- ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path); 37 | 38 | if (0 === $this->process->execute($command, $ignoredOutput)) { 39 | return \React\Promise\resolve(); 40 | } 41 | 42 | $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); 43 | } 44 | 45 | if (!class_exists('RarArchive')) { 46 | // php.ini path is added to the error message to help users find the correct file 47 | $iniMessage = IniHelper::getMessage(); 48 | 49 | $error = "Could not decompress the archive, enable the PHP rar extension or install unrar.\n" 50 | . $iniMessage . "\n" . $processError; 51 | 52 | if (!Platform::isWindows()) { 53 | $error = "Could not decompress the archive, enable the PHP rar extension.\n" . $iniMessage; 54 | } 55 | 56 | throw new \RuntimeException($error); 57 | } 58 | 59 | $rarArchive = RarArchive::open($file); 60 | 61 | if (false === $rarArchive) { 62 | throw new \UnexpectedValueException('Could not open RAR archive: ' . $file); 63 | } 64 | 65 | $entries = $rarArchive->getEntries(); 66 | 67 | if (false === $entries) { 68 | throw new \RuntimeException('Could not retrieve RAR archive entries'); 69 | } 70 | 71 | foreach ($entries as $entry) { 72 | if (false === $entry->extract($path)) { 73 | throw new \RuntimeException('Could not extract entry'); 74 | } 75 | } 76 | 77 | $rarArchive->close(); 78 | 79 | return \React\Promise\resolve(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Composer/Repository/WritableArrayRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Repository; 14 | 15 | use Composer\Package\AliasPackage; 16 | use Composer\Installer\InstallationManager; 17 | 18 | /** 19 | * Writable array repository. 20 | * 21 | * @author Jordi Boggiano 22 | */ 23 | class WritableArrayRepository extends ArrayRepository implements WritableRepositoryInterface 24 | { 25 | /** 26 | * @var string[] 27 | */ 28 | protected $devPackageNames = array(); 29 | 30 | /** @var bool|null */ 31 | private $devMode = null; 32 | 33 | /** 34 | * @return bool|null true if dev requirements were installed, false if --no-dev was used, null if yet unknown 35 | */ 36 | public function getDevMode() 37 | { 38 | return $this->devMode; 39 | } 40 | 41 | /** 42 | * @inheritDoc 43 | */ 44 | public function setDevPackageNames(array $devPackageNames) 45 | { 46 | $this->devPackageNames = $devPackageNames; 47 | } 48 | 49 | /** 50 | * @inheritDoc 51 | */ 52 | public function getDevPackageNames() 53 | { 54 | return $this->devPackageNames; 55 | } 56 | 57 | /** 58 | * @inheritDoc 59 | */ 60 | public function write($devMode, InstallationManager $installationManager) 61 | { 62 | $this->devMode = $devMode; 63 | } 64 | 65 | /** 66 | * @inheritDoc 67 | */ 68 | public function reload() 69 | { 70 | $this->devMode = null; 71 | } 72 | 73 | /** 74 | * @inheritDoc 75 | */ 76 | public function getCanonicalPackages() 77 | { 78 | $packages = $this->getPackages(); 79 | 80 | // get at most one package of each name, preferring non-aliased ones 81 | $packagesByName = array(); 82 | foreach ($packages as $package) { 83 | if (!isset($packagesByName[$package->getName()]) || $packagesByName[$package->getName()] instanceof AliasPackage) { 84 | $packagesByName[$package->getName()] = $package; 85 | } 86 | } 87 | 88 | $canonicalPackages = array(); 89 | 90 | // unfold aliased packages 91 | foreach ($packagesByName as $package) { 92 | while ($package instanceof AliasPackage) { 93 | $package = $package->getAliasOf(); 94 | } 95 | 96 | $canonicalPackages[] = $package; 97 | } 98 | 99 | return $canonicalPackages; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Composer/Config/ConfigSourceInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Config; 14 | 15 | /** 16 | * Configuration Source Interface 17 | * 18 | * @author Jordi Boggiano 19 | * @author Beau Simensen 20 | */ 21 | interface ConfigSourceInterface 22 | { 23 | /** 24 | * Add a repository 25 | * 26 | * @param string $name Name 27 | * @param mixed[]|false $config Configuration 28 | * @param bool $append Whether the repo should be appended (true) or prepended (false) 29 | * 30 | * @return void 31 | */ 32 | public function addRepository($name, $config, $append = true); 33 | 34 | /** 35 | * Remove a repository 36 | * 37 | * @param string $name 38 | * 39 | * @return void 40 | */ 41 | public function removeRepository($name); 42 | 43 | /** 44 | * Add a config setting 45 | * 46 | * @param string $name Name 47 | * @param mixed $value Value 48 | * 49 | * @return void 50 | */ 51 | public function addConfigSetting($name, $value); 52 | 53 | /** 54 | * Remove a config setting 55 | * 56 | * @param string $name 57 | * 58 | * @return void 59 | */ 60 | public function removeConfigSetting($name); 61 | 62 | /** 63 | * Add a property 64 | * 65 | * @param string $name Name 66 | * @param string $value Value 67 | * 68 | * @return void 69 | */ 70 | public function addProperty($name, $value); 71 | 72 | /** 73 | * Remove a property 74 | * 75 | * @param string $name 76 | * 77 | * @return void 78 | */ 79 | public function removeProperty($name); 80 | 81 | /** 82 | * Add a package link 83 | * 84 | * @param string $type Type (require, require-dev, provide, suggest, replace, conflict) 85 | * @param string $name Name 86 | * @param string $value Value 87 | * 88 | * @return void 89 | */ 90 | public function addLink($type, $name, $value); 91 | 92 | /** 93 | * Remove a package link 94 | * 95 | * @param string $type Type (require, require-dev, provide, suggest, replace, conflict) 96 | * @param string $name Name 97 | * 98 | * @return void 99 | */ 100 | public function removeLink($type, $name); 101 | 102 | /** 103 | * Gives a user-friendly name to this source (file path or so) 104 | * 105 | * @return string 106 | */ 107 | public function getName(); 108 | } 109 | -------------------------------------------------------------------------------- /src/Composer/Util/ComposerMirror.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | use Composer\Pcre\Preg; 16 | 17 | /** 18 | * Composer mirror utilities 19 | * 20 | * @author Jordi Boggiano 21 | */ 22 | class ComposerMirror 23 | { 24 | /** 25 | * @param string $mirrorUrl 26 | * @param string $packageName 27 | * @param string $version 28 | * @param string|null $reference 29 | * @param string|null $type 30 | * @param string|null $prettyVersion 31 | * 32 | * @return string 33 | */ 34 | public static function processUrl($mirrorUrl, $packageName, $version, $reference, $type, $prettyVersion = null) 35 | { 36 | if ($reference) { 37 | $reference = Preg::isMatch('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference); 38 | } 39 | $version = strpos($version, '/') === false ? $version : md5($version); 40 | 41 | $from = array('%package%', '%version%', '%reference%', '%type%'); 42 | $to = array($packageName, $version, $reference, $type); 43 | if (null !== $prettyVersion) { 44 | $from[] = '%prettyVersion%'; 45 | $to[] = $prettyVersion; 46 | } 47 | 48 | return str_replace($from, $to, $mirrorUrl); 49 | } 50 | 51 | /** 52 | * @param string $mirrorUrl 53 | * @param string $packageName 54 | * @param string $url 55 | * @param string|null $type 56 | * 57 | * @return string 58 | */ 59 | public static function processGitUrl($mirrorUrl, $packageName, $url, $type) 60 | { 61 | if (Preg::isMatch('#^(?:(?:https?|git)://github\.com/|git@github\.com:)([^/]+)/(.+?)(?:\.git)?$#', $url, $match)) { 62 | $url = 'gh-'.$match[1].'/'.$match[2]; 63 | } elseif (Preg::isMatch('#^https://bitbucket\.org/([^/]+)/(.+?)(?:\.git)?/?$#', $url, $match)) { 64 | $url = 'bb-'.$match[1].'/'.$match[2]; 65 | } else { 66 | $url = Preg::replace('{[^a-z0-9_.-]}i', '-', trim($url, '/')); 67 | } 68 | 69 | return str_replace( 70 | array('%package%', '%normalizedUrl%', '%type%'), 71 | array($packageName, $url, $type), 72 | $mirrorUrl 73 | ); 74 | } 75 | 76 | /** 77 | * @param string $mirrorUrl 78 | * @param string $packageName 79 | * @param string $url 80 | * @param string $type 81 | * 82 | * @return string 83 | */ 84 | public static function processHgUrl($mirrorUrl, $packageName, $url, $type) 85 | { 86 | return self::processGitUrl($mirrorUrl, $packageName, $url, $type); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Composer/IO/NullIO.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\IO; 14 | 15 | /** 16 | * IOInterface that is not interactive and never writes the output 17 | * 18 | * @author Christophe Coevoet 19 | */ 20 | class NullIO extends BaseIO 21 | { 22 | /** 23 | * @inheritDoc 24 | */ 25 | public function isInteractive() 26 | { 27 | return false; 28 | } 29 | 30 | /** 31 | * @inheritDoc 32 | */ 33 | public function isVerbose() 34 | { 35 | return false; 36 | } 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public function isVeryVerbose() 42 | { 43 | return false; 44 | } 45 | 46 | /** 47 | * @inheritDoc 48 | */ 49 | public function isDebug() 50 | { 51 | return false; 52 | } 53 | 54 | /** 55 | * @inheritDoc 56 | */ 57 | public function isDecorated() 58 | { 59 | return false; 60 | } 61 | 62 | /** 63 | * @inheritDoc 64 | */ 65 | public function write($messages, $newline = true, $verbosity = self::NORMAL) 66 | { 67 | } 68 | 69 | /** 70 | * @inheritDoc 71 | */ 72 | public function writeError($messages, $newline = true, $verbosity = self::NORMAL) 73 | { 74 | } 75 | 76 | /** 77 | * @inheritDoc 78 | */ 79 | public function overwrite($messages, $newline = true, $size = 80, $verbosity = self::NORMAL) 80 | { 81 | } 82 | 83 | /** 84 | * @inheritDoc 85 | */ 86 | public function overwriteError($messages, $newline = true, $size = 80, $verbosity = self::NORMAL) 87 | { 88 | } 89 | 90 | /** 91 | * @inheritDoc 92 | */ 93 | public function ask($question, $default = null) 94 | { 95 | return $default; 96 | } 97 | 98 | /** 99 | * @inheritDoc 100 | */ 101 | public function askConfirmation($question, $default = true) 102 | { 103 | return $default; 104 | } 105 | 106 | /** 107 | * @inheritDoc 108 | */ 109 | public function askAndValidate($question, $validator, $attempts = null, $default = null) 110 | { 111 | return $default; 112 | } 113 | 114 | /** 115 | * @inheritDoc 116 | */ 117 | public function askAndHideAnswer($question) 118 | { 119 | return null; 120 | } 121 | 122 | /** 123 | * @inheritDoc 124 | */ 125 | public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false) 126 | { 127 | return $default; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /doc/fixtures/repo-composer-with-providers/p/foo/bar$4baabb3303afa3e34a4d3af18fb138e5f3b79029c1f8d9ab5b477ea15776ba0a.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | "foo\/bar": { 4 | "1.0.0": { 5 | "name": "foo\/bar", 6 | "version": "1.0.0", 7 | "version_normalized": "1.0.0.0", 8 | "source": { 9 | "type": "hg", 10 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 11 | "reference": "249dec95a52a" 12 | }, 13 | "time": "2014-10-11 15:42:00", 14 | "type": "library", 15 | "uid": 3 16 | }, 17 | "1.0.1": { 18 | "name": "foo\/bar", 19 | "version": "1.0.1", 20 | "version_normalized": "1.0.1.0", 21 | "source": { 22 | "type": "hg", 23 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 24 | "reference": "21e3328295d4" 25 | }, 26 | "time": "2014-10-11 15:45:56", 27 | "type": "library", 28 | "uid": 4 29 | }, 30 | "1.0.x-dev": { 31 | "name": "foo\/bar", 32 | "version": "1.0.x-dev", 33 | "version_normalized": "1.0.9999999.9999999-dev", 34 | "source": { 35 | "type": "hg", 36 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 37 | "reference": "14dc17c8e860" 38 | }, 39 | "time": "2014-10-11 15:45:59", 40 | "type": "library", 41 | "uid": 5 42 | }, 43 | "1.1.0": { 44 | "name": "foo\/bar", 45 | "version": "1.1.0", 46 | "version_normalized": "1.1.0.0", 47 | "source": { 48 | "type": "hg", 49 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 50 | "reference": "d2fa3e69ad5b" 51 | }, 52 | "require": { 53 | "bar\/baz": "~1.0" 54 | }, 55 | "time": "2014-10-11 15:43:16", 56 | "type": "library", 57 | "uid": 6 58 | }, 59 | "dev-default": { 60 | "name": "foo\/bar", 61 | "version": "dev-default", 62 | "version_normalized": "9999999-dev", 63 | "source": { 64 | "type": "hg", 65 | "url": "http:\/\/some.where\/over\/the\/rainbow\/", 66 | "reference": "8e5a5c224336" 67 | }, 68 | "require": { 69 | "bar\/baz": "~1.0" 70 | }, 71 | "time": "2014-10-11 15:43:18", 72 | "type": "library", 73 | "uid": 7 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /bin/composer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | check(); 21 | unset($xdebug); 22 | 23 | if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '4.0', '>=')) { 24 | echo 'HHVM 4.0 has dropped support for Composer, please use PHP instead. Aborting.'.PHP_EOL; 25 | exit(1); 26 | } 27 | if (!extension_loaded('iconv') && !extension_loaded('mbstring')) { 28 | echo 'The iconv OR mbstring extension is required and both are missing.' 29 | .PHP_EOL.'Install either of them or recompile php without --disable-iconv.' 30 | .PHP_EOL.'Aborting.'.PHP_EOL; 31 | exit(1); 32 | } 33 | 34 | if (function_exists('ini_set')) { 35 | @ini_set('display_errors', '1'); 36 | 37 | // Set user defined memory limit 38 | if ($memoryLimit = getenv('COMPOSER_MEMORY_LIMIT')) { 39 | @ini_set('memory_limit', $memoryLimit); 40 | } else { 41 | $memoryInBytes = function ($value) { 42 | $unit = strtolower(substr($value, -1, 1)); 43 | $value = (int) $value; 44 | switch($unit) { 45 | case 'g': 46 | $value *= 1024; 47 | // no break (cumulative multiplier) 48 | case 'm': 49 | $value *= 1024; 50 | // no break (cumulative multiplier) 51 | case 'k': 52 | $value *= 1024; 53 | } 54 | 55 | return $value; 56 | }; 57 | 58 | $memoryLimit = trim(ini_get('memory_limit')); 59 | // Increase memory_limit if it is lower than 1.5GB 60 | if ($memoryLimit != -1 && $memoryInBytes($memoryLimit) < 1024 * 1024 * 1536) { 61 | @ini_set('memory_limit', '1536M'); 62 | } 63 | unset($memoryInBytes); 64 | } 65 | unset($memoryLimit); 66 | } 67 | 68 | // Workaround PHP bug on Windows where env vars containing Unicode chars are mangled in $_SERVER 69 | // see https://github.com/php/php-src/issues/7896 70 | if (PHP_VERSION_ID >= 70113 && (PHP_VERSION_ID < 80016 || (PHP_VERSION_ID >= 80100 && PHP_VERSION_ID < 80103)) && Platform::isWindows()) { 71 | foreach ($_SERVER as $serverVar => $serverVal) { 72 | if (($serverVal = getenv($serverVar)) !== false) { 73 | $_SERVER[$serverVar] = $serverVal; 74 | } 75 | } 76 | } 77 | 78 | Platform::putEnv('COMPOSER_BINARY', realpath($_SERVER['argv'][0])); 79 | 80 | ErrorHandler::register(); 81 | 82 | // run the command application 83 | $application = new Application(); 84 | $application->run(); 85 | -------------------------------------------------------------------------------- /src/Composer/Platform/Runtime.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Platform; 14 | 15 | class Runtime 16 | { 17 | /** 18 | * @param string $constant 19 | * @param class-string $class 20 | * 21 | * @return bool 22 | */ 23 | public function hasConstant($constant, $class = null) 24 | { 25 | return defined(ltrim($class.'::'.$constant, ':')); 26 | } 27 | 28 | /** 29 | * @param string $constant 30 | * @param class-string $class 31 | * 32 | * @return mixed 33 | */ 34 | public function getConstant($constant, $class = null) 35 | { 36 | return constant(ltrim($class.'::'.$constant, ':')); 37 | } 38 | 39 | /** 40 | * @param string $fn 41 | * 42 | * @return bool 43 | */ 44 | public function hasFunction($fn) 45 | { 46 | return function_exists($fn); 47 | } 48 | 49 | /** 50 | * @param callable $callable 51 | * @param mixed[] $arguments 52 | * 53 | * @return mixed 54 | */ 55 | public function invoke($callable, array $arguments = array()) 56 | { 57 | return call_user_func_array($callable, $arguments); 58 | } 59 | 60 | /** 61 | * @param class-string $class 62 | * 63 | * @return bool 64 | */ 65 | public function hasClass($class) 66 | { 67 | return class_exists($class, false); 68 | } 69 | 70 | /** 71 | * @param class-string $class 72 | * @param mixed[] $arguments 73 | * 74 | * @return object 75 | * @throws \ReflectionException 76 | */ 77 | public function construct($class, array $arguments = array()) 78 | { 79 | if (empty($arguments)) { 80 | return new $class; 81 | } 82 | 83 | $refl = new \ReflectionClass($class); 84 | 85 | return $refl->newInstanceArgs($arguments); 86 | } 87 | 88 | /** @return string[] */ 89 | public function getExtensions() 90 | { 91 | return get_loaded_extensions(); 92 | } 93 | 94 | /** 95 | * @param string $extension 96 | * 97 | * @return string 98 | */ 99 | public function getExtensionVersion($extension) 100 | { 101 | return phpversion($extension); 102 | } 103 | 104 | /** 105 | * @param string $extension 106 | * 107 | * @return string 108 | * @throws \ReflectionException 109 | */ 110 | public function getExtensionInfo($extension) 111 | { 112 | $reflector = new \ReflectionExtension($extension); 113 | 114 | ob_start(); 115 | $reflector->info(); 116 | 117 | return ob_get_clean(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Composer/Question/StrictConfirmationQuestion.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Question; 14 | 15 | use Composer\Pcre\Preg; 16 | use Symfony\Component\Console\Exception\InvalidArgumentException; 17 | use Symfony\Component\Console\Question\Question; 18 | 19 | /** 20 | * Represents a yes/no question 21 | * Enforces strict responses rather than non-standard answers counting as default 22 | * Based on Symfony\Component\Console\Question\ConfirmationQuestion 23 | * 24 | * @author Theo Tonge 25 | */ 26 | class StrictConfirmationQuestion extends Question 27 | { 28 | /** @var non-empty-string */ 29 | private $trueAnswerRegex; 30 | /** @var non-empty-string */ 31 | private $falseAnswerRegex; 32 | 33 | /** 34 | * Constructor.s 35 | * 36 | * @param string $question The question to ask to the user 37 | * @param bool $default The default answer to return, true or false 38 | * @param non-empty-string $trueAnswerRegex A regex to match the "yes" answer 39 | * @param non-empty-string $falseAnswerRegex A regex to match the "no" answer 40 | */ 41 | public function __construct($question, $default = true, $trueAnswerRegex = '/^y(?:es)?$/i', $falseAnswerRegex = '/^no?$/i') 42 | { 43 | parent::__construct($question, (bool) $default); 44 | 45 | $this->trueAnswerRegex = $trueAnswerRegex; 46 | $this->falseAnswerRegex = $falseAnswerRegex; 47 | $this->setNormalizer($this->getDefaultNormalizer()); 48 | $this->setValidator($this->getDefaultValidator()); 49 | } 50 | 51 | /** 52 | * Returns the default answer normalizer. 53 | * 54 | * @return callable 55 | */ 56 | private function getDefaultNormalizer() 57 | { 58 | $default = $this->getDefault(); 59 | $trueRegex = $this->trueAnswerRegex; 60 | $falseRegex = $this->falseAnswerRegex; 61 | 62 | return function ($answer) use ($default, $trueRegex, $falseRegex) { 63 | if (is_bool($answer)) { 64 | return $answer; 65 | } 66 | if (empty($answer) && !empty($default)) { 67 | return $default; 68 | } 69 | 70 | if (Preg::isMatch($trueRegex, $answer)) { 71 | return true; 72 | } 73 | 74 | if (Preg::isMatch($falseRegex, $answer)) { 75 | return false; 76 | } 77 | 78 | return null; 79 | }; 80 | } 81 | 82 | /** 83 | * Returns the default answer validator. 84 | * 85 | * @return callable 86 | */ 87 | private function getDefaultValidator() 88 | { 89 | return function ($answer) { 90 | if (!is_bool($answer)) { 91 | throw new InvalidArgumentException('Please answer yes, y, no, or n.'); 92 | } 93 | 94 | return $answer; 95 | }; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Composer/Util/ErrorHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | use Composer\IO\IOInterface; 16 | use Composer\Pcre\Preg; 17 | 18 | /** 19 | * Convert PHP errors into exceptions 20 | * 21 | * @author Artem Lopata 22 | */ 23 | class ErrorHandler 24 | { 25 | /** @var ?IOInterface */ 26 | private static $io; 27 | 28 | /** 29 | * Error handler 30 | * 31 | * @param int $level Level of the error raised 32 | * @param string $message Error message 33 | * @param string $file Filename that the error was raised in 34 | * @param int $line Line number the error was raised at 35 | * 36 | * @static 37 | * @throws \ErrorException 38 | * @return bool 39 | */ 40 | public static function handle($level, $message, $file, $line) 41 | { 42 | // error code is not included in error_reporting 43 | if (!(error_reporting() & $level)) { 44 | return true; 45 | } 46 | 47 | if (filter_var(ini_get('xdebug.scream'), FILTER_VALIDATE_BOOLEAN)) { 48 | $message .= "\n\nWarning: You have xdebug.scream enabled, the warning above may be". 49 | "\na legitimately suppressed error that you were not supposed to see."; 50 | } 51 | 52 | if ($level !== E_DEPRECATED && $level !== E_USER_DEPRECATED) { 53 | throw new \ErrorException($message, 0, $level, $file, $line); 54 | } 55 | 56 | if (self::$io) { 57 | // ignore symfony/* deprecation warnings 58 | // TODO remove in 2.3 59 | if (Preg::isMatch('{^Return type of Symfony\\\\.*ReturnTypeWillChange}is', $message)) { 60 | return true; 61 | } 62 | if (strpos(strtr($file, '\\', '/'), 'vendor/symfony/') !== false) { 63 | return true; 64 | } 65 | 66 | self::$io->writeError('Deprecation Notice: '.$message.' in '.$file.':'.$line.''); 67 | if (self::$io->isVerbose()) { 68 | self::$io->writeError('Stack trace:'); 69 | self::$io->writeError(array_filter(array_map(function ($a) { 70 | if (isset($a['line'], $a['file'])) { 71 | return ' '.$a['file'].':'.$a['line'].''; 72 | } 73 | 74 | return null; 75 | }, array_slice(debug_backtrace(), 2)))); 76 | } 77 | } 78 | 79 | return true; 80 | } 81 | 82 | /** 83 | * Register error handler. 84 | * 85 | * @param IOInterface|null $io 86 | * 87 | * @return void 88 | */ 89 | public static function register(IOInterface $io = null) 90 | { 91 | set_error_handler(array(__CLASS__, 'handle')); 92 | error_reporting(E_ALL | E_STRICT); 93 | self::$io = $io; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /doc/articles/resolving-merge-conflicts.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | # Resolving merge conflicts 6 | 7 | When working as a team on the same Composer project, you will eventually run into a scenario 8 | where multiple people added, updated or removed something in the `composer.json` and 9 | `composer.lock` files in multiple branches. When those branches are eventually merged 10 | together, you will get merge conflicts. Resolving these merge conflicts is not as straight 11 | forward as on other files, especially not regarding the `composer.lock` file. 12 | 13 | > **Note:** It might not immediately be obvious why text based merging is not possible for 14 | > lock files, so let's imagine the following example where we want to merge two branches; 15 | > 16 | > - Branch 1 has added package A which requires package B. Package B is locked at version `1.0.0`. 17 | > - Branch 2 has added package C which conflicts with all versions below `1.2.0` of package B. 18 | > 19 | > A text based merge would result in package A version `1.0.0`, package B version `1.0.0` 20 | > and package C version `1.0.0`. This is an invalid result, as the conflict of package C 21 | > was not considered and would require an upgrade of package B. 22 | 23 | ## 1. Reapplying changes 24 | 25 | The safest method to merge Composer files is to accept the version from one branch and apply 26 | the changes from the other branch. 27 | 28 | An example where we have two branches: 29 | 30 | 1. Package 'A' has been added 31 | 2. Package 'B' has been removed and package 'C' is added. 32 | 33 | To resolve the conflict when we merge these two branches: 34 | 35 | - We choose the branch that has the most changes, and accept the `composer.json` and `composer.lock` 36 | files from that branch. In this case, we choose the Composer files from branch 2. 37 | - We reapply the changes from the other branch (branch 1). In this case we have to run 38 | `composer require package/A` again. 39 | 40 | ## 2. Validating your merged files 41 | 42 | Before committing, make sure the resulting `composer.json` and `composer.lock` files are valid. 43 | To do this, run the following commands: 44 | 45 | ```sh 46 | php composer.phar validate 47 | php composer.phar install [--dry-run] 48 | ``` 49 | 50 | ## Important considerations 51 | 52 | Keep in mind that whenever merge conflicts occur on the lock file, the information, about the exact version 53 | new packages were locked on for one of the branches, is lost. When package A in branch 1 is constrained 54 | as `^1.2.0` and locked as `1.2.0`, it might get updated when branch 2 is used as baseline and a new 55 | `composer require package/A:^1.2.0` is executed, as that will use the most recent version that the 56 | constraint allows when possible. There might be a version 1.3.0 for that package available by now, which 57 | will now be used instead. 58 | 59 | Choosing the correct [version constraints](../articles/versions.md) and making sure the packages adhere 60 | to [semantic versioning](https://semver.org/) when using 61 | [next significant release operators](versions.md#next-significant-release-operators) should make sure 62 | that merging branches does not break anything by accidentally updating a dependency. 63 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/MultiConflictRule.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | /** 16 | * @author Nils Adermann 17 | * 18 | * MultiConflictRule([A, B, C]) acts as Rule([-A, -B]), Rule([-A, -C]), Rule([-B, -C]) 19 | */ 20 | class MultiConflictRule extends Rule 21 | { 22 | /** @var int[] */ 23 | protected $literals; 24 | 25 | /** 26 | * @param int[] $literals 27 | */ 28 | public function __construct(array $literals, $reason, $reasonData) 29 | { 30 | parent::__construct($reason, $reasonData); 31 | 32 | if (\count($literals) < 3) { 33 | throw new \RuntimeException("multi conflict rule requires at least 3 literals"); 34 | } 35 | 36 | // sort all packages ascending by id 37 | sort($literals); 38 | 39 | $this->literals = $literals; 40 | } 41 | 42 | /** 43 | * @return int[] 44 | */ 45 | public function getLiterals() 46 | { 47 | return $this->literals; 48 | } 49 | 50 | /** 51 | * @inheritDoc 52 | */ 53 | public function getHash() 54 | { 55 | $data = unpack('ihash', md5('c:'.implode(',', $this->literals), true)); 56 | 57 | return $data['hash']; 58 | } 59 | 60 | /** 61 | * Checks if this rule is equal to another one 62 | * 63 | * Ignores whether either of the rules is disabled. 64 | * 65 | * @param Rule $rule The rule to check against 66 | * @return bool Whether the rules are equal 67 | */ 68 | public function equals(Rule $rule) 69 | { 70 | if ($rule instanceof MultiConflictRule) { 71 | return $this->literals === $rule->getLiterals(); 72 | } 73 | 74 | return false; 75 | } 76 | 77 | /** 78 | * @return bool 79 | */ 80 | public function isAssertion() 81 | { 82 | return false; 83 | } 84 | 85 | /** 86 | * @return never 87 | * @throws \RuntimeException 88 | */ 89 | public function disable() 90 | { 91 | throw new \RuntimeException("Disabling multi conflict rules is not possible. Please contact composer at https://github.com/composer/composer to let us debug what lead to this situation."); 92 | } 93 | 94 | /** 95 | * Formats a rule as a string of the format (Literal1|Literal2|...) 96 | * 97 | * @return string 98 | */ 99 | public function __toString() 100 | { 101 | // TODO multi conflict? 102 | $result = $this->isDisabled() ? 'disabled(multi(' : '(multi('; 103 | 104 | foreach ($this->literals as $i => $literal) { 105 | if ($i != 0) { 106 | $result .= '|'; 107 | } 108 | $result .= $literal; 109 | } 110 | 111 | $result .= '))'; 112 | 113 | return $result; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Composer/Package/Archiver/ZipArchiver.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Archiver; 14 | 15 | use ZipArchive; 16 | use Composer\Util\Filesystem; 17 | 18 | /** 19 | * @author Jan Prieser 20 | */ 21 | class ZipArchiver implements ArchiverInterface 22 | { 23 | /** @var array */ 24 | protected static $formats = array( 25 | 'zip' => true, 26 | ); 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public function archive($sources, $target, $format, array $excludes = array(), $ignoreFilters = false) 32 | { 33 | $fs = new Filesystem(); 34 | $sources = $fs->normalizePath($sources); 35 | 36 | $zip = new ZipArchive(); 37 | $res = $zip->open($target, ZipArchive::CREATE); 38 | if ($res === true) { 39 | $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters); 40 | foreach ($files as $file) { 41 | /** @var \SplFileInfo $file */ 42 | $filepath = strtr($file->getPath()."/".$file->getFilename(), '\\', '/'); 43 | $localname = $filepath; 44 | if (strpos($localname, $sources . '/') === 0) { 45 | $localname = substr($localname, strlen($sources . '/')); 46 | } 47 | if ($file->isDir()) { 48 | $zip->addEmptyDir($localname); 49 | } else { 50 | $zip->addFile($filepath, $localname); 51 | } 52 | 53 | /** 54 | * ZipArchive::setExternalAttributesName is available from >= PHP 5.6 55 | * setExternalAttributesName() is only available with libzip 0.11.2 or above 56 | */ 57 | if (PHP_VERSION_ID >= 50600 && method_exists($zip, 'setExternalAttributesName')) { 58 | $perms = fileperms($filepath); 59 | 60 | /** 61 | * Ensure to preserve the permission umasks for the filepath in the archive. 62 | */ 63 | $zip->setExternalAttributesName($localname, ZipArchive::OPSYS_UNIX, $perms << 16); 64 | } 65 | } 66 | if ($zip->close()) { 67 | return $target; 68 | } 69 | } 70 | $message = sprintf( 71 | "Could not create archive '%s' from '%s': %s", 72 | $target, 73 | $sources, 74 | $zip->getStatusString() 75 | ); 76 | throw new \RuntimeException($message); 77 | } 78 | 79 | /** 80 | * @inheritDoc 81 | */ 82 | public function supports($format, $sourceType) 83 | { 84 | return isset(static::$formats[$format]) && $this->compressionAvailable(); 85 | } 86 | 87 | /** 88 | * @return bool 89 | */ 90 | private function compressionAvailable() 91 | { 92 | return class_exists('ZipArchive'); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Composer/Util/PackageSorter.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Util; 14 | 15 | use Composer\Package\PackageInterface; 16 | use Composer\Package\RootPackageInterface; 17 | 18 | class PackageSorter 19 | { 20 | /** 21 | * Sorts packages by dependency weight 22 | * 23 | * Packages of equal weight are sorted alphabetically 24 | * 25 | * @param PackageInterface[] $packages 26 | * @param array $weights Pre-set weights for some packages to give them more (negative number) or less (positive) weight offsets 27 | * @return PackageInterface[] sorted array 28 | */ 29 | public static function sortPackages(array $packages, array $weights = array()) 30 | { 31 | $usageList = array(); 32 | 33 | foreach ($packages as $package) { 34 | $links = $package->getRequires(); 35 | if ($package instanceof RootPackageInterface) { 36 | $links = array_merge($links, $package->getDevRequires()); 37 | } 38 | foreach ($links as $link) { 39 | $target = $link->getTarget(); 40 | $usageList[$target][] = $package->getName(); 41 | } 42 | } 43 | $computing = array(); 44 | $computed = array(); 45 | $computeImportance = function ($name) use (&$computeImportance, &$computing, &$computed, $usageList, $weights) { 46 | // reusing computed importance 47 | if (isset($computed[$name])) { 48 | return $computed[$name]; 49 | } 50 | 51 | // canceling circular dependency 52 | if (isset($computing[$name])) { 53 | return 0; 54 | } 55 | 56 | $computing[$name] = true; 57 | $weight = isset($weights[$name]) ? $weights[$name] : 0; 58 | 59 | if (isset($usageList[$name])) { 60 | foreach ($usageList[$name] as $user) { 61 | $weight -= 1 - $computeImportance($user); 62 | } 63 | } 64 | 65 | unset($computing[$name]); 66 | $computed[$name] = $weight; 67 | 68 | return $weight; 69 | }; 70 | 71 | $weightedPackages = array(); 72 | 73 | foreach ($packages as $index => $package) { 74 | $name = $package->getName(); 75 | $weight = $computeImportance($name); 76 | $weightedPackages[] = array('name' => $name, 'weight' => $weight, 'index' => $index); 77 | } 78 | 79 | usort($weightedPackages, function ($a, $b) { 80 | if ($a['weight'] !== $b['weight']) { 81 | return $a['weight'] - $b['weight']; 82 | } 83 | 84 | return strnatcasecmp($a['name'], $b['name']); 85 | }); 86 | 87 | $sortedPackages = array(); 88 | 89 | foreach ($weightedPackages as $pkg) { 90 | $sortedPackages[] = $packages[$pkg['index']]; 91 | } 92 | 93 | return $sortedPackages; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Operation/UpdateOperation.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver\Operation; 14 | 15 | use Composer\Package\PackageInterface; 16 | use Composer\Package\Version\VersionParser; 17 | 18 | /** 19 | * Solver update operation. 20 | * 21 | * @author Konstantin Kudryashov 22 | */ 23 | class UpdateOperation extends SolverOperation implements OperationInterface 24 | { 25 | const TYPE = 'update'; 26 | 27 | /** 28 | * @var PackageInterface 29 | */ 30 | protected $initialPackage; 31 | 32 | /** 33 | * @var PackageInterface 34 | */ 35 | protected $targetPackage; 36 | 37 | /** 38 | * @param PackageInterface $initial initial package 39 | * @param PackageInterface $target target package (updated) 40 | */ 41 | public function __construct(PackageInterface $initial, PackageInterface $target) 42 | { 43 | $this->initialPackage = $initial; 44 | $this->targetPackage = $target; 45 | } 46 | 47 | /** 48 | * Returns initial package. 49 | * 50 | * @return PackageInterface 51 | */ 52 | public function getInitialPackage() 53 | { 54 | return $this->initialPackage; 55 | } 56 | 57 | /** 58 | * Returns target package. 59 | * 60 | * @return PackageInterface 61 | */ 62 | public function getTargetPackage() 63 | { 64 | return $this->targetPackage; 65 | } 66 | 67 | /** 68 | * @inheritDoc 69 | */ 70 | public function show($lock) 71 | { 72 | return self::format($this->initialPackage, $this->targetPackage, $lock); 73 | } 74 | 75 | /** 76 | * @param bool $lock 77 | * @return string 78 | */ 79 | public static function format(PackageInterface $initialPackage, PackageInterface $targetPackage, $lock = false) 80 | { 81 | $fromVersion = $initialPackage->getFullPrettyVersion(); 82 | $toVersion = $targetPackage->getFullPrettyVersion(); 83 | 84 | if ($fromVersion === $toVersion && $initialPackage->getSourceReference() !== $targetPackage->getSourceReference()) { 85 | $fromVersion = $initialPackage->getFullPrettyVersion(true, PackageInterface::DISPLAY_SOURCE_REF); 86 | $toVersion = $targetPackage->getFullPrettyVersion(true, PackageInterface::DISPLAY_SOURCE_REF); 87 | } elseif ($fromVersion === $toVersion && $initialPackage->getDistReference() !== $targetPackage->getDistReference()) { 88 | $fromVersion = $initialPackage->getFullPrettyVersion(true, PackageInterface::DISPLAY_DIST_REF); 89 | $toVersion = $targetPackage->getFullPrettyVersion(true, PackageInterface::DISPLAY_DIST_REF); 90 | } 91 | 92 | $actionName = VersionParser::isUpgrade($initialPackage->getVersion(), $targetPackage->getVersion()) ? 'Upgrading' : 'Downgrading'; 93 | 94 | return $actionName.' '.$initialPackage->getPrettyName().' ('.$fromVersion.' => '.$toVersion.')'; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Composer/DependencyResolver/Rule2Literals.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\DependencyResolver; 14 | 15 | /** 16 | * @author Nils Adermann 17 | * @phpstan-import-type ReasonData from Rule 18 | */ 19 | class Rule2Literals extends Rule 20 | { 21 | /** @var int */ 22 | protected $literal1; 23 | /** @var int */ 24 | protected $literal2; 25 | 26 | /** 27 | * @param int $literal1 28 | * @param int $literal2 29 | * @param Rule::RULE_* $reason A RULE_* constant 30 | * @param mixed $reasonData 31 | * 32 | * @phpstan-param ReasonData $reasonData 33 | */ 34 | public function __construct($literal1, $literal2, $reason, $reasonData) 35 | { 36 | parent::__construct($reason, $reasonData); 37 | 38 | if ($literal1 < $literal2) { 39 | $this->literal1 = $literal1; 40 | $this->literal2 = $literal2; 41 | } else { 42 | $this->literal1 = $literal2; 43 | $this->literal2 = $literal1; 44 | } 45 | } 46 | 47 | /** @return int[] */ 48 | public function getLiterals() 49 | { 50 | return array($this->literal1, $this->literal2); 51 | } 52 | 53 | /** 54 | * @inheritDoc 55 | */ 56 | public function getHash() 57 | { 58 | return $this->literal1.','.$this->literal2; 59 | } 60 | 61 | /** 62 | * Checks if this rule is equal to another one 63 | * 64 | * Ignores whether either of the rules is disabled. 65 | * 66 | * @param Rule $rule The rule to check against 67 | * @return bool Whether the rules are equal 68 | */ 69 | public function equals(Rule $rule) 70 | { 71 | // specialized fast-case 72 | if ($rule instanceof self) { 73 | if ($this->literal1 !== $rule->literal1) { 74 | return false; 75 | } 76 | 77 | if ($this->literal2 !== $rule->literal2) { 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | $literals = $rule->getLiterals(); 85 | if (2 != \count($literals)) { 86 | return false; 87 | } 88 | 89 | if ($this->literal1 !== $literals[0]) { 90 | return false; 91 | } 92 | 93 | if ($this->literal2 !== $literals[1]) { 94 | return false; 95 | } 96 | 97 | return true; 98 | } 99 | 100 | /** @return false */ 101 | public function isAssertion() 102 | { 103 | return false; 104 | } 105 | 106 | /** 107 | * Formats a rule as a string of the format (Literal1|Literal2|...) 108 | * 109 | * @return string 110 | */ 111 | public function __toString() 112 | { 113 | $result = $this->isDisabled() ? 'disabled(' : '('; 114 | 115 | $result .= $this->literal1 . '|' . $this->literal2 . ')'; 116 | 117 | return $result; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Composer/Installer/PackageEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Installer; 14 | 15 | use Composer\Composer; 16 | use Composer\IO\IOInterface; 17 | use Composer\DependencyResolver\Operation\OperationInterface; 18 | use Composer\Repository\RepositoryInterface; 19 | use Composer\EventDispatcher\Event; 20 | 21 | /** 22 | * The Package Event. 23 | * 24 | * @author Jordi Boggiano 25 | */ 26 | class PackageEvent extends Event 27 | { 28 | /** 29 | * @var Composer 30 | */ 31 | private $composer; 32 | 33 | /** 34 | * @var IOInterface 35 | */ 36 | private $io; 37 | 38 | /** 39 | * @var bool 40 | */ 41 | private $devMode; 42 | 43 | /** 44 | * @var RepositoryInterface 45 | */ 46 | private $localRepo; 47 | 48 | /** 49 | * @var OperationInterface[] 50 | */ 51 | private $operations; 52 | 53 | /** 54 | * @var OperationInterface The operation instance which is being executed 55 | */ 56 | private $operation; 57 | 58 | /** 59 | * Constructor. 60 | * 61 | * @param string $eventName 62 | * @param Composer $composer 63 | * @param IOInterface $io 64 | * @param bool $devMode 65 | * @param RepositoryInterface $localRepo 66 | * @param OperationInterface[] $operations 67 | * @param OperationInterface $operation 68 | */ 69 | public function __construct($eventName, Composer $composer, IOInterface $io, $devMode, RepositoryInterface $localRepo, array $operations, OperationInterface $operation) 70 | { 71 | parent::__construct($eventName); 72 | 73 | $this->composer = $composer; 74 | $this->io = $io; 75 | $this->devMode = $devMode; 76 | $this->localRepo = $localRepo; 77 | $this->operations = $operations; 78 | $this->operation = $operation; 79 | } 80 | 81 | /** 82 | * @return Composer 83 | */ 84 | public function getComposer() 85 | { 86 | return $this->composer; 87 | } 88 | 89 | /** 90 | * @return IOInterface 91 | */ 92 | public function getIO() 93 | { 94 | return $this->io; 95 | } 96 | 97 | /** 98 | * @return bool 99 | */ 100 | public function isDevMode() 101 | { 102 | return $this->devMode; 103 | } 104 | 105 | /** 106 | * @return RepositoryInterface 107 | */ 108 | public function getLocalRepo() 109 | { 110 | return $this->localRepo; 111 | } 112 | 113 | /** 114 | * @return OperationInterface[] 115 | */ 116 | public function getOperations() 117 | { 118 | return $this->operations; 119 | } 120 | 121 | /** 122 | * Returns the package instance. 123 | * 124 | * @return OperationInterface 125 | */ 126 | public function getOperation() 127 | { 128 | return $this->operation; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Composer/Installer/NoopInstaller.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Installer; 14 | 15 | use Composer\Repository\InstalledRepositoryInterface; 16 | use Composer\Package\PackageInterface; 17 | 18 | /** 19 | * Does not install anything but marks packages installed in the repo 20 | * 21 | * Useful for dry runs 22 | * 23 | * @author Jordi Boggiano 24 | */ 25 | class NoopInstaller implements InstallerInterface 26 | { 27 | /** 28 | * @inheritDoc 29 | */ 30 | public function supports($packageType) 31 | { 32 | return true; 33 | } 34 | 35 | /** 36 | * @inheritDoc 37 | */ 38 | public function isInstalled(InstalledRepositoryInterface $repo, PackageInterface $package) 39 | { 40 | return $repo->hasPackage($package); 41 | } 42 | 43 | /** 44 | * @inheritDoc 45 | */ 46 | public function download(PackageInterface $package, PackageInterface $prevPackage = null) 47 | { 48 | return \React\Promise\resolve(); 49 | } 50 | 51 | /** 52 | * @inheritDoc 53 | */ 54 | public function prepare($type, PackageInterface $package, PackageInterface $prevPackage = null) 55 | { 56 | return \React\Promise\resolve(); 57 | } 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public function cleanup($type, PackageInterface $package, PackageInterface $prevPackage = null) 63 | { 64 | return \React\Promise\resolve(); 65 | } 66 | 67 | /** 68 | * @inheritDoc 69 | */ 70 | public function install(InstalledRepositoryInterface $repo, PackageInterface $package) 71 | { 72 | if (!$repo->hasPackage($package)) { 73 | $repo->addPackage(clone $package); 74 | } 75 | 76 | return \React\Promise\resolve(); 77 | } 78 | 79 | /** 80 | * @inheritDoc 81 | */ 82 | public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) 83 | { 84 | if (!$repo->hasPackage($initial)) { 85 | throw new \InvalidArgumentException('Package is not installed: '.$initial); 86 | } 87 | 88 | $repo->removePackage($initial); 89 | if (!$repo->hasPackage($target)) { 90 | $repo->addPackage(clone $target); 91 | } 92 | 93 | return \React\Promise\resolve(); 94 | } 95 | 96 | /** 97 | * @inheritDoc 98 | */ 99 | public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) 100 | { 101 | if (!$repo->hasPackage($package)) { 102 | throw new \InvalidArgumentException('Package is not installed: '.$package); 103 | } 104 | $repo->removePackage($package); 105 | 106 | return \React\Promise\resolve(); 107 | } 108 | 109 | /** 110 | * @inheritDoc 111 | */ 112 | public function getInstallPath(PackageInterface $package) 113 | { 114 | $targetDir = $package->getTargetDir(); 115 | 116 | return $package->getPrettyName() . ($targetDir ? '/'.$targetDir : ''); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Composer/Package/RootPackage.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package; 14 | 15 | /** 16 | * The root package represents the project's composer.json and contains additional metadata 17 | * 18 | * @author Jordi Boggiano 19 | */ 20 | class RootPackage extends CompletePackage implements RootPackageInterface 21 | { 22 | const DEFAULT_PRETTY_VERSION = '1.0.0+no-version-set'; 23 | 24 | /** @var string */ 25 | protected $minimumStability = 'stable'; 26 | /** @var bool */ 27 | protected $preferStable = false; 28 | /** @var array Map of package name to stability constant */ 29 | protected $stabilityFlags = array(); 30 | /** @var mixed[] */ 31 | protected $config = array(); 32 | /** @var array Map of package name to reference/commit hash */ 33 | protected $references = array(); 34 | /** @var array */ 35 | protected $aliases = array(); 36 | 37 | /** 38 | * {@inerhitDoc} 39 | */ 40 | public function setMinimumStability($minimumStability) 41 | { 42 | $this->minimumStability = $minimumStability; 43 | } 44 | 45 | /** 46 | * @inheritDoc 47 | */ 48 | public function getMinimumStability() 49 | { 50 | return $this->minimumStability; 51 | } 52 | 53 | /** 54 | * @inheritDoc 55 | */ 56 | public function setStabilityFlags(array $stabilityFlags) 57 | { 58 | $this->stabilityFlags = $stabilityFlags; 59 | } 60 | 61 | /** 62 | * @inheritDoc 63 | */ 64 | public function getStabilityFlags() 65 | { 66 | return $this->stabilityFlags; 67 | } 68 | 69 | /** 70 | * {@inerhitDoc} 71 | */ 72 | public function setPreferStable($preferStable) 73 | { 74 | $this->preferStable = $preferStable; 75 | } 76 | 77 | /** 78 | * @inheritDoc 79 | */ 80 | public function getPreferStable() 81 | { 82 | return $this->preferStable; 83 | } 84 | 85 | /** 86 | * {@inerhitDoc} 87 | */ 88 | public function setConfig(array $config) 89 | { 90 | $this->config = $config; 91 | } 92 | 93 | /** 94 | * @inheritDoc 95 | */ 96 | public function getConfig() 97 | { 98 | return $this->config; 99 | } 100 | 101 | /** 102 | * {@inerhitDoc} 103 | */ 104 | public function setReferences(array $references) 105 | { 106 | $this->references = $references; 107 | } 108 | 109 | /** 110 | * @inheritDoc 111 | */ 112 | public function getReferences() 113 | { 114 | return $this->references; 115 | } 116 | 117 | /** 118 | * {@inerhitDoc} 119 | */ 120 | public function setAliases(array $aliases) 121 | { 122 | $this->aliases = $aliases; 123 | } 124 | 125 | /** 126 | * @inheritDoc 127 | */ 128 | public function getAliases() 129 | { 130 | return $this->aliases; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Composer/Package/Archiver/ArchivableFilesFinder.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Package\Archiver; 14 | 15 | use Composer\Pcre\Preg; 16 | use Composer\Util\Filesystem; 17 | use FilesystemIterator; 18 | use Symfony\Component\Finder\Finder; 19 | use Symfony\Component\Finder\SplFileInfo; 20 | 21 | /** 22 | * A Symfony Finder wrapper which locates files that should go into archives 23 | * 24 | * Handles .gitignore, .gitattributes and .hgignore files as well as composer's 25 | * own exclude rules from composer.json 26 | * 27 | * @author Nils Adermann 28 | */ 29 | class ArchivableFilesFinder extends \FilterIterator 30 | { 31 | /** 32 | * @var Finder 33 | */ 34 | protected $finder; 35 | 36 | /** 37 | * Initializes the internal Symfony Finder with appropriate filters 38 | * 39 | * @param string $sources Path to source files to be archived 40 | * @param string[] $excludes Composer's own exclude rules from composer.json 41 | * @param bool $ignoreFilters Ignore filters when looking for files 42 | */ 43 | public function __construct($sources, array $excludes, $ignoreFilters = false) 44 | { 45 | $fs = new Filesystem(); 46 | 47 | $sources = $fs->normalizePath(realpath($sources)); 48 | 49 | if ($ignoreFilters) { 50 | $filters = array(); 51 | } else { 52 | $filters = array( 53 | new GitExcludeFilter($sources), 54 | new ComposerExcludeFilter($sources, $excludes), 55 | ); 56 | } 57 | 58 | $this->finder = new Finder(); 59 | 60 | $filter = function (\SplFileInfo $file) use ($sources, $filters, $fs) { 61 | if ($file->isLink() && strpos($file->getRealPath(), $sources) !== 0) { 62 | return false; 63 | } 64 | 65 | $relativePath = Preg::replace( 66 | '#^'.preg_quote($sources, '#').'#', 67 | '', 68 | $fs->normalizePath($file->getRealPath()) 69 | ); 70 | 71 | $exclude = false; 72 | foreach ($filters as $filter) { 73 | $exclude = $filter->filter($relativePath, $exclude); 74 | } 75 | 76 | return !$exclude; 77 | }; 78 | 79 | if (method_exists($filter, 'bindTo')) { 80 | $filter = $filter->bindTo(null); 81 | } 82 | 83 | $this->finder 84 | ->in($sources) 85 | ->filter($filter) 86 | ->ignoreVCS(true) 87 | ->ignoreDotFiles(false) 88 | ->sortByName(); 89 | 90 | parent::__construct($this->finder->getIterator()); 91 | } 92 | 93 | #[\ReturnTypeWillChange] 94 | public function accept() 95 | { 96 | /** @var SplFileInfo $current */ 97 | $current = $this->getInnerIterator()->current(); 98 | 99 | if (!$current->isDir()) { 100 | return true; 101 | } 102 | 103 | $iterator = new FilesystemIterator($current, FilesystemIterator::SKIP_DOTS); 104 | 105 | return !$iterator->valid(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Composer/IO/BufferIO.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\IO; 14 | 15 | use Composer\Pcre\Preg; 16 | use Symfony\Component\Console\Helper\QuestionHelper; 17 | use Symfony\Component\Console\Output\StreamOutput; 18 | use Symfony\Component\Console\Formatter\OutputFormatterInterface; 19 | use Symfony\Component\Console\Input\StreamableInputInterface; 20 | use Symfony\Component\Console\Input\StringInput; 21 | use Symfony\Component\Console\Helper\HelperSet; 22 | 23 | /** 24 | * @author Jordi Boggiano 25 | */ 26 | class BufferIO extends ConsoleIO 27 | { 28 | /** @var StringInput */ 29 | protected $input; 30 | /** @var StreamOutput */ 31 | protected $output; 32 | 33 | /** 34 | * @param string $input 35 | * @param int $verbosity 36 | * @param OutputFormatterInterface|null $formatter 37 | */ 38 | public function __construct($input = '', $verbosity = StreamOutput::VERBOSITY_NORMAL, OutputFormatterInterface $formatter = null) 39 | { 40 | $input = new StringInput($input); 41 | $input->setInteractive(false); 42 | 43 | $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity, $formatter ? $formatter->isDecorated() : false, $formatter); 44 | 45 | parent::__construct($input, $output, new HelperSet(array( 46 | new QuestionHelper(), 47 | ))); 48 | } 49 | 50 | /** 51 | * @return string output 52 | */ 53 | public function getOutput() 54 | { 55 | fseek($this->output->getStream(), 0); 56 | 57 | $output = stream_get_contents($this->output->getStream()); 58 | 59 | $output = Preg::replaceCallback("{(?<=^|\n|\x08)(.+?)(\x08+)}", function ($matches) { 60 | $pre = strip_tags($matches[1]); 61 | 62 | if (strlen($pre) === strlen($matches[2])) { 63 | return ''; 64 | } 65 | 66 | // TODO reverse parse the string, skipping span tags and \033\[([0-9;]+)m(.*?)\033\[0m style blobs 67 | return rtrim($matches[1])."\n"; 68 | }, $output); 69 | 70 | return $output; 71 | } 72 | 73 | /** 74 | * @param string[] $inputs 75 | * 76 | * @see createStream 77 | * 78 | * @return void 79 | */ 80 | public function setUserInputs(array $inputs) 81 | { 82 | if (!$this->input instanceof StreamableInputInterface) { 83 | throw new \RuntimeException('Setting the user inputs requires at least the version 3.2 of the symfony/console component.'); 84 | } 85 | 86 | $this->input->setStream($this->createStream($inputs)); 87 | $this->input->setInteractive(true); 88 | } 89 | 90 | /** 91 | * @param string[] $inputs 92 | * 93 | * @return false|resource stream 94 | */ 95 | private function createStream(array $inputs) 96 | { 97 | $stream = fopen('php://memory', 'r+'); 98 | 99 | foreach ($inputs as $input) { 100 | fwrite($stream, $input.PHP_EOL); 101 | } 102 | 103 | rewind($stream); 104 | 105 | return $stream; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Composer/Platform/Version.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Platform; 14 | 15 | use Composer\Pcre\Preg; 16 | 17 | /** 18 | * @author Lars Strojny 19 | */ 20 | class Version 21 | { 22 | /** 23 | * @param string $opensslVersion 24 | * @param bool $isFips 25 | * @return string|null 26 | */ 27 | public static function parseOpenssl($opensslVersion, &$isFips) 28 | { 29 | $isFips = false; 30 | 31 | if (!Preg::isMatch('/^(?[0-9.]+)(?[a-z]{0,2})?(?(?:-?(?:dev|pre|alpha|beta|rc|fips)[\d]*)*)?(?-\w+)?$/', $opensslVersion, $matches)) { 32 | return null; 33 | } 34 | 35 | $isFips = strpos($matches['suffix'], 'fips') !== false; 36 | $suffix = strtr('-'.ltrim($matches['suffix'], '-'), array('-fips' => '', '-pre' => '-alpha')); 37 | $patch = self::convertAlphaVersionToIntVersion($matches['patch']); 38 | 39 | return rtrim($matches['version'].'.'.$patch.$suffix, '-'); 40 | } 41 | 42 | /** 43 | * @param string $libjpegVersion 44 | * @return string|null 45 | */ 46 | public static function parseLibjpeg($libjpegVersion) 47 | { 48 | if (!Preg::isMatch('/^(?\d+)(?[a-z]*)$/', $libjpegVersion, $matches)) { 49 | return null; 50 | } 51 | 52 | return $matches['major'].'.'.self::convertAlphaVersionToIntVersion($matches['minor']); 53 | } 54 | 55 | /** 56 | * @param string $zoneinfoVersion 57 | * @return string|null 58 | */ 59 | public static function parseZoneinfoVersion($zoneinfoVersion) 60 | { 61 | if (!Preg::isMatch('/^(?\d{4})(?[a-z]*)$/', $zoneinfoVersion, $matches)) { 62 | return null; 63 | } 64 | 65 | return $matches['year'].'.'.self::convertAlphaVersionToIntVersion($matches['revision']); 66 | } 67 | 68 | /** 69 | * "" => 0, "a" => 1, "zg" => 33 70 | * 71 | * @param string $alpha 72 | * @return int 73 | */ 74 | private static function convertAlphaVersionToIntVersion($alpha) 75 | { 76 | return strlen($alpha) * (-ord('a') + 1) + array_sum(array_map('ord', str_split($alpha))); 77 | } 78 | 79 | /** 80 | * @param int $versionId 81 | * @return string 82 | */ 83 | public static function convertLibxpmVersionId($versionId) 84 | { 85 | return self::convertVersionId($versionId, 100); 86 | } 87 | 88 | /** 89 | * @param int $versionId 90 | * @return string 91 | */ 92 | public static function convertOpenldapVersionId($versionId) 93 | { 94 | return self::convertVersionId($versionId, 100); 95 | } 96 | 97 | /** 98 | * @param int $versionId 99 | * @param int $base 100 | * 101 | * @return string 102 | */ 103 | private static function convertVersionId($versionId, $base) 104 | { 105 | return sprintf( 106 | '%d.%d.%d', 107 | $versionId / ($base * $base), 108 | (int) ($versionId / $base) % $base, 109 | $versionId % $base 110 | ); 111 | } 112 | } 113 | --------------------------------------------------------------------------------