VersionParser.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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\Package\Version;
  12. use Composer\Package\LinkConstraint\MultiConstraint;
  13. use Composer\Package\LinkConstraint\VersionConstraint;
  14. /**
  15. * Version parser
  16. *
  17. * @author Jordi Boggiano <j.boggiano@seld.be>
  18. */
  19. class VersionParser
  20. {
  21. private $modifierRegex = '[.-]?(?:(beta|RC|alpha|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?';
  22. /**
  23. * Normalizes a version string to be able to perform comparisons on it
  24. *
  25. * @param string $version
  26. * @return array
  27. */
  28. public function normalize($version)
  29. {
  30. $version = trim($version);
  31. // match classical versioning
  32. if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?'.$this->modifierRegex.'$}i', $version, $matches)) {
  33. $version = $matches[1]
  34. .(!empty($matches[2]) ? $matches[2] : '.0')
  35. .(!empty($matches[3]) ? $matches[3] : '.0')
  36. .(!empty($matches[4]) ? $matches[4] : '.0');
  37. $index = 5;
  38. } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)'.$this->modifierRegex.'$}i', $version, $matches)) { // match date-based versioning
  39. $version = preg_replace('{\D}', '-', $matches[1]);
  40. $index = 2;
  41. }
  42. // add version modifiers if a version was matched
  43. if (isset($index)) {
  44. if (!empty($matches[$index])) {
  45. $mod = array('{^pl?$}', '{^rc$}');
  46. $modNormalized = array('patch', 'RC');
  47. $version .= '-'.preg_replace($mod, $modNormalized, strtolower($matches[$index]))
  48. . (!empty($matches[$index+1]) ? $matches[$index+1] : '');
  49. }
  50. if (!empty($matches[$index+2])) {
  51. $version .= '-dev';
  52. }
  53. return $version;
  54. }
  55. throw new \UnexpectedValueException('Invalid version string '.$version);
  56. }
  57. /**
  58. * Parses as constraint string into LinkConstraint objects
  59. *
  60. * @param string $constraints
  61. * @return \Composer\Package\LinkConstraint\LinkConstraintInterface
  62. */
  63. public function parseConstraints($constraints)
  64. {
  65. $constraints = preg_split('{\s*,\s*}', trim($constraints));
  66. if (count($constraints) > 1) {
  67. $constraintObjects = array();
  68. foreach ($constraints as $key => $constraint) {
  69. $constraintObjects = array_merge($constraintObjects, $this->parseConstraint($constraint));
  70. }
  71. } else {
  72. $constraintObjects = $this->parseConstraint($constraints[0]);
  73. }
  74. if (1 === count($constraintObjects)) {
  75. return $constraintObjects[0];
  76. }
  77. return new MultiConstraint($constraintObjects);
  78. }
  79. private function parseConstraint($constraint)
  80. {
  81. if ('*' === $constraint || '*.*' === $constraint || '*.*.*' === $constraint) {
  82. return array();
  83. }
  84. // match wildcard constraints
  85. if (preg_match('{^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.\*$}', $constraint, $matches)) {
  86. if (isset($matches[3])) {
  87. $lowVersion = $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.0';
  88. $highVersion = $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.9999999';
  89. } elseif (isset($matches[2])) {
  90. $lowVersion = $matches[1] . '.' . $matches[2] . '.0.0';
  91. $highVersion = $matches[1] . '.' . $matches[2] . '.9999999.9999999';
  92. } else {
  93. $lowVersion = $matches[1] . '.0.0.0';
  94. $highVersion = $matches[1] . '.9999999.9999999.9999999';
  95. }
  96. return array(
  97. new VersionConstraint('>=', $lowVersion),
  98. new VersionConstraint('<', $highVersion),
  99. );
  100. }
  101. // match operators constraints
  102. if (preg_match('{^(>=?|<=?|==?)?\s*(\d+.*)}', $constraint, $matches)) {
  103. $version = $this->normalize($matches[2]);
  104. return array(new VersionConstraint($matches[1] ?: '=', $version));
  105. }
  106. throw new \UnexpectedValueException('Could not parse version constraint '.$constraint);
  107. }
  108. }