1
= Source Package Release =
3
The SourcePackageRelease table represents a particular release of a
4
SourcePackageName, but isn't tied to any particular DistroSeries
5
as the same release can appear in many.
7
In a very basic explanation, this table caches the attributes of an
8
uploaded DSC (Debian Source Control) file.
10
This model allow us to have more granular control of the fields,
11
enabling faster searches, faster readings and model constraints.
13
== Basic attributes ==
15
Let's get one from the database:
17
>>> from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
18
>>> spr = SourcePackageRelease.get(14)
24
datetime.datetime(2004, 9, 27, 11, 57, 13, tzinfo=<UTC>)
26
published_archives returns a set of all the archives that this
27
SourcePackageRelease is published in.
29
>>> for archive in spr.published_archives:
30
... print archive.displayname
31
Primary Archive for Ubuntu Linux
32
Primary Archive for Ubuntu Test
34
'age' is a special property that performs on-the-fly:
38
It returns a timedelta object:
41
datetime.timedelta(...)
43
Check if the result match the locally calculated one:
47
>>> local_now = datetime.datetime.now(pytz.timezone('UTC'))
49
>>> expected_age = local_now - spr.dateuploaded
50
>>> spr.age.days == expected_age.days
53
Modify dateuploaded to a certain number of days in the past and check
54
if the 'age' result looks sane:
56
>>> spr.dateuploaded = (local_now - datetime.timedelta(days=10))
57
>>> spr.age.days == 10
60
Mozilla-firefox 0.9 has got some builds. including a PPA build. The 'builds'
61
property only returns the non-PPA builds.
63
>>> from lp.buildmaster.model.packagebuild import PackageBuild
64
>>> from lp.registry.interfaces.person import IPersonSet
65
>>> from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
66
>>> from storm.store import Store
67
>>> cprov_ppa = getUtility(IPersonSet).getByName('cprov').archive
68
>>> ff_ppa_build = Store.of(cprov_ppa).find(
69
... BinaryPackageBuild,
70
... BinaryPackageBuild.source_package_release == spr,
71
... BinaryPackageBuild.package_build == PackageBuild.id,
72
... PackageBuild.archive == cprov_ppa)
73
>>> ff_ppa_build.count()
75
>>> ff_ppa_build[0].archive.purpose.name
77
>>> spr.builds.count()
80
All the builds returned are for non-PPA archives:
82
>>> set(build.archive.purpose.name for build in spr.builds)
85
We can use the magic productrelease property to map this to a ProductRelease:
87
>>> pr = spr.productrelease
88
>>> print pr.product.name
90
>>> print pr.productseries.name
95
We can use the sourcepackage and distrosourcepackage properties to
96
grab magical objects representing that package in the distribution to
97
which it was uploaded:
99
>>> print spr.sourcepackage.displayname
100
mozilla-firefox in Ubuntu Warty
101
>>> print spr.distrosourcepackage.displayname
102
mozilla-firefox in Ubuntu
104
It should also work when the version has a dash and packaging revision
107
>>> spr = SourcePackageRelease.get(16)
110
>>> print spr.version
112
>>> pr = spr.productrelease
113
>>> print pr.product.name
115
>>> print pr.productseries.name
120
If there isn't one, that should return None.
122
>>> print SourcePackageRelease.get(20).productrelease
125
Check that the uploaded changesfile works:
127
>>> commercial = SourcePackageRelease.get(36)
128
>>> commercial.upload_changesfile.http_url
129
'http://.../commercialpackage_1.0-1_source.changes'
131
Check ISourcePackageRelease.override() behaviour:
133
>>> spr.component.name, spr.section.name
134
(u'main', u'editors')
136
>>> from lp.soyuz.interfaces.component import IComponentSet
137
>>> from lp.soyuz.interfaces.section import ISectionSet
138
>>> new_comp = getUtility(IComponentSet)['universe']
139
>>> new_sec = getUtility(ISectionSet)['mail']
141
Override the current sourcepackagerelease with new component/section
144
>>> spr.override(component=new_comp, section=new_sec)
146
>>> spr.component.name, spr.section.name
147
(u'universe', u'mail')
149
Abort transaction to avoid error propagation of the new attributes:
151
>>> import transaction
152
>>> transaction.abort()
155
Verify the creation of a new ISourcePackageRelease based on the
158
>>> from lp.registry.interfaces.distribution import IDistributionSet
159
>>> from lp.registry.interfaces.gpg import IGPGKeySet
160
>>> from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
161
>>> from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
163
>>> hoary = getUtility(IDistributionSet)['ubuntu']['hoary']
165
All the arguments to create an ISourcePackageRelease are obtained when
166
processing a source upload, see more details in nascentupload.txt.
167
Some of the 20 required arguments are foreign keys or DB contants:
169
>>> arg_name = getUtility(ISourcePackageNameSet)['pmount']
170
>>> arg_comp = getUtility(IComponentSet)['universe']
171
>>> arg_sect = getUtility(ISectionSet)['web']
172
>>> arg_key = getUtility(IGPGKeySet).get(1)
173
>>> arg_maintainer = hoary.owner
174
>>> arg_creator = hoary.owner
175
>>> arg_urgency = SourcePackageUrgency.LOW
176
>>> arg_recipebuild = factory.makeSourcePackageRecipeBuild()
179
The other argurments are strings:
181
>>> version = '0.0.99'
182
>>> dsc = 'smashed dsc...'
183
>>> copyright = 'smashed debian/copyright ...'
184
>>> changelog_entry = 'contigous text....'
185
>>> archhintlist = 'any'
186
>>> builddepends = 'cdbs, debhelper (>= 4.1.0), libsysfs-dev, libhal-dev'
187
>>> builddependsindep = ''
188
>>> dsc_maintainer_rfc822 = 'Foo Bar <foo@bar.com>'
189
>>> dsc_standards_version = '2.6.1'
190
>>> dsc_format = '1.0'
191
>>> dsc_binaries = 'pmount'
192
>>> archive = hoary.main_archive
194
Having proper arguments in hand we can create a new
195
ISourcePackageRelease, it will automatically set the
196
'upload_distroseries' to the API entry point, in this case Hoary.
198
>>> new_spr = hoary.createUploadedSourcePackageRelease(
199
... arg_name, version, arg_maintainer,
200
... builddepends, builddependsindep, archhintlist, arg_comp, arg_creator,
201
... arg_urgency, changelog, changelog_entry, dsc, arg_key, arg_sect,
202
... dsc_maintainer_rfc822, dsc_standards_version, dsc_format,
203
... dsc_binaries, archive, copyright=copyright,
204
... build_conflicts=None, build_conflicts_indep=None,
205
... source_package_recipe_build=arg_recipebuild)
207
>>> new_spr.upload_distroseries.name
211
>>> new_spr.upload_archive.id == hoary.main_archive.id
213
>>> new_spr.copyright
214
u'smashed debian/copyright ...'
215
>>> new_spr.source_package_recipe_build == arg_recipebuild
218
Throw away the DB changes:
220
>>> transaction.abort()
222
Let's get a sample SourcePackageRelease:
224
>>> spr_test = SourcePackageRelease.get(20)
231
The size of a source package can be obtained via the getPackageSize() method.
232
It returns the sum of the size of all files comprising the source package (in
235
>>> spr = SourcePackageRelease.get(14)
238
>>> spr.getPackageSize()
241
Verify that empty packages have a size of zero.
243
>>> from lp.registry.model.sourcepackagename import SourcePackageName
244
>>> linux_src = SourcePackageName.selectOneBy(
245
... name="linux-source-2.6.15")
246
>>> spr = SourcePackageRelease.selectOneBy(
247
... sourcepackagename=linux_src, version='2.6.15.3')
248
>>> spr.getPackageSize()
252
== Accessing SourcePackageReleases ==
254
SourcePackageReleases are accessible according to the archives where
257
We will use SoyuzTestPublisher to create new publications.
259
>>> from lp.registry.interfaces.distribution import (
260
... IDistributionSet)
261
>>> from lp.registry.interfaces.person import IPersonSet
262
>>> from lp.soyuz.tests.test_publishing import (
263
... SoyuzTestPublisher)
265
>>> test_publisher = SoyuzTestPublisher()
267
>>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
268
>>> hoary = ubuntu.getSeries('hoary')
269
>>> test_publisher.addFakeChroots(hoary)
270
>>> unused = test_publisher.setUpDefaultDistroSeries(hoary)
272
If a SourcePackageRelease is only published in a private PPA, only
273
users with access (launchpad.View) to that archive will be able to get
274
the same permission on it.
276
>>> cprov = getUtility(IPersonSet).getByName('cprov')
278
>>> login('foo.bar@canonical.com')
279
>>> cprov_private_ppa = factory.makeArchive(
280
... owner=cprov, private=True, name='pppa')
282
>>> private_publication = test_publisher.getPubSource(
283
... archive=cprov_private_ppa)
285
>>> test_sourcepackagerelease = private_publication.sourcepackagerelease
286
>>> print test_sourcepackagerelease.title
289
>>> published_archives = test_sourcepackagerelease.published_archives
290
>>> for archive in published_archives:
291
... print archive.displayname
292
PPA named pppa for Celso Providelo
294
'foo - 666' sourcepackagerelease is only published in Celso's Private
295
PPA. So, Only Celso and administrators can get 'launchpad.View' on it.
297
>>> from canonical.launchpad.webapp.authorization import (
298
... check_permission)
300
>>> login('no-priv@canonical.com')
301
>>> check_permission('launchpad.View', test_sourcepackagerelease)
304
>>> login('celso.providelo@canonical.com')
305
>>> check_permission('launchpad.View', test_sourcepackagerelease)
308
>>> login('foo.bar@canonical.com')
309
>>> check_permission('launchpad.View', test_sourcepackagerelease)
312
Once the SourcePackageRelease in question gets copied to a public
313
archive, let's say Ubuntu primary archive, it will become publicly
316
>>> from lp.registry.interfaces.pocket import (
317
... PackagePublishingPocket)
319
>>> public_publication = private_publication.copyTo(
320
... hoary, PackagePublishingPocket.RELEASE, ubuntu.main_archive)
322
'foo - 666' is now published in Celso's private PPA and the Ubuntu
323
primary archive, which is public.
325
>>> published_archives = test_sourcepackagerelease.published_archives
326
>>> for archive in published_archives:
327
... print archive.displayname
328
Primary Archive for Ubuntu Linux
329
PPA named pppa for Celso Providelo
331
And we can see it's publicly available now, as expected.
334
>>> check_permission('launchpad.View', test_sourcepackagerelease)
337
>>> login('no-priv@canonical.com')
338
>>> check_permission('launchpad.View', test_sourcepackagerelease)
341
>>> login('celso.providelo@canonical.com')
342
>>> check_permission('launchpad.View', test_sourcepackagerelease)
345
>>> login('foo.bar@canonical.com')
346
>>> check_permission('launchpad.View', test_sourcepackagerelease)
349
Another common scenario is that once the package is unembargoed from the
350
private PPA, it gets deleted from that private PPA. At this point the
351
package is still public:
353
>>> private_publication.requestDeletion(cprov)
354
>>> transaction.commit()
355
>>> login('no-priv@canonical.com')
356
>>> check_permission('launchpad.View', test_sourcepackagerelease)
359
The next stage of the lifecycle is for the remaining publication to be
360
superseded. The package will still be public after that happens.
362
>>> login('foo.bar@canonical.com')
363
>>> unused = public_publication.supersede()
364
>>> transaction.commit()
365
>>> login('no-priv@canonical.com')
366
>>> check_permission('launchpad.View', test_sourcepackagerelease)
369
published_archives shows the superseded/deleted publications still:
371
>>> published_archives = test_sourcepackagerelease.published_archives
372
>>> for archive in published_archives:
373
... print archive.displayname
374
Primary Archive for Ubuntu Linux
375
PPA named pppa for Celso Providelo