Merge lp:~wgrant/launchpad/refactor-_dominateBinary into lp:launchpad

Proposed by William Grant
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 11181
Proposed branch: lp:~wgrant/launchpad/refactor-_dominateBinary
Merge into: lp:launchpad
Diff against target: 753 lines (+184/-226)
9 files modified
lib/lp/archivepublisher/domination.py (+49/-179)
lib/lp/archivepublisher/tests/test_dominator.py (+13/-15)
lib/lp/registry/doc/distroseries.txt (+3/-3)
lib/lp/soyuz/doc/archive.txt (+2/-7)
lib/lp/soyuz/doc/distroarchseries.txt (+2/-3)
lib/lp/soyuz/doc/publishing.txt (+2/-10)
lib/lp/soyuz/interfaces/publishing.py (+19/-6)
lib/lp/soyuz/model/publishing.py (+91/-1)
lib/lp/soyuz/scripts/ftpmaster.py (+3/-2)
To merge this branch: bzr merge lp:~wgrant/launchpad/refactor-_dominateBinary
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+29667@code.launchpad.net

Commit message

Move per-publication Dominator logic into the model.

Description of the change

This branch shuffles lots of logic from lp.archivepublisher into the model. The diff is horrific, I admit, but the files have ended up much cleaner than before.

Package domination is currently performed by lp.archivepublisher.domination.Dominator. It finds a list of domination candidates, then calls its _dominateSource and _dominateBinary methods to supersede each publication. But there's a a method for that purpose on IPublishing, which I(Source|Binary)PackagePublishingHistory inherit: IPublishing.supersede. Sadly, this method is only used in tests, and doesn't encapsulate the full functionality required to replace _dominateBinary and _dominateSource.

This branch moves the logic from _dominateBinary and _dominateSource into [SB]PPH.supersede, letting Dominator just identify candidates and call a single method on each to let them handle themselves.

SPPH.supersede is simple: it checks that the publication can be superseded, then calls the base method (setting datesuperseded and status), and sets supersededby if a dominant publication is provided.

BPPH.supersede does the same, but also incorporates additional functionality from _dominateBinar*ies*: the atomic arch-indep domination behaviour. As described in bug #48760, this requires that if an architecture-independent publication is superseded, it should immediately supersede the corresponding publications on every other architecture. This is implemented by moving Dominator._getOtherBinaryPublications to BPPH._getOtherPublications, and superseding publications found by it. With that behaviour encapsulated in the model, the Dominator code ends up much cleaner.

With all that code ripped out into the model, some duplication was revealed in Dominator. A couple of methods had distinct source and binary versions, with only simple attribute name differences. I've merged them by passing around a couple of attrgetters. Not pretty, but better than duplicating the code.

All this brings huge potential for test cleanups. But this branch is big enough, so another (slightly oversized) test rewrite branch follows.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

