diff options
| -rw-r--r-- | crocoite/test_tools.py | 28 | ||||
| -rw-r--r-- | crocoite/tools.py | 71 | ||||
| -rw-r--r-- | setup.py | 1 | 
3 files changed, 99 insertions, 1 deletions
| diff --git a/crocoite/test_tools.py b/crocoite/test_tools.py index 947d020..c320ad9 100644 --- a/crocoite/test_tools.py +++ b/crocoite/test_tools.py @@ -25,8 +25,9 @@ import pytest  from warcio.archiveiterator import ArchiveIterator  from warcio.warcwriter import WARCWriter  from warcio.statusandheaders import StatusAndHeaders +from pkg_resources import parse_version -from .tools import mergeWarc +from .tools import mergeWarc, Errata, FixableErrata  from .util import packageUrl  @pytest.fixture @@ -195,3 +196,28 @@ def test_resp_revisit_other_url(writer):      output.seek(0)      recordsEqual (makeGolden (writer, records), ArchiveIterator (output)) +def test_errata_contains(): +    """ Test version matching """ +    e = Errata('some-uuid', 'description', ['a<1.0']) +    assert {'a': parse_version('0.1')} in e +    assert {'a': parse_version('1.0')} not in e +    assert {'b': parse_version('1.0')} not in e + +    e = Errata('some-uuid', 'description', ['a<1.0,>0.1']) +    assert {'a': parse_version('0.1')} not in e +    assert {'a': parse_version('0.2')} in e +    assert {'a': parse_version('1.0')} not in e + +    # a AND b +    e = Errata('some-uuid', 'description', ['a<1.0', 'b>1.0']) +    assert {'a': parse_version('0.1')} not in e +    assert {'b': parse_version('1.1')} not in e +    assert {'a': parse_version('0.1'), 'b': parse_version('1.1')} in e + +def test_errata_fixable (): +    e = Errata('some-uuid', 'description', ['a<1.0', 'b>1.0']) +    assert not e.fixable + +    e = FixableErrata('some-uuid', 'description', ['a<1.0', 'b>1.0']) +    assert e.fixable + diff --git a/crocoite/tools.py b/crocoite/tools.py index e2dc6a7..84c6f44 100644 --- a/crocoite/tools.py +++ b/crocoite/tools.py @@ -26,6 +26,7 @@ import shutil, sys, os, logging, argparse, json  from io import BytesIO  from warcio.archiveiterator import ArchiveIterator  from warcio.warcwriter import WARCWriter +from pkg_resources import parse_version, parse_requirements  from .util import packageUrl, getSoftwareInfo  def mergeWarc (files, output): @@ -122,3 +123,73 @@ def extractScreenshot ():              else:                  print ('not overwriting {}'.format (outpath)) +class Errata: +    __slots__ = ('uuid', 'description', 'affects') + +    def __init__ (self, uuid, description, affects): +        self.uuid = uuid +        self.description = description +        # slightly abusing setuptool’s version parsing/matching here +        self.affects = list (parse_requirements(affects)) + +    def __contains__ (self, pkg): +        """ +        Return True if the versions in pkg are affected by this errata + +        pkg must be a mapping from project_name to version +        """ +        matchedAll = [] +        for a in self.affects: +            haveVersion = pkg.get (a.project_name, None) +            matchedAll.append (haveVersion is not None and haveVersion in a) +        return all (matchedAll) + +    def __repr__ (self): +        return '{}({!r}, {!r}, {!r})'.format (self.__class__.__name__, +                self.uuid, self.description, self.affects) + +    @property +    def fixable (self): +        return getattr (self, 'applyFix', None) is not None + +    def toDict (self): +        return {'uuid': self.uuid, +                'description': self.description, +                'affects': list (map (str, self.affects)), +                'fixable': self.fixable} + +class FixableErrata(Errata): +    def applyFix (self, records): +        raise NotImplementedError () # pragma: no cover + +bugs = [ +    Errata (uuid='34a176b3-ad3d-430f-a082-68087f304572', +            description='Generated by version < 1.0. No erratas are supported for this version.', +            affects=['crocoite<1.0'], +            ), +    ] + +def makeReport (fd): +    for record in ArchiveIterator (fd): +        if record.rec_type == 'warcinfo': +            try: +                data = json.load (record.raw_stream) +                haveVersions = dict ([(pkg['projectName'], parse_version(pkg['version'])) for pkg in data['software']['self']]) +                yield from filter (lambda b: haveVersions in b, bugs) +            except json.decoder.JSONDecodeError: +                pass + +def errata (): +    parser = argparse.ArgumentParser(description='Show/fix erratas for WARCs generated by {}.'.format (__package__)) +    parser.add_argument('input', type=argparse.FileType ('rb'), help='Input WARC') + +    args = parser.parse_args() + +    hasErrata = False +    for item in makeReport (args.input): +        json.dump (item.toDict (), sys.stdout) +        sys.stdout.write ('\n') +        sys.stdout.flush () +        hasErrata = True +    return int (hasErrata) + @@ -26,6 +26,7 @@ setup(              'crocoite-irc-dashboard = crocoite.cli:dashboard',              'crocoite-merge-warc = crocoite.tools:mergeWarcCli',              'crocoite-extract-screenshot = crocoite.tools:extractScreenshot', +            'crocoite-errata = crocoite.tools:errata',              ],      },      package_data={ | 
