Merge lp:~jtv/launchpad/bug-834388 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Данило Шеган
Approved revision: no longer in the source branch.
Merged at revision: 13868
Proposed branch: lp:~jtv/launchpad/bug-834388
Merge into: lp:launchpad
Diff against target: 173 lines (+32/-45)
4 files modified
lib/lp/soyuz/interfaces/publishing.py (+8/-1)
lib/lp/soyuz/model/publishing.py (+14/-25)
lib/lp/soyuz/scripts/ftpmaster.py (+10/-11)
lib/lp/soyuz/tests/test_publishing.py (+0/-8)
To merge this branch: bzr merge lp:~jtv/launchpad/bug-834388
Reviewer Review Type Date Requested Status
Данило Шеган (community) Approve
Review via email: mp+73483@code.launchpad.net

Commit message

[r=danilo][bug=834388] Don't bypass ORM in IPublishingSet.setMultipleDeleted.

Description of the change

= 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

To post a comment you must log in.
Revision history for this message
Данило Шеган (danilo) wrote :

Assuming all is well tested and you watch for performance degradation, all is fine.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
2--- lib/lp/soyuz/interfaces/publishing.py 2011-08-26 16:44:05 +0000
3+++ lib/lp/soyuz/interfaces/publishing.py 2011-09-05 03:15:31 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 # pylint: disable-msg=E0211,E0213
10@@ -1149,6 +1149,13 @@
11 :return: a `LibraryFileAlias` instance or None
12 """
13
14+ def setMultipleDeleted(publication_class, ds, removed_by,
15+ removal_comment=None):
16+ """Mark publications as deleted.
17+
18+ This is a supporting operation for a deletion request.
19+ """
20+
21 def requestDeletion(sources, removed_by, removal_comment=None):
22 """Delete the source and binary publications specified.
23
24
25=== modified file 'lib/lp/soyuz/model/publishing.py'
26--- lib/lp/soyuz/model/publishing.py 2011-08-30 16:48:26 +0000
27+++ lib/lp/soyuz/model/publishing.py 2011-09-05 03:15:31 +0000
28@@ -334,10 +334,8 @@
29
30 def setDeleted(self, removed_by, removal_comment=None):
31 """Set to DELETED status."""
32- self.status = PackagePublishingStatus.DELETED
33- self.datesuperseded = UTC_NOW
34- self.removed_by = removed_by
35- self.removal_comment = removal_comment
36+ getUtility(IPublishingSet).setMultipleDeleted(
37+ self.__class__, [self.id], removed_by, removal_comment)
38
39 def requestObsolescence(self):
40 """See `IArchivePublisher`."""
41@@ -1966,28 +1964,19 @@
42 if len(ids) == 0:
43 return
44
45- table = publication_class.__name__
46- permitted_tables = [
47- 'BinaryPackagePublishingHistory',
48- 'SourcePackagePublishingHistory',
49+ permitted_classes = [
50+ BinaryPackagePublishingHistory,
51+ SourcePackagePublishingHistory,
52 ]
53- assert table in permitted_tables, "Deleting wrong type."
54-
55- params = sqlvalues(
56- deleted=PackagePublishingStatus.DELETED, now=UTC_NOW,
57- removal_comment=removal_comment, removed_by=removed_by)
58-
59- IMasterStore(publication_class).execute("\n".join([
60- "UPDATE %s" % table,
61- """
62- SET
63- status = %(deleted)s,
64- datesuperseded = %(now)s,
65- removed_by = %(removed_by)s,
66- removal_comment = %(removal_comment)s
67- """ % params,
68- "WHERE id IN %s" % sqlvalues(ids),
69- ]))
70+ assert publication_class in permitted_classes, "Deleting wrong type."
71+
72+ affected_pubs = IMasterStore(publication_class).find(
73+ publication_class, publication_class.id.is_in(ids))
74+ affected_pubs.set(
75+ status=PackagePublishingStatus.DELETED,
76+ datesuperseded=UTC_NOW,
77+ removed_byID=removed_by.id,
78+ removal_comment=removal_comment)
79
80 def requestDeletion(self, sources, removed_by, removal_comment=None):
81 """See `IPublishingSet`."""
82
83=== modified file 'lib/lp/soyuz/scripts/ftpmaster.py'
84--- lib/lp/soyuz/scripts/ftpmaster.py 2011-08-25 08:29:37 +0000
85+++ lib/lp/soyuz/scripts/ftpmaster.py 2011-09-05 03:15:31 +0000
86@@ -1,4 +1,4 @@
87-# Copyright 2009 Canonical Ltd. This software is licensed under the
88+# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
89 # GNU Affero General Public License version 3 (see the file LICENSE).
90
91 """FTPMaster utilities."""
92@@ -52,6 +52,7 @@
93 )
94 from lp.registry.interfaces.series import SeriesStatus
95 from lp.registry.interfaces.sourcepackage import SourcePackageFileType
96+from lp.services.browser_helpers import get_plural_text
97 from lp.services.scripts.base import (
98 LaunchpadScript,
99 LaunchpadScriptFailure,
100@@ -1256,10 +1257,10 @@
101
102 self.logger.info("Removing candidates:")
103 for removable in removables:
104- self.logger.info('\t%s' % removable.displayname)
105+ self.logger.info('\t%s', removable.displayname)
106
107- self.logger.info("Removed-by: %s" % removed_by.displayname)
108- self.logger.info("Comment: %s" % self.options.removal_comment)
109+ self.logger.info("Removed-by: %s", removed_by.displayname)
110+ self.logger.info("Comment: %s", self.options.removal_comment)
111
112 removals = []
113 for removable in removables:
114@@ -1268,14 +1269,12 @@
115 removal_comment=self.options.removal_comment)
116 removals.append(removable)
117
118- if len(removals) == 1:
119- self.logger.info(
120- "%s package successfully removed." % len(removals))
121- elif len(removals) > 1:
122- self.logger.info(
123- "%s packages successfully removed." % len(removals))
124- else:
125+ if len(removals) == 0:
126 self.logger.info("No package removed (bug ?!?).")
127+ else:
128+ self.logger.info(
129+ "%d %s successfully removed.", len(removals),
130+ get_plural_text(len(removals), "package", "packages"))
131
132 # Information returned mainly for the benefit of the test harness.
133 return removals
134
135=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
136--- lib/lp/soyuz/tests/test_publishing.py 2011-08-26 09:17:08 +0000
137+++ lib/lp/soyuz/tests/test_publishing.py 2011-09-05 03:15:31 +0000
138@@ -1179,8 +1179,6 @@
139 spph = self.factory.makeSourcePackagePublishingHistory()
140 getUtility(IPublishingSet).requestDeletion(
141 [spph], self.factory.makePerson())
142- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
143- transaction.commit()
144 self.assertEqual(PackagePublishingStatus.DELETED, spph.status)
145
146 def test_requestDeletion_leaves_other_SPPHs_alone(self):
147@@ -1188,8 +1186,6 @@
148 other_spph = self.factory.makeSourcePackagePublishingHistory()
149 getUtility(IPublishingSet).requestDeletion(
150 [other_spph], self.factory.makePerson())
151- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
152- transaction.commit()
153 self.assertEqual(PackagePublishingStatus.PENDING, spph.status)
154
155 def test_requestDeletion_marks_attached_BPPHs_deleted(self):
156@@ -1197,8 +1193,6 @@
157 spph = self.factory.makeSPPHForBPPH(bpph)
158 getUtility(IPublishingSet).requestDeletion(
159 [spph], self.factory.makePerson())
160- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
161- transaction.commit()
162 self.assertEqual(PackagePublishingStatus.DELETED, spph.status)
163
164 def test_requestDeletion_leaves_other_BPPHs_alone(self):
165@@ -1206,8 +1200,6 @@
166 unrelated_spph = self.factory.makeSourcePackagePublishingHistory()
167 getUtility(IPublishingSet).requestDeletion(
168 [unrelated_spph], self.factory.makePerson())
169- # XXX JeroenVermeulen 2011-08-25, bug=834388: obviate commit.
170- transaction.commit()
171 self.assertEqual(PackagePublishingStatus.PENDING, bpph.status)
172
173 def test_requestDeletion_accepts_empty_sources_list(self):