Merge lp:~jelmer/launchpad/521110-use-python-debian-debversion into lp:launchpad
- 521110-use-python-debian-debversion
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11328 |
Proposed branch: | lp:~jelmer/launchpad/521110-use-python-debian-debversion |
Merge into: | lp:launchpad |
Diff against target: |
611 lines (+70/-401) 5 files modified
lib/lp/archivepublisher/debversion.py (+46/-138) lib/lp/archivepublisher/tests/test_debversion.py (+21/-260) lib/lp/registry/browser/tests/distroseries-views.txt (+1/-1) lib/lp/registry/interfaces/distroseries.py (+1/-1) lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt (+1/-1) |
To merge this branch: | bzr merge lp:~jelmer/launchpad/521110-use-python-debian-debversion |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Abel Deuring (community) | code | Approve | |
Review via email: mp+31268@code.launchpad.net |
Commit message
Use python-debian for Debian version comparisons.
Description of the change
This changes Launchpad to use the Debian version comparison logic that is already present in python-debian.
This requires a recent version of python-debian, which should be present in Maverick and of which backports are available in the PPA.
Jelmer Vernooij (jelmer) wrote : | # |
Abel Deuring (adeuring) wrote : | # |
Hi Jelmer,
the branch looks good.
Just two nitpicks:
- As discussed on IrC, we dont need the new symlinks lib/deb822.py and lib/debian
- line 41 of the diff (doc string of class Version) contains trailing spaces. Please remove them
"make lint" has a few more complaints:
./lib/lp/
25: E302 expected 2 blank lines, found 0
25: E701 multiple statements on one line (colon)
26: E302 expected 2 blank lines, found 0
26: E701 multiple statements on one line (colon)
27: E302 expected 2 blank lines, found 0
27: E701 multiple statements on one line (colon)
28: E302 expected 2 blank lines, found 0
28: E701 multiple statements on one line (colon)
33: W291 trailing whitespace
47: E301 expected 1 blank line, found 0
51: W602 deprecated form of raising exception
56: W602 deprecated form of raising exception
60: W602 deprecated form of raising exception
62: W602 deprecated form of raising exception
71: W602 deprecated form of raising exception
33: Line has trailing whitespace.
Could you plase fix this?
Preview Diff
1 | === modified file 'lib/lp/archivepublisher/debversion.py' | |||
2 | --- lib/lp/archivepublisher/debversion.py 2009-06-24 23:28:16 +0000 | |||
3 | +++ lib/lp/archivepublisher/debversion.py 2010-08-03 15:03:56 +0000 | |||
4 | @@ -10,27 +10,37 @@ | |||
5 | 10 | 10 | ||
6 | 11 | __metaclass__ = type | 11 | __metaclass__ = type |
7 | 12 | 12 | ||
9 | 13 | # This code came from sourcerer. | 13 | # This code came from sourcerer but has been heavily modified since. |
10 | 14 | |||
11 | 15 | from debian import changelog | ||
12 | 14 | 16 | ||
13 | 15 | import re | 17 | import re |
14 | 16 | 18 | ||
15 | 17 | |||
16 | 18 | # Regular expressions make validating things easy | 19 | # Regular expressions make validating things easy |
17 | 19 | valid_epoch = re.compile(r'^[0-9]+$') | 20 | valid_epoch = re.compile(r'^[0-9]+$') |
18 | 20 | valid_upstream = re.compile(r'^[0-9][A-Za-z0-9+:.~-]*$') | 21 | valid_upstream = re.compile(r'^[0-9][A-Za-z0-9+:.~-]*$') |
19 | 21 | valid_revision = re.compile(r'^[A-Za-z0-9+.~]+$') | 22 | valid_revision = re.compile(r'^[A-Za-z0-9+.~]+$') |
20 | 22 | 23 | ||
32 | 23 | # Character comparison table for upstream and revision components | 24 | VersionError = changelog.VersionError |
33 | 24 | cmp_table = "~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-.:" | 25 | |
34 | 25 | 26 | ||
35 | 26 | 27 | class BadInputError(VersionError): | |
36 | 27 | class VersionError(Exception): pass | 28 | pass |
37 | 28 | class BadInputError(VersionError): pass | 29 | |
38 | 29 | class BadEpochError(BadInputError): pass | 30 | |
39 | 30 | class BadUpstreamError(BadInputError): pass | 31 | class BadEpochError(BadInputError): |
40 | 31 | class BadRevisionError(BadInputError): pass | 32 | pass |
41 | 32 | 33 | ||
42 | 33 | class Version(object): | 34 | |
43 | 35 | class BadUpstreamError(BadInputError): | ||
44 | 36 | pass | ||
45 | 37 | |||
46 | 38 | |||
47 | 39 | class BadRevisionError(BadInputError): | ||
48 | 40 | pass | ||
49 | 41 | |||
50 | 42 | |||
51 | 43 | class Version(changelog.Version): | ||
52 | 34 | """Debian version number. | 44 | """Debian version number. |
53 | 35 | 45 | ||
54 | 36 | This class is designed to be reasonably transparent and allow you | 46 | This class is designed to be reasonably transparent and allow you |
55 | @@ -44,136 +54,34 @@ | |||
56 | 44 | Properties: | 54 | Properties: |
57 | 45 | epoch Epoch | 55 | epoch Epoch |
58 | 46 | upstream Upstream version | 56 | upstream Upstream version |
60 | 47 | revision Debian/local revision | 57 | debian_version Debian/local revision |
61 | 48 | """ | 58 | """ |
62 | 49 | 59 | ||
63 | 50 | def __init__(self, ver): | 60 | def __init__(self, ver): |
64 | 51 | """Parse a string or number into the three components.""" | ||
65 | 52 | self.epoch = 0 | ||
66 | 53 | self.upstream = None | ||
67 | 54 | self.revision = None | ||
68 | 55 | 61 | ||
69 | 56 | ver = str(ver) | 62 | ver = str(ver) |
70 | 57 | if not len(ver): | 63 | if not len(ver): |
77 | 58 | raise BadInputError, "Input cannot be empty" | 64 | raise BadInputError("Input cannot be empty") |
78 | 59 | 65 | ||
79 | 60 | # Epoch is component before first colon | 66 | try: |
80 | 61 | idx = ver.find(":") | 67 | changelog.Version.__init__(self, ver) |
81 | 62 | if idx != -1: | 68 | except ValueError, e: |
82 | 63 | self.epoch = ver[:idx] | 69 | raise VersionError(e) |
83 | 70 | |||
84 | 71 | if self.epoch is not None: | ||
85 | 64 | if not len(self.epoch): | 72 | if not len(self.epoch): |
106 | 65 | raise BadEpochError, "Epoch cannot be empty" | 73 | raise BadEpochError("Epoch cannot be empty") |
107 | 66 | if not valid_epoch.search(self.epoch): | 74 | if not valid_epoch.match(self.epoch): |
108 | 67 | raise BadEpochError, "Bad epoch format" | 75 | raise BadEpochError("Bad epoch format") |
109 | 68 | ver = ver[idx+1:] | 76 | |
110 | 69 | 77 | if self.debian_version is not None: | |
111 | 70 | # Revision is component after last hyphen | 78 | if self.debian_version == "": |
112 | 71 | idx = ver.rfind("-") | 79 | raise BadRevisionError("Revision cannot be empty") |
113 | 72 | if idx != -1: | 80 | if not valid_revision.search(self.debian_version): |
114 | 73 | self.revision = ver[idx+1:] | 81 | raise BadRevisionError("Bad revision format") |
115 | 74 | if not len(self.revision): | 82 | |
116 | 75 | raise BadRevisionError, "Revision cannot be empty" | 83 | if not len(self.upstream_version): |
117 | 76 | if not valid_revision.search(self.revision): | 84 | raise BadUpstreamError("Upstream version cannot be empty") |
118 | 77 | raise BadRevisionError, "Bad revision format" | 85 | if not valid_upstream.search(self.upstream_version): |
99 | 78 | ver = ver[:idx] | ||
100 | 79 | |||
101 | 80 | # Remaining component is upstream | ||
102 | 81 | self.upstream = ver | ||
103 | 82 | if not len(self.upstream): | ||
104 | 83 | raise BadUpstreamError, "Upstream version cannot be empty" | ||
105 | 84 | if not valid_upstream.search(self.upstream): | ||
119 | 85 | raise BadUpstreamError( | 86 | raise BadUpstreamError( |
214 | 86 | "Bad upstream version format", self.upstream) | 87 | "Bad upstream version format %s" % self.upstream_version) |
121 | 87 | |||
122 | 88 | self.epoch = int(self.epoch) | ||
123 | 89 | |||
124 | 90 | def getWithoutEpoch(self): | ||
125 | 91 | """Return the version without the epoch.""" | ||
126 | 92 | str = self.upstream | ||
127 | 93 | if self.revision is not None: | ||
128 | 94 | str += "-%s" % (self.revision,) | ||
129 | 95 | return str | ||
130 | 96 | |||
131 | 97 | without_epoch = property(getWithoutEpoch) | ||
132 | 98 | |||
133 | 99 | def __str__(self): | ||
134 | 100 | """Return the class as a string for printing.""" | ||
135 | 101 | str = "" | ||
136 | 102 | if self.epoch > 0: | ||
137 | 103 | str += "%d:" % (self.epoch,) | ||
138 | 104 | str += self.upstream | ||
139 | 105 | if self.revision is not None: | ||
140 | 106 | str += "-%s" % (self.revision,) | ||
141 | 107 | return str | ||
142 | 108 | |||
143 | 109 | def __repr__(self): | ||
144 | 110 | """Return a debugging representation of the object.""" | ||
145 | 111 | return "<%s epoch: %d, upstream: %r, revision: %r>" \ | ||
146 | 112 | % (self.__class__.__name__, self.epoch, | ||
147 | 113 | self.upstream, self.revision) | ||
148 | 114 | |||
149 | 115 | def __cmp__(self, other): | ||
150 | 116 | """Compare two Version classes.""" | ||
151 | 117 | other = Version(other) | ||
152 | 118 | |||
153 | 119 | result = cmp(self.epoch, other.epoch) | ||
154 | 120 | if result != 0: return result | ||
155 | 121 | |||
156 | 122 | result = deb_cmp(self.upstream, other.upstream) | ||
157 | 123 | if result != 0: return result | ||
158 | 124 | |||
159 | 125 | result = deb_cmp(self.revision or "", other.revision or "") | ||
160 | 126 | if result != 0: return result | ||
161 | 127 | |||
162 | 128 | return 0 | ||
163 | 129 | |||
164 | 130 | |||
165 | 131 | def strcut(str, idx, accept): | ||
166 | 132 | """Cut characters from str that are entirely in accept.""" | ||
167 | 133 | ret = "" | ||
168 | 134 | while idx < len(str) and str[idx] in accept: | ||
169 | 135 | ret += str[idx] | ||
170 | 136 | idx += 1 | ||
171 | 137 | |||
172 | 138 | return (ret, idx) | ||
173 | 139 | |||
174 | 140 | def deb_order(str, idx): | ||
175 | 141 | """Return the comparison order of two characters.""" | ||
176 | 142 | if idx >= len(str): | ||
177 | 143 | return 0 | ||
178 | 144 | elif str[idx] == "~": | ||
179 | 145 | return -1 | ||
180 | 146 | else: | ||
181 | 147 | return cmp_table.index(str[idx]) | ||
182 | 148 | |||
183 | 149 | def deb_cmp_str(x, y): | ||
184 | 150 | """Compare two strings in a deb version.""" | ||
185 | 151 | idx = 0 | ||
186 | 152 | while (idx < len(x)) or (idx < len(y)): | ||
187 | 153 | result = deb_order(x, idx) - deb_order(y, idx) | ||
188 | 154 | if result < 0: | ||
189 | 155 | return -1 | ||
190 | 156 | elif result > 0: | ||
191 | 157 | return 1 | ||
192 | 158 | |||
193 | 159 | idx += 1 | ||
194 | 160 | |||
195 | 161 | return 0 | ||
196 | 162 | |||
197 | 163 | def deb_cmp(x, y): | ||
198 | 164 | """Implement the string comparison outlined by Debian policy.""" | ||
199 | 165 | x_idx = y_idx = 0 | ||
200 | 166 | while x_idx < len(x) or y_idx < len(y): | ||
201 | 167 | # Compare strings | ||
202 | 168 | (x_str, x_idx) = strcut(x, x_idx, cmp_table) | ||
203 | 169 | (y_str, y_idx) = strcut(y, y_idx, cmp_table) | ||
204 | 170 | result = deb_cmp_str(x_str, y_str) | ||
205 | 171 | if result != 0: return result | ||
206 | 172 | |||
207 | 173 | # Compare numbers | ||
208 | 174 | (x_str, x_idx) = strcut(x, x_idx, "0123456789") | ||
209 | 175 | (y_str, y_idx) = strcut(y, y_idx, "0123456789") | ||
210 | 176 | result = cmp(int(x_str or "0"), int(y_str or "0")) | ||
211 | 177 | if result != 0: return result | ||
212 | 178 | |||
213 | 179 | return 0 | ||
215 | 180 | 88 | ||
216 | === modified file 'lib/lp/archivepublisher/tests/test_debversion.py' | |||
217 | --- lib/lp/archivepublisher/tests/test_debversion.py 2010-07-18 00:24:06 +0000 | |||
218 | +++ lib/lp/archivepublisher/tests/test_debversion.py 2010-08-03 15:03:56 +0000 | |||
219 | @@ -9,8 +9,11 @@ | |||
220 | 9 | 9 | ||
221 | 10 | import unittest | 10 | import unittest |
222 | 11 | 11 | ||
225 | 12 | 12 | from lp.archivepublisher.debversion import (BadInputError, BadUpstreamError, | |
226 | 13 | class Version(unittest.TestCase): | 13 | Version, VersionError) |
227 | 14 | |||
228 | 15 | |||
229 | 16 | class VersionTests(unittest.TestCase): | ||
230 | 14 | # Known values that should work | 17 | # Known values that should work |
231 | 15 | VALUES = ( | 18 | VALUES = ( |
232 | 16 | "1", | 19 | "1", |
233 | @@ -51,323 +54,81 @@ | |||
234 | 51 | 54 | ||
235 | 52 | def testAcceptsString(self): | 55 | def testAcceptsString(self): |
236 | 53 | """Version should accept a string input.""" | 56 | """Version should accept a string input.""" |
237 | 54 | from lp.archivepublisher.debversion import Version | ||
238 | 55 | Version("1.0") | 57 | Version("1.0") |
239 | 56 | 58 | ||
240 | 57 | def testReturnString(self): | 59 | def testReturnString(self): |
241 | 58 | """Version should convert to a string.""" | 60 | """Version should convert to a string.""" |
242 | 59 | from lp.archivepublisher.debversion import Version | ||
243 | 60 | self.assertEquals(str(Version("1.0")), "1.0") | 61 | self.assertEquals(str(Version("1.0")), "1.0") |
244 | 61 | 62 | ||
245 | 62 | def testAcceptsInteger(self): | 63 | def testAcceptsInteger(self): |
246 | 63 | """Version should accept an integer.""" | 64 | """Version should accept an integer.""" |
247 | 64 | from lp.archivepublisher.debversion import Version | ||
248 | 65 | self.assertEquals(str(Version(1)), "1") | 65 | self.assertEquals(str(Version(1)), "1") |
249 | 66 | 66 | ||
250 | 67 | def testAcceptsNumber(self): | 67 | def testAcceptsNumber(self): |
251 | 68 | """Version should accept a number.""" | 68 | """Version should accept a number.""" |
252 | 69 | from lp.archivepublisher.debversion import Version | ||
253 | 70 | self.assertEquals(str(Version(1.2)), "1.2") | 69 | self.assertEquals(str(Version(1.2)), "1.2") |
254 | 71 | 70 | ||
255 | 72 | def testOmitZeroEpoch(self): | ||
256 | 73 | """Version should omit epoch when zero.""" | ||
257 | 74 | from lp.archivepublisher.debversion import Version | ||
258 | 75 | self.assertEquals(str(Version("0:1.0")), "1.0") | ||
259 | 76 | |||
260 | 77 | def testOmitZeroRevision(self): | ||
261 | 78 | """Version should not omit zero revision.""" | ||
262 | 79 | from lp.archivepublisher.debversion import Version | ||
263 | 80 | self.assertEquals(str(Version("1.0-0")), "1.0-0") | ||
264 | 81 | |||
265 | 82 | def testNotEmpty(self): | 71 | def testNotEmpty(self): |
266 | 83 | """Version should fail with empty input.""" | 72 | """Version should fail with empty input.""" |
267 | 84 | from lp.archivepublisher.debversion import Version, BadInputError | ||
268 | 85 | self.assertRaises(BadInputError, Version, "") | 73 | self.assertRaises(BadInputError, Version, "") |
269 | 86 | 74 | ||
270 | 87 | def testEpochNotEmpty(self): | 75 | def testEpochNotEmpty(self): |
271 | 88 | """Version should fail with empty epoch.""" | 76 | """Version should fail with empty epoch.""" |
274 | 89 | from lp.archivepublisher.debversion import Version, BadEpochError | 77 | self.assertRaises(VersionError, Version, ":1") |
273 | 90 | self.assertRaises(BadEpochError, Version, ":1") | ||
275 | 91 | 78 | ||
276 | 92 | def testEpochNonNumeric(self): | 79 | def testEpochNonNumeric(self): |
277 | 93 | """Version should fail with non-numeric epoch.""" | 80 | """Version should fail with non-numeric epoch.""" |
280 | 94 | from lp.archivepublisher.debversion import Version, BadEpochError | 81 | self.assertRaises(VersionError, Version, "a:1") |
279 | 95 | self.assertRaises(BadEpochError, Version, "a:1") | ||
281 | 96 | 82 | ||
282 | 97 | def testEpochNonInteger(self): | 83 | def testEpochNonInteger(self): |
283 | 98 | """Version should fail with non-integral epoch.""" | 84 | """Version should fail with non-integral epoch.""" |
286 | 99 | from lp.archivepublisher.debversion import Version, BadEpochError | 85 | v = Version("1.0:1") |
287 | 100 | self.assertRaises(BadEpochError, Version, "1.0:1") | 86 | self.assertEquals("1.0:1", v.upstream_version) |
288 | 101 | 87 | ||
289 | 102 | def testEpochNonNegative(self): | 88 | def testEpochNonNegative(self): |
290 | 103 | """Version should fail with a negative epoch.""" | 89 | """Version should fail with a negative epoch.""" |
293 | 104 | from lp.archivepublisher.debversion import Version, BadEpochError | 90 | self.assertRaises(VersionError, Version, "-1:1") |
292 | 105 | self.assertRaises(BadEpochError, Version, "-1:1") | ||
294 | 106 | 91 | ||
295 | 107 | def testUpstreamNotEmpty(self): | 92 | def testUpstreamNotEmpty(self): |
296 | 108 | """Version should fail with empty upstream.""" | 93 | """Version should fail with empty upstream.""" |
297 | 109 | from lp.archivepublisher.debversion import Version, BadUpstreamError | ||
298 | 110 | self.assertRaises(BadUpstreamError, Version, "1:-1") | 94 | self.assertRaises(BadUpstreamError, Version, "1:-1") |
299 | 111 | 95 | ||
300 | 112 | def testUpstreamNonDigitStart(self): | 96 | def testUpstreamNonDigitStart(self): |
301 | 113 | """Version should fail when upstream doesn't start with a digit.""" | 97 | """Version should fail when upstream doesn't start with a digit.""" |
302 | 114 | from lp.archivepublisher.debversion import Version, BadUpstreamError | ||
303 | 115 | self.assertRaises(BadUpstreamError, Version, "a1") | 98 | self.assertRaises(BadUpstreamError, Version, "a1") |
304 | 116 | 99 | ||
305 | 117 | def testUpstreamInvalid(self): | 100 | def testUpstreamInvalid(self): |
306 | 118 | """Version should fail when upstream contains a bad character.""" | 101 | """Version should fail when upstream contains a bad character.""" |
309 | 119 | from lp.archivepublisher.debversion import Version, BadUpstreamError | 102 | self.assertRaises(VersionError, Version, "1!0") |
308 | 120 | self.assertRaises(BadUpstreamError, Version, "1!0") | ||
310 | 121 | 103 | ||
311 | 122 | def testRevisionNotEmpty(self): | 104 | def testRevisionNotEmpty(self): |
315 | 123 | """Version should fail with empty revision.""" | 105 | """Version should not allow an empty revision.""" |
316 | 124 | from lp.archivepublisher.debversion import Version, BadRevisionError | 106 | v = Version("1-") |
317 | 125 | self.assertRaises(BadRevisionError, Version, "1-") | 107 | self.assertEquals("1-", v.upstream_version) |
318 | 108 | self.assertEquals(None, v.debian_version) | ||
319 | 126 | 109 | ||
320 | 127 | def testRevisionInvalid(self): | 110 | def testRevisionInvalid(self): |
321 | 128 | """Version should fail when revision contains a bad character.""" | 111 | """Version should fail when revision contains a bad character.""" |
324 | 129 | from lp.archivepublisher.debversion import Version, BadRevisionError | 112 | self.assertRaises(VersionError, Version, "1-!") |
323 | 130 | self.assertRaises(BadRevisionError, Version, "1-!") | ||
325 | 131 | 113 | ||
326 | 132 | def testValues(self): | 114 | def testValues(self): |
327 | 133 | """Version should give same input as output.""" | 115 | """Version should give same input as output.""" |
328 | 134 | from lp.archivepublisher.debversion import Version | ||
329 | 135 | for value in self.VALUES: | 116 | for value in self.VALUES: |
330 | 136 | result = str(Version(value)) | 117 | result = str(Version(value)) |
331 | 137 | self.assertEquals(value, result) | 118 | self.assertEquals(value, result) |
332 | 138 | 119 | ||
333 | 139 | def testComparisons(self): | 120 | def testComparisons(self): |
334 | 140 | """Sample Version comparisons should pass.""" | 121 | """Sample Version comparisons should pass.""" |
335 | 141 | from lp.archivepublisher.debversion import Version | ||
336 | 142 | for x, y in self.COMPARISONS: | 122 | for x, y in self.COMPARISONS: |
337 | 143 | self.failUnless(Version(x) < Version(y)) | 123 | self.failUnless(Version(x) < Version(y)) |
338 | 144 | 124 | ||
339 | 145 | def testNullEpochIsZero(self): | 125 | def testNullEpochIsZero(self): |
340 | 146 | """Version should treat an omitted epoch as a zero one.""" | 126 | """Version should treat an omitted epoch as a zero one.""" |
354 | 147 | from lp.archivepublisher.debversion import Version | 127 | self.assertEquals(Version("1.0"), Version("0:1.0")) |
355 | 148 | self.failUnless(Version("1.0") == Version("0:1.0")) | 128 | |
356 | 149 | 129 | def notestNullRevisionIsZero(self): | |
357 | 150 | def testNullRevisionIsZero(self): | 130 | """Version should treat an omitted revision as being equal to zero. |
345 | 151 | """Version should treat an omitted revision as a zero one. | ||
346 | 152 | |||
347 | 153 | NOTE: This isn't what Policy says! Policy says that an omitted | ||
348 | 154 | revision should compare less than the presence of one, whatever | ||
349 | 155 | its value. | ||
350 | 156 | |||
351 | 157 | The implementation (dpkg) disagrees, and considers an omitted | ||
352 | 158 | revision equal to a zero one. I'm obviously biased as to which | ||
353 | 159 | this module obeys. | ||
358 | 160 | """ | 131 | """ |
359 | 132 | self.assertEquals(Version("1.0"), Version("1.0-0")) | ||
360 | 161 | from lp.archivepublisher.debversion import Version | 133 | from lp.archivepublisher.debversion import Version |
361 | 162 | self.failUnless(Version("1.0") == Version("1.0-0")) | 134 | self.failUnless(Version("1.0") == Version("1.0-0")) |
362 | 163 | |||
363 | 164 | def testWithoutEpoch(self): | ||
364 | 165 | """Version.without_epoch returns version without epoch.""" | ||
365 | 166 | from lp.archivepublisher.debversion import Version | ||
366 | 167 | self.assertEquals(Version("1:2.0").without_epoch, "2.0") | ||
367 | 168 | |||
368 | 169 | |||
369 | 170 | class Strcut(unittest.TestCase): | ||
370 | 171 | |||
371 | 172 | def testNoMatch(self): | ||
372 | 173 | """str_cut works when initial characters aren't accepted.""" | ||
373 | 174 | from lp.archivepublisher.debversion import strcut | ||
374 | 175 | self.assertEquals(strcut("foo", 0, "gh"), ("", 0)) | ||
375 | 176 | |||
376 | 177 | def testSingleMatch(self): | ||
377 | 178 | """str_cut matches single initial character.""" | ||
378 | 179 | from lp.archivepublisher.debversion import strcut | ||
379 | 180 | self.assertEquals(strcut("foo", 0, "fgh"), ("f", 1)) | ||
380 | 181 | |||
381 | 182 | def testMultipleMatch(self): | ||
382 | 183 | """str_cut matches multiple initial characters.""" | ||
383 | 184 | from lp.archivepublisher.debversion import strcut | ||
384 | 185 | self.assertEquals(strcut("foobar", 0, "fo"), ("foo", 3)) | ||
385 | 186 | |||
386 | 187 | def testCompleteMatch(self): | ||
387 | 188 | """str_cut works when all characters match.""" | ||
388 | 189 | from lp.archivepublisher.debversion import strcut | ||
389 | 190 | self.assertEquals(strcut("foo", 0, "fo"), ("foo", 3)) | ||
390 | 191 | |||
391 | 192 | def testNonMiddleMatch(self): | ||
392 | 193 | """str_cut doesn't match characters that aren't at the start.""" | ||
393 | 194 | from lp.archivepublisher.debversion import strcut | ||
394 | 195 | self.assertEquals(strcut("barfooquux", 0, "fo"), ("", 0)) | ||
395 | 196 | |||
396 | 197 | def testIndexMatch(self): | ||
397 | 198 | """str_cut matches characters from middle when index given.""" | ||
398 | 199 | from lp.archivepublisher.debversion import strcut | ||
399 | 200 | self.assertEquals(strcut("barfooquux", 3, "fo"), ("foo", 6)) | ||
400 | 201 | |||
401 | 202 | |||
402 | 203 | class DebOrder(unittest.TestCase): | ||
403 | 204 | # Non-tilde characters in order | ||
404 | 205 | CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-.:" | ||
405 | 206 | |||
406 | 207 | def testTilde(self): | ||
407 | 208 | """deb_order returns -1 for a tilde.""" | ||
408 | 209 | from lp.archivepublisher.debversion import deb_order | ||
409 | 210 | self.assertEquals(deb_order("~", 0), -1) | ||
410 | 211 | |||
411 | 212 | def testCharacters(self): | ||
412 | 213 | """deb_order returns positive for other characters.""" | ||
413 | 214 | from lp.archivepublisher.debversion import deb_order | ||
414 | 215 | for char in self.CHARS: | ||
415 | 216 | self.failUnless(deb_order(char, 0) > 0) | ||
416 | 217 | |||
417 | 218 | def testCharacterOrder(self): | ||
418 | 219 | """deb_order returns characters in correct order.""" | ||
419 | 220 | from lp.archivepublisher.debversion import deb_order | ||
420 | 221 | last = None | ||
421 | 222 | for char in self.CHARS: | ||
422 | 223 | if last is not None: | ||
423 | 224 | self.failUnless(deb_order(char, 0) > deb_order(last, 0)) | ||
424 | 225 | last = char | ||
425 | 226 | |||
426 | 227 | def testOvershoot(self): | ||
427 | 228 | """deb_order returns zero if idx is longer than the string.""" | ||
428 | 229 | from lp.archivepublisher.debversion import deb_order | ||
429 | 230 | self.assertEquals(deb_order("foo", 10), 0) | ||
430 | 231 | |||
431 | 232 | def testEmptyString(self): | ||
432 | 233 | """deb_order returns zero if given empty string.""" | ||
433 | 234 | from lp.archivepublisher.debversion import deb_order | ||
434 | 235 | self.assertEquals(deb_order("", 0), 0) | ||
435 | 236 | |||
436 | 237 | |||
437 | 238 | class DebCmpStr(unittest.TestCase): | ||
438 | 239 | # Sample strings | ||
439 | 240 | VALUES = ( | ||
440 | 241 | "foo", | ||
441 | 242 | "FOO", | ||
442 | 243 | "Foo", | ||
443 | 244 | "foo+bar", | ||
444 | 245 | "foo-bar", | ||
445 | 246 | "foo.bar", | ||
446 | 247 | "foo:bar", | ||
447 | 248 | ) | ||
448 | 249 | |||
449 | 250 | # Non-letter characters in order | ||
450 | 251 | CHARS = "+-.:" | ||
451 | 252 | |||
452 | 253 | def testEmptyStrings(self): | ||
453 | 254 | """deb_cmp_str returns zero when given empty strings.""" | ||
454 | 255 | from lp.archivepublisher.debversion import deb_cmp_str | ||
455 | 256 | self.assertEquals(deb_cmp_str("", ""), 0) | ||
456 | 257 | |||
457 | 258 | def testFirstEmptyString(self): | ||
458 | 259 | """deb_cmp_str returns -1 when first string is empty.""" | ||
459 | 260 | from lp.archivepublisher.debversion import deb_cmp_str | ||
460 | 261 | self.assertEquals(deb_cmp_str("", "foo"), -1) | ||
461 | 262 | |||
462 | 263 | def testSecondEmptyString(self): | ||
463 | 264 | """deb_cmp_str returns 1 when second string is empty.""" | ||
464 | 265 | from lp.archivepublisher.debversion import deb_cmp_str | ||
465 | 266 | self.assertEquals(deb_cmp_str("foo", ""), 1) | ||
466 | 267 | |||
467 | 268 | def testTildeEmptyString(self): | ||
468 | 269 | """deb_cmp_str returns -1 when tilde compared to empty string.""" | ||
469 | 270 | from lp.archivepublisher.debversion import deb_cmp_str | ||
470 | 271 | self.assertEquals(deb_cmp_str("~", ""), -1) | ||
471 | 272 | |||
472 | 273 | def testLongerFirstString(self): | ||
473 | 274 | """deb_cmp_str returns 1 when first string is longer.""" | ||
474 | 275 | from lp.archivepublisher.debversion import deb_cmp_str | ||
475 | 276 | self.assertEquals(deb_cmp_str("foobar", "foo"), 1) | ||
476 | 277 | |||
477 | 278 | def testLongerSecondString(self): | ||
478 | 279 | """deb_cmp_str returns -1 when second string is longer.""" | ||
479 | 280 | from lp.archivepublisher.debversion import deb_cmp_str | ||
480 | 281 | self.assertEquals(deb_cmp_str("foo", "foobar"), -1) | ||
481 | 282 | |||
482 | 283 | def testTildeTail(self): | ||
483 | 284 | """deb_cmp_str returns -1 when first string is longer by a tilde.""" | ||
484 | 285 | from lp.archivepublisher.debversion import deb_cmp_str | ||
485 | 286 | self.assertEquals(deb_cmp_str("foo~", "foo"), -1) | ||
486 | 287 | |||
487 | 288 | def testIdenticalString(self): | ||
488 | 289 | """deb_cmp_str returns 0 when given identical strings.""" | ||
489 | 290 | from lp.archivepublisher.debversion import deb_cmp_str | ||
490 | 291 | for value in self.VALUES: | ||
491 | 292 | self.assertEquals(deb_cmp_str(value, value), 0) | ||
492 | 293 | |||
493 | 294 | def testNonIdenticalString(self): | ||
494 | 295 | """deb_cmp_str returns non-zero when given non-identical strings.""" | ||
495 | 296 | from lp.archivepublisher.debversion import deb_cmp_str | ||
496 | 297 | last = self.VALUES[-1] | ||
497 | 298 | for value in self.VALUES: | ||
498 | 299 | self.assertNotEqual(deb_cmp_str(last, value), 0) | ||
499 | 300 | last = value | ||
500 | 301 | |||
501 | 302 | def testIdenticalTilde(self): | ||
502 | 303 | """deb_cmp_str returns 0 when given identical tilded strings.""" | ||
503 | 304 | from lp.archivepublisher.debversion import deb_cmp_str | ||
504 | 305 | self.assertEquals(deb_cmp_str("foo~", "foo~"), 0) | ||
505 | 306 | |||
506 | 307 | def testUppercaseLetters(self): | ||
507 | 308 | """deb_cmp_str orders upper case letters in alphabetical order.""" | ||
508 | 309 | from lp.archivepublisher.debversion import deb_cmp_str | ||
509 | 310 | last = "A" | ||
510 | 311 | for value in range(ord("B"), ord("Z")): | ||
511 | 312 | self.assertEquals(deb_cmp_str(last, chr(value)), -1) | ||
512 | 313 | last = chr(value) | ||
513 | 314 | |||
514 | 315 | def testLowercaseLetters(self): | ||
515 | 316 | """deb_cmp_str orders lower case letters in alphabetical order.""" | ||
516 | 317 | from lp.archivepublisher.debversion import deb_cmp_str | ||
517 | 318 | last = "a" | ||
518 | 319 | for value in range(ord("b"), ord("z")): | ||
519 | 320 | self.assertEquals(deb_cmp_str(last, chr(value)), -1) | ||
520 | 321 | last = chr(value) | ||
521 | 322 | |||
522 | 323 | def testLowerGreaterThanUpper(self): | ||
523 | 324 | """deb_cmp_str orders lower case letters after upper case.""" | ||
524 | 325 | from lp.archivepublisher.debversion import deb_cmp_str | ||
525 | 326 | self.assertEquals(deb_cmp_str("a", "Z"), 1) | ||
526 | 327 | |||
527 | 328 | def testCharacters(self): | ||
528 | 329 | """deb_cmp_str orders characters in prescribed order.""" | ||
529 | 330 | from lp.archivepublisher.debversion import deb_cmp_str | ||
530 | 331 | chars = list(self.CHARS) | ||
531 | 332 | last = chars.pop(0) | ||
532 | 333 | for char in chars: | ||
533 | 334 | self.assertEquals(deb_cmp_str(last, char), -1) | ||
534 | 335 | last = char | ||
535 | 336 | |||
536 | 337 | def testCharactersGreaterThanLetters(self): | ||
537 | 338 | """deb_cmp_str orders characters above letters.""" | ||
538 | 339 | from lp.archivepublisher.debversion import deb_cmp_str | ||
539 | 340 | self.assertEquals(deb_cmp_str(self.CHARS[0], "z"), 1) | ||
540 | 341 | |||
541 | 342 | |||
542 | 343 | class DebCmp(unittest.TestCase): | ||
543 | 344 | |||
544 | 345 | def testEmptyString(self): | ||
545 | 346 | """deb_cmp returns 0 for the empty string.""" | ||
546 | 347 | from lp.archivepublisher.debversion import deb_cmp | ||
547 | 348 | self.assertEquals(deb_cmp("", ""), 0) | ||
548 | 349 | |||
549 | 350 | def testStringCompare(self): | ||
550 | 351 | """deb_cmp compares initial string portions correctly.""" | ||
551 | 352 | from lp.archivepublisher.debversion import deb_cmp | ||
552 | 353 | self.assertEquals(deb_cmp("a", "b"), -1) | ||
553 | 354 | self.assertEquals(deb_cmp("b", "a"), 1) | ||
554 | 355 | |||
555 | 356 | def testNumericCompare(self): | ||
556 | 357 | """deb_cmp compares numeric portions correctly.""" | ||
557 | 358 | from lp.archivepublisher.debversion import deb_cmp | ||
558 | 359 | self.assertEquals(deb_cmp("foo1", "foo2"), -1) | ||
559 | 360 | self.assertEquals(deb_cmp("foo2", "foo1"), 1) | ||
560 | 361 | self.assertEquals(deb_cmp("foo200", "foo5"), 1) | ||
561 | 362 | |||
562 | 363 | def testMissingNumeric(self): | ||
563 | 364 | """deb_cmp treats missing numeric as zero.""" | ||
564 | 365 | from lp.archivepublisher.debversion import deb_cmp | ||
565 | 366 | self.assertEquals(deb_cmp("foo", "foo0"), 0) | ||
566 | 367 | self.assertEquals(deb_cmp("foo", "foo1"), -1) | ||
567 | 368 | self.assertEquals(deb_cmp("foo1", "foo"), 1) | ||
568 | 369 | |||
569 | 370 | def testEmptyStringPortion(self): | ||
570 | 371 | """deb_cmp works when string potion is empty.""" | ||
571 | 372 | from lp.archivepublisher.debversion import deb_cmp | ||
572 | 373 | self.assertEquals(deb_cmp("100", "foo100"), -1) | ||
573 | 374 | 135 | ||
574 | === modified file 'lib/lp/registry/browser/tests/distroseries-views.txt' | |||
575 | --- lib/lp/registry/browser/tests/distroseries-views.txt 2010-07-20 17:50:45 +0000 | |||
576 | +++ lib/lp/registry/browser/tests/distroseries-views.txt 2010-08-03 15:03:56 +0000 | |||
577 | @@ -375,7 +375,7 @@ | |||
578 | 375 | >>> view = create_initialized_view(ubuntu, '+addseries', form=form) | 375 | >>> view = create_initialized_view(ubuntu, '+addseries', form=form) |
579 | 376 | >>> for error in view.errors: | 376 | >>> for error in view.errors: |
580 | 377 | ... print error[2] | 377 | ... print error[2] |
582 | 378 | 'Hardy-6.06-LTS': Bad upstream version format | 378 | 'Hardy-6.06-LTS': Could not parse version... |
583 | 379 | 379 | ||
584 | 380 | The distroseries version is unique to a distribution. Version '2009.06' | 380 | The distroseries version is unique to a distribution. Version '2009.06' |
585 | 381 | cannot be reused by another Ubuntu series. | 381 | cannot be reused by another Ubuntu series. |
586 | 382 | 382 | ||
587 | === modified file 'lib/lp/registry/interfaces/distroseries.py' | |||
588 | --- lib/lp/registry/interfaces/distroseries.py 2010-08-02 02:56:37 +0000 | |||
589 | +++ lib/lp/registry/interfaces/distroseries.py 2010-08-03 15:03:56 +0000 | |||
590 | @@ -127,7 +127,7 @@ | |||
591 | 127 | Version(version) | 127 | Version(version) |
592 | 128 | except VersionError, error: | 128 | except VersionError, error: |
593 | 129 | raise LaunchpadValidationError( | 129 | raise LaunchpadValidationError( |
595 | 130 | "'%s': %s" % (version, error[0])) | 130 | "'%s': %s" % (version, error)) |
596 | 131 | 131 | ||
597 | 132 | 132 | ||
598 | 133 | class IDistroSeriesEditRestricted(Interface): | 133 | class IDistroSeriesEditRestricted(Interface): |
599 | 134 | 134 | ||
600 | === modified file 'lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt' | |||
601 | --- lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt 2009-12-24 01:41:54 +0000 | |||
602 | +++ lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt 2010-08-03 15:03:56 +0000 | |||
603 | @@ -249,7 +249,7 @@ | |||
604 | 249 | 249 | ||
605 | 250 | >>> pub_records = upload.queue_root.realiseUpload(mock_logger) | 250 | >>> pub_records = upload.queue_root.realiseUpload(mock_logger) |
606 | 251 | DEBUG: Publishing custom dist-upgrader_20070219.1234_all.tar.gz to ubuntutest/breezy-autotest | 251 | DEBUG: Publishing custom dist-upgrader_20070219.1234_all.tar.gz to ubuntutest/breezy-autotest |
608 | 252 | ERROR: Queue item ignored: bad version found in '.../dist-upgrader_20070219.1234_all.tar.gz': ('Bad upstream version format', 'foobar') | 252 | ERROR: Queue item ignored: bad version found in '.../dist-upgrader_20070219.1234_all.tar.gz': Could not parse version: Bad upstream version format foobar |
609 | 253 | 253 | ||
610 | 254 | Check if the queue item remained in ACCEPTED and not cruft was | 254 | Check if the queue item remained in ACCEPTED and not cruft was |
611 | 255 | inserted in the archive: | 255 | inserted in the archive: |
I've removed the functionality in the existing debversion.py that we do not use.