You need to sign in or sign up before continuing.
version_recommend.py 27.8 KB
Newer Older
1 2
#!-*- coding:utf-8 -*-

S
Shinwell Hu 已提交
3 4 5
import re
import datetime
import time
L
licihua 已提交
6
from typing import List
S
Shinwell Hu 已提交
7 8 9

__ALL__ = ["VersionRecommend"]

L
licihua 已提交
10 11 12 13 14
class VersionType(object):

    def __init__(self):
        self._version_type = None

S
Shinwell Hu 已提交
15 16 17 18
    def version_match(self, pkg_version):
        pass

    def latest_version(self, version_entry):
L
licihua 已提交
19
        version_entry.sort(reverse=True)
S
Shinwell Hu 已提交
20 21 22
        return version_entry[0]

    def maintain_version(self, version_entry, current_version, pkg_type):
L
licihua 已提交
23
        _ = version_entry, pkg_type
24
        return current_version
S
Shinwell Hu 已提交
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
    def _max(self, z1, z2):
        d1 = tuple(self._split(z1))  # 第一个参数版本号拆分,获取里面的数字/字母,得到序列
        d2 = tuple(self._split(z2))  # 第二个参数版本号拆分,获取里面的数字/字母,得到序列
        len1 = len(d1)
        len2 = len(d2)
        length = min(len1, len2)
        for index in range(length):
            if d1[index].isdigit() and d1[index].isdigit():
                if int(d1[index]) > int(d2[index]):
                    return 1
                elif int(d1[index]) < int(d2[index]):
                    return -1
            else:
                if d1[index] > d2[index]:
                    return 1
                elif d1[index] < d2[index]:
                    return -1
        if len1 > len2:
            return 1
        else:
            return -1

S
Shinwell Hu 已提交
48 49 50
    def get_version_mode(self):
        return self._version_type

51 52 53 54 55 56 57 58 59
    def _split(self, x):
        for f, s in re.findall(r'([\d.]+)|([^\d.]+)', x):
            if f:
                float(f)
                yield f
            else:
                yield s


L
licihua 已提交
60
class VersionTypeXYZW(VersionType):
61

S
Shinwell Hu 已提交
62 63
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
64
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77
        if len(digital_list) != 4:  # 通过 '.'分割后,应该剩下4位
            return False
        if len(digital_list[0]) > 2:  # 第一位版本号不应该大于2位
            return False
        if len(digital_list[1]) > 2:  # 第二位版本号不应该大于2位
            return False
        if len(digital_list[2]) > 3:  # 第三位版本号不应该大于3位
            return False
        if len(digital_list[3]) > 1:  # 第四位版本号不应该大于1位
            return False
        return True

    def maintain_version(self, version_entry, current_version, pkg_type):
L
licihua 已提交
78
        if len(version_entry) == 1:  # 仅一个版本,当前即为最新版本
L
licihua 已提交
79 80 81 82 83 84 85 86
            return version_entry[0]

        version_candidate = []
        version_digital = re.split(r'[._-]', current_version)  # 将版本号做拆分
        xyz = version_digital[0:3]
        for version in version_entry:
            version_temp = re.split(r'[._-]', version)
            if version_digital[0:3] == version_temp[0:3]:  # 如果版本号与当前版本前三位一致,说明是维护分支版本
L
licihua 已提交
87
                version_candidate.append(version_temp)  # 将同特性版本的子版本挑选出来
L
licihua 已提交
88 89 90 91 92 93 94 95 96 97 98

        if len(version_candidate) == 1:
            return '.'.join(version_candidate[0])

        w = '0'
        for version in version_candidate:
            if len(version) <= 3:
                continue

            if self._max(version[3], w) > 0:
                w = version[3]
99

L
licihua 已提交
100 101 102 103
        xyz.append(w)
        return '.'.join(xyz)

    def latest_version(self, version_entry):
L
licihua 已提交
104
        if len(version_entry) == 1:  # 仅一个版本,当前即为最新版本
L
licihua 已提交
105 106
            return version_entry[0]
        version_list = []
S
Shinwell Hu 已提交
107
        for version in version_entry:
L
licihua 已提交
108
            version_list.append(re.split(r'[._-]', version))  # 将 version 拆分为列表,方便后续比较
L
licihua 已提交
109
        x = '0'
L
licihua 已提交
110
        for version in version_list:  # 第一轮比较取出最大的第一位
