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
This commit is contained in:
Ian Wienand
2014-12-08 15:16:44 +11:00
parent e3238b83ab
commit 16913c2e37
3 changed files with 97 additions and 20 deletions

View File

@@ -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<indent>[ \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())

View File

@@ -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("")

View File

@@ -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):