Merge lp:~james-w/launchpad/move-soyuz-test-publisher into lp:launchpad

Proposed by James Westby
Status: Work in progress
Proposed branch: lp:~james-w/launchpad/move-soyuz-test-publisher
Merge into: lp:launchpad
Prerequisite: lp:~james-w/launchpad/more-matchers
Diff against target: 1673 lines (+1213/-251)
6 files modified
lib/lp/archivepublisher/config.py (+19/-0)
lib/lp/archivepublisher/tests/test_config.py (+50/-23)
lib/lp/registry/browser/tests/test_person_view.py (+3/-1)
lib/lp/registry/tests/test_distributionsourcepackage.py (+2/-1)
lib/lp/soyuz/testing/publisher.py (+1049/-0)
lib/lp/soyuz/tests/test_publishing.py (+90/-226)
To merge this branch: bzr merge lp:~james-w/launchpad/move-soyuz-test-publisher
Reviewer Review Type Date Requested Status
Launchpad code reviewers Pending
Review via email: mp+32157@code.launchpad.net

Commit message

Add lp.soyuz.testing.publisher to replace SoyuzTestPublisher and TestNativePublishingBase from lp.soyuz.tests.test_publishing.

Description of the change

Hi,

This branch moves SoyuzTestPublisher and the associated
TestNativePublishingBase to lp.soyuz.testing.publisher,
and also changes the API somewhat.

The main thrust of this change is to get tests away from
sampledata, but there are far to many using these classes
to do it in one go. Therefore I created a new class that
can be transitioned to gradually.

In addition to this I changed the API somewhat to be what
I consider to be cleaner. This way mainly a taste thing,
but some of the changes will also stop tests being too
tightly bound to the implementation of these classes, giving
us more freedom to change things in future. Some of the changes
were a little more than that though, such as removing lots
of commits from the tests using TestNativePublishingBase.
If there are lots of tests that need that many commits then
we can add it back as an opt-in thing, we should punish
every test with it.

In addition I also documented the new interface with docstrings,
and a module docstring to help with porting.

This branch clocks in a bit heavy, but I hope you will forgive
me as quite a lot of that is added docstrings, and there is
quite a lot of moved code.

Thanks,

James

To post a comment you must log in.
11349. By James Westby

Inherit the binary publication component from the source.

11350. By James Westby

Use removeSecurityProxy to change an upload_archive.

Revision history for this message
Jonathan Lange (jml) wrote :
Download full text (5.4 KiB)

On Mon, Aug 9, 2010 at 11:39 PM, James Westby <email address hidden> wrote:
> James Westby has proposed merging lp:~james-w/launchpad/move-soyuz-test-publisher into lp:launchpad/devel with lp:~james-w/launchpad/more-matchers as a prerequisite.
>
> Requested reviews:
>  Launchpad code reviewers (launchpad-reviewers)
>
>
> Hi,
>
> This branch moves SoyuzTestPublisher and the associated
> TestNativePublishingBase to lp.soyuz.testing.publisher,
> and also changes the API somewhat.
>

Thanks!

FWIW, code reviews are much simpler if simple code moves are separated
from API changes. However, I do not wish to look a gift horse in the
mouth, so...

> The main thrust of this change is to get tests away from
> sampledata, but there are far to many using these classes
> to do it in one go. Therefore I created a new class that
> can be transitioned to gradually.
>

Seems sensible.

> In addition to this I changed the API somewhat to be what
> I consider to be cleaner. This way mainly a taste thing,
> but some of the changes will also stop tests being too
> tightly bound to the implementation of these classes, giving
> us more freedom to change things in future.

That's ok, I have excellent taste.

> Some of the changes
> were a little more than that though, such as removing lots
> of commits from the tests using TestNativePublishingBase.
> If there are lots of tests that need that many commits then
> we can add it back as an opt-in thing, we should punish
> every test with it.
>

+1

> In addition I also documented the new interface with docstrings,
> and a module docstring to help with porting.
>

Sweet!

Only typos noticed below, along with a couple of small nitpicks. Feel
free to land without getting another review.

...
> === added file 'lib/lp/soyuz/testing/__init__.py'
> === renamed file 'lib/lp/soyuz/testing/__init__.py' => 'lib/lp/soyuz/testing/publisher.py'
> --- lib/lp/soyuz/testing/__init__.py    2010-08-09 22:38:48 +0000
> +++ lib/lp/soyuz/testing/publisher.py   2010-08-09 22:38:53 +0000
> @@ -0,0 +1,1059 @@
> +# Copyright 2010 Canonical Ltd.  This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""Testing helpers for publishing.
> +
> +Porting from TestNativePublishingBase to PublishingTestCase:
> +
...
> +
> +Porting from `lp.soyuz.tests.test_publishing.SoyuzTestPublisher` to
> +`lp.soyuz.testing.publisher.SoyuzTestPublisher`:
> +
...
> +"""
> +
> +__metaclass__ = type
> +
> +__all__ = [
> +    'makeDistributionLucilleconfig',
> +    'makeDistroSeriesLucilleconfig',
> +    'PublishingTestCase',
> +    'SoyuzTestPublisher',
> +]
> +
...
> +
> +class SoyuzTestPublisher:
> +    """Helper class able to publish source and binary packages.
> +
...
> +
> +    Each method has a number of paramters that can be used to control

"parameters"

...
> +    def addFile(self, filename, filecontent=None, restricted=False,
> +                expires=None):
> +        """Add a file to the Librarian.
> +
> +        :param filename: the filename to add.
> +        :param filecontent: the content of the file, or None to generate
> +            some content.
> +        :param restricted: whether t...

Read more...

Unmerged revisions

11350. By James Westby

Use removeSecurityProxy to change an upload_archive.

11349. By James Westby

Inherit the binary publication component from the source.

11348. By James Westby

Some adjustments to fix test fallout.

11347. By James Westby

Write some porting documentation.

11346. By James Westby

Have the PublishingTestCase clean up the created directories.

11345. By James Westby

Port test_config from sampledata.

11344. By James Westby

Finish documenting the new interface.

11343. By James Westby

Revert test cleanups for moving to a subsequent branch.

11342. By James Westby

Revert change of layer as it is no longer necessary.

11341. By James Westby

Fix a test.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/archivepublisher/config.py'
--- lib/lp/archivepublisher/config.py 2010-07-07 06:28:03 +0000
+++ lib/lp/archivepublisher/config.py 2010-08-10 01:42:59 +0000
@@ -7,6 +7,7 @@
7# distribution and distroseries tables7# distribution and distroseries tables
88
9import os9import os
10import shutil
10from StringIO import StringIO11from StringIO import StringIO
11from ConfigParser import ConfigParser12from ConfigParser import ConfigParser
1213
@@ -192,3 +193,21 @@
192 continue193 continue
193 if not os.path.exists(directory):194 if not os.path.exists(directory):
194 os.makedirs(directory, 0755)195 os.makedirs(directory, 0755)
196
197 def removeArchiveDirs(self):
198 required_directories = [
199 self.distroroot,
200 self.poolroot,
201 self.distsroot,
202 self.archiveroot,
203 self.cacheroot,
204 self.overrideroot,
205 self.miscroot,
206 self.temproot,
207 ]
208
209 for directory in required_directories:
210 if directory is None:
211 continue
212 if os.path.exists(directory):
213 shutil.rmtree(directory)
195214
=== modified file 'lib/lp/archivepublisher/tests/test_config.py'
--- lib/lp/archivepublisher/tests/test_config.py 2010-07-18 00:24:06 +0000
+++ lib/lp/archivepublisher/tests/test_config.py 2010-08-10 01:42:59 +0000
@@ -5,52 +5,79 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8import unittest8import os
9
10from zope.component import getUtility
119
12from canonical.config import config10from canonical.config import config
13from canonical.launchpad.interfaces import IDistributionSet
14from canonical.testing import LaunchpadZopelessLayer11from canonical.testing import LaunchpadZopelessLayer
1512from lp.archivepublisher.config import Config
1613from lp.soyuz.testing.publisher import (
17class TestConfig(unittest.TestCase):14 makeDistributionLucilleconfig, makeDistroSeriesLucilleconfig)
15from lp.testing import TestCaseWithFactory
16
17
18class TestConfig(TestCaseWithFactory):
18 layer = LaunchpadZopelessLayer19 layer = LaunchpadZopelessLayer
1920
20 def setUp(self):21 def setUp(self):
22 super(TestConfig, self).setUp()
21 self.layer.switchDbUser(config.archivepublisher.dbuser)23 self.layer.switchDbUser(config.archivepublisher.dbuser)
22 self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']24 self.distribution = self.factory.makeDistribution()
25 makeDistributionLucilleconfig(self.distribution)
26 series1 = self.factory.makeDistroSeries(
27 distribution=self.distribution)
28 makeDistroSeriesLucilleconfig(series1)
29 series2 = self.factory.makeDistroSeries(
30 distribution=self.distribution)
31 makeDistroSeriesLucilleconfig(series2)
32 for series in (series1, series2):
33 for i in range(2):
34 self.factory.makeDistroArchSeries(distroseries=series)
35
36 def getConfig(self):
37 return Config(self.distribution)
2338
24 def testInstantiate(self):39 def testInstantiate(self):
25 """Config should instantiate"""40 """Config should instantiate"""
26 from lp.archivepublisher.config import Config41 d = self.getConfig()
27 d = Config(self.ubuntutest)
2842
29 def testDistroName(self):43 def testDistroName(self):
30 """Config should be able to return the distroName"""44 """Config should be able to return the distroName"""
31 from lp.archivepublisher.config import Config45 d = self.getConfig()
32 d = Config(self.ubuntutest)46 self.assertEqual(self.distribution.name, d.distroName)
33 self.assertEqual(d.distroName, "ubuntutest")
3447
35 def testDistroSeriesNames(self):48 def testDistroSeriesNames(self):
36 """Config should return two distroseries names"""49 """Config should return two distroseries names"""
37 from lp.archivepublisher.config import Config50 d = self.getConfig()
38 d = Config(self.ubuntutest)
39 dsns = d.distroSeriesNames()51 dsns = d.distroSeriesNames()
40 self.assertEquals(len(dsns), 2)52 self.assertEqual(
41 self.assertEquals(dsns[0], "breezy-autotest")53 sorted([ds.name for ds in self.distribution.series]),
42 self.assertEquals(dsns[1], "hoary-test")54 sorted(dsns))
4355
44 def testArchTagsForSeries(self):56 def testArchTagsForSeries(self):
45 """Config should have the arch tags for the drs"""57 """Config should have the arch tags for the drs"""
46 from lp.archivepublisher.config import Config58 d = self.getConfig()
47 d = Config(self.ubuntutest)59 archs = d.archTagsForSeries(self.distribution.series[0].name)
48 archs = d.archTagsForSeries("hoary-test")
49 self.assertEquals(len(archs), 2)60 self.assertEquals(len(archs), 2)
5061
51 def testDistroConfig(self):62 def testDistroConfig(self):
52 """Config should have parsed a distro config"""63 """Config should have parsed a distro config"""
53 from lp.archivepublisher.config import Config64 d = self.getConfig()
54 d = Config(self.ubuntutest)
55 # NOTE: Add checks here when you add stuff in util.py65 # NOTE: Add checks here when you add stuff in util.py
56 self.assertEquals(d.stayofexecution, 5)66 self.assertEquals(d.stayofexecution, 5)
67
68 def test_removeArchiveDirs(self):
69 d = self.getConfig()
70 d.setupArchiveDirs()
71 d.removeArchiveDirs()
72 for directory in [
73 d.distroroot,
74 d.poolroot,
75 d.distsroot,
76 d.archiveroot,
77 d.cacheroot,
78 d.overrideroot,
79 d.miscroot,
80 d.temproot,
81 ]:
82 self.assertFalse(
83 os.path.exists(directory), "%s was not deleted" % directory)
5784
=== modified file 'lib/lp/registry/browser/tests/test_person_view.py'
--- lib/lp/registry/browser/tests/test_person_view.py 2010-08-02 02:13:52 +0000
+++ lib/lp/registry/browser/tests/test_person_view.py 2010-08-10 01:42:59 +0000
@@ -7,6 +7,7 @@
77
8import transaction8import transaction
9from zope.component import getUtility9from zope.component import getUtility
10from zope.security.proxy import removeSecurityProxy
1011
11from canonical.config import config12from canonical.config import config
12from canonical.launchpad.ftests import ANONYMOUS, login13from canonical.launchpad.ftests import ANONYMOUS, login
@@ -528,7 +529,8 @@
528 pub_source=src_pub)529 pub_source=src_pub)
529 self.build = binaries[0].binarypackagerelease.build530 self.build = binaries[0].binarypackagerelease.build
530 self.build.status = BuildStatus.FAILEDTOBUILD531 self.build.status = BuildStatus.FAILEDTOBUILD
531 self.build.archive = publisher.distroseries.main_archive532 removeSecurityProxy(
533 self.build).archive = publisher.distroseries.main_archive
532 login(ANONYMOUS)534 login(ANONYMOUS)
533535
534 def test_related_software_with_failed_build(self):536 def test_related_software_with_failed_build(self):
535537
=== modified file 'lib/lp/registry/tests/test_distributionsourcepackage.py'
--- lib/lp/registry/tests/test_distributionsourcepackage.py 2009-07-19 23:17:34 +0000
+++ lib/lp/registry/tests/test_distributionsourcepackage.py 2010-08-10 01:42:59 +0000
@@ -9,6 +9,7 @@
9import unittest9import unittest
1010
11from zope.component import getUtility11from zope.component import getUtility
12from zope.security.proxy import removeSecurityProxy
1213
13from canonical.testing import LaunchpadZopelessLayer14from canonical.testing import LaunchpadZopelessLayer
1415
@@ -136,7 +137,7 @@
136 # Ensure that the gedit package in gedit-nightly was originally137 # Ensure that the gedit package in gedit-nightly was originally
137 # uploaded to gedit-beta (ie. copied from there).138 # uploaded to gedit-beta (ie. copied from there).
138 gedit_release = self.gedit_nightly_src_hist.sourcepackagerelease139 gedit_release = self.gedit_nightly_src_hist.sourcepackagerelease
139 gedit_release.upload_archive = self.archives['gedit-beta']140 removeSecurityProxy(gedit_release).upload_archive = self.archives['gedit-beta']
140141
141 related_archives = self.source_package.findRelatedArchives()142 related_archives = self.source_package.findRelatedArchives()
142 related_archive_names = [143 related_archive_names = [
143144
=== added file 'lib/lp/soyuz/testing/__init__.py'
=== renamed file 'lib/lp/soyuz/testing/__init__.py' => 'lib/lp/soyuz/testing/publisher.py'
--- lib/lp/soyuz/testing/__init__.py 2010-08-10 01:42:55 +0000
+++ lib/lp/soyuz/testing/publisher.py 2010-08-10 01:42:59 +0000
@@ -0,0 +1,1049 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Testing helpers for publishing.
5
6Porting from TestNativePublishingBase to PublishingTestCase:
7
8 * The publisher methods are no longer available on `self`. Use the
9 instance variable `publisher` now.
10 * `self.pool_dir` and `self.temp_dir` are now not available by
11 default, either use `self.config.poolroot` and `self.config.temproot`,
12 or create a subclass with a setUp that sets them if you access them
13 a lot.
14 * The archive directories on disk will be removed at `tearDown` time.
15 * `checkPublication`, `checkPublications`, `checkPastDate` and
16 `checkSuperseded` are now not available by default, replaced by
17 matchers.
18 - `self.checkPublication(pub, status)` is now
19 `self.assertThat(pub, PublishedStateIs(status))`
20 - `self.checkPublications(pubs, status)` is now
21 `self.assertThat(pubs, PublishedStateIs(status))`
22 - `self.checkPastDate(date, lag=lag)` is now
23 `self.assertThat(date, DateIsInPast(lag=lag))`
24 - `self.checkSuperseded(pubs, supersededby=supersededby)` is now
25 `self.assertThat(pubs, IsSupersededBy(supersededby))`
26 Where `PublishedStateIs` and `IsSupersededBy` can be imported from
27 `lp.soyuz.testing.matchers`, and `DateIsInPast` can be imported
28 from `lp.testing.matchers`.
29 * As `self.getPubSource` and `self.getPubBinaries` are no more they
30 no longer commit after they are called.
31 * See below for changed usage of `SoyuzTestPublisher` as well.
32
33Porting from `lp.soyuz.tests.test_publishing.SoyuzTestPublisher` to
34`lp.soyuz.testing.publisher.SoyuzTestPublisher`:
35
36 * `prepareBreezyAutotest` is removed, in favour of using the
37 factory. Replace calls by `prepare`, or `prepareForBinaryPublications`
38 depending on whether you plan to publish binaries.
39 * The `ubuntutest` attribute is replaced by `distribution` and now
40 could be any distribution.
41 * The `breezy_autotest` attribute has been replaced by `distroseries`,
42 and now could be any distroseries of `distribution`.
43 * The `person` attribute has been removed, and uploads are now
44 attributed to arbitrary people.
45 * The `breezy_autotest_i386` and `breezy_autotest_hppa` attributes
46 have been removed.
47 * The `SourcePackageName` for the default package name isn't created
48 until it is needed.
49 * Some methods may have different defaults for some less important
50 parameters. These should be specified explicitly if needed.
51 * The following methods have been replaced,
52 - `getPubSource` is replaced by `publishSource`
53 - `getPubBinaries` is replaced by `publishBinaries`
54 - `addPackageUpload` is replaced by `makePackageUpload`
55 - `addMockFile` is replaced by `addFile`
56"""
57
58__metaclass__ = type
59
60__all__ = [
61 'makeDistributionLucilleconfig',
62 'makeDistroSeriesLucilleconfig',
63 'PublishingTestCase',
64 'SoyuzTestPublisher',
65]
66
67import datetime
68import operator
69import os
70
71import pytz
72from zope.security.proxy import removeSecurityProxy
73
74from canonical.config import config
75from canonical.database.constants import UTC_NOW
76from canonical.launchpad.scripts import QuietFakeLogger
77from canonical.testing import LaunchpadZopelessLayer
78from lp.archivepublisher.config import Config
79from lp.archivepublisher.diskpool import DiskPool
80from lp.buildmaster.interfaces.buildbase import BuildStatus
81from lp.registry.interfaces.pocket import PackagePublishingPocket
82from lp.soyuz.interfaces.binarypackagerelease import BinaryPackageFormat
83from lp.soyuz.interfaces.publishing import (
84 PackagePublishingPriority, PackagePublishingStatus)
85from lp.testing import TestCaseWithFactory
86from lp.testing.factory import LaunchpadObjectFactory
87
88
89class SoyuzTestPublisher:
90 """Helper class able to publish source and binary packages.
91
92 Once you have a test publisher you can use it to publish packages,
93 either source only, or source and binary, with all required
94 links between them. This can ease complicated test setup where lots
95 of coherent objects are required. Where your needs are more simple,
96 you may be better served by using the LaunchpadObjectFactory directly,
97 to avoid coupling your tests with aspects that aren't important to it.
98
99 To create a SoyuzTestPublisher, simply instantiate the class. If you
100 already have an instance of the LaunchpadObjectFactory you should
101 pass this to the constructor, but if you don't you can omit it and
102 one will be created for you.
103
104 publisher = SoyuzTestPublisher(factory=factory)
105
106 The test publisher has a distribution and a distroseries within
107 that distribution which are the default targets of the packages
108 that it publishes. It is required to set these up by calling
109
110 publisher.prepare()
111
112 or if you are going to publish binary packages
113
114 publisher.prepareForBinaryPublications()
115
116 At any time you can change the default distroseries, for instance
117 if you wish to publish packages to two distroseries during the course
118 of your tests. You can do this by calling
119
120 publisher.setDefaultDistroSeries(distroseries=distroseries)
121
122 or alternatively omit the distroseries parameter to have a new
123 distroseries created in the default distribution.
124
125 You are then ready to publish packages. For this use the publish
126 methods. To publish a source package call
127
128 source_publishing = publisher.publishSource()
129
130 which will publish a new source package in to the default distroseries,
131 and return the publishing record to you.
132
133 To publish binary packages call
134
135 binary_publishings = publisher.publishBinaries()
136
137 which will create you a source package, and then a binary package for
138 each architecture in the default distroseries, with the associated
139 build records, and return you a list of the binary publishing records
140 that it created.
141
142 Each method has a number of paramters that can be used to control
143 various aspects of the packages that are published, such as the name,
144 version, pocket, status, etc. You should specify all of the parameters
145 that are germane to your test, to decouple your tests from the defaults
146 of the test publisher.
147
148 There are additional methods that may be of use in certain situations,
149 as they allow you to create subsets of the objects created by the
150 above methods, or supplemental objects that are required by some tests.
151 """
152
153 def __init__(self, factory=None):
154 """Create a `SoyuzTestPublisher`
155
156 :param factory: the `LaunchpadObjectFactory` to use for creating
157 objects, or None to create one.
158 """
159 self.factory = factory
160 if self.factory is None:
161 self.factory = LaunchpadObjectFactory()
162 self.default_package_name = 'foo'
163
164 def prepare(self):
165 """Setup the instance with a standard skeleton.
166
167 See `setUpForBinaryPublications` if you wish to publish binaries.
168 """
169 self.distribution = self.factory.makeDistribution()
170 self.setDefaultDistroSeries()
171
172 def prepareForBinaryPublications(self):
173 """Setup this instance for publishing binary packages."""
174 self.prepare()
175 distroarchseries1 = self.factory.makeDistroArchSeries(
176 distroseries=self.distroseries, supports_virtualized=True)
177 distroarchseries2 = self.factory.makeDistroArchSeries(
178 distroseries=self.distroseries, supports_virtualized=True)
179 removeSecurityProxy(self.distroseries).nominatedarchindep = (
180 distroarchseries1)
181 self.addFakeChroots(distroseries=self.distroseries)
182
183 def setDefaultDistroSeries(self, distroseries=None):
184 """Set the default series for publishing packages.
185
186 If you don't specify a distroseries as a target in other method
187 calls then the distroseries set as default by the last call
188 to this method will be used.
189
190 :param distroseries: The `IDistroSeries` to use as default. If
191 it's None, one will be created.
192 :return: The default `IDistroSeries`.
193 """
194 if distroseries is None:
195 distroseries = self.factory.makeDistroRelease(
196 distribution=self.distribution)
197 self.distroseries = distroseries
198 return self.distroseries
199
200 def addFakeChroots(self, distroseries=None):
201 """Add fake chroots for all the architectures in distroseries.
202
203 This creates files on the librarian for each `IDistroArchSeries`
204 in the distroseries. The chroots aren't suitable for actually
205 building packages, but are sufficient for other methods to
206 believe it would be worth trying.
207
208 :param distroseries: the `IDistroSeries` for which each architecture
209 will get a chroot, this can be None to use the default
210 distroseries.
211 """
212 if distroseries is None:
213 distroseries = self.distroseries
214 fake_chroot = self.addFile('fake_chroot.tar.gz')
215 for arch in distroseries.architectures:
216 arch.addOrUpdateChroot(fake_chroot)
217
218 def addFile(self, filename, filecontent=None, restricted=False,
219 expires=None):
220 """Add a file to the Librarian.
221
222 :param filename: the filename to add.
223 :param filecontent: the content of the file, or None to generate
224 some content.
225 :param restricted: whether the file should be on the restricted
226 librarian.
227 :param exipres: a `datetime.datetime` at which the file should
228 expire, or None to not have the file expire.
229 :return: an `ILibraryFileAlias` corresponding to the file uploaded.
230 """
231 return self.factory.makeLibraryFileAlias(
232 filename=filename, content=filecontent, restricted=restricted,
233 content_type='application/text', expires=expires)
234
235 # backwards compatibility for the old interface.
236 addMockFile = addFile
237
238 def makePackageUpload(self, archive=None, distroseries=None,
239 pocket=None, changes_file_name=None,
240 changes_file_content=None, signing_key=None,
241 status=None):
242 """Make a `PackageUpload`.
243
244 :param archive: the archive to upload to, or None to use
245 the default archive.
246 :param distroseries: the distroseries to upload to, or
247 None to use the default.
248 :param pocket: the `PackagePublishingPocket` to upload to,
249 or None for the default pocket, RELEASE.
250 :param changes_file_name: the filename of the changes file
251 to create, or None for an arbitrary name.
252 :param changes_file_content: the content of the changes
253 file, or None to generate some.
254 :param signing_key: the key with which to sign the upload,
255 or None to have an unsigned upload.
256 :param status: the `PackageUploadStatus` of the upload, or
257 None for an arbitrary status.
258 :return: the created `PackageUpload`.
259 """
260 if distroseries is None:
261 distroseries = self.distroseries
262 if archive is None:
263 archive = distroseries.distribution.main_archive
264 if pocket is None:
265 pocket = PackagePublishingPocket.RELEASE
266 package_upload = self.factory.makePackageUpload(
267 archive=archive, distroseries=distroseries, pocket=pocket,
268 changes_filename=changes_file_name,
269 changes_file_content=changes_file_content,
270 signing_key=signing_key, status=status)
271 return package_upload
272
273 def makeSourcePackageRelease(self, distroseries=None, sourcename=None,
274 archive=None, version=None, urgency=None,
275 component_name=None, section_name=None,
276 maintainer=None, creator=None,
277 builddepends=None, builddependsindep=None,
278 build_conflicts=None,
279 build_conflicts_indep=None,
280 architecturehintlist=None,
281 dsc_signing_key=None,
282 dsc_maintainer_rfc822=None,
283 dsc_standards_version=None,
284 dsc_format=None, dsc_binaries=None,
285 date_uploaded=None, changelog_entry=None):
286 """Make a `SourcePackageRelease`.
287
288 :param distroseries: the distroseries that the package should
289 be targered to, or None to use the default.
290 :param archive: the archive that should be targeted, or
291 None to use the default.
292 :param sourcename: the (string) source package name to create
293 a package for, or None to use the default.
294 :param version: the (string) version of the package to create,
295 or None to use an arbitrary version.
296 :param component_name: the name of the component the package
297 should be targeted at, or None to use an arbitrary component.
298 :param section_name: the name of the section the package
299 should be targeted to, or None to use an arbitrary section.
300 :param urgency: the `SourcePackageUrgency` that should be used for
301 the created `SourcePackageRelease`, or None to use an arbitrary
302 urgency.
303 :param builddepends: the build depends that should be recorded
304 for the source package.
305 :type builddepends: str or None
306 :param builddependsindep: the Build-Depends-Indep that should
307 be recorded for the source package.
308 :type builddependsindep: str or None
309 :param buildconflicts: the build conflicts that should be recorded
310 for the source package.
311 :type buildconflicts: str or None
312 :param buildconflictsindep: the Build-Conflicts-Indep that should
313 be recorded for the source package.
314 :type buildconflictsindep: str or None
315 :param architecturehintlist: the list of architectures the
316 source should state it should be built for, either 'all',
317 'any', a list of architectures, or None for an arbitrary
318 hint list.
319 :type architecturehintlist: str or None
320 :param dsc_standards_version: the standards version that should
321 be recorded as having come from the uploaded .dsc, or None
322 for an arbitrary standards version.
323 :type dsc_standards_version: str or None
324 :param dsc_format: the dsc formath that sould be recorded
325 as having come from the uploaded .dsc, or None for an
326 arbitrary format.
327 :type dsc_standards_version: str or None
328 :param dsc_binaries: the list of binary packages that
329 should be recorded has having come from the uploaded
330 .dsc, or None for an arbitrary list.
331 :type dsc_binaries: str or None
332 :param dsc_maintainer_rfc822: the string containing the
333 name and email address of the person that changed the
334 package, in rfc822 format, or None for an arbitrary
335 person's details.
336 :param maintainer: the `IPerson` that should be recorded as
337 the maintainer of the package, or None for an arbitrary
338 person.
339 :param creator: the `IPerson` that should be recorded as
340 the uploader of the package, or None for an arbitrary
341 person.
342 :param date_uploaded: the datetime that the package should
343 appear to have been uploaded at, or None for an arbitrary
344 date.
345 :param changelog_entry: the changelog entry of the upload, or
346 None for no entry.
347 :return: the created `SourcePackageRelease`.
348 """
349 if distroseries is None:
350 distroseries = self.distroseries
351 if archive is None:
352 archive = distroseries.distribution.main_archive
353 if sourcename is None:
354 sourcename = self.default_package_name
355 spn = self.factory.getOrMakeSourcePackageName(name=sourcename)
356 component = self.factory.makeComponent(name=component_name)
357 if dsc_binaries is None:
358 dsc_binaries = '%s-bin' % sourcename
359 if architecturehintlist is None:
360 architecturehintlist = 'all'
361 if dsc_standards_version is None:
362 dsc_standards_version = '3.6.2'
363 if dsc_format is None:
364 dsc_format = '1.0'
365 if date_uploaded is None:
366 date_uploaded = UTC_NOW
367 return self.factory.makeSourcePackageRelease(
368 distroseries=distroseries,
369 sourcepackagename=spn,
370 maintainer=maintainer,
371 creator=creator,
372 component=component,
373 section_name=section_name,
374 urgency=urgency,
375 version=version,
376 builddepends=builddepends,
377 builddependsindep=builddependsindep,
378 build_conflicts=build_conflicts,
379 build_conflicts_indep=build_conflicts_indep,
380 architecturehintlist=architecturehintlist,
381 dscsigningkey=dsc_signing_key,
382 dsc_maintainer_rfc822=dsc_maintainer_rfc822,
383 dsc_standards_version=dsc_standards_version,
384 dsc_format=dsc_format,
385 dsc_binaries=dsc_binaries,
386 archive=archive,
387 date_uploaded=date_uploaded,
388 changelog_entry=changelog_entry,
389 )
390
391 def publishSource(self, sourcename=None, version=None,
392 component_name=None, section_name=None,
393 filename=None, filecontent=None,
394 changes_file_content=None, status=None, pocket=None,
395 urgency=None, scheduleddeletiondate=None,
396 dateremoved=None, distroseries=None, archive=None,
397 builddepends=None, builddependsindep=None,
398 build_conflicts=None, build_conflicts_indep=None,
399 architecturehintlist=None, dsc_standards_version=None,
400 dsc_format=None, dsc_binaries=None,
401 dsc_maintainer_rfc822=None, maintainer=None,
402 creator=None, date_uploaded=None,
403 files_expire=None, changelog_entry=None):
404 """Publish a source package.
405
406 Publishes a source package and returns the resulting
407 `SourcePackagePublishingHistory`.
408
409 :param sourcename: the (string) source package name to publish
410 a package for, or None to use the default.
411 :param version: the (string) version of the package to publish,
412 or None to use an arbitrary version.
413 :param component_name: the name of the component to publish to,
414 or None to use an arbitrary component.
415 :param section_name: the name of the section to publish to,
416 or None to use an arbitrary section.
417 :param filename: the filename of the file making up the
418 `SourcePackageRelease`, or None to use a name based
419 on sourcename and version.
420 :param filecontent: the content of the file making up the
421 `SourcePackageRelease`, or None to use arbitrary content.
422 :param changes_file_content: the content of the changes
423 file for the upload, or None to use arbitrary content.
424 :param status: the `PackagePublishingStatus` that should be used
425 for the created publishing record, or None for the default
426 status, PUBLISHED.
427 :param pocket: the `PackagePublishingPocket` that should be
428 used for the created publishing record and the associated
429 `PackageUpload`, or None for teh default pocket, RELEASE.
430 :param urgency: the `SourcePackageUrgency` that should be used for
431 the created `SourcePackageRelease`, or None to use an arbitrary
432 urgency.
433 :param scheduleddeletiondate: the scheduled deletion date that
434 should be set on the created publishing record, or None
435 to have no scheduled deletion date.
436 :type scheduleddeletiondate: `datetime.datetime`
437 :param dateremoved: the date that should be recorded as being
438 the date the package was removed on the created publishing
439 record, or None if it hasn't been removed.
440 :type dateremoved: `datetime.datetime`
441 :param distroseries: the distroseries that should be
442 published to, or None to use the default.
443 :param archive: the archive that should be published to, or
444 None to use the default.
445 :param builddepends: the build depends that should be recorded
446 for the source package.
447 :type builddepends: str or None
448 :param builddependsindep: the Build-Depends-Indep that should
449 be recorded for the source package.
450 :type builddependsindep: str or None
451 :param buildconflicts: the build conflicts that should be recorded
452 for the source package.
453 :type buildconflicts: str or None
454 :param buildconflictsindep: the Build-Conflicts-Indep that should
455 be recorded for the source package.
456 :type buildconflictsindep: str or None
457 :param architecturehintlist: the list of architectures the
458 source should state it should be built for, either 'all',
459 'any', a list of architectures, or None for an arbitrary
460 hint list.
461 :type architecturehintlist: str or None
462 :param dsc_standards_version: the standards version that should
463 be recorded as having come from the uploaded .dsc, or None
464 for an arbitrary standards version.
465 :type dsc_standards_version: str or None
466 :param dsc_format: the dsc formath that sould be recorded
467 as having come from the uploaded .dsc, or None for an
468 arbitrary format.
469 :type dsc_standards_version: str or None
470 :param dsc_binaries: the list of binary packages that
471 should be recorded has having come from the uploaded
472 .dsc, or None for an arbitrary list.
473 :type dsc_binaries: str or None
474 :param dsc_maintainer_rfc822: the string containing the
475 name and email address of the person that changed the
476 package, in rfc822 format, or None for an arbitrary
477 person's details.
478 :param maintainer: the `IPerson` that should be recorded as
479 the maintainer of the package, or None for an arbitrary
480 person.
481 :param creator: the `IPerson` that should be recorded as
482 the uploader of the package, or None for an arbitrary
483 person.
484 :param date_uploaded: the datetime that the package should
485 appear to have been uploaded at, or None for an arbitrary
486 date.
487 :param files_expire: the date at which the librarian files
488 for the package should expire, or None for no expiry.
489 :param changelog_entry: the changelog entry of the upload, or
490 None for no entry.
491 :return: the created `SourcePackagePublishingHistory`.
492 """
493 spr = self.makeSourcePackageRelease(
494 distroseries=distroseries,
495 sourcename=sourcename,
496 archive=archive,
497 version=version,
498 urgency=urgency,
499 component_name=component_name,
500 section_name=section_name,
501 maintainer=maintainer,
502 creator=creator,
503 builddepends=builddepends,
504 builddependsindep=builddependsindep,
505 build_conflicts=build_conflicts,
506 build_conflicts_indep=build_conflicts_indep,
507 architecturehintlist=architecturehintlist,
508 dsc_maintainer_rfc822=dsc_maintainer_rfc822,
509 dsc_standards_version=dsc_standards_version,
510 dsc_format=dsc_format,
511 dsc_binaries=dsc_binaries,
512 date_uploaded=date_uploaded,
513 changelog_entry=changelog_entry,
514 )
515 changes_file_name = "%s_%s_source.changes" % (
516 spr.sourcepackagename.name, spr.version)
517 package_upload = self.makePackageUpload(
518 archive=spr.upload_archive,
519 distroseries=spr.upload_distroseries,
520 pocket=pocket,
521 changes_file_name=changes_file_name,
522 changes_file_content=changes_file_content,
523 )
524 removeSecurityProxy(package_upload).addSource(spr)
525
526 if filename is None:
527 filename = "%s_%s.dsc" % (
528 spr.sourcepackagename.name, spr.version)
529 alias = self.addFile(
530 filename, filecontent=filecontent,
531 restricted=spr.upload_archive.private, expires=files_expire)
532 spr.addFile(alias)
533
534 if status is None:
535 status = PackagePublishingStatus.PUBLISHED
536 if date_uploaded is None:
537 date_uploaded = UTC_NOW
538 spph = self.factory.makeSourcePackagePublishingHistory(
539 distroseries=spr.upload_distroseries,
540 archive=spr.upload_archive,
541 sourcepackagerelease=spr,
542 status=status,
543 date_uploaded=date_uploaded,
544 dateremoved=dateremoved,
545 scheduleddeletiondate=scheduleddeletiondate,
546 pocket=package_upload.pocket,
547 )
548 return spph
549
550 def publishBinaries(self, binaryname=None, summary=None,
551 description=None, shlibdep=None, depends=None,
552 recommends=None, suggests=None, conflicts=None,
553 replaces=None, provides=None, pre_depends=None,
554 enhances=None, breaks=None, filecontent=None,
555 changes_file_content=None, status=None,
556 pocket=None, format=None, scheduleddeletiondate=None,
557 dateremoved=None, distroseries=None, archive=None,
558 pub_source=None, version=None,
559 architecturespecific=False, builder=None,
560 component_name=None, section_name=None,
561 priority=None, installed_size=None,
562 files_expire=None):
563 """Publish some binary packages.
564
565 Publishes a number of binary packages and returns a list of the
566 resulting `BinaryPackagePublishingHistory` objects.
567
568 :param binaryname: the binary package name to use, or None
569 for a name derived from the default package name.
570 :type binaryname: str or None
571 :param summary: the summary (first line) of the package description.
572 :type summary: str or None.
573 :param description: the continuation lines of the package
574 description.
575 :type description: str or None
576 :param shlibdep: the shared library dependencies the binary packages
577 should have.
578 :type shlibdep: str or None
579 :param depends: the string containing the package dependencies the
580 binary packages should have.
581 :type depends: str or None
582 :param recommends: the string containing the package recommendations
583 the binary packages should have.
584 :type recommends: str or None
585 :param suggests: the string containing the package suggestions
586 the binary packages should have.
587 :type suggests: str or None
588 :param conflicts: the string containing the package conflicts
589 the binary packages should have.
590 :type conflicts: str or None
591 :param replaces: the string containing the package replaces
592 relationships the binary packages should have.
593 :type replaces: str or None
594 :param provides: the string containing the package provides
595 relationships the binary packages should have.
596 :type provides: str or None
597 :param pre_depends: the string containing the package
598 pre-dependencies the binary packages should have.
599 :type pre_depends: str or None
600 :param enhances: the string containing the package enhances
601 relationships the binary packages should have.
602 :type enhances: str or None
603 :param breaks: the string containing the package breaks
604 relationships the binary packages should have.
605 :type breaks: str or None
606 :param filecontent: the content that the files associated with
607 the binary packages should have.
608 :type filecontent: str or None
609 :param changes_file_content: the content that the uploaded changes
610 file associated with the binary packages should have.
611 :type changes_file_content: str or None
612 :param status: the `PackagePublishingStatus` that the binary
613 packages should have, or None for the default,
614 `PackagePublishingStatus.PUBLISHED`.
615 :type status: `PackagePublishingStatus` or None
616 :param pocket: the `PackagePublishingPocket` that the binary
617 packages should be published to, or None for the default,
618 `PackagePublishingPocket.RELEASE`.
619 :type pocket: `PackagePublishingPocket` or None
620 :param format: the `BinaryPackageFormat` that the binary packages
621 should be, or None for the default, `BinaryPackageFormat.DEB`.
622 :type format: `BinaryPackageFormat` or None
623 :param scheduleddeletiondate: the date that the packages should
624 be scheduled for deletion, or None if it should not
625 be.
626 :type scheduleddeletiondate: `datetime.datetime` or None
627 :param dateremoved: the date that the packages should
628 be recorded as having been deleted, or None for packages
629 that haven't been deleted.
630 :type dateremoved: `datetime.datetime` or None
631 :param distroseries: the distroseries that the packages should
632 be published to, or None for the default distroseries.
633 :type distroseries: `IDistroSeries` or None
634 :param archive: the archive that the packages should be published
635 to, or None for the default archive.
636 :type archive: `IArchive` or None
637 :param pub_source: the `SourcePackagePublishingHistory` that
638 the builds and binaries should be associated with, or
639 None to create a new one.
640 :type pub_source: `SourcePackagePublishingHistory` or None
641 :param version: the version that the binary packages should
642 have, or None for an arbitrary version.
643 :type version: str or None
644 :param architecturespecific: whether the binary packages
645 should be architecturespecific, default is False.
646 :type architecturespecific: bool
647 :param builder: the builder that the builds should state they
648 were built by, or None.
649 :type builder: `IBuilder` or None
650 :param component_name: the name of the component that the packages
651 should be published to, or None for an arbitrary component.
652 :type component_name: str or None
653 :param section_name: the name of the section that the packages
654 should be published to, or None for an arbitrary section.
655 :type section_name: str or None
656 :param priority: the `PackagePublishingPriority` that the packages
657 should be published with, or None for an arbitrary priority.
658 :type priority: `PackagePublishingPriority` or None
659 :param installed_size: the size that the packages should report
660 that they take up when installed, or None for an arbitrary
661 size.
662 :type installed_size: int or None
663 :param files_expire: when the files associated with the packages
664 should expire, or None to not expire.
665 :type files_expire: `datetime.datetime` or None
666 :return: the binary publishing records that were created.
667 :rtype: an iterable of `BinaryPackagePublishingHistory`.
668 """
669 if binaryname is None:
670 binaryname = "%s-bin" % self.default_package_name
671 if distroseries is None:
672 distroseries = self.distroseries
673
674 if distroseries.nominatedarchindep is None:
675 raise AssertionError(
676 "distroseries not set up for binary publishing. If you "
677 "are using the default you should use "
678 "setUpForBinaryPublications() rather than setUp().")
679
680 if archive is None:
681 archive = distroseries.main_archive
682
683 if pub_source is None:
684 sourcename = "%s" % binaryname.split('-')[0]
685 if architecturespecific:
686 architecturehintlist = 'any'
687 else:
688 architecturehintlist = 'all'
689
690 pub_source = self.publishSource(
691 sourcename=sourcename, status=status, pocket=pocket,
692 archive=archive, distroseries=distroseries,
693 version=version, architecturehintlist=architecturehintlist,
694 component_name=component_name, files_expire=files_expire)
695 else:
696 archive = pub_source.archive
697
698 builds = pub_source.createMissingBuilds()
699 published_binaries = []
700 for build in builds:
701 build.builder = builder
702 binarypackagerelease = self.uploadBinaryForBuild(
703 build, binaryname, filecontent=filecontent, summary=summary,
704 description=description, shlibdep=shlibdep,
705 depends=depends, recommends=recommends, suggests=suggests,
706 conflicts=conflicts, replaces=replaces,
707 provides=provides, pre_depends=pre_depends,
708 enhances=enhances, breaks=breaks, format=format,
709 installed_size=installed_size, priority=priority,
710 files_expire=files_expire)
711 pub_binaries = self.publishBinaryInArchive(
712 binarypackagerelease, archive, status=status, pocket=pocket,
713 scheduleddeletiondate=scheduleddeletiondate,
714 dateremoved=dateremoved)
715 published_binaries.extend(pub_binaries)
716 package_upload = self.makePackageUpload(
717 archive=archive, distroseries=distroseries, pocket=pocket,
718 changes_file_content=changes_file_content,
719 changes_file_name='%s_%s_%s.changes' %
720 (binaryname, binarypackagerelease.version,
721 build.arch_tag))
722 package_upload.addBuild(build)
723
724 return sorted(
725 published_binaries, key=operator.attrgetter('id'), reverse=True)
726
727 def uploadBinaryForBuild(self, build, binaryname, filecontent=None,
728 summary=None, description=None, shlibdep=None,
729 depends=None, recommends=None, suggests=None,
730 conflicts=None, replaces=None, provides=None,
731 pre_depends=None, enhances=None, breaks=None,
732 format=None, installed_size=None,
733 version=None, files_expire=None, priority=None):
734 """Create a `BinaryPackageRelease` for a `PackageBuild`.
735
736 Given a build this method will create a `BinaryPackageRelease`
737 for a package that results from the build. It will also
738 add a file that represents the contents of that binary package,
739 and will adjust the build to look like it has completed.
740
741 :param build: the build that the binary should be associated with.
742 :type build: `PackageBuild`
743 :param binaryname: the name of the binary package that should
744 be created.
745 :type binaryname: str
746 :param filecontent: the content that the file associated with
747 the binary package should have.
748 :type filecontent: str or None
749 :param summary: the summary (first line) of the package description.
750 :type summary: str or None.
751 :param description: the continuation lines of the package
752 description.
753 :type description: str or None
754 :param shlibdep: the shared library dependencies the binary package
755 should have.
756 :type shlibdep: str or None
757 :param depends: the string containing the package dependencies the
758 binary package should have.
759 :type depends: str or None
760 :param recommends: the string containing the package recommendations
761 the binary package should have.
762 :type recommends: str or None
763 :param suggests: the string containing the package suggestions
764 the binary package should have.
765 :type suggests: str or None
766 :param conflicts: the string containing the package conflicts
767 the binary package should have.
768 :type conflicts: str or None
769 :param replaces: the string containing the package replaces
770 relationships the binary package should have.
771 :type replaces: str or None
772 :param provides: the string containing the package provides
773 relationships the binary package should have.
774 :type provides: str or None
775 :param pre_depends: the string containing the package
776 pre-dependencies the binary package should have.
777 :type pre_depends: str or None
778 :param enhances: the string containing the package enhances
779 relationships the binary package should have.
780 :type enhances: str or None
781 :param breaks: the string containing the package breaks
782 relationships the binary package should have.
783 :type breaks: str or None
784 :param format: the `BinaryPackageFormat` that the binary package
785 should be, or None for the default, `BinaryPackageFormat.DEB`.
786 :type format: `BinaryPackageFormat` or None
787 :param installed_size: the size that the package should report
788 that it takes up when installed, or None for an arbitrary
789 size.
790 :type installed_size: int or None
791 :param version: the version that the binary package should
792 have, or None for an arbitrary version.
793 :type version: str or None
794 :param files_expire: when the file associated with the package
795 should expire, or None to not expire.
796 :type files_expire: `datetime.datetime` or None
797 :param priority: the priority the package should state, or None
798 for an arbitrary priority.
799 :type priority: `PackagePublishingPriority` or None
800 :return: the created binary package
801 :rtype: `BinaryPackageRelease`
802 """
803 sourcepackagerelease = build.source_package_release
804 distroarchseries = build.distro_arch_series
805 architecturespecific = (
806 not sourcepackagerelease.architecturehintlist == 'all')
807 binarypackagename = self.factory.getOrMakeBinaryPackageName(
808 name=binaryname)
809 if format is None:
810 format = BinaryPackageFormat.DEB
811
812 binarypackagerelease = self.factory.makeBinaryPackageRelease(
813 build=build,
814 binarypackagename=binarypackagename,
815 summary=summary,
816 description=description,
817 shlibdeps=shlibdep,
818 depends=depends,
819 recommends=recommends,
820 suggests=suggests,
821 conflicts=conflicts,
822 replaces=replaces,
823 provides=provides,
824 pre_depends=pre_depends,
825 enhances=enhances,
826 breaks=breaks,
827 essential=False,
828 architecturespecific=architecturespecific,
829 binpackageformat=format,
830 priority=priority,
831 installed_size=installed_size,
832 component=sourcepackagerelease.component,
833 version=version,
834 )
835
836 # Create the corresponding binary file.
837 if architecturespecific:
838 filearchtag = distroarchseries.architecturetag
839 else:
840 filearchtag = 'all'
841 filename = '%s_%s_%s.%s' % (binaryname, sourcepackagerelease.version,
842 filearchtag, format.name.lower())
843 alias = self.addFile(
844 filename, filecontent=filecontent,
845 restricted=build.archive.private, expires=files_expire)
846 binarypackagerelease.addFile(alias)
847
848 # Adjust the build record in way it looks complete.
849 naked_build = removeSecurityProxy(build)
850 naked_build.status = BuildStatus.FULLYBUILT
851 naked_build.date_finished = datetime.datetime(
852 2008, 1, 1, 0, 5, 0, tzinfo=pytz.UTC)
853 naked_build.date_started = (
854 build.date_finished - datetime.timedelta(minutes=5))
855 buildlog_filename = 'buildlog_%s-%s-%s.%s_%s_%s.txt.gz' % (
856 build.distribution.name,
857 build.distro_series.name,
858 build.distro_arch_series.architecturetag,
859 build.source_package_release.name,
860 build.source_package_release.version,
861 build.status.name)
862 naked_build.log = self.addFile(
863 buildlog_filename, filecontent='Built!',
864 restricted=build.archive.private)
865
866 return binarypackagerelease
867
868 def publishBinaryInArchive(self, binarypackagerelease, archive,
869 status=None, pocket=None,
870 scheduleddeletiondate=None,
871 dateremoved=None):
872 """Publish a `BinaryPackageRelease` in to an archive.
873
874 Returns the created `BinaryPackagePublishingHistory`.
875
876 :param binarypackagerelease: the binary package to publish.
877 :type binarypackagerelease: `BinaryPackageRelease`
878 :param archive: the archive to publish to.
879 :type archive: `IArchive`
880 :param status: the status that the created publishing record
881 should have, or None for the default of
882 `PackagePublishingStatus.PENDING`.
883 :type status: `PackagePublishingStatus` or None
884 :param pocket: the pocket to publish to, or None for the
885 default pocket of `PackagePublishingPocket.RELEASE`.
886 :type pocket: `PackagePublishingPocket` or None
887 :param scheduleddeletiondate: the date at which the record should
888 be scheduled for deletion, or None to not schedule for
889 deletion.
890 :type scheduleddeletiondate: `datetime.datetime` or None
891 :param dateremoved: the date that the publishing should
892 be recorded as having been deleted, or None to not set it.
893 :type dateremoved: `datetime.datetime` or None
894 :return: the created publishing record.
895 :rtype: `BinaryPackagePublishingHistory`
896 """
897 distroarchseries = binarypackagerelease.build.distro_arch_series
898
899 # Publish the binary.
900 if binarypackagerelease.architecturespecific:
901 archs = [distroarchseries]
902 else:
903 archs = distroarchseries.distroseries.architectures
904
905 if status is None:
906 status = PackagePublishingStatus.PENDING
907 if pocket is None:
908 pocket = PackagePublishingPocket.RELEASE
909
910 pub_binaries = []
911 for arch in archs:
912 pub = self.factory.makeBinaryPackagePublishingHistory(
913 distroarchseries=arch,
914 binarypackagerelease=binarypackagerelease,
915 status=status,
916 scheduleddeletiondate=scheduleddeletiondate,
917 dateremoved=dateremoved,
918 pocket=pocket,
919 archive=archive,
920 section_name=binarypackagerelease.section.name,
921 priority=binarypackagerelease.priority,
922 component=binarypackagerelease.component,
923 )
924 pub_binaries.append(pub)
925
926 return pub_binaries
927
928 def _findChangesFile(self, top, name_fragment):
929 """File with given name fragment in directory tree starting at top."""
930 for root, dirs, files in os.walk(top, topdown=False):
931 for name in files:
932 if (name.endswith('.changes') and
933 name.find(name_fragment) > -1):
934 return os.path.join(root, name)
935 return None
936
937 def createSource(self, sourcename, version, archive=None,
938 distroseries=None, new_version=None,
939 component_name=None):
940 """Create source with meaningful '.changes' file.
941
942 :param sourcename: the source package name that the changes
943 file should reference.
944 :type sourcename: str
945 :param version: the version of the changes file that should
946 be used.
947 :type version: str
948 :param archive: the archive that should be uploaded to, or None
949 for the default archive.
950 :type archive: `IArchive` or None
951 :param distroseries: the distroseries to publish to, or None
952 for the default.
953 :type distroseries: `IDistroSeries` or None
954 :param new_version: the version of the package to publish,
955 or None to use the found version.
956 :type new_version: str or None
957 :param component_name: the name of the component to upload
958 and publish to, or None for an arbitrary component.
959 :type component_name: str
960 :return: the created `SourcePackagePublishingHistory`, or
961 None if the changes file wasn't found.
962 :rtype: `SourcePackagePublishingHistory` or None
963 """
964 top = 'lib/lp/archiveuploader/tests/data/suite'
965 name_fragment = '%s_%s' % (sourcename, version)
966 changesfile_path = self._findChangesFile(top, name_fragment)
967
968 source = None
969
970 if changesfile_path is not None:
971 if new_version is None:
972 new_version = version
973 changesfile_content = ''
974 handle = open(changesfile_path, 'r')
975 try:
976 changesfile_content = handle.read()
977 finally:
978 handle.close()
979
980 source = self.publishSource(
981 sourcename=sourcename, archive=archive, version=new_version,
982 changes_file_content=changesfile_content,
983 distroseries=distroseries, component_name=component_name)
984
985 return source
986
987
988def makeDistributionLucilleconfig(distribution):
989 """Create a lucille config for the distribution."""
990 removeSecurityProxy(distribution).lucilleconfig = """[publishing]
991pendingremovalduration=5
992root=/var/tmp/archive
993archiveroot=/var/tmp/archive/%(name)s
994poolroot=/var/tmp/archive/%(name)s/pool
995distsroot=/var/tmp/archive/%(name)s/dists
996overrideroot=/var/tmp/archive/%(name)s-overrides
997cacheroot=/var/tmp/archive/%(name)s-cache
998miscroot=/var/tmp/archive/%(name)s-misc
999""" % dict(name=distribution.name)
1000
1001
1002def makeDistroSeriesLucilleconfig(distroseries):
1003 """Create a lucille config for the distroseries."""
1004 removeSecurityProxy(distroseries).lucilleconfig = """[publishing]
1005components = %(components)s
1006""" % dict(components=[c.name for c in distroseries.components])
1007
1008
1009class PublishingTestCase(TestCaseWithFactory):
1010 """A test case that has access to a `SoyuzTestPublisher`.
1011
1012 In addition:
1013
1014 * the default distribution and distroseries of
1015 the publisher will have lucille configurations, so that they
1016 can be used with the publisher.
1017 * the publisher configuration will have been asked to create
1018 the directories necessary for publishing the default
1019 distribution.
1020
1021 :ivar publisher: a `SoyuzTestPublisher` instance, prepared for
1022 binary uploads.
1023 :type publisher: `SoyuzTestPublisher`
1024 :ivar config: the publisher configuration for the default
1025 distribution of `publisher`.
1026 :type config: `lp.archivepublisher.config.Config`
1027 :ivar logger: a logger that the publisher will use.
1028 :type logger: `canonical.launchpad.scripts.QuietFakeLogger`
1029 :ivar disk_pool: a `DiskPool` for the default distribution
1030 of `publisher`.
1031 :type disk_pool: `lp.archivepublisher.diskpool.DiskPool`
1032 """
1033
1034 layer = LaunchpadZopelessLayer
1035 dbuser = config.archivepublisher.dbuser
1036
1037 def setUp(self):
1038 super(PublishingTestCase, self).setUp()
1039 self.layer.switchDbUser(self.dbuser)
1040 self.publisher = SoyuzTestPublisher(factory=self.factory)
1041 self.publisher.prepareForBinaryPublications()
1042 makeDistributionLucilleconfig(self.publisher.distribution)
1043 makeDistroSeriesLucilleconfig(self.publisher.distroseries)
1044 self.config = Config(self.publisher.distribution)
1045 self.addCleanup(self.config.removeArchiveDirs)
1046 self.config.setupArchiveDirs()
1047 self.logger = QuietFakeLogger()
1048 self.disk_pool = DiskPool(
1049 self.config.poolroot, self.config.temproot, self.logger)
01050
=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py 2010-08-10 01:42:55 +0000
+++ lib/lp/soyuz/tests/test_publishing.py 2010-08-10 01:42:59 +0000
@@ -22,7 +22,6 @@
22from lp.app.errors import NotFoundError22from lp.app.errors import NotFoundError
23from lp.archivepublisher.config import Config23from lp.archivepublisher.config import Config
24from lp.archivepublisher.diskpool import DiskPool24from lp.archivepublisher.diskpool import DiskPool
25from lp.buildmaster.interfaces.buildbase import BuildStatus
26from lp.registry.interfaces.distribution import IDistributionSet25from lp.registry.interfaces.distribution import IDistributionSet
27from lp.registry.interfaces.person import IPersonSet26from lp.registry.interfaces.person import IPersonSet
28from lp.registry.interfaces.pocket import PackagePublishingPocket27from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -37,20 +36,50 @@
37 IPublishingSet, PackagePublishingPriority, PackagePublishingStatus)36 IPublishingSet, PackagePublishingPriority, PackagePublishingStatus)
38from lp.soyuz.interfaces.queue import PackageUploadStatus37from lp.soyuz.interfaces.queue import PackageUploadStatus
39from lp.soyuz.testing.matchers import IsSupersededBy, PublishedStateIs38from lp.soyuz.testing.matchers import IsSupersededBy, PublishedStateIs
39from lp.soyuz.testing.publisher import (
40 SoyuzTestPublisher as _SoyuzTestPublisher)
40from canonical.launchpad.scripts import FakeLogger41from canonical.launchpad.scripts import FakeLogger
41from lp.testing import TestCaseWithFactory42from lp.testing import TestCaseWithFactory
42from lp.testing.matchers import DateIsInPast43from lp.testing.matchers import DateIsInPast
43from lp.testing.factory import LaunchpadObjectFactory
44from lp.testing.sampledata import UBUNTU_DEVELOPER_ADMIN_NAME44from lp.testing.sampledata import UBUNTU_DEVELOPER_ADMIN_NAME
45from lp.testing.fakemethod import FakeMethod45from lp.testing.fakemethod import FakeMethod
4646
4747
48class SoyuzTestPublisher:48class SoyuzTestPublisher(_SoyuzTestPublisher):
49 """Helper class able to publish coherent source and binaries in Soyuz."""49
5050 def regetBreezyAutotest(self):
51 def __init__(self):51 self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
52 self.factory = LaunchpadObjectFactory()52 self.breezy_autotest = self.ubuntutest['breezy-autotest']
53 self.default_package_name = 'foo'53 self.person = getUtility(IPersonSet).getByName('name16')
54 self.breezy_autotest_i386 = self.breezy_autotest['i386']
55 self.breezy_autotest_hppa = self.breezy_autotest['hppa']
56
57 def prepareBreezyAutotest(self):
58 """Prepare ubuntutest/breezy-autotest for publications.
59
60 It's also called during the normal test-case setUp.
61 """
62 self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
63 self.breezy_autotest = self.ubuntutest['breezy-autotest']
64 self.setUpDefaultDistroSeries(self.breezy_autotest)
65 # Only create the DistroArchSeries needed if they do not exist yet.
66 # This makes it easier to experiment at the python command line
67 # (using "make harness").
68 try:
69 self.breezy_autotest_i386 = self.breezy_autotest['i386']
70 except NotFoundError:
71 self.breezy_autotest_i386 = self.breezy_autotest.newArch(
72 'i386', ProcessorFamily.get(1), False, self.person,
73 supports_virtualized=True)
74 try:
75 self.breezy_autotest_hppa = self.breezy_autotest['hppa']
76 except NotFoundError:
77 self.breezy_autotest_hppa = self.breezy_autotest.newArch(
78 'hppa', ProcessorFamily.get(4), False, self.person)
79 self.breezy_autotest.nominatedarchindep = self.breezy_autotest_i386
80 fake_chroot = self.addMockFile('fake_chroot.tar.gz')
81 self.breezy_autotest_i386.addOrUpdateChroot(fake_chroot)
82 self.breezy_autotest_hppa.addOrUpdateChroot(fake_chroot)
5483
55 def setUpDefaultDistroSeries(self, distroseries=None):84 def setUpDefaultDistroSeries(self, distroseries=None):
56 """Set up a distroseries that will be used by default.85 """Set up a distroseries that will be used by default.
@@ -67,8 +96,8 @@
67 :return: The `IDistroSeries` that got set as default.96 :return: The `IDistroSeries` that got set as default.
68 """97 """
69 if distroseries is None:98 if distroseries is None:
70 distroseries = self.factory.makeDistroRelease()99 distroseries = self.factory.makeDistroSeries()
71 self.distroseries = distroseries100 distroseries = self.setDefaultDistroSeries(distroseries=distroseries)
72 # Set up a person that has a GPG key.101 # Set up a person that has a GPG key.
73 self.person = getUtility(IPersonSet).getByName(102 self.person = getUtility(IPersonSet).getByName(
74 UBUNTU_DEVELOPER_ADMIN_NAME)103 UBUNTU_DEVELOPER_ADMIN_NAME)
@@ -78,58 +107,6 @@
78 name_set.getOrCreateByName(self.default_package_name)107 name_set.getOrCreateByName(self.default_package_name)
79 return self.distroseries108 return self.distroseries
80109
81 def prepareBreezyAutotest(self):
82 """Prepare ubuntutest/breezy-autotest for publications.
83
84 It's also called during the normal test-case setUp.
85 """
86 self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
87 self.breezy_autotest = self.ubuntutest['breezy-autotest']
88 self.setUpDefaultDistroSeries(self.breezy_autotest)
89 # Only create the DistroArchSeries needed if they do not exist yet.
90 # This makes it easier to experiment at the python command line
91 # (using "make harness").
92 try:
93 self.breezy_autotest_i386 = self.breezy_autotest['i386']
94 except NotFoundError:
95 self.breezy_autotest_i386 = self.breezy_autotest.newArch(
96 'i386', ProcessorFamily.get(1), False, self.person,
97 supports_virtualized=True)
98 try:
99 self.breezy_autotest_hppa = self.breezy_autotest['hppa']
100 except NotFoundError:
101 self.breezy_autotest_hppa = self.breezy_autotest.newArch(
102 'hppa', ProcessorFamily.get(4), False, self.person)
103 self.breezy_autotest.nominatedarchindep = self.breezy_autotest_i386
104 fake_chroot = self.addMockFile('fake_chroot.tar.gz')
105 self.breezy_autotest_i386.addOrUpdateChroot(fake_chroot)
106 self.breezy_autotest_hppa.addOrUpdateChroot(fake_chroot)
107
108 def addFakeChroots(self, distroseries=None):
109 """Add fake chroots for all the architectures in distroseries."""
110 if distroseries is None:
111 distroseries = self.distroseries
112 fake_chroot = self.addMockFile('fake_chroot.tar.gz')
113 for arch in distroseries.architectures:
114 arch.addOrUpdateChroot(fake_chroot)
115
116 def regetBreezyAutotest(self):
117 self.ubuntutest = getUtility(IDistributionSet)['ubuntutest']
118 self.breezy_autotest = self.ubuntutest['breezy-autotest']
119 self.person = getUtility(IPersonSet).getByName('name16')
120 self.breezy_autotest_i386 = self.breezy_autotest['i386']
121 self.breezy_autotest_hppa = self.breezy_autotest['hppa']
122
123 def addMockFile(self, filename, filecontent='nothing', restricted=False,
124 expires=None):
125 """Add a mock file in Librarian.
126
127 Returns a ILibraryFileAlias corresponding to the file uploaded.
128 """
129 return self.factory.makeLibraryFileAlias(
130 filename=filename, content=filecontent, restricted=restricted,
131 content_type='application/text', expires=expires)
132
133 def addPackageUpload(self, archive, distroseries,110 def addPackageUpload(self, archive, distroseries,
134 pocket=PackagePublishingPocket.RELEASE,111 pocket=PackagePublishingPocket.RELEASE,
135 changes_file_name="foo_666_source.changes",112 changes_file_name="foo_666_source.changes",
@@ -137,12 +114,11 @@
137 upload_status=PackageUploadStatus.DONE):114 upload_status=PackageUploadStatus.DONE):
138 person = self.factory.makePerson()115 person = self.factory.makePerson()
139 signing_key = self.factory.makeGPGKey(person)116 signing_key = self.factory.makeGPGKey(person)
140 package_upload = self.factory.makePackageUpload(117 return self.makePackageUpload(
141 archive=archive, distroseries=distroseries, pocket=pocket,118 archive=archive, distroseries=distroseries,
142 changes_filename=changes_file_name,119 pocket=pocket, changes_file_name=changes_file_name,
143 changes_file_content=changes_file_content,120 changes_file_content=changes_file_content,
144 signing_key=signing_key, status=upload_status)121 signing_key=signing_key, status=upload_status)
145 return package_upload
146122
147 def getPubSource(self, sourcename=None, version='666', component='main',123 def getPubSource(self, sourcename=None, version='666', component='main',
148 filename=None, section='base',124 filename=None, section='base',
@@ -161,23 +137,16 @@
161 maintainer=None, creator=None, date_uploaded=UTC_NOW,137 maintainer=None, creator=None, date_uploaded=UTC_NOW,
162 spr_only=False, files_expire=None,138 spr_only=False, files_expire=None,
163 changelog_entry=None):139 changelog_entry=None):
164 """Return a mock source publishing record.
165
166 if spr_only is specified, the source is not published and the
167 sourcepackagerelease object is returned instead.
168 """
169 if sourcename is None:140 if sourcename is None:
170 sourcename = self.default_package_name141 sourcename = self.default_package_name
171 spn = self.factory.getOrMakeSourcePackageName(name=sourcename)142 spn = self.factory.getOrMakeSourcePackageName(name=sourcename)
172 component = self.factory.makeComponent(name=component)143 component = self.factory.makeComponent(name=component)
173
174 if distroseries is None:
175 distroseries = self.distroseries
176 if archive is None:
177 archive = distroseries.main_archive
178 if creator is None:144 if creator is None:
179 creator = self.factory.makePerson()145 creator = self.factory.makePerson()
180 self.factory.makeGPGKey(creator)146 if not creator.gpg_keys:
147 dscsigningkey = self.factory.makeGPGKey(creator)
148 else:
149 dscsigningkey = creator.gpg_keys[0]
181150
182 changes_file_name = "%s_%s_source.changes" % (sourcename, version)151 changes_file_name = "%s_%s_source.changes" % (sourcename, version)
183 if spr_only:152 if spr_only:
@@ -191,7 +160,7 @@
191 upload_status=upload_status)160 upload_status=upload_status)
192161
193 spr = self.factory.makeSourcePackageRelease(162 spr = self.factory.makeSourcePackageRelease(
194 distroseries=distroseries,163 distroseries=package_upload.distroseries,
195 sourcepackagename=spn,164 sourcepackagename=spn,
196 maintainer=maintainer,165 maintainer=maintainer,
197 creator=creator,166 creator=creator,
@@ -204,12 +173,12 @@
204 build_conflicts=build_conflicts,173 build_conflicts=build_conflicts,
205 build_conflicts_indep=build_conflicts_indep,174 build_conflicts_indep=build_conflicts_indep,
206 architecturehintlist=architecturehintlist,175 architecturehintlist=architecturehintlist,
207 dscsigningkey=creator.gpg_keys[0],176 dscsigningkey=dscsigningkey,
208 dsc_maintainer_rfc822=dsc_maintainer_rfc822,177 dsc_maintainer_rfc822=dsc_maintainer_rfc822,
209 dsc_standards_version=dsc_standards_version,178 dsc_standards_version=dsc_standards_version,
210 dsc_format=dsc_format,179 dsc_format=dsc_format,
211 dsc_binaries=dsc_binaries,180 dsc_binaries=dsc_binaries,
212 archive=archive,181 archive=package_upload.archive,
213 date_uploaded=date_uploaded,182 date_uploaded=date_uploaded,
214 changelog_entry=changelog_entry,183 changelog_entry=changelog_entry,
215 )184 )
@@ -217,8 +186,8 @@
217186
218 if filename is None:187 if filename is None:
219 filename = "%s_%s.dsc" % (sourcename, version)188 filename = "%s_%s.dsc" % (sourcename, version)
220 alias = self.addMockFile(189 alias = self.addFile(
221 filename, filecontent, restricted=archive.private,190 filename, filecontent, restricted=package_upload.archive.private,
222 expires=files_expire)191 expires=files_expire)
223 spr.addFile(alias)192 spr.addFile(alias)
224193
@@ -226,7 +195,7 @@
226 return spr195 return spr
227196
228 spph = self.factory.makeSourcePackagePublishingHistory(197 spph = self.factory.makeSourcePackagePublishingHistory(
229 distroseries=distroseries,198 distroseries=package_upload.distroseries,
230 sourcepackagerelease=spr,199 sourcepackagerelease=spr,
231 component=spr.component,200 component=spr.component,
232 section_name=spr.section.name,201 section_name=spr.section.name,
@@ -234,8 +203,8 @@
234 date_uploaded=date_uploaded,203 date_uploaded=date_uploaded,
235 dateremoved=dateremoved,204 dateremoved=dateremoved,
236 scheduleddeletiondate=scheduleddeletiondate,205 scheduleddeletiondate=scheduleddeletiondate,
237 pocket=pocket,206 pocket=package_upload.pocket,
238 archive=archive,207 archive=package_upload.archive,
239 )208 )
240 return spph209 return spph
241210
@@ -290,11 +259,11 @@
290 build, binaryname, filecontent, summary, description,259 build, binaryname, filecontent, summary, description,
291 shlibdep, depends, recommends, suggests, conflicts, replaces,260 shlibdep, depends, recommends, suggests, conflicts, replaces,
292 provides, pre_depends, enhances, breaks, format,261 provides, pre_depends, enhances, breaks, format,
293 installed_size=installed_size, component=component,262 installed_size=installed_size, files_expire=files_expire)
294 files_expire=files_expire)
295 pub_binaries = self.publishBinaryInArchive(263 pub_binaries = self.publishBinaryInArchive(
296 binarypackagerelease, archive, status, pocket,264 binarypackagerelease, archive, status, pocket,
297 scheduleddeletiondate, dateremoved, section, priority)265 scheduleddeletiondate, dateremoved, section, priority,
266 component_name=component)
298 published_binaries.extend(pub_binaries)267 published_binaries.extend(pub_binaries)
299 package_upload = self.addPackageUpload(268 package_upload = self.addPackageUpload(
300 archive, distroseries, pocket,269 archive, distroseries, pocket,
@@ -307,147 +276,42 @@
307 return sorted(276 return sorted(
308 published_binaries, key=operator.attrgetter('id'), reverse=True)277 published_binaries, key=operator.attrgetter('id'), reverse=True)
309278
310 def uploadBinaryForBuild(279 def uploadBinaryForBuild(self, build, binaryname, filecontent="anything",
311 self, build, binaryname, filecontent="anything",280 summary="summary", description="description",
312 summary="summary", description="description", shlibdep=None,281 shlibdep=None, depends=None, recommends=None,
313 depends=None, recommends=None, suggests=None, conflicts=None,282 suggests=None, conflicts=None, replaces=None,
314 replaces=None, provides=None, pre_depends=None, enhances=None,283 provides=None, pre_depends=None, enhances=None,
315 breaks=None, format=BinaryPackageFormat.DEB, installed_size=None,284 breaks=None, format=BinaryPackageFormat.DEB,
316 component=None, version=None, files_expire=None):285 installed_size=None, version=None,
286 files_expire=None, priority=None):
317 """Return the corresponding `BinaryPackageRelease`."""287 """Return the corresponding `BinaryPackageRelease`."""
318 sourcepackagerelease = build.source_package_release288 return super(SoyuzTestPublisher, self).uploadBinaryForBuild(
319 distroarchseries = build.distro_arch_series289 build, binaryname, filecontent=filecontent, summary=summary,
320 architecturespecific = (290 description=description, shlibdep=shlibdep, depends=depends,
321 not sourcepackagerelease.architecturehintlist == 'all')291 recommends=recommends, suggests=suggests, conflicts=conflicts,
322 if component is not None:292 replaces=replaces, provides=provides, pre_depends=pre_depends,
323 component = self.factory.makeComponent(name=component)293 enhances=enhances, breaks=breaks, format=format,
324294 installed_size=installed_size, version=version,
325 binarypackagename = self.factory.getOrMakeBinaryPackageName(295 files_expire=files_expire, priority=priority)
326 name=binaryname)296
327297 def publishBinaryInArchive(self, binarypackagerelease, archive,
328 binarypackagerelease = self.factory.makeBinaryPackageRelease(298 status=PackagePublishingStatus.PENDING,
329 build=build,299 pocket=PackagePublishingPocket.RELEASE,
330 binarypackagename=binarypackagename,300 scheduleddeletiondate=None, dateremoved=None,
331 summary=summary,301 section=None, priority=None,
332 description=description,302 component_name=None):
333 shlibdeps=shlibdep,
334 depends=depends,
335 recommends=recommends,
336 suggests=suggests,
337 conflicts=conflicts,
338 replaces=replaces,
339 provides=provides,
340 pre_depends=pre_depends,
341 enhances=enhances,
342 breaks=breaks,
343 essential=False,
344 architecturespecific=architecturespecific,
345 binpackageformat=format,
346 priority=PackagePublishingPriority.STANDARD,
347 installed_size=installed_size,
348 component=component,
349 version=version,
350 )
351
352 # Create the corresponding binary file.
353 if architecturespecific:
354 filearchtag = distroarchseries.architecturetag
355 else:
356 filearchtag = 'all'
357 filename = '%s_%s_%s.%s' % (binaryname, sourcepackagerelease.version,
358 filearchtag, format.name.lower())
359 alias = self.addMockFile(
360 filename, filecontent=filecontent,
361 restricted=build.archive.private, expires=files_expire)
362 binarypackagerelease.addFile(alias)
363
364 # Adjust the build record in way it looks complete.
365 naked_build = removeSecurityProxy(build)
366 naked_build.status = BuildStatus.FULLYBUILT
367 naked_build.date_finished = datetime.datetime(
368 2008, 1, 1, 0, 5, 0, tzinfo=pytz.UTC)
369 naked_build.date_started = (
370 build.date_finished - datetime.timedelta(minutes=5))
371 buildlog_filename = 'buildlog_%s-%s-%s.%s_%s_%s.txt.gz' % (
372 build.distribution.name,
373 build.distro_series.name,
374 build.distro_arch_series.architecturetag,
375 build.source_package_release.name,
376 build.source_package_release.version,
377 build.status.name)
378 naked_build.log = self.addMockFile(
379 buildlog_filename, filecontent='Built!',
380 restricted=build.archive.private)
381
382 return binarypackagerelease
383
384 def publishBinaryInArchive(
385 self, binarypackagerelease, archive,
386 status=PackagePublishingStatus.PENDING,
387 pocket=PackagePublishingPocket.RELEASE,
388 scheduleddeletiondate=None, dateremoved=None, section=None,
389 priority=None):
390 """Return the corresponding BinaryPackagePublishingHistory."""303 """Return the corresponding BinaryPackagePublishingHistory."""
391 distroarchseries = binarypackagerelease.build.distro_arch_series304 return super(SoyuzTestPublisher, self).publishBinaryInArchive(
392305 binarypackagerelease, archive, status=status, pocket=pocket,
393 # Publish the binary.306 scheduleddeletiondate=scheduleddeletiondate,
394 if binarypackagerelease.architecturespecific:307 dateremoved=dateremoved)
395 archs = [distroarchseries]308
396 else:309 def createSource(self, archive, sourcename, version, distroseries=None,
397 archs = distroarchseries.distroseries.architectures310 new_version=None, component='main'):
398
399 pub_binaries = []
400 for arch in archs:
401 pub = self.factory.makeBinaryPackagePublishingHistory(
402 distroarchseries=arch,
403 binarypackagerelease=binarypackagerelease,
404 status=status,
405 scheduleddeletiondate=scheduleddeletiondate,
406 dateremoved=dateremoved,
407 pocket=pocket,
408 archive=archive,
409 section_name=section,
410 priority=priority,
411 )
412 pub_binaries.append(pub)
413
414 return pub_binaries
415
416 def _findChangesFile(self, top, name_fragment):
417 """File with given name fragment in directory tree starting at top."""
418 for root, dirs, files in os.walk(top, topdown=False):
419 for name in files:
420 if (name.endswith('.changes') and
421 name.find(name_fragment) > -1):
422 return os.path.join(root, name)
423 return None
424
425 def createSource(
426 self, archive, sourcename, version, distroseries=None,
427 new_version=None, component='main'):
428 """Create source with meaningful '.changes' file."""311 """Create source with meaningful '.changes' file."""
429 top = 'lib/lp/archiveuploader/tests/data/suite'312 return super(SoyuzTestPublisher, self).createSource(
430 name_fragment = '%s_%s' % (sourcename, version)313 sourcename, version, archive=archive, distroseries=distroseries,
431 changesfile_path = self._findChangesFile(top, name_fragment)314 new_version=new_version, component_name=component)
432
433 source = None
434
435 if changesfile_path is not None:
436 if new_version is None:
437 new_version = version
438 changesfile_content = ''
439 handle = open(changesfile_path, 'r')
440 try:
441 changesfile_content = handle.read()
442 finally:
443 handle.close()
444
445 source = self.getPubSource(
446 sourcename=sourcename, archive=archive, version=new_version,
447 changes_file_content=changesfile_content,
448 distroseries=distroseries, component=component)
449
450 return source
451315
452316
453class TestNativePublishingBase(TestCaseWithFactory, SoyuzTestPublisher):317class TestNativePublishingBase(TestCaseWithFactory, SoyuzTestPublisher):