L
licihua 已提交
111 112 113 114
            if self._max(x, version[0]) < 0:
                x = version[0]

        version_candidate = []
L
licihua 已提交
115
        for version in version_list:  # 将第一位最大的列入候选列表,准备第二位比较
L
licihua 已提交
116 117 118 119 120 121 122 123
            if x == version[0]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        version_list = version_candidate[:]
        y = '0'
L
licihua 已提交
124 125
        for version in version_list:  # 第二轮比较取出最大的第二位
            if len(version) <= 1:  # 过滤仅一位的版本号
L
licihua 已提交
126 127 128 129 130
                continue
            if self._max(y, version[1]) < 0:
                y = version[1]

        version_candidate.clear()
L
licihua 已提交
131
        for version in version_list:  # 将第二位最大的列入候选列表,准备第三位比较
L
licihua 已提交
132 133 134 135 136 137 138 139
            if y == version[1]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        z = '0'
        version_list = version_candidate[:]
L
licihua 已提交
140 141
        for version in version_list:  # 第三轮比较取出最大的第三位
            if len(version) <= 2:  # 过滤仅二位的版本号
L
licihua 已提交
142 143 144 145 146
                continue
            if self._max(z, version[2]) < 0:
                z = version[2]

        version_candidate.clear()
L
licihua 已提交
147 148
        for version in version_list:  # 最后一位最大版本必须惟一,直接返回结果
            if len(version) <= 2:  # 过滤仅二位的版本号
L
licihua 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
                continue
            if z == version[2]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        w = '0'
        version_list = version_candidate[:]
        for version in version_list:  # 最后一位最大版本必须惟一,直接返回结果
            if len(version) <= 3:  # 过滤仅三位的版本号
                continue
            if self._max(w, version[3]) < 0:
                w = version[3]

L
licihua 已提交
164
        for version in version_list:  # 最后一位最大版本必须惟一,直接返回结果
L
licihua 已提交
165 166 167 168 169 170
            if len(version) <= 3:  # 过滤仅三位的版本号
                continue
            if w == version[3]:
                return '.'.join(version)

        return ''
S
Shinwell Hu 已提交
171 172

    def __init__(self):
L
licihua 已提交
173
        super().__init__()
S
Shinwell Hu 已提交
174 175 176
        self._version_type = 'x.y.z.w'


L
licihua 已提交
177 178
class VersionTypeXYZ(VersionType):

S
Shinwell Hu 已提交
179 180
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
181
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
182 183 184 185
        if len(digital_list) != 3:  # 通过 '.'分割后,应该剩下3位
            return False
        if len(digital_list[0]) > 2:  # 第一位版本号不应该大于2位
            return False
L
licihua 已提交
186
        if len(digital_list[1]) > 3:  # 第二位版本号不应该大于3位
S
Shinwell Hu 已提交
187 188 189 190 191 192
            return False
        if len(digital_list[2]) > 3:  # 第三位版本号不应该大于3位
            return False
        return True

    def maintain_version(self, version_entry, current_version, pkg_type):
L
licihua 已提交
193
        if len(version_entry) == 1:  # 仅一个版本,当前即为最新版本
194 195 196
            return version_entry[0]

        version_candidate = []
L
licihua 已提交
197
        version_digital = re.split(r'[._-]', current_version)  # 将版本号做拆分
198
        xy = version_digital[0:2]
S
Shinwell Hu 已提交
199
        for version in version_entry:
L
licihua 已提交
200
            version_temp = re.split(r'[._-]', version)
201
            if version_digital[0:2] == version_temp[0:2]:  # 如果版本号与当前版本前两位一致,说明是维护分支版本
L
licihua 已提交
202
                version_candidate.append(version_temp)  # 将同特性版本的子版本挑选出来
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218

        if len(version_candidate) == 1:
            return '.'.join(version_candidate[0])

        z = '0'
        for version in version_candidate:
            if len(version) <= 2:
                continue

            if self._max(version[2], z) > 0:
                z = version[2]

        xy.append(z)
        return '.'.join(xy)

    def latest_version(self, version_entry):
L
licihua 已提交
219
        if len(version_entry) == 1:  # 仅一个版本,当前即为最新版本
220 221 222
            return version_entry[0]
        version_list = []
        for version in version_entry:
L
licihua 已提交
223
            version_list.append(re.split(r'[._-]', version))  # 将 version 拆分为列表,方便后续比较
