Merge lp:~rvb/launchpad/bug-869221 into lp:launchpad

Proposed by Raphaël Badin on 2011-10-07
Status: Merged
Approved by: Raphaël Badin on 2011-10-07
Approved revision: 14109
Merged at revision: 14121
Proposed branch: lp:~rvb/launchpad/bug-869221
Merge into: lp:launchpad
Diff against target: 171 lines (+77/-11) 4 files modified
To merge this branch: bzr merge lp:~rvb/launchpad/bug-869221
Reviewer Review Type Date Requested Status
Julian Edwards 2011-10-07 Approve on 2011-10-07
Review via email: mp+78548@code.launchpad.net

Commit Message

[r=julian-edwards][bug=869221][incr] Raise a proper error when a derived series won't be able to have an architecture to build architecture independent binaries.

Description of the Change

Before that branch, the arch independent builder for the derived series was simply taken from the first parent, no question asked. This is obviously a problem if the architecture in question was not among the architectures selected for the derived series.

This branch fixes that:
- In the case of multiple parents, we try to find a candidate for the child's nominatedarch.arch_tag by computing the intersection between the list of the parents architecture indep builders and the selected architectures;
- If this list is empty a proper error is raised.

A following branch will force the user to include a proper architecture in the list of the selected archtectures on the +initseries.

= Tests =

./bin/test -vvc test_initialize_distroseries test_multiple_parents_child_nominatedarchindep
./bin/test -vvc test_initialize_distroseries test_multiple_parents_no_child_nominatedarchindep

= QA =

*Test 1*
Initialize a series with architectures 'a' and 'b' ('b' being the arch indep one). Only select architecture 'a' for the child. The init job should error with the proper error message: "The distroseries has no architectures selected to build architecture independent binaries."

*Test 2*
Initialize a series from 2 parents: p1 and p2, p1 having two archtectures 'a' and 'b' ('b' being the arch indep one) and p2 having one architecture 'a' ('a' being - obviously - the arch indep one). Then initialize a child with only architecture 'a'. This should succeed and the nominatedarchindep for the resulting child should be 'a'.

To post a comment you must log in.
Julian Edwards (julian-edwards) wrote :

19 + if (len(potential_nominated_arches) == 0):
20 + raise InitializationError(
21 + ("The distroseries has no architectures selected to "
22 + "build architecture independent binaries."))

Nit - too many parentheses here, on all four lines :)

Everything else looks great, thanks!

review: Approve
Raphaël Badin (rvb) wrote :

> 19 + if (len(potential_nominated_arches) == 0):
> 20 + raise InitializationError(
> 21 + ("The distroseries has no architectures selected to "
> 22 + "build architecture independent binaries."))
>
> Nit - too many parentheses here, on all four lines :)

Fixed.

> Everything else looks great, thanks!

Thanks for the review!

lp:~rvb/launchpad/bug-869221 updated on 2011-10-07
14110. By Raphaël Badin on 2011-10-07

Remove some parentheses.

14111. By Raphaël Badin on 2011-10-07

Fix tests.

Preview Diff

