~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/doc/sourcepackagerelease.txt

[r=sinzui][bug=855670] Add additional checks to the private team
        launchpad.LimitedView security adaptor so more users in defined
        roles can see the team.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
= Source Package Release =
 
2
 
 
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.
 
6
 
 
7
In a very basic explanation, this table caches the attributes of an
 
8
uploaded DSC (Debian Source Control) file.
 
9
 
 
10
This model allow us to have more granular control of the fields,
 
11
enabling faster searches, faster readings and model constraints.
 
12
 
 
13
== Basic attributes ==
 
14
 
 
15
Let's get one from the database:
 
16
 
 
17
   >>> from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
 
18
   >>> spr = SourcePackageRelease.get(14)
 
19
   >>> spr.name
 
20
   u'mozilla-firefox'
 
21
   >>> spr.version
 
22
   u'0.9'
 
23
   >>> spr.dateuploaded
 
24
   datetime.datetime(2004, 9, 27, 11, 57, 13, tzinfo=<UTC>)
 
25
 
 
26
published_archives returns a set of all the archives that this
 
27
SourcePackageRelease is published in.
 
28
 
 
29
    >>> for archive in spr.published_archives:
 
30
    ...     print archive.displayname
 
31
    Primary Archive for Ubuntu Linux
 
32
    Primary Archive for Ubuntu Test
 
33
 
 
34
'age' is a special property that performs on-the-fly:
 
35
{{{
 
36
NOW - dateuploaded
 
37
}}}
 
38
It returns a timedelta object:
 
39
 
 
40
   >>> spr.age
 
41
   datetime.timedelta(...)
 
42
 
 
43
Check if the result match the locally calculated one:
 
44
 
 
45
   >>> import datetime
 
46
   >>> import pytz
 
47
   >>> local_now = datetime.datetime.now(pytz.timezone('UTC'))
 
48
 
 
49
   >>> expected_age = local_now - spr.dateuploaded
 
50
   >>> spr.age.days == expected_age.days
 
51
   True
 
52
 
 
53
Modify dateuploaded to a certain number of days in the past and check
 
54
if the 'age' result looks sane:
 
55
 
 
56
   >>> spr.dateuploaded = (local_now - datetime.timedelta(days=10))
 
57
   >>> spr.age.days == 10
 
58
   True
 
59
 
 
60
Mozilla-firefox 0.9 has got some builds. including a PPA build.  The 'builds'
 
61
property only returns the non-PPA builds.
 
62
 
 
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()
 
74
   1
 
75
   >>> ff_ppa_build[0].archive.purpose.name
 
76
   'PPA'
 
77
   >>> spr.builds.count()
 
78
   4
 
79
 
 
80
All the builds returned are for non-PPA archives:
 
81
 
 
82
   >>> set(build.archive.purpose.name for build in spr.builds)
 
83
   set(['PRIMARY'])
 
84
 
 
85
We can use the magic productrelease property to map this to a ProductRelease:
 
86
 
 
87
   >>> pr = spr.productrelease
 
88
   >>> print pr.product.name
 
89
   firefox
 
90
   >>> print pr.productseries.name
 
91
   trunk
 
92
   >>> print pr.version
 
93
   0.9
 
94
 
 
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:
 
98
 
 
99
   >>> print spr.sourcepackage.displayname
 
100
   mozilla-firefox in Ubuntu Warty
 
101
   >>> print spr.distrosourcepackage.displayname
 
102
   mozilla-firefox in Ubuntu
 
103
 
 
104
It should also work when the version has a dash and packaging revision
 
105
after it:
 
106
 
 
107
   >>> spr = SourcePackageRelease.get(16)
 
108
   >>> print spr.name
 
109
   netapplet
 
110
   >>> print spr.version
 
111
   1.0-1
 
112
   >>> pr = spr.productrelease
 
113
   >>> print pr.product.name
 
114
   netapplet
 
115
   >>> print pr.productseries.name
 
116
   trunk
 
117
   >>> print pr.version
 
118
   1.0
 
119
 
 
120
If there isn't one, that should return None.
 
121
 
 
122
   >>> print SourcePackageRelease.get(20).productrelease
 
123
   None
 
124
 
 
125
Check that the uploaded changesfile works:
 
126
 
 
127
   >>> commercial = SourcePackageRelease.get(36)
 
128
   >>> commercial.upload_changesfile.http_url
 
129
   'http://.../commercialpackage_1.0-1_source.changes'
 
130
 
 
131
Check ISourcePackageRelease.override() behaviour:
 
132
 
 
133
   >>> spr.component.name, spr.section.name
 
134
   (u'main', u'editors')
 
135
 
 
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']
 
140
 
 
141
Override the current sourcepackagerelease with new component/section
 
142
pair:
 
143
 
 
144
   >>> spr.override(component=new_comp, section=new_sec)
 
145
 
 
146
   >>> spr.component.name, spr.section.name
 
147
   (u'universe', u'mail')
 
148
 
 
149
Abort transaction to avoid error propagation of the new attributes:
 
150
 
 
151
   >>> import transaction
 
152
   >>> transaction.abort()
 
153
 
 
154
 
 
155
Verify the creation of a new ISourcePackageRelease based on the
 
156
IDistroSeries API:
 
157
 
 
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
 