224
        x = '0'
L
licihua 已提交
225
        for version in version_list:  # 第一轮比较取出最大的第一位
226 227 228 229
            if self._max(x, version[0]) < 0:
                x = version[0]

        version_candidate = []
L
licihua 已提交
230
        for version in version_list:  # 将第一位最大的列入候选列表,准备第二位比较
231 232 233 234 235 236 237 238
            if x == version[0]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        version_list = version_candidate[:]
        y = '0'
L
licihua 已提交
239 240
        for version in version_list:  # 第二轮比较取出最大的第二位
            if len(version) <= 1:  # 过滤仅一位的版本号
241 242 243
                continue
            if self._max(y, version[1]) < 0:
                y = version[1]
244

245
        version_candidate.clear()
L
licihua 已提交
246
        for version in version_list:  # 将第二位最大的列入候选列表,准备第三位比较
247 248 249 250 251 252 253 254
            if y == version[1]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        z = '0'
        version_list = version_candidate[:]
L
licihua 已提交
255 256
        for version in version_list:  # 第三轮比较取出最大的第三位
            if len(version) <= 2:  # 过滤仅二位的版本号
257 258 259
                continue
            if self._max(z, version[2]) < 0:
                z = version[2]
260

L
licihua 已提交
261
        for version in version_list:  # 最后一位最大版本必须惟一,直接返回结果
262 263 264 265 266 267
            if len(version) <= 2:  # 过滤仅二位的版本号
                continue
            if z == version[2]:
                return '.'.join(version)

        return ''
S
Shinwell Hu 已提交
268 269

    def __init__(self):
L
licihua 已提交
270
        super().__init__()
S
Shinwell Hu 已提交
271 272 273
        self._version_type = 'x.y.z'


L
licihua 已提交
274 275
class VersionTypeXY(VersionType):

S
Shinwell Hu 已提交
276 277
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
278
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
279 280 281 282 283 284 285 286 287
        if len(digital_list) != 2:  # 通过 '.'分割后,应该剩下2位
            return False
        if len(digital_list[0]) > 2:  # 第一位版本号不应该大于2位
            return False
        if len(digital_list[1]) > 3:  # 第二位版本号不应该大于2位
            return False
        return True

    def __init__(self):
L
licihua 已提交
288
        super().__init__()
S
Shinwell Hu 已提交
289 290
        self._version_type = 'x.y'

291
    def latest_version(self, version_entry):
L
licihua 已提交
292
        if len(version_entry) == 1:  # 仅一个版本,当前即为最新版本
293 294 295
            return version_entry[0]
        version_list = []
        for version in version_entry:
L
licihua 已提交
296
            version_list.append(re.split(r'[._-]', version))  # 将 version 拆分为列表,方便后续比较
297
        x = '0'
L
licihua 已提交
298
        for version in version_list:  # 第一轮比较取出最大的第一位
299 300
            if self._max(x, version[0]) < 0:
                x = version[0]
301

302
        version_candidate = []
L
licihua 已提交
303
        for version in version_list:  # 将第一位最大的列入候选列表,准备第二位比较
304 305 306 307 308 309 310 311
            if x == version[0]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        version_list = version_candidate[:]
        y = '0'
L
licihua 已提交
312 313
        for version in version_list:  # 第二轮比较取出最大的第二位
            if len(version) <= 1:  # 过滤仅一位的版本号
314 315 316
                continue
            if self._max(y, version[1]) < 0:
                y = version[1]
317

318
        version_candidate.clear()
L
licihua 已提交
319 320
        for version in version_list:  # x.y 版本类型中会小概率出现三位版本号,需要将第二位最大的列入候选列表,准备第三位比较
            if len(version) <= 1:  # 过滤仅一位的版本号
L
licihua 已提交
321
                continue
322 323 324 325 326 327 328 329
            if y == version[1]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        z = '0'
        version_list = version_candidate[:]
L
licihua 已提交
330 331
        for version in version_list:  # 第三轮比较取出最大的第三位
            if len(version) <= 2:  # 过滤仅二位的版本号
332 333 334 335
                continue
            if self._max(z, version[2]) < 0:
                z = version[2]

L
licihua 已提交
336
        for version in version_list:  # 最后一位最大版本必须惟一,直接返回结果
