summaryrefslogtreecommitdiff
path: root/crocoite
diff options
context:
space:
mode:
Diffstat (limited to 'crocoite')
-rw-r--r--crocoite/test_tools.py28
-rw-r--r--crocoite/tools.py71
2 files changed, 98 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)
+