your VWS in supersede doesn't really gel for me - please remove or comment

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/archivepublisher/domination.py'
--- lib/lp/archivepublisher/domination.py 2010-05-18 10:30:12 +0000
+++ lib/lp/archivepublisher/domination.py 2010-07-20 09:44:57 +0000
@@ -52,9 +52,12 @@
5252
53__all__ = ['Dominator']53__all__ = ['Dominator']
5454
55import apt_pkg
56from datetime import timedelta55from datetime import timedelta
56import functools
57import gc57import gc
58import operator
59
60import apt_pkg
5861
59from lp.archivepublisher import ELIGIBLE_DOMINATION_STATES62from lp.archivepublisher import ELIGIBLE_DOMINATION_STATES
60from canonical.database.constants import UTC_NOW63from canonical.database.constants import UTC_NOW
@@ -73,38 +76,23 @@
73 clear_current_connection_cache()76 clear_current_connection_cache()
74 gc.collect()77 gc.collect()
7578
76PENDING = PackagePublishingStatus.PENDING
77PUBLISHED = PackagePublishingStatus.PUBLISHED
78SUPERSEDED = PackagePublishingStatus.SUPERSEDED
79DELETED = PackagePublishingStatus.DELETED
80OBSOLETE = PackagePublishingStatus.OBSOLETE
8179
82# Ugly, but works80# Ugly, but works
83apt_pkg.InitSystem()81apt_pkg.InitSystem()
8482
85def _compare_source_packages_by_version_and_date(p1, p2):83
86 """Compare packages p1 and p2 by their version; using Debian rules.84def _compare_packages_by_version_and_date(get_release, p1, p2):
8785 """Compare publications p1 and p2 by their version; using Debian rules.
88 If the comparison is the same sourcepackagerelease, compare by datecreated86
89 instead. So later records beat earlier ones.87 If the publications are for the same package, compare by datecreated
90 """88 instead. This lets newer records win.
91 if p1.sourcepackagerelease.id == p2.sourcepackagerelease.id:89 """
92 return cmp(p1.datecreated, p2.datecreated)90 if get_release(p1).id == get_release(p2).id:
9391 return cmp(p1.datecreated, p2.datecreated)
94 return apt_pkg.VersionCompare(p1.sourcepackagerelease.version,92
95 p2.sourcepackagerelease.version)93 return apt_pkg.VersionCompare(get_release(p1).version,
9694 get_release(p2).version)
97def _compare_binary_packages_by_version_and_date(p1, p2):95
98 """Compare packages p1 and p2 by their version; using Debian rules
99
100 If the comparison is the same binarypackagerelease, compare by datecreated
101 instead. So later records beat earlier ones.
102 """
103 if p1.binarypackagerelease.id == p2.binarypackagerelease.id:
104 return cmp(p1.datecreated, p2.datecreated)
105
106 return apt_pkg.VersionCompare(p1.binarypackagerelease.version,
107 p2.binarypackagerelease.version)
10896
109class Dominator:97class Dominator:
110 """ Manage the process of marking packages as superseded.98 """ Manage the process of marking packages as superseded.
@@ -123,131 +111,22 @@
123 self.archive = archive111 self.archive = archive
124 self.debug = self._logger.debug112 self.debug = self._logger.debug
125113
126 def _dominateSource(self, sourceinput):114 def _dominatePublications(self, pubs):
127 """115 """Perform dominations for the given publications.
128 Perform dominations for source.116
129 """117 :param pubs: A dict mapping names to a list of publications. Every
130 self.debug("Dominating sources...")118 publication must be PUBLISHED or PENDING, and the first in each
131 for sourcename in sourceinput.keys():119 list will be treated as dominant (so should be the latest).
132 # source is a list of versions ordered most-recent-first120 """
133 # basically skip the first entry because that is121 self.debug("Dominating packages...")
134 # never dominated by us, then just set subsequent entries122
135 # to SUPERSEDED unless they're already there or pending123 for name in pubs.keys():
136 # removal124 assert pubs[name], (
137 assert sourceinput[sourcename], (125 "Empty list of publications for %s" % name)
138 "Empty list of publications for %s" % sourcename)126 for pubrec in pubs[name][1:]:
139 super_release = sourceinput[sourcename][0].sourcepackagerelease127 pubrec.supersede(pubs[name][0], self)
140 super_release_name = super_release.sourcepackagename.name128
141 for pubrec in sourceinput[sourcename][1:]:129 def _sortPackages(self, pkglist, is_source=True):
142 if pubrec.status == PUBLISHED or pubrec.status == PENDING:
143 this_release = pubrec.sourcepackagerelease
144
145 this_release_name = this_release.sourcepackagename.name
146 self.debug(
147 "%s/%s has been judged as superseded by %s/%s" %
148 (this_release_name, this_release.version,
149 super_release_name, super_release.version))
150
151 pubrec.status = SUPERSEDED
152 pubrec.datesuperseded = UTC_NOW
153 pubrec.supersededby = super_release
154
155 def _getOtherBinaryPublications(self, dominated):
156 """Return remaining publications of the same binarypackagerelease.
157
158 It only considers binary publications in the same distroseries,
159 pocket and archive context, which is the limit where the domination
160 should happen.
161
162 Return only binaries published or pending in the same component,
163 section and priority, this way the just-made override will be
164 preserved.
165 """
166 # Avoid circular imports.
167 from lp.soyuz.model.publishing import (
168 BinaryPackagePublishingHistory)
169
170 dominated_series = dominated.distroarchseries.distroseries
171 available_architectures = [
172 das.id for das in dominated_series.architectures]
173 query = """
174 BinaryPackagePublishingHistory.status IN %s AND
175 BinaryPackagePublishingHistory.distroarchseries IN %s AND
176 BinaryPackagePublishingHistory.binarypackagerelease = %s AND
177 BinaryPackagePublishingHistory.pocket = %s AND
178 BinaryPackagePublishingHistory.archive = %s AND
179 BinaryPackagePublishingHistory.component = %s AND
180 BinaryPackagePublishingHistory.section = %s AND
181 BinaryPackagePublishingHistory.priority = %s
182 """ % sqlvalues([PUBLISHED, PENDING], available_architectures,
183 dominated.binarypackagerelease, dominated.pocket,
184 dominated.archive, dominated.component,
185 dominated.section, dominated.priority)
186 return BinaryPackagePublishingHistory.select(query)
187
188 def _dominateBinary(self, dominated, dominant):
189 """Dominate the given binarypackagerelease publication."""
190 # At this point only PUBLISHED (ancient versions) or PENDING (
191 # multiple overrides/copies) publications should be given. We
192 # tolerate SUPERSEDED architecture-independent binaries, because
193 # they are dominated automatically once the first publication is
194 # processed.
195 if dominated.status not in [PUBLISHED, PENDING]:
196 arch_independent = (
197 dominated.binarypackagerelease.architecturespecific == False)
198 assert arch_independent, (
199 "Should not dominate unpublished architecture specific "
200 "binary %s (%s)" % (
201 dominated.binarypackagerelease.title,
202 dominated.distroarchseries.architecturetag))
203 return
204
205 dominant_build = dominant.binarypackagerelease.build
206 distroarchseries = dominant_build.distro_arch_series
207 self.debug(
208 "The %s build of %s has been judged as superseded by the build "
209 "of %s. Arch-specific == %s" % (
210 distroarchseries.architecturetag,
211 dominated.binarypackagerelease.title,
212 dominant.binarypackagerelease.build.source_package_release.title,
213 dominated.binarypackagerelease.architecturespecific))
214 dominated.status = SUPERSEDED
215 dominated.datesuperseded = UTC_NOW
216 # Binary package releases are superseded by the new build,
217 # not the new binary package release. This is because
218 # there may not *be* a new matching binary package -
219 # source packages can change the binaries they build
220 # between releases.
221 dominated.supersededby = dominant_build
222
223 def _dominateBinaries(self, binaryinput):
224 """Perform dominations for binaries."""
225 self.debug("Dominating binaries...")
226 for binaryname in binaryinput.keys():
227 # binary is a list of versions ordered most-recent-first
228 # basically skip the first entry because that is
229 # never dominated by us, then just set subsequent entries
230 # to SUPERSEDED unless they're already there or pending
231 # removal
232 assert binaryinput[binaryname], (
233 "Empty list of publications for %s" % binaryname)
234 # At some future point, this code might automatically locate
235 # binaries which are no longer built from source (NBS).
236 # Currently this is done in archive cruft check.
237 dominant = binaryinput[binaryname][0]
238 for dominated in binaryinput[binaryname][1:]:
239 # Dominate all publications of architecture independent
240 # binaries altogether in this distroseries and pocket.
241 if not dominated.binarypackagerelease.architecturespecific:
242 other_publications = self._getOtherBinaryPublications(
243 dominated)
244 for dominated in other_publications:
245 self._dominateBinary(dominated, dominant)
246 else:
247 self._dominateBinary(dominated, dominant)
248
249
250 def _sortPackages(self, pkglist, isSource=True):
251 # pkglist is a list of packages with the following130 # pkglist is a list of packages with the following
252 # * sourcepackagename or packagename as appropriate131 # * sourcepackagename or packagename as appropriate
253 # * version132 # * version
@@ -255,32 +134,22 @@
255 # Don't care about any other attributes134 # Don't care about any other attributes
256 outpkgs = {}135 outpkgs = {}
257136
258 if isSource:137 self.debug("Sorting packages...")
259 self.debug("Sorting sources...")138
260 else:139 attr_prefix = 'source' if is_source else 'binary'
261 self.debug("Sorting binaries...")140 get_release = operator.attrgetter(attr_prefix + 'packagerelease')
141 get_name = operator.attrgetter(attr_prefix + 'packagename')
262142
263 for inpkg in pkglist:143 for inpkg in pkglist:
264 if isSource:144 L = outpkgs.setdefault(
265 L = outpkgs.setdefault(145 get_name(get_release(inpkg)).name.encode('utf-8'), [])
266 inpkg.sourcepackagerelease.sourcepackagename.name.encode(
267 'utf-8'), [])
268 else:
269 L = outpkgs.setdefault(
270 inpkg.binarypackagerelease.binarypackagename.name.encode(
271 'utf-8'), [])
272
273 L.append(inpkg)146 L.append(inpkg)
274147
275 for pkgname in outpkgs:148 for pkgname in outpkgs:
276 if len(outpkgs[pkgname]) > 1:149 if len(outpkgs[pkgname]) > 1:
277 if isSource:150 outpkgs[pkgname].sort(
278 outpkgs[pkgname].sort(151 functools.partial(
279 _compare_source_packages_by_version_and_date)152 _compare_packages_by_version_and_date, get_release))
280 else:
281 outpkgs[pkgname].sort(
282 _compare_binary_packages_by_version_and_date)
283
284 outpkgs[pkgname].reverse()153 outpkgs[pkgname].reverse()
285154
286 return outpkgs155 return outpkgs
@@ -443,11 +312,12 @@
443 binarypackagerelease.id312 binarypackagerelease.id
444 AND binarypackagerelease.binarypackagename IN (313 AND binarypackagerelease.binarypackagename IN (
445 SELECT name FROM PubDomHelper WHERE count > 1)"""314 SELECT name FROM PubDomHelper WHERE count > 1)"""
446 % sqlvalues (distroarchseries, self.archive,315 % sqlvalues(distroarchseries, self.archive,
447 pocket, PackagePublishingStatus.PUBLISHED),316 pocket, PackagePublishingStatus.PUBLISHED),
448 clauseTables=['BinaryPackageRelease'])317 clauseTables=['BinaryPackageRelease'])
449318
450 self._dominateBinaries(self._sortPackages(binaries, False))319 self.debug("Dominating binaries...")
320 self._dominatePublications(self._sortPackages(binaries, False))
451 if do_clear_cache:321 if do_clear_cache:
452 self.debug("Flushing SQLObject cache.")322 self.debug("Flushing SQLObject cache.")
453 clear_cache()323 clear_cache()
@@ -464,7 +334,8 @@
464 sources = SourcePackagePublishingHistory.selectBy(334 sources = SourcePackagePublishingHistory.selectBy(
465 distroseries=dr, archive=self.archive, pocket=pocket,335 distroseries=dr, archive=self.archive, pocket=pocket,
466 status=PackagePublishingStatus.PUBLISHED)336 status=PackagePublishingStatus.PUBLISHED)
467 self._dominateSource(self._sortPackages(sources))337 self.debug("Dominating sources...")
338 self._dominatePublications(self._sortPackages(sources))
468 flush_database_updates()339 flush_database_updates()
469340
470 sources = SourcePackagePublishingHistory.select("""341 sources = SourcePackagePublishingHistory.select("""
@@ -492,4 +363,3 @@
492363
493 self.debug("Domination for %s/%s finished" %364 self.debug("Domination for %s/%s finished" %
494 (dr.name, pocket.title))365 (dr.name, pocket.title))
495
496366
=== modified file 'lib/lp/archivepublisher/tests/test_dominator.py'
--- lib/lp/archivepublisher/tests/test_dominator.py 2010-07-18 00:24:06 +0000
+++ lib/lp/archivepublisher/tests/test_dominator.py 2010-07-20 09:44:57 +0000
@@ -75,7 +75,7 @@
75 # and dominated, the subsequents.75 # and dominated, the subsequents.
76 source_input = {'foo': [dominant_source, dominated_source]}76 source_input = {'foo': [dominant_source, dominated_source]}
7777
78 dominator._dominateSource(source_input)78 dominator._dominatePublications(source_input)
79 flush_database_updates()79 flush_database_updates()
8080
81 # The dominant version remains correctly published.81 # The dominant version remains correctly published.
@@ -96,7 +96,7 @@
96 dominator = Dominator(self.logger, self.ubuntutest.main_archive)96 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
97 source_input = {'foo': []}97 source_input = {'foo': []}
98 self.assertRaises(98 self.assertRaises(
99 AssertionError, dominator._dominateSource, source_input)99 AssertionError, dominator._dominatePublications, source_input)
100100
101 def testBinariesDomination(self):101 def testBinariesDomination(self):
102 """Test overall binary domination procedure."""102 """Test overall binary domination procedure."""
@@ -108,7 +108,7 @@
108 # See comment about domination input format and ordering above.108 # See comment about domination input format and ordering above.
109 binary_input = {'foo-bin': [dominant, dominated]}109 binary_input = {'foo-bin': [dominant, dominated]}
110110
111 dominator._dominateBinaries(binary_input)111 dominator._dominatePublications(binary_input)
112 flush_database_updates()112 flush_database_updates()
113113
114 # Dominant version remains correctly published.114 # Dominant version remains correctly published.
@@ -129,7 +129,7 @@
129 dominator = Dominator(self.logger, self.ubuntutest.main_archive)129 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
130 binary_input = {'foo-bin': []}130 binary_input = {'foo-bin': []}
131 self.assertRaises(131 self.assertRaises(
132 AssertionError, dominator._dominateBinaries, binary_input)132 AssertionError, dominator._dominatePublications, binary_input)
133133
134 def testBinaryDomination(self):134 def testBinaryDomination(self):
135 """Test binary domination unit procedure."""135 """Test binary domination unit procedure."""
@@ -138,7 +138,7 @@
138 [dominant_source, dominant, dominated_source,138 [dominant_source, dominant, dominated_source,
139 dominated] = self.createSimpleDominationContext()139 dominated] = self.createSimpleDominationContext()
140140
141 dominator._dominateBinary(dominated, dominant)141 dominated.supersede(dominant)
142 flush_database_updates()142 flush_database_updates()
143143
144 dominated = self.checkBinaryPublication(144 dominated = self.checkBinaryPublication(
@@ -150,7 +150,7 @@
150 def testBinaryDominationAssertsPendingOrPublished(self):150 def testBinaryDominationAssertsPendingOrPublished(self):
151 """Test binary domination asserts coherent dominated status.151 """Test binary domination asserts coherent dominated status.
152152
153 Normally _dominateBinary only accepts domination candidates in153 Normally supersede() only accepts domination candidates in
154 PUBLISHED or PENDING status, a exception is opened for architecture154 PUBLISHED or PENDING status, a exception is opened for architecture
155 independent binaries because during the iteration they might have155 independent binaries because during the iteration they might have
156 been already SUPERSEDED with its first publication, when it happens156 been already SUPERSEDED with its first publication, when it happens
@@ -165,7 +165,7 @@
165 dominated] = self.createSimpleDominationContext()165 dominated] = self.createSimpleDominationContext()
166166
167 # Let's modify the domination candidate, so it will look wrong to167 # Let's modify the domination candidate, so it will look wrong to
168 # _dominateBinary which will raise because it's a architecture168 # supersede() which will raise because it's a architecture
169 # specific binary publication not in PENDING or PUBLISHED state.169 # specific binary publication not in PENDING or PUBLISHED state.
170 dominated.status = PackagePublishingStatus.SUPERSEDED170 dominated.status = PackagePublishingStatus.SUPERSEDED
171 manual_domination_date = datetime.datetime(171 manual_domination_date = datetime.datetime(
@@ -176,7 +176,7 @@
176 # An error like that in production clearly indicates that something176 # An error like that in production clearly indicates that something
177 # is wrong in the Dominator look-up methods.177 # is wrong in the Dominator look-up methods.
178 self.assertRaises(178 self.assertRaises(
179 AssertionError, dominator._dominateBinary, dominated, dominant)179 AssertionError, dominated.supersede, dominant)
180180
181 # The refused publishing record remains the same.181 # The refused publishing record remains the same.
182 dominated = self.checkBinaryPublication(182 dominated = self.checkBinaryPublication(
@@ -188,7 +188,7 @@
188 dominated.binarypackagerelease.architecturespecific = False188 dominated.binarypackagerelease.architecturespecific = False
189 flush_database_updates()189 flush_database_updates()
190190
191 dominator._dominateBinary(dominated, dominant)191 dominated.supersede(dominant)
192 flush_database_updates()192 flush_database_updates()
193 dominated = self.checkBinaryPublication(193 dominated = self.checkBinaryPublication(
194 dominated, PackagePublishingStatus.SUPERSEDED)194 dominated, PackagePublishingStatus.SUPERSEDED)
@@ -197,14 +197,12 @@
197 def testOtherBinaryPublications(self):197 def testOtherBinaryPublications(self):
198 """Check the basis of architecture independent binary domination.198 """Check the basis of architecture independent binary domination.
199199
200 We use _getOtherBinaryPublications to identify other publications of200 We use _getOtherPublications to identify other publications of the
201 the same binarypackagerelease in other architectures (architecture201 same binarypackagerelease in other architectures (architecture
202 independent binaries), they will be dominated during a single step.202 independent binaries), they will be dominated during a single step.
203203
204 See overall details in `testDominationOfOldArchIndepBinaries`.204 See overall details in `testDominationOfOldArchIndepBinaries`.
205 """205 """
206 dominator = Dominator(self.logger, self.ubuntutest.main_archive)
207
208 # Create architecture independent publications for foo-bin_1.0206 # Create architecture independent publications for foo-bin_1.0
209 # in i386 & hppa.207 # in i386 & hppa.
210 pub_source_archindep = self.getPubSource(208 pub_source_archindep = self.getPubSource(
@@ -232,7 +230,7 @@
232230
233 # Check if we can reach the i386 publication using231 # Check if we can reach the i386 publication using
234 # _getOtherBinaryPublications over the hppa binary.232 # _getOtherBinaryPublications over the hppa binary.
235 [found] = list(dominator._getOtherBinaryPublications(hppa_pub))233 [found] = list(hppa_pub._getOtherPublications())
236 self.assertEqual(i386_pub, found)234 self.assertEqual(i386_pub, found)
237235
238 # Create architecture specific publications for foo-bin_1.1 in236 # Create architecture specific publications for foo-bin_1.1 in
@@ -251,7 +249,7 @@
251 # Check if there is no other publication of the hppa binary package249 # Check if there is no other publication of the hppa binary package
252 # release.250 # release.
253 self.assertEqual(251 self.assertEqual(
254 dominator._getOtherBinaryPublications(hppa_pub).count(),252 hppa_pub._getOtherPublications().count(),
255 0)253 0)
256254
257 def testDominationOfOldArchIndepBinaries(self):255 def testDominationOfOldArchIndepBinaries(self):
258256
=== modified file 'lib/lp/registry/doc/distroseries.txt'
--- lib/lp/registry/doc/distroseries.txt 2010-06-22 19:37:43 +0000
+++ lib/lp/registry/doc/distroseries.txt 2010-07-20 09:44:57 +0000
@@ -593,17 +593,17 @@
593Supersede previous netapplet publication:593Supersede previous netapplet publication:
594594
595 >>> last_published = netapplet_srcrel.publishing_history[1]595 >>> last_published = netapplet_srcrel.publishing_history[1]
596 >>> superseded_netapplet = last_published.supersede()596 >>> last_published.supersede()
597 >>> flush_database_updates()597 >>> flush_database_updates()
598598
599 >>> netapplet_srcrel.publishing_history.count()599 >>> netapplet_srcrel.publishing_history.count()
600 2600 2
601601
602 >>> print superseded_netapplet.status.name602 >>> print last_published.status.name
603 SUPERSEDED603 SUPERSEDED
604604
605 >>> from canonical.database.sqlbase import get_transaction_timestamp605 >>> from canonical.database.sqlbase import get_transaction_timestamp
606 >>> superseded_netapplet.datesuperseded == get_transaction_timestamp()606 >>> last_published.datesuperseded == get_transaction_timestamp()
607 True607 True
608608
609609
610610
=== modified file 'lib/lp/soyuz/doc/archive.txt'
--- lib/lp/soyuz/doc/archive.txt 2010-07-02 21:25:36 +0000
+++ lib/lp/soyuz/doc/archive.txt 2010-07-20 09:44:57 +0000
@@ -913,10 +913,8 @@
913913
914 >>> cprov_archive.number_of_sources914 >>> cprov_archive.number_of_sources
915 3915 3
916 >>> superseded = cprov_archive.getPublishedSources(916 >>> cprov_archive.getPublishedSources(
917 ... name='cdrkit')[0].supersede()917 ... name='cdrkit')[0].supersede()
918 >>> from canonical.launchpad.ftests import syncUpdate
919 >>> syncUpdate(superseded)
920918
921 >>> cprov_archive.number_of_sources919 >>> cprov_archive.number_of_sources
922 2920 2
@@ -926,9 +924,8 @@
926924
927 >>> cprov_archive.number_of_binaries925 >>> cprov_archive.number_of_binaries
928 3926 3
929 >>> superseded = cprov_archive.getAllPublishedBinaries(927 >>> cprov_archive.getAllPublishedBinaries(
930 ... name='mozilla-firefox')[0].supersede()928 ... name='mozilla-firefox')[0].supersede()
931 >>> syncUpdate(superseded)
932929
933 >>> cprov_archive.number_of_binaries930 >>> cprov_archive.number_of_binaries
934 2931 2
@@ -982,7 +979,6 @@
982979
983 >>> login("celso.providelo@canonical.com")980 >>> login("celso.providelo@canonical.com")
984 >>> removal_candidate.requestDeletion(cprov, 'go away !')981 >>> removal_candidate.requestDeletion(cprov, 'go away !')
985 >>> syncUpdate(removal_candidate)
986982
987 >>> cprov_archive.getSourcesForDeletion(name='ice').count()983 >>> cprov_archive.getSourcesForDeletion(name='ice').count()
988 1984 1
@@ -1022,7 +1018,6 @@
10221018
1023 >>> for bin in removal_candidate.getPublishedBinaries():1019 >>> for bin in removal_candidate.getPublishedBinaries():
1024 ... bin.requestDeletion(cprov, 'go away !')1020 ... bin.requestDeletion(cprov, 'go away !')
1025 ... syncUpdate(bin)
10261021
1027 >>> cprov_archive.getSourcesForDeletion(name='ice').count()1022 >>> cprov_archive.getSourcesForDeletion(name='ice').count()
1028 01023 0
10291024
=== modified file 'lib/lp/soyuz/doc/distroarchseries.txt'
--- lib/lp/soyuz/doc/distroarchseries.txt 2010-05-13 20:01:58 +0000
+++ lib/lp/soyuz/doc/distroarchseries.txt 2010-07-20 09:44:57 +0000
@@ -123,12 +123,11 @@
123123
124Supersede current publication:124Supersede current publication:
125125
126 >>> pmount_pubrec = pmount_hoary_i386_released.current_publishing_record126 >>> pub = pmount_hoary_i386_released.current_publishing_record
127 >>> superseded_pmount = pmount_pubrec.supersede()127 >>> pub.supersede()
128 >>> pmount_hoary_i386.publishing_history.count()128 >>> pmount_hoary_i386.publishing_history.count()
129 3129 3
130130
131 >>> pub = superseded_pmount
132 >>> print pub.status.name, pub.datesuperseded is not None131 >>> print pub.status.name, pub.datesuperseded is not None
133 SUPERSEDED True132 SUPERSEDED True
134133
135134
=== modified file 'lib/lp/soyuz/doc/publishing.txt'
--- lib/lp/soyuz/doc/publishing.txt 2010-05-27 22:18:16 +0000
+++ lib/lp/soyuz/doc/publishing.txt 2010-07-20 09:44:57 +0000
@@ -543,11 +543,8 @@
543excluded from the getPublishedBinaries() results, but not from the543excluded from the getPublishedBinaries() results, but not from the
544getBuiltBinaries() result.544getBuiltBinaries() result.
545545
546 >>> from canonical.launchpad.ftests import syncUpdate
547
548 >>> a_binary = source.getPublishedBinaries()[0]546 >>> a_binary = source.getPublishedBinaries()[0]
549 >>> superseded = a_binary.supersede()547 >>> a_binary.supersede()
550 >>> syncUpdate(superseded)
551548
552 >>> len(source.getPublishedBinaries())549 >>> len(source.getPublishedBinaries())
553 1550 1
@@ -561,7 +558,6 @@
561 >>> deletable = source.getPublishedBinaries()[0]558 >>> deletable = source.getPublishedBinaries()[0]
562 >>> deletable.requestDeletion(mark, "go")559 >>> deletable.requestDeletion(mark, "go")
563 >>> deleted = deletable560 >>> deleted = deletable
564 >>> syncUpdate(deleted)
565561
566 >>> len(source.getPublishedBinaries())562 >>> len(source.getPublishedBinaries())
567 0563 0
@@ -577,7 +573,6 @@
577573
578 >>> for bin in copied_source.getPublishedBinaries():574 >>> for bin in copied_source.getPublishedBinaries():
579 ... obsoleted = bin.requestObsolescence()575 ... obsoleted = bin.requestObsolescence()
580 ... syncUpdate(obsoleted)
581576
582 >>> len(copied_source.getPublishedBinaries())577 >>> len(copied_source.getPublishedBinaries())
583 0578 0
@@ -596,7 +591,6 @@
596 >>> for pub in copied_source.getBuiltBinaries():591 >>> for pub in copied_source.getBuiltBinaries():
597 ... pub.status = PackagePublishingStatus.PUBLISHED592 ... pub.status = PackagePublishingStatus.PUBLISHED
598 ... pub.scheduleddeletiondate = None593 ... pub.scheduleddeletiondate = None
599 ... syncUpdate(pub)
600594
601Now we override the first binary publication, the hppa one, to595Now we override the first binary publication, the hppa one, to
602component 'universe'.596component 'universe'.
@@ -631,10 +625,8 @@
631We have to re-publish the superseded and the deleted publications above625We have to re-publish the superseded and the deleted publications above
632because it's used below.626because it's used below.
633627
634 >>> superseded.status = PackagePublishingStatus.PUBLISHED628 >>> a_binary.status = PackagePublishingStatus.PUBLISHED
635 >>> syncUpdate(superseded)
636 >>> deleted.status = PackagePublishingStatus.PUBLISHED629 >>> deleted.status = PackagePublishingStatus.PUBLISHED
637 >>> syncUpdate(deleted)
638630
639631
640Copying and inspecting architecture independent binaries632Copying and inspecting architecture independent binaries
641633
=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
--- lib/lp/soyuz/interfaces/publishing.py 2010-03-11 02:32:07 +0000
+++ lib/lp/soyuz/interfaces/publishing.py 2010-07-20 09:44:57 +0000
@@ -278,12 +278,7 @@
278 """278 """
279279
280 def supersede():280 def supersede():
281 """Supersede this publication.281 """Supersede this publication."""
282
283 :return: The superseded publishing records, either a
284 `ISourcePackagePublishingHistory` or
285 `IBinaryPackagePublishingHistory`.
286 """
287282
288 def requestObsolescence():283 def requestObsolescence():
289 """Make this publication obsolete.284 """Make this publication obsolete.
@@ -632,6 +627,15 @@
632 :return: a list of `ILibraryFileAlias`.627 :return: a list of `ILibraryFileAlias`.
633 """628 """
634629
630 def supersede(dominant=None, logger=None):
631 """Supersede this publication.
632
633 :param dominant: optional `ISourcePackagePublishingHistory` which is
634 triggering the domination.
635 :param logger: optional object to which debug information will be
636 logged.
637 """
638
635 def changeOverride(new_component=None, new_section=None):639 def changeOverride(new_component=None, new_section=None):
636 """Change the component and/or section of this publication640 """Change the component and/or section of this publication
637641
@@ -838,6 +842,15 @@
838 title=_("Priority Name"),842 title=_("Priority Name"),
839 required=False, readonly=True))843 required=False, readonly=True))
840844
845 def supersede(dominant=None, logger=None):
846 """Supersede this publication.
847
848 :param dominant: optional `IBinaryPackagePublishingHistory` which is
849 triggering the domination.
850 :param logger: optional object to which debug information will be
851 logged.
852 """
853
841 def changeOverride(new_component=None, new_section=None,854 def changeOverride(new_component=None, new_section=None,
842 new_priority=None):855 new_priority=None):
843 """Change the component, section and/or priority of this publication.856 """Change the component, section and/or priority of this publication.
844857
=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py 2010-07-20 09:16:14 +0000
+++ lib/lp/soyuz/model/publishing.py 2010-07-20 09:44:57 +0000
@@ -37,6 +37,7 @@
37from canonical.database.enumcol import EnumCol37from canonical.database.enumcol import EnumCol
38from canonical.launchpad.components.decoratedresultset import (38from canonical.launchpad.components.decoratedresultset import (
39 DecoratedResultSet)39 DecoratedResultSet)
40from canonical.launchpad.interfaces.lpstorm import IMasterStore
40from canonical.launchpad.webapp.interfaces import (41from canonical.launchpad.webapp.interfaces import (
41 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)42 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
42from canonical.launchpad.webapp.interfaces import NotFoundError43from canonical.launchpad.webapp.interfaces import NotFoundError
@@ -70,6 +71,10 @@
70from lp.soyuz.scripts.changeoverride import ArchiveOverriderError71from lp.soyuz.scripts.changeoverride import ArchiveOverriderError
7172
7273
74PENDING = PackagePublishingStatus.PENDING
75PUBLISHED = PackagePublishingStatus.PUBLISHED
76
77
73# XXX cprov 2006-08-18: move it away, perhaps archivepublisher/pool.py78# XXX cprov 2006-08-18: move it away, perhaps archivepublisher/pool.py
74def makePoolPath(source_name, component_name):79def makePoolPath(source_name, component_name):
75 """Return the pool path for a given source name and component name."""80 """Return the pool path for a given source name and component name."""
@@ -271,7 +276,6 @@
271 """See `IPublishing`."""276 """See `IPublishing`."""
272 self.status = PackagePublishingStatus.SUPERSEDED277 self.status = PackagePublishingStatus.SUPERSEDED
273 self.datesuperseded = UTC_NOW278 self.datesuperseded = UTC_NOW
274 return self
275279
276 def requestDeletion(self, removed_by, removal_comment=None):280 def requestDeletion(self, removed_by, removal_comment=None):
277 """See `IPublishing`."""281 """See `IPublishing`."""
@@ -673,6 +677,25 @@
673677
674 return fields678 return fields
675679
680 def supersede(self, dominant=None, logger=None):
681 """See `ISourcePackagePublishingHistory`."""
682 assert self.status in [PUBLISHED, PENDING], (
683 "Should not dominate unpublished source %s" %
684 self.sourcepackagerelease.title)
685
686 super(SourcePackagePublishingHistory, self).supersede()
687
688 if dominant is not None:
689 if logger is not None:
690 logger.debug(
691 "%s/%s has been judged as superseded by %s/%s" %
692 (self.sourcepackagerelease.sourcepackagename.name,
693 self.sourcepackagerelease.version,
694 dominant.sourcepackagerelease.sourcepackagename.name,
695 dominant.sourcepackagerelease.version))
696
697 self.supersededby = dominant.sourcepackagerelease
698
676 def changeOverride(self, new_component=None, new_section=None):699 def changeOverride(self, new_component=None, new_section=None):
677 """See `ISourcePackagePublishingHistory`."""700 """See `ISourcePackagePublishingHistory`."""
678 # Check we have been asked to do something701 # Check we have been asked to do something
@@ -927,6 +950,73 @@
927950
928 return fields951 return fields
929952
953 def _getOtherPublications(self):
954 """Return remaining publications with the same overrides.
955
956 Only considers binary publications in the same archive, distroseries,
957 pocket, component, section and priority context. These publications
958 are candidates for domination if this is an architecture-independent
959 package.
960
961 The override match is critical -- it prevents a publication created
962 by new overrides from superseding itself.
963 """
964 available_architectures = [
965 das.id for das in self.distroarchseries.distroseries.architectures]
966 return IMasterStore(BinaryPackagePublishingHistory).find(
967 BinaryPackagePublishingHistory,
968 BinaryPackagePublishingHistory.status.is_in(
969 [PUBLISHED, PENDING]),
970 BinaryPackagePublishingHistory.distroarchseries in (
971 available_architectures),
972 binarypackagerelease=self.binarypackagerelease,
973 archive=self.archive,
974 pocket=self.pocket,
975 component=self.component,
976 section=self.section,
977 priority=self.priority)
978
979 def supersede(self, dominant=None, logger=None):
980 """See `IBinaryPackagePublishingHistory`."""
981 # At this point only PUBLISHED (ancient versions) or PENDING (
982 # multiple overrides/copies) publications should be given. We
983 # tolerate SUPERSEDED architecture-independent binaries, because
984 # they are dominated automatically once the first publication is
985 # processed.
986 if self.status not in [PUBLISHED, PENDING]:
987 assert not self.binarypackagerelease.architecturespecific, (
988 "Should not dominate unpublished architecture specific "
989 "binary %s (%s)" % (
990 self.binarypackagerelease.title,
991 self.distroarchseries.architecturetag))
992 return
993
994 super(BinaryPackagePublishingHistory, self).supersede()
995
996 if dominant is not None:
997 dominant_build = dominant.binarypackagerelease.build
998 distroarchseries = dominant_build.distro_arch_series
999 if logger is not None:
1000 logger.debug(
1001 "The %s build of %s has been judged as superseded by the "
1002 "build of %s. Arch-specific == %s" % (
1003 distroarchseries.architecturetag,
1004 self.binarypackagerelease.title,
1005 dominant_build.source_package_release.title,
1006 self.binarypackagerelease.architecturespecific))
1007 # Binary package releases are superseded by the new build,
1008 # not the new binary package release. This is because
1009 # there may not *be* a new matching binary package -
1010 # source packages can change the binaries they build
1011 # between releases.
1012 self.supersededby = dominant_build
1013
1014 # If this is architecture-independet, all publications with the same
1015 # context and overrides should be dominated simultaneously.
1016 if not self.binarypackagerelease.architecturespecific:
1017 for dominated in self._getOtherPublications():
1018 dominated.supersede(dominant, logger)
1019
930 def changeOverride(self, new_component=None, new_section=None,1020 def changeOverride(self, new_component=None, new_section=None,
931 new_priority=None):1021 new_priority=None):
932 """See `IBinaryPackagePublishingHistory`."""1022 """See `IBinaryPackagePublishingHistory`."""
9331023
=== modified file 'lib/lp/soyuz/scripts/ftpmaster.py'
--- lib/lp/soyuz/scripts/ftpmaster.py 2010-04-13 14:28:58 +0000
+++ lib/lp/soyuz/scripts/ftpmaster.py 2010-07-20 09:44:57 +0000
@@ -451,13 +451,14 @@
451 dasbp = distroarchseries.getBinaryPackage(binarypackagename)451 dasbp = distroarchseries.getBinaryPackage(binarypackagename)
452 dasbpr = dasbp.currentrelease452 dasbpr = dasbp.currentrelease
453 try:453 try:
454 sbpph = dasbpr.current_publishing_record.supersede()454 bpph = dasbpr.current_publishing_record
455 bpph.supersede()
455 # We're blindly removing for all arches, if it's not there456 # We're blindly removing for all arches, if it's not there
456 # for some, that's fine ...457 # for some, that's fine ...
457 except NotFoundError:458 except NotFoundError:
458 pass459 pass
459 else:460 else:
460 version = sbpph.binarypackagerelease.version461 version = bpph.binarypackagerelease.version
461 self.logger.info ("Removed %s_%s from %s/%s ... "462 self.logger.info ("Removed %s_%s from %s/%s ... "
462 % (package, version,463 % (package, version,
463 self.distroseries.name,464 self.distroseries.name,