337 338 339 340 341 342 343 344 345
            if len(version) <= 2:  # 过滤仅二位的版本号
                continue
            if z == version[2]:
                return '.'.join(version)

        return ''

    def maintain_version(self, version_entry, current_version, pkg_type):
        version_candidate = []
L
licihua 已提交
346
        version_digital = re.split(r'[._-]', current_version)  # 将版本号做拆分
L
licihua 已提交
347
        x = [version_digital[0]]
348
        for version in version_entry:
L
licihua 已提交
349
            version_temp = re.split(r'[._-]', version)
350
            if version_digital[0] == version_temp[0]:  # 如果版本号与当前版本前两位一致,说明是维护分支版本
L
licihua 已提交
351
                version_candidate.append(version_temp)  # 将同特性版本的子版本挑选出来
352 353 354 355 356 357 358 359 360 361 362 363 364

        if len(version_candidate) == 1:
            return '.'.join(version_candidate[0])

        y = '0'
        for version in version_candidate[0:]:
            if len(version) <= 1:
                continue

            if self._max(version[1], y) > 0:
                y = version[1]
        x.append(y)
        return '.'.join(x)
S
Shinwell Hu 已提交
365

L
licihua 已提交
366 367 368

class VersionTypeX(VersionType):

S
Shinwell Hu 已提交
369 370
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
371
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
372 373 374 375 376 377
        if len(digital_list) != 1:  # 通过 '.'分割后,应该剩下1位
            return False
        if len(digital_list[0]) > 3:  # 第一位版本号不应该大于3位
            return False
        return True

378
    def latest_version(self, version_entry):
L
licihua 已提交
379
        if 1 == len(version_entry):  # 仅一个版本,当前即为最新版本
380
            return version_entry[0]
L
licihua 已提交
381
        version_list: List[List[str]] = []
382
        for version in version_entry:
L
licihua 已提交
383
            version_list.append(re.split(r'[._-]', version))  # 将 version 拆分为列表,方便后续比较
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
        x = '0'
        for version in version_list:  # 第一轮比较取出最大的第一位
            if self._max(x, version[0]) < 0:
                x = version[0]

        version_candidate = []
        for version in version_list:  # 将第一位最大的列入候选列表,准备第二位比较
            if x == version[0]:
                version_candidate.append(version)

        if len(version_candidate) == 1:  # 仅一个版本,候选即为最新版本
            return '.'.join(version_candidate[0])

        version_list = version_candidate[:]
        y = '0'
        for version in version_list:  # 第二轮比较取出最大的第二位
            if len(version) <= 1:  # 过滤仅一位的版本号
                continue
            if self._max(y, version[1]) < 0:
                y = version[1]

        x.append(y)
        return '.'.join(x)

    def maintain_version(self, version_entry, current_version, pkg_type):
        version_candidate = []
L
licihua 已提交
410
        version_digital = re.split(r'[._-]', current_version)  # 将版本号做拆分
L
licihua 已提交
411
        x = [version_digital[0]]
412
        for version in version_entry:
L
licihua 已提交
413
            version_temp = re.split(r'[._-]', version)
414
            if version_digital[0] == version_temp[0]:  # 如果版本号与当前版本前两位一致,说明是维护分支版本
L
licihua 已提交
415
                version_candidate.append(version_temp)  # 将同特性版本的子版本挑选出来
416 417 418 419 420 421 422 423 424 425 426 427 428

        if len(version_candidate) == 1:
            return '.'.join(version_candidate[0])

        y = '0'
        for version in version_candidate[0:]:
            if len(version) <= 1:
                continue

            if self._max(version[1], y) > 0:
                y = version[1]
        x.append(y)
        return '.'.join(x)
L
licihua 已提交
429

S
Shinwell Hu 已提交
430
    def __init__(self):
L
licihua 已提交
431
        super().__init__()
S
Shinwell Hu 已提交
432 433 434
        self._version_type = 'x'


L
licihua 已提交
435 436
class VersionTypeYyyyXY(VersionType):

S
Shinwell Hu 已提交
437 438
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
439
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
440 441 442 443 444
        if len(digital_list) != 3:  # 通过 '.'分割后,应该剩下3位
            return False

        if len(digital_list[0]) != 4:  # 第一位为发布年份,位数为4位
            return False
L
licihua 已提交
445

