From 2eb84d9ef7397e3aa0299aadc0bd0d918e08e231 Mon Sep 17 00:00:00 2001 From: Alberto Nidasio <alberto.nidasio@skywarder.eu> Date: Sun, 2 Oct 2022 09:28:15 +0200 Subject: [PATCH] [SBS][Linter] Updated cppcheck and copyright output --- sbs | 140 +++++++++++++++++++++++----------------------- scripts/linter.py | 94 +++++++++++++++---------------- 2 files changed, 116 insertions(+), 118 deletions(-) diff --git a/sbs b/sbs index 5dce172a4..5cecc767b 100755 --- a/sbs +++ b/sbs @@ -52,7 +52,7 @@ init_dirs() { find_deps() { ohai "Find dependencies" - + command -v cmake > /dev/null 2>&1 && found_cmake=true command -v arm-miosix-eabi-g++ > /dev/null 2>&1 && found_miosixgpp=true command -v ccache > /dev/null 2>&1 && found_ccache=true @@ -63,7 +63,7 @@ find_deps() { command -v clang-format > /dev/null 2>&1 && found_clangformat=true command -v st-flash > /dev/null 2>&1 && found_stflash=true command -v ST-LINK_CLI.exe > /dev/null 2>&1 && found_stlink=true - + printf "Found CMake: "; [ "$found_cmake" = true ] && echo "yes" || echo "no" printf "Found arm-miosix-eabi-g++: "; [ "$found_miosixgpp" = true ] && echo "yes" || echo "no" printf "Found Ccache: "; [ "$found_ccache" = true ] && echo "yes" || echo "no" @@ -73,8 +73,8 @@ find_deps() { printf "Found clang-tidy: "; [ "$found_clangtidy" = true ] && echo "yes" || echo "no" printf "Found clang-format: "; [ "$found_clangformat" = true ] && echo "yes" || echo "no" printf "Found flasher: "; [ "$found_stflash" = true ] && echo "st-flash" \ - || { [ "$found_stlink" = true ] && echo "st-link" || echo "no"; } - + || { [ "$found_stlink" = true ] && echo "st-link" || echo "no"; } + [ "$found_cmake" = true ] || { echo "Error: CMake must be installed"; return 1; } [ "$found_miosixgpp" = true ] || { echo "Error: arm-miosix-eabi-g++ must be installed"; return 1; } } @@ -83,51 +83,51 @@ find_deps() { # See: https://gitlab.kitware.com/cmake/cmake/-/issues/20212 cmake_disable_excluded_tests() { declare build_dir="$1" - + [ ! -f "$build_dir/$CTEST_FILENAME" ] || sed -i.bak 's/^subdirs/# subdirs/' "$build_dir/$CTEST_FILENAME" } configure() { declare build_dir="$1" - + ohai "Configure" - + [ -f "$toolchain_file" ] || { echo "Error: CMake Toolchain File for Miosix was not found"; return 1; } - + declare -a defs=(-DCMAKE_EXPORT_COMPILE_COMMANDS=ON) defs+=(-DCMAKE_C_FLAGS=-fdiagnostics-color=always -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always) [ "$config_host" = false ] && defs+=(-DCMAKE_TOOLCHAIN_FILE="$toolchain_file" -DBUILD_TESTING=OFF) [ "$found_ccache" = true ] && defs+=(-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache) [ "$config_debug" = true ] && defs+=(-DCMAKE_BUILD_TYPE=Debug) || defs+=(-DCMAKE_BUILD_TYPE=Release) [ "$config_verbose" = true ] && defs+=(-DCMAKE_VERBOSE_MAKEFILE=ON) - + declare gen [ "$found_ninja" = true ] && gen=-GNinja || gen=-G"Unix Makefiles" - + cmake -B"$build_dir" "${defs[@]}" "$gen" "$source_dir" || return - + { [ "$config_debug" = true ] && touch "$build_dir/$DEBUG_FILENAME"; } || rm -f "$build_dir/$DEBUG_FILENAME" { [ "$config_verbose" = true ] && touch "$build_dir/$VERBOSE_FILENAME"; } || rm -f "$build_dir/$VERBOSE_FILENAME" } check_configured() { declare build_dir="$1" - + declare to_reconfigure=false if [ ! -d "$build_dir" ]; then to_reconfigure=true - elif [ ! -f "$build_dir/$CMAKE_FILENAME" ]; then + elif [ ! -f "$build_dir/$CMAKE_FILENAME" ]; then rm -rf "$build_dir" to_reconfigure=true else [ -f "$build_dir/$DEBUG_FILENAME" ] && found_debug=true || found_debug=false [ -f "$build_dir/$VERBOSE_FILENAME" ] && found_verbose=true || found_verbose=false if [ "$config_debug" != "$found_debug" ] \ - || [ "$config_verbose" != "$found_verbose" ]; then + || [ "$config_verbose" != "$found_verbose" ]; then to_reconfigure=true fi fi - + if [ "$to_reconfigure" = true ]; then configure "$build_dir" fi @@ -136,36 +136,36 @@ check_configured() { build() { declare build_dir="$1" declare target="$2" - + check_configured "$build_dir" || return - + ohai "Build" - + declare -a opts get_build_opts opts - + cmake --build "$build_dir" "${opts[@]}" --target "$target" } build_all() { declare build_dir="$build_default_dir" - + build "$build_dir" all } clean() { declare build_desc="$1" declare build_dir="$2" - + ohai "Clean ($build_desc)" - + if [ -f "$build_dir/$CMAKE_FILENAME" ]; then declare -a opts get_build_opts opts - + cmake --build "$build_dir" "${opts[@]}" --target clean fi - + echo "Removing build folder..." rm -rf "$build_dir" } @@ -178,16 +178,16 @@ clean_all() { flash() { declare target="$1" declare build_dir="$build_default_dir" - + build "$build_dir" "$target" || return - + ohai "Flash" - + [ -f "$build_dir/$target.bin" ] || { echo "Error: target '$target' is not flashable"; return 1; } - + if [ "$found_stflash" = true ]; then st-flash --reset write "$build_dir/$target.bin" 0x8000000 - elif [ "$found_stlink" = true ]; then + elif [ "$found_stlink" = true ]; then ST-LINK_CLI.exe -P "$build_dir/$target.bin" 0x8000000 -V -Rst else echo "Error: No flashing software found!" @@ -198,120 +198,120 @@ flash() { run_tests() { declare target="$1" declare build_dir="$build_host_dir" - + config_host=true - + build "$build_dir" "$target" || return - + ohai "Test" - + cmake_disable_excluded_tests "$build_dir" ( cd "$build_dir" || return; ctest ) } list() { declare build_dir="$build_default_dir" - + check_configured "$build_dir" || return - + ohai "List targets" - + declare -a opts get_build_opts opts - + echo "[1/1] All SBS targets available:" cmake --build "$build_dir" "${opts[@]}" --target help \ - | grep -o '^[^/]*\.bin' | cut -f 1 -d '.' + | grep -o '^[^/]*\.bin' | cut -f 1 -d '.' } boards() { declare build_dir="$build_default_dir" - + check_configured "$build_dir" || return - + ohai "List boards" - + declare -a opts get_build_opts opts - + cmake --build "$build_dir" "${opts[@]}" --target help-boards } lint_copyright() { ohai "Lint (Copyright)" - + "$sbs_base/scripts/linter.py" --copyright "$source_dir/src" } lint_find() { ohai "Lint (Find)" - + "$sbs_base/scripts/linter.py" --find "$source_dir/src" } lint_clangtidy() { declare build_dir="$1" - + check_configured "$build_dir" || return - + ohai "Lint (clang-tidy)" - + defs=(--extra-arg=-D_MIOSIX=1 --extra-arg=-D_MIOSIX_GCC_PATCH_MINOR=1 \ - --extra-arg=-D_MIOSIX_GCC_PATCH_MAJOR=3 --extra-arg=-D__LINT__) + --extra-arg=-D_MIOSIX_GCC_PATCH_MAJOR=3 --extra-arg=-D__LINT__) IFS=$'\n' read -rd '' -a incs < \ - <(arm-miosix-eabi-g++ -E -Wp,-v -xc++ /dev/null 2>&1 \ - | sed -n "s/^ /--extra-arg=-isystem/p") - + <(arm-miosix-eabi-g++ -E -Wp,-v -xc++ /dev/null 2>&1 \ + | sed -n "s/^ /--extra-arg=-isystem/p") + declare opts=() [ "$to_edit" = true ] && opts+=(--fix-notes --fix-errors) - + find "$source_dir/src" \ - -type f \( -iname "*.cpp" -o -iname "*.h" -o -iname "*.c" \) \ - -exec clang-tidy --header-filter=".*" -p="$build_dir" "${defs[@]}" \ - "${incs[@]}" "${opts[@]}" {} \; + -type f \( -iname "*.cpp" -o -iname "*.h" -o -iname "*.c" \) \ + -exec clang-tidy --header-filter=".*" -p="$build_dir" "${defs[@]}" \ + "${incs[@]}" "${opts[@]}" {} \; } lint_cppcheck() { ohai "Lint (Cppcheck)" - + declare -a opts=() [ -n "$jobs" ] && opts+=("-j $jobs") - - cppcheck --language=c++ --std=c++11 --enable=all --inline-suppr \ - --suppress=unmatchedSuppression --suppress=unusedFunction \ - --suppress=missingInclude --error-exitcode=1 "${opts[@]}" \ - "$source_dir/src" + + cppcheck --language=c++ --std=c++14 --enable=all --inline-suppr \ + --suppress=unmatchedSuppression --suppress=unusedFunction \ + --suppress=missingInclude --error-exitcode=1 -q "${opts[@]}" \ + "$source_dir/src" } lint_clangformat() { declare to_edit="$1" - + ohai "Lint (clang-format)" - + declare -a opts=(--style=file --Werror) [ "$to_edit" = true ] && opts+=(-i) || opts+=(--dry-run) - + find "$source_dir/src" \ - -type f \( -iname "*.cpp" -o -iname "*.h" -o -iname "*.c" \) \ - -exec clang-format "${opts[@]}" {} \; + -type f \( -iname "*.cpp" -o -iname "*.h" -o -iname "*.c" \) \ + -exec clang-format "${opts[@]}" {} \; } lint() { declare to_edit="$1" - + if [ "$found_python" = true ]; then lint_copyright lint_find fi - + if [ "$found_clangtidy" = true ] && [ "$lint_clangtidy" = true ]; then lint_clangtidy "$build_default_dir" fi - + if [ "$found_cppcheck" = true ]; then lint_cppcheck fi - + if [ "$found_clangformat" = true ]; then lint_clangformat "$to_edit" fi diff --git a/scripts/linter.py b/scripts/linter.py index 4b2e80586..bbc7b2835 100755 --- a/scripts/linter.py +++ b/scripts/linter.py @@ -92,10 +92,6 @@ def print_banner(): print('+------------------------------+') -def linter_print(*strings): - print('[linter]', *strings) - - class Colors(): BLACK = '\033[30m' RED = '\033[31m' @@ -111,7 +107,7 @@ class Colors(): # Checks for the right copyright notice in all .h and .cpp files def check_copyright(directory): - linter_print(Colors.GREEN + 'Copyright check' + Colors.RESET) + print(Colors.GREEN + 'Copyright check' + Colors.RESET) # Statistics totalCheckdFilesCounter = 0 @@ -134,7 +130,7 @@ def check_copyright(directory): filesWithErrorsCounter += 1 # The file's copyright notice does not match the template! - linter_print(Colors.YELLOW + 'Wrong copyright notice in file {0}'.format( + print(Colors.YELLOW + 'Wrong copyright notice in file {0}'.format( currentFilepath) + Colors.RESET) else: fileAuthors = [a.strip() @@ -142,10 +138,10 @@ def check_copyright(directory): # Check the number of authors against 'Author' or `Authors` if len(fileAuthors) == 1 and match.group(1)[-1] == 's': - linter_print('\'Authors\' should to be changed to \'Author\' in {0}'.format( + print('\'Authors\' should to be changed to \'Author\' in {0}'.format( currentFilepath)) if len(fileAuthors) > 1 and match.group(1)[-1] != 's': - linter_print('\'Author\' should to be changed to \'Authors\' in {0}'.format( + print('\'Author\' should to be changed to \'Authors\' in {0}'.format( currentFilepath)) # Save statistics on authors @@ -157,28 +153,29 @@ def check_copyright(directory): averageAuthorsPerFile += len(fileAuthors) averageAuthorsPerFile /= totalCheckdFilesCounter - linter_print('Checked {} files'.format(totalCheckdFilesCounter)) + print('Checked {} files'.format(totalCheckdFilesCounter)) if filesWithErrorsCounter == 0: - linter_print('All the files have the correct copyright notice') + print('All the files have the correct copyright notice') else: - linter_print(Colors.RED + '{:.1f}% ({}/{}) of all analyzed files do not match with the copyright template!'.format( + print(Colors.RED + '{:.1f}% ({}/{}) of all analyzed files do not match with the copyright template!'.format( 100*filesWithErrorsCounter/totalCheckdFilesCounter, filesWithErrorsCounter, totalCheckdFilesCounter) + Colors.RESET) - if(not args.quiet): - linter_print('{:.2} authors per file'.format( + if (not args.quiet): + print('{:.2} authors per file'.format( averageAuthorsPerFile)) - linter_print('Number of mentions per author:') - for author in authors: - linter_print('{:3} - {}'.format(authors[author], author)) + + print('Number of mentions per author:') + for author in sorted(authors.items(), key=lambda item: item[1], reverse=True): + print('{:3} - {}'.format(author[1], author[0])) # Exit if error if at least one file isn't correct - if(filesWithErrorsCounter > 0): + if (filesWithErrorsCounter > 0): exit(-1) # Checks if all .h and .cpp files respects the clang format specified in .clang-format file def check_format(directory): - linter_print(Colors.GREEN + 'Formatting check' + Colors.RESET) + print(Colors.GREEN + 'Formatting check' + Colors.RESET) # Statistics totalCheckdFilesCounter = 0 @@ -197,27 +194,27 @@ def check_format(directory): ['clang-format', '-style=file', '--dry-run', '--Werror', '--ferror-limit=1', currentFilepath], stderr=DEVNULL) # If and error occurs warn the user - if(returnCode != 0): + if (returnCode != 0): filesWithErrorsCounter += 1 - if(not args.quiet): - linter_print(Colors.YELLOW + 'Wrong code format for file {1}'.format( + if (not args.quiet): + print(Colors.YELLOW + 'Wrong code format for file {1}'.format( returnCode, currentFilepath) + Colors.RESET) - linter_print('Checked {} files'.format(totalCheckdFilesCounter)) + print('Checked {} files'.format(totalCheckdFilesCounter)) if filesWithErrorsCounter == 0: - linter_print('All the files match the Skyward formatting style') + print('All the files match the Skyward formatting style') else: - linter_print(Colors.RED + '{:4.1f}% ({}/{}) of all analyzed files do not match Skyward formatting style!'.format( + print(Colors.RED + '{:4.1f}% ({}/{}) of all analyzed files do not match Skyward formatting style!'.format( 100*filesWithErrorsCounter/totalCheckdFilesCounter, filesWithErrorsCounter, totalCheckdFilesCounter), Colors.RESET) # Exit if error if at least one file isn't correct - if(filesWithErrorsCounter > 0): + if (filesWithErrorsCounter > 0): exit(-1) def find_in_code(directory, searchTerm, extensionFilters=('.cpp', '.h'), pathFilter=None): - linter_print( + print( Colors.GREEN + 'Checking for \'{}\' in code files'.format(searchTerm) + Colors.RESET) # Statistics @@ -243,16 +240,16 @@ def find_in_code(directory, searchTerm, extensionFilters=('.cpp', '.h'), pathFil filesWithErrorsCounter += 1 # The current file has the error - if(not args.quiet): - linter_print(Colors.YELLOW + 'Found \'{}\' in file {}'.format(searchTerm, - currentFilepath) + Colors.RESET) + if (not args.quiet): + print(Colors.YELLOW + 'Found \'{}\' in file {}'.format(searchTerm, + currentFilepath) + Colors.RESET) - linter_print('Checked {} files'.format(totalCheckdFilesCounter)) + print('Checked {} files'.format(totalCheckdFilesCounter)) if filesWithErrorsCounter == 0: - linter_print( + print( 'All the files does not contain \'{}\''.format(searchTerm)) else: - linter_print(Colors.RED + '{:.1f}% ({}/{}) of all analyzed files contain \'{}\'!'.format( + print(Colors.RED + '{:.1f}% ({}/{}) of all analyzed files contain \'{}\'!'.format( 100*filesWithErrorsCounter/totalCheckdFilesCounter, filesWithErrorsCounter, totalCheckdFilesCounter, searchTerm) + Colors.RESET) return filesWithErrorsCounter @@ -260,7 +257,8 @@ def find_in_code(directory, searchTerm, extensionFilters=('.cpp', '.h'), pathFil def check_find(directory): sum = find_in_code(directory, r'^using namespace', '.h') - sum += find_in_code(directory, r'[^a-zA-Z0-9]printf\(', pathFilter='shared') + sum += find_in_code(directory, + r'[^a-zA-Z0-9]printf\(', pathFilter='shared') sum += find_in_code(directory, r'( |^)assert\(') sum += find_in_code(directory, '^ *throw ', pathFilter='catch') @@ -269,7 +267,7 @@ def check_find(directory): def check_cppcheck(directory): - linter_print(Colors.GREEN + 'cppcheck' + Colors.RESET) + print(Colors.GREEN + 'cppcheck' + Colors.RESET) # Run cppcheck on the directory try: result = check_output(['cppcheck', '-q', '--language=c++', '--template=gcc', '--std=c++11', '--enable=all', '--inline-suppr', @@ -280,21 +278,21 @@ def check_cppcheck(directory): errors = re.findall(r'\[(\w+)\]', result.decode('utf-8')) errors = Counter(errors) - if(not args.quiet): - linter_print('cppcheck found the following errors:') + if (not args.quiet): + print('cppcheck found the following errors:') for error in errors: - linter_print('{:3} - {}'.format(errors[error], error)) + print('{:3} - {}'.format(errors[error], error)) totalErrors = sum(errors.values()) - if(totalErrors > 0): - linter_print( + if (totalErrors > 0): + print( Colors.RED + 'cppcheck found {} errors in total'.format(totalErrors) + Colors.RESET) exit(-1) else: - linter_print('cppcheck did not find any errors') + print('cppcheck did not find any errors') except CalledProcessError as e: - linter_print(e.output.decode('utf-8')) + print(e.output.decode('utf-8')) exit(-1) # ------------------------------------------------------------- @@ -305,26 +303,26 @@ def check_cppcheck(directory): parser = config_cmd_parser() args = parser.parse_args() -if(not args.directory): - linter_print('No directory specified') +if (not args.directory): + print('No directory specified') print('') parser.print_help() exit(-1) -if(args.copyright): +if (args.copyright): check_copyright(args.directory) -if(args.format): +if (args.format): check_format(args.directory) -if(args.cppcheck): +if (args.cppcheck): check_cppcheck(args.directory) -if(args.find): +if (args.find): check_find(args.directory) # Checks everything if no option is specified -if(not args.copyright and not args.format and not args.find and not args.cppcheck): +if (not args.copyright and not args.format and not args.find and not args.cppcheck): check_copyright(args.directory) check_format(args.directory) check_find(args.directory) -- GitLab