From e63dc805cf4cfceb7f3d49cf7f8eccdfc03722ea Mon Sep 17 00:00:00 2001 From: Castulo Martinez Date: Thu, 11 Jul 2019 23:58:15 +0000 Subject: [PATCH] Adding flag validation to the swupd build process swupd supports global flags and supports local flags that are specific to subcommands. Flags that are specific to subcommands can be reused in a different subcommand. Global flags should be unique and should not be reused as local flags to avoid conflicts. This commit adds a bash script that checks that the flags currently used in swupd are valid (have no conflicts with other flags from the same command or with the global flags). This script will be run as part of the build process so in case an invalid flag is found the build will be stopped. Alternatively, the script can be used by developers to validate a new flag during the implementation time. Signed-off-by: Castulo Martinez --- .travis.yml | 2 +- Makefile.am | 4 + scripts/flag_validator.bash | 183 ++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100755 scripts/flag_validator.bash diff --git a/.travis.yml b/.travis.yml index dd71f2a6..1793d68e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ jobs: include: - stage: "Static Analysis" name: "Static Analysis & Unit Tests" - script: make compliant && make shellcheck && sudo sh -c 'umask 0022 && make unit-check' && make docs-coverage + script: make compliant && make shellcheck && make check-flags && sudo sh -c 'umask 0022 && make unit-check' && make docs-coverage - stage: test name: "Functional Tests - update (group 1)" script: env TESTS="$GROUP1" make -e check diff --git a/Makefile.am b/Makefile.am index 988c5cad..01c3b101 100644 --- a/Makefile.am +++ b/Makefile.am @@ -412,6 +412,7 @@ shellcheck: shellcheck-all: shellcheck swupd.bash + shellcheck scripts/flag_validator.bash find -name "*.bats" -exec sh -c "\ echo checking {}; \ sed 's/^@.*/func() {/' {} | \ @@ -422,6 +423,9 @@ shellcheck-all: check-test-ids: test/functional/check_ids.bash +check-flags: + scripts/flag_validator.bash + release: @git rev-parse v$(PACKAGE_VERSION) &> /dev/null; \ if [ "$$?" -eq 0 ]; then \ diff --git a/scripts/flag_validator.bash b/scripts/flag_validator.bash new file mode 100755 index 00000000..4b076e48 --- /dev/null +++ b/scripts/flag_validator.bash @@ -0,0 +1,183 @@ +#!/bin/bash + +SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SWUPD_DIR="$SCRIPTS_DIR"/.. +SWUPD="$SWUPD_DIR"/swupd + +swupd_commands=(info autoupdate check-update update bundle-add bundle-remove bundle-list search-file diagnose repair os-install mirror clean hashdump) +conflict=0 + +count_global_flags() { + + sudo "$SWUPD" info --help | grep -oe "-.," | cut -c2 | wc -l + +} + +get_global_flags() { + + sudo "$SWUPD" info --help | grep -oe "-.," | cut -c2 | tr '\n' ' ' + +} + +count_command_flags() { + + local command=$1 + sudo "$SWUPD" "$command" --help | sed -n '/^Options:/,$p' | grep -oe "-.," | cut -c2 | wc -l + +} + +get_command_flags() { + + local command=$1 + sudo "$SWUPD" "$command" --help | sed -n '/^Options:/,$p' | grep -oe "-.," | cut -c2 | tr '\n' ' ' + +} + +find_global_flag_conflict() { + + local flags_count + local unique_flags_count + + # global flags have to be compared only against other global flags + flags_count=$(count_global_flags) + unique_flags_count=$(get_global_flags | tr ' ' '\n' | sort -u | wc -l) + if [ "$flags_count" != "$unique_flags_count" ]; then + echo "Conflict found: There is a duplicated global flag" + conflict=1 + fi + +} + +find_command_flag_conflict() { + + local command=$1 + local flags_count + local unique_flags_count + declare -a local_flags + declare -a global_flags + + # first let's make sure there are no duplicated local flags + flags_count=$(count_command_flags "$command") + unique_flags_count=$(get_command_flags "$command" | tr ' ' '\n' | sort -u | wc -l) + if [ "$flags_count" != "$unique_flags_count" ]; then + echo "Conflict found: There is a duplicated flag in the $command command" + conflict=1 + fi + + # local flags have to be compared against global flags too + IFS=" " read -r -a global_flags <<< "$(get_global_flags)" + IFS=" " read -r -a local_flags <<< "$(get_command_flags "$command")" + for local_flag in "${local_flags[@]}"; do + for global_flag in "${global_flags[@]}"; do + if [ "$local_flag" == "$global_flag" ]; then + echo "Conflict found: The flag '-$local_flag' from 'swupd $command' already exists as a global flag" + conflict=1 + fi + done + done + +} + +validate_existing_flags() { + + find_global_flag_conflict + + for cmd in "${swupd_commands[@]}"; do + find_command_flag_conflict "$cmd" + done + + if [ "$conflict" -eq 1 ]; then + exit 1 + fi + echo "No conflicts found with the flags" + +} + +validate_flag() { + + local command=$1 + local cmd_flag=$2 + declare -a flags + + find_global_flag_conflict + IFS=" " read -r -a flags <<< "$(get_global_flags)" + for f in "${flags[@]}"; do + if [ "$cmd_flag" == "$f" ]; then + echo "Conflict found: The flag '-$f' from 'swupd $command' already exists as a global flag" + exit 1 + fi + done + + if [ "$command" != "global" ]; then + find_command_flag_conflict "$command" + IFS=" " read -r -a flags <<< "$(get_command_flags "$command")" + for f in "${flags[@]}"; do + if [ "$cmd_flag" == "$f" ]; then + echo "Conflict found: The flag '-$f' already exists in 'swupd $command'" + exit 1 + fi + done + fi + + echo "No conflicts found with the 'swupd $command -$cmd_flag' flag" + +} + +usage() { + + cat <<-EOM + + Validates that the flags used in swupd are not duplicated + + Usage: + flag_validator.bash + + Example: + flag_validator.bash bundle-add w + + Notes: + If run with no argument, it validates the existing flags + If run with the arguments, it validate that is a valid option for + If is a global option, use "global " + + EOM + +} + +# Entry point +arg=$1 +flag=$2 + +if [ "$arg" == "--help" ] || [ "$arg" == "-h" ]; then + usage + exit +fi + +# If run with no argument, it validates the existing flags +if [ -z "$arg" ]; then + validate_existing_flags + exit +fi + +# If run with the arguments, it validates +# that is a valid option for +if [ -z "$flag" ]; then + echo "Error: Mandatory argument missing" + usage + exit 1 +fi + +swupd_commands+=("global") +for val in "${swupd_commands[@]}"; do + if [ "$val" == "$arg" ]; then + # remove the '-' if it has one + flag=$(echo "$flag" | tr --delete '-') + validate_flag "$arg" "$flag" + exit "$conflict" + fi +done + +echo "Error: The provided command '$arg' is invalid" +echo "Available commands:" +echo "${swupd_commands[@]}" | tr ' ' '\n' +exit 1