S
Shinwell Hu 已提交
446 447 448 449 450 451 452
        year = int(digital_list[0])
        if year < 2000 or year > datetime.datetime.now().year:  # 软件发布时间应该大于2000 年,小于当前时间
            return False

        if len(digital_list[1]) > 2:  # 第二位版本号不应该大于2位
            return False

L
licihua 已提交
453
        if str(int(digital_list[1])) != digital_list[1]:  # 版本类型为数字,且非0 开头
L
licihua 已提交
454 455
            return False

S
Shinwell Hu 已提交
456 457
        if len(digital_list[2]) > 2:  # 第三位版本号不应该大于2位
            return False
L
licihua 已提交
458

L
licihua 已提交
459
        if str(int(digital_list[2])) != digital_list[2]:  # 版本类型为数字,且非0 开头
L
licihua 已提交
460 461
            return False

S
Shinwell Hu 已提交
462 463 464
        return True

    def __init__(self):
L
licihua 已提交
465
        super().__init__()
S
Shinwell Hu 已提交
466 467 468
        self._version_type = 'yyyy.x.y'


L
licihua 已提交
469 470
class VersionTypeYyyyX(VersionType):

S
Shinwell Hu 已提交
471 472
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
473
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487
        if len(digital_list) != 2:  # 通过 '.'分割后,应该剩下2位
            return False

        if len(digital_list[0]) != 4:  # 第一位为发布年份,位数为4位
            return False
        year = int(digital_list[0])
        if year < 2000 or year > datetime.datetime.now().year:  # 软件发布时间应该大于2000 年,小于当前时间
            return False

        if len(digital_list[1]) > 2:  # 第二位版本号不应该大于2位
            return False
        return True

    def __init__(self):
L
licihua 已提交
488
        super().__init__()
S
Shinwell Hu 已提交
489 490 491
        self._version_type = 'yyyy.x'


L
licihua 已提交
492 493
class VersionTypeYyyyW(VersionType):

L
licihua 已提交
494 495 496 497
    def version_match(self, pkg_version):
        version = pkg_version.strip()
        if len(version) != 5:  # 共5 位
            return False
L
licihua 已提交
498
        if not str(version[0:4]).isdigit():  # 前四位为年份数字
L
licihua 已提交
499 500 501 502 503 504 505 506 507
            return False

        year = int(version[0:4])
        if year < 2000 or year > datetime.datetime.now().year:  # 软件发布时间应该大于2000 年,小于当前时间
            return False

        return True

    def __init__(self):
L
licihua 已提交
508
        super().__init__()
L
licihua 已提交
509 510
        self._version_type = 'yyyyw'

L
licihua 已提交
511 512 513

class VersionTypeYyyyMmDd(VersionType):

S
Shinwell Hu 已提交
514 515
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
516
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
        if len(digital_list) != 3:  # 通过 '.'分割后,应该剩下3位
            return False

        if len(digital_list[0]) != 4:  # 第一位为发布年份,位数为4位
            return False

        if int(digital_list[1]) > 12 or int(digital_list[1]) == 0:  # 第二位为发布月份,小于12
            return False

        if int(digital_list[2]) > 31 or int(digital_list[2]) == 0:  # 第三位为发布日期,小于31
            return False

        # 判断日期是否为合法日期
        try:
            if '_' in version:
                d_time = time.mktime(time.strptime(version, "%Y_%m_%d"))
L
licihua 已提交
533
            elif '-' in version:
L
licihua 已提交
534 535
                d_time = time.mktime(time.strptime(version, "%Y-%m-%d"))
            elif '.' in version:
S
Shinwell Hu 已提交
536
                d_time = time.mktime(time.strptime(version, "%Y.%m.%d"))
L
licihua 已提交
537 538
            else:
                return False
S
Shinwell Hu 已提交
539 540 541 542 543 544 545

            now_str = datetime.datetime.now().strftime('%Y-%m-%d')
            end_time = time.mktime(time.strptime(now_str, '%Y-%m-%d'))
            if d_time > end_time:  # 判断日期是否大于当前日期
                return False
            else:
                return True
L
licihua 已提交
546
        except ValueError as e:  # 时间格式非法
S
Shinwell Hu 已提交
547 548 549 550
            print('Time foramt failed %s.', version)
            return False

    def __init__(self):
L
licihua 已提交
551
        super().__init__()
S
Shinwell Hu 已提交
552 553 554
        self._version_type = 'yyyy.mm.dd'


L
licihua 已提交
555 556
class VersionTypeYyyyMm(VersionType):

