Skip site navigation (1)Skip section navigation (2)
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>