diff options
Diffstat (limited to 'crocoite/tools.py')
-rw-r--r-- | crocoite/tools.py | 71 |
1 files changed, 71 insertions, 0 deletions
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) + |