S
Shinwell Hu 已提交
557 558
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
559
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
        if len(digital_list) != 2:  # 通过 '.'分割后,应该剩下2位
            return False

        if len(digital_list[0]) != 4:  # 第一位为发布年份,位数为4位
            return False
        year = int(digital_list[0])
        if year < 2000 or year > datetime.datetime.now().year:  # 软件发布时间应该大于2000 年,小于当前时间
            return False

        if int(digital_list[1]) > 12 or int(digital_list[1]) == 0:  # 第二位为发布月份,小于12
            return False

        if year == datetime.datetime.now().year and \
                int(digital_list[1]) > datetime.datetime.now().month:
            return False

        return True

    def __init__(self):
L
licihua 已提交
579
        super().__init__()
S
Shinwell Hu 已提交
580 581
        self._version_type = 'yyyy.mm'

L
licihua 已提交
582 583 584

class VersionTypeYyyyMm(VersionType):

585 586
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
587
        if len(version) != 6:  # 长度为6
588 589
            return False

L
licihua 已提交
590
        if not version.isdigit():  # 时间格式为数字
591 592
            return False

L
licihua 已提交
593
        digital_list = [version[0:4], version[4:]]
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610

        if len(digital_list[0]) != 4:  # 第一位为发布年份,位数为4位
            return False
        year = int(digital_list[0])
        if year < 2000 or year > datetime.datetime.now().year:  # 软件发布时间应该大于2000 年,小于当前时间
            return False

        if int(digital_list[1]) > 12 or int(digital_list[1]) == 0:  # 第二位为发布月份,小于12
            return False

        if year == datetime.datetime.now().year and \
                int(digital_list[1]) > datetime.datetime.now().month:
            return False

        return True

    def __init__(self):
L
licihua 已提交
611
        super().__init__()
612
        self._version_type = 'yyyymm'
S
Shinwell Hu 已提交
613

L
licihua 已提交
614 615 616

class VersionTypeXYymmZ(VersionType):

S
Shinwell Hu 已提交
617 618
    def version_match(self, pkg_version):
        version = pkg_version.strip()
L
licihua 已提交
619
        digital_list = re.split(r'[._-]', version)
S
Shinwell Hu 已提交
620 621 622 623 624 625
        if len(digital_list) != 3:  # 通过 '.'分割后,应该剩下3位
            return False

        if len(digital_list[0]) > 2:  # 第一位为主版本号,小于2位
            return False
        # 将年月拆分后分别判断
L
licihua 已提交
626
        if len(digital_list[1]) != 4:  # 年月等于4位
627
            return False
S
Shinwell Hu 已提交
628 629 630 631
        year = str(digital_list[1][:2])
        month = str(digital_list[1][-2:])
        if year > datetime.datetime.now().year[-2:]:  # 年份不能大于当前年份,不用考虑20000 年前的情况
            return False
L
licihua 已提交
632
        if month > '12' or month == '0':
S
Shinwell Hu 已提交
633 634 635 636 637 638
            return False
        if len(digital_list[2]) > 2:  # 迭代号不大于2位
            return False
        return True

    def __init__(self):
L
licihua 已提交
639
        super().__init__()
S
Shinwell Hu 已提交
640 641 642
        self._version_type = 'x.yymm.z'


L
licihua 已提交
643 644
class VersionTypeYyyymmdd(VersionType):

S
Shinwell Hu 已提交
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
    def version_match(self, pkg_version):
        version = pkg_version.strip()
        if len(version) != 8:  # 日期长度满足 8 位要求
            return False
        if not version.isdigit():  # 连续数字,没有其他分别符号
            return False
        digital_list = [version[:4], version[4:6], version[6:]]

        if int(digital_list[1]) > 12 or int(digital_list[1]) == 0:  # 第二位为发布月份,小于12
            return False

        if int(digital_list[2]) > 31 or int(digital_list[2]) == 0:  # 第三位为发布日期,小于31
            return False

        # 判断日期是否为合法日期
        try:
            d_time = time.mktime(time.strptime(version, "%Y%m%d"))
            now_str = datetime.datetime.now().strftime('%Y-%m-%d')
            end_time = time.mktime(time.strptime(now_str, '%Y-%m-%d'))
            if d_time > end_time:  # 判断日期是否大于当前日期
                return False
            else:
                return True
L
licihua 已提交
668
        except ValueError as e:  # 时间格式非法
