launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #21427
[Merge] lp:~cjwatson/launchpad/store-buildinfo into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/store-buildinfo into lp:launchpad.
Commit message:
Store uploaded .buildinfo files.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1657704 in Launchpad itself: "please start storing buildinfo files, for new dpkg versions"
https://bugs.launchpad.net/launchpad/+bug/1657704
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/store-buildinfo/+merge/321263
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/store-buildinfo into lp:launchpad.
=== added file 'lib/lp/archiveuploader/buildinfofile.py'
--- lib/lp/archiveuploader/buildinfofile.py 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/buildinfofile.py 2017-03-29 09:33:19 +0000
@@ -0,0 +1,89 @@
+# Copyright 2017 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Build information files."""
+
+__metaclass__ = type
+
+__all__ = [
+ 'BuildInfoFile',
+ ]
+
+from lp.app.errors import NotFoundError
+from lp.archiveuploader.dscfile import SignableTagFile
+from lp.archiveuploader.nascentuploadfile import PackageUploadFile
+from lp.archiveuploader.utils import (
+ re_isbuildinfo,
+ re_no_epoch,
+ UploadError,
+ )
+
+
+class BuildInfoFile(PackageUploadFile, SignableTagFile):
+ """Represents an uploaded build information file."""
+
+ def __init__(self, filepath, checksums, size, component_and_section,
+ priority_name, package, version, changes, policy, logger):
+ super(BuildInfoFile, self).__init__(
+ filepath, checksums, size, component_and_section, priority_name,
+ package, version, changes, policy, logger)
+ self.parse(verify_signature=not policy.unsigned_buildinfo_ok)
+ arch_match = re_isbuildinfo.match(self.filename)
+ self.architecture = arch_match.group(3)
+
+ @property
+ def is_sourceful(self):
+ # XXX cjwatson 2017-03-29: We should get this from the parsed
+ # Architecture field instead.
+ return self.architecture == "source"
+
+ @property
+ def is_binaryful(self):
+ # XXX cjwatson 2017-03-29: We should get this from the parsed
+ # Architecture field instead.
+ return self.architecture != "source"
+
+ @property
+ def is_archindep(self):
+ # XXX cjwatson 2017-03-29: We should get this from the parsed
+ # Architecture field instead.
+ return self.architecture == "all"
+
+ def verify(self):
+ """Verify the uploaded buildinfo file.
+
+ It returns an iterator over all the encountered errors and warnings.
+ """
+ self.logger.debug("Verifying buildinfo file %s" % self.filename)
+
+ version_chopped = re_no_epoch.sub('', self.version)
+ buildinfo_match = re_isbuildinfo.match(self.filename)
+ filename_version = buildinfo_match.group(2)
+ if filename_version != version_chopped:
+ yield UploadError("%s: should be %s according to changes file."
+ % (filename_version, version_chopped))
+
+ def checkBuild(self, build):
+ """See `PackageUploadFile`."""
+ try:
+ das = self.policy.distroseries[self.architecture]
+ except NotFoundError:
+ raise UploadError(
+ "Upload to unknown architecture %s for distroseries %s" %
+ (self.architecture, self.policy.distroseries))
+
+ # Sanity check; raise an error if the build we've been
+ # told to link to makes no sense.
+ if (build.pocket != self.policy.pocket or
+ build.distro_arch_series != das or
+ build.archive != self.policy.archive):
+ raise UploadError(
+ "Attempt to upload buildinfo specifying build %s, where it "
+ "doesn't fit." % build.id)
+
+ def storeInDatabase(self):
+ """Create and return the corresponding `LibraryFileAlias` reference."""
+ with open(self.filepath, "rb") as f:
+ return self.librarian.create(
+ self.filename, self.size, f, self.content_type,
+ restricted=self.policy.archive.private)
=== modified file 'lib/lp/archiveuploader/changesfile.py'
--- lib/lp/archiveuploader/changesfile.py 2015-07-29 01:59:43 +0000
+++ lib/lp/archiveuploader/changesfile.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
""" ChangesFile class
@@ -17,6 +17,7 @@
import os
+from lp.archiveuploader.buildinfofile import BuildInfoFile
from lp.archiveuploader.dscfile import (
DSCFile,
SignableTagFile,
@@ -36,6 +37,7 @@
parse_and_merge_file_lists,
re_changes_file_name,
re_isadeb,
+ re_isbuildinfo,
re_issource,
rfc822_encode_address,
UploadError,
@@ -75,6 +77,7 @@
}
dsc = None
+ buildinfo = None
maintainer = None
changed_by = None
filename_archtag = None
@@ -209,6 +212,8 @@
if cls == DSCFile:
self.dsc = file_instance
+ elif cls == BuildInfoFile:
+ self.buildinfo = file_instance
except UploadError as error:
yield error
else:
@@ -366,6 +371,7 @@
"""Determine the name and PackageUploadFile subclass for the filename."""
source_match = re_issource.match(filename)
binary_match = re_isadeb.match(filename)
+ buildinfo_match = re_isbuildinfo.match(filename)
if source_match:
package = source_match.group(1)
if (determine_source_file_type(filename) ==
@@ -380,6 +386,9 @@
BinaryPackageFileType.DDEB: DdebBinaryUploadFile,
BinaryPackageFileType.UDEB: UdebBinaryUploadFile,
}[determine_binary_file_type(filename)]
+ elif buildinfo_match:
+ package = buildinfo_match.group(1)
+ cls = BuildInfoFile
else:
raise CannotDetermineFileTypeError(
"Could not determine the type of %r" % filename)
=== modified file 'lib/lp/archiveuploader/dscfile.py'
--- lib/lp/archiveuploader/dscfile.py 2016-06-01 01:59:32 +0000
+++ lib/lp/archiveuploader/dscfile.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
""" DSCFile and related.
@@ -671,6 +671,11 @@
user_defined_fields = self.extractUserDefinedFields([
(field, encoded[field]) for field in self._dict.iterkeys()])
+ if self.changes.buildinfo is not None:
+ buildinfo_lfa = self.changes.buildinfo.storeInDatabase()
+ else:
+ buildinfo_lfa = None
+
release = self.policy.distroseries.createUploadedSourcePackageRelease(
sourcepackagename=source_name,
version=self.dsc_version,
@@ -698,6 +703,7 @@
copyright=encoded.get('copyright'),
# dateuploaded by default is UTC:now in the database
user_defined_fields=user_defined_fields,
+ buildinfo=buildinfo_lfa,
)
# SourcePackageFiles should contain also the DSC
=== modified file 'lib/lp/archiveuploader/nascentupload.py'
--- lib/lp/archiveuploader/nascentupload.py 2015-12-30 23:34:34 +0000
+++ lib/lp/archiveuploader/nascentupload.py 2017-03-29 09:33:19 +0000
@@ -24,6 +24,7 @@
from zope.component import getUtility
from lp.app.errors import NotFoundError
+from lp.archiveuploader.buildinfofile import BuildInfoFile
from lp.archiveuploader.changesfile import ChangesFile
from lp.archiveuploader.dscfile import DSCFile
from lp.archiveuploader.nascentuploadfile import (
@@ -267,6 +268,15 @@
files_archdep or not uploaded_file.is_archindep)
elif isinstance(uploaded_file, SourceUploadFile):
files_sourceful = True
+ elif isinstance(uploaded_file, BuildInfoFile):
+ files_sourceful = (
+ files_sourceful or uploaded_file.is_sourceful)
+ if uploaded_file.is_binaryful:
+ files_binaryful = files_binaryful or True
+ files_archindep = (
+ files_archindep or uploaded_file.is_archindep)
+ files_archdep = (
+ files_archdep or not uploaded_file.is_archindep)
else:
# This is already caught in ChangesFile.__init__
raise AssertionError("Unknown uploaded file type.")
@@ -857,6 +867,10 @@
assert self.queue_root.pocket == bpf_build.pocket, (
"Binary was not build for the claimed pocket.")
binary_package_file.storeInDatabase(bpf_build)
+ if self.changes.buildinfo is not None:
+ self.changes.buildinfo.checkBuild(bpf_build)
+ bpf_build.addBuildInfo(
+ self.changes.buildinfo.storeInDatabase())
processed_builds.append(bpf_build)
# Store the related builds after verifying they were built
=== modified file 'lib/lp/archiveuploader/tests/__init__.py'
--- lib/lp/archiveuploader/tests/__init__.py 2014-08-13 07:49:59 +0000
+++ lib/lp/archiveuploader/tests/__init__.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for the archive uploader."""
@@ -81,8 +81,9 @@
def __init__(self):
AbstractUploadPolicy.__init__(self)
- # We require the changes to be signed but not the dsc
+ # We require the changes to be signed but not the dsc or buildinfo
self.unsigned_dsc_ok = True
+ self.unsigned_buildinfo_ok = True
def validateUploadType(self, upload):
"""We accept uploads of any type."""
=== added directory 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo'
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.buildinfo'
--- lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.buildinfo 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.buildinfo 2017-03-29 09:33:19 +0000
@@ -0,0 +1,20 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Format: 1.0
+Source: bar
+Binary: bar
+Architecture: i386
+Version: 1.0-1
+Checksums-Md5:
+ 39a6dde58f0b84139e9877892f6ac56a 644 devel optional bar_1.0-1_i386.deb
+Build-Origin: Ubuntu
+Build-Architecture: i386
+Build-Date: Wed, 29 Mar 2017 00:01:21 +0100
+
+-----BEGIN PGP SIGNATURE-----
+
+iF0EARECAB0WIQQ0DKO7Jw4nFsnuC3aOfrcIbGSoxQUCWNrrewAKCRCOfrcIbGSo
+xR+6AJ4nl/x722AMwRVIKkjiuS834aQ+cwCfZ6x6BxiLb2jKj7Vvt+0txNMDZ44=
+=RKsi
+-----END PGP SIGNATURE-----
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.changes'
--- lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.changes 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.changes 2017-03-29 09:33:19 +0000
@@ -0,0 +1,29 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Format: 1.7
+Date: Thu, 16 Feb 2006 15:34:09 +0000
+Source: bar
+Binary: bar
+Architecture: i386
+Version: 1.0-1
+Distribution: breezy
+Urgency: low
+Maintainer: Launchpad team <launchpad@xxxxxxxxxxxxxxxxxxx>
+Changed-By: Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
+Description:
+ bar - Stuff for testing
+Changes:
+ bar (1.0-1) breezy; urgency=low
+ .
+ * Initial version
+Files:
+ 39a6dde58f0b84139e9877892f6ac56a 644 devel optional bar_1.0-1_i386.deb
+ 219b626c05f0524aa4c958ee29e200d2 490 devel optional bar_1.0-1_i386.buildinfo
+
+-----BEGIN PGP SIGNATURE-----
+
+iF0EARECAB0WIQQ0DKO7Jw4nFsnuC3aOfrcIbGSoxQUCWNrrfAAKCRCOfrcIbGSo
+xTI3AJ9aO+JcL++Yed7SbxLY1q2oL4ePlQCeMV/dGsE7TRfwm0mGXOizrDK47H8=
+=akjD
+-----END PGP SIGNATURE-----
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.deb'
Binary files lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.deb 1970-01-01 00:00:00 +0000 and lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_binary_buildinfo/bar_1.0-1_i386.deb 2017-03-29 09:33:19 +0000 differ
=== added directory 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo'
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1.diff.gz'
Binary files lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1.diff.gz 1970-01-01 00:00:00 +0000 and lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1.diff.gz 2017-03-29 09:33:19 +0000 differ
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1.dsc'
--- lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1.dsc 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1.dsc 2017-03-29 09:33:19 +0000
@@ -0,0 +1,21 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Format: 1.0
+Source: bar
+Version: 1.0-1
+Binary: bar
+Maintainer: Launchpad team <launchpad@xxxxxxxxxxxxxxxxxxx>
+Architecture: any
+Standards-Version: 3.6.2
+Files:
+ fc1464e5985b962a042d5354452f361d 164 bar_1.0.orig.tar.gz
+ 1e35b810764f140af9616de8274e6e73 537 bar_1.0-1.diff.gz
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.3 (GNU/Linux)
+
+iD8DBQFFt7Cojn63CGxkqMURAo6FAJ9ZUagUNtYpmZrqFwL6LXDKOUSOPwCdFqPa
+BdrMeT+0Hg+yMS69uO+qJRI=
+=mjFU
+-----END PGP SIGNATURE-----
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1_source.buildinfo'
--- lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1_source.buildinfo 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1_source.buildinfo 2017-03-29 09:33:19 +0000
@@ -0,0 +1,20 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Format: 1.0
+Source: bar
+Binary: bar
+Architecture: source
+Version: 1.0-1
+Checksums-Md5:
+ 5d533778b698edc1a122098a98c8490e 512 devel optional bar_1.0-1.dsc
+Build-Origin: Ubuntu
+Build-Architecture: amd64
+Build-Date: Tue, 28 Mar 2017 23:51:59 +0100
+
+-----BEGIN PGP SIGNATURE-----
+
+iF0EARECAB0WIQQ0DKO7Jw4nFsnuC3aOfrcIbGSoxQUCWNrrcQAKCRCOfrcIbGSo
+xZc8AKCTbuZAnDyUdoBEsKy3QFxo+2BAEgCgiTklyo2HZuTBJyag1ayw/65bfoM=
+=mB68
+-----END PGP SIGNATURE-----
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1_source.changes'
--- lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1_source.changes 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0-1_source.changes 2017-03-29 09:33:19 +0000
@@ -0,0 +1,31 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Format: 1.7
+Date: Thu, 16 Feb 2006 15:34:09 +0000
+Source: bar
+Binary: bar
+Architecture: source
+Version: 1.0-1
+Distribution: breezy
+Urgency: low
+Maintainer: Launchpad team <launchpad@xxxxxxxxxxxxxxxxxxx>
+Changed-By: Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
+Description:
+ bar - Stuff for testing
+Changes:
+ bar (1.0-1) breezy; urgency=low
+ .
+ * Initial version
+Files:
+ 5d533778b698edc1a122098a98c8490e 512 devel optional bar_1.0-1.dsc
+ fc1464e5985b962a042d5354452f361d 164 devel optional bar_1.0.orig.tar.gz
+ 1e35b810764f140af9616de8274e6e73 537 devel optional bar_1.0-1.diff.gz
+ c45de110a35a944cd8d6bf990852d4a9 488 devel optional bar_1.0-1_source.buildinfo
+
+-----BEGIN PGP SIGNATURE-----
+
+iF0EARECAB0WIQQ0DKO7Jw4nFsnuC3aOfrcIbGSoxQUCWNrrcQAKCRCOfrcIbGSo
+xULLAKCMydlA1Ct6xd8f4ckvaM0YGWHRLACeKVyQO0SaCoLtJxd5SOJVe7VACNA=
+=A0cM
+-----END PGP SIGNATURE-----
=== added file 'lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0.orig.tar.gz'
Binary files lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0.orig.tar.gz 1970-01-01 00:00:00 +0000 and lib/lp/archiveuploader/tests/data/suite/bar_1.0-1_buildinfo/bar_1.0.orig.tar.gz 2017-03-29 09:33:19 +0000 differ
=== added file 'lib/lp/archiveuploader/tests/test_buildinfofile.py'
--- lib/lp/archiveuploader/tests/test_buildinfofile.py 1970-01-01 00:00:00 +0000
+++ lib/lp/archiveuploader/tests/test_buildinfofile.py 2017-03-29 09:33:19 +0000
@@ -0,0 +1,92 @@
+# Copyright 2017 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Build information file tests."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+
+from debian.deb822 import Changes
+
+from lp.archiveuploader.buildinfofile import BuildInfoFile
+from lp.archiveuploader.nascentuploadfile import UploadError
+from lp.archiveuploader.tests.test_nascentuploadfile import (
+ PackageUploadFileTestCase,
+ )
+from lp.testing.layers import LaunchpadZopelessLayer
+
+
+class TestBuildInfoFile(PackageUploadFileTestCase):
+
+ layer = LaunchpadZopelessLayer
+
+ def getBaseBuildInfo(self):
+ # XXX cjwatson 2017-03-20: This will need to be fleshed out if we
+ # ever start doing non-trivial buildinfo parsing.
+ # A Changes object is close enough.
+ buildinfo = Changes()
+ buildinfo["Format"] = "0.1"
+ return buildinfo
+
+ def makeBuildInfoFile(self, filename, buildinfo, component_and_section,
+ priority_name, package, version, changes):
+ path, md5, sha1, size = self.writeUploadFile(
+ filename, buildinfo.dump())
+ return BuildInfoFile(
+ path, {"MD5": md5}, size, component_and_section, priority_name,
+ package, version, changes, self.policy, self.logger)
+
+ def test_properties(self):
+ buildinfo = self.getBaseBuildInfo()
+ changes = self.getBaseChanges()
+ for (arch, is_sourceful, is_binaryful, is_archindep) in (
+ ("source", True, False, False),
+ ("all", False, True, True),
+ ("i386", False, True, False),
+ ):
+ buildinfofile = self.makeBuildInfoFile(
+ "foo_0.1-1_%s.buildinfo" % arch, buildinfo,
+ "main/net", "extra", "dulwich", "0.42",
+ self.createChangesFile("foo_0.1-1_%s.changes" % arch, changes))
+ self.assertEqual(arch, buildinfofile.architecture)
+ self.assertEqual(is_sourceful, buildinfofile.is_sourceful)
+ self.assertEqual(is_binaryful, buildinfofile.is_binaryful)
+ self.assertEqual(is_archindep, buildinfofile.is_archindep)
+
+ def test_storeInDatabase(self):
+ buildinfo = self.getBaseBuildInfo()
+ changes = self.getBaseChanges()
+ buildinfofile = self.makeBuildInfoFile(
+ "foo_0.1-1_source.buildinfo", buildinfo,
+ "main/net", "extra", "dulwich", "0.42",
+ self.createChangesFile("foo_0.1-1_source.changes", changes))
+ lfa = buildinfofile.storeInDatabase()
+ self.layer.txn.commit()
+ self.assertEqual(buildinfo.dump(), lfa.read())
+
+ def test_checkBuild(self):
+ das = self.factory.makeDistroArchSeries(
+ distroseries=self.policy.distroseries, architecturetag="i386")
+ build = self.factory.makeBinaryPackageBuild(
+ distroarchseries=das, archive=self.policy.archive)
+ buildinfo = self.getBaseBuildInfo()
+ changes = self.getBaseChanges()
+ buildinfofile = self.makeBuildInfoFile(
+ "foo_0.1-1_i386.buildinfo", buildinfo,
+ "main/net", "extra", "dulwich", "0.42",
+ self.createChangesFile("foo_0.1-1_i386.changes", changes))
+ buildinfofile.checkBuild(build)
+
+ def test_checkBuild_inconsistent(self):
+ das = self.factory.makeDistroArchSeries(
+ distroseries=self.policy.distroseries, architecturetag="amd64")
+ build = self.factory.makeBinaryPackageBuild(
+ distroarchseries=das, archive=self.policy.archive)
+ buildinfo = self.getBaseBuildInfo()
+ changes = self.getBaseChanges()
+ buildinfofile = self.makeBuildInfoFile(
+ "foo_0.1-1_i386.buildinfo", buildinfo,
+ "main/net", "extra", "dulwich", "0.42",
+ self.createChangesFile("foo_0.1-1_i386.changes", changes))
+ self.assertRaises(UploadError, buildinfofile.checkBuild, build)
=== modified file 'lib/lp/archiveuploader/tests/test_changesfile.py'
--- lib/lp/archiveuploader/tests/test_changesfile.py 2015-07-29 04:17:26 +0000
+++ lib/lp/archiveuploader/tests/test_changesfile.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Test ChangesFile functionality."""
@@ -15,6 +15,7 @@
)
from zope.component import getUtility
+from lp.archiveuploader.buildinfofile import BuildInfoFile
from lp.archiveuploader.changesfile import (
CannotDetermineFileTypeError,
ChangesFile,
@@ -71,6 +72,12 @@
('foo', UdebBinaryUploadFile),
determine_file_class_and_name('foo_1.0_all.udeb'))
+ def testBuildInfoFile(self):
+ # A buildinfo file is a BuildInfoFile.
+ self.assertEqual(
+ ('foo', BuildInfoFile),
+ determine_file_class_and_name('foo_1.0_all.buildinfo'))
+
def testUnmatchingFile(self):
# Files with unknown extensions or none at all are not
# identified.
=== modified file 'lib/lp/archiveuploader/tests/test_uploadpolicy.py'
--- lib/lp/archiveuploader/tests/test_uploadpolicy.py 2016-05-09 18:06:07 +0000
+++ lib/lp/archiveuploader/tests/test_uploadpolicy.py 2017-03-29 09:33:19 +0000
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
from zope.component import getUtility
@@ -174,6 +174,8 @@
self.assertTrue(buildd_policy.unsigned_changes_ok)
self.assertFalse(insecure_policy.unsigned_dsc_ok)
self.assertTrue(buildd_policy.unsigned_dsc_ok)
+ self.assertFalse(insecure_policy.unsigned_buildinfo_ok)
+ self.assertTrue(buildd_policy.unsigned_buildinfo_ok)
def test_setOptions_distro_name(self):
# Policies pick up the distribution name from options.
=== modified file 'lib/lp/archiveuploader/tests/test_uploadprocessor.py'
--- lib/lp/archiveuploader/tests/test_uploadprocessor.py 2017-01-10 15:18:48 +0000
+++ lib/lp/archiveuploader/tests/test_uploadprocessor.py 2017-03-29 09:33:19 +0000
@@ -119,6 +119,7 @@
self.name = "broken"
self.unsigned_changes_ok = True
self.unsigned_dsc_ok = True
+ self.unsigned_buildinfo_ok = True
def checkUpload(self, upload):
"""Raise an exception upload processing is not expecting."""
@@ -2017,6 +2018,47 @@
version=u"1.0-2", exact_match=True)
self.assertEqual(PackagePublishingPocket.PROPOSED, queue_item.pocket)
+ def test_source_buildinfo(self):
+ # A buildinfo file is attached to the SPR.
+ uploadprocessor = self.setupBreezyAndGetUploadProcessor()
+ upload_dir = self.queueUpload("bar_1.0-1_buildinfo")
+ with open(os.path.join(upload_dir, "bar_1.0-1_source.buildinfo")) as f:
+ buildinfo_contents = f.read()
+ self.processUpload(uploadprocessor, upload_dir)
+ source_pub = self.publishPackage("bar", "1.0-1")
+ self.assertEqual(
+ buildinfo_contents,
+ source_pub.sourcepackagerelease.buildinfo.read())
+
+ def test_binary_buildinfo(self):
+ # A buildinfo file is attached to the BPB.
+ uploadprocessor = self.setupBreezyAndGetUploadProcessor()
+ upload_dir = self.queueUpload("bar_1.0-1")
+ self.processUpload(uploadprocessor, upload_dir)
+ source_pub = self.publishPackage("bar", "1.0-1")
+ [build] = source_pub.createMissingBuilds()
+ self.switchToAdmin()
+ [queue_item] = self.breezy.getPackageUploads(
+ status=PackageUploadStatus.ACCEPTED,
+ version=u"1.0-1", name=u"bar")
+ queue_item.setDone()
+ build.buildqueue_record.markAsBuilding(self.factory.makeBuilder())
+ build.updateStatus(BuildStatus.UPLOADING)
+ self.switchToUploader()
+ shutil.rmtree(upload_dir)
+ self.layer.txn.commit()
+ behaviour = IBuildFarmJobBehaviour(build)
+ leaf_name = behaviour.getUploadDirLeaf(build.build_cookie)
+ upload_dir = self.queueUpload(
+ "bar_1.0-1_binary_buildinfo", queue_entry=leaf_name)
+ with open(os.path.join(upload_dir, "bar_1.0-1_i386.buildinfo")) as f:
+ buildinfo_contents = f.read()
+ self.options.context = "buildd"
+ self.options.builds = True
+ BuildUploadHandler(
+ uploadprocessor, self.incoming_folder, leaf_name).process()
+ self.assertEqual(buildinfo_contents, build.buildinfo.read())
+
class TestUploadHandler(TestUploadProcessorBase):
=== modified file 'lib/lp/archiveuploader/uploadpolicy.py'
--- lib/lp/archiveuploader/uploadpolicy.py 2016-01-26 15:47:37 +0000
+++ lib/lp/archiveuploader/uploadpolicy.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Policy management for the upload handler."""
@@ -87,6 +87,7 @@
self.archive = None
self.unsigned_changes_ok = False
self.unsigned_dsc_ok = False
+ self.unsigned_buildinfo_ok = False
self.create_people = True
# future_time_grace is in seconds
self.future_time_grace = 24 * HOURS
@@ -290,6 +291,7 @@
# We permit unsigned uploads because we trust our build daemons
self.unsigned_changes_ok = True
self.unsigned_dsc_ok = True
+ self.unsigned_buildinfo_ok = True
def setOptions(self, options):
"""Store the options for later."""
@@ -330,9 +332,10 @@
def __init__(self):
AbstractUploadPolicy.__init__(self)
- # We don't require changes or dsc to be signed for syncs
+ # We don't require changes/dsc/buildinfo to be signed for syncs
self.unsigned_changes_ok = True
self.unsigned_dsc_ok = True
+ self.unsigned_buildinfo_ok = True
def policySpecificChecks(self, upload):
"""Perform sync specific checks."""
=== modified file 'lib/lp/archiveuploader/utils.py'
--- lib/lp/archiveuploader/utils.py 2016-06-01 01:59:32 +0000
+++ lib/lp/archiveuploader/utils.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Archive uploader utilities."""
@@ -17,6 +17,7 @@
'prefix_multi_line_string',
're_taint_free',
're_isadeb',
+ 're_isbuildinfo',
're_issource',
're_is_component_orig_tar_ext',
're_is_component_orig_tar_ext_sig',
@@ -66,6 +67,7 @@
re_taint_free = re.compile(r"^[-+~/\.\w]+$")
re_isadeb = re.compile(r"(.+?)_(.+?)_(.+)\.(u?d?deb)$")
+re_isbuildinfo = re.compile(r"(.+?)_(.+?)_(.+)\.buildinfo$")
source_file_exts = [
'orig(?:-.+)?\.tar\.(?:gz|bz2|xz)(?:\.asc)?', 'diff.gz',
=== modified file 'lib/lp/registry/interfaces/distroseries.py'
--- lib/lp/registry/interfaces/distroseries.py 2016-11-14 19:55:07 +0000
+++ lib/lp/registry/interfaces/distroseries.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Interfaces including and related to IDistroSeries."""
@@ -686,7 +686,7 @@
dsc_binaries, archive, copyright, build_conflicts,
build_conflicts_indep, dateuploaded=None,
source_package_recipe_build=None, user_defined_fields=None,
- homepage=None):
+ homepage=None, buildinfo=None):
"""Create an uploads `SourcePackageRelease`.
Set this distroseries set to be the uploadeddistroseries.
@@ -726,6 +726,7 @@
user defined fields.
:param homepage: optional string with (unchecked) upstream homepage
URL
+ :param buildinfo: optional LFA with build information file
:return: the just creates `SourcePackageRelease`
"""
=== modified file 'lib/lp/registry/model/distroseries.py'
--- lib/lp/registry/model/distroseries.py 2016-04-04 12:54:43 +0000
+++ lib/lp/registry/model/distroseries.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Database classes for a distribution series."""
@@ -1187,7 +1187,7 @@
dsc_binaries, archive, copyright, build_conflicts,
build_conflicts_indep, dateuploaded=DEFAULT,
source_package_recipe_build=None, user_defined_fields=None,
- homepage=None):
+ homepage=None, buildinfo=None):
"""See `IDistroSeries`."""
return SourcePackageRelease(
upload_distroseries=self, sourcepackagename=sourcepackagename,
@@ -1206,7 +1206,8 @@
build_conflicts=build_conflicts,
build_conflicts_indep=build_conflicts_indep,
source_package_recipe_build=source_package_recipe_build,
- user_defined_fields=user_defined_fields, homepage=homepage)
+ user_defined_fields=user_defined_fields, homepage=homepage,
+ buildinfo=buildinfo)
def getComponentByName(self, name):
"""See `IDistroSeries`."""
=== modified file 'lib/lp/soyuz/enums.py'
--- lib/lp/soyuz/enums.py 2016-05-26 14:53:06 +0000
+++ lib/lp/soyuz/enums.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Enumerations used in the lp/soyuz modules."""
@@ -197,6 +197,13 @@
similar operating systems for distributing debug symbols.
""")
+ BUILDINFO = DBItem(5, """
+ Build information
+
+ A file used by Debian-based systems to record information about the
+ build environment.
+ """)
+
class BinaryPackageFormat(DBEnumeratedType):
"""Binary Package Format
=== modified file 'lib/lp/soyuz/interfaces/binarypackagebuild.py'
--- lib/lp/soyuz/interfaces/binarypackagebuild.py 2016-01-08 13:15:02 +0000
+++ lib/lp/soyuz/interfaces/binarypackagebuild.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""BinaryPackageBuild interfaces."""
@@ -145,6 +145,10 @@
description=_("The URL for the changes file for this build. "
"Will be None if the build was imported by Gina.")))
+ buildinfo = Attribute(
+ "The `LibraryFileAlias` object containing build information for "
+ "this build, if any.")
+
package_upload = Attribute(
"The `PackageUpload` record corresponding to the original upload "
"of the binaries resulted from this build. It's 'None' if it is "
@@ -157,6 +161,15 @@
),
exported_as="score")
+ def updateStatus(status, builder=None, slave_status=None,
+ date_started=None, date_finished=None,
+ force_invalid_transition=False, buildinfo=None):
+ """See `IBuildFarmJob.updateStatus`.
+
+ This version also accepts a `buildinfo` parameter which sets the
+ build's buildinfo file if it has not already been set.
+ """
+
def updateDependencies():
"""Update the build-dependencies line within the targeted context."""
@@ -265,6 +278,12 @@
If the build is not in a cancellable state, this method is a no-op.
"""
+ def addBuildInfo(buildinfo):
+ """Add a buildinfo file to this build.
+
+ :param buildinfo: An `ILibraryFileAlias`.
+ """
+
class IBinaryPackageBuildRestricted(Interface):
"""Restricted `IBinaryPackageBuild` attributes.
@@ -337,7 +356,8 @@
"""Interface for BinaryPackageBuildSet"""
def new(source_package_release, archive, distro_arch_series, pocket,
- arch_indep=False, status=BuildStatus.NEEDSBUILD, builder=None):
+ arch_indep=False, status=BuildStatus.NEEDSBUILD, builder=None,
+ buildinfo=None):
"""Create a new `IBinaryPackageBuild`.
:param source_package_release: An `ISourcePackageRelease`.
@@ -348,6 +368,7 @@
addition to architecture specific ones.
:param status: A `BuildStatus` item indicating the builds status.
:param builder: An optional `IBuilder`.
+ :param buildinfo: An optional `ILibraryFileAlias`.
"""
def getBySourceAndLocation(source_package_release, archive,
=== modified file 'lib/lp/soyuz/interfaces/sourcepackagerelease.py'
--- lib/lp/soyuz/interfaces/sourcepackagerelease.py 2016-07-29 07:37:33 +0000
+++ lib/lp/soyuz/interfaces/sourcepackagerelease.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Source package release interfaces."""
@@ -44,6 +44,9 @@
change_summary = Attribute(
"The message on the latest change in this release. This is usually "
"a snippet from the changelog")
+ buildinfo = Attribute(
+ "LibraryFileAlias containing build information for this source "
+ "upload, if any.")
builddepends = TextLine(
title=_("DSC build depends"),
description=_("A comma-separated list of packages on which this "
=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py 2016-01-08 13:15:02 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -81,11 +81,11 @@
LibraryFileAlias,
LibraryFileContent,
)
+from lp.soyuz.adapters.buildarch import determine_architectures_to_build
from lp.soyuz.enums import (
ArchivePurpose,
PackagePublishingStatus,
)
-from lp.soyuz.adapters.buildarch import determine_architectures_to_build
from lp.soyuz.interfaces.archive import (
InvalidExternalDependencies,
validate_external_dependencies,
@@ -229,6 +229,9 @@
name='external_dependencies',
validator=storm_validate_external_dependencies)
+ buildinfo_id = Int(name='buildinfo')
+ buildinfo = Reference(buildinfo_id, 'LibraryFileAlias.id')
+
def getLatestSourcePublication(self):
from lp.soyuz.model.publishing import SourcePackagePublishingHistory
store = Store.of(self)
@@ -703,6 +706,13 @@
estimate = 5
return datetime.timedelta(minutes=estimate)
+ def addBuildInfo(self, buildinfo):
+ """See `IBinaryPackageBuild`."""
+ if self.buildinfo is None:
+ self.buildinfo = buildinfo
+ else:
+ assert self.buildinfo == buildinfo
+
def verifySuccessfulUpload(self):
return bool(self.binarypackages)
@@ -783,7 +793,8 @@
class BinaryPackageBuildSet(SpecificBuildFarmJobSourceMixin):
def new(self, source_package_release, archive, distro_arch_series, pocket,
- arch_indep=None, status=BuildStatus.NEEDSBUILD, builder=None):
+ arch_indep=None, status=BuildStatus.NEEDSBUILD, builder=None,
+ buildinfo=None):
"""See `IBinaryPackageBuildSet`."""
# Force the current timestamp instead of the default UTC_NOW for
# the transaction, avoid several row with same datecreated.
@@ -806,7 +817,7 @@
distribution=distro_arch_series.distroseries.distribution,
distro_series=distro_arch_series.distroseries,
source_package_name=source_package_release.sourcepackagename,
- date_created=date_created)
+ buildinfo=buildinfo, date_created=date_created)
def getByID(self, id):
"""See `IBinaryPackageBuildSet`."""
=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
--- lib/lp/soyuz/model/sourcepackagerelease.py 2016-12-22 16:32:38 +0000
+++ lib/lp/soyuz/model/sourcepackagerelease.py 2017-03-29 09:33:19 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -100,6 +100,7 @@
version = StringCol(dbName='version', notNull=True)
changelog = ForeignKey(foreignKey='LibraryFileAlias', dbName='changelog')
changelog_entry = StringCol(dbName='changelog_entry')
+ buildinfo = ForeignKey(foreignKey='LibraryFileAlias', dbName='buildinfo')
builddepends = StringCol(dbName='builddepends')
builddependsindep = StringCol(dbName='builddependsindep')
build_conflicts = StringCol(dbName='build_conflicts')
Follow ups