jupyter-builder 0.1.0a2__py3-none-any.whl → 0.1.0a4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jupyter_builder/__init__.py +1 -1
- jupyter_builder/base_extension_app.py +1 -3
- jupyter_builder/commands.py +6 -9
- jupyter_builder/debug_log_file_mixin.py +7 -7
- jupyter_builder/extension_commands/build.py +4 -4
- jupyter_builder/extension_commands/develop.py +2 -2
- jupyter_builder/extension_commands/watch.py +4 -4
- jupyter_builder/federated_extensions.py +36 -43
- jupyter_builder/federated_extensions_requirements.py +12 -12
- jupyter_builder/jupyterlab_semver.py +970 -3
- jupyter_builder/yarn.js +8 -13
- jupyter_builder-0.1.0a4.dist-info/METADATA +175 -0
- jupyter_builder-0.1.0a4.dist-info/RECORD +20 -0
- {jupyter_builder-0.1.0a2.dist-info → jupyter_builder-0.1.0a4.dist-info}/WHEEL +1 -1
- jupyter_builder/jupyterlab_server_req.py +0 -66
- jupyter_builder-0.1.0a2.dist-info/METADATA +0 -119
- jupyter_builder-0.1.0a2.dist-info/RECORD +0 -21
- {jupyter_builder-0.1.0a2.dist-info → jupyter_builder-0.1.0a4.dist-info}/entry_points.txt +0 -0
- {jupyter_builder-0.1.0a2.dist-info → jupyter_builder-0.1.0a4.dist-info}/licenses/LICENSE +0 -0
|
@@ -27,6 +27,330 @@
|
|
|
27
27
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
28
|
# SOFTWARE.
|
|
29
29
|
|
|
30
|
+
import logging
|
|
31
|
+
import re
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
SEMVER_SPEC_VERSION = "2.0.0"
|
|
37
|
+
|
|
38
|
+
string_type = str
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class _R:
|
|
42
|
+
def __init__(self, i):
|
|
43
|
+
self.i = i
|
|
44
|
+
|
|
45
|
+
def __call__(self):
|
|
46
|
+
v = self.i
|
|
47
|
+
self.i += 1
|
|
48
|
+
return v
|
|
49
|
+
|
|
50
|
+
def value(self):
|
|
51
|
+
return self.i
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Extendlist(list):
|
|
55
|
+
def __setitem__(self, i, v):
|
|
56
|
+
try:
|
|
57
|
+
list.__setitem__(self, i, v)
|
|
58
|
+
except IndexError:
|
|
59
|
+
if len(self) == i:
|
|
60
|
+
self.append(v)
|
|
61
|
+
else:
|
|
62
|
+
raise
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def list_get(xs, i):
|
|
66
|
+
try:
|
|
67
|
+
return xs[i]
|
|
68
|
+
except IndexError:
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
R = _R(0)
|
|
73
|
+
src = Extendlist()
|
|
74
|
+
regexp = {}
|
|
75
|
+
|
|
76
|
+
# The following Regular Expressions can be used for tokenizing,
|
|
77
|
+
# validating, and parsing SemVer version strings.
|
|
78
|
+
|
|
79
|
+
# ## Numeric Identifier
|
|
80
|
+
# A single `0`, or a non-zero digit followed by zero or more digits.
|
|
81
|
+
|
|
82
|
+
NUMERICIDENTIFIER = R()
|
|
83
|
+
src[NUMERICIDENTIFIER] = "0|[1-9]\\d*"
|
|
84
|
+
|
|
85
|
+
NUMERICIDENTIFIERLOOSE = R()
|
|
86
|
+
src[NUMERICIDENTIFIERLOOSE] = "[0-9]+"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ## Non-numeric Identifier
|
|
90
|
+
# Zero or more digits, followed by a letter or hyphen, and then zero or
|
|
91
|
+
# more letters, digits, or hyphens.
|
|
92
|
+
|
|
93
|
+
NONNUMERICIDENTIFIER = R()
|
|
94
|
+
src[NONNUMERICIDENTIFIER] = "\\d*[a-zA-Z-][a-zA-Z0-9-]*"
|
|
95
|
+
|
|
96
|
+
# ## Main Version
|
|
97
|
+
# Three dot-separated numeric identifiers.
|
|
98
|
+
|
|
99
|
+
MAINVERSION = R()
|
|
100
|
+
src[MAINVERSION] = (
|
|
101
|
+
"("
|
|
102
|
+
+ src[NUMERICIDENTIFIER]
|
|
103
|
+
+ ")\\."
|
|
104
|
+
+ "("
|
|
105
|
+
+ src[NUMERICIDENTIFIER]
|
|
106
|
+
+ ")\\."
|
|
107
|
+
+ "("
|
|
108
|
+
+ src[NUMERICIDENTIFIER]
|
|
109
|
+
+ ")"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
MAINVERSIONLOOSE = R()
|
|
113
|
+
src[MAINVERSIONLOOSE] = (
|
|
114
|
+
"("
|
|
115
|
+
+ src[NUMERICIDENTIFIERLOOSE]
|
|
116
|
+
+ ")\\."
|
|
117
|
+
+ "("
|
|
118
|
+
+ src[NUMERICIDENTIFIERLOOSE]
|
|
119
|
+
+ ")\\."
|
|
120
|
+
+ "("
|
|
121
|
+
+ src[NUMERICIDENTIFIERLOOSE]
|
|
122
|
+
+ ")"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# ## Pre-release Version Identifier
|
|
127
|
+
# A numeric identifier, or a non-numeric identifier.
|
|
128
|
+
|
|
129
|
+
PRERELEASEIDENTIFIER = R()
|
|
130
|
+
src[PRERELEASEIDENTIFIER] = "(?:" + src[NUMERICIDENTIFIER] + "|" + src[NONNUMERICIDENTIFIER] + ")"
|
|
131
|
+
|
|
132
|
+
PRERELEASEIDENTIFIERLOOSE = R()
|
|
133
|
+
src[PRERELEASEIDENTIFIERLOOSE] = (
|
|
134
|
+
"(?:" + src[NUMERICIDENTIFIERLOOSE] + "|" + src[NONNUMERICIDENTIFIER] + ")"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# ## Pre-release Version
|
|
139
|
+
# Hyphen, followed by one or more dot-separated pre-release version
|
|
140
|
+
# identifiers.
|
|
141
|
+
|
|
142
|
+
PRERELEASE = R()
|
|
143
|
+
src[PRERELEASE] = (
|
|
144
|
+
"(?:-(" + src[PRERELEASEIDENTIFIER] + "(?:\\." + src[PRERELEASEIDENTIFIER] + ")*))"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
PRERELEASELOOSE = R()
|
|
148
|
+
src[PRERELEASELOOSE] = (
|
|
149
|
+
"(?:-?(" + src[PRERELEASEIDENTIFIERLOOSE] + "(?:\\." + src[PRERELEASEIDENTIFIERLOOSE] + ")*))"
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# ## Build Metadata Identifier
|
|
153
|
+
# Any combination of digits, letters, or hyphens.
|
|
154
|
+
|
|
155
|
+
BUILDIDENTIFIER = R()
|
|
156
|
+
src[BUILDIDENTIFIER] = "[0-9A-Za-z-]+"
|
|
157
|
+
|
|
158
|
+
# ## Build Metadata
|
|
159
|
+
# Plus sign, followed by one or more period-separated build metadata
|
|
160
|
+
# identifiers.
|
|
161
|
+
|
|
162
|
+
BUILD = R()
|
|
163
|
+
src[BUILD] = "(?:\\+(" + src[BUILDIDENTIFIER] + "(?:\\." + src[BUILDIDENTIFIER] + ")*))"
|
|
164
|
+
|
|
165
|
+
# ## Full Version String
|
|
166
|
+
# A main version, followed optionally by a pre-release version and
|
|
167
|
+
# build metadata.
|
|
168
|
+
|
|
169
|
+
# Note that the only major, minor, patch, and pre-release sections of
|
|
170
|
+
# the version string are capturing groups. The build metadata is not a
|
|
171
|
+
# capturing group, because it should not ever be used in version
|
|
172
|
+
# comparison.
|
|
173
|
+
|
|
174
|
+
FULL = R()
|
|
175
|
+
FULLPLAIN = "v?" + src[MAINVERSION] + src[PRERELEASE] + "?" + src[BUILD] + "?"
|
|
176
|
+
|
|
177
|
+
src[FULL] = "^" + FULLPLAIN + "$"
|
|
178
|
+
|
|
179
|
+
# like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
|
|
180
|
+
# also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
|
|
181
|
+
# common in the npm registry.
|
|
182
|
+
LOOSEPLAIN = "[v=\\s]*" + src[MAINVERSIONLOOSE] + src[PRERELEASELOOSE] + "?" + src[BUILD] + "?"
|
|
183
|
+
|
|
184
|
+
LOOSE = R()
|
|
185
|
+
src[LOOSE] = "^" + LOOSEPLAIN + "$"
|
|
186
|
+
|
|
187
|
+
GTLT = R()
|
|
188
|
+
src[GTLT] = "((?:<|>)?=?)"
|
|
189
|
+
|
|
190
|
+
# Something like "2.*" or "1.2.x".
|
|
191
|
+
# Note that "x.x" is a valid xRange identifier, meaning "any version"
|
|
192
|
+
# Only the first item is strictly required.
|
|
193
|
+
XRANGEIDENTIFIERLOOSE = R()
|
|
194
|
+
src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + "|x|X|\\*"
|
|
195
|
+
XRANGEIDENTIFIER = R()
|
|
196
|
+
src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + "|x|X|\\*"
|
|
197
|
+
|
|
198
|
+
XRANGEPLAIN = R()
|
|
199
|
+
src[XRANGEPLAIN] = (
|
|
200
|
+
"[v=\\s]*("
|
|
201
|
+
+ src[XRANGEIDENTIFIER]
|
|
202
|
+
+ ")"
|
|
203
|
+
+ "(?:\\.("
|
|
204
|
+
+ src[XRANGEIDENTIFIER]
|
|
205
|
+
+ ")"
|
|
206
|
+
+ "(?:\\.("
|
|
207
|
+
+ src[XRANGEIDENTIFIER]
|
|
208
|
+
+ ")"
|
|
209
|
+
+ "(?:"
|
|
210
|
+
+ src[PRERELEASE]
|
|
211
|
+
+ ")?"
|
|
212
|
+
+ src[BUILD]
|
|
213
|
+
+ "?"
|
|
214
|
+
+ ")?)?"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
XRANGEPLAINLOOSE = R()
|
|
218
|
+
src[XRANGEPLAINLOOSE] = (
|
|
219
|
+
"[v=\\s]*("
|
|
220
|
+
+ src[XRANGEIDENTIFIERLOOSE]
|
|
221
|
+
+ ")"
|
|
222
|
+
+ "(?:\\.("
|
|
223
|
+
+ src[XRANGEIDENTIFIERLOOSE]
|
|
224
|
+
+ ")"
|
|
225
|
+
+ "(?:\\.("
|
|
226
|
+
+ src[XRANGEIDENTIFIERLOOSE]
|
|
227
|
+
+ ")"
|
|
228
|
+
+ "(?:"
|
|
229
|
+
+ src[PRERELEASELOOSE]
|
|
230
|
+
+ ")?"
|
|
231
|
+
+ src[BUILD]
|
|
232
|
+
+ "?"
|
|
233
|
+
+ ")?)?"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
XRANGE = R()
|
|
237
|
+
src[XRANGE] = "^" + src[GTLT] + "\\s*" + src[XRANGEPLAIN] + "$"
|
|
238
|
+
XRANGELOOSE = R()
|
|
239
|
+
src[XRANGELOOSE] = "^" + src[GTLT] + "\\s*" + src[XRANGEPLAINLOOSE] + "$"
|
|
240
|
+
|
|
241
|
+
# Tilde ranges.
|
|
242
|
+
# Meaning is "reasonably at or greater than"
|
|
243
|
+
LONETILDE = R()
|
|
244
|
+
src[LONETILDE] = "(?:~>?)"
|
|
245
|
+
|
|
246
|
+
TILDETRIM = R()
|
|
247
|
+
src[TILDETRIM] = "(\\s*)" + src[LONETILDE] + "\\s+"
|
|
248
|
+
regexp[TILDETRIM] = re.compile(src[TILDETRIM], re.M)
|
|
249
|
+
tildeTrimReplace = r"\1~"
|
|
250
|
+
|
|
251
|
+
TILDE = R()
|
|
252
|
+
src[TILDE] = "^" + src[LONETILDE] + src[XRANGEPLAIN] + "$"
|
|
253
|
+
TILDELOOSE = R()
|
|
254
|
+
src[TILDELOOSE] = "^" + src[LONETILDE] + src[XRANGEPLAINLOOSE] + "$"
|
|
255
|
+
|
|
256
|
+
# Caret ranges.
|
|
257
|
+
# Meaning is "at least and backwards compatible with"
|
|
258
|
+
LONECARET = R()
|
|
259
|
+
src[LONECARET] = "(?:\\^)"
|
|
260
|
+
|
|
261
|
+
CARETTRIM = R()
|
|
262
|
+
src[CARETTRIM] = "(\\s*)" + src[LONECARET] + "\\s+"
|
|
263
|
+
regexp[CARETTRIM] = re.compile(src[CARETTRIM], re.M)
|
|
264
|
+
caretTrimReplace = r"\1^"
|
|
265
|
+
|
|
266
|
+
CARET = R()
|
|
267
|
+
src[CARET] = "^" + src[LONECARET] + src[XRANGEPLAIN] + "$"
|
|
268
|
+
CARETLOOSE = R()
|
|
269
|
+
src[CARETLOOSE] = "^" + src[LONECARET] + src[XRANGEPLAINLOOSE] + "$"
|
|
270
|
+
|
|
271
|
+
# A simple gt/lt/eq thing, or just "" to indicate "any version"
|
|
272
|
+
COMPARATORLOOSE = R()
|
|
273
|
+
src[COMPARATORLOOSE] = "^" + src[GTLT] + "\\s*(" + LOOSEPLAIN + ")$|^$"
|
|
274
|
+
COMPARATOR = R()
|
|
275
|
+
src[COMPARATOR] = "^" + src[GTLT] + "\\s*(" + FULLPLAIN + ")$|^$"
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
# An expression to strip any whitespace between the gtlt and the thing
|
|
279
|
+
# it modifies, so that `> 1.2.3` ==> `>1.2.3`
|
|
280
|
+
COMPARATORTRIM = R()
|
|
281
|
+
src[COMPARATORTRIM] = "(\\s*)" + src[GTLT] + "\\s*(" + LOOSEPLAIN + "|" + src[XRANGEPLAIN] + ")"
|
|
282
|
+
|
|
283
|
+
# this one has to use the /g flag
|
|
284
|
+
regexp[COMPARATORTRIM] = re.compile(src[COMPARATORTRIM], re.M)
|
|
285
|
+
comparatorTrimReplace = r"\1\2\3"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# Something like `1.2.3 - 1.2.4`
|
|
289
|
+
# Note that these all use the loose form, because they'll be
|
|
290
|
+
# checked against either the strict or loose comparator form
|
|
291
|
+
# later.
|
|
292
|
+
HYPHENRANGE = R()
|
|
293
|
+
src[HYPHENRANGE] = (
|
|
294
|
+
"^\\s*(" + src[XRANGEPLAIN] + ")" + "\\s+-\\s+" + "(" + src[XRANGEPLAIN] + ")" + "\\s*$"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
HYPHENRANGELOOSE = R()
|
|
298
|
+
src[HYPHENRANGELOOSE] = (
|
|
299
|
+
"^\\s*("
|
|
300
|
+
+ src[XRANGEPLAINLOOSE]
|
|
301
|
+
+ ")"
|
|
302
|
+
+ "\\s+-\\s+"
|
|
303
|
+
+ "("
|
|
304
|
+
+ src[XRANGEPLAINLOOSE]
|
|
305
|
+
+ ")"
|
|
306
|
+
+ "\\s*$"
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# Star ranges basically just allow anything at all.
|
|
310
|
+
STAR = R()
|
|
311
|
+
src[STAR] = "(<|>)?=?\\s*\\*"
|
|
312
|
+
|
|
313
|
+
# version name recovery for convenient
|
|
314
|
+
RECOVERYVERSIONNAME = R()
|
|
315
|
+
_n = src[NUMERICIDENTIFIER]
|
|
316
|
+
_pre = src[PRERELEASELOOSE]
|
|
317
|
+
src[RECOVERYVERSIONNAME] = f"v?({_n})(?:\\.({_n}))?{_pre}?"
|
|
318
|
+
|
|
319
|
+
# Compile to actual regexp objects.
|
|
320
|
+
# All are flag-free, unless they were created above with a flag.
|
|
321
|
+
for i in range(R.value()):
|
|
322
|
+
logger.debug("genregxp %s %s", i, src[i])
|
|
323
|
+
if i not in regexp:
|
|
324
|
+
regexp[i] = re.compile(src[i])
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def parse(version, loose):
|
|
328
|
+
r = regexp[LOOSE] if loose else regexp[FULL]
|
|
329
|
+
m = r.search(version)
|
|
330
|
+
if m:
|
|
331
|
+
return semver(version, loose)
|
|
332
|
+
else:
|
|
333
|
+
return None
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def valid(version, loose):
|
|
337
|
+
v = parse(version, loose)
|
|
338
|
+
if v.version:
|
|
339
|
+
return v
|
|
340
|
+
else:
|
|
341
|
+
return None
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def clean(version, loose):
|
|
345
|
+
s = parse(version, loose)
|
|
346
|
+
if s:
|
|
347
|
+
return s.version
|
|
348
|
+
else:
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
NUMERIC = re.compile(r"^\d+$")
|
|
353
|
+
|
|
30
354
|
|
|
31
355
|
def semver(version, loose):
|
|
32
356
|
if isinstance(version, SemVer):
|
|
@@ -65,7 +389,7 @@ class SemVer:
|
|
|
65
389
|
self.prerelease = []
|
|
66
390
|
else:
|
|
67
391
|
self.prerelease = [
|
|
68
|
-
(int(
|
|
392
|
+
(int(id_) if NUMERIC.search(id_) else id_) for id_ in m.group(3).split(".")
|
|
69
393
|
]
|
|
70
394
|
else:
|
|
71
395
|
# these are actually numbers
|
|
@@ -77,7 +401,7 @@ class SemVer:
|
|
|
77
401
|
self.prerelease = []
|
|
78
402
|
else:
|
|
79
403
|
self.prerelease = [
|
|
80
|
-
(int(
|
|
404
|
+
(int(id_) if NUMERIC.search(id_) else id_) for id_ in m.group(4).split(".")
|
|
81
405
|
]
|
|
82
406
|
if m.group(5):
|
|
83
407
|
self.build = m.group(5).split(".")
|
|
@@ -116,7 +440,7 @@ class SemVer:
|
|
|
116
440
|
or compare_identifiers(str(self.patch), str(other.patch))
|
|
117
441
|
)
|
|
118
442
|
|
|
119
|
-
def compare_pre(self, other):
|
|
443
|
+
def compare_pre(self, other): # noqa PLR0911
|
|
120
444
|
if not isinstance(other, SemVer):
|
|
121
445
|
other = make_semver(other, self.loose)
|
|
122
446
|
|
|
@@ -232,10 +556,81 @@ class SemVer:
|
|
|
232
556
|
return self
|
|
233
557
|
|
|
234
558
|
|
|
559
|
+
def inc(version, release, loose, identifier=None): # wow!
|
|
560
|
+
try:
|
|
561
|
+
return make_semver(version, loose).inc(release, identifier=identifier).version
|
|
562
|
+
except Exception as e:
|
|
563
|
+
logger.debug(e, exc_info=5)
|
|
564
|
+
return None
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def compare_identifiers(a, b):
|
|
568
|
+
anum = NUMERIC.search(a)
|
|
569
|
+
bnum = NUMERIC.search(b)
|
|
570
|
+
|
|
571
|
+
if anum and bnum:
|
|
572
|
+
a = int(a)
|
|
573
|
+
b = int(b)
|
|
574
|
+
|
|
575
|
+
if anum and not bnum:
|
|
576
|
+
return -1
|
|
577
|
+
elif bnum and not anum:
|
|
578
|
+
return 1
|
|
579
|
+
elif a < b:
|
|
580
|
+
return -1
|
|
581
|
+
elif a > b:
|
|
582
|
+
return 1
|
|
583
|
+
else:
|
|
584
|
+
return 0
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def rcompare_identifiers(a, b):
|
|
588
|
+
return compare_identifiers(b, a)
|
|
589
|
+
|
|
590
|
+
|
|
235
591
|
def compare(a, b, loose):
|
|
236
592
|
return make_semver(a, loose).compare(b)
|
|
237
593
|
|
|
238
594
|
|
|
595
|
+
def compare_loose(a, b):
|
|
596
|
+
return compare(a, b, True)
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
def rcompare(a, b, loose):
|
|
600
|
+
return compare(b, a, loose)
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
def make_key_function(loose):
|
|
604
|
+
def key_function(version):
|
|
605
|
+
v = make_semver(version, loose)
|
|
606
|
+
key = (v.major, v.minor, v.patch)
|
|
607
|
+
if v.prerelease: # noqa SIM108
|
|
608
|
+
key = key + tuple(v.prerelease)
|
|
609
|
+
else:
|
|
610
|
+
# NOT having a prerelease is > having one
|
|
611
|
+
key = (*key, float("inf"))
|
|
612
|
+
|
|
613
|
+
return key
|
|
614
|
+
|
|
615
|
+
return key_function
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
loose_key_function = make_key_function(True)
|
|
619
|
+
full_key_function = make_key_function(True)
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def sort(list_, loose):
|
|
623
|
+
keyf = loose_key_function if loose else full_key_function
|
|
624
|
+
list_.sort(key=keyf)
|
|
625
|
+
return list_
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def rsort(list_, loose):
|
|
629
|
+
keyf = loose_key_function if loose else full_key_function
|
|
630
|
+
list_.sort(key=keyf, reverse=True)
|
|
631
|
+
return list_
|
|
632
|
+
|
|
633
|
+
|
|
239
634
|
def gt(a, b, loose):
|
|
240
635
|
return compare(a, b, loose) > 0
|
|
241
636
|
|
|
@@ -244,9 +639,581 @@ def lt(a, b, loose):
|
|
|
244
639
|
return compare(a, b, loose) < 0
|
|
245
640
|
|
|
246
641
|
|
|
642
|
+
def eq(a, b, loose):
|
|
643
|
+
return compare(a, b, loose) == 0
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def neq(a, b, loose):
|
|
647
|
+
return compare(a, b, loose) != 0
|
|
648
|
+
|
|
649
|
+
|
|
247
650
|
def gte(a, b, loose):
|
|
248
651
|
return compare(a, b, loose) >= 0
|
|
249
652
|
|
|
250
653
|
|
|
251
654
|
def lte(a, b, loose):
|
|
252
655
|
return compare(a, b, loose) <= 0
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def cmp(a, op, b, loose): # noqa PLR0911
|
|
659
|
+
logger.debug("cmp: %s", op)
|
|
660
|
+
if op == "===":
|
|
661
|
+
return a == b
|
|
662
|
+
elif op == "!==":
|
|
663
|
+
return a != b
|
|
664
|
+
elif op == "" or op == "=" or op == "==":
|
|
665
|
+
return eq(a, b, loose)
|
|
666
|
+
elif op == "!=":
|
|
667
|
+
return neq(a, b, loose)
|
|
668
|
+
elif op == ">":
|
|
669
|
+
return gt(a, b, loose)
|
|
670
|
+
elif op == ">=":
|
|
671
|
+
return gte(a, b, loose)
|
|
672
|
+
elif op == "<":
|
|
673
|
+
return lt(a, b, loose)
|
|
674
|
+
elif op == "<=":
|
|
675
|
+
return lte(a, b, loose)
|
|
676
|
+
else:
|
|
677
|
+
raise ValueError(f"Invalid operator: {op}")
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def comparator(comp, loose):
|
|
681
|
+
if isinstance(comp, Comparator):
|
|
682
|
+
if comp.loose == loose:
|
|
683
|
+
return comp
|
|
684
|
+
else:
|
|
685
|
+
comp = comp.value
|
|
686
|
+
|
|
687
|
+
# if (!(this instanceof Comparator))
|
|
688
|
+
# return new Comparator(comp, loose)
|
|
689
|
+
return Comparator(comp, loose)
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
make_comparator = comparator
|
|
693
|
+
|
|
694
|
+
ANY = object()
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
class Comparator:
|
|
698
|
+
semver = None
|
|
699
|
+
|
|
700
|
+
def __init__(self, comp, loose):
|
|
701
|
+
logger.debug("comparator: %s %s", comp, loose)
|
|
702
|
+
self.loose = loose
|
|
703
|
+
self.parse(comp)
|
|
704
|
+
|
|
705
|
+
if self.semver == ANY:
|
|
706
|
+
self.value = ""
|
|
707
|
+
else:
|
|
708
|
+
self.value = self.operator + self.semver.version
|
|
709
|
+
|
|
710
|
+
def parse(self, comp):
|
|
711
|
+
r = regexp[COMPARATORLOOSE] if self.loose else regexp[COMPARATOR]
|
|
712
|
+
logger.debug("parse comp=%s", comp)
|
|
713
|
+
m = r.search(comp)
|
|
714
|
+
|
|
715
|
+
if m is None:
|
|
716
|
+
raise ValueError(f"Invalid comparator: {comp}")
|
|
717
|
+
|
|
718
|
+
self.operator = m.group(1)
|
|
719
|
+
# if it literally is just '>' or '' then allow anything.
|
|
720
|
+
if m.group(2) is None:
|
|
721
|
+
self.semver = ANY
|
|
722
|
+
else:
|
|
723
|
+
self.semver = semver(m.group(2), self.loose)
|
|
724
|
+
|
|
725
|
+
def __repr__(self):
|
|
726
|
+
return f'<SemVer Comparator "{self}">'
|
|
727
|
+
|
|
728
|
+
def __str__(self):
|
|
729
|
+
return self.value
|
|
730
|
+
|
|
731
|
+
def test(self, version):
|
|
732
|
+
logger.debug("Comparator, test %s, %s", version, self.loose)
|
|
733
|
+
if self.semver == ANY:
|
|
734
|
+
return True
|
|
735
|
+
else:
|
|
736
|
+
return cmp(version, self.operator, self.semver, self.loose)
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
def make_range(range_, loose):
|
|
740
|
+
if isinstance(range_, Range) and range_.loose == loose:
|
|
741
|
+
return range_
|
|
742
|
+
|
|
743
|
+
# if (!(this instanceof Range))
|
|
744
|
+
# return new Range(range, loose);
|
|
745
|
+
return Range(range_, loose)
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
class Range:
|
|
749
|
+
def __init__(self, range_, loose):
|
|
750
|
+
self.loose = loose
|
|
751
|
+
# First, split based on boolean or ||
|
|
752
|
+
self.raw = range_
|
|
753
|
+
xs = [self.parse_range(r.strip()) for r in re.split(r"\s*\|\|\s*", range_)]
|
|
754
|
+
self.set = [r for r in xs if r]
|
|
755
|
+
|
|
756
|
+
if not len(self.set):
|
|
757
|
+
raise ValueError(f"Invalid SemVer Range: {range_}")
|
|
758
|
+
|
|
759
|
+
self.format()
|
|
760
|
+
|
|
761
|
+
def __repr__(self):
|
|
762
|
+
return f'<SemVer Range "{self.range}">'
|
|
763
|
+
|
|
764
|
+
def format(self):
|
|
765
|
+
self.range = "||".join(
|
|
766
|
+
[" ".join(c.value for c in comps).strip() for comps in self.set]
|
|
767
|
+
).strip()
|
|
768
|
+
logger.debug("Range format %s", self.range)
|
|
769
|
+
return self.range
|
|
770
|
+
|
|
771
|
+
def __str__(self):
|
|
772
|
+
return self.range
|
|
773
|
+
|
|
774
|
+
def parse_range(self, range_):
|
|
775
|
+
loose = self.loose
|
|
776
|
+
logger.debug("range %s %s", range_, loose)
|
|
777
|
+
# `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
|
|
778
|
+
hr = regexp[HYPHENRANGELOOSE] if loose else regexp[HYPHENRANGE]
|
|
779
|
+
|
|
780
|
+
range_ = hr.sub(
|
|
781
|
+
hyphen_replace,
|
|
782
|
+
range_,
|
|
783
|
+
)
|
|
784
|
+
logger.debug("hyphen replace %s", range_)
|
|
785
|
+
|
|
786
|
+
# `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
|
|
787
|
+
range_ = regexp[COMPARATORTRIM].sub(comparatorTrimReplace, range_)
|
|
788
|
+
logger.debug("comparator trim %s, %s", range_, regexp[COMPARATORTRIM])
|
|
789
|
+
|
|
790
|
+
# `~ 1.2.3` => `~1.2.3`
|
|
791
|
+
range_ = regexp[TILDETRIM].sub(tildeTrimReplace, range_)
|
|
792
|
+
|
|
793
|
+
# `^ 1.2.3` => `^1.2.3`
|
|
794
|
+
range_ = regexp[CARETTRIM].sub(caretTrimReplace, range_)
|
|
795
|
+
|
|
796
|
+
# normalize spaces
|
|
797
|
+
range_ = " ".join(re.split(r"\s+", range_))
|
|
798
|
+
|
|
799
|
+
# At this point, the range is completely trimmed and
|
|
800
|
+
# ready to be split into comparators.
|
|
801
|
+
comp_re = regexp[COMPARATORLOOSE] if loose else regexp[COMPARATOR]
|
|
802
|
+
set_ = re.split(
|
|
803
|
+
r"\s+", " ".join([parse_comparator(comp, loose) for comp in range_.split(" ")])
|
|
804
|
+
)
|
|
805
|
+
if self.loose:
|
|
806
|
+
# in loose mode, throw out any that are not valid comparators
|
|
807
|
+
set_ = [comp for comp in set_ if comp_re.search(comp)]
|
|
808
|
+
set_ = [make_comparator(comp, loose) for comp in set_]
|
|
809
|
+
return set_
|
|
810
|
+
|
|
811
|
+
def test(self, version):
|
|
812
|
+
if not version: # xxx
|
|
813
|
+
return False
|
|
814
|
+
|
|
815
|
+
if isinstance(version, string_type):
|
|
816
|
+
version = make_semver(version, loose=self.loose)
|
|
817
|
+
|
|
818
|
+
return any(test_set(e, version) for e in self.set)
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
# Mostly just for testing and legacy API reasons
|
|
822
|
+
def to_comparators(range_, loose):
|
|
823
|
+
return [
|
|
824
|
+
" ".join([c.value for c in comp]).strip().split(" ")
|
|
825
|
+
for comp in make_range(range_, loose).set
|
|
826
|
+
]
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
# comprised of xranges, tildes, stars, and gtlt's at this point.
|
|
830
|
+
# already replaced the hyphen ranges
|
|
831
|
+
# turn into a set of JUST comparators.
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def parse_comparator(comp, loose):
|
|
835
|
+
logger.debug("comp %s", comp)
|
|
836
|
+
comp = replace_carets(comp, loose)
|
|
837
|
+
logger.debug("caret %s", comp)
|
|
838
|
+
comp = replace_tildes(comp, loose)
|
|
839
|
+
logger.debug("tildes %s", comp)
|
|
840
|
+
comp = replace_xranges(comp, loose)
|
|
841
|
+
logger.debug("xrange %s", comp)
|
|
842
|
+
comp = replace_stars(comp, loose)
|
|
843
|
+
logger.debug("stars %s", comp)
|
|
844
|
+
return comp
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
def is_x(id_):
|
|
848
|
+
return id_ is None or id_ == "" or id_.lower() == "x" or id_ == "*"
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
# ~, ~> --> * (any, kinda silly)
|
|
852
|
+
# ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
|
|
853
|
+
# ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
|
|
854
|
+
# ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
|
|
855
|
+
# ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
|
|
856
|
+
# ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
def replace_tildes(comp, loose):
|
|
860
|
+
return " ".join([replace_tilde(c, loose) for c in re.split(r"\s+", comp.strip())])
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
def replace_tilde(comp, loose):
|
|
864
|
+
r = regexp[TILDELOOSE] if loose else regexp[TILDE]
|
|
865
|
+
|
|
866
|
+
def repl(mob):
|
|
867
|
+
_ = mob.group(0)
|
|
868
|
+
M, m, p, pr, _ = mob.groups()
|
|
869
|
+
logger.debug("tilde %s %s %s %s %s %s", comp, _, M, m, p, pr)
|
|
870
|
+
if is_x(M):
|
|
871
|
+
ret = ""
|
|
872
|
+
elif is_x(m):
|
|
873
|
+
ret = ">=" + M + ".0.0 <" + str(int(M) + 1) + ".0.0"
|
|
874
|
+
elif is_x(p):
|
|
875
|
+
# ~1.2 == >=1.2.0 <1.3.0
|
|
876
|
+
ret = ">=" + M + "." + m + ".0 <" + M + "." + str(int(m) + 1) + ".0"
|
|
877
|
+
elif pr:
|
|
878
|
+
logger.debug("replaceTilde pr %s", pr)
|
|
879
|
+
if pr[0] != "-":
|
|
880
|
+
pr = "-" + pr
|
|
881
|
+
ret = ">=" + M + "." + m + "." + p + pr + " <" + M + "." + str(int(m) + 1) + ".0"
|
|
882
|
+
else:
|
|
883
|
+
# ~1.2.3 == >=1.2.3 <1.3.0
|
|
884
|
+
ret = ">=" + M + "." + m + "." + p + " <" + M + "." + str(int(m) + 1) + ".0"
|
|
885
|
+
logger.debug("tilde return, %s", ret)
|
|
886
|
+
return ret
|
|
887
|
+
|
|
888
|
+
return r.sub(repl, comp)
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
# ^ --> * (any, kinda silly)
|
|
892
|
+
# ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
|
|
893
|
+
# ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
|
|
894
|
+
# ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
|
|
895
|
+
# ^1.2.3 --> >=1.2.3 <2.0.0
|
|
896
|
+
# ^1.2.0 --> >=1.2.0 <2.0.0
|
|
897
|
+
def replace_carets(comp, loose):
|
|
898
|
+
return " ".join([replace_caret(c, loose) for c in re.split(r"\s+", comp.strip())])
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
def replace_caret(comp, loose):
|
|
902
|
+
r = regexp[CARETLOOSE] if loose else regexp[CARET]
|
|
903
|
+
|
|
904
|
+
def repl(mob):
|
|
905
|
+
m0 = mob.group(0)
|
|
906
|
+
M, m, p, pr, _ = mob.groups()
|
|
907
|
+
logger.debug("caret %s %s %s %s %s %s", comp, m0, M, m, p, pr)
|
|
908
|
+
|
|
909
|
+
if is_x(M):
|
|
910
|
+
ret = ""
|
|
911
|
+
elif is_x(m):
|
|
912
|
+
ret = ">=" + M + ".0.0 <" + str(int(M) + 1) + ".0.0"
|
|
913
|
+
elif is_x(p):
|
|
914
|
+
if M == "0":
|
|
915
|
+
ret = ">=" + M + "." + m + ".0 <" + M + "." + str(int(m) + 1) + ".0"
|
|
916
|
+
else:
|
|
917
|
+
ret = ">=" + M + "." + m + ".0 <" + str(int(M) + 1) + ".0.0"
|
|
918
|
+
elif pr:
|
|
919
|
+
logger.debug("replaceCaret pr %s", pr)
|
|
920
|
+
if pr[0] != "-":
|
|
921
|
+
pr = "-" + pr
|
|
922
|
+
if M == "0":
|
|
923
|
+
if m == "0":
|
|
924
|
+
ret = (
|
|
925
|
+
">="
|
|
926
|
+
+ M
|
|
927
|
+
+ "."
|
|
928
|
+
+ m
|
|
929
|
+
+ "."
|
|
930
|
+
+ (p or "")
|
|
931
|
+
+ pr
|
|
932
|
+
+ " <"
|
|
933
|
+
+ M
|
|
934
|
+
+ "."
|
|
935
|
+
+ m
|
|
936
|
+
+ "."
|
|
937
|
+
+ str(int(p or 0) + 1)
|
|
938
|
+
)
|
|
939
|
+
else:
|
|
940
|
+
ret = (
|
|
941
|
+
">="
|
|
942
|
+
+ M
|
|
943
|
+
+ "."
|
|
944
|
+
+ m
|
|
945
|
+
+ "."
|
|
946
|
+
+ (p or "")
|
|
947
|
+
+ pr
|
|
948
|
+
+ " <"
|
|
949
|
+
+ M
|
|
950
|
+
+ "."
|
|
951
|
+
+ str(int(m) + 1)
|
|
952
|
+
+ ".0"
|
|
953
|
+
)
|
|
954
|
+
else:
|
|
955
|
+
ret = ">=" + M + "." + m + "." + (p or "") + pr + " <" + str(int(M) + 1) + ".0.0"
|
|
956
|
+
else:
|
|
957
|
+
if M == "0":
|
|
958
|
+
if m == "0":
|
|
959
|
+
ret = (
|
|
960
|
+
">="
|
|
961
|
+
+ M
|
|
962
|
+
+ "."
|
|
963
|
+
+ m
|
|
964
|
+
+ "."
|
|
965
|
+
+ (p or "")
|
|
966
|
+
+ " <"
|
|
967
|
+
+ M
|
|
968
|
+
+ "."
|
|
969
|
+
+ m
|
|
970
|
+
+ "."
|
|
971
|
+
+ str(int(p or 0) + 1)
|
|
972
|
+
)
|
|
973
|
+
else:
|
|
974
|
+
ret = (
|
|
975
|
+
">="
|
|
976
|
+
+ M
|
|
977
|
+
+ "."
|
|
978
|
+
+ m
|
|
979
|
+
+ "."
|
|
980
|
+
+ (p or "")
|
|
981
|
+
+ " <"
|
|
982
|
+
+ M
|
|
983
|
+
+ "."
|
|
984
|
+
+ str(int(m) + 1)
|
|
985
|
+
+ ".0"
|
|
986
|
+
)
|
|
987
|
+
else:
|
|
988
|
+
ret = ">=" + M + "." + m + "." + (p or "") + " <" + str(int(M) + 1) + ".0.0"
|
|
989
|
+
logger.debug("caret return %s", ret)
|
|
990
|
+
return ret
|
|
991
|
+
|
|
992
|
+
return r.sub(repl, comp)
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
def replace_xranges(comp, loose):
|
|
996
|
+
logger.debug("replaceXRanges %s %s", comp, loose)
|
|
997
|
+
return " ".join([replace_xrange(c, loose) for c in re.split(r"\s+", comp.strip())])
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
def replace_xrange(comp, loose):
|
|
1001
|
+
comp = comp.strip()
|
|
1002
|
+
r = regexp[XRANGELOOSE] if loose else regexp[XRANGE]
|
|
1003
|
+
|
|
1004
|
+
def repl(mob):
|
|
1005
|
+
ret = mob.group(0)
|
|
1006
|
+
gtlt, M, m, p, pr, _ = mob.groups()
|
|
1007
|
+
|
|
1008
|
+
logger.debug("xrange %s %s %s %s %s %s %s", comp, ret, gtlt, M, m, p, pr)
|
|
1009
|
+
|
|
1010
|
+
xM = is_x(M)
|
|
1011
|
+
xm = xM or is_x(m)
|
|
1012
|
+
xp = xm or is_x(p)
|
|
1013
|
+
any_x = xp
|
|
1014
|
+
|
|
1015
|
+
if gtlt == "=" and any_x:
|
|
1016
|
+
gtlt = ""
|
|
1017
|
+
|
|
1018
|
+
logger.debug("xrange gtlt=%s any_x=%s", gtlt, any_x)
|
|
1019
|
+
if xM:
|
|
1020
|
+
if gtlt == ">" or gtlt == "<": # noqa SIM108
|
|
1021
|
+
# nothing is allowed
|
|
1022
|
+
ret = "<0.0.0"
|
|
1023
|
+
else:
|
|
1024
|
+
ret = "*"
|
|
1025
|
+
elif gtlt and any_x:
|
|
1026
|
+
# replace X with 0, and then append the -0 min-prerelease
|
|
1027
|
+
if xm:
|
|
1028
|
+
m = 0
|
|
1029
|
+
if xp:
|
|
1030
|
+
p = 0
|
|
1031
|
+
|
|
1032
|
+
if gtlt == ">":
|
|
1033
|
+
# >1 => >=2.0.0
|
|
1034
|
+
# >1.2 => >=1.3.0
|
|
1035
|
+
# >1.2.3 => >= 1.2.4
|
|
1036
|
+
gtlt = ">="
|
|
1037
|
+
if xm:
|
|
1038
|
+
M = int(M) + 1
|
|
1039
|
+
m = 0
|
|
1040
|
+
p = 0
|
|
1041
|
+
elif xp:
|
|
1042
|
+
m = int(m) + 1
|
|
1043
|
+
p = 0
|
|
1044
|
+
elif gtlt == "<=":
|
|
1045
|
+
# <=0.7.x is actually <0.8.0, since any 0.7.x should
|
|
1046
|
+
# pass. Similarly, <=7.x is actually <8.0.0, etc.
|
|
1047
|
+
gtlt = "<"
|
|
1048
|
+
if xm:
|
|
1049
|
+
M = int(M) + 1
|
|
1050
|
+
else:
|
|
1051
|
+
m = int(m) + 1
|
|
1052
|
+
|
|
1053
|
+
ret = gtlt + str(M) + "." + str(m) + "." + str(p)
|
|
1054
|
+
elif xm:
|
|
1055
|
+
ret = ">=" + M + ".0.0 <" + str(int(M) + 1) + ".0.0"
|
|
1056
|
+
elif xp:
|
|
1057
|
+
ret = ">=" + M + "." + m + ".0 <" + M + "." + str(int(m) + 1) + ".0"
|
|
1058
|
+
logger.debug("xRange return %s", ret)
|
|
1059
|
+
|
|
1060
|
+
return ret
|
|
1061
|
+
|
|
1062
|
+
return r.sub(repl, comp)
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
# Because * is AND-ed with everything else in the comparator,
|
|
1066
|
+
# and '' means "any version", just remove the *s entirely.
|
|
1067
|
+
def replace_stars(comp, loose):
|
|
1068
|
+
logger.debug("replaceStars %s %s", comp, loose)
|
|
1069
|
+
# Looseness is ignored here. star is always as loose as it gets!
|
|
1070
|
+
return regexp[STAR].sub("", comp.strip())
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
# This function is passed to string.replace(re[HYPHENRANGE])
|
|
1074
|
+
# M, m, patch, prerelease, build
|
|
1075
|
+
# 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
|
|
1076
|
+
# 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
|
|
1077
|
+
# 1.2 - 3.4 => >=1.2.0 <3.5.0
|
|
1078
|
+
def hyphen_replace(mob):
|
|
1079
|
+
from_, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr, tb = mob.groups()
|
|
1080
|
+
if is_x(fM):
|
|
1081
|
+
from_ = ""
|
|
1082
|
+
elif is_x(fm):
|
|
1083
|
+
from_ = ">=" + fM + ".0.0"
|
|
1084
|
+
elif is_x(fp):
|
|
1085
|
+
from_ = ">=" + fM + "." + fm + ".0"
|
|
1086
|
+
else:
|
|
1087
|
+
from_ = ">=" + from_
|
|
1088
|
+
|
|
1089
|
+
if is_x(tM):
|
|
1090
|
+
to = ""
|
|
1091
|
+
elif is_x(tm):
|
|
1092
|
+
to = "<" + str(int(tM) + 1) + ".0.0"
|
|
1093
|
+
elif is_x(tp):
|
|
1094
|
+
to = "<" + tM + "." + str(int(tm) + 1) + ".0"
|
|
1095
|
+
elif tpr:
|
|
1096
|
+
to = "<=" + tM + "." + tm + "." + tp + "-" + tpr
|
|
1097
|
+
else:
|
|
1098
|
+
to = "<=" + to
|
|
1099
|
+
return (from_ + " " + to).strip()
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
def test_set(set_, version):
|
|
1103
|
+
for e in set_:
|
|
1104
|
+
if not e.test(version):
|
|
1105
|
+
return False
|
|
1106
|
+
if len(version.prerelease) > 0:
|
|
1107
|
+
# Find the set of versions that are allowed to have prereleases
|
|
1108
|
+
# For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
|
|
1109
|
+
# That should allow `1.2.3-pr.2` to pass.
|
|
1110
|
+
# However, `1.2.4-alpha.notready` should NOT be allowed,
|
|
1111
|
+
# even though it's within the range set by the comparators.
|
|
1112
|
+
for e in set_:
|
|
1113
|
+
if e.semver == ANY:
|
|
1114
|
+
continue
|
|
1115
|
+
if len(e.semver.prerelease) > 0:
|
|
1116
|
+
allowed = e.semver
|
|
1117
|
+
if (
|
|
1118
|
+
allowed.major == version.major
|
|
1119
|
+
and allowed.minor == version.minor
|
|
1120
|
+
and allowed.patch == version.patch
|
|
1121
|
+
):
|
|
1122
|
+
return True
|
|
1123
|
+
# Version has a -pre, but it's not one of the ones we like.
|
|
1124
|
+
return False
|
|
1125
|
+
return True
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
def satisfies(version, range_, loose=False):
|
|
1129
|
+
try:
|
|
1130
|
+
range_ = make_range(range_, loose)
|
|
1131
|
+
except Exception:
|
|
1132
|
+
return False
|
|
1133
|
+
return range_.test(version)
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
def max_satisfying(versions, range_, loose=False):
|
|
1137
|
+
try:
|
|
1138
|
+
range_ob = make_range(range_, loose=loose)
|
|
1139
|
+
except Exception:
|
|
1140
|
+
return None
|
|
1141
|
+
max_ = None
|
|
1142
|
+
max_sv = None
|
|
1143
|
+
for v in versions:
|
|
1144
|
+
if range_ob.test(v): # noqa # satisfies(v, range_, loose=loose)
|
|
1145
|
+
if max_ is None or max_sv.compare(v) == -1: # compare(max, v, true)
|
|
1146
|
+
max_ = v
|
|
1147
|
+
max_sv = make_semver(max_, loose=loose)
|
|
1148
|
+
return max_
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
def valid_range(range_, loose):
|
|
1152
|
+
try:
|
|
1153
|
+
# Return '*' instead of '' so that truthiness works.
|
|
1154
|
+
# This will throw if it's invalid anyway
|
|
1155
|
+
return make_range(range_, loose).range or "*"
|
|
1156
|
+
except Exception:
|
|
1157
|
+
return None
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
# Determine if version is less than all the versions possible in the range
|
|
1161
|
+
def ltr(version, range_, loose):
|
|
1162
|
+
return outside(version, range_, "<", loose)
|
|
1163
|
+
|
|
1164
|
+
|
|
1165
|
+
# Determine if version is greater than all the versions possible in the range.
|
|
1166
|
+
def rtr(version, range_, loose):
|
|
1167
|
+
return outside(version, range_, ">", loose)
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
def outside(version, range_, hilo, loose):
|
|
1171
|
+
version = make_semver(version, loose)
|
|
1172
|
+
range_ = make_range(range_, loose)
|
|
1173
|
+
|
|
1174
|
+
if hilo == ">":
|
|
1175
|
+
gtfn = gt
|
|
1176
|
+
ltefn = lte
|
|
1177
|
+
ltfn = lt
|
|
1178
|
+
comp = ">"
|
|
1179
|
+
ecomp = ">="
|
|
1180
|
+
elif hilo == "<":
|
|
1181
|
+
gtfn = lt
|
|
1182
|
+
ltefn = gte
|
|
1183
|
+
ltfn = gt
|
|
1184
|
+
comp = "<"
|
|
1185
|
+
ecomp = "<="
|
|
1186
|
+
else:
|
|
1187
|
+
raise ValueError("Must provide a hilo val of '<' or '>'")
|
|
1188
|
+
|
|
1189
|
+
# If it satisfies the range it is not outside
|
|
1190
|
+
if satisfies(version, range_, loose):
|
|
1191
|
+
return False
|
|
1192
|
+
|
|
1193
|
+
# From now on, variable terms are as if we're in "gtr" mode.
|
|
1194
|
+
# but note that everything is flipped for the "ltr" function.
|
|
1195
|
+
for comparators in range_.set:
|
|
1196
|
+
high = None
|
|
1197
|
+
low = None
|
|
1198
|
+
|
|
1199
|
+
for comparator in comparators:
|
|
1200
|
+
high = high or comparator
|
|
1201
|
+
low = low or comparator
|
|
1202
|
+
|
|
1203
|
+
if gtfn(comparator.semver, high.semver, loose):
|
|
1204
|
+
high = comparator
|
|
1205
|
+
elif ltfn(comparator.semver, low.semver, loose):
|
|
1206
|
+
low = comparator
|
|
1207
|
+
|
|
1208
|
+
# If the edge version comparator has a operator then our version
|
|
1209
|
+
# isn't outside it
|
|
1210
|
+
if high.operator == comp or high.operator == ecomp:
|
|
1211
|
+
return False
|
|
1212
|
+
|
|
1213
|
+
# If the lowest version comparator has an operator and our version
|
|
1214
|
+
# is less than it then it isn't higher than the range
|
|
1215
|
+
if (not low.operator or low.operator == comp) and ltefn(version, low.semver): # noqa SIM114
|
|
1216
|
+
return False
|
|
1217
|
+
elif low.operator == ecomp and ltfn(version, low.semver):
|
|
1218
|
+
return False
|
|
1219
|
+
return True
|