S
Shinwell Hu 已提交
669 670 671 672
            print('Time format failed %s,', version)
            return False

    def __init__(self):
L
licihua 已提交
673
        super().__init__()
S
Shinwell Hu 已提交
674 675 676
        self._version_type = 'yyyymmdd'


L
licihua 已提交
677
class VersionRecommend(object):
678

S
Shinwell Hu 已提交
679
    def __init__(self, version_entry, current_version, pkg_type):
L
licihua 已提交
680
        self.latest_version = current_version  # 提供初值,避免 current_version 为空导致后面出现异常
L
licihua 已提交
681
        self.maintain_version = current_version
682 683 684 685 686 687
        self.version_type = self._version_match(version_entry)
        if self.version_type is None:
            print('version type is None:', current_version)
            return

        print('version type = ', self.version_type.get_version_mode())
S
Shinwell Hu 已提交
688 689 690
        self.latest_version = self._get_latest_version(version_entry)
        self.maintain_version = self._get_maintain_version(version_entry, current_version, pkg_type)

691 692
    def _version_match(self, version_entry):

L
licihua 已提交
693 694 695 696 697 698 699 700 701 702 703 704
        version_method = {VersionTypeXYZW(): 0,
                          VersionTypeXYZ(): 0,
                          VersionTypeXY(): 0,
                          VersionTypeX(): 0,
                          VersionTypeYyyyXY(): 0,
                          VersionTypeYyyyX(): 0,
                          VersionTypeYyyyW(): 0,
                          VersionTypeYyyyMmDd(): 0,
                          VersionTypeYyyyMm(): 0,
                          VersionTypeYyyyMm(): 0,
                          VersionTypeXYymmZ(): 0,
                          VersionTypeYyyymmdd(): 0}
705 706 707 708
        if not version_entry:
            return None
        for version in version_entry[:]:
            if not self._version_valid(version):
L
licihua 已提交
709
                version_entry.remove(version)  # 删除非法版本号
710 711 712 713 714 715 716
                continue
            for method, count in version_method.items():
                if method.version_match(version):
                    version_method[method] = count + 1

        # 解决多版本类型问题,选取类型最多的作为匹配,这个处理不是最优方案,需要改进
        method = max(version_method, key=lambda x: version_method[x])
L
licihua 已提交
717

718 719 720 721 722 723
        if version_method[method] == 0:
            return None
        else:
            return method

    def _version_valid(self, version):
L
licihua 已提交
724 725
        m = re.match("^[0-9a-zA-Z._-]*$", version)
        if m is None:  # 版本号应该是 数字/小写字母/下划线/. 组成
726 727 728
            return False

        m = re.match('^[0-9].*', version)
L
licihua 已提交
729
        if m is None:  # 版本号应该是数字开头
730 731
            return False

L
licihua 已提交
732 733 734 735 736 737 738 739 740 741
        if 'rc' in version \
                or 'RC' in version \
                or 'dev' in version \
                or 'beta' in version \
                or 'Beta' in version \
                or 'BETA' in version \
                or 'alpha' in version \
                or 'pl' in version \
                or 'pre' in version \
                or 'PRE' in version \
L
licihua 已提交
742
                or 'bp' in version:  # 仅获取正式版本
L
licihua 已提交
743 744 745
            return False

        if 'ubuntu' in version or 'fedora' in version:  # 去掉厂家专用版本号
746 747 748
            return False

        return True
S
Shinwell Hu 已提交
749 750

    def _get_latest_version(self, version_entry):
751 752 753 754
        if self.version_type is None:
            return ''
        else:
            return self.version_type.latest_version(version_entry)
S
Shinwell Hu 已提交
755 756

    def _get_maintain_version(self, version_entry, current_version, pkg_type):
757 758 759 760
        if self.version_type is None:
            return ''
        else:
            return self.version_type.maintain_version(version_entry, current_version, pkg_type)
S
Shinwell Hu 已提交
761 762 763


if __name__ == '__main__':
L
licihua 已提交
764 765
    version_recommend = VersionRecommend(
        ['0.1', '0.2', '1.2.3', '1.2.4', '1.2.6', '1.3.0', '1.5-rc', '2.0-rc'], '1.2.3', 0)
766
    print('latest_version', version_recommend.latest_version)
L
licihua 已提交
767
    print('maintain_version', version_recommend.maintain_version)