launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04824
[Merge] lp:~jtv/launchpad/bug-834388 into lp:launchpad
Jeroen T. Vermeulen has proposed merging lp:~jtv/launchpad/bug-834388 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #834388 in Launchpad itself: "PublishingSet.requestDeletion bypasses ORM"
https://bugs.launchpad.net/launchpad/+bug/834388
For more details, see:
https://code.launchpad.net/~jtv/launchpad/bug-834388/+merge/73483
= Summary =
IPublishingSet.setMultipleDeleted updates the database through raw SQL. This necessitates commits in tests, a separate ORM-based implementation in [SB]PPH for individual records, and so on.
== Proposed fix ==
Use storm.ResultSet.set() instead. Implement [SB]PPH.setDeleted in terms of the updated method. Remove the now unnecessary commits from tests.
== Pre-implementation notes ==
Suggested by wgrant; I wasn't aware of storm.ResultSet.set.
== Implementation details ==
A lot of the diff is in ftpmaster.py. It goes through some contortions to delete [SB]PPHs one by one, when the normal case is actually ideally suited for mass deletions. I changed that, but in a roundabout way: I now need to filter the BPPHs out of the list of removables after first gathering them for no better reason than to maintain logging output.
Still, I hope it's a first step towards moving even more of this into IPublishingSet.requestDeletion in the future. We may decide that we don't need to log binaries that are deleted as a consequence of source deletion, or we may add a source-only option to requestDeletion, or we may decide that we don't need source-only and/or binary-only deletions at all. Adding an informational return value to requestDeletion may obviate some of the contortions. I wish I could go into it and do a better job right now, but we're on a feature death march. The only reason I made this change, really, is that I just added DSDJ creation to requestDeletion, and thus slowed this inefficient code down even further.
== Tests ==
{{{
./bin/test lp.soyuz.tests.test_publishing
./bin/test lp.soyuz -t ftpmaster
}}}
== Demo and Q/A ==
Archive deletion must still work, and mark publication records as deleted.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/soyuz/tests/test_publishing.py
lib/lp/soyuz/model/publishing.py
lib/lp/soyuz/scripts/ftpmaster.py
--
https://code.launchpad.net/~jtv/launchpad/bug-834388/+merge/73483
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/launchpad/bug-834388 into lp:launchpad.
=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py 2011-08-30 16:48:26 +0000
+++ lib/lp/soyuz/model/publishing.py 2011-08-31 04:54:24 +0000
@@ -334,10 +334,8 @@
def setDeleted(self, removed_by, removal_comment=None):
"""Set to DELETED status."""
- self.status = PackagePublishingStatus.DELETED
- self.datesuperseded = UTC_NOW
- self.removed_by = removed_by
- self.removal_comment = removal_comment
+ getUtility(IPublishingSet).setMultipleDeleted(
+ self.__class__, [self.id], removed_by, removal_comment)
def requestObsolescence(self):
"""See `IArchivePublisher`."""
@@ -1966,28 +1964,19 @@
if len(ids) == 0:
return
- table = publication_class.__name__
- permitted_tables = [
- 'BinaryPackagePublishingHistory',
- 'SourcePackagePublishingHistory',
+ permitted_classes = [
+ BinaryPackagePublishingHistory,
+ SourcePackagePublishingHistory,
]
- assert table in permitted_tables, "Deleting wrong type."
-
- params = sqlvalues(
- deleted=PackagePublishingStatus.DELETED, now=UTC_NOW,
- removal_comment=removal_comment, removed_by=removed_by)
-
- IMasterStore(publication_class).execute("\n".join([
- "UPDATE %s" % table,
- """
- SET
- status = %(deleted)s,
- datesuperseded = %(now)s,
- removed_by = %(removed_by)s,
- removal_comment = %(removal_comment)s
- """ % params,
- "WHERE id IN %s" % sqlvalues(ids),
- ]))
+ assert publication_class in permitted_classes, "Deleting wrong type."
+
+ affected_pubs = IMasterStore(publication_class).find(
+ publication_class, publication_class.id.is_in(ids))
+ affected_pubs.set(
+ status=PackagePublishingStatus.DELETED,
+ datesuperseded=UTC_NOW,
+ removed_byID=removed_by.id,
+ removal_comment=removal_comment)
def requestDeletion(self, sources, removed_by, removal_comment=None):
"""See `IPublishingSet`."""
=== modified file 'lib/lp/soyuz/scripts/ftpmaster.py'
--- lib/lp/soyuz/scripts/ftpmaster.py 2011-08-25 08:29:37 +0000
+++ lib/lp/soyuz/scripts/ftpmaster.py 2011-08-31 04:54:24 +0000
@@ -52,6 +52,7 @@
)
from lp.registry.interfaces.series import SeriesStatus
from lp.registry.interfaces.sourcepackage import SourcePackageFileType
+from lp.services.browser_helpers import get_plural_text
from lp.services.scripts.base import (
LaunchpadScript,
LaunchpadScriptFailure,
@@ -62,6 +63,10 @@
)
from lp.soyuz.enums import PackagePublishingStatus
from lp.soyuz.interfaces.binarypackagename import IBinaryPackageNameSet
+from lp.soyuz.interfaces.publishing import (
+ IPublishingSet,
+ ISourcePackagePublishingHistory,
+ )
from lp.soyuz.scripts.ftpmasterbase import (
SoyuzScript,
SoyuzScriptError,
@@ -1256,26 +1261,38 @@
self.logger.info("Removing candidates:")
for removable in removables:
- self.logger.info('\t%s' % removable.displayname)
+ self.logger.info('\t%s', removable.displayname)
- self.logger.info("Removed-by: %s" % removed_by.displayname)
- self.logger.info("Comment: %s" % self.options.removal_comment)
+ self.logger.info("Removed-by: %s", removed_by.displayname)
+ self.logger.info("Comment: %s", self.options.removal_comment)
removals = []
- for removable in removables:
- removable.requestDeletion(
- removed_by=removed_by,
+ if self.options.binaryonly or self.options.sourceonly:
+ # Tedious. Delete each BPPH/SPPH individually.
+ for removable in removables:
+ removable.requestDeletion(
+ removed_by=removed_by,
+ removal_comment=self.options.removal_comment)
+ removals.append(removable)
+ else:
+ # Mass-delete the sources, and the binaries will follow
+ # automatically. The binaries are only interesting for
+ # logging.
+ sources = [
+ removable
+ for removable in removables
+ if ISourcePackagePublishingHistory.implementedBy(
+ removable)]
+ getUtility(IPublishingSet).requestDeletion(
+ sources, removed_by,
removal_comment=self.options.removal_comment)
- removals.append(removable)
- if len(removals) == 1:
- self.logger.info(
- "%s package successfully removed." % len(removals))
- elif len(removals) > 1:
- self.logger.info(
- "%s packages successfully removed." % len(removals))
- else:
+ if len(removals) == 0:
self.logger.info("No package removed (bug ?!?).")
+ else:
+ self.logger.info(
+ "%d %s successfully removed.", len(removals),
+ get_plural_text(len(removals), "package", "packages"))
# Information returned mainly for the benefit of the test harness.
return removals
=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py 2011-08-26 09:17:08 +0000
+++ lib/lp/soyuz/tests/test_publishing.py 2011-08-31 04:54:24 +0000
@@ -1179,8 +1179,6 @@
spph = self.factory.makeSourcePackagePublishingHistory()
getUtility(IPublishingSet).requestDeletion(
[spph], self.factory.makePerson())
- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
- transaction.commit()
self.assertEqual(PackagePublishingStatus.DELETED, spph.status)
def test_requestDeletion_leaves_other_SPPHs_alone(self):
@@ -1188,8 +1186,6 @@
other_spph = self.factory.makeSourcePackagePublishingHistory()
getUtility(IPublishingSet).requestDeletion(
[other_spph], self.factory.makePerson())
- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
- transaction.commit()
self.assertEqual(PackagePublishingStatus.PENDING, spph.status)
def test_requestDeletion_marks_attached_BPPHs_deleted(self):
@@ -1197,8 +1193,6 @@
spph = self.factory.makeSPPHForBPPH(bpph)
getUtility(IPublishingSet).requestDeletion(
[spph], self.factory.makePerson())
- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
- transaction.commit()
self.assertEqual(PackagePublishingStatus.DELETED, spph.status)
def test_requestDeletion_leaves_other_BPPHs_alone(self):
@@ -1206,8 +1200,6 @@
unrelated_spph = self.factory.makeSourcePackagePublishingHistory()
getUtility(IPublishingSet).requestDeletion(
[unrelated_spph], self.factory.makePerson())
- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
- transaction.commit()
self.assertEqual(PackagePublishingStatus.PENDING, bpph.status)
def test_requestDeletion_accepts_empty_sources_list(self):