Merge ~cjwatson/launchpad:version-lookup-as-text into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 609e834528f76747ca4e8ea7b2121451e74c611c
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:version-lookup-as-text
Merge into: launchpad:master
Prerequisite: ~cjwatson/launchpad:db-xpr-version-text
Diff against target: 368 lines (+114/-28)
10 files modified
lib/lp/registry/model/distributionsourcepackage.py (+1/-1)
lib/lp/registry/model/distroseriesdifference.py (+2/-1)
lib/lp/registry/model/sourcepackage.py (+4/-16)
lib/lp/registry/tests/test_distributionsourcepackage.py (+19/-1)
lib/lp/soyuz/model/archive.py (+7/-4)
lib/lp/soyuz/model/distroarchseriesbinarypackage.py (+2/-1)
lib/lp/soyuz/model/publishing.py (+2/-1)
lib/lp/soyuz/model/queue.py (+2/-1)
lib/lp/soyuz/scripts/gina/handlers.py (+2/-2)
lib/lp/soyuz/tests/test_archive.py (+73/-0)
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+389597@code.launchpad.net

Commit message

Match source/binary versions as exact strings

Description of the change

There is one case in the primary archive of a package (libapache-authznetldap-perl) with both 0.7-4 and 0.07-4 versions, which compare equal according to Debian version comparison rules and thus the debversion type, but are obviously unequal strings. Adjust version-based lookups to match versions as text strings rather than as versions.

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) wrote :