162
 
 
163
  >>> hoary = getUtility(IDistributionSet)['ubuntu']['hoary']
 
164
 
 
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:
 
168
 
 
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()
 
177
  >>> changelog = None
 
178
 
 
179
The other argurments are strings:
 
180
 
 
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
 
193
 
 
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.
 
197
 
 
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)
 
206
 
 
207
  >>> new_spr.upload_distroseries.name
 
208
  u'hoary'
 
209
  >>> new_spr.version
 
210
  u'0.0.99'
 
211
  >>> new_spr.upload_archive.id == hoary.main_archive.id
 
212
  True
 
213
  >>> new_spr.copyright
 
214
  u'smashed debian/copyright ...'
 
215
  >>> new_spr.source_package_recipe_build == arg_recipebuild
 
216
  True
 
217
 
 
218
Throw away the DB changes:
 
219
 
 
220
  >>> transaction.abort()
 
221
 
 
222
Let's get a sample SourcePackageRelease:
 
223
 
 
224
   >>> spr_test = SourcePackageRelease.get(20)
 
225
   >>> spr_test.name
 
226
   u'pmount'
 
227
 
 
228
 
 
229
== Package sizes ==
 
230
 
 
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
 
233
kilo-bytes).
 
234
 
 
235
    >>> spr = SourcePackageRelease.get(14)
 
236
    >>> spr.name
 
237
    u'mozilla-firefox'
 
238
    >>> spr.getPackageSize()
 
239
    9690.0
 
240
 
 
241
Verify that empty packages have a size of zero.
 
242
 
 
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()
 
249
    0.0
 
250
 
 
251
 
 
252
== Accessing SourcePackageReleases ==
 
253
 
 
254
SourcePackageReleases are accessible according to the archives where
 
255
they are published.
 
256
 
 
257
We will use SoyuzTestPublisher to create new publications.
 
258
 
 
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)
 
264
 
 
265
    >>> test_publisher = SoyuzTestPublisher()
 
266
 
 
267
    >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
 
268
    >>> hoary = ubuntu.getSeries('hoary')
 
269
    >>> test_publisher.addFakeChroots(hoary)
 
270
    >>> unused = test_publisher.setUpDefaultDistroSeries(hoary)
 
271
 
 
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.
 
275
 
 
276
    >>> cprov = getUtility(IPersonSet).getByName('cprov')
 
277
 
 
278
    >>> login('foo.bar@canonical.com')
 
279
    >>> cprov_private_ppa = factory.makeArchive(
 
280
    ...     owner=cprov, private=True, name='pppa')
 
281
 
 
282
    >>> private_publication = test_publisher.getPubSource(
 
283
    ...     archive=cprov_private_ppa)
 
284
 
 
285
    >>> test_sourcepackagerelease = private_publication.sourcepackagerelease
 
286
    >>> print test_sourcepackagerelease.title
 
287
    foo - 666
 
288
 
 
289
    >>> published_archives = test_sourcepackagerelease.published_archives
 
290
    >>> for archive in published_archives:
 
291
    ...     print archive.displayname
 
292
    PPA named pppa for Celso Providelo
 
293
 
 
294
'foo - 666' sourcepackagerelease is only published in Celso's Private
 
295
PPA. So, Only Celso and administrators can get 'launchpad.View' on it.
 
296
 
 
297
    >>> from canonical.launchpad.webapp.authorization import (
 
298
    ...     check_permission)
 
299
 
 
300
    >>> login('no-priv@canonical.com')
 
301
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
302
    False
 
303
 
 
304
    >>> login('celso.providelo@canonical.com')
 
305
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
306
    True
 
307
 
 
308
    >>> login('foo.bar@canonical.com')
 
309
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
310
    True
 
311
 
 
312
Once the SourcePackageRelease in question gets copied to a public
 
313
archive, let's say Ubuntu primary archive, it will become publicly
 
314
available.
 
315
 
 
316
    >>> from lp.registry.interfaces.pocket import (
 
317
    ...     PackagePublishingPocket)
 
318
 
 
319
    >>> public_publication = private_publication.copyTo(
 
320
    ...     hoary, PackagePublishingPocket.RELEASE, ubuntu.main_archive)
 
321
 
 
322
'foo - 666' is now published in Celso's private PPA and the Ubuntu
 
323
primary archive, which is public.
 
324
 
 
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
 
330
 
 
331
And we can see it's publicly available now, as expected.
 
332
 
 
333
    >>> login(ANONYMOUS)
 
334
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
335
    True
 
336
 
 
337
    >>> login('no-priv@canonical.com')
 
338
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
339
    True
 
340
 
 
341
    >>> login('celso.providelo@canonical.com')
 
342
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
343
    True
 
344
 
 
345
    >>> login('foo.bar@canonical.com')
 
346
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
347
    True
 
348
 
 
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:
 
352
 
 
353
    >>> private_publication.requestDeletion(cprov)
 
354
    >>> transaction.commit()
 
355
    >>> login('no-priv@canonical.com')
 
356
    >>> check_permission('launchpad.View', test_sourcepackagerelease)
 
357
    True
 
358
 
 
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.
 
361
 
 
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)
 
367
    True
 
368
 
 
369
published_archives shows the superseded/deleted publications still:
 
370
 
 
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
 
376