summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Weimer <fw@deneb.enyo.de>2010-05-07 21:03:10 +0000
committerFlorian Weimer <fw@deneb.enyo.de>2010-05-07 21:03:10 +0000
commit8bf3653393970280ba1a0edd4fd4647ae80630c6 (patch)
tree87415b4d608816b5ac3fe3fe00d3c1d643067d6c
parenta18d05666236a74c154c14b14e325becd90d9108 (diff)
sectracker.diagnostics: introduce separate diagnostics module
git-svn-id: svn+ssh://svn.debian.org/svn/secure-testing@14628 e39458fd-73e7-0310-bf30-c45bca0a0e42
-rw-r--r--lib/python/parsers.py102
-rw-r--r--lib/python/sectracker/__init__.py0
-rw-r--r--lib/python/sectracker/diagnostics.py80
3 files changed, 127 insertions, 55 deletions
diff --git a/lib/python/parsers.py b/lib/python/parsers.py
index 90cdda0541..f6a691e45c 100644
--- a/lib/python/parsers.py
+++ b/lib/python/parsers.py
@@ -23,6 +23,8 @@ import regexpcase
import xcollections
import xpickle
+import sectracker.diagnostics
+
FORMAT = "1"
@xpickle.loader("BINARY" + FORMAT)
@@ -67,12 +69,6 @@ def _sortedtuple(seq):
l.sort()
return tuple(l)
-Message = xcollections.namedtuple("Message", "file line level message")
-def addmessage(messages, file, line, level, msg):
- if level not in ("error", "warning"):
- raise ValueError("invalid message level: " + repr(level))
- messages.append(Message(file, line, level, msg))
-
FlagAnnotation = xcollections.namedtuple("FlagAnnotation", "line type")
StringAnnotation = xcollections.namedtuple("StringAnnotation",
"line type description")
@@ -86,40 +82,36 @@ def _annotationdispatcher():
# Parser for inner annotations, like (bug #1345; low)
urgencies=set("unimportant low medium high".split())
@regexpcase.rule('(bug filed|%s)' % '|'.join(urgencies))
- def innerflag(groups, file, line, messages, flags, bugs):
+ def innerflag(groups, diag, flags, bugs):
f = groups[0]
if f in flags:
- addmessage(messages, file, line, "error",
- "duplicate flag: " + repr(f))
+ diag.error("duplicate flag: " + repr(f))
else:
flags.add(f)
@regexpcase.rule(r'bug #(\d+)')
- def innerbug(groups, file, line, messages, flags, bugs):
+ def innerbug(groups, diag, flags, bugs):
no = int(groups[0])
if no in bugs:
- messages.add(file, line, "error",
- "duplicate bug number: " + groups[0])
+ diag.error("duplicate bug number: " + groups[0])
else:
bugs.add(no)
- def innerdefault(text, file, line, messages, flags, bugs):
- addmessage(messages, file, line, "error",
- "invalid inner annotation: " + repr(text))
+ def innerdefault(text, diag, flags, bugs):
+ diag.error("invalid inner annotation: " + repr(text))
innerdispatch = regexpcase.RegexpCase((innerflag, innerbug),
default=innerdefault)
- def parseinner(file, line, messages, inner):
+ def parseinner(diag, inner):
if not inner:
return (None, (), False)
flags = set()
bugs = set()
for innerann in inner.split(";"):
- innerdispatch(innerann.strip(), file, line, messages, flags, bugs)
+ innerdispatch(innerann.strip(), diag, flags, bugs)
urgency = urgencies.intersection(flags)
if urgency:
if len(urgency) > 1:
- addmessage(messages, file, line, "error",
- "multiple urgencies: " + ", ".join(urgency))
+ diag.error("multiple urgencies: " + ", ".join(urgency))
else:
urgency = urgency.pop()
else:
@@ -127,8 +119,7 @@ def _annotationdispatcher():
bug_filed = "bug filed" in flags
if bugs and bug_filed:
- addmessage(messages, file, line, "error",
- "'bug filed' and bug numbers listed")
+ diag.error("'bug filed' and bug numbers listed")
bug_filed = False
return (urgency, _sortedtuple(bugs), bug_filed)
@@ -137,58 +128,56 @@ def _annotationdispatcher():
@regexpcase.rule(r'(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)\s*'
+ r'(?:\s([A-Za-z0-9:.+~-]+)\s*)?(?:\s\((.*)\))?')
- def package_version(groups, file, line, messages, anns):
+ def package_version(groups, diag, anns):
release, package, version, inner = groups
- inner = parseinner(file, line, messages, inner)
+ inner = parseinner(diag, inner)
if version is None:
kind = "unfixed"
else:
kind = "fixed"
anns.append(PackageAnnotation(
- *((line, "package", release, package, kind, version, None)
- + inner)))
+ *((diag.line(), "package", release, package, kind,
+ version, None) + inner)))
pseudo_freetext = "no-dsa not-affected end-of-life".split()
pseudo_struct = set("unfixed removed itp undetermined".split())
@regexpcase.rule(r'(?:\[([a-z]+)\]\s)?-\s([A-Za-z0-9:.+-]+)'
+ r'\s+<([a-z-]+)>\s*(?:\s\((.*)\))?')
- def package_pseudo(groups, file, line, messages, anns):
+ def package_pseudo(groups, diag, anns):
release, package, version, inner = groups
if version in pseudo_freetext:
anns.append(PackageAnnotation(
- line, "package", release, package, version, None, inner,
- None, (), False))
+ diag.line(), "package", release, package, version,
+ None, inner, None, (), False))
elif version in pseudo_struct:
- inner = parseinner(file, line, messages, inner)
+ inner = parseinner(diag, inner)
if version == "itp" and not inner[1]:
- addmessage(messages, file, line, "error",
- "<itp> needs Debian bug reference")
+ diag.error("<itp> needs Debian bug reference")
anns.append(PackageAnnotation(
- *((line, "package", release, package, version, None, None)
- + inner)))
+ *((diag.line(), "package", release, package, version,
+ None, None) + inner)))
else:
- addmessage(messages, file, line, "error",
- "invalid pseudo-version: " + repr(version))
+ diag.error("invalid pseudo-version: " + repr(version))
@regexpcase.rule(r'\{(.*)\}')
- def xref(groups, file, line, messages, anns):
+ def xref(groups, diag, anns):
x = _sortedtuple(groups[0].strip().split())
if x:
- anns.append(XrefAnnotation(line, "xref", x))
+ anns.append(XrefAnnotation(diag.line(), "xref", x))
else:
- addmessage(messages, file, line, "error", "empty cross-reference")
+ diag.error("empty cross-reference")
return regexpcase.RegexpCase(
((r'(RESERVED|REJECTED)',
- lambda groups, file, line, messages, anns:
- anns.append(FlagAnnotation(line, groups[0]))),
+ lambda groups, diag, anns:
+ anns.append(FlagAnnotation(diag.line(), groups[0]))),
(r'(NOT-FOR-US|NOTE|TODO):\s+(\S.*)',
- lambda groups, file, line, messages, anns:
- anns.append(StringAnnotation(line, *groups))),
+ lambda groups, diag, anns:
+ anns.append(StringAnnotation(diag.line(), *groups))),
package_version, package_pseudo, xref),
prefix=r"\s+", suffix=r"\s*",
- default=lambda text, file, line, messages, anns:
- addmessage(messages, file, line, "error", "invalid annotation"))
+ default=lambda text, diag, anns:
+ diag.error("invalid annotation"))
_annotationdispatcher = _annotationdispatcher()
List = xcollections.namedtuple("List", "list messages")
@@ -209,7 +198,7 @@ def cvelist(path, f):
lineno = 0
headerlineno = None
bugs = []
- messages = []
+ diag = sectracker.diagnostics.Diagnostics()
name = desc = None
anns = []
@@ -226,37 +215,37 @@ def cvelist(path, f):
for line in f.readlines():
lineno += 1
+ diag.setlocation(path, lineno)
+
if line[:1] in " \t":
if name is None:
- addmessage(messages, path, lineno, "error", "header expected")
+ diag.error("header expected")
continue
- _annotationdispatcher(line, path, lineno, messages, anns)
+ _annotationdispatcher(line, diag, anns)
else:
emit()
headerlineno = lineno
match = _re_cve_header.match(line)
if match is None:
- addmessage(message, path, lineno, "error", "malformed header")
+ diag.error("malformed header")
name = desc = None
continue
name, desc = match.groups()
if desc:
if desc[0] == '(':
if desc[-1] <> ')':
- addmessage(message, path, lineno, "error",
- "missing ')'")
+ diag.error("error", "missing ')'")
else:
desc = desc[1:-1]
elif desc[0] == '[':
if desc[-1] <> ']':
- addmessage(message, path, lineno, "error",
- "missing ']'")
+ diag.error("missing ']'")
else:
desc = desc[1:-1]
emit()
- return List(tuple(bugs), tuple(messages))
+ return List(tuple(bugs), diag.messages())
def _test():
o = binarypackages("../../data/packages/sid__main_i386_Packages")
@@ -272,6 +261,7 @@ def _test():
for err in o.messages:
print "%s:%d: %s: %s" % (err.file, err.line, err.level, err.message)
+ Message = sectracker.diagnostics.Message
for (line, res, xmsgs) in [
(' - foo <unfixed>',
PackageAnnotation(17, "package", None, "foo", "unfixed", None,
@@ -346,8 +336,10 @@ def _test():
"invalid pseudo-version: 'garbled'"),)),
]:
anns = []
- msgs = []
- _annotationdispatcher(line, "CVE", 17, msgs, anns)
+ diag = sectracker.diagnostics.Diagnostics()
+ diag.setlocation("CVE", 17)
+ _annotationdispatcher(line, diag, anns)
+ msgs = diag.messages()
assert tuple(msgs) == xmsgs, repr(msgs)
if anns:
r = anns[0]
diff --git a/lib/python/sectracker/__init__.py b/lib/python/sectracker/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/python/sectracker/__init__.py
diff --git a/lib/python/sectracker/diagnostics.py b/lib/python/sectracker/diagnostics.py
new file mode 100644
index 0000000000..635358cf88
--- /dev/null
+++ b/lib/python/sectracker/diagnostics.py
@@ -0,0 +1,80 @@
+# sectracker.diagnostics -- keeping track of errors and warnings
+# Copyright (C) 2010 Florian Weimer <fw@deneb.enyo.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import xcollections
+
+Message = xcollections.namedtuple("Message", "file line level message")
+
+def _checkfile(file):
+ if not isinstance(file, basestring):
+ raise ValueError("file name is not a string: " + repr(file))
+ return file
+
+def _checkline(line):
+ if not isinstance(line, int):
+ raise ValueError("not a number: " + repr(line))
+ if line <= 0:
+ raise ValueError("line number must be positive: " + repr(line))
+ return line
+
+class Diagnostics:
+ def __init__(self):
+ self._messages = []
+ self._file = None
+ self._line = None
+
+ def setlocation(self, file, line=1):
+ if file is None and line is None:
+ self._file = self._line = None
+ else:
+ self._file = _checkfile(file)
+ self._line = _checkline(line)
+
+ def error(self, message, file=None, line=None):
+ self.record(file, line, "error", message)
+
+ def warning(self, message, file=None, line=None):
+ self.record(file, line, "warning", message)
+
+ def record(self, file, line, level, message):
+ if file is None:
+ file = self._file
+ if file is None:
+ raise Excpetion("location has not been set")
+ else:
+ _checkfile(file)
+ if line is None:
+ line = self._line
+ if line is None:
+ raise Excpetion("location has not been set")
+ else:
+ _checkline(line)
+ self._messages.append(Message(file, line, level, message))
+
+ def file(self):
+ if self._file is None:
+ raise Excpetion("location has not been set")
+ return self._file
+
+ def line(self):
+ if self._line is None:
+ raise Excpetion("location has not been set")
+ return self._line
+
+ def messages(self):
+ return tuple(self._messages)
+

© 2014-2024 Faster IT GmbH | imprint | privacy policy