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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 | import copy
import pytest
from debian.debian_support import NativeVersion as Version
def _decompose_version_string(version_string):
"""Return the "Ubuntu"-relevant parts of a version string
Returns a 3-tuple of (prefix_parts, ubuntu_maj, ubuntu_min), throwing away
some information.
prefix_parts is a list of separated string parts forming the first
"non-Ubuntu" part of the string, to which Ubuntu-specific version parts
might be appended. This excludes any "build" and subsequent parts, as they
are not relevant to version bumping. This also excludes any "ubuntu" and
subseqent parts, as the necessary information there is encoded using
ubuntu_maj and ubuntu_min instead.
ubuntu_maj is the "major" Ubuntu version number as an integer, or None if
not present. For example, in the version strings "1.0-2ubuntu3" and
"1.0-2ubuntu3.4", 3 is the major Ubuntu version number in both cases. In
"1.0-2", the major Ubuntu version number is not present.
ubuntu_min is the "minor" Ubuntu version number as an integer, or None if
not present. For example, in the version strings "1.0-2ubuntu3.4", 4 is the
Ubuntu minor version number. In both "1.0-2" and "1.0-2ubuntu3", the minor
Ubuntu version number is not present.
For version strings not following these standard forms, the result is
undefined except where specific test cases exist for them.
"""
parts = [
part
for part in
Version.re_all_digits_or_not.findall(version_string)
]
if 'build' in parts and 'ubuntu' in parts:
raise ValueError("Not sure how to decompose %s" % version_string)
elif 'build' in parts:
return parts[:parts.index('build')], None, None
elif 'ubuntu' in parts:
ubuntu_idx = parts.index('ubuntu')
static_parts = parts[:ubuntu_idx]
suffix_parts = parts[ubuntu_idx+1:]
try:
ubuntu_maj = int(suffix_parts[0])
except IndexError:
# nothing after "Xubuntu", treated as 1
ubuntu_maj = 1
if len(suffix_parts) < 2:
ubuntu_min = None
else:
try:
ubuntu_min = int(suffix_parts[-1])
except ValueError:
ubuntu_min = None
return static_parts, ubuntu_maj, ubuntu_min
else:
return parts, None, None
def _bump_version_object(old_version_object, bump_function):
"""Return a new Version object with the correct attribute bumped
Native packages need to have their debian_version bumped; conversely
non-native packages need to have their upstream_version bumped with their
debian_version staying the same. The bumping mechanism is the same either
way. This function handles this by working out which is needed, calling
bump_function with the old version string to return a bumped attribute
string, and creating a new Version object with the required attributed
bumped accordingly.
"""
if old_version_object.debian_version is None:
bump_attr = 'upstream_version'
else:
bump_attr = 'debian_version'
old_version_string = getattr(old_version_object, bump_attr)
new_version_string = bump_function(old_version_string)
new_version_object = copy.deepcopy(old_version_object)
setattr(new_version_object, bump_attr, new_version_string)
return new_version_object
def _bump_development_version_string(version):
static_parts, old_ubuntu_maj, _ = _decompose_version_string(version)
new_ubuntu_maj = 1 if old_ubuntu_maj is None else old_ubuntu_maj + 1
new_parts = static_parts + ['ubuntu', str(new_ubuntu_maj)]
return ''.join(new_parts)
def _bump_sru_version_string(version, series=None):
static_parts, old_maj, old_min = _decompose_version_string(version)
new_maj = 0 if old_maj is None else old_maj
new_min = 1 if old_min is None else old_min + 1
bumped_parts = ['ubuntu', str(new_maj), '.']
if series:
bumped_parts.extend([series, '.'])
bumped_parts.append(str(new_min))
return ''.join(static_parts + bumped_parts)
def next_development_version(version):
return _bump_version_object(version, _bump_development_version_string)
def next_sru_version(before, series, unapproved, after):
return _bump_version_object(unapproved, _bump_sru_version_string)
@pytest.mark.parametrize('test_input, expected', [
('2', (['2'], None, None)),
('2ubuntu1', (['2'], 1, None)),
('2ubuntu1.3', (['2'], 1, 3)),
('2ubuntu0.16.04.3', (['2'], 0, 3)),
('2build1', (['2'], None, None)),
('2build1.3', (['2'], None, None)),
])
def test_decompose_version_string(test_input, expected):
assert _decompose_version_string(test_input) == expected
@pytest.mark.parametrize('test_input, expected', [
('1.0-2', '1.0-2ubuntu1'),
('1.0-2ubuntu1', '1.0-2ubuntu2'),
('1.0-2ubuntu1.3', '1.0-2ubuntu2'),
('1.0-2ubuntu2', '1.0-2ubuntu3'),
('1.0-2build1', '1.0-2ubuntu1'),
('1', '1ubuntu1'),
('1ubuntu2', '1ubuntu3'),
('1.0-3ubuntu', '1.0-3ubuntu2'),
])
def test_next_development_version(test_input, expected):
assert next_development_version(Version(test_input)) == expected
@pytest.mark.parametrize('before, series, unapproved, after, expected', [
([], '16.04', '1.0-1', [], '1.0-1ubuntu0.1'),
(['1.0-1'], '16.04', '1.0-1', [], '1.0-1ubuntu0.16.04.1'),
])
def test_next_sru_version(before, series, unapproved, after, expected):
assert next_sru_version(
before=[Version(vstr) for vstr in before],
series=series,
unapproved=Version(unapproved),
after=[Version(vstr) for vstr in after],
) == expected
|