kumquat-buildroot/utils/checkpackagelib
Ricardo Martincoski 1734127e59 utils/check-package: prepare to run external tools
Some file formats have well-established syntax checkers.
One example of this is the tool 'shellcheck' that can analyse shell
scripts for common mistakes.

There is no reason to reimplement such tools in check-package, when we
can just call them.

Add the ability to check-package to call external tools that will run
once for each file to be analysed.
For simplicity, when the tool generated one or more warnings, count it
as a single warning from check-package, that can display something like
this:

|$ ./utils/check-package  package/unscd/S46unscd
|package/unscd/S46unscd:0: run 'shellcheck' and fix the warnings
|25 lines processed
|1 warnings generated

|$ ./utils/check-package -vvvvvvvvvvvvvvvv package/unscd/S46unscd
|package/unscd/S46unscd:0: run 'shellcheck' and fix the warnings
|In package/unscd/S46unscd line 9:
|        printf "Starting ${NAME}: "
|               ^------------------^ SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
|In package/unscd/S46unscd line 11:
|        [ $? -eq 0 ] && echo "OK" || echo "FAIL"
|          ^-- SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
|In package/unscd/S46unscd line 14:
|        printf "Stopping ${NAME}: "
|               ^------------------^ SC2059: Don't use variables in the printf format string. Use printf "..%s.." "$foo".
|In package/unscd/S46unscd line 16:
|        [ $? -eq 0 ] && echo "OK" || echo "FAIL"
|          ^-- SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
|For more information:
|  https://www.shellcheck.net/wiki/SC2059 -- Don't use variables in the printf...
|  https://www.shellcheck.net/wiki/SC2181 -- Check exit code directly with e.g...
|25 lines processed
|1 warnings generated

In this first commit, add only the ability for check-package to call
external tools and not an example of such tool, as adding each tool to
call may need update to the docker image and can lead to it's own
discussion on how to implement.

Signed-off-by: Ricardo Martincoski <ricardo.martincoski@gmail.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2022-02-06 16:38:52 +01:00
..
__init__.py
base.py utils/check-package: prepare to run external tools 2022-02-06 16:38:52 +01:00
lib_config.py
lib_hash.py support/download: drop support for the 'none' hash 2022-01-11 21:58:01 +01:00
lib_mk.py utils/checkpackagelib/lib_mk.py: fix check for overridden variable 2021-12-10 20:01:40 +01:00
lib_patch.py
lib.py
readme.txt
test_lib_config.py utils/checkpackagelib: add unit tests 2022-02-06 15:35:19 +01:00
test_lib_hash.py utils/checkpackagelib: add unit tests 2022-02-06 15:35:19 +01:00
test_lib_mk.py utils/checkpackagelib: add unit tests 2022-02-06 15:35:19 +01:00
test_lib_patch.py utils/checkpackagelib: add unit tests 2022-02-06 15:35:19 +01:00
test_lib.py utils/checkpackagelib: add unit tests 2022-02-06 15:35:19 +01:00
test_util.py utils/checkpackagelib: add unit tests 2022-02-06 15:35:19 +01:00

How the scripts are structured:
- check-package is the main engine, called by the user.
  For each input file, this script decides which parser should be used and it
  collects all classes declared in the library file and instantiates them.
  The main engine opens the input files and it serves each raw line (including
  newline!) to the method check_line() of every check object.
  Two special methods before() and after() are used to call the initialization
  of variables (for the case it needs to keep data across calls) and the
  equivalent finalization (e.g. for the case a warning must be issued if some
  pattern is not in the input file).
- base.py contains the base class for all check functions.
- lib.py contains the classes for common check functions.
  Each check function is explicitly included in a given type-parsing library.
  Do not include every single check function in this file, a class that will
  only parse hash files should be implemented in the hash-parsing library.
  When a warning must be issued, the check function returns an array of strings.
  Each string is a warning message and is displayed if the corresponding verbose
  level is active. When the script is called without --verbose only the first
  warning in the returned array is printed; when called with --verbose both
  first and second warnings are printed; when called with -vv until the third
  warning is printed; an so on.
  Helper functions can be defined and will not be called by the main script.
- lib_type.py contains check functions specific to files of this type.

Some hints when changing this code:
- prefer O(n) algorithms, where n is the total number of lines in the files
  processed.
- when there is no other reason for ordering, use alphabetical order (e.g. keep
  the check functions in alphabetical order, keep the imports in alphabetical
  order, and so on).
- keep in mind that for every class the method before() will be called before
  any line is served to be checked by the method check_line(). A class that
  checks the filename should only implement the method before(). A function that
  needs to keep data across calls (e.g. keep the last line before the one being
  processed) should initialize all variables using this method.
- keep in mind that for every class the method after() will be called after all
  lines were served to be checked by the method check_line(). A class that
  checks the absence of a pattern in the file will need to use this method.
- try to avoid false warnings. It's better to not issue a warning message to a
  corner case than have too many false warnings. The second can make users stop
  using the script.
- do not check spacing in the input line in every single function. Trailing
  whitespace and wrong indentation should be checked by separate functions.
- avoid duplicate tests. Try to test only one thing in each function.
- in the warning message, include the url to a section from the manual, when
  applicable. It potentially will make more people know the manual.
- use short sentences in the warning messages. A complete explanation can be
  added to show when --verbose is used.
- when testing, verify the error message is displayed when the error pattern is
  found, but also verify the error message is not displayed for few
  well-formatted packages... there are many of these, just pick your favorite
  as golden package that should not trigger any warning message.
- check the url displayed by the warning message works.

Usage examples:
- to get a list of check functions that would be called without actually
  calling them you can use the --dry-run option:
$ utils/check-package --dry-run package/yourfavorite/*

- when you just added a new check function, e.g. Something, check how it behaves
  for all current packages:
$ utils/check-package --include-only Something $(find package -type f)

- the effective processing time (when the .pyc were already generated and all
  files to be processed are cached in the RAM) should stay in the order of few
  seconds:
$ utils/check-package $(find package -type f) >/dev/null ; \
  time utils/check-package $(find package -type f) >/dev/null

- vim users can navigate the warnings (most editors probably have similar
  function) since warnings are generated in the form 'path/file:line: warning':
$ find package/ -name 'Config.*' > filelist && vim -c \
  'set makeprg=utils/check-package\ $(cat\ filelist)' -c make -c copen