1=== modified file 'lib/lp/registry/stories/webservice/xx-derivedistroseries.txt'
2--- lib/lp/registry/stories/webservice/xx-derivedistroseries.txt 2011-06-09 10:50:25 +0000
3+++ lib/lp/registry/stories/webservice/xx-derivedistroseries.txt 2011-10-07 16:16:48 +0000
4@@ -11,11 +11,14 @@
5 >>> from lp.testing.sampledata import ADMIN_EMAIL
6 >>> from canonical.launchpad.testing.pages import webservice_for_person
7 >>> from canonical.launchpad.webapp.interfaces import OAuthPermission
8+ >>> from zope.security.proxy import removeSecurityProxy
9
10 >>> login(ADMIN_EMAIL)
11
12 >>> soyuz_team = factory.makeTeam(name='soyuz-team')
13 >>> parent_series = factory.makeDistroSeries(name="parentseries")
14+ >>> arch = factory.makeDistroArchSeries(distroseries=parent_series)
15+ >>> removeSecurityProxy(parent_series).nominatedarchindep = arch
16 >>> child_series = factory.makeDistroSeries(name='child1')
17 >>> child_series_with_parent = factory.makeDistroSeries(
18 ... name='child-with-parent')
19
20=== modified file 'lib/lp/registry/tests/test_initderiveddistroseries.py'
21--- lib/lp/registry/tests/test_initderiveddistroseries.py 2011-08-22 11:39:17 +0000
22+++ lib/lp/registry/tests/test_initderiveddistroseries.py 2011-10-07 16:16:48 +0000
23@@ -42,6 +42,8 @@
24 def setUp(self):
25 super(TestDeriveDistroSeries, self).setUp()
26 self.parent = self.factory.makeDistroSeries()
27+ arch = self.factory.makeDistroArchSeries(distroseries=self.parent)
28+ removeSecurityProxy(self.parent).nominatedarchindep = arch
29 self.child = self.factory.makeDistroSeries()
30 removeSecurityProxy(self.child).driver = self.factory.makePerson()
31 login_person(self.child.driver)
32@@ -187,11 +189,11 @@
33 res = self.create2archParentAndSource(packages={'p1': '1.1'})
34 parent, parent_das, parent_das2, source = res
35 # Create builds for the architecture of parent_das2.
36- source.createMissingBuilds(architectures_available=[parent_das2])
37+ source.createMissingBuilds(architectures_available=[parent_das])
38 child = self.factory.makeDistroSeries(
39 distribution=parent.distribution, previous_series=parent)
40
41- # Initialize only with parent_das's architecture. The build is
42+ # Initialize only with parent_das2's architecture. The build is
43 # in the other architecture so no exception should be raised.
44 child.initDerivedDistroSeries(
45- child.driver, [parent.id], (parent_das.architecturetag, ), ())
46+ child.driver, [parent.id], (parent_das2.architecturetag, ), ())
47
48=== modified file 'lib/lp/soyuz/scripts/initialize_distroseries.py'
49--- lib/lp/soyuz/scripts/initialize_distroseries.py 2011-10-03 09:28:45 +0000
50+++ lib/lp/soyuz/scripts/initialize_distroseries.py 2011-10-07 16:16:48 +0000
51@@ -157,11 +157,22 @@
52 ".").format(
53 child=self.distroseries))
54 self._checkParents()
55+ self._checkArchindep()
56 for parent in self.derivation_parents:
57 self._checkBuilds(parent)
58 self._checkQueue(parent)
59 self._checkSeries()
60
61+ def _checkArchindep(self):
62+ # Check that the child distroseries has an architecture to
63+ # build architecture independent binaries.
64+ potential_nominated_arches = self._potential_nominated_arches(
65+ self.derivation_parents)
66+ if len(potential_nominated_arches) == 0:
67+ raise InitializationError(
68+ "The distroseries has no architectures selected to "
69+ "build architecture independent binaries.")
70+
71 def _checkPublisherConfig(self):
72 """A series cannot be initialized if it has no publisher config
73 set up.
74@@ -365,9 +376,23 @@
75 """ % (sqlvalues(self.distroseries, self.distroseries.owner)
76 + (das_filter, )))
77 self._store.flush()
78- # Take nominatedarchindep from the first parent.
79- self.distroseries.nominatedarchindep = self.distroseries[
80- self.derivation_parents[0].nominatedarchindep.architecturetag]
81+ # Select the arch-indep builder from the intersection between
82+ # the selected architectures and the list of the parent's
83+ # arch-indep builders.
84+ arch_tag = self._potential_nominated_arches(
85+ self.derivation_parents).pop()
86+ self.distroseries.nominatedarchindep = self.distroseries[arch_tag]
87+
88+ def _potential_nominated_arches(self, parent_list):
89+ parent_indep_archtags = set(
90+ parent.nominatedarchindep.architecturetag
91+ for parent in parent_list
92+ if parent.nominatedarchindep is not None)
93+
94+ if len(self.arches) == 0:
95+ return parent_indep_archtags
96+ else:
97+ return parent_indep_archtags.intersection(self.arches)
98
99 def _copy_packages(self):
100 # Perform the copies
101
102=== modified file 'lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py'
103--- lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2011-10-03 09:28:45 +0000
104+++ lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2011-10-07 16:16:48 +0000
105@@ -259,7 +259,7 @@
106 parent, parent_das, parent_das2, source = res
107 # Create builds for the architecture of parent_das2.
108 source.createMissingBuilds(architectures_available=[parent_das2])
109- # Initialize only with parent_das2's architecture.
110+ # Initialize only with parent_das's architecture.
111 child = self.factory.makeDistroSeries()
112 ids = InitializeDistroSeries(
113 child, [parent.id], arches=[parent_das2.architecturetag])
114@@ -293,13 +293,13 @@
115 # architecture we're initializing with, IDS will succeed.
116 res = self.create2archParentAndSource(packages={'p1': '1.1'})
117 parent, parent_das, parent_das2, source = res
118- # Create builds for the architecture of parent_das2.
119- source.createMissingBuilds(architectures_available=[parent_das2])
120- # Initialize only with parent_das's architecture.
121+ # Create builds for the architecture of parent_das.
122+ source.createMissingBuilds(architectures_available=[parent_das])
123+ # Initialize only with parent_das2's architecture.
124 child = self.factory.makeDistroSeries(
125 distribution=parent.distribution, previous_series=parent)
126 ids = InitializeDistroSeries(
127- child, arches=[parent_das.architecturetag])
128+ child, arches=[parent_das2.architecturetag])
129
130 # No error is raised because we're initializing only the architecture
131 # which has no pending builds in it.
132@@ -1383,3 +1383,39 @@
133 self.assertEqual([], self.getWaitingJobs(child, 'p2', prev_parent2))
134 self.assertNotEqual([], self.getWaitingJobs(child, 'p1', parent3))
135 self.assertEqual([], self.getWaitingJobs(child, 'p3', parent3))
136+
137+ def test_multiple_parents_child_nominatedarchindep(self):
138+ # If the list of the selected architectures and the list of the
139+ # nominatedarchindep for all the parent intersect, the child's
140+ # nominatedarchindep is taken from the intersection of the two
141+ # lists.
142+ parent1, unused = self.setupParent(
143+ packages={}, arch_tag='i386')
144+ parent2, unused = self.setupParent(
145+ packages={}, arch_tag='amd64')
146+ child = self._fullInitialize(
147+ [parent1, parent2],
148+ arches=[parent2.nominatedarchindep.architecturetag])
149+ self.assertEqual(
150+ child.nominatedarchindep.architecturetag,
151+ parent2.nominatedarchindep.architecturetag)
152+
153+ def test_multiple_parents_no_child_nominatedarchindep(self):
154+ # If the list of the selected architectures and the list of the
155+ # nominatedarchindep for all the parents don't intersect, an
156+ # error is raised because it means that the child won't have an
157+ # architecture to build architecture independent binaries.
158+ parent1, unused = self.setupParent(
159+ packages={}, arch_tag='i386')
160+ self.setupDas(parent1, 'hppa', 'powerpc')
161+ parent2, unused = self.setupParent(
162+ packages={}, arch_tag='amd64')
163+ child = self.factory.makeDistroSeries()
164+ ids = InitializeDistroSeries(
165+ child, [parent1.id, parent2.id],
166+ arches=['powerpc'])
167+ self.assertRaisesWithContent(
168+ InitializationError,
169+ ("The distroseries has no architectures selected to "
170+ "build architecture independent binaries."),
171+ ids.check)