Date: Mon, 15 Oct 2012 20:19:57 +0000 (UTC) From: Chris Rees <crees@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r241598 - user/crees/rclint Message-ID: <201210152019.q9FKJvAJ064874@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: crees (ports committer) Date: Mon Oct 15 20:19:57 2012 New Revision: 241598 URL: http://svn.freebsd.org/changeset/base/241598 Log: Split into functions; code is only used once, but separating makes it easier to read Check default variable assignments and be very fussy Use \ instead of : as error delimiter Modified: user/crees/rclint/errors.en user/crees/rclint/rclint.py Modified: user/crees/rclint/errors.en ============================================================================== --- user/crees/rclint/errors.en Mon Oct 15 18:15:18 2012 (r241597) +++ user/crees/rclint/errors.en Mon Oct 15 20:19:57 2012 (r241598) @@ -1,15 +1,31 @@ -# Rigid format of this file; colon-separated tuples to define +# Rigid format of this file; backslash-separated tuples to define # error messages and explanations. # format as follows: -error_id:message:explanation -name_missing:name is set late or not at all:Directly following the sourcing of scripts must follow setting of the variable name. -name_quoted:name is quoted:Do not quote the value of name. If it has spaces, use underscores. -rc_subr_late:rc.subr sourcing late or nonexistent:The first non-comment non-blank line in any rc file must be sourcing /etc/rc.subr. -rcorder_keyword_freebsd:Do not include FreeBSD in the KEYWORD rcorder line:Historically FreeBSD scripts were marked in the KEYWORD section. This is no longer necessary. -rcorder_missing:Missing rcorder block:Following the FreeBSD RCSId keyword must be nothing but empty comment lines and an rcorder block. -rcorder_order:rcorder block in the wrong order; should be PROVIDE/REQUIRE/BEFORE/KEYWORD:See the article on RC scripting. -rcvar_incorrect:rcvar is not set correctly:rcvar must be directly set to name_enable. Do not quote, and do not use indirection; ${name}_enable is slower than example_enable. -rcvar_missing:rcvar is set late or not at all:Setting rcvar must be done straight after setting name. -rcvar_quoted:rcvar is quoted:Do not quote the value of rcvar. -rcsid:Missing FreeBSD RCSId keyword:All rc scripts must contain a line beginning # $FreeBSD$. Do not include blank lines without comment markers at the beginning (#) until the script begins. -shebang:Incorrect shebang used:All rc scripts must start with the correct shebang; #!/bin/sh. +error_id\message\explanation + +defaults_invalid\Invalid lines in defaults block.\Allowed are variable assignments (including eval statements) and comments. A blank line ends the block. +defaults_mandatory_colon\Override blanks in mandatory values (:=/:- vs =/-)\Values that must not be blank (such as _enable) should be set by default as ${var:=value}; thus disallowing blank values (man sh) +defaults_non_mandatory_colon\Do not clobber blank values for non-mandatory variables\Syntax for variables that are not mandatory is ${var=value}; including := will override var="" set in rc.conf (man sh) +defaults_old_style\Prefer condensed version for setting default values of variables\When setting the default value for a variable, it is much less verbose and clearer to use the : ${variable=var} notation, as well as it being obvious that the source and destination variable are the same +defaults_value_quoted\Do not quote values set by default\With the syntax ${variable=value}, value can even contain spaces and does not need quoting + +load_rc_config_extra\load_rc_config not followed by blank line\The load_rc_config line must form its own block +load_rc_config_missing\load_rc_config is late, incorrect or missing\Directly following the name/rcvar block must be load_rc_config $name, unquoted + +name_missing\name is set late or not at all\Directly following the sourcing of scripts must follow setting of the variable name +name_quoted\name is quoted\Do not quote the value of name. If it has spaces, use underscores + +rc_subr_late\rc.subr sourcing late or nonexistent\The first non-comment non-blank line in any rc file must be sourcing /etc/rc.subr + +rcorder_keyword_freebsd\Do not include FreeBSD in the KEYWORD rcorder line\Historically FreeBSD scripts were marked in the KEYWORD section. This is no longer necessary +rcorder_missing\Missing rcorder block\Following the FreeBSD RCSId keyword must be nothing but empty comment lines and an rcorder block +rcorder_order\rcorder block in the wrong order; should be PROVIDE/REQUIRE/BEFORE/KEYWORD\See the article on RC scripting + +rcvar_extra\extra lines in name/rcvar block\Order should be [blank line]/name=/rcvar=/[blank line] +rcvar_incorrect\rcvar is not set correctly\rcvar must be directly set to name_enable. Do not quote, and do not use indirection; ${name}_enable is slower than example_enable +rcvar_missing\rcvar is set late or not at all\Setting rcvar must be done straight after setting name +rcvar_quoted\rcvar is quoted\Do not quote the value of rcvar + +rcsid\Missing FreeBSD RCSId keyword\All rc scripts must contain a line beginning # $FreeBSD$. Do not include blank lines without comment markers at the beginning (#) until the script begins + +shebang\Incorrect shebang used\All rc scripts must start with the correct shebang; #!/bin/sh Modified: user/crees/rclint/rclint.py ============================================================================== --- user/crees/rclint/rclint.py Mon Oct 15 18:15:18 2012 (r241597) +++ user/crees/rclint/rclint.py Mon Oct 15 20:19:57 2012 (r241598) @@ -32,9 +32,10 @@ micro = 0 import argparse import logging import re +import textwrap def error_explain(error): - if verbosity > 0: print error['explanation'] + if verbosity > 0: print textwrap.fill(error['explanation'], initial_indent='==> ', subsequent_indent=' ') def error(type, line_number, filename): logging.error("[%d]%s: %s " % (line_number, filename, errors[type]['message'])) @@ -43,6 +44,10 @@ def error(type, line_number, filename): def check_quoted(string): return True if string[0] == '"' or string[0] == "'" else False +def mandatory(var): + mand = ['enable'] + return True if var.split('_')[-1] in mand else False + def get_value(var, line): n = re.match('%s=(\S*)$' % var, line) if n: @@ -51,11 +56,7 @@ def get_value(var, line): else: return False -def do_rclint(filename): - logging.debug('Suck in file %s' % filename) - lines=[line.rstrip('\n') for line in open(filename)] - num = 0 - +def check_header(lines, num, filename): # Basic order; shebang, copyright, RCSId, gap, rcorder logging.debug('Check shebang') @@ -97,8 +98,9 @@ def do_rclint(filename): if re.match('# [PRBK]', lines[num]): error('rcorder_order', num, filename) - documentation_line = num + return num +def check_intro(lines, num, filename): logging.debug('Checking sourcing lines') while lines[num] == '' or lines[num][0] == '#': num += 1 @@ -130,7 +132,67 @@ def do_rclint(filename): error('rcvar_incorrect', num, filename) else: num += 1 - + + logging.debug('Checking load_rc_config') + if lines[num] == '': + num += 1 + else: + error('rcvar_extra', num, filename) + + if re.match('load_rc_config (?:\$name|%s)' % name, lines[num]): + num += 1 + else: + error('load_rc_config_missing', num, filename) + + if lines[num] == '': + num += 1 + else: + error('load_rc_config_extra', num, filename) + + return num + +def check_defaults(lines, num, filename): + logging.debug('Checking defaults set') + + default = { } + try: + while lines[num] != '': + while lines[num][0] == '#' or lines[num][:4] == 'eval': num += 1 + if lines[num][0] == ':': + # Shorthand set self-default assignment + (target, operator, value) = re.match(': \${([^:=]+)(:?=)([^}]+)}', lines[num]).groups() + if operator == ':=' and not mandatory(target): + error('defaults_non_mandatory_colon', num, filename) + elif operator == '=' and mandatory(target): + error('defaults_mandatory_colon', num, filename) + + else: + # Longhand set default assignment + (target, source, operator, value) = re.match('([^=]+)=\${([^:-]+)(:?-)([^}]+)}', lines[num]).groups() + if target == source: + error('defaults_old_style', num, filename) + + if operator == ':-' and not mandatory(target): + error('defaults_non_mandatory_colon', num, filename) + elif operator == '-' and mandatory(target): + error('defaults_mandatory_colon', num, filename) + + if check_quoted(value): + error('defaults_value_quoted', num, filename) + + num += 1 + except: + error('defaults_invalid', num, filename) + +def do_rclint(filename): + logging.debug('Suck in file %s' % filename) + lines=[line.rstrip('\n') for line in open(filename)] + begin_num = 0 + + endofheader_num = check_header(lines, begin_num, filename) + endofintro_num = check_intro(lines, endofheader_num, filename) + endofdefaults_num = check_defaults(lines, endofintro_num, filename) + parser = argparse.ArgumentParser() parser.add_argument('filenames', nargs = '+') @@ -151,7 +213,7 @@ try: for e in f.readlines(): if e[0] == '#' or len(e) == 1: continue - e = e.split(':') + e = e.split('\\') errors[e[0]] = { 'message': e[1], 'explanation': e[2] } except: logging.error('Cannot open database for language %s' % errordb)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210152019.q9FKJvAJ064874>