Merge lp:~cjwatson/launchpad/init-packageset-fixes into lp:launchpad

Proposed by Colin Watson on 2012-04-23
Status: Merged
Approved by: William Grant on 2012-04-23
Approved revision: no longer in the source branch.
Merged at revision: 15137
Proposed branch: lp:~cjwatson/launchpad/init-packageset-fixes
Merge into: lp:launchpad
Diff against target: 99 lines (+53/-9)
2 files modified
lib/lp/soyuz/scripts/initialize_distroseries.py (+3/-5)
lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py (+50/-4)
To merge this branch: bzr merge lp:~cjwatson/launchpad/init-packageset-fixes
Reviewer Review Type Date Requested Status
William Grant code 2012-04-23 Approve on 2012-04-23
Review via email: mp+103036@code.launchpad.net

Commit Message

Fix InitializeDistroSeries._copy_packagesets to copy from only the most recent series, not merge packagesets from all series.

Description of the Change

== Summary ==

Bug 887185 reports that initialize-distroseries.py has been creating duplicate ArchivePermission rows. Relatedly, I've also noticed that, rather than copying the list of source packages in a given packageset from oneiric to precise when initialising precise (say), it's been merging the source packages in all instances of that packageset name in all distroseries. These look intuitively related, and indeed they turn out to be due to the same underlying bug.

== Proposed fix ==

        packagesets = self._store.find(
            Packageset, DistroSeries.id.is_in(self.derivation_parent_ids))

The intention is obvious here, but that code is missing anything relating the Packageset and Distroseries rows, so it ends up just loading all packagesets. Adding the obvious And(Packageset.distroseries == DistroSeries.id, ...) makes it work.

== Implementation details ==

+49 LoC, but I'd like to get this landed in time for opening Ubuntu Q and so don't want to spend lots of time refactoring if possible; could I use some credit from r15080 (-232) or r15103 (-93)?

== Tests ==

bin/test -vvct test_initialize_distroseries

== Demo and Q/A ==

I'm open to suggestions of something that can be done in practice in a reasonable time. My guess would be that we run initialize-distroseries.py on some suitable series on dogfood and then inspect the results, but I don't know what would be a suitable series and I don't know whether running i-d on dogfood is practical.

== lint ==

None.

To post a comment you must log in.
Colin Watson (cjwatson) wrote :

Oh, incidentally, I don't think this entirely closes this bug, as we need to check for existing busted data and do something about it if any, so this is probably [incr]. I'm willing to work on the rest, although probably not immediately.

William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/scripts/initialize_distroseries.py'
2--- lib/lp/soyuz/scripts/initialize_distroseries.py 2011-12-30 06:14:56 +0000
3+++ lib/lp/soyuz/scripts/initialize_distroseries.py 2012-04-23 01:10:24 +0000
4@@ -1,4 +1,4 @@
5-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
6+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
7 # GNU Affero General Public License version 3 (see the file LICENSE).
8
9 """Initialize a distroseries from its parent distroseries."""
10@@ -655,11 +655,9 @@
11
12 def _copy_packagesets(self):
13 """Copy packagesets from the parent distroseries."""
14- # Avoid circular imports.
15- from lp.registry.model.distroseries import DistroSeries
16-
17 packagesets = self._store.find(
18- Packageset, DistroSeries.id.is_in(self.derivation_parent_ids))
19+ Packageset,
20+ Packageset.distroseries_id.is_in(self.derivation_parent_ids))
21 parent_to_child = {}
22 # Create the packagesets and any archivepermissions if we're not
23 # copying cross-distribution.
24
25=== modified file 'lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py'
26--- lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2012-01-01 02:58:52 +0000
27+++ lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2012-04-23 01:10:24 +0000
28@@ -1,4 +1,4 @@
29-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
30+# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
31 # GNU Affero General Public License version 3 (see the file LICENSE).
32
33 """Test the initialize_distroseries script machinery."""
34@@ -156,9 +156,13 @@
35 distroseries=distroseries,
36 sourcepackagename=spn,
37 pocket=PackagePublishingPocket.RELEASE)
38- packageset = getUtility(IPackagesetSet).new(
39- packageset_name, packageset_name, distroseries.owner,
40- distroseries=distroseries)
41+ try:
42+ packageset = getUtility(IPackagesetSet).getByName(
43+ packageset_name, distroseries=distroseries)
44+ except NoSuchPackageSet:
45+ packageset = getUtility(IPackagesetSet).new(
46+ packageset_name, packageset_name, distroseries.owner,
47+ distroseries=distroseries)
48 packageset.addSources(package_name)
49 if create_build:
50 source.createMissingBuilds()
51@@ -686,6 +690,48 @@
52 [(u'udev', u'0.1-1'), (u'firefox', u'2.1')],
53 pub_sources)
54
55+ def test_copying_packagesets_no_duplication(self):
56+ # Copying packagesets only copies the packageset from the most
57+ # recent series, rather than merging those from all series.
58+ previous_parent, _ = self.setupParent()
59+ parent = self._fullInitialize([previous_parent])
60+ self.factory.makeSourcePackagePublishingHistory(distroseries=parent)
61+ p1, parent_packageset, _ = self.createPackageInPackageset(
62+ parent, u"p1", u"packageset")
63+ uploader1 = self.factory.makePerson()
64+ getUtility(IArchivePermissionSet).newPackagesetUploader(
65+ parent.main_archive, uploader1, parent_packageset)
66+ child = self._fullInitialize(
67+ [previous_parent], previous_series=parent,
68+ distribution=parent.distribution)
69+ # Make sure the child's packageset has disjoint packages and
70+ # permissions.
71+ p2, child_packageset, _ = self.createPackageInPackageset(
72+ child, u"p2", u"packageset")
73+ child_packageset.removeSources([u"p1"])
74+ uploader2 = self.factory.makePerson()
75+ getUtility(IArchivePermissionSet).newPackagesetUploader(
76+ child.main_archive, uploader2, child_packageset)
77+ getUtility(IArchivePermissionSet).deletePackagesetUploader(
78+ parent.main_archive, uploader1, child_packageset)
79+ grandchild = self._fullInitialize(
80+ [previous_parent], previous_series=child,
81+ distribution=parent.distribution)
82+ grandchild_packageset = getUtility(IPackagesetSet).getByName(
83+ parent_packageset.name, distroseries=grandchild)
84+ # The copied grandchild set has sources matching the child.
85+ self.assertContentEqual(
86+ child_packageset.getSourcesIncluded(),
87+ grandchild_packageset.getSourcesIncluded())
88+ # It also has permissions matching the child.
89+ perms2 = getUtility(IArchivePermissionSet).uploadersForPackageset(
90+ parent.main_archive, child_packageset)
91+ perms3 = getUtility(IArchivePermissionSet).uploadersForPackageset(
92+ parent.main_archive, grandchild_packageset)
93+ self.assertContentEqual(
94+ [perm.person.name for perm in perms2],
95+ [perm.person.name for perm in perms3])
96+
97 def test_intra_distro_perm_copying(self):
98 # If child.distribution equals parent.distribution, we also
99 # copy the archivepermissions.