From 16913c2e3789c2cf4e43f18265f309b775888475 Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Mon, 8 Dec 2014 15:16:44 +1100 Subject: [PATCH] Move messages into a dict Move messages into a dict. This is to enable easily saving meta-data about the tests; like if they should default themselves as warnings or errors. As an example, add "--show" that prints out all the tests. The "long_msg" component is designed so that documenation can be generated directly from the code, but is not implemented just yet. Change-Id: Ib16211ec53c8dbedf55016f3acb8e02be0b56bf6 --- bashate/bashate.py | 27 ++++++----- bashate/messages.py | 85 +++++++++++++++++++++++++++++++---- bashate/tests/test_bashate.py | 5 ++- 3 files changed, 97 insertions(+), 20 deletions(-) diff --git a/bashate/bashate.py b/bashate/bashate.py index ae4b1c3..85283cc 100644 --- a/bashate/bashate.py +++ b/bashate/bashate.py @@ -21,6 +21,8 @@ import sys from bashate import messages +MESSAGES = messages.MESSAGES + def not_continuation(line): return not re.search('\\\\$', line) @@ -38,28 +40,28 @@ def check_for_do(line, report): if re.search('for \([^\(]', line): return if not re.search(';\s*do$', line): - report.print_error((messages.E010 % operator), line) + report.print_error((MESSAGES['E010'].msg % operator), line) def check_if_then(line, report): if not_continuation(line): if re.search('^\s*(el)?if \[', line): if not re.search(';\s*then$', line): - report.print_error(messages.E011, line) + report.print_error(MESSAGES['E011'].msg, line) def check_no_trailing_whitespace(line, report): if re.search('[ \t]+$', line): - report.print_error(messages.E001, line) + report.print_error(MESSAGES['E001'].msg, line) def check_indents(line, report): m = re.search('^(?P[ \t]+)', line) if m: if re.search('\t', m.group('indent')): - report.print_error(messages.E002, line) + report.print_error(MESSAGES['E002'].msg, line) if (len(m.group('indent')) % 4) != 0: - report.print_error(messages.E003, line) + report.print_error(MESSAGES['E003'].msg, line) def check_function_decl(line, report): @@ -74,7 +76,7 @@ def check_function_decl(line, report): failed = True if failed: - report.print_error(messages.E020, line) + report.print_error(MESSAGES['E020'].msg, line) def starts_multiline(line): @@ -88,7 +90,7 @@ def end_of_multiline(line, token): def check_arithmetic(line, report): if "$[" in line: - report.print_error(messages.E041, line) + report.print_error(MESSAGES['E041'].msg, line) class BashateRun(object): @@ -160,7 +162,7 @@ class BashateRun(object): # find the end of a heredoc in the last file. if in_multiline: report.print_error( - messages.E012, + MESSAGES['E012'].msg, multiline_line, filename=prev_file, filelineno=multiline_start) @@ -170,7 +172,7 @@ class BashateRun(object): # newline if prev_file and not prev_line.endswith('\n'): report.print_error( - messages.E004, + MESSAGES['E004'].msg, prev_line, filename=prev_file, filelineno=prev_lineno) @@ -238,8 +240,13 @@ def main(): parser.add_argument('-w', '--warn', help='Rules to warn (rather than error)') parser.add_argument('-v', '--verbose', action='store_true', default=False) + parser.add_argument('-s', '--show', action='store_true', default=False) opts = parser.parse_args() + if opts.show is True: + messages.print_messages() + sys.exit(0) + files = opts.files if not files: parser.print_usage() @@ -261,8 +268,8 @@ def main(): if run.ERRORS > 0: print("%d bashate error(s) found" % run.ERRORS) return 1 - return 0 + return 0 if __name__ == "__main__": sys.exit(main()) diff --git a/bashate/messages.py b/bashate/messages.py index 00aecb2..69db474 100644 --- a/bashate/messages.py +++ b/bashate/messages.py @@ -10,15 +10,82 @@ # License for the specific language governing permissions and limitations # under the License. -E001 = "E001: Trailing Whitespace" -E002 = "E002: Tab indents" -E003 = "E003: Indent not multiple of 4" -E004 = "E004: File did not end with a newline" -E010 = "E010: Do not on same line as %s" -E011 = "E011: Then keyword is not on same line as if or elif keyword" -E012 = "E012: heredoc did not end before EOF" +class _Message: + """An individual bashate message. -E020 = "E020: Function declaration not in format ^function name {$" + This should be accessed via the MESSAGES dict keyed by msg_id, + e.g. -E041 = "E041: Arithmetic expansion using $[ is deprecated for $(('" + from bashate.messages import MESSAGES + print(MESSAGES['E123'].msg) + + :param msg_id: The unique message id (E...) + :param msg_str: The short message string, as displayed in program + output + :param long_msg: A longer more involved message, designed for + documentation + """ + def __init__(self, msg_id, msg_str, long_msg): + self.msg_id = msg_id + self.msg_str = msg_str + self.long_msg = long_msg + + @property + def msg(self): + # For historical reasons, the code relies on "id: msg" so build + # that up as .msg property for quick access. + return "%s: %s" % (self.msg_id, self.msg_str) + +_messages = { + 'E001': { + 'msg': 'Trailing Whitespace', + 'long_msg': None + }, + 'E002': { + 'msg': 'Tab indents', + 'long_msg': None + }, + 'E003': { + 'msg': 'Indent not multiple of 4', + 'long_msg': None + }, + 'E004': { + 'msg': 'File did not end with a newline', + 'long_msg': None + }, + 'E010': { + 'msg': 'Do not on same line as %s', + 'long_msg': None + }, + 'E011': { + 'msg': 'Then keyword is not on same line as if or elif keyword', + 'long_msg': None + }, + 'E012': { + 'msg': 'heredoc did not end before EOF', + 'long_msg': None + }, + 'E020': { + 'msg': 'Function declaration not in format ^function name {$', + 'long_msg': None + }, + 'E041': { + 'msg': 'Arithmetic expansion using $[ is deprecated for $((', + 'long_msg': None + }, +} + +MESSAGES = {} +for k, v in _messages.items(): + MESSAGES[k] = _Message(k, v['msg'], v['long_msg']) + + +def print_messages(): + print("\nAvailable bashate checks") + print("------------------------") + for k, v in MESSAGES.items(): + print(" %(id)s : %(string)s" % { + 'id': v.msg_id, + 'string': v.msg_str}) + print("") diff --git a/bashate/tests/test_bashate.py b/bashate/tests/test_bashate.py index f2d8b43..6e5573f 100644 --- a/bashate/tests/test_bashate.py +++ b/bashate/tests/test_bashate.py @@ -24,6 +24,9 @@ from bashate import messages from bashate.tests import base +MESSAGES = messages.MESSAGES + + class TestBashate(base.TestCase): def setUp(self): @@ -118,7 +121,7 @@ class TestBashate(base.TestCase): bashate.check_for_do(test_line, self.run) m_print_error.assert_called_once_with( - messages.E010 % 'while', test_line) + MESSAGES['E010'].msg % 'while', test_line) class TestBashateSamples(base.TestCase):