1#!/usr/bin/env python
2# ***** BEGIN LICENSE BLOCK *****
3# This Source Code Form is subject to the terms of the Mozilla Public
4# License, v. 2.0. If a copy of the MPL was not distributed with this file,
5# You can obtain one at http://mozilla.org/MPL/2.0/.
6# ***** END LICENSE BLOCK *****
7"""Generic error lists.
8
9Error lists are used to parse output in mozharness.base.log.OutputParser.
10
11Each line of output is matched against each substring or regular expression
12in the error list.  On a match, we determine the 'level' of that line,
13whether IGNORE, DEBUG, INFO, WARNING, ERROR, CRITICAL, or FATAL.
14
15TODO: Context lines (requires work on the OutputParser side)
16
17TODO: We could also create classes that generate these, but with the
18appropriate level (please don't die on any errors; please die on any
19warning; etc.) or platform or language or whatever.
20"""
21
22from __future__ import absolute_import
23import re
24
25from mozharness.base.log import CRITICAL, DEBUG, ERROR, WARNING
26
27
28# Exceptions
29class VCSException(Exception):
30    pass
31
32
33# ErrorLists {{{1
34BaseErrorList = [{"substr": r"""command not found""", "level": ERROR}]
35
36HgErrorList = BaseErrorList + [
37    {
38        "regex": re.compile(r"""^abort:"""),
39        "level": ERROR,
40        "explanation": "Automation Error: hg not responding",
41    },
42    {
43        "substr": r"""unknown exception encountered""",
44        "level": ERROR,
45        "explanation": "Automation Error: python exception in hg",
46    },
47    {
48        "substr": r"""failed to import extension""",
49        "level": WARNING,
50        "explanation": "Automation Error: hg extension missing",
51    },
52]
53
54GitErrorList = BaseErrorList + [
55    {"substr": r"""Permission denied (publickey).""", "level": ERROR},
56    {"substr": r"""fatal: The remote end hung up unexpectedly""", "level": ERROR},
57    {"substr": r"""does not appear to be a git repository""", "level": ERROR},
58    {"substr": r"""error: src refspec""", "level": ERROR},
59    {"substr": r"""invalid author/committer line -""", "level": ERROR},
60    {"substr": r"""remote: fatal: Error in object""", "level": ERROR},
61    {
62        "substr": r"""fatal: sha1 file '<stdout>' write error: Broken pipe""",
63        "level": ERROR,
64    },
65    {"substr": r"""error: failed to push some refs to """, "level": ERROR},
66    {"substr": r"""remote: error: denying non-fast-forward """, "level": ERROR},
67    {"substr": r"""! [remote rejected] """, "level": ERROR},
68    {"regex": re.compile(r"""remote:.*No such file or directory"""), "level": ERROR},
69]
70
71PythonErrorList = BaseErrorList + [
72    {"regex": re.compile(r"""Warning:.*Error: """), "level": WARNING},
73    {"regex": re.compile(r"""package.*> Error:"""), "level": ERROR},
74    {"substr": r"""Traceback (most recent call last)""", "level": ERROR},
75    {"substr": r"""SyntaxError: """, "level": ERROR},
76    {"substr": r"""TypeError: """, "level": ERROR},
77    {"substr": r"""NameError: """, "level": ERROR},
78    {"substr": r"""ZeroDivisionError: """, "level": ERROR},
79    {"regex": re.compile(r"""raise \w*Exception: """), "level": CRITICAL},
80    {"regex": re.compile(r"""raise \w*Error: """), "level": CRITICAL},
81]
82
83VirtualenvErrorList = [
84    {"substr": r"""not found or a compiler error:""", "level": WARNING},
85    {"regex": re.compile("""\d+: error: """), "level": ERROR},
86    {"regex": re.compile("""\d+: warning: """), "level": WARNING},
87    {
88        "regex": re.compile(r"""Downloading .* \(.*\): *([0-9]+%)? *[0-9\.]+[kmKM]b"""),
89        "level": DEBUG,
90    },
91] + PythonErrorList
92
93RustErrorList = [
94    {"regex": re.compile(r"""error\[E\d+\]:"""), "level": ERROR},
95    {"substr": r"""error: Could not compile""", "level": ERROR},
96    {"substr": r"""error: aborting due to previous error""", "level": ERROR},
97]
98
99# We may need to have various MakefileErrorLists for differing amounts of
100# warning-ignoring-ness.
101MakefileErrorList = (
102    BaseErrorList
103    + PythonErrorList
104    + RustErrorList
105    + [
106        {"substr": r"""No rule to make target """, "level": ERROR},
107        {"regex": re.compile(r"""akefile.*was not found\."""), "level": ERROR},
108        {"regex": re.compile(r"""Stop\.$"""), "level": ERROR},
109        {"regex": re.compile(r""":\d+: error:"""), "level": ERROR},
110        {
111            "regex": re.compile(r"""make\[\d+\]: \*\*\* \[.*\] Error \d+"""),
112            "level": ERROR,
113        },
114        {"regex": re.compile(r""":\d+: warning:"""), "level": WARNING},
115        {"regex": re.compile(r"""make(?:\[\d+\])?: \*\*\*/"""), "level": ERROR},
116        {"substr": r"""Warning: """, "level": WARNING},
117    ]
118)
119
120TarErrorList = BaseErrorList + [
121    {"substr": r"""(stdin) is not a bzip2 file.""", "level": ERROR},
122    {"regex": re.compile(r"""Child returned status [1-9]"""), "level": ERROR},
123    {"substr": r"""Error exit delayed from previous errors""", "level": ERROR},
124    {"substr": r"""stdin: unexpected end of file""", "level": ERROR},
125    {"substr": r"""stdin: not in gzip format""", "level": ERROR},
126    {"substr": r"""Cannot exec: No such file or directory""", "level": ERROR},
127    {"substr": r""": Error is not recoverable: exiting now""", "level": ERROR},
128]
129
130ZipErrorList = BaseErrorList + [
131    {
132        "substr": r"""zip warning:""",
133        "level": WARNING,
134    },
135    {
136        "substr": r"""zip error:""",
137        "level": ERROR,
138    },
139    {
140        "substr": r"""Cannot open file: it does not appear to be a valid archive""",
141        "level": ERROR,
142    },
143]
144
145ZipalignErrorList = BaseErrorList + [
146    {
147        "regex": re.compile(r"""Unable to open .* as a zip archive"""),
148        "level": ERROR,
149    },
150    {
151        "regex": re.compile(r"""Output file .* exists"""),
152        "level": ERROR,
153    },
154    {
155        "substr": r"""Input and output can't be the same file""",
156        "level": ERROR,
157    },
158]
159
160
161# __main__ {{{1
162if __name__ == "__main__":
163    """TODO: unit tests."""
164    pass
165