Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

InstalledVersions.php 15 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer;
  12. use Composer\Autoload\ClassLoader;
  13. use Composer\Semver\VersionParser;
  14. /**
  15. * This class is copied in every Composer installed project and available to all
  16. *
  17. * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
  18. *
  19. * To require its presence, you can require `composer-runtime-api ^2.0`
  20. */
  21. class InstalledVersions
  22. {
  23. /**
  24. * @var mixed[]|null
  25. * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
  26. */
  27. private static $installed;
  28. /**
  29. * @var bool|null
  30. */
  31. private static $canGetVendors;
  32. /**
  33. * @var array[]
  34. * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
  35. */
  36. private static $installedByVendor = array();
  37. /**
  38. * Returns a list of all package names which are present, either by being installed, replaced or provided
  39. *
  40. * @return string[]
  41. * @psalm-return list<string>
  42. */
  43. public static function getInstalledPackages()
  44. {
  45. $packages = array();
  46. foreach (self::getInstalled() as $installed) {
  47. $packages[] = array_keys($installed['versions']);
  48. }
  49. if (1 === \count($packages)) {
  50. return $packages[0];
  51. }
  52. return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
  53. }
  54. /**
  55. * Returns a list of all package names with a specific type e.g. 'library'
  56. *
  57. * @param string $type
  58. * @return string[]
  59. * @psalm-return list<string>
  60. */
  61. public static function getInstalledPackagesByType($type)
  62. {
  63. $packagesByType = array();
  64. foreach (self::getInstalled() as $installed) {
  65. foreach ($installed['versions'] as $name => $package) {
  66. if (isset($package['type']) && $package['type'] === $type) {
  67. $packagesByType[] = $name;
  68. }
  69. }
  70. }
  71. return $packagesByType;
  72. }
  73. /**
  74. * Checks whether the given package is installed
  75. *
  76. * This also returns true if the package name is provided or replaced by another package
  77. *
  78. * @param string $packageName
  79. * @param bool $includeDevRequirements
  80. * @return bool
  81. */
  82. public static function isInstalled($packageName, $includeDevRequirements = true)
  83. {
  84. foreach (self::getInstalled() as $installed) {
  85. if (isset($installed['versions'][$packageName])) {
  86. return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
  87. }
  88. }
  89. return false;
  90. }
  91. /**
  92. * Checks whether the given package satisfies a version constraint
  93. *
  94. * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
  95. *
  96. * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
  97. *
  98. * @param VersionParser $parser Install composer/semver to have access to this class and functionality
  99. * @param string $packageName
  100. * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
  101. * @return bool
  102. */
  103. public static function satisfies(VersionParser $parser, $packageName, $constraint)
  104. {
  105. $constraint = $parser->parseConstraints($constraint);
  106. $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
  107. return $provided->matches($constraint);
  108. }
  109. /**
  110. * Returns a version constraint representing all the range(s) which are installed for a given package
  111. *
  112. * It is easier to use this via isInstalled() with the $constraint argument if you need to check
  113. * whether a given version of a package is installed, and not just whether it exists
  114. *
  115. * @param string $packageName
  116. * @return string Version constraint usable with composer/semver
  117. */
  118. public static function getVersionRanges($packageName)
  119. {
  120. foreach (self::getInstalled() as $installed) {
  121. if (!isset($installed['versions'][$packageName])) {
  122. continue;
  123. }
  124. $ranges = array();
  125. if (isset($installed['versions'][$packageName]['pretty_version'])) {
  126. $ranges[] = $installed['versions'][$packageName]['pretty_version'];
  127. }
  128. if (array_key_exists('aliases', $installed['versions'][$packageName])) {
  129. $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
  130. }
  131. if (array_key_exists('replaced', $installed['versions'][$packageName])) {
  132. $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
  133. }
  134. if (array_key_exists('provided', $installed['versions'][$packageName])) {
  135. $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
  136. }
  137. return implode(' || ', $ranges);
  138. }
  139. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  140. }
  141. /**
  142. * @param string $packageName
  143. * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
  144. */
  145. public static function getVersion($packageName)
  146. {
  147. foreach (self::getInstalled() as $installed) {
  148. if (!isset($installed['versions'][$packageName])) {
  149. continue;
  150. }
  151. if (!isset($installed['versions'][$packageName]['version'])) {
  152. return null;
  153. }
  154. return $installed['versions'][$packageName]['version'];
  155. }
  156. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  157. }
  158. /**
  159. * @param string $packageName
  160. * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
  161. */
  162. public static function getPrettyVersion($packageName)
  163. {
  164. foreach (self::getInstalled() as $installed) {
  165. if (!isset($installed['versions'][$packageName])) {
  166. continue;
  167. }
  168. if (!isset($installed['versions'][$packageName]['pretty_version'])) {
  169. return null;
  170. }
  171. return $installed['versions'][$packageName]['pretty_version'];
  172. }
  173. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  174. }
  175. /**
  176. * @param string $packageName
  177. * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
  178. */
  179. public static function getReference($packageName)
  180. {
  181. foreach (self::getInstalled() as $installed) {
  182. if (!isset($installed['versions'][$packageName])) {
  183. continue;
  184. }
  185. if (!isset($installed['versions'][$packageName]['reference'])) {
  186. return null;
  187. }
  188. return $installed['versions'][$packageName]['reference'];
  189. }
  190. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  191. }
  192. /**
  193. * @param string $packageName
  194. * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
  195. */
  196. public static function getInstallPath($packageName)
  197. {
  198. foreach (self::getInstalled() as $installed) {
  199. if (!isset($installed['versions'][$packageName])) {
  200. continue;
  201. }
  202. return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
  203. }
  204. throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
  205. }
  206. /**
  207. * @return array
  208. * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
  209. */
  210. public static function getRootPackage()
  211. {
  212. $installed = self::getInstalled();
  213. return $installed[0]['root'];
  214. }
  215. /**
  216. * Returns the raw installed.php data for custom implementations
  217. *
  218. * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
  219. * @return array[]
  220. * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
  221. */
  222. public static function getRawData()
  223. {
  224. @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
  225. if (null === self::$installed) {
  226. // only require the installed.php file if this file is loaded from its dumped location,
  227. // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
  228. if (substr(__DIR__, -8, 1) !== 'C') {
  229. self::$installed = include __DIR__ . '/installed.php';
  230. } else {
  231. self::$installed = array();
  232. }
  233. }
  234. return self::$installed;
  235. }
  236. /**
  237. * Returns the raw data of all installed.php which are currently loaded for custom implementations
  238. *
  239. * @return array[]
  240. * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
  241. */
  242. public static function getAllRawData()
  243. {
  244. return self::getInstalled();
  245. }
  246. /**
  247. * Lets you reload the static array from another file
  248. *
  249. * This is only useful for complex integrations in which a project needs to use
  250. * this class but then also needs to execute another project's autoloader in process,
  251. * and wants to ensure both projects have access to their version of installed.php.
  252. *
  253. * A typical case would be PHPUnit, where it would need to make sure it reads all
  254. * the data it needs from this class, then call reload() with
  255. * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
  256. * the project in which it runs can then also use this class safely, without
  257. * interference between PHPUnit's dependencies and the project's dependencies.
  258. *
  259. * @param array[] $data A vendor/composer/installed.php data set
  260. * @return void
  261. *
  262. * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
  263. */
  264. public static function reload($data)
  265. {
  266. self::$installed = $data;
  267. self::$installedByVendor = array();
  268. }
  269. /**
  270. * @return array[]
  271. * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
  272. */
  273. private static function getInstalled()
  274. {
  275. if (null === self::$canGetVendors) {
  276. self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
  277. }
  278. $installed = array();
  279. if (self::$canGetVendors) {
  280. foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
  281. if (isset(self::$installedByVendor[$vendorDir])) {
  282. $installed[] = self::$installedByVendor[$vendorDir];
  283. } elseif (is_file($vendorDir.'/composer/installed.php')) {
  284. $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
  285. if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
  286. self::$installed = $installed[count($installed) - 1];
  287. }
  288. }
  289. }
  290. }
  291. if (null === self::$installed) {
  292. // only require the installed.php file if this file is loaded from its dumped location,
  293. // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
  294. if (substr(__DIR__, -8, 1) !== 'C') {
  295. self::$installed = require __DIR__ . '/installed.php';
  296. } else {
  297. self::$installed = array();
  298. }
  299. }
  300. $installed[] = self::$installed;
  301. return $installed;
  302. }
  303. }