launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26367
[Merge] ~cjwatson/launchpad:py3-tagfiles-bytes into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:py3-tagfiles-bytes into launchpad:master.
Commit message:
Always parse tagfiles as bytes
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/398367
Most field values are restricted to ASCII anyway, but dealing with everything as bytes makes our data types more consistent, allowing them to work on Python 3.
Apologies for the size of this MP; I couldn't manage to reduce it while making it still reasonably obvious what was going on. It ended up being simplest to convert pretty much all the tagfile parsing logic at once.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-tagfiles-bytes into launchpad:master.
diff --git a/lib/lp/archiveuploader/changesfile.py b/lib/lp/archiveuploader/changesfile.py
index e3d5c5c..09cb65e 100644
--- a/lib/lp/archiveuploader/changesfile.py
+++ b/lib/lp/archiveuploader/changesfile.py
@@ -17,6 +17,8 @@ __all__ = [
import os
+import six
+
from lp.archiveuploader.buildinfofile import BuildInfoFile
from lp.archiveuploader.dscfile import (
DSCFile,
@@ -47,6 +49,7 @@ from lp.registry.interfaces.sourcepackage import (
SourcePackageFileType,
SourcePackageUrgency,
)
+from lp.services.encoding import guess as guess_encoding
from lp.soyuz.enums import BinaryPackageFileType
@@ -241,14 +244,14 @@ class ChangesFile(SignableTagFile):
if 'Urgency' not in self._dict:
# Urgency is recommended but not mandatory. Default to 'low'
- self._dict['Urgency'] = "low"
+ self._dict['Urgency'] = b"low"
- raw_urgency = self._dict['Urgency'].lower()
+ raw_urgency = six.ensure_text(self._dict['Urgency']).lower()
if raw_urgency not in self.urgency_map:
yield UploadWarning(
"Unable to grok urgency %s, overriding with 'low'"
% (raw_urgency))
- self._dict['Urgency'] = "low"
+ self._dict['Urgency'] = b"low"
if not self.policy.unsigned_changes_ok:
assert self.signer is not None, (
@@ -297,7 +300,7 @@ class ChangesFile(SignableTagFile):
For example, 'hoary' or 'hoary-security'.
"""
- return self._dict['Distribution']
+ return six.ensure_text(self._dict['Distribution'])
@property
def architectures(self):
@@ -306,22 +309,23 @@ class ChangesFile(SignableTagFile):
For instance ['source', 'all'] or ['source', 'i386', 'amd64']
or ['source'].
"""
- return set(self._dict['Architecture'].split())
+ return set(six.ensure_text(self._dict['Architecture']).split())
@property
def binaries(self):
"""Return set of binary package names listed."""
- return set(self._dict.get('Binary', '').strip().split())
+ return set(
+ six.ensure_text(self._dict.get('Binary', '')).strip().split())
@property
def converted_urgency(self):
"""Return the appropriate SourcePackageUrgency item."""
- return self.urgency_map[self._dict['Urgency'].lower()]
+ return self.urgency_map[six.ensure_text(self._dict['Urgency']).lower()]
@property
def version(self):
"""Return changesfile claimed version."""
- return self._dict['Version']
+ return six.ensure_text(self._dict['Version'])
@classmethod
def formatChangesComment(cls, comment):
@@ -338,24 +342,24 @@ class ChangesFile(SignableTagFile):
@property
def changes_comment(self):
"""Return changesfile 'change' comment."""
- comment = self._dict['Changes']
+ comment = guess_encoding(self._dict['Changes'])
return self.formatChangesComment(comment)
@property
def date(self):
"""Return changesfile date."""
- return self._dict['Date']
+ return six.ensure_text(self._dict['Date'])
@property
def source(self):
"""Return changesfile claimed source name."""
- return self._dict['Source']
+ return six.ensure_text(self._dict['Source'])
@property
def architecture_line(self):
"""Return changesfile archicteture line."""
- return self._dict['Architecture']
+ return six.ensure_text(self._dict['Architecture'])
@property
def simulated_changelog(self):
@@ -369,8 +373,8 @@ class ChangesFile(SignableTagFile):
"""
changes_author = rfc822_encode_address(
self.changed_by['name'], self.changed_by['email'])
- return '%s\n\n -- %s %s' % (
- self.changes_comment, changes_author.encode('utf-8'), self.date)
+ return (u'%s\n\n -- %s %s' % (
+ self.changes_comment, changes_author, self.date)).encode('UTF-8')
def determine_file_class_and_name(filename):
diff --git a/lib/lp/archiveuploader/dscfile.py b/lib/lp/archiveuploader/dscfile.py
index 3ae5496..9140ef4 100644
--- a/lib/lp/archiveuploader/dscfile.py
+++ b/lib/lp/archiveuploader/dscfile.py
@@ -127,7 +127,7 @@ class SignableTagFile:
if self.signingkey is not None:
return self.signingkey.owner
- def parse(self, verify_signature=True, as_bytes=False):
+ def parse(self, verify_signature=True):
"""Parse the tag file, optionally verifying the signature.
If verify_signature is True, signingkey will be set to the signing
@@ -169,7 +169,7 @@ class SignableTagFile:
self.parsed_content = self.raw_content
try:
self._dict = parse_tagfile_content(
- self.parsed_content, filename=self.filepath, as_bytes=as_bytes)
+ self.parsed_content, filename=self.filepath)
except TagFileParseError as error:
raise UploadError(
"Unable to parse %s: %s" % (self.filename, error))
@@ -223,8 +223,8 @@ class SignableTagFile:
raise UploadError("Invalid Maintainer.")
if person is None and self.policy.create_people:
- package = self._dict['Source']
- version = self._dict['Version']
+ package = six.ensure_text(self._dict['Source'])
+ version = six.ensure_text(self._dict['Version'])
if self.policy.distroseries and self.policy.pocket:
policy_suite = ('%s/%s' % (self.policy.distroseries.name,
self.policy.pocket.name))
@@ -295,7 +295,7 @@ class DSCFile(SourceUploadFile, SignableTagFile):
SourceUploadFile.__init__(
self, filepath, checksums, size, component_and_section, priority,
package, version, changes, policy, logger)
- self.parse(verify_signature=not policy.unsigned_dsc_ok, as_bytes=True)
+ self.parse(verify_signature=not policy.unsigned_dsc_ok)
self.logger.debug("Performing DSC verification.")
for mandatory_field in self.mandatory_fields:
@@ -310,7 +310,7 @@ class DSCFile(SourceUploadFile, SignableTagFile):
# the wild generates dsc files with format missing, and we need
# to accept them.
if 'Format' not in self._dict:
- self._dict['Format'] = "1.0"
+ self._dict['Format'] = b"1.0"
if self.format is None:
raise EarlyReturnUploadError(
@@ -323,12 +323,12 @@ class DSCFile(SourceUploadFile, SignableTagFile):
@property
def source(self):
"""Return the DSC source name."""
- return self._dict['Source']
+ return six.ensure_text(self._dict['Source'])
@property
def dsc_version(self):
"""Return the DSC source version."""
- return self._dict['Version']
+ return six.ensure_text(self._dict['Version'])
@property
def format(self):
@@ -342,12 +342,12 @@ class DSCFile(SourceUploadFile, SignableTagFile):
@property
def architecture(self):
"""Return the DSC source architecture."""
- return self._dict['Architecture']
+ return six.ensure_text(self._dict['Architecture'])
@property
def binary(self):
"""Return the DSC claimed binary line."""
- return self._dict['Binary']
+ return six.ensure_text(self._dict['Binary'])
#
# DSC file checks.
@@ -411,6 +411,7 @@ class DSCFile(SourceUploadFile, SignableTagFile):
for field_name in ['Build-Depends', 'Build-Depends-Indep']:
field = self._dict.get(field_name, None)
if field is not None:
+ field = six.ensure_text(field)
if field.startswith("ARRAY"):
yield UploadError(
"%s: invalid %s field produced by a broken version "
diff --git a/lib/lp/archiveuploader/nascentuploadfile.py b/lib/lp/archiveuploader/nascentuploadfile.py
index dc5a8ed..48f079d 100644
--- a/lib/lp/archiveuploader/nascentuploadfile.py
+++ b/lib/lp/archiveuploader/nascentuploadfile.py
@@ -344,12 +344,12 @@ class PackageUploadFile(NascentUploadFile):
if self.section_name not in valid_sections:
raise UploadError(
- "%s: Unknown section %r" % (
+ "%s: Unknown section '%s'" % (
self.filename, self.section_name))
if self.component_name not in valid_components:
raise UploadError(
- "%s: Unknown component %r" % (
+ "%s: Unknown component '%s'" % (
self.filename, self.component_name))
@property
@@ -585,6 +585,7 @@ class BaseBinaryUploadFile(PackageUploadFile):
control_source = self.control.get("Source", None)
if control_source is not None:
+ control_source = six.ensure_text(control_source)
if "(" in control_source:
src_match = re_extract_src_version.match(control_source)
self.source_name = src_match.group(1)
@@ -595,14 +596,20 @@ class BaseBinaryUploadFile(PackageUploadFile):
else:
self.source_name = self.control.get("Package")
self.source_version = self.control.get("Version")
+ if self.source_name is not None:
+ self.source_name = six.ensure_text(self.source_name)
+ if self.source_version is not None:
+ self.source_version = six.ensure_text(self.source_version)
# Store control_version for external use (archive version consistency
# checks in nascentupload.py)
self.control_version = self.control.get("Version")
+ if self.control_version is not None:
+ self.control_version = six.ensure_text(self.control_version)
def verifyPackage(self):
"""Check if the binary is in changesfile and its name is valid."""
- control_package = self.control.get("Package", '')
+ control_package = six.ensure_text(self.control.get("Package", b''))
# Since DDEBs are generated after the original DEBs are processed
# and considered by `dpkg-genchanges` they are only half-incorporated
@@ -651,36 +658,37 @@ class BaseBinaryUploadFile(PackageUploadFile):
Also check if it is a valid architecture in LP context.
"""
- control_arch = self.control.get("Architecture", '')
+ control_arch = six.ensure_text(self.control.get("Architecture", b''))
valid_archs = [a.architecturetag
for a in self.policy.distroseries.architectures]
if control_arch not in valid_archs and control_arch != "all":
yield UploadError(
- "%s: Unknown architecture: %r" % (
+ "%s: Unknown architecture: '%s'" % (
self.filename, control_arch))
if control_arch not in self.changes.architectures:
yield UploadError(
- "%s: control file lists arch as %r which isn't "
+ "%s: control file lists arch as '%s' which isn't "
"in the changes file." % (self.filename, control_arch))
if control_arch != self.architecture:
yield UploadError(
- "%s: control file lists arch as %r which doesn't "
- "agree with version %r in the filename."
+ "%s: control file lists arch as '%s' which doesn't "
+ "agree with version '%s' in the filename."
% (self.filename, control_arch, self.architecture))
def verifyDepends(self):
"""Check if control depends field is present and not empty."""
- control_depends = self.control.get('Depends', "--unset-marker--")
+ control_depends = self.control.get('Depends', b"--unset-marker--")
if not control_depends:
yield UploadError(
"%s: Depends field present and empty." % self.filename)
def verifySection(self):
"""Check the section & priority match those in changesfile."""
- control_section_and_component = self.control.get('Section', '')
+ control_section_and_component = six.ensure_text(
+ self.control.get('Section', b''))
control_component, control_section = splitComponentAndSection(
control_section_and_component)
if ((control_component, control_section) !=
@@ -693,7 +701,7 @@ class BaseBinaryUploadFile(PackageUploadFile):
def verifyPriority(self):
"""Check if priority matches changesfile."""
- control_priority = self.control.get('Priority', '')
+ control_priority = six.ensure_text(self.control.get('Priority', b''))
if control_priority and self.priority_name != control_priority:
yield UploadError(
"%s control file lists priority as %s but changes file has "
@@ -896,7 +904,7 @@ class BaseBinaryUploadFile(PackageUploadFile):
is_essential = encoded.get('Essential', '').lower() == 'yes'
architecturespecific = not self.is_archindep
- installedsize = int(self.control.get('Installed-Size', '0'))
+ installedsize = int(self.control.get('Installed-Size', b'0'))
binary_name = getUtility(
IBinaryPackageNameSet).getOrCreateByName(self.package)
diff --git a/lib/lp/archiveuploader/tagfiles.py b/lib/lp/archiveuploader/tagfiles.py
index 5d3adc0..666c9c1 100644
--- a/lib/lp/archiveuploader/tagfiles.py
+++ b/lib/lp/archiveuploader/tagfiles.py
@@ -22,7 +22,7 @@ class TagFileParseError(Exception):
pass
-def parse_tagfile_content(content, filename=None, as_bytes=False):
+def parse_tagfile_content(content, filename=None):
"""Parses a tag file and returns a dictionary where each field is a key.
The mandatory first argument is the contents of the tag file as a
@@ -30,13 +30,15 @@ def parse_tagfile_content(content, filename=None, as_bytes=False):
An OpenPGP cleartext signature will be stripped before parsing if
one is present.
+
+ Header values are always returned as bytes.
"""
with tempfile.TemporaryFile() as f:
f.write(strip_pgp_signature(content))
f.seek(0)
try:
- stanzas = list(apt_pkg.TagFile(f, bytes=as_bytes))
+ stanzas = list(apt_pkg.TagFile(f, bytes=True))
except SystemError as e:
raise TagFileParseError("%s: %s" % (filename, e))
if len(stanzas) != 1:
@@ -61,8 +63,10 @@ def parse_tagfile(filename):
The mandatory first argument is the filename of the tag file, and
the contents of that file is passed on to parse_tagfile_content.
+
+ Header values are always returned as bytes.
"""
- with open(filename, "r") as changes_in:
+ with open(filename, "rb") as changes_in:
content = changes_in.read()
if not content:
raise TagFileParseError("%s: empty file" % filename)
diff --git a/lib/lp/archiveuploader/tests/nascentupload-closing-bugs.txt b/lib/lp/archiveuploader/tests/nascentupload-closing-bugs.txt
index dc39b37..91db6b5 100644
--- a/lib/lp/archiveuploader/tests/nascentupload-closing-bugs.txt
+++ b/lib/lp/archiveuploader/tests/nascentupload-closing-bugs.txt
@@ -78,8 +78,8 @@ This new version fixes bug #6 according its changesfiles:
>>> print(bar2_src.changes.changed_by['person'].name)
kinnison
- >>> bar2_src.changes._dict['Launchpad-bugs-fixed']
- '6'
+ >>> print(six.ensure_str(bar2_src.changes._dict['Launchpad-bugs-fixed']))
+ 6
>>> print bar2_src.changes.changes_comment
bar (1.0-2) breezy; urgency=low
diff --git a/lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt b/lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt
index 5acbc91..1ba7b85 100644
--- a/lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt
+++ b/lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt
@@ -204,11 +204,11 @@ SourcePackageRelease record store a proper 'version':
For source uploads, Changes.version == DSC.version == SPR.version:
- >>> bar_src_upload.changes.version
- '1:1.0-9'
+ >>> print(bar_src_upload.changes.version)
+ 1:1.0-9
- >>> bar_src_upload.changes.dsc.dsc_version
- '1:1.0-9'
+ >>> print(bar_src_upload.changes.dsc.dsc_version)
+ 1:1.0-9
>>> bar_src_queue = bar_src_upload.queue_root
>>> bar_spr = bar_src_queue.sources[0].sourcepackagerelease
@@ -247,21 +247,21 @@ The Changesfile version always refers to the source version and the
binary versions included in the upload can diverge between themselves
and from the source version.
- >>> bar_bin_upload.changes.version
- '1:1.0-9'
+ >>> print(bar_bin_upload.changes.version)
+ 1:1.0-9
>>> deb_file = bar_bin_upload.changes.files[0]
- >>> deb_file.filename
- 'bar_6.6.6_i386.deb'
+ >>> print(deb_file.filename)
+ bar_6.6.6_i386.deb
- >>> deb_file.version
- '1:1.0-9'
+ >>> print(deb_file.version)
+ 1:1.0-9
- >>> deb_file.source_version
- '1:1.0-9'
+ >>> print(deb_file.source_version)
+ 1:1.0-9
- >>> deb_file.control_version
- '1:6.6.6'
+ >>> print(deb_file.control_version)
+ 1:6.6.6
Anyway, the proper value for BinaryPackageRelease.version is the
version stored in the binary control file:
diff --git a/lib/lp/archiveuploader/tests/nascentupload.txt b/lib/lp/archiveuploader/tests/nascentupload.txt
index 6bdda3d..37f6836 100644
--- a/lib/lp/archiveuploader/tests/nascentupload.txt
+++ b/lib/lp/archiveuploader/tests/nascentupload.txt
@@ -231,8 +231,9 @@ should match the files target architectures:
... print f.filename, f
ed_0.2-20_i386.deb <...DebBinaryUploadFile...>
- >>> [a for a in ed_mismatched_upload.changes.architectures]
- ['amd64']
+ >>> for a in ed_mismatched_upload.changes.architectures:
+ ... print(a)
+ amd64
Since the changesfile specify that only 'amd64' will be used and
there is a file that depends on 'i386' the upload is rejected:
@@ -280,8 +281,10 @@ And because of that it's not considered native.
But if we check the DSC we will find the reference to the already
known ORIG file:
- >>> [f.filename for f in ed_upload.changes.dsc.files]
- ['ed_0.2.orig.tar.gz', 'ed_0.2-21.diff.gz']
+ >>> for f in ed_upload.changes.dsc.files:
+ ... print(f.filename)
+ ed_0.2.orig.tar.gz
+ ed_0.2-21.diff.gz
>>> success = ed_upload.do_accept()
>>> success
diff --git a/lib/lp/archiveuploader/tests/nascentuploadfile.txt b/lib/lp/archiveuploader/tests/nascentuploadfile.txt
index 0dbd48b..85a2ac7 100644
--- a/lib/lp/archiveuploader/tests/nascentuploadfile.txt
+++ b/lib/lp/archiveuploader/tests/nascentuploadfile.txt
@@ -90,18 +90,18 @@ file name.
At this point the changesfile content is already parsed:
- >>> ed_binary_changes.source
- 'ed'
+ >>> print(ed_binary_changes.source)
+ ed
- >>> ed_binary_changes.version
- '0.2-20'
+ >>> print(ed_binary_changes.version)
+ 0.2-20
>>> for item in ed_binary_changes.architectures:
... print(item)
i386
- >>> ed_binary_changes.suite_name
- 'unstable'
+ >>> print(ed_binary_changes.suite_name)
+ unstable
Push upload targeted suite into policy before the checks, nomally done
by NascentUpload object:
@@ -129,15 +129,19 @@ At this point we can inspect the list of files contained in the upload.
... print uploaded_file.filename
ed_0.2-20_i386.deb
- >>> [f.filename for f in ed_binary_changes.binary_package_files]
- ['ed_0.2-20_i386.deb']
- >>> [f.filename for f in ed_binary_changes.source_package_files]
- []
-
- >>> [f.filename for f in ed_source_changes.binary_package_files]
- []
- >>> [f.filename for f in ed_source_changes.source_package_files]
- ['ed_0.2-20.dsc', 'ed_0.2-20.diff.gz', 'ed_0.2.orig.tar.gz']
+ >>> for f in ed_binary_changes.binary_package_files:
+ ... print(f.filename)
+ ed_0.2-20_i386.deb
+ >>> for f in ed_binary_changes.source_package_files:
+ ... print(f.filename)
+
+ >>> for f in ed_source_changes.binary_package_files:
+ ... print(f.filename)
+ >>> for f in ed_source_changes.source_package_files:
+ ... print(f.filename)
+ ed_0.2-20.dsc
+ ed_0.2-20.diff.gz
+ ed_0.2.orig.tar.gz
Similar to what we have in 'processFiles' ChangesFile.verify is also
a error generator
@@ -364,14 +368,14 @@ in the ChangesFile instance.
The DSCFile also presents a similar behaviour to access its parsed
contents:
- >>> ed_source_dsc.source
- 'ed'
- >>> ed_source_dsc.version
- '0.2-20'
- >>> ed_source_dsc.architecture
- 'any'
- >>> ed_source_dsc.binary
- 'ed'
+ >>> print(ed_source_dsc.source)
+ ed
+ >>> print(ed_source_dsc.version)
+ 0.2-20
+ >>> print(ed_source_dsc.architecture)
+ any
+ >>> print(ed_source_dsc.binary)
+ ed
The DSC is GPG-signed most of the time, so we can guarantee who was
the author. The DSCFile class implements the same address parsing
@@ -482,7 +486,7 @@ changes file:
... 'main/net', 'important', 'foo', '1.2', ed_binary_changes,
... modified_insecure_policy, DevNullLogger())
>>> list(ed_binary_deb.verify())
- [UploadError('ed_0.2-20_i386.deb
+ [UploadError(...'ed_0.2-20_i386.deb
control file lists section as main/editors but changes file has
main/net.',)]
@@ -493,7 +497,7 @@ It also checks the priority against the changes file:
... 'main/editors', 'extra', 'foo', '1.2', ed_binary_changes,
... modified_insecure_policy, DevNullLogger())
>>> list(ed_binary_deb.verify())
- [UploadError('ed_0.2-20_i386.deb
+ [UploadError(...'ed_0.2-20_i386.deb
control file lists priority as important but changes file has extra.',)]
The timestamp of the files in the .deb are tested against the policy for
diff --git a/lib/lp/archiveuploader/tests/test_changesfile.py b/lib/lp/archiveuploader/tests/test_changesfile.py
index 60c8646..8f76d23 100644
--- a/lib/lp/archiveuploader/tests/test_changesfile.py
+++ b/lib/lp/archiveuploader/tests/test_changesfile.py
@@ -10,6 +10,7 @@ __metaclass__ = type
import os
from debian.deb822 import Changes
+import six
from testtools.matchers import (
Equals,
MatchesDict,
@@ -281,9 +282,9 @@ class ChangesFileTests(TestCase):
"mypkg_0.1_i386.changes", contents)
self.assertEqual([], list(changes.processAddresses()))
self.assertEqual(
- "Something changed\n\n"
- " -- Somebody <somebody@xxxxxxxxxx> "
- "Fri, 25 Jun 2010 11:20:22 -0600",
+ b"Something changed\n\n"
+ b" -- Somebody <somebody@xxxxxxxxxx> "
+ b"Fri, 25 Jun 2010 11:20:22 -0600",
changes.simulated_changelog)
def test_requires_changed_by(self):
@@ -377,7 +378,7 @@ class TestSignatureVerification(TestCase):
expected = "\\AFormat: 1.7\n.*foo_1.0-1.diff.gz\\Z"
self.assertTextMatchesExpressionIgnoreWhitespace(
expected,
- changesfile.parsed_content)
+ six.ensure_text(changesfile.parsed_content))
def test_no_signature_rejected(self):
# An unsigned changes file is rejected.
@@ -399,6 +400,6 @@ class TestSignatureVerification(TestCase):
expected = "\\AFormat: 1.7\n.*foo_1.0-1.diff.gz\\Z"
self.assertTextMatchesExpressionIgnoreWhitespace(
expected,
- changesfile.parsed_content)
+ six.ensure_text(changesfile.parsed_content))
self.assertEqual("breezy", changesfile.suite_name)
self.assertNotIn("evil", changesfile.changes_comment)
diff --git a/lib/lp/archiveuploader/tests/test_tagfiles.py b/lib/lp/archiveuploader/tests/test_tagfiles.py
index 3deff06..f5bf552 100755
--- a/lib/lp/archiveuploader/tests/test_tagfiles.py
+++ b/lib/lp/archiveuploader/tests/test_tagfiles.py
@@ -31,7 +31,7 @@ class Testtagfiles(unittest.TestCase):
reject them if it can't understand.
"""
parsed = parse_tagfile(datadir("bad-multiline-changes"))
- self.assertEqual('unstable', parsed['Distribution'])
+ self.assertEqual(b'unstable', parsed['Distribution'])
def testCheckParseMalformedMultiline(self):
"""Malformed but somewhat readable files do not raise an exception.
@@ -40,7 +40,7 @@ class Testtagfiles(unittest.TestCase):
reject them if it can't understand.
"""
parsed = parse_tagfile(datadir("bad-multiline-changes"))
- self.assertEqual('unstable', parsed['Distribution'])
+ self.assertEqual(b'unstable', parsed['Distribution'])
self.assertRaises(KeyError, parsed.__getitem__, 'Fish')
def testCheckParseEmptyChangesRaises(self):
@@ -82,7 +82,7 @@ class TestTagFileDebianPolicyCompat(unittest.TestCase):
tagfile_path = datadir("test436182_0.1_source.changes")
tagfile = open(tagfile_path)
- self.apt_pkg_parsed_version = apt_pkg.TagFile(tagfile)
+ self.apt_pkg_parsed_version = apt_pkg.TagFile(tagfile, bytes=True)
self.apt_pkg_parsed_version.step()
self.parse_tagfile_version = parse_tagfile(tagfile_path)
@@ -97,17 +97,17 @@ class TestTagFileDebianPolicyCompat(unittest.TestCase):
2. appended a trailing '\n' to the end of the value.
"""
- expected_text = (
- 'test75874 anotherbinary\n'
- ' andanother andonemore\n'
- '\tlastone')
+ expected_bytes = (
+ b'test75874 anotherbinary\n'
+ b' andanother andonemore\n'
+ b'\tlastone')
self.assertEqual(
- expected_text,
+ expected_bytes,
self.apt_pkg_parsed_version.section['Binary'])
self.assertEqual(
- expected_text,
+ expected_bytes,
self.parse_tagfile_version['Binary'])
def test_parse_tagfile_with_newline_delimited_field(self):
@@ -123,19 +123,19 @@ class TestTagFileDebianPolicyCompat(unittest.TestCase):
see http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Files
"""
- expected_text = (
- 'f26bb9b29b1108e53139da3584a4dc92 1511 test75874_0.1.tar.gz\n '
- '29c955ff520cea32ab3e0316306d0ac1 393742 '
- 'pmount_0.9.7.orig.tar.gz\n'
- ' 91a8f46d372c406fadcb57c6ff7016f3 5302 '
- 'pmount_0.9.7-2ubuntu2.diff.gz')
+ expected_bytes = (
+ b'f26bb9b29b1108e53139da3584a4dc92 1511 test75874_0.1.tar.gz\n '
+ b'29c955ff520cea32ab3e0316306d0ac1 393742 '
+ b'pmount_0.9.7.orig.tar.gz\n'
+ b' 91a8f46d372c406fadcb57c6ff7016f3 5302 '
+ b'pmount_0.9.7-2ubuntu2.diff.gz')
self.assertEqual(
- expected_text,
+ expected_bytes,
self.apt_pkg_parsed_version.section['Files'])
self.assertEqual(
- expected_text,
+ expected_bytes,
self.parse_tagfile_version['Files'])
def test_parse_description_field(self):
@@ -144,19 +144,19 @@ class TestTagFileDebianPolicyCompat(unittest.TestCase):
See http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description
"""
- expected_text = (
- "Here's the single-line synopsis.\n"
- " Then there is the extended description which can\n"
- " span multiple lines, and even include blank-lines like this:\n"
- " .\n"
- " There you go. If a line starts with two or more spaces,\n"
- " it will be displayed verbatim. Like this one:\n"
- " Example verbatim line.\n"
- " Another verbatim line.\n"
- " OK, back to normal.")
+ expected_bytes = (
+ b"Here's the single-line synopsis.\n"
+ b" Then there is the extended description which can\n"
+ b" span multiple lines, and even include blank-lines like this:\n"
+ b" .\n"
+ b" There you go. If a line starts with two or more spaces,\n"
+ b" it will be displayed verbatim. Like this one:\n"
+ b" Example verbatim line.\n"
+ b" Another verbatim line.\n"
+ b" OK, back to normal.")
self.assertEqual(
- expected_text,
+ expected_bytes,
self.apt_pkg_parsed_version.section['Description'])
# In the past our parse_tagfile function replaced blank-line
@@ -164,5 +164,5 @@ class TestTagFileDebianPolicyCompat(unittest.TestCase):
# but it is now compatible with ParseTagFiles (and ready to be
# replaced by ParseTagFiles).
self.assertEqual(
- expected_text,
+ expected_bytes,
self.parse_tagfile_version['Description'])
diff --git a/lib/lp/archiveuploader/utils.py b/lib/lp/archiveuploader/utils.py
index 334a2aa..bc5cf80 100644
--- a/lib/lp/archiveuploader/utils.py
+++ b/lib/lp/archiveuploader/utils.py
@@ -270,7 +270,7 @@ def parse_file_list(s, field_name, count):
if s is None:
return None
processed = []
- for line in s.strip().split('\n'):
+ for line in six.ensure_text(s).strip().split('\n'):
split = line.strip().split()
if len(split) != count:
raise UploadError(
diff --git a/lib/lp/soyuz/doc/gina.txt b/lib/lp/soyuz/doc/gina.txt
index 2e2e253..f342cf3 100644
--- a/lib/lp/soyuz/doc/gina.txt
+++ b/lib/lp/soyuz/doc/gina.txt
@@ -134,38 +134,38 @@ Check STDERR for the errors we expected:
>>> print(proc.stderr.read())
ERROR Error processing package files for clearlooks
...
- ExecutionError: Error 2 unpacking source
+ ...ExecutionError: Error 2 unpacking source
WARNING Invalid format in db1-compat, assumed '1.0'
WARNING Source package ed lacks section, assumed 'misc'
ERROR Unable to create SourcePackageData for mkvmlinuz
...
- InvalidVersionError: mkvmlinuz has an invalid version: None
+ ...InvalidVersionError: mkvmlinuz has an invalid version: None
WARNING Invalid urgency in python-pam, None, assumed 'low'
ERROR Error processing package files for util-linux
...
- PoolFileNotFound: File util-linux_2.12p-2ubuntu2.2.dsc not in archive
+ ...PoolFileNotFound: File util-linux_2.12p-2ubuntu2.2.dsc not in archive
ERROR Error processing package files for bsdutils
...
- PoolFileNotFound: .../bsdutils_2.12p-2ubuntu2_i386.deb not found
+ ...PoolFileNotFound: .../bsdutils_2.12p-2ubuntu2_i386.deb not found
WARNING Binary package ed lacks valid priority, assumed 'extra'
ERROR Unable to create BinaryPackageData for mount
...
- InvalidVersionError: mount has an invalid version: -ewePP2.12p-2ubuntu2
+ ...InvalidVersionError: mount has an invalid version: -ewePP2.12p-2ubuntu2
WARNING Binary package python-pam lacks a section, assumed 'misc'
ERROR Error processing package files for python2.4-pam
...
- PoolFileNotFound: .../python2.4-pam_0.4.2-10.1ubuntu3_i386.deb not found
+ ...PoolFileNotFound: .../python2.4-pam_0.4.2-10.1ubuntu3_i386.deb not found
ERROR Error processing package files for python2.4-sqlite
...
- PoolFileNotFound: .../python2.4-sqlite_1.0.1-1ubuntu1_i386.deb not found
+ ...PoolFileNotFound: .../python2.4-sqlite_1.0.1-1ubuntu1_i386.deb not found
WARNING No source package rioutil (1.4.4-1.0.1) listed for rioutil (1.4.4-1.0.1), scrubbing archive...
WARNING Nope, couldn't find it. Could it be a bin-only-NMU? Checking...
ERROR Error processing package files for util-linux
...
- PoolFileNotFound: .../util-linux_2.12p-2ubuntu2_i386.deb not found
+ ...PoolFileNotFound: .../util-linux_2.12p-2ubuntu2_i386.deb not found
ERROR Unable to create BinaryPackageData for util-linux-locales
...
- MissingRequiredArguments: ['installed_size']
+ ...MissingRequiredArguments: ['installed_size']
ERROR Invalid Sources stanza in /tmp/tmp...
...
WARNING No changelog file found for mkvmlinuz in mkvmlinuz-14ubuntu1
@@ -173,13 +173,13 @@ Check STDERR for the errors we expected:
WARNING Invalid urgency in mkvmlinuz, None, assumed 'low'
ERROR Error processing package files for python-sqlite
...
- PoolFileNotFound: File python-sqlite_1.0.1-2ubuntu1.dsc not in archive
+ ...PoolFileNotFound: File python-sqlite_1.0.1-2ubuntu1.dsc not in archive
ERROR Error processing package files for util-linux
...
- PoolFileNotFound: File util-linux_2.12p-6ubuntu5.dsc not in archive
+ ...PoolFileNotFound: File util-linux_2.12p-6ubuntu5.dsc not in archive
ERROR Error processing package files for python-sqlite
...
- PoolFileNotFound: .../python-sqlite_1.0.1-2ubuntu1_all.deb not found
+ ...PoolFileNotFound: .../python-sqlite_1.0.1-2ubuntu1_all.deb not found
WARNING No source package ubuntu-meta (0.80) listed for ubuntu-base (0.80), scrubbing archive...
<BLANKLINE>
@@ -230,7 +230,7 @@ Check if the changelog message was stored correcly:
Check that the changelog was uploaded to the librarian correctly:
- >>> print(x11p.changelog.read())
+ >>> print(six.ensure_text(x11p.changelog.read()))
x11proto-damage (6.8.99.7-2) breezy; urgency=low
<BLANKLINE>
* Add dependency on x11proto-fixes-dev.
@@ -521,45 +521,45 @@ run.
>>> print(proc.stderr.read())
ERROR Error processing package files for clearlooks
...
- ExecutionError: Error 2 unpacking source
+ ...ExecutionError: Error 2 unpacking source
WARNING Source package ed lacks section, assumed 'misc'
ERROR Unable to create SourcePackageData for mkvmlinuz
...
- InvalidVersionError: mkvmlinuz has an invalid version: None
+ ...InvalidVersionError: mkvmlinuz has an invalid version: None
ERROR Error processing package files for util-linux
...
- PoolFileNotFound: File util-linux_2.12p-2ubuntu2.2.dsc not in archive
+ ...PoolFileNotFound: File util-linux_2.12p-2ubuntu2.2.dsc not in archive
ERROR Error processing package files for bsdutils
...
- PoolFileNotFound: .../bsdutils_2.12p-2ubuntu2_i386.deb not found
+ ...PoolFileNotFound: .../bsdutils_2.12p-2ubuntu2_i386.deb not found
WARNING Binary package ed lacks valid priority, assumed 'extra'
ERROR Unable to create BinaryPackageData for mount
...
- InvalidVersionError: mount has an invalid version: -ewePP2.12p-2ubuntu2
+ ...InvalidVersionError: mount has an invalid version: -ewePP2.12p-2ubuntu2
WARNING Binary package python-pam lacks a section, assumed 'misc'
ERROR Error processing package files for python2.4-pam
...
- PoolFileNotFound: .../python2.4-pam_0.4.2-10.1ubuntu3_i386.deb not found
+ ...PoolFileNotFound: .../python2.4-pam_0.4.2-10.1ubuntu3_i386.deb not found
ERROR Error processing package files for python2.4-sqlite
...
- PoolFileNotFound: .../python2.4-sqlite_1.0.1-1ubuntu1_i386.deb not found
+ ...PoolFileNotFound: .../python2.4-sqlite_1.0.1-1ubuntu1_i386.deb not found
ERROR Error processing package files for util-linux
...
- PoolFileNotFound: .../util-linux_2.12p-2ubuntu2_i386.deb not found
+ ...PoolFileNotFound: .../util-linux_2.12p-2ubuntu2_i386.deb not found
ERROR Unable to create BinaryPackageData for util-linux-locales
...
- MissingRequiredArguments: ['installed_size']
+ ...MissingRequiredArguments: ['installed_size']
ERROR Invalid Sources stanza in /tmp/tmp...
...
ERROR Error processing package files for python-sqlite
...
- PoolFileNotFound: File python-sqlite_1.0.1-2ubuntu1.dsc not in archive
+ ...PoolFileNotFound: File python-sqlite_1.0.1-2ubuntu1.dsc not in archive
ERROR Error processing package files for util-linux
...
- PoolFileNotFound: File util-linux_2.12p-6ubuntu5.dsc not in archive
+ ...PoolFileNotFound: File util-linux_2.12p-6ubuntu5.dsc not in archive
ERROR Error processing package files for python-sqlite
...
- PoolFileNotFound: .../python-sqlite_1.0.1-2ubuntu1_all.deb not found
+ ...PoolFileNotFound: .../python-sqlite_1.0.1-2ubuntu1_all.deb not found
<BLANKLINE>
>>> proc.wait()
0
@@ -815,7 +815,7 @@ For kicks, finally, run gina on a configured but incomplete archive:
>>> print(proc.stderr.read())
ERROR Failed to analyze archive for bogoland
...
- MangledArchiveError: No archive directory for bogoland/main
+ ...MangledArchiveError: No archive directory for bogoland/main
<BLANKLINE>
>>> proc.wait()
1
diff --git a/lib/lp/soyuz/doc/soyuz-upload.txt b/lib/lp/soyuz/doc/soyuz-upload.txt
index 5030c6a..7962cb2 100644
--- a/lib/lp/soyuz/doc/soyuz-upload.txt
+++ b/lib/lp/soyuz/doc/soyuz-upload.txt
@@ -61,13 +61,14 @@ been uploaded over FTP.
... tf = {}
...
... if "Source" in tf:
- ... package_names.append(tf["Source"])
+ ... package_names.append(six.ensure_text(tf["Source"]))
...
... send_filepaths = [changes_filepath]
... if "Files" in tf:
... send_filepaths.extend(
... [os.path.join(test_files_dir, line.split()[-1])
- ... for line in tf["Files"].splitlines() if line])
+ ... for line in six.ensure_text(tf["Files"]).splitlines()
+ ... if line])
...
... sent_filenames.extend(
... os.path.basename(filepath) for filepath in send_filepaths)
@@ -87,7 +88,7 @@ been uploaded over FTP.
Check that what we've just uploaded (everything in test_files_dir) is
what we were expecting to have uploaded.
- >>> package_names
+ >>> print(pretty(package_names))
['drdsl', 'etherwake']
At that point we must have a bunch of directories in the upload base
diff --git a/lib/lp/soyuz/mail/packageupload.py b/lib/lp/soyuz/mail/packageupload.py
index f194061..a5686a1 100644
--- a/lib/lp/soyuz/mail/packageupload.py
+++ b/lib/lp/soyuz/mail/packageupload.py
@@ -140,6 +140,8 @@ def fetch_information(spr, bprs, changes, previous_version=None):
changelog = ChangesFile.formatChangesComment(
sanitize_string(changes.get('Changes')))
date = changes.get('Date')
+ if date is not None:
+ date = six.ensure_text(date)
try:
changedby = parse_maintainer_bytes(
changes.get('Changed-By'), 'Changed-By')
@@ -151,7 +153,7 @@ def fetch_information(spr, bprs, changes, previous_version=None):
except ParseMaintError:
pass
notify_changed_by = changes.get(
- 'Launchpad-Notify-Changed-By', '') == 'yes'
+ 'Launchpad-Notify-Changed-By', b'') == b'yes'
elif spr or bprs:
if not spr and bprs:
spr = bprs[0].build.source_package_release
diff --git a/lib/lp/soyuz/mail/tests/test_packageupload.py b/lib/lp/soyuz/mail/tests/test_packageupload.py
index 7881462..d39d9c3 100644
--- a/lib/lp/soyuz/mail/tests/test_packageupload.py
+++ b/lib/lp/soyuz/mail/tests/test_packageupload.py
@@ -254,10 +254,10 @@ class TestNotification(TestCaseWithFactory):
def test_fetch_information_changes(self):
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Foo Bar <foo.bar@xxxxxxxxxxx>',
- 'Maintainer': 'Foo Bar <foo.bar@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Foo Bar <foo.bar@xxxxxxxxxxx>',
+ 'Maintainer': b'Foo Bar <foo.bar@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
info = fetch_information(None, None, changes)
self.assertEqual('2001-01-01', info['date'])
@@ -272,11 +272,11 @@ class TestNotification(TestCaseWithFactory):
def test_fetch_information_changes_notify_changed_by(self):
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Foo Bar <foo.bar@xxxxxxxxxxx>',
- 'Maintainer': 'Foo Bar <foo.bar@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
- 'Launchpad-Notify-Changed-By': 'yes',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Foo Bar <foo.bar@xxxxxxxxxxx>',
+ 'Maintainer': b'Foo Bar <foo.bar@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
+ 'Launchpad-Notify-Changed-By': b'yes',
}
info = fetch_information(None, None, changes)
self.assertEqual('2001-01-01', info['date'])
@@ -410,10 +410,10 @@ class TestNotification(TestCaseWithFactory):
# Test getRecipientsForAction with good email addresses..
blamer, maintainer, changer = self._setup_recipients()
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
self.assertRecipientsEqual(
[blamer, maintainer, changer],
@@ -422,10 +422,10 @@ class TestNotification(TestCaseWithFactory):
def test_getRecipientsForAction_bad_maintainer_email(self):
blamer, maintainer, changer = self._setup_recipients()
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer at example.com>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer at example.com>',
+ 'Changes': b' * Foo!',
}
self.assertRecipientsEqual(
[blamer, changer], changes, blamer, maintainer, changer)
@@ -434,10 +434,10 @@ class TestNotification(TestCaseWithFactory):
# Test getRecipientsForAction with invalid changedby email address.
blamer, maintainer, changer = self._setup_recipients()
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer at example.com>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer at example.com>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
self.assertRecipientsEqual(
[blamer, maintainer], changes, blamer, maintainer, changer)
@@ -447,10 +447,10 @@ class TestNotification(TestCaseWithFactory):
# to the archive owner.
_, maintainer, changer = self._setup_recipients()
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
self.assertRecipientsEqual(
[], changes, None, maintainer, changer,
@@ -461,10 +461,10 @@ class TestNotification(TestCaseWithFactory):
# signed the upload.
blamer, maintainer, changer = self._setup_recipients()
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
self.assertRecipientsEqual(
[blamer], changes, blamer, maintainer, changer,
@@ -475,11 +475,11 @@ class TestNotification(TestCaseWithFactory):
# notifications go to the changer even for PPA uploads.
blamer, maintainer, changer = self._setup_recipients()
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
- 'Launchpad-Notify-Changed-By': 'yes',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
+ 'Launchpad-Notify-Changed-By': b'yes',
}
self.assertRecipientsEqual(
[blamer, changer], changes, blamer, maintainer, changer,
@@ -500,10 +500,10 @@ class TestNotification(TestCaseWithFactory):
spr = self.factory.makeSourcePackageRelease(
component=component, section_name="libs")
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
mailer = PackageUploadMailer.forAction(
"accepted", blamer, spr, [], [], archive, distroseries,
@@ -545,10 +545,10 @@ class TestNotification(TestCaseWithFactory):
spr = self.factory.makeSourcePackageRelease(
component=component, section_name="libs")
changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
- 'Changes': ' * Foo!',
+ 'Date': b'2001-01-01',
+ 'Changed-By': b'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': b'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': b' * Foo!',
}
mailer = PackageUploadMailer.forAction(
"accepted", blamer, spr, [], [], archive, distroseries,
diff --git a/lib/lp/soyuz/scripts/gina/archive.py b/lib/lp/soyuz/scripts/gina/archive.py
index 6ecb30a..e2f524c 100644
--- a/lib/lp/soyuz/scripts/gina/archive.py
+++ b/lib/lp/soyuz/scripts/gina/archive.py
@@ -22,6 +22,7 @@ import shutil
import tempfile
import apt_pkg
+import six
from lp.services.scripts import log
from lp.soyuz.scripts.gina import call
@@ -202,13 +203,14 @@ class PackagesMap:
# because most of them are the same for all architectures,
# but we go over it to also cover source packages that only
# compile for one architecture.
- sources = apt_pkg.TagFile(info_set.srcfile)
+ sources = apt_pkg.TagFile(info_set.srcfile, bytes=True)
try:
for section in sources:
try:
src_tmp = dict(section)
- src_tmp['Component'] = info_set.component
- src_name = src_tmp['Package']
+ src_tmp['Component'] = six.ensure_binary(
+ info_set.component)
+ src_name = six.ensure_text(src_tmp['Package'])
except KeyError:
log.exception(
"Invalid Sources stanza in %s",
@@ -229,13 +231,14 @@ class PackagesMap:
tmpbin_map = self.bin_map[info_set.arch]
- binaries = apt_pkg.TagFile(info_set.binfile)
+ binaries = apt_pkg.TagFile(info_set.binfile, bytes=True)
for section in binaries:
try:
bin_tmp = dict(section)
# The component isn't listed in the tagfile.
- bin_tmp['Component'] = info_set.component
- bin_name = bin_tmp['Package']
+ bin_tmp['Component'] = six.ensure_binary(
+ info_set.component)
+ bin_name = six.ensure_text(bin_tmp['Package'])
except KeyError:
log.exception(
"Invalid Releases stanza in %s",
@@ -244,12 +247,13 @@ class PackagesMap:
tmpbin_map[bin_name] = bin_tmp
# Run over the D-I stanzas and store info in tmp_bin_map.
- dibinaries = apt_pkg.TagFile(info_set.difile)
+ dibinaries = apt_pkg.TagFile(info_set.difile, bytes=True)
for section in dibinaries:
try:
dibin_tmp = dict(section)
- dibin_tmp['Component'] = info_set.component
- dibin_name = dibin_tmp['Package']
+ dibin_tmp['Component'] = six.ensure_binary(
+ info_set.component)
+ dibin_name = six.ensure_text(dibin_tmp['Package'])
except KeyError:
log.exception("Invalid D-I Releases stanza in %s" %
info_set.difile)
diff --git a/lib/lp/soyuz/scripts/gina/changelog.py b/lib/lp/soyuz/scripts/gina/changelog.py
index bd637da..ec20556 100644
--- a/lib/lp/soyuz/scripts/gina/changelog.py
+++ b/lib/lp/soyuz/scripts/gina/changelog.py
@@ -8,13 +8,15 @@ __metaclass__ = type
import re
import sys
-
-first_re = re.compile(r"^([a-z0-9][a-z0-9\\+\\.\\-]+)\s+\(([^ ]+)\)")
-urgency_re = re.compile(r'(?:urgency|priority)=([^ ,;:.]+)')
+import six
from lp.archivepublisher.debversion import Version
+first_re = re.compile(br"^([a-z0-9][a-z0-9\\+\\.\\-]+)\s+\(([^ ]+)\)")
+urgency_re = re.compile(br'(?:urgency|priority)=([^ ,;:.]+)')
+
+
def parse_first_line(line):
# SRCPKGNAME (VERSION).*((urgency|priority)=\S+)?
match = first_re.match(line)
@@ -33,8 +35,8 @@ def parse_first_line(line):
def parse_last_line(line):
- maint = line[:line.find(">") + 1].strip()
- date = line[line.find(">") + 1:].strip()
+ maint = line[:line.find(b">") + 1].strip()
+ date = line[line.find(b">") + 1:].strip()
return (maint, date)
@@ -48,40 +50,40 @@ def parse_changelog_stanza(firstline, stanza, lastline):
"urgency": urgency,
"maintainer": maint,
"date": date,
- "changes": "".join(stanza).strip("\n")
+ "changes": b"".join(stanza).strip(b"\n")
}
def parse_changelog(changelines):
state = 0
- firstline = ""
+ firstline = b""
stanza = []
rets = []
for line in changelines:
#print line[:-1]
if state == 0:
- if (line.startswith(" ") or line.startswith("\t") or
+ if (line.startswith(b" ") or line.startswith(b"\t") or
not line.rstrip()):
#print "State0 skip"
continue
try:
(source, version, urgency) = parse_first_line(line.strip())
- Version(version)
+ Version(six.ensure_text(version))
except:
stanza.append(line)
#print "state0 Exception skip"
continue
firstline = line.strip()
- stanza = [line, '\n']
+ stanza = [line, b'\n']
state = 1
continue
if state == 1:
stanza.append(line)
- stanza.append('\n')
+ stanza.append(b'\n')
- if line.startswith(" --") and "@" in line:
+ if line.startswith(b" --") and b"@" in line:
#print "state1 accept"
# Last line of stanza
rets.append(parse_changelog_stanza(firstline,
@@ -93,12 +95,12 @@ def parse_changelog(changelines):
if state == 1:
rets[-1]["changes"] += firstline
if len(rets):
- rets[-1]["changes"] += "".join(stanza).strip("\n")
+ rets[-1]["changes"] += b"".join(stanza).strip(b"\n")
return rets
if __name__ == '__main__':
import pprint
- with open(sys.argv[1]) as f:
+ with open(sys.argv[1], "rb") as f:
pprint.pprint(parse_changelog(f))
diff --git a/lib/lp/soyuz/scripts/gina/dominate.py b/lib/lp/soyuz/scripts/gina/dominate.py
index 6b27a18..0745f92 100644
--- a/lib/lp/soyuz/scripts/gina/dominate.py
+++ b/lib/lp/soyuz/scripts/gina/dominate.py
@@ -8,6 +8,7 @@ __all__ = [
'dominate_imported_source_packages',
]
+import six
from zope.component import getUtility
from lp.archivepublisher.domination import Dominator
@@ -27,7 +28,8 @@ def dominate_imported_source_packages(txn, logger, distro_name, series_name,
for package_name, pub_count in package_counts:
entries = packages_map.src_map.get(package_name, [])
live_versions = [
- entry['Version'] for entry in entries if 'Version' in entry]
+ six.ensure_text(entry['Version'])
+ for entry in entries if 'Version' in entry]
# Gina import just ensured that any live version in the Sources
# file has a Published publication. So there should be at least
diff --git a/lib/lp/soyuz/scripts/gina/handlers.py b/lib/lp/soyuz/scripts/gina/handlers.py
index d3d4333..85f7fce 100644
--- a/lib/lp/soyuz/scripts/gina/handlers.py
+++ b/lib/lp/soyuz/scripts/gina/handlers.py
@@ -513,21 +513,21 @@ class SourcePackageHandler:
# Since the dsc doesn't know, we add in the directory, package
# component and section
dsc_contents['directory'] = os.path.join("pool",
- poolify(sp_name, sp_component))
- dsc_contents['package'] = sp_name
- dsc_contents['component'] = sp_component
- dsc_contents['section'] = sp_section
+ poolify(sp_name, sp_component)).encode("ASCII")
+ dsc_contents['package'] = sp_name.encode("ASCII")
+ dsc_contents['component'] = sp_component.encode("ASCII")
+ dsc_contents['section'] = sp_section.encode("ASCII")
# the dsc doesn't list itself so add it ourselves
if 'files' not in dsc_contents:
log.error('DSC for %s didn\'t contain a files entry: %r' %
(dsc_name, dsc_contents))
return None
- if not dsc_contents['files'].endswith("\n"):
- dsc_contents['files'] += "\n"
+ if not dsc_contents['files'].endswith(b"\n"):
+ dsc_contents['files'] += b"\n"
# XXX kiko 2005-10-21: Why do we hack the md5sum and size of the DSC?
# Should probably calculate it properly.
- dsc_contents['files'] += "xxx 000 %s" % dsc_name
+ dsc_contents['files'] += ("xxx 000 %s" % dsc_name).encode("ASCII")
# SourcePackageData requires capitals
capitalized_dsc = {}
diff --git a/lib/lp/soyuz/scripts/gina/packages.py b/lib/lp/soyuz/scripts/gina/packages.py
index 6f294d2..504e907 100644
--- a/lib/lp/soyuz/scripts/gina/packages.py
+++ b/lib/lp/soyuz/scripts/gina/packages.py
@@ -29,6 +29,7 @@ import shutil
import tempfile
import scandir
+import six
from lp.app.validators.version import valid_debian_version
from lp.archivepublisher.diskpool import poolify
@@ -123,7 +124,7 @@ def read_dsc(package, version, component, distro_name, archive_root):
distro_name, archive_root)
try:
- with open(dsc_path) as f:
+ with open(dsc_path, "rb") as f:
dsc = f.read().strip()
fullpath = os.path.join(source_dir, "debian", "changelog")
@@ -331,11 +332,11 @@ class SourcePackageData(AbstractPackageData):
def __init__(self, **args):
for k, v in args.items():
if k == 'Binary':
- self.binaries = stripseq(v.split(","))
+ self.binaries = stripseq(six.ensure_text(v).split(","))
elif k == 'Section':
- self.section = parse_section(v)
+ self.section = parse_section(six.ensure_text(v))
elif k == 'Urgency':
- urgency = v
+ urgency = six.ensure_text(v)
# This is to handle cases like:
# - debget: 'high (actually works)
# - lxtools: 'low, closes=90239'
@@ -345,23 +346,20 @@ class SourcePackageData(AbstractPackageData):
urgency = urgency.split(",")[0]
self.urgency = urgency
elif k == 'Maintainer':
- displayname, emailaddress = parse_person(v)
try:
- self.maintainer = (
- encoding.guess(displayname),
- emailaddress,
- )
+ maintainer = encoding.guess(v)
except UnicodeDecodeError:
raise DisplayNameDecodingError(
- "Could not decode name %s" % displayname)
+ "Could not decode Maintainer field %r" % v)
+ self.maintainer = parse_person(maintainer)
elif k == 'Files' or k.startswith('Checksums-'):
if not hasattr(self, 'files'):
self.files = []
- files = v.split("\n")
+ files = six.ensure_text(v).split("\n")
for f in files:
self.files.append(stripseq(f.split(" "))[-1])
else:
- self.set_field(k, v)
+ self.set_field(k, encoding.guess(v))
if self.section is None:
self.section = 'misc'
@@ -390,7 +388,7 @@ class SourcePackageData(AbstractPackageData):
self.copyright = encoding.guess(copyright)
parsed_changelog = None
if changelog:
- parsed_changelog = parse_changelog(changelog.split('\n'))
+ parsed_changelog = parse_changelog(changelog.split(b'\n'))
self.urgency = None
self.changelog = None
@@ -398,17 +396,21 @@ class SourcePackageData(AbstractPackageData):
if parsed_changelog and parsed_changelog[0]:
cldata = parsed_changelog[0]
if 'changes' in cldata:
- if cldata["package"] != self.package:
+ cldata_package = six.ensure_text(cldata["package"])
+ cldata_version = six.ensure_text(cldata["version"])
+ if cldata_package != self.package:
log.warning(
"Changelog package %s differs from %s" %
- (cldata["package"], self.package))
- if cldata["version"] != self.version:
+ (cldata_package, self.package))
+ if cldata_version != self.version:
log.warning(
"Changelog version %s differs from %s" %
- (cldata["version"], self.version))
+ (cldata_version, self.version))
self.changelog_entry = encoding.guess(cldata["changes"])
self.changelog = changelog
self.urgency = cldata["urgency"]
+ if self.urgency is not None:
+ self.urgency = six.ensure_text(self.urgency)
else:
log.warning(
"Changelog empty for source %s (%s)" %
@@ -483,11 +485,11 @@ class BinaryPackageData(AbstractPackageData):
def __init__(self, **args):
for k, v in args.items():
if k == "Maintainer":
- self.maintainer = parse_person(v)
+ self.maintainer = parse_person(encoding.guess(v))
elif k == "Essential":
- self.essential = (v == "yes")
+ self.essential = (v == b"yes")
elif k == 'Section':
- self.section = parse_section(v)
+ self.section = parse_section(six.ensure_text(v))
elif k == "Description":
self.description = encoding.guess(v)
summary = self.description.split("\n")[0].strip()
@@ -495,21 +497,22 @@ class BinaryPackageData(AbstractPackageData):
summary = summary + '.'
self.summary = summary
elif k == "Installed-Size":
+ installed_size = six.ensure_text(v)
try:
- self.installed_size = int(v)
+ self.installed_size = int(installed_size)
except ValueError:
raise MissingRequiredArguments("Installed-Size is "
- "not a valid integer: %r" % v)
+ "not a valid integer: %r" % installed_size)
elif k == "Built-Using":
- self.built_using = v
+ self.built_using = six.ensure_text(v)
# Preserve the original form of Built-Using to avoid
# possible unfortunate apt behaviour. This is most easily
# done by adding it to _user_defined as well.
if self._user_defined is None:
self._user_defined = []
- self._user_defined.append([k, v])
+ self._user_defined.append([k, self.built_using])
else:
- self.set_field(k, v)
+ self.set_field(k, encoding.guess(v))
if self.source:
# We need to handle cases like "Source: myspell
diff --git a/lib/lp/soyuz/scripts/gina/runner.py b/lib/lp/soyuz/scripts/gina/runner.py
index f5056c6..c956744 100644
--- a/lib/lp/soyuz/scripts/gina/runner.py
+++ b/lib/lp/soyuz/scripts/gina/runner.py
@@ -10,6 +10,7 @@ import sys
import time
import psycopg2
+import six
from zope.component import getUtility
from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -120,7 +121,7 @@ def run_gina(options, ztm, target_section):
def attempt_source_package_import(distro, source, package_root,
importer_handler):
"""Attempt to import a source package, and handle typical errors."""
- package_name = source.get("Package", "unknown")
+ package_name = six.ensure_text(source.get("Package", "unknown"))
try:
try:
do_one_sourcepackage(
diff --git a/lib/lp/soyuz/scripts/tests/test_gina.py b/lib/lp/soyuz/scripts/tests/test_gina.py
index e36bc6a..0fbd765 100644
--- a/lib/lp/soyuz/scripts/tests/test_gina.py
+++ b/lib/lp/soyuz/scripts/tests/test_gina.py
@@ -12,6 +12,7 @@ from unittest import TestLoader
import apt_pkg
from fixtures import EnvironmentVariableFixture
+import six
from testtools.matchers import (
MatchesSetwise,
MatchesStructure,
@@ -274,10 +275,10 @@ class TestSourcePackageData(TestCaseWithFactory):
len(debian_tar_contents))))
dsc_contents = parse_tagfile(dsc_path)
- dsc_contents["Directory"] = pool_dir
- dsc_contents["Package"] = "foo"
- dsc_contents["Component"] = "main"
- dsc_contents["Section"] = "misc"
+ dsc_contents["Directory"] = six.ensure_binary(pool_dir)
+ dsc_contents["Package"] = b"foo"
+ dsc_contents["Component"] = b"main"
+ dsc_contents["Section"] = b"misc"
sp_data = SourcePackageData(**dsc_contents)
# Unpacking this in an Ubuntu context fails.
@@ -329,10 +330,10 @@ class TestSourcePackageData(TestCaseWithFactory):
len(debian_tar_contents))))
dsc_contents = parse_tagfile(dsc_path)
- dsc_contents["Directory"] = pool_dir
- dsc_contents["Package"] = "foo"
- dsc_contents["Component"] = "main"
- dsc_contents["Section"] = "misc"
+ dsc_contents["Directory"] = six.ensure_binary(pool_dir)
+ dsc_contents["Package"] = b"foo"
+ dsc_contents["Component"] = b"main"
+ dsc_contents["Section"] = b"misc"
sp_data = SourcePackageData(**dsc_contents)
unpack_tmpdir = self.makeTemporaryDirectory()
@@ -351,20 +352,20 @@ class TestSourcePackageData(TestCaseWithFactory):
def test_checksum_fields(self):
# We only need one of Files or Checksums-*.
base_dsc_contents = {
- "Package": "foo",
- "Binary": "foo",
- "Version": "1.0-1",
- "Maintainer": "Foo Bar <foo@xxxxxxxxxxxxx>",
- "Section": "misc",
- "Architecture": "all",
- "Directory": "pool/main/f/foo",
- "Component": "main",
+ "Package": b"foo",
+ "Binary": b"foo",
+ "Version": b"1.0-1",
+ "Maintainer": b"Foo Bar <foo@xxxxxxxxxxxxx>",
+ "Section": b"misc",
+ "Architecture": b"all",
+ "Directory": b"pool/main/f/foo",
+ "Component": b"main",
}
for field in (
"Files", "Checksums-Sha1", "Checksums-Sha256",
"Checksums-Sha512"):
dsc_contents = dict(base_dsc_contents)
- dsc_contents[field] = "xxx 000 foo_1.0-1.dsc"
+ dsc_contents[field] = b"xxx 000 foo_1.0-1.dsc"
sp_data = SourcePackageData(**dsc_contents)
self.assertEqual(["foo_1.0-1.dsc"], sp_data.files)
self.assertRaises(
@@ -382,18 +383,18 @@ class TestSourcePackageHandler(TestCaseWithFactory):
series.distribution.name, archive_root,
PackagePublishingPocket.RELEASE, None)
dsc_contents = {
- "Format": "3.0 (quilt)",
- "Source": "foo",
- "Binary": "foo",
- "Architecture": "all arm64",
- "Version": "1.0-1",
- "Maintainer": "Foo Bar <foo@xxxxxxxxxxxxx>",
- "Files": "xxx 000 foo_1.0-1.dsc",
- "Build-Indep-Architecture": "amd64",
- "Directory": "pool/main/f/foo",
- "Package": "foo",
- "Component": "main",
- "Section": "misc",
+ "Format": b"3.0 (quilt)",
+ "Source": b"foo",
+ "Binary": b"foo",
+ "Architecture": b"all arm64",
+ "Version": b"1.0-1",
+ "Maintainer": b"Foo Bar <foo@xxxxxxxxxxxxx>",
+ "Files": b"xxx 000 foo_1.0-1.dsc",
+ "Build-Indep-Architecture": b"amd64",
+ "Directory": b"pool/main/f/foo",
+ "Package": b"foo",
+ "Component": b"main",
+ "Section": b"misc",
}
sp_data = SourcePackageData(**dsc_contents)
self.assertEqual(
@@ -427,9 +428,10 @@ class TestSourcePackagePublisher(TestCaseWithFactory):
publisher = SourcePackagePublisher(series, pocket, None)
publisher.publish(spr, SourcePackageData(
- component='main', section=section.name, version='1.0',
- maintainer=maintainer.preferredemail, architecture='all',
- files='foo.py', binaries='foo.py'))
+ component=b'main', section=section.name.encode('ASCII'),
+ version=b'1.0',
+ maintainer=maintainer.preferredemail.email.encode('ASCII'),
+ architecture=b'all', files=b'foo.py', binaries=b'foo.py'))
[spph] = series.main_archive.getPublishedSources()
self.assertEqual(PackagePublishingStatus.PUBLISHED, spph.status)
@@ -442,21 +444,21 @@ class TestBinaryPackageData(TestCaseWithFactory):
def test_checksum_fields(self):
# We only need one of MD5sum or SHA*.
base_deb_contents = {
- "Package": "foo",
- "Installed-Size": "0",
- "Maintainer": "Foo Bar <foo@xxxxxxxxxxxxx>",
- "Section": "misc",
- "Architecture": "all",
- "Version": "1.0-1",
- "Filename": "pool/main/f/foo/foo_1.0-1_all.deb",
- "Component": "main",
- "Size": "0",
- "Description": "",
- "Priority": "extra",
+ "Package": b"foo",
+ "Installed-Size": b"0",
+ "Maintainer": b"Foo Bar <foo@xxxxxxxxxxxxx>",
+ "Section": b"misc",
+ "Architecture": b"all",
+ "Version": b"1.0-1",
+ "Filename": b"pool/main/f/foo/foo_1.0-1_all.deb",
+ "Component": b"main",
+ "Size": b"0",
+ "Description": b"",
+ "Priority": b"extra",
}
for field in ("MD5sum", "SHA1", "SHA256", "SHA512"):
deb_contents = dict(base_deb_contents)
- deb_contents[field] = "0"
+ deb_contents[field] = b"0"
BinaryPackageData(**deb_contents)
self.assertRaises(
MissingRequiredArguments, BinaryPackageData, **base_deb_contents)
@@ -477,21 +479,21 @@ class TestBinaryPackageHandler(TestCaseWithFactory):
spr = self.factory.makeSourcePackageRelease(
distroseries=das.distroseries)
deb_contents = {
- "Package": "foo",
- "Installed-Size": "0",
- "Maintainer": "Foo Bar <foo@xxxxxxxxxxxxx>",
- "Section": "misc",
- "Architecture": "amd64",
- "Version": "1.0-1",
- "Filename": "pool/main/f/foo/foo_1.0-1_amd64.deb",
- "Component": "main",
- "Size": "0",
- "MD5sum": "0" * 32,
- "Description": "",
- "Summary": "",
- "Priority": "extra",
- "Python-Version": "2.7",
- "Built-Using": "nonexistent (= 0.1)",
+ "Package": b"foo",
+ "Installed-Size": b"0",
+ "Maintainer": b"Foo Bar <foo@xxxxxxxxxxxxx>",
+ "Section": b"misc",
+ "Architecture": b"amd64",
+ "Version": b"1.0-1",
+ "Filename": b"pool/main/f/foo/foo_1.0-1_amd64.deb",
+ "Component": b"main",
+ "Size": b"0",
+ "MD5sum": b"0" * 32,
+ "Description": b"",
+ "Summary": b"",
+ "Priority": b"extra",
+ "Python-Version": b"2.7",
+ "Built-Using": b"nonexistent (= 0.1)",
}
bp_data = BinaryPackageData(**deb_contents)
self.assertContentEqual(
@@ -529,20 +531,20 @@ class TestBinaryPackageHandler(TestCaseWithFactory):
built_using_relationship = "%s (= %s)" % (
built_using_spr.name, built_using_spr.version)
deb_contents = {
- "Package": "foo",
- "Installed-Size": "0",
- "Maintainer": "Foo Bar <foo@xxxxxxxxxxxxx>",
- "Section": "misc",
- "Architecture": "amd64",
- "Version": "1.0-1",
- "Filename": "pool/main/f/foo/foo_1.0-1_amd64.deb",
- "Component": "main",
- "Size": "0",
- "MD5sum": "0" * 32,
- "Description": "",
- "Summary": "",
- "Priority": "extra",
- "Built-Using": built_using_relationship,
+ "Package": b"foo",
+ "Installed-Size": b"0",
+ "Maintainer": b"Foo Bar <foo@xxxxxxxxxxxxx>",
+ "Section": b"misc",
+ "Architecture": b"amd64",
+ "Version": b"1.0-1",
+ "Filename": b"pool/main/f/foo/foo_1.0-1_amd64.deb",
+ "Component": b"main",
+ "Size": b"0",
+ "MD5sum": b"0" * 32,
+ "Description": b"",
+ "Summary": b"",
+ "Priority": b"extra",
+ "Built-Using": built_using_relationship.encode("ASCII"),
}
bp_data = BinaryPackageData(**deb_contents)
self.assertContentEqual(
@@ -579,11 +581,13 @@ class TestBinaryPackagePublisher(TestCaseWithFactory):
publisher = BinaryPackagePublisher(series, pocket, None)
publisher.publish(bpr, BinaryPackageData(
- component='main', section=section.name, version='1.0',
- maintainer=maintainer.preferredemail, architecture='all',
- files='foo.py', binaries='foo.py', size=128, installed_size=1024,
- md5sum='e83b5dd68079d727a494a469d40dc8db', description='test',
- summary='Test!'))
+ component=b'main', section=section.name.encode('ASCII'),
+ version=b'1.0',
+ maintainer=maintainer.preferredemail.email.encode('ASCII'),
+ architecture=b'all', files=b'foo.py', binaries=b'foo.py',
+ size=128, installed_size=1024,
+ md5sum=b'e83b5dd68079d727a494a469d40dc8db', description=b'test',
+ summary=b'Test!'))
[bpph] = series.main_archive.getAllPublishedBinaries()
self.assertEqual(PackagePublishingStatus.PUBLISHED, bpph.status)