1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
<?php /** * Simple semver version handling. * * We use this instead of something like `composer/semver` to avoid * plugins needing to include yet-another dependency package. The * amount of code we need here is pretty small. * * We use this instead of PHP's `version_compare()` because that doesn't * handle prerelease versions in the way anyone other than PHP devs would * expect, and silently breaks on various unexpected input. * * @package automattic/jetpack-assets */
namespace Automattic\Jetpack\Assets;
use InvalidArgumentException;
/** * Simple semver version handling. */ class Semver { /** * Parse a semver version. * * @param string $version Version. * @return array With components: * - major: (int) Major version. * - minor: (int) Minor version. * - patch: (int) Patch version. * - version: (string) Major.minor.patch. * - prerelease: (string|null) Pre-release string. * - buildinfo: (string|null) Build metadata string. * @throws InvalidArgumentException If the version number is not in a recognized format. */ public static function parse( $version ) { // This is slightly looser than the official version from semver.org, in that leading zeros are allowed. if ( ! preg_match( '/^(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<prerelease>(?:[0-9a-zA-Z-]+)(?:\.(?:[0-9a-zA-Z-]+))*))?(?:\+(?P<buildinfo>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/', $version, $m ) ) { throw new InvalidArgumentException( "Version number \"$version\" is not in a recognized format." ); } $info = array( 'major' => (int) $m['major'], 'minor' => (int) $m['minor'], 'patch' => (int) $m['patch'], 'version' => sprintf( '%d.%d.%d', $m['major'], $m['minor'], $m['patch'] ), 'prerelease' => isset( $m['prerelease'] ) && '' !== $m['prerelease'] ? $m['prerelease'] : null, 'buildinfo' => isset( $m['buildinfo'] ) && '' !== $m['buildinfo'] ? $m['buildinfo'] : null, );
if ( null !== $info['prerelease'] ) { $sep = ''; $prerelease = ''; foreach ( explode( '.', $info['prerelease'] ) as $part ) { if ( ctype_digit( $part ) ) { $part = (int) $part; } $prerelease .= $sep . $part; $sep = '.'; } $info['prerelease'] = $prerelease; }
return $info; }
/** * Compare two version numbers. * * @param string $a First version. * @param string $b Second version. * @return int Less than, equal to, or greater than 0 depending on whether `$a` is less than, equal to, or greater than `$b`. * @throws InvalidArgumentException If the version numbers are not in a recognized format. */ public static function compare( $a, $b ) { $aa = self::parse( $a ); $bb = self::parse( $b ); if ( $aa['major'] !== $bb['major'] ) { return $aa['major'] - $bb['major']; } if ( $aa['minor'] !== $bb['minor'] ) { return $aa['minor'] - $bb['minor']; } if ( $aa['patch'] !== $bb['patch'] ) { return $aa['patch'] - $bb['patch']; }
if ( null === $aa['prerelease'] ) { return null === $bb['prerelease'] ? 0 : 1; } if ( null === $bb['prerelease'] ) { return -1; }
$aaa = explode( '.', $aa['prerelease'] ); $bbb = explode( '.', $bb['prerelease'] ); $al = count( $aaa ); $bl = count( $bbb ); for ( $i = 0; $i < $al && $i < $bl; $i++ ) { $a = $aaa[ $i ]; $b = $bbb[ $i ]; if ( ctype_digit( $a ) ) { if ( ctype_digit( $b ) ) { if ( (int) $a !== (int) $b ) { return (int) $a - (int) $b; } } else { return -1; } } elseif ( ctype_digit( $b ) ) { return 1; } else { $tmp = strcmp( $a, $b ); if ( 0 !== $tmp ) { return $tmp; } } } return $al - $bl; } }
|