nice set of tests as usual.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/registry/model/distributionsourcepackage.py b/lib/lp/registry/model/distributionsourcepackage.py
2index 9e40f02..da4a021 100644
3--- a/lib/lp/registry/model/distributionsourcepackage.py
4+++ b/lib/lp/registry/model/distributionsourcepackage.py
5@@ -261,7 +261,7 @@ class DistributionSourcePackage(BugTargetBase,
6 SourcePackageRelease.id AND
7 SourcePackagePublishingHistory.sourcepackagename = %s AND
8 SourcePackageRelease.sourcepackagename = %s AND
9- SourcePackageRelease.version = %s
10+ SourcePackageRelease.version::text = %s
11 """ % sqlvalues(self.distribution,
12 self.distribution.all_distro_archive_ids,
13 self.sourcepackagename,
14diff --git a/lib/lp/registry/model/distroseriesdifference.py b/lib/lp/registry/model/distroseriesdifference.py
15index 1735ea6..3cdcd16 100644
16--- a/lib/lp/registry/model/distroseriesdifference.py
17+++ b/lib/lp/registry/model/distroseriesdifference.py
18@@ -23,6 +23,7 @@ import six
19 from sqlobject import StringCol
20 from storm.expr import (
21 And,
22+ Cast,
23 Column,
24 Desc,
25 Or,
26@@ -147,7 +148,7 @@ def most_recent_publications(dsds, in_parent, statuses, match_version=False):
27 conditions,
28 SourcePackageRelease.id ==
29 SourcePackagePublishingHistory.sourcepackagereleaseID,
30- SourcePackageRelease.version == version_col,
31+ Cast(SourcePackageRelease.version, "text") == version_col,
32 )
33 # The sort order is critical so that the DISTINCT ON clause selects the
34 # most recent publication (i.e. the one with the highest id).
35diff --git a/lib/lp/registry/model/sourcepackage.py b/lib/lp/registry/model/sourcepackage.py
36index 42da907..9e40417 100644
37--- a/lib/lp/registry/model/sourcepackage.py
38+++ b/lib/lp/registry/model/sourcepackage.py
39@@ -217,12 +217,11 @@ class SourcePackage(BugTargetBase, HasCodeImportsMixin,
40 return '<%s %r %r %r>' % (self.__class__.__name__,
41 self.distribution, self.distroseries, self.sourcepackagename)
42
43- def _getPublishingHistory(self, version=None, include_status=None,
44- exclude_status=None, order_by=None):
45+ def _getPublishingHistory(self, include_status=None, order_by=None):
46 """Build a query and return a list of SourcePackagePublishingHistory.
47
48 This is mainly a helper function for this class so that code is
49- not duplicated. include_status and exclude_status must be a sequence.
50+ not duplicated. include_status must be a sequence.
51 """
52 clauses = []
53 clauses.append(
54@@ -235,9 +234,6 @@ class SourcePackage(BugTargetBase, HasCodeImportsMixin,
55 self.sourcepackagename,
56 self.distroseries,
57 self.distribution.all_distro_archive_ids))
58- if version:
59- clauses.append(
60- "SourcePackageRelease.version = %s" % sqlvalues(version))
61
62 if include_status:
63 if not isinstance(include_status, list):
64@@ -245,12 +241,6 @@ class SourcePackage(BugTargetBase, HasCodeImportsMixin,
65 clauses.append("SourcePackagePublishingHistory.status IN %s"
66 % sqlvalues(include_status))
67
68- if exclude_status:
69- if not isinstance(exclude_status, list):
70- exclude_status = list(exclude_status)
71- clauses.append("SourcePackagePublishingHistory.status NOT IN %s"
72- % sqlvalues(exclude_status))
73-
74 query = " AND ".join(clauses)
75
76 if not order_by:
77@@ -260,12 +250,10 @@ class SourcePackage(BugTargetBase, HasCodeImportsMixin,
78 query, orderBy=order_by, clauseTables=['SourcePackageRelease'],
79 prejoinClauseTables=['SourcePackageRelease'])
80
81- def _getFirstPublishingHistory(self, version=None, include_status=None,
82- exclude_status=None, order_by=None):
83+ def _getFirstPublishingHistory(self, include_status=None, order_by=None):
84 """As _getPublishingHistory, but just returns the first item."""
85 try:
86- package = self._getPublishingHistory(
87- version, include_status, exclude_status, order_by)[0]
88+ package = self._getPublishingHistory(include_status, order_by)[0]
89 except IndexError:
90 return None
91 else:
92diff --git a/lib/lp/registry/tests/test_distributionsourcepackage.py b/lib/lp/registry/tests/test_distributionsourcepackage.py
93index 15da65e..677d080 100644
94--- a/lib/lp/registry/tests/test_distributionsourcepackage.py
95+++ b/lib/lp/registry/tests/test_distributionsourcepackage.py
96@@ -6,7 +6,10 @@
97 __metaclass__ = type
98
99 from storm.store import Store
100-from testtools.matchers import Equals
101+from testtools.matchers import (
102+ Equals,
103+ MatchesStructure,
104+ )
105 import transaction
106 from zope.component import getUtility
107 from zope.security.proxy import removeSecurityProxy
108@@ -165,6 +168,21 @@ class TestDistributionSourcePackage(TestCaseWithFactory):
109 driver = distribution.drivers[0]
110 self.assertTrue(dsp.personHasDriverRights(driver))
111
112+ def test_getVersion_matches_version_as_text(self):
113+ # Versions such as 0.7-4 and 0.07-4 are equal according to the
114+ # "debversion" type, but for lookup purposes we compare the text of
115+ # the version strings exactly.
116+ distribution = self.factory.makeDistribution()
117+ dsp = self.factory.makeDistributionSourcePackage(
118+ distribution=distribution)
119+ spph = self.factory.makeSourcePackagePublishingHistory(
120+ archive=distribution.main_archive,
121+ sourcepackagename=dsp.sourcepackagename, version="0.7-4")
122+ self.assertThat(dsp.getVersion("0.7-4"), MatchesStructure.byEquality(
123+ distribution=distribution,
124+ sourcepackagerelease=spph.sourcepackagerelease))
125+ self.assertIsNone(dsp.getVersion("0.07-4"))
126+
127
128 class TestDistributionSourcePackageFindRelatedArchives(TestCaseWithFactory):
129
130diff --git a/lib/lp/soyuz/model/archive.py b/lib/lp/soyuz/model/archive.py
131index f5f711b..3217e1d 100644
132--- a/lib/lp/soyuz/model/archive.py
133+++ b/lib/lp/soyuz/model/archive.py
134@@ -26,6 +26,7 @@ from sqlobject import (
135 from storm.base import Storm
136 from storm.expr import (
137 And,
138+ Cast,
139 Count,
140 Desc,
141 Join,
142@@ -656,7 +657,8 @@ class Archive(SQLBase):
143 raise VersionRequiresName(
144 "The 'version' parameter can be used only together with"
145 " the 'name' parameter.")
146- clauses.append(SourcePackageRelease.version == version)
147+ clauses.append(
148+ Cast(SourcePackageRelease.version, "text") == version)
149 elif not order_by_date:
150 order_by.insert(1, Desc(SourcePackageRelease.version))
151
152@@ -854,7 +856,8 @@ class Archive(SQLBase):
153 "The 'version' parameter can be used only together with"
154 " the 'name' parameter.")
155
156- clauses.append(BinaryPackageRelease.version == version)
157+ clauses.append(
158+ Cast(BinaryPackageRelease.version, "text") == version)
159 elif ordered:
160 order_by.insert(1, Desc(BinaryPackageRelease.version))
161
162@@ -1726,7 +1729,7 @@ class Archive(SQLBase):
163 SourcePackageRelease.id,
164 SourcePackageRelease.sourcepackagename == SourcePackageName.id,
165 SourcePackageName.name == name,
166- SourcePackageRelease.version == version,
167+ Cast(SourcePackageRelease.version, "text") == version,
168 SourcePackageRelease.id ==
169 SourcePackageReleaseFile.sourcepackagereleaseID,
170 SourcePackageReleaseFile.libraryfileID == LibraryFileAlias.id,
171@@ -1750,7 +1753,7 @@ class Archive(SQLBase):
172 BinaryPackagePublishingHistory.binarypackagename == name,
173 BinaryPackagePublishingHistory.binarypackagereleaseID ==
174 BinaryPackageRelease.id,
175- BinaryPackageRelease.version == version,
176+ Cast(BinaryPackageRelease.version, "text") == version,
177 BinaryPackageBuild.id == BinaryPackageRelease.buildID,
178 DistroArchSeries.id == BinaryPackageBuild.distro_arch_series_id,
179 DistroArchSeries.architecturetag == archtag,
180diff --git a/lib/lp/soyuz/model/distroarchseriesbinarypackage.py b/lib/lp/soyuz/model/distroarchseriesbinarypackage.py
181index 180a874..a2a92f5 100644
182--- a/lib/lp/soyuz/model/distroarchseriesbinarypackage.py
183+++ b/lib/lp/soyuz/model/distroarchseriesbinarypackage.py
184@@ -9,6 +9,7 @@ __all__ = [
185 'DistroArchSeriesBinaryPackage',
186 ]
187
188+from storm.expr import Cast
189 from storm.locals import Desc
190 from zope.interface import implementer
191
192@@ -120,7 +121,7 @@ class DistroArchSeriesBinaryPackage:
193 """See IDistroArchSeriesBinaryPackage."""
194 bpph = IStore(BinaryPackagePublishingHistory).find(
195 BinaryPackagePublishingHistory,
196- BinaryPackageRelease.version == version,
197+ Cast(BinaryPackageRelease.version, "text") == version,
198 *self._getPublicationJoins()
199 ).order_by(Desc(BinaryPackagePublishingHistory.datecreated)
200 ).first()
201diff --git a/lib/lp/soyuz/model/publishing.py b/lib/lp/soyuz/model/publishing.py
202index 5e6173a..52ffae4 100644
203--- a/lib/lp/soyuz/model/publishing.py
204+++ b/lib/lp/soyuz/model/publishing.py
205@@ -30,6 +30,7 @@ from sqlobject import (
206 )
207 from storm.expr import (
208 And,
209+ Cast,
210 Desc,
211 Join,
212 LeftJoin,
213@@ -1061,7 +1062,7 @@ class PublishingSet:
214 BinaryPackagePublishingHistory.distroarchseriesID == das.id,
215 BinaryPackagePublishingHistory.binarypackagenameID ==
216 bpr.binarypackagenameID,
217- BinaryPackageRelease.version == bpr.version,
218+ Cast(BinaryPackageRelease.version, "text") == bpr.version,
219 )
220
221 candidates = (
222diff --git a/lib/lp/soyuz/model/queue.py b/lib/lp/soyuz/model/queue.py
223index 82e02a9..6465bd8 100644
224--- a/lib/lp/soyuz/model/queue.py
225+++ b/lib/lp/soyuz/model/queue.py
226@@ -23,6 +23,7 @@ from sqlobject import (
227 SQLObjectNotFound,
228 StringCol,
229 )
230+from storm.expr import Cast
231 from storm.locals import (
232 And,
233 Desc,
234@@ -1487,7 +1488,7 @@ class PackageUploadSet:
235 PackageUpload.status.is_in(approved_status),
236 PackageUpload.archive == archive,
237 DistroSeries.distribution == distribution,
238- SourcePackageRelease.version == version,
239+ Cast(SourcePackageRelease.version, "text") == version,
240 SourcePackageName.name == name)
241
242 return conflicts.one()
243diff --git a/lib/lp/soyuz/scripts/gina/handlers.py b/lib/lp/soyuz/scripts/gina/handlers.py
244index 597e5aa..99c8166 100644
245--- a/lib/lp/soyuz/scripts/gina/handlers.py
246+++ b/lib/lp/soyuz/scripts/gina/handlers.py
247@@ -560,7 +560,7 @@ class SourcePackageHandler:
248 # the distribution, no matter what status.
249 query = """
250 SourcePackageRelease.sourcepackagename = %s AND
251- SourcePackageRelease.version = %s AND
252+ SourcePackageRelease.version::text = %s AND
253 SourcePackagePublishingHistory.sourcepackagerelease =
254 SourcePackageRelease.id AND
255 SourcePackagePublishingHistory.distroseries =
256@@ -762,7 +762,7 @@ class BinaryPackageHandler:
257 "BinaryPackageRelease.id ="
258 " BinaryPackagePublishingHistory.binarypackagerelease AND "
259 "BinaryPackageRelease.binarypackagename=%s AND "
260- "BinaryPackageRelease.version=%s AND "
261+ "BinaryPackageRelease.version::text = %s AND "
262 "BinaryPackageRelease.build = BinaryPackageBuild.id AND "
263 "BinaryPackageBuild.distro_arch_series = DistroArchSeries.id AND "
264 "DistroArchSeries.distroseries = DistroSeries.id AND "
265diff --git a/lib/lp/soyuz/tests/test_archive.py b/lib/lp/soyuz/tests/test_archive.py
266index b015953..91acf53 100644
267--- a/lib/lp/soyuz/tests/test_archive.py
268+++ b/lib/lp/soyuz/tests/test_archive.py
269@@ -1565,6 +1565,23 @@ class TestGetBinaryPackageRelease(TestCaseWithFactory):
270 self.factory.makeArchive().getBinaryPackageRelease(
271 self.bpns['foo-bin'], '1.2.3-4', 'i386'))
272
273+ def test_matches_version_as_text(self):
274+ # Versions such as 1.2.3-4 and 1.02.003-4 are equal according to the
275+ # "debversion" type, but for lookup purposes we compare the text of
276+ # the version strings exactly.
277+ other_i386_pub, other_hppa_pub = self.publisher.getPubBinaries(
278+ version='1.02.003-4', archive=self.archive, binaryname='foo-bin',
279+ status=PackagePublishingStatus.PUBLISHED,
280+ architecturespecific=True)
281+ self.assertEqual(
282+ self.i386_pub.binarypackagerelease,
283+ self.archive.getBinaryPackageRelease(
284+ self.bpns['foo-bin'], '1.2.3-4', 'i386'))
285+ self.assertEqual(
286+ other_i386_pub.binarypackagerelease,
287+ self.archive.getBinaryPackageRelease(
288+ self.bpns['foo-bin'], '1.02.003-4', 'i386'))
289+
290
291 class TestGetBinaryPackageReleaseByFileName(TestCaseWithFactory):
292 """Ensure that getBinaryPackageReleaseByFileName works as expected."""
293@@ -2594,6 +2611,28 @@ class TestGetSourceFileByName(TestCaseWithFactory):
294 pub2.source_package_name, pub2.source_package_version,
295 dsc2.filename))
296
297+ def test_matches_version_as_text(self):
298+ # Versions such as 0.7-4 and 0.7-04 are equal according to the
299+ # "debversion" type, but for lookup purposes we compare the text of
300+ # the version strings exactly.
301+ pub = self.factory.makeSourcePackagePublishingHistory(
302+ archive=self.archive, version='0.7-4')
303+ orig = self.factory.makeLibraryFileAlias(
304+ filename='foo_0.7.orig.tar.gz')
305+ pub.sourcepackagerelease.addFile(orig)
306+ pub2 = self.factory.makeSourcePackagePublishingHistory(
307+ archive=self.archive, sourcepackagename=pub.sourcepackagename.name,
308+ version='0.7-04')
309+ orig2 = self.factory.makeLibraryFileAlias(
310+ filename='foo_0.7.orig.tar.gz')
311+ pub2.sourcepackagerelease.addFile(orig2)
312+ self.assertEqual(
313+ orig, self.archive.getSourceFileByName(
314+ pub.sourcepackagename.name, '0.7-4', orig.filename))
315+ self.assertEqual(
316+ orig2, self.archive.getSourceFileByName(
317+ pub.sourcepackagename.name, '0.7-04', orig2.filename))
318+
319
320 class TestGetPublishedSources(TestCaseWithFactory):
321
322@@ -2744,6 +2783,22 @@ class TestGetPublishedSources(TestCaseWithFactory):
323 [pubs[i] for i in (3, 2, 1, 0, 4)],
324 list(archive.getPublishedSources(order_by_date=True)))
325
326+ def test_matches_version_as_text(self):
327+ # Versions such as 0.7-4 and 0.07-4 are equal according to the
328+ # "debversion" type, but for lookup purposes we compare the text of
329+ # the version strings exactly.
330+ archive = self.factory.makeArchive()
331+ pub = self.factory.makeSourcePackagePublishingHistory(
332+ archive=archive, version='0.7-4')
333+ self.assertEqual(
334+ [pub], list(archive.getPublishedSources(
335+ name=pub.sourcepackagename.name, version='0.7-4',
336+ exact_match=True)))
337+ self.assertEqual(
338+ [], list(archive.getPublishedSources(
339+ name=pub.sourcepackagename.name, version='0.07-4',
340+ exact_match=True)))
341+
342
343 class TestGetPublishedSourcesWebService(TestCaseWithFactory):
344
345@@ -3499,6 +3554,24 @@ class TestgetAllPublishedBinaries(TestCaseWithFactory):
346 [pubs[i] for i in (3, 2, 1, 0, 4)],
347 list(archive.getAllPublishedBinaries(order_by_date=True)))
348
349+ def test_matches_version_as_text(self):
350+ # Versions such as 0.7-4 and 0.07-4 are equal according to the
351+ # "debversion" type, but for lookup purposes we compare the text of
352+ # the version strings exactly.
353+ archive = self.factory.makeArchive()
354+ pub = self.factory.makeBinaryPackagePublishingHistory(
355+ archive=archive, version='0.7-4')
356+ self.assertEqual(
357+ [pub],
358+ list(archive.getAllPublishedBinaries(
359+ name=pub.binarypackagename.name, version='0.7-4',
360+ exact_match=True)))
361+ self.assertEqual(
362+ [],
363+ list(archive.getAllPublishedBinaries(
364+ name=pub.binarypackagename.name, version='0.07-4',
365+ exact_match=True)))
366+
367
368 class TestRemovingPermissions(TestCaseWithFactory):
369

Subscribers

People subscribed via source and target branches

to status/vote changes: