From: Joerg Jaspert Date: Wed, 28 Oct 2009 13:58:19 +0000 (+0100) Subject: Merge branch 'merge' X-Git-Url: https://git.decadent.org.uk/gitweb/?a=commitdiff_plain;h=05c002afb12f077d753234de45753062fa54ce02;hp=83f868120d67c62349c628ee154885508bedc2b0;p=dak.git Merge branch 'merge' * merge: Port check_dsc_files to use get_format_from_string. Make build_file_list to use get_format_from_string and friends. Add get_format_from_string utility method Attach validate_format(...) to each SourceFormat that can reject formats. Split out parse_format to module-level and test it explicitly. Split parsing of "Format:" string and validation of it. Compare None with object identity, not equality "Format: 0.0" is now invalid Add regression tests for parse_format. Move "Format:" field parsing into srcformats.py --- diff --git a/daklib/srcformats.py b/daklib/srcformats.py index 0a74c192..ade3c453 100644 --- a/daklib/srcformats.py +++ b/daklib/srcformats.py @@ -1,7 +1,53 @@ import re +from regexes import re_verwithext +from dak_exceptions import UnknownFormatError + srcformats = [] +def get_format_from_string(txt): + """ + Returns the SourceFormat class that corresponds to the specified .changes + Format value. If the string does not match any class, UnknownFormatError + is raised. + """ + + for format in srcformats: + if format.re_format.match(txt): + return format + + raise UnknownFormatError, "Unknown format %r" % txt + +def parse_format(txt): + """ + Parse a .changes Format string into a tuple representation for easy + comparison. + + >>> parse_format('1.0') + (1, 0) + >>> parse_format('8.4 (hardy)') + (8, 4, 'hardy') + + If the format doesn't match these forms, raises UnknownFormatError. + """ + + format = re_verwithext.search(txt) + + if format is None: + raise UnknownFormatError, txt + + format = format.groups() + + if format[1] is None: + format = int(float(format[0])), 0, format[2] + else: + format = int(format[0]), int(format[1]), format[2] + + if format[2] is None: + format = format[:2] + + return format + class SourceFormat(type): def __new__(cls, name, bases, attrs): klass = super(SourceFormat, cls).__new__(cls, name, bases, attrs) @@ -24,6 +70,15 @@ class SourceFormat(type): if has[key]: yield "contains source files not allowed in format %s" % cls.name + @classmethod + def validate_format(cls, format, is_a_dsc=False, field='files'): + """ + Raises UnknownFormatError if the specified format tuple is not valid for + this format (for example, the format (1, 0) is not valid for the + "3.0 (quilt)" format). Return value is undefined in all other cases. + """ + pass + class FormatOne(SourceFormat): __metaclass__ = SourceFormat @@ -46,6 +101,19 @@ class FormatOne(SourceFormat): for msg in super(FormatOne, cls).reject_msgs(has): yield msg + @classmethod + def validate_format(cls, format, is_a_dsc=False, field='files'): + msg = "Invalid format %s definition: %r" % (cls.name, format) + + if is_a_dsc: + if format != (1, 0): + raise UnknownFormatError, msg + else: + if (format < (1,5) or format > (1,8)): + raise UnknownFormatError, msg + if field != "files" and format < (1,8): + raise UnknownFormatError, msg + class FormatThree(SourceFormat): __metaclass__ = SourceFormat @@ -55,6 +123,12 @@ class FormatThree(SourceFormat): requires = ('native_tar',) disallowed = ('orig_tar', 'debian_diff', 'debian_tar', 'more_orig_tar') + @classmethod + def validate_format(cls, format, **kwargs): + if format != (3, 0, 'native'): + raise UnknownFormatError, "Invalid format %s definition: %r" % \ + (cls.name, format) + class FormatThreeQuilt(SourceFormat): __metaclass__ = SourceFormat @@ -63,3 +137,9 @@ class FormatThreeQuilt(SourceFormat): requires = ('orig_tar', 'debian_tar') disallowed = ('debian_diff', 'native_tar') + + @classmethod + def validate_format(cls, format, **kwargs): + if format != (3, 0, 'quilt'): + raise UnknownFormatError, "Invalid format %s definition: %r" % \ + (cls.name, format) diff --git a/daklib/utils.py b/daklib/utils.py index 788bcd41..2b243b85 100755 --- a/daklib/utils.py +++ b/daklib/utils.py @@ -44,11 +44,10 @@ from dbconn import DBConn, get_architecture, get_component, get_suite from dak_exceptions import * from textutils import fix_maintainer from regexes import re_html_escaping, html_escaping, re_single_line_field, \ - re_multi_line_field, re_srchasver, re_verwithext, \ - re_taint_free, re_gpg_uid, re_re_mark, \ - re_whitespace_comment, re_issource + re_multi_line_field, re_srchasver, re_taint_free, \ + re_gpg_uid, re_re_mark, re_whitespace_comment, re_issource -from srcformats import srcformats +from srcformats import get_format_from_string from collections import defaultdict ################################################################################ @@ -417,12 +416,15 @@ def check_dsc_files(dsc_filename, dsc=None, dsc_files=None): rejmsg.append("%s: lists multiple %s" % (dsc_filename, file_type)) # Source format specific tests - for format in srcformats: - if format.re_format.match(dsc['format']): - rejmsg.extend([ - '%s: %s' % (dsc_filename, x) for x in format.reject_msgs(has) - ]) - break + try: + format = get_format_from_string(dsc['format']) + rejmsg.extend([ + '%s: %s' % (dsc_filename, x) for x in format.reject_msgs(has) + ]) + + except UnknownFormatError: + # Not an error here for now + pass return rejmsg @@ -524,30 +526,9 @@ def build_file_list(changes, is_a_dsc=0, field="files", hashname="md5sum"): if not changes.has_key(field): raise NoFilesFieldError - # Make sure we recognise the format of the Files: field - format = re_verwithext.search(changes.get("format", "0.0")) - if not format: - raise UnknownFormatError, "%s" % (changes.get("format","0.0")) - - format = format.groups() - if format[1] == None: - format = int(float(format[0])), 0, format[2] - else: - format = int(format[0]), int(format[1]), format[2] - if format[2] == None: - format = format[:2] - - if is_a_dsc: - # format = (0,0) are missing format headers of which we still - # have some in the archive. - if format != (1,0) and format != (0,0) and \ - format != (3,0,"quilt") and format != (3,0,"native"): - raise UnknownFormatError, "%s" % (changes.get("format","0.0")) - else: - if (format < (1,5) or format > (1,8)): - raise UnknownFormatError, "%s" % (changes.get("format","0.0")) - if field != "files" and format < (1,8): - raise UnknownFormatError, "%s" % (changes.get("format","0.0")) + # Get SourceFormat object for this Format and validate it + format = get_format_from_string(changes.get['format']) + format.validate_format(is_a_dsc=is_a_dsc, field=field) includes_section = (not is_a_dsc) and field == "files" diff --git a/tests/test_srcformats.py b/tests/test_srcformats.py index 9fec4a87..f6d7215f 100755 --- a/tests/test_srcformats.py +++ b/tests/test_srcformats.py @@ -8,6 +8,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from collections import defaultdict from daklib import srcformats +from daklib.dak_exceptions import UnknownFormatError class SourceFormatTestCase(unittest.TestCase): def get_rejects(self, has_vars): @@ -102,5 +103,110 @@ class FormatTreeQuiltTestCase(SourceFormatTestCase): 'native_tar': 1, }) +## + +class ParseFormatTestCase(unittest.TestCase): + def assertParse(self, format, expected): + self.assertEqual(srcformats.parse_format(format), expected) + + def assertParseFail(self, format): + self.assertRaises( + UnknownFormatError, + lambda: srcformats.parse_format(format) + ) + + def testParse(self): + self.assertParse('1.0', (1, 0)) + + def testEmpty(self): + self.assertParseFail('') + self.assertParseFail(' ') + self.assertParseFail(' ') + + def textText(self): + self.assertParse('1.2 (three)', (1, 2, 'three')) + self.assertParseFail('0.0 ()') + +class ValidateFormatTestCase(unittest.TestCase): + def assertValid(self, format, **kwargs): + kwargs['is_a_dsc'] = kwargs.get('is_a_dsc', True) + self.fmt.validate_format(format, **kwargs) + + def assertInvalid(self, *args, **kwargs): + self.assertRaises( + UnknownFormatError, + lambda: self.assertValid(*args, **kwargs), + ) + +class ValidateFormatOneTestCase(ValidateFormatTestCase): + fmt = srcformats.FormatOne + + def testValid(self): + self.assertValid((1, 0)) + + def testInvalid(self): + self.assertInvalid((0, 1)) + self.assertInvalid((3, 0, 'quilt')) + + ## + + def testBinary(self): + self.assertValid((1, 5), is_a_dsc=False) + self.assertInvalid((1, 0), is_a_dsc=False) + + def testRange(self): + self.assertInvalid((1, 3), is_a_dsc=False) + self.assertValid((1, 5), is_a_dsc=False) + self.assertValid((1, 8), is_a_dsc=False) + self.assertInvalid((1, 9), is_a_dsc=False) + + def testFilesField(self): + self.assertInvalid((1, 7), is_a_dsc=False, field='notfiles') + self.assertValid((1, 8), is_a_dsc=False, field='notfiles') + +class ValidateFormatThreeTestCase(ValidateFormatTestCase): + fmt = srcformats.FormatThree + + def testValid(self): + self.assertValid((3, 0, 'native')) + + def testInvalid(self): + self.assertInvalid((1, 0)) + self.assertInvalid((0, 0)) + self.assertInvalid((3, 0, 'quilt')) + +class ValidateFormatThreeQuiltTestCase(ValidateFormatTestCase): + fmt = srcformats.FormatThreeQuilt + + def testValid(self): + self.assertValid((3, 0, 'quilt')) + + def testInvalid(self): + self.assertInvalid((1, 0)) + self.assertInvalid((0, 0)) + self.assertInvalid((3, 0, 'native')) + +class FormatFromStringTestCase(unittest.TestCase): + def assertFormat(self, txt, klass): + self.assertEqual(srcformats.get_format_from_string(txt), klass) + + def assertInvalid(self, txt): + self.assertRaises( + UnknownFormatError, + lambda: srcformats.get_format_from_string(txt), + ) + + def testFormats(self): + self.assertFormat('1.0', srcformats.FormatOne) + self.assertFormat('3.0 (native)', srcformats.FormatThree) + self.assertFormat('3.0 (quilt)', srcformats.FormatThreeQuilt) + + def testInvalidFormats(self): + self.assertInvalid('') + self.assertInvalid('.') + self.assertInvalid('3.0 (cvs)') + self.assertInvalid(' 1.0 ') + self.assertInvalid('8.4 (hardy)') + if __name__ == '__main__': unittest.main()