Merge lp:~al-maisan/launchpad/psds-model-changes-399186 into lp:launchpad/db-devel

Proposed by Muharem Hrnjadovic on 2009-10-27
Status: Merged
Merged at revision: not available
Proposed branch: lp:~al-maisan/launchpad/psds-model-changes-399186
Merge into: lp:launchpad/db-devel
Diff against target: 668 lines
10 files modified
database/schema/comments.sql (+10/-1)
database/schema/patch-2207-06-0.sql (+122/-0)
database/schema/security.cfg (+5/-0)
database/schema/trusted.sql (+15/-0)
lib/lp/soyuz/configure.zcml (+8/-0)
lib/lp/soyuz/interfaces/packageset.py (+40/-5)
lib/lp/soyuz/interfaces/packagesetgroup.py (+41/-0)
lib/lp/soyuz/model/packageset.py (+53/-5)
lib/lp/soyuz/model/packagesetgroup.py (+30/-0)
lib/lp/soyuz/tests/test_packageset.py (+121/-0)
To merge this branch: bzr merge lp:~al-maisan/launchpad/psds-model-changes-399186
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code 2009-10-27 Approve on 2009-10-27
Review via email: mp+14038@code.launchpad.net
To post a comment you must log in.
Muharem Hrnjadovic (al-maisan) wrote :

Hello there!

The branch at hand introduces the association between package sets and
distro series as well as a new model class (PackagesetGroup) that
facilitates the tracking of equivalent package sets across distro series
boundaries.

For more detail on these changes and why they are needed, please see:

  * the original "package set and distro series" meeting minutes:
    http://pastebin.ubuntu.com/302054/
  * Julian's update: http://pastebin.ubuntu.com/302058/

Please note that the underlying db schema patch (http://tinyurl.com/ykkwb97) has already been approved.
This branch is based on the respective schema patch branch (lp:~al-maisan/launchpad/psds-399186). The *actual* diff for it is here:

    http://pastebin.ubuntu.com/302886/

Tests to run:

    bin/test -vvt packageset

No pertinent "make lint" errors or warnings.

Brad Crittenden (bac) wrote :

Hi Muharem,

Thanks for the branch. It looks good except for the following small items:

* Line 46 - End of line comments are discouraged by our coding standards. Please move to the previous line.

* I think "The person who owns the package set at hand." would read better for most users as "The person who owns this package set."

* Lines 91,110 - Capitalize Ubuntu.

* Line 383 - typo 'dupliacte'

review: Approve (code)
Muharem Hrnjadovic (al-maisan) wrote :

Brad Crittenden wrote:
> Review: Approve code
> Hi Muharem,
>
> Thanks for the branch. It looks good except for the following small items:
>
> * Line 46 - End of line comments are discouraged by our coding standards. Please move to the previous line.
>
> * I think "The person who owns the package set at hand." would read better for most users as "The person who owns this package set."
>
> * Lines 91,110 - Capitalize Ubuntu.
>
> * Line 383 - typo 'dupliacte'

Hello Brad,

thank you very much for the review! I have revised the branch to
accommodate your suggestions.

Best regards

--
Muharem Hrnjadovic <email address hidden>
Public key id : B2BBFCFC
Key fingerprint : A5A3 CC67 2B87 D641 103F 5602 219F 6B60 B2BB FCFC

1=== modified file 'lib/lp/soyuz/interfaces/packageset.py'
2--- lib/lp/soyuz/interfaces/packageset.py 2009-10-27 15:42:04 +0000
3+++ lib/lp/soyuz/interfaces/packageset.py 2009-10-27 22:26:47 +0000
4@@ -35,13 +35,15 @@
5
6 class NoSuchPackageSet(NameLookupFailed):
7 """Raised when we try to look up an PackageSet that doesn't exist."""
8- webservice_error(400) #Bad request.
9+ # Bad request.
10+ webservice_error(400)
11 _message_prefix = "No such packageset"
12
13
14 class DuplicatePackagesetName(Exception):
15 """Raised for packagesets with the same name and distroseries."""
16- webservice_error(400) # Bad request.
17+ # Bad request.
18+ webservice_error(400)
19
20
21 class IPackagesetViewOnly(IHasOwner):
22@@ -56,7 +58,7 @@
23
24 owner = exported(Reference(
25 IPerson, title=_("Person"), required=True, readonly=True,
26- description=_("The person who owns the package set at hand.")))
27+ description=_("The person who owns this package set.")))
28
29 name = exported(TextLine(
30 title=_('Valid package set name'),
31@@ -336,7 +338,7 @@
32 title=_('Package set description'), required=True),
33 owner=Reference(
34 IPerson, title=_("Person"), required=True, readonly=True,
35- description=_("The person who owns the package set at hand.")),
36+ description=_("The person who owns this package set.")),
37 distroseries=Reference(
38 IDistroSeries, title=_("Distroseries"), required=False,
39 readonly=True, description=_(
40@@ -350,7 +352,7 @@
41 :param description: the description for the package set to be created.
42 :param owner: the owner of the package set to be created.
43 :param distroseries: the distroseries to which the new packageset
44- is related. Defaults to the current ubuntu series.
45+ is related. Defaults to the current Ubuntu series.
46 :param related_set: the newly created package set is to be related to
47 `related_set` (by being placed in the same package group).
48
49@@ -368,7 +370,7 @@
50
51 :param name: the name of the package set sought.
52 :param distroseries: the distroseries to which the new packageset
53- is related. Defaults to the current ubuntu series.
54+ is related. Defaults to the current Ubuntu series.
55
56 :return: An `IPackageset` instance or None.
57 """
58
59=== modified file 'lib/lp/soyuz/tests/test_packageset.py'
60--- lib/lp/soyuz/tests/test_packageset.py 2009-10-27 15:51:28 +0000
61+++ lib/lp/soyuz/tests/test_packageset.py 2009-10-27 22:21:31 +0000
62@@ -70,7 +70,7 @@
63
64 self.failUnlessRaises(
65 DuplicatePackagesetName, self.packageset_set.new,
66- u'kernel', u'A packageset with a dupliacte name', self.person1,
67+ u'kernel', u'A packageset with a duplicate name', self.person1,
68 distroseries=self.distroseries_experimental)
69
70 def test_new_duplicate_name_for_different_distroseries(self):

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/comments.sql'
2--- database/schema/comments.sql 2009-10-07 12:54:03 +0000
3+++ database/schema/comments.sql 2009-10-27 23:43:13 +0000
4@@ -2239,11 +2239,20 @@
5
6 -- Packageset
7
8-COMMENT ON TABLE Packageset IS 'Package sets facilitate the grouping of packages for purposes like the control of upload permissions, et.';
9+COMMENT ON TABLE Packageset IS 'Package sets facilitate the grouping of packages (in a given distro series) for purposes like the control of upload permissions, etc.';
10 COMMENT ON COLUMN Packageset.date_created IS 'Date and time of creation.';
11 COMMENT ON COLUMN Packageset.owner IS 'The Person or team who owns the package set';
12 COMMENT ON COLUMN Packageset.name IS 'The name for the package set on hand.';
13 COMMENT ON COLUMN Packageset.description IS 'The description for the package set on hand.';
14+COMMENT ON COLUMN Packageset.packagesetgroup IS 'The group this package set is affiliated with.';
15+COMMENT ON COLUMN Packageset.distroseries IS 'The distro series this package set belongs to.';
16+
17+-- PackagesetGroup
18+
19+COMMENT ON TABLE PackagesetGroup IS 'Package set groups keep track of equivalent package sets across distro series boundaries.';
20+COMMENT ON COLUMN Packageset.date_created IS 'Date and time of creation.';
21+COMMENT ON COLUMN Packageset.owner IS 'The Person or team who owns the package
22+set group.';
23
24 -- PackagesetSources
25
26
27=== added file 'database/schema/patch-2207-06-0.sql'
28--- database/schema/patch-2207-06-0.sql 1970-01-01 00:00:00 +0000
29+++ database/schema/patch-2207-06-0.sql 2009-10-27 23:43:13 +0000
30@@ -0,0 +1,122 @@
31+-- Copyright 2009 Canonical Ltd. This software is licensed under the
32+-- GNU Affero General Public License version 3 (see the file LICENSE).
33+
34+SET client_min_messages=ERROR;
35+
36+-- ** PART 1 ** Create the 'packagesetgroup' table and the
37+-- 'packageset.packagesetgroup' foreign key,
38+-- populate the 'packagesetgroup' table
39+
40+-- This table keeps track of package sets that are equivalent across
41+-- distro series boundaries.
42+CREATE SEQUENCE packagesetgroup_id_seq
43+ START WITH 1
44+ INCREMENT BY 1
45+ NO MAXVALUE
46+ NO MINVALUE
47+ CACHE 1;
48+CREATE TABLE packagesetgroup (
49+ id integer NOT NULL DEFAULT nextval('packagesetgroup_id_seq'),
50+ date_created timestamp without time zone DEFAULT timezone('UTC'::text, now()) NOT NULL,
51+ owner integer NOT NULL,
52+ -- Please note: the 'name' column is only here to ease the data migration
53+ -- and will be dropped at the end of this patch.
54+ name text NOT NULL
55+);
56+ALTER SEQUENCE packagesetgroup_id_seq OWNED BY packagesetgroup.id;
57+ALTER TABLE ONLY packagesetgroup
58+ ADD CONSTRAINT packagesetgroup_pkey PRIMARY KEY (id);
59+ALTER TABLE ONLY packagesetgroup
60+ ADD CONSTRAINT packagesetgroup__owner__fk
61+ FOREIGN KEY (owner) REFERENCES person(id);
62+
63+-- Package sets and their clones belong to the same package set group.
64+ALTER TABLE ONLY packageset ADD COLUMN packagesetgroup integer;
65+ALTER TABLE ONLY packageset
66+ ADD CONSTRAINT packageset__packagesetgroup__fk
67+ FOREIGN KEY (packagesetgroup) REFERENCES packagesetgroup(id);
68+
69+-- Create a group for each of the original (karmic koala) package sets.
70+INSERT INTO packagesetgroup(owner, name)
71+SELECT packageset.owner, packageset.name
72+FROM packageset WHERE NOT packageset.name LIKE('lucid-%');
73+
74+
75+-- ** PART 2 ** Associate the karmic koala package sets and their lucid lynx
76+-- clones with the appropriate package set groups
77+
78+-- Update the karmic koala package sets so they reference their groups.
79+UPDATE packageset SET packagesetgroup = packagesetgroup.id
80+FROM packagesetgroup WHERE packageset.name = packagesetgroup.name;
81+
82+-- Update the lucid lynx package set *clones* so they reference their groups
83+-- as well.
84+UPDATE packageset SET packagesetgroup = packagesetgroup.id
85+FROM packagesetgroup WHERE packageset.name = 'lucid-' || packagesetgroup.name;
86+
87+-- ** PART 3 ** Add the 'packageset.distroseries' foreign key and
88+-- initialise it for the existing package sets.
89+
90+-- A package set lives in a distro series context.
91+ALTER TABLE ONLY packageset ADD COLUMN distroseries integer;
92+
93+-- Define the foreign key constraint.
94+ALTER TABLE ONLY packageset
95+ ADD CONSTRAINT packageset__distroseries__fk
96+ FOREIGN KEY (distroseries) REFERENCES distroseries(id);
97+
98+-- First migrate the original package sets created for the karmic koala.
99+UPDATE packageset SET distroseries = distroseries.id FROM distroseries
100+WHERE distroseries.name = 'karmic' AND NOT packageset.name LIKE('lucid-%');
101+
102+-- Migrate the lucid lynx package sets next.
103+UPDATE packageset SET distroseries = distroseries.id FROM distroseries
104+WHERE distroseries.name = 'lucid' AND packageset.name LIKE('lucid-%');
105+
106+-- Make the 'distroseries' foreign key mandatory.
107+ALTER TABLE ONLY packageset ALTER COLUMN distroseries SET NOT NULL;
108+
109+-- The package set name is now only unique in conjunction with a distro series.
110+ALTER TABLE ONLY packageset
111+ DROP CONSTRAINT packageset_name_key;
112+ALTER TABLE ONLY packageset
113+ ADD CONSTRAINT packageset__name__distroseries__key UNIQUE (name, distroseries);
114+
115+-- ** PART 4 ** Strip off the 'lucid-' prefix of the lucid lynx
116+-- package set names
117+UPDATE packageset SET name = substring(name FROM length('lucid-')+1)
118+WHERE name LIKE('lucid-%');
119+
120+-- ** PART 5 ** Create package set groups for package sets that were added in
121+-- lucid lynx but do not exist in the karmic koala,
122+-- associate these package sets with their newly created groups
123+INSERT INTO packagesetgroup(owner, name)
124+SELECT packageset.owner, packageset.name
125+FROM packageset, distroseries WHERE
126+ packageset.packagesetgroup IS NULL
127+ AND packageset.distroseries = distroseries.id
128+ AND distroseries.name = 'lucid';
129+
130+UPDATE packageset SET packagesetgroup = packagesetgroup.id
131+FROM packagesetgroup, distroseries
132+WHERE
133+ packageset.packagesetgroup IS NULL
134+ AND packageset.distroseries = distroseries.id
135+ AND distroseries.name = 'lucid'
136+ AND packageset.name = packagesetgroup.name;
137+
138+-- ** PART 6 ** Make the 'packageset.packagesetgroup' foreign key mandatory
139+ALTER TABLE ONLY packageset ALTER COLUMN packagesetgroup SET NOT NULL;
140+
141+-- ** PART 7 ** Drop the 'packagesetgroup.name' column that was only added
142+-- for data migration purposes.
143+ALTER TABLE ONLY packagesetgroup DROP COLUMN name;
144+
145+-- Define indices on the newly added foreign keys.
146+CREATE INDEX packageset__packagesetgroup__idx
147+ ON packageset(packagesetgroup);
148+CREATE INDEX packageset__distroseries__idx
149+ ON packageset(distroseries);
150+CREATE INDEX packagesetgroup__owner__idx ON PackageSetGroup(owner);
151+
152+INSERT INTO LaunchpadDatabaseRevision VALUES (2207, 06, 0);
153
154=== modified file 'database/schema/security.cfg'
155--- database/schema/security.cfg 2009-10-15 23:26:39 +0000
156+++ database/schema/security.cfg 2009-10-27 23:43:13 +0000
157@@ -226,6 +226,7 @@
158 public.packagediff = SELECT, INSERT, UPDATE, DELETE
159 public.packagediff = SELECT, INSERT, UPDATE, DELETE
160 public.packageset = SELECT, INSERT, UPDATE, DELETE
161+public.packagesetgroup = SELECT, INSERT, UPDATE, DELETE
162 public.packagesetsources = SELECT, INSERT, UPDATE, DELETE
163 public.packagesetinclusion = SELECT, INSERT, UPDATE, DELETE
164 public.flatpackagesetinclusion = SELECT, INSERT, UPDATE, DELETE
165@@ -777,6 +778,7 @@
166 public.packagecopyrequest = SELECT, INSERT, UPDATE
167 public.packagediff = SELECT, INSERT, UPDATE
168 public.packageset = SELECT
169+public.packagesetgroup = SELECT
170 public.packagesetsources = SELECT, INSERT, UPDATE, DELETE
171 public.packagesetinclusion = SELECT, INSERT, UPDATE, DELETE
172 public.flatpackagesetinclusion = SELECT, INSERT, UPDATE, DELETE
173@@ -854,6 +856,7 @@
174 public.teammembership = SELECT
175 public.gpgkey = SELECT
176 public.packageset = SELECT
177+public.packagesetgroup = SELECT
178 public.packagesetsources = SELECT
179 public.packagesetinclusion = SELECT
180 public.flatpackagesetinclusion = SELECT
181@@ -1054,6 +1057,7 @@
182 public.archive = SELECT, INSERT, UPDATE
183 public.archivearch = SELECT, INSERT, UPDATE
184 public.packageset = SELECT
185+public.packagesetgroup = SELECT
186 public.packagesetsources = SELECT
187 public.packagesetinclusion = SELECT
188 public.flatpackagesetinclusion = SELECT
189@@ -1242,6 +1246,7 @@
190 public.personlanguage = SELECT
191 public.structuralsubscription = SELECT
192 public.packageset = SELECT
193+public.packagesetgroup = SELECT
194 public.packagesetsources = SELECT
195 public.packagesetinclusion = SELECT
196 public.flatpackagesetinclusion = SELECT
197
198=== modified file 'database/schema/trusted.sql'
199--- database/schema/trusted.sql 2009-08-19 15:35:13 +0000
200+++ database/schema/trusted.sql 2009-10-27 23:43:13 +0000
201@@ -1029,7 +1029,22 @@
202 DECLARE
203 parent_name text;
204 child_name text;
205+ parent_distroseries text;
206+ child_distroseries text;
207 BEGIN
208+ -- Make sure that the package sets being associated here belong
209+ -- to the same distro series.
210+ IF (SELECT parent.distroseries != child.distroseries
211+ FROM packageset parent, packageset child
212+ WHERE parent.id = NEW.parent AND child.id = NEW.child)
213+ THEN
214+ SELECT name INTO parent_name FROM packageset WHERE id = NEW.parent;
215+ SELECT name INTO child_name FROM packageset WHERE id = NEW.child;
216+ SELECT ds.name INTO parent_distroseries FROM packageset ps, distroseries ds WHERE ps.id = NEW.parent AND ps.distroseries = ds.id;
217+ SELECT ds.name INTO child_distroseries FROM packageset ps, distroseries ds WHERE ps.id = NEW.child AND ps.distroseries = ds.id;
218+ RAISE EXCEPTION 'Package sets % and % belong to different distro series (to % and % respectively) and thus cannot be associated.', child_name, parent_name, child_distroseries, parent_distroseries;
219+ END IF;
220+
221 IF EXISTS(
222 SELECT * FROM flatpackagesetinclusion
223 WHERE parent = NEW.child AND child = NEW.parent LIMIT 1)
224
225=== modified file 'lib/lp/soyuz/configure.zcml'
226--- lib/lp/soyuz/configure.zcml 2009-10-05 13:31:09 +0000
227+++ lib/lp/soyuz/configure.zcml 2009-10-27 23:43:13 +0000
228@@ -856,4 +856,12 @@
229 new"/>
230 </securedutility>
231
232+ <!-- PackagesetGroup -->
233+ <class
234+ class="lp.soyuz.model.packagesetgroup.PackagesetGroup">
235+ <allow
236+ interface="lp.soyuz.interfaces.packagesetgroup.IPackagesetGroup"/>
237+ </class>
238+
239+
240 </configure>
241
242=== modified file 'lib/lp/soyuz/interfaces/packageset.py'
243--- lib/lp/soyuz/interfaces/packageset.py 2009-07-25 16:33:39 +0000
244+++ lib/lp/soyuz/interfaces/packageset.py 2009-10-27 23:43:13 +0000
245@@ -8,6 +8,7 @@
246 __metaclass__ = type
247
248 __all__ = [
249+ 'DuplicatePackagesetName',
250 'IPackageset',
251 'IPackagesetSet',
252 'NoSuchPackageSet',
253@@ -26,16 +27,25 @@
254 operation_parameters, operation_returns_collection_of,
255 operation_returns_entry, webservice_error)
256 from lazr.restful.fields import Reference
257+from lp.registry.interfaces.distroseries import IDistroSeries
258 from lp.registry.interfaces.person import IPerson
259 from lp.registry.interfaces.role import IHasOwner
260+from lp.soyuz.interfaces.packagesetgroup import IPackagesetGroup
261
262
263 class NoSuchPackageSet(NameLookupFailed):
264 """Raised when we try to look up an PackageSet that doesn't exist."""
265- webservice_error(400) #Bad request.
266+ # Bad request.
267+ webservice_error(400)
268 _message_prefix = "No such packageset"
269
270
271+class DuplicatePackagesetName(Exception):
272+ """Raised for packagesets with the same name and distroseries."""
273+ # Bad request.
274+ webservice_error(400)
275+
276+
277 class IPackagesetViewOnly(IHasOwner):
278 """A read-only interface for package sets."""
279 export_as_webservice_entry()
280@@ -48,7 +58,7 @@
281
282 owner = exported(Reference(
283 IPerson, title=_("Person"), required=True, readonly=True,
284- description=_("The person who owns the package set at hand.")))
285+ description=_("The person who owns this package set.")))
286
287 name = exported(TextLine(
288 title=_('Valid package set name'),
289@@ -58,6 +68,18 @@
290 title=_("Description"), required=True, readonly=True,
291 description=_("The description for the package set at hand.")))
292
293+ distroseries = Reference(
294+ IDistroSeries, title=_("Distribution series"), required=True,
295+ readonly=True,
296+ description=_(
297+ "The distroseries to which this package set is related."))
298+
299+ packagesetgroup = Reference(
300+ IPackagesetGroup, title=_('Packageset group'), required=True,
301+ readonly=True,
302+ description=_(
303+ 'Used internally to link packagesets across distroseries'))
304+
305 def sourcesIncluded(direct_inclusion=False):
306 """Get all source names associated with this package set.
307
308@@ -316,15 +338,26 @@
309 title=_('Package set description'), required=True),
310 owner=Reference(
311 IPerson, title=_("Person"), required=True, readonly=True,
312- description=_("The person who owns the package set at hand.")))
313+ description=_("The person who owns this package set.")),
314+ distroseries=Reference(
315+ IDistroSeries, title=_("Distroseries"), required=False,
316+ readonly=True, description=_(
317+ "The distribution series to which the packageset "
318+ "is related.")))
319 @export_factory_operation(IPackageset, [])
320- def new(name, description, owner):
321+ def new(name, description, owner, distroseries=None, related_set=None):
322 """Create a new package set.
323
324 :param name: the name of the package set to be created.
325 :param description: the description for the package set to be created.
326 :param owner: the owner of the package set to be created.
327+ :param distroseries: the distroseries to which the new packageset
328+ is related. Defaults to the current Ubuntu series.
329+ :param related_set: the newly created package set is to be related to
330+ `related_set` (by being placed in the same package group).
331
332+ :raises DuplicatePackagesetName: if a package set with the same `name`
333+ exists in `distroseries` already.
334 :return: a newly created `IPackageset`.
335 """
336
337@@ -332,10 +365,12 @@
338 name=TextLine(title=_('Package set name'), required=True))
339 @operation_returns_entry(IPackageset)
340 @export_read_operation()
341- def getByName(name):
342+ def getByName(name, distroseries=None):
343 """Return the single package set with the given name (if any).
344
345 :param name: the name of the package set sought.
346+ :param distroseries: the distroseries to which the new packageset
347+ is related. Defaults to the current Ubuntu series.
348
349 :return: An `IPackageset` instance or None.
350 """
351
352=== added file 'lib/lp/soyuz/interfaces/packagesetgroup.py'
353--- lib/lp/soyuz/interfaces/packagesetgroup.py 1970-01-01 00:00:00 +0000
354+++ lib/lp/soyuz/interfaces/packagesetgroup.py 2009-10-27 23:43:13 +0000
355@@ -0,0 +1,41 @@
356+# Copyright 2009 Canonical Ltd. This software is licensed under the
357+# GNU Affero General Public License version 3 (see the file LICENSE).
358+
359+"""Packageset Group interface."""
360+
361+__metaclass__ = type
362+
363+__all__ = [
364+ 'IPackagesetGroup',
365+ ]
366+
367+from zope.schema import Datetime, Int
368+
369+from lazr.restful.fields import Reference
370+
371+from canonical.launchpad import _
372+from lp.registry.interfaces.person import IPerson
373+from lp.registry.interfaces.role import IHasOwner
374+
375+
376+class IPackagesetGroup(IHasOwner):
377+ """A group of related package sets across distroseries'
378+
379+ This class is used internally to group related packagesets across
380+ distroseries. For example, if in Karmic there is a 'gnome-games'
381+ package set, and this package set is cloned initially for Lucid,
382+ then both packagesets would refer to the same packageset-group.
383+
384+ Packageset-groups are not exposed at all. The date_created and
385+ owner fields are present for internal use only.
386+ """
387+ id = Int(title=_('ID'), required=True, readonly=True)
388+
389+ date_created = Datetime(
390+ title=_("Date Created"), required=True, readonly=True,
391+ description=_("The creation date/time for this packageset group."))
392+
393+ owner = Reference(
394+ IPerson, title=_("Person"), required=True, readonly=True,
395+ description=_("The person who created this packageset group."))
396+
397
398=== modified file 'lib/lp/soyuz/model/packageset.py'
399--- lib/lp/soyuz/model/packageset.py 2009-07-25 16:33:39 +0000
400+++ lib/lp/soyuz/model/packageset.py 2009-10-27 23:43:13 +0000
401@@ -6,6 +6,7 @@
402
403 import pytz
404
405+from storm.exceptions import IntegrityError
406 from storm.expr import In, SQL
407 from storm.locals import DateTime, Int, Reference, Storm, Unicode
408
409@@ -13,12 +14,13 @@
410 from zope.interface import implements
411
412 from canonical.launchpad.interfaces.lpstorm import IMasterStore, IStore
413+from lp.registry.interfaces.distribution import IDistributionSet
414 from lp.registry.interfaces.sourcepackagename import (
415 ISourcePackageName, ISourcePackageNameSet)
416 from lp.registry.model.sourcepackagename import SourcePackageName
417 from lp.soyuz.interfaces.packageset import (
418- IPackageset, IPackagesetSet, NoSuchPackageSet)
419-
420+ DuplicatePackagesetName, IPackageset, IPackagesetSet, NoSuchPackageSet)
421+from lp.soyuz.model.packagesetgroup import PackagesetGroup
422
423 def _order_result_set(result_set):
424 """Default order for package set and source package name result sets."""
425@@ -45,6 +47,12 @@
426 name = Unicode(name='name', allow_none=False)
427 description = Unicode(name='description', allow_none=False)
428
429+ distroseries_id = Int(name='distroseries', allow_none=False)
430+ distroseries = Reference(distroseries_id, 'DistroSeries.id')
431+
432+ packagesetgroup_id = Int(name='packagesetgroup', allow_none=False)
433+ packagesetgroup = Reference(packagesetgroup_id, 'PackagesetGroup.id')
434+
435 def add(self, data):
436 """See `IPackageset`."""
437 handlers = (
438@@ -292,26 +300,66 @@
439 """See `IPackagesetSet`."""
440 implements(IPackagesetSet)
441
442- def new(self, name, description, owner):
443+ def new(
444+ self, name, description, owner, distroseries=None, related_set=None):
445 """See `IPackagesetSet`."""
446 store = IMasterStore(Packageset)
447+
448+ packagesetgroup = None
449+ if related_set is not None:
450+ # Use the packagesetgroup of the `related_set`.
451+ packagesetgroup = related_set.packagesetgroup
452+ else:
453+ # We create the related internal PackagesetGroup for this
454+ # packageset so that we can later see related package sets across
455+ # distroserieses.
456+ packagesetgroup = PackagesetGroup()
457+ packagesetgroup.owner = owner
458+ store.add(packagesetgroup)
459+
460+ if distroseries is None:
461+ ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
462+ distroseries = ubuntu.currentseries
463+
464 packageset = Packageset()
465+ packageset.packagesetgroup = packagesetgroup
466 packageset.name = name
467 packageset.description = description
468 packageset.owner = owner
469+
470+ packageset.distroseries = distroseries
471+
472 store.add(packageset)
473+
474+ # We need to ensure that the cached statements are flushed so that
475+ # the duplicate name constraint gets triggered here.
476+ try:
477+ store.flush()
478+ except IntegrityError:
479+ raise DuplicatePackagesetName()
480+
481 return packageset
482
483 def __getitem__(self, name):
484 """See `IPackagesetSet`."""
485 return self.getByName(name)
486
487- def getByName(self, name):
488+ def getByName(self, name, distroseries=None):
489 """See `IPackagesetSet`."""
490 store = IStore(Packageset)
491 if not isinstance(name, unicode):
492 name = unicode(name, 'utf-8')
493- package_set = store.find(Packageset, Packageset.name == name).one()
494+
495+ extra_args = []
496+ if distroseries is not None:
497+ extra_args.append(Packageset.distroseries == distroseries)
498+ else:
499+ ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
500+ extra_args.append(Packageset.distroseries == ubuntu.currentseries)
501+
502+ package_set = store.find(
503+ Packageset, Packageset.name == name, *extra_args).one()
504+
505 if package_set is None:
506 raise NoSuchPackageSet(name)
507 return package_set
508
509=== added file 'lib/lp/soyuz/model/packagesetgroup.py'
510--- lib/lp/soyuz/model/packagesetgroup.py 1970-01-01 00:00:00 +0000
511+++ lib/lp/soyuz/model/packagesetgroup.py 2009-10-27 23:43:13 +0000
512@@ -0,0 +1,30 @@
513+# Copyright 2009 Canonical Ltd. This software is licensed under the
514+# GNU Affero General Public License version 3 (see the file LICENSE).
515+
516+__metaclass__ = type
517+
518+__all__ = [
519+ 'PackagesetGroup',
520+ ]
521+
522+import pytz
523+
524+from storm.locals import DateTime, Int, Reference, Storm
525+
526+from zope.interface import implements
527+
528+from lp.soyuz.interfaces.packagesetgroup import IPackagesetGroup
529+
530+
531+class PackagesetGroup(Storm):
532+ """See `IPackageset`."""
533+ implements(IPackagesetGroup)
534+ __storm_table__ = 'PackagesetGroup'
535+ id = Int(primary=True)
536+
537+ date_created = DateTime(
538+ name='date_created', allow_none=False, tzinfo=pytz.UTC)
539+
540+ owner_id = Int(name='owner', allow_none=False)
541+ owner = Reference(owner_id, 'Person.id')
542+
543
544=== added file 'lib/lp/soyuz/tests/test_packageset.py'
545--- lib/lp/soyuz/tests/test_packageset.py 1970-01-01 00:00:00 +0000
546+++ lib/lp/soyuz/tests/test_packageset.py 2009-10-27 23:43:13 +0000
547@@ -0,0 +1,121 @@
548+# Copyright 2009 Canonical Ltd. This software is licensed under the
549+# GNU Affero General Public License version 3 (see the file LICENSE).
550+
551+"""Test Packageset features."""
552+
553+from zope.component import getUtility
554+
555+from canonical.testing import LaunchpadZopelessLayer
556+
557+from lp.testing import TestCaseWithFactory
558+from lp.registry.interfaces.distribution import IDistributionSet
559+from lp.registry.interfaces.distroseries import DistroSeriesStatus
560+from lp.soyuz.interfaces.packageset import (
561+ DuplicatePackagesetName, IPackagesetSet)
562+
563+
564+class TestPackagesetSetNew(TestCaseWithFactory):
565+
566+ layer = LaunchpadZopelessLayer
567+
568+ def setUp(self):
569+ """Setup a distribution with multiple distroseries."""
570+ super(TestPackagesetSetNew, self).setUp()
571+ self.distribution = getUtility(IDistributionSet).getByName(
572+ 'ubuntu')
573+ self.distroseries_current = self.distribution.currentseries
574+ self.distroseries_experimental = self.factory.makeDistroRelease(
575+ distribution = self.distribution, name="experimental",
576+ status=DistroSeriesStatus.EXPERIMENTAL)
577+
578+ self.person1 = self.factory.makePerson(
579+ name='hacker', displayname=u'Happy Hacker')
580+
581+ self.packageset_set = getUtility(IPackagesetSet)
582+
583+ def test_new_defaults_to_current_distroseries(self):
584+ # If the distroseries is not provided, the current development
585+ # distroseries will be assumed.
586+ packageset = self.packageset_set.new(
587+ u'kernel', u'Contains all OS kernel packages', self.person1)
588+
589+ self.failUnlessEqual(
590+ self.distroseries_current, packageset.distroseries)
591+
592+ def test_new_with_specified_distroseries(self):
593+ # A distroseries can be provided when creating a package set.
594+ packageset = self.packageset_set.new(
595+ u'kernel', u'Contains all OS kernel packages', self.person1,
596+ distroseries=self.distroseries_experimental)
597+
598+ self.failUnlessEqual(
599+ self.distroseries_experimental, packageset.distroseries)
600+
601+ def test_new_creates_new_packageset_group(self):
602+ # Creating a new packageset should also create a new packageset
603+ # group with the same owner.
604+ packageset = self.packageset_set.new(
605+ u'kernel', u'Contains all OS kernel packages', self.person1,
606+ distroseries=self.distroseries_experimental)
607+
608+ self.failUnlessEqual(
609+ self.person1, packageset.packagesetgroup.owner)
610+
611+ def test_new_duplicate_name_for_same_distroseries(self):
612+ # Creating a packageset with a duplicate name for the
613+ # given distroseries will fail.
614+ packageset = self.packageset_set.new(
615+ u'kernel', u'Contains all OS kernel packages', self.person1,
616+ distroseries=self.distroseries_experimental)
617+
618+ self.failUnlessRaises(
619+ DuplicatePackagesetName, self.packageset_set.new,
620+ u'kernel', u'A packageset with a duplicate name', self.person1,
621+ distroseries=self.distroseries_experimental)
622+
623+ def test_new_duplicate_name_for_different_distroseries(self):
624+ # Creating a packageset with a duplicate name but for a different
625+ # series is no problem.
626+ packageset = self.packageset_set.new(
627+ u'kernel', u'Contains all OS kernel packages', self.person1)
628+
629+ packageset2 = self.packageset_set.new(
630+ u'kernel', u'A packageset with a duplicate name', self.person1,
631+ distroseries=self.distroseries_experimental)
632+ self.assertEqual(packageset.name, packageset2.name)
633+
634+ def test_new_related_packageset(self):
635+ # Creating a new package set while specifying a `related_set` should
636+ # have the effect that the former ends up in the same group as the
637+ # latter.
638+ pset1 = self.packageset_set.new(
639+ u'kernel', u'Contains all OS kernel packages', self.person1)
640+
641+ pset2 = self.packageset_set.new(
642+ u'kernel', u'A related package set.', self.person1,
643+ distroseries=self.distroseries_experimental, related_set=pset1)
644+ self.assertEqual(pset1.packagesetgroup, pset2.packagesetgroup)
645+
646+ def test_get_by_name_in_current_distroseries(self):
647+ # IPackagesetSet.getByName() will return the package set in the
648+ # current distroseries if the optional `distroseries` parameter is
649+ # omitted.
650+ pset1 = self.packageset_set.new(
651+ u'kernel', u'Contains all OS kernel packages', self.person1)
652+ pset2 = self.packageset_set.new(
653+ u'kernel', u'A related package set.', self.person1,
654+ distroseries=self.distroseries_experimental, related_set=pset1)
655+ pset_found = getUtility(IPackagesetSet).getByName('kernel')
656+ self.assertEqual(pset1, pset_found)
657+
658+ def test_get_by_name_in_specified_distroseries(self):
659+ # IPackagesetSet.getByName() will return the package set in the
660+ # specified distroseries.
661+ pset1 = self.packageset_set.new(
662+ u'kernel', u'Contains all OS kernel packages', self.person1)
663+ pset2 = self.packageset_set.new(
664+ u'kernel', u'A related package set.', self.person1,
665+ distroseries=self.distroseries_experimental, related_set=pset1)
666+ pset_found = getUtility(IPackagesetSet).getByName(
667+ 'kernel', distroseries=self.distroseries_experimental)
668+ self.assertEqual(pset2, pset_found)

Subscribers

People subscribed via source and target branches

to status/vote changes: