← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~jelmer/launchpad/613468-xb-ppa into lp:launchpad

 

Jelmer Vernooij has proposed merging lp:~jelmer/launchpad/613468-xb-ppa into lp:launchpad with lp:~jelmer/launchpad/nascentuploadfile-tests as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers): code


This branch makes us write user-defined fields into Packages and Sources files. 

To do this we need to do two things:

- when parsing newly uploaded files the custom upload fields need to be stored in the 
database.
- when generating Sources and Packages files, write out the custom user fields

-- 
https://code.launchpad.net/~jelmer/launchpad/613468-xb-ppa/+merge/32908
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jelmer/launchpad/613468-xb-ppa into lp:launchpad.
=== modified file 'lib/lp/archiveuploader/dscfile.py'
--- lib/lp/archiveuploader/dscfile.py	2010-08-17 18:15:59 +0000
+++ lib/lp/archiveuploader/dscfile.py	2010-08-17 18:16:00 +0000
@@ -152,6 +152,16 @@
         "architecture",
         "files"])
 
+    known_fields = mandatory_fields.union(set([
+        "build-depends",
+        "build-depends-indep",
+        "build-conflicts",
+        "build-conflicts-indep",
+        "format",
+        "standards-version",
+        "filecontents",
+        ]))
+
     # Note that files is actually only set inside verify().
     files = None
     # Copyright and changelog_path are only set inside unpackAndCheckSource().
@@ -626,6 +636,9 @@
         source_name = getUtility(
             ISourcePackageNameSet).getOrCreateByName(self.source)
 
+        user_defined_fields = self.extractUserDefinedFields([
+            (field, encoded[field]) for field in self._dict])
+
         release = self.policy.distroseries.createUploadedSourcePackageRelease(
             sourcepackagename=source_name,
             version=self.dsc_version,
@@ -651,6 +664,7 @@
             source_package_recipe_build=build,
             copyright=encoded.get('copyright'),
             # dateuploaded by default is UTC:now in the database
+            user_defined_fields=user_defined_fields,
             )
 
         # SourcePackageFiles should contain also the DSC

=== modified file 'lib/lp/archiveuploader/nascentuploadfile.py'
--- lib/lp/archiveuploader/nascentuploadfile.py	2010-08-17 18:15:59 +0000
+++ lib/lp/archiveuploader/nascentuploadfile.py	2010-08-17 18:16:00 +0000
@@ -331,6 +331,12 @@
         """Return an ISection for self.section_name."""
         return getUtility(ISectionSet)[self.section_name]
 
+    def extractUserDefinedFields(self, control):
+        """Extract the user defined fields out of a control file list.
+        """
+        return [(field, contents) for (field, contents) in
+            control if field not in self.known_fields]
+
 
 class SourceUploadFile(SourceFileMixin, PackageUploadFile):
     """Files mentioned in changesfile as source (orig, diff, tar).
@@ -376,6 +382,25 @@
     # Capitalised because we extract these directly from the control file.
     mandatory_fields = set(["Package", "Architecture", "Version"])
 
+    known_fields = mandatory_fields.union(set([
+        "Depends",
+        "Conflicts",
+        "Breaks",
+        "Recommends",
+        "Suggests",
+        "Replaces",
+        "Provides",
+        "Pre-Depends",
+        "Enhances",
+        "Essential",
+        "Description",
+        "Installed-Size",
+        "Priority",
+        "Section",
+        "Maintainer",
+        "Source",
+        ]))
+
     # Map priorities to their dbschema valuesa
     # We treat a priority of '-' as EXTRA since some packages in some distros
     # are broken and we can't fix the world.
@@ -873,6 +898,9 @@
         else:
             debug_package = None
 
+        user_defined_fields = self.extractUserDefinedFields(
+            [(field, encoded[field]) for field in self.control])
+
         binary = build.createBinaryPackageRelease(
             binarypackagename=binary_name,
             version=self.control_version,
@@ -895,6 +923,7 @@
             essential=is_essential,
             installedsize=installedsize,
             architecturespecific=architecturespecific,
+            user_defined_fields=user_defined_fields,
             debug_package=debug_package)
 
         library_file = self.librarian.create(self.filename,

=== modified file 'lib/lp/archiveuploader/tests/__init__.py'
--- lib/lp/archiveuploader/tests/__init__.py	2010-08-06 13:52:46 +0000
+++ lib/lp/archiveuploader/tests/__init__.py	2010-08-17 18:16:00 +0000
@@ -8,7 +8,7 @@
 __metaclass__ = type
 
 __all__ = ['datadir', 'getPolicy', 'insertFakeChangesFile',
-           'insertFakeChangesFileForAllPackageUploads', 'mock_options',
+           'insertFakeChangesFileForAllPackageUploads', 
            'mock_logger', 'mock_logger_quiet']
 
 import os
@@ -98,6 +98,5 @@
         self.print_traceback(exc_info)
 
 
-mock_options = MockUploadOptions()
 mock_logger = MockUploadLogger()
 mock_logger_quiet = MockUploadLogger(verbose=False)

=== modified file 'lib/lp/archiveuploader/tests/test_nascentuploadfile.py'
--- lib/lp/archiveuploader/tests/test_nascentuploadfile.py	2010-08-17 18:15:59 +0000
+++ lib/lp/archiveuploader/tests/test_nascentuploadfile.py	2010-08-17 18:16:00 +0000
@@ -175,6 +175,22 @@
         self.assertEquals("0.42", release.version)
         self.assertEquals("dpkg, bzr", release.builddepends)
 
+    def test_user_defined_fields(self):
+        # Test that storeInDatabase updates user_defined_fields.
+        dsc = self.getBaseDsc()
+        dsc["Python-Version"] = "2.5"
+        changes = self.getBaseChanges()
+        uploadfile = self.createDSCFile(
+            "foo.dsc", dsc, "main/net", "extra", "dulwich", "0.42",
+            self.createChangesFile("foo.changes", changes))
+        (uploadfile.changelog_path, changelog_digest, changelog_size) = (
+            self.writeUploadFile("changelog", "DUMMY"))
+        uploadfile.files = []
+        release = uploadfile.storeInDatabase(None)
+        # DSCFile lowercases the field names
+        self.assertEquals(
+            [["python-version", u"2.5"]], release.user_defined_fields)
+
 
 class DebBinaryUploadFileTests(PackageUploadFileTestCase):
     """Tests for DebBinaryUploadFile."""
@@ -241,5 +257,19 @@
         self.assertEquals(False, bpr.essential)
         self.assertEquals(524, bpr.installedsize)
         self.assertEquals(True, bpr.architecturespecific)
-        self.assertEquals(None, bpr.recommends)
+        self.assertEquals("", bpr.recommends)
         self.assertEquals("0.42", bpr.version)
+
+    def test_user_defined_fields(self):
+        # Test that storeInDatabase stores user defined fields
+        uploadfile = self.createDebBinaryUploadFile(
+            "foo_0.42_i386.deb", "main/python", "unknown", "mypkg", "0.42",
+            None)
+        control = self.getBaseControl()
+        control["Python-Version"] = "2.5"
+        uploadfile.parseControl(control)
+        build = self.factory.makeBinaryPackageBuild()
+        bpr = uploadfile.storeInDatabase(build)
+        self.assertEquals(
+            [[u"Homepage", u"http://samba.org/~jelmer/dulwich";],
+             [u"Python-Version", u"2.5"]], bpr.user_defined_fields)

=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py	2010-08-03 08:49:19 +0000
+++ lib/lp/soyuz/model/publishing.py	2010-08-17 18:16:00 +0000
@@ -325,6 +325,12 @@
         """
         self.fields.append((name, value))
 
+    def extend(self, entries):
+        """Extend the internal list with the key-value pairs in entries.
+
+        """
+        self.fields.extend(entries)
+
     def makeOutput(self):
         """Return a line-by-line aggregation of appended fields.
 
@@ -672,6 +678,8 @@
         fields.append('Format', spr.dsc_format)
         fields.append('Directory', pool_path)
         fields.append('Files', files_subsection)
+        if spr.user_defined_fields:
+            fields.extend(spr.user_defined_fields)
 
         return fields
 
@@ -941,6 +949,8 @@
         fields.append('MD5sum', bin_md5)
         fields.append('SHA1', bin_sha1)
         fields.append('Description', bin_description)
+        if bpr.user_defined_fields:
+            fields.extend(bpr.user_defined_fields)
 
         # XXX cprov 2006-11-03: the extra override fields (Bugs, Origin and
         # Task) included in the template be were not populated.

=== modified file 'lib/lp/soyuz/tests/test_publish_archive_indexes.py'
--- lib/lp/soyuz/tests/test_publish_archive_indexes.py	2010-07-20 12:06:36 +0000
+++ lib/lp/soyuz/tests/test_publish_archive_indexes.py	2010-08-17 18:16:00 +0000
@@ -8,6 +8,8 @@
 import tempfile
 import unittest
 
+from lp.soyuz.model.publishing import IndexStanzaFields
+
 from lp.soyuz.tests.test_publishing import TestNativePublishingBase
 
 
@@ -52,6 +54,34 @@
              u' 5913c3ad52c14a62e6ae7eef51f9ef42 28 foo_666.dsc'],
             pub_source.getIndexStanza().splitlines())
 
+    def testSourceStanzaCustomFields(self):
+        """Check just-created source publication Index stanza 
+        with custom fields (Python-Version).
+        """
+        pub_source = self.getPubSource(
+            builddepends='fooish', builddependsindep='pyfoo',
+            build_conflicts='bar', build_conflicts_indep='pybar',
+            user_defined_fields=[("Python-Version", "< 1.5")])
+
+        self.assertEqual(
+            [u'Package: foo',
+             u'Binary: foo-bin',
+             u'Version: 666',
+             u'Section: base',
+             u'Maintainer: Foo Bar <foo@xxxxxxx>',
+             u'Build-Depends: fooish',
+             u'Build-Depends-Indep: pyfoo',
+             u'Build-Conflicts: bar',
+             u'Build-Conflicts-Indep: pybar',
+             u'Architecture: all',
+             u'Standards-Version: 3.6.2',
+             u'Format: 1.0',
+             u'Directory: pool/main/f/foo',
+             u'Files:',
+             u' 5913c3ad52c14a62e6ae7eef51f9ef42 28 foo_666.dsc',
+             u'Python-Version: < 1.5'],
+            pub_source.getIndexStanza().splitlines())
+
     def testBinaryStanza(self):
         """Check just-created binary publication Index stanza.
 
@@ -90,6 +120,45 @@
              u' it does nothing, though'],
             pub_binary.getIndexStanza().splitlines())
 
+    def testBinaryStanzaWithCustomFields(self):
+        """Check just-created binary publication Index stanza with
+        custom fields (Python-Version).
+
+        """
+        pub_binaries = self.getPubBinaries(
+            depends='biscuit', recommends='foo-dev', suggests='pyfoo',
+            conflicts='old-foo', replaces='old-foo', provides='foo-master',
+            pre_depends='master-foo', enhances='foo-super', breaks='old-foo',
+            user_defined_fields=[("Python-Version", ">= 2.4")])
+        pub_binary = pub_binaries[0]
+        self.assertEqual(
+            [u'Package: foo-bin',
+             u'Source: foo',
+             u'Priority: standard',
+             u'Section: base',
+             u'Installed-Size: 100',
+             u'Maintainer: Foo Bar <foo@xxxxxxx>',
+             u'Architecture: all',
+             u'Version: 666',
+             u'Recommends: foo-dev',
+             u'Replaces: old-foo',
+             u'Suggests: pyfoo',
+             u'Provides: foo-master',
+             u'Depends: biscuit',
+             u'Conflicts: old-foo',
+             u'Pre-Depends: master-foo',
+             u'Enhances: foo-super',
+             u'Breaks: old-foo',
+             u'Filename: pool/main/f/foo/foo-bin_666_all.deb',
+             u'Size: 18',
+             u'MD5sum: 008409e7feb1c24a6ccab9f6a62d24c5',
+             u'SHA1: 30b7b4e583fa380772c5a40e428434628faef8cf',
+             u'Description: Foo app is great',
+             u' Well ...',
+             u' it does nothing, though',
+             u'Python-Version: >= 2.4'],
+            pub_binary.getIndexStanza().splitlines())
+
     def testBinaryStanzaDescription(self):
         """ Check the description field.
 
@@ -301,18 +370,16 @@
 
 
 class TestIndexStanzaFieldsHelper(unittest.TestCase):
-
-    def testIndexStanzaFields(self):
-        """Check how this auxiliary class works...
-
-        This class provides simple FIFO API for aggregating fields
-        (name & values) in a ordered way.
-
-        Provides an method to format the option in a ready-to-use string.
-        """
-        # Avoid circular imports.
-        from lp.soyuz.model.publishing import IndexStanzaFields
-
+    """Check how this auxiliary class works...
+
+    This class provides simple FIFO API for aggregating fields
+    (name & values) in a ordered way.
+
+    Provides an method to format the option in a ready-to-use string.
+    """
+
+
+    def test_simple(self):
         fields = IndexStanzaFields()
         fields.append('breakfast', 'coffee')
         fields.append('lunch', 'beef')
@@ -324,15 +391,18 @@
             ['breakfast: coffee', 'lunch: beef', 'dinner: fish',
              ], fields.makeOutput().splitlines())
 
+    def test_preserves_order(self):
         fields = IndexStanzaFields()
         fields.append('one', 'um')
         fields.append('three', 'tres')
         fields.append('two', 'dois')
+        fields.append(None, None)
 
         self.assertEqual(
             ['one: um', 'three: tres', 'two: dois',
              ], fields.makeOutput().splitlines())
 
+    def test_files(self):
         # Special treatment for field named 'Files'
         # do not add a space between <name>:<value>
         # <value> will always start with a new line.
@@ -342,3 +412,12 @@
 
         self.assertEqual(
             ['one: um', 'Files:<no_sep>'], fields.makeOutput().splitlines())
+
+    def test_extend(self):
+        fields = IndexStanzaFields()
+        fields.append('one', 'um')
+        fields.extend([('three', 'tres'), ['four', 'five']])
+
+        self.assertEqual(
+            ['one: um', 'three: tres', 'four: five',
+             ], fields.makeOutput().splitlines())

=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py	2010-08-12 14:03:47 +0000
+++ lib/lp/soyuz/tests/test_publishing.py	2010-08-17 18:16:00 +0000
@@ -47,8 +47,7 @@
 from lp.soyuz.interfaces.queue import PackageUploadStatus
 from canonical.launchpad.scripts import FakeLogger
 from lp.testing import TestCaseWithFactory
-from lp.testing.factory import (
-    LaunchpadObjectFactory, remove_security_proxy_and_shout_at_engineer)
+from lp.testing.factory import LaunchpadObjectFactory
 from lp.testing.fakemethod import FakeMethod
 
 
@@ -172,7 +171,7 @@
                      build_conflicts_indep=None,
                      dsc_maintainer_rfc822='Foo Bar <foo@xxxxxxx>',
                      maintainer=None, creator=None, date_uploaded=UTC_NOW,
-                     spr_only=False):
+                     spr_only=False, user_defined_fields=None):
         """Return a mock source publishing record.
 
         if spr_only is specified, the source is not published and the
@@ -216,7 +215,8 @@
             dsc_standards_version=dsc_standards_version,
             dsc_format=dsc_format,
             dsc_binaries=dsc_binaries,
-            archive=archive, dateuploaded=date_uploaded)
+            archive=archive, dateuploaded=date_uploaded,
+            user_defined_fields=user_defined_fields)
 
         changes_file_name = "%s_%s_source.changes" % (sourcename, version)
         if spr_only:
@@ -279,7 +279,7 @@
                        architecturespecific=False,
                        builder=None,
                        component='main',
-                       with_debug=False):
+                       with_debug=False, user_defined_fields=None):
         """Return a list of binary publishing records."""
         if distroseries is None:
             distroseries = self.distroseries
@@ -323,7 +323,8 @@
                 build, binaryname, filecontent, summary, description,
                 shlibdep, depends, recommends, suggests, conflicts, replaces,
                 provides, pre_depends, enhances, breaks, format,
-                binarypackagerelease_ddeb)
+                binarypackagerelease_ddeb,
+                user_defined_fields=user_defined_fields)
             pub_binaries += self.publishBinaryInArchive(
                 binarypackagerelease, archive, status, pocket,
                 scheduleddeletiondate, dateremoved)
@@ -344,7 +345,8 @@
         summary="summary", description="description", shlibdep=None,
         depends=None, recommends=None, suggests=None, conflicts=None,
         replaces=None, provides=None, pre_depends=None, enhances=None,
-        breaks=None, format=BinaryPackageFormat.DEB, debug_package=None):
+        breaks=None, format=BinaryPackageFormat.DEB, debug_package=None,
+        user_defined_fields=None):
         """Return the corresponding `BinaryPackageRelease`."""
         sourcepackagerelease = build.source_package_release
         distroarchseries = build.distro_arch_series
@@ -376,7 +378,8 @@
             architecturespecific=architecturespecific,
             binpackageformat=format,
             priority=PackagePublishingPriority.STANDARD,
-            debug_package=debug_package)
+            debug_package=debug_package,
+            user_defined_fields=user_defined_fields)
 
         # Create the corresponding binary file.
         if architecturespecific: