checker: Introduce hal-rootstrap-checker accepted/tizen/unified/20240812.190146 accepted/tizen/unified/dev/20240813.040007 accepted/tizen/unified/x/20240813.112440
authorYoungjae Cho <y0.cho@samsung.com>
Tue, 6 Aug 2024 08:52:13 +0000 (17:52 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Fri, 9 Aug 2024 08:49:22 +0000 (17:49 +0900)
The hal-rootstrap-checker is mainly for screening packages out from
build that have dependencies to unmanaged, especially ABI incompatible,
packages. It operates after every %install stage of rpmbuild, aided by
rpm macro. Those managed/unmanaged packages can be configured by yaml
file described below.

The rpm package has implemented empty macro,
 %{__hal_rootstrap_checker_install_post}
and the rpmbuild has gained 'Requires' dependency to the
hal-rootstrap-checker, making the hal-rootstrap-checker overwrite the
macro with its macro, executing hal-rootstrap-checker.sh. See
hal-rootstrap-checker-rpmmacros.

The hal-rootstrap-checker.sh can be configured by yaml file with the
same name. The default one is
 /etc/hal/rootstrap/hal-rootstrap-checker.yaml.

And there can be another one,
 /etc/hal/rootstrap/rules.d/hal-rootstrap-checker.yaml,
which shades the default configuration, and it gives a way for applying
custom defined configuration.

For those details about configuration attributes, see the yaml file.

Change-Id: I354f154fa6ac670c2e95fc09b947dbc4ecfaf229
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
packaging/hal-rootstrap-checker-rpmmacros [new file with mode: 0644]
packaging/hal-rootstrap-checker.sh [new file with mode: 0644]
packaging/hal-rootstrap-checker.yaml [new file with mode: 0644]
packaging/hal-rootstrap.spec

diff --git a/packaging/hal-rootstrap-checker-rpmmacros b/packaging/hal-rootstrap-checker-rpmmacros
new file mode 100644 (file)
index 0000000..77a7054
--- /dev/null
@@ -0,0 +1,3 @@
+%__hal_rootstrap_checker_install_post \
+    /etc/hal/rootstrap/hal-rootstrap-checker.sh %{!?disable_hal_rootstrap_checker:0}%{?disable_hal_rootstrap_checker} %{_sourcedir} \
+%{nil}
diff --git a/packaging/hal-rootstrap-checker.sh b/packaging/hal-rootstrap-checker.sh
new file mode 100644 (file)
index 0000000..4a5ecd5
--- /dev/null
@@ -0,0 +1,236 @@
+#!/bin/bash
+
+# Disable pathname expansion by '*' or '?'
+set -f
+
+IFS=";"
+
+# Message formatting
+LINE_MAX_LENGTH=90
+
+print_border() {
+       PLACEHOLDER=$(printf "%*s" "$LINE_MAX_LENGTH" " ")
+       echo ${PLACEHOLDER// /\#}
+}
+
+print_message() {
+       MESSAGE_MAX_LENGTH=$(($LINE_MAX_LENGTH - 3))
+       printf "# %-*s#\n" "$MESSAGE_MAX_LENGTH" "$1"
+}
+
+print_not_allowed_warning() {
+       WARNING_TYPE=$1
+       NOT_ALLOWED_LIST=$2
+       ALLOWED_LIST=$3
+       CHECK_ALWAYS=$4
+
+       print_border
+       print_border
+
+       print_message "WARNING: There are not allowed $WARNING_TYPE. They might cause ABI break."
+       for NOT_ALLOWED in ${NOT_ALLOWED_LIST}; do
+               print_message "WARNING:  - $NOT_ALLOWED"
+       done
+
+       print_message "WARINIG:"
+       if [[ ! -z $ALLOWED_LIST ]]; then
+               print_message "WARNING: Use only allowed packages below for $WARNING_TYPE"
+               for ALLOWED in ${ALLOWED_LIST}; do
+                       print_message "WARNING:  - $ALLOWED"
+               done
+       else
+               print_message "WARNING: It is not allowed to specify $WARNING_TYPE"
+       fi
+
+       if [[ $CHECK_ALWAYS == "no" ]]; then
+               print_message "WARNING:"
+               print_message "WARNING: Give parameter --define 'disable_hal_rootstrap_checker 1' to gbs build"
+               print_message "WARNING: to skip this check."
+       fi
+
+       print_border
+       print_border
+}
+
+# main
+DISABLE_HAL_ROOTSTRAP_CHECKER=$1
+SOURCEDIR=$2
+
+# Checker configuration filepath
+HAL_ROOTSTRAP_CHECKER_CONF=/etc/hal/rootstrap/hal-rootstrap-checker.yaml
+HAL_ROOTSTRAP_CHECKER_CONF_D=/etc/hal/rootstrap/rules.d/hal-rootstrap-checker.yaml
+
+# Checker configuration
+TARGET_PACKAGE_NAME=""
+EXCLUDED_TARGET_PACKAGE_NAME=""
+ALLOWED_BUILDREQUIRES=""
+ALLOWED_REQUIRES=""
+CHECK_ALWAYS="no"
+
+# Locate configuration file
+CONFFILE=""
+if [[ -s $HAL_ROOTSTRAP_CHECKER_CONF_D ]]; then
+       CONFFILE=$HAL_ROOTSTRAP_CHECKER_CONF_D
+elif [[ -s $HAL_ROOTSTRAP_CHECKER_CONF ]]; then
+       CONFFILE=$HAL_ROOTSTRAP_CHECKER_CONF
+else
+       echo "No configuration has been specified. Skipping test"
+       exit 0
+fi
+
+# Naive yaml parser for configuration file
+KEY=""
+while read LINE; do
+       # Trim comment(#) and whitespace
+       LINE=$(echo "$LINE" | sed 's/#.*//')
+       LINE=$(echo "$LINE" | sed 's/^[[:space:]]*\(.*\)[[:space:]]*$/\1/')
+
+       if [[ -z "$LINE" ]]; then
+               continue
+       fi
+
+       VALUE=""
+       if [[ "$LINE" =~ ^(.*):\ (.*)$ ]]; then # 'key: value'
+               KEY="${BASH_REMATCH[1]}"
+               VALUE="${BASH_REMATCH[2]}"
+       elif [[ "$LINE" =~ ^(.*):$ ]]; then # 'key:'
+               KEY="${BASH_REMATCH[1]}"
+               VALUE=""
+       elif [[ "$LINE" =~ ^-\ (.*)$ ]]; then # '- value'
+               VALUE="${BASH_REMATCH[1]}"
+       fi
+
+       if [[ -z "$VALUE" ]]; then
+               continue
+       fi
+
+       case $KEY in
+               target_package_name)
+                       TARGET_PACKAGE_NAME+="$VALUE$IFS"
+                       ;;
+               excluded_target_package_name)
+                       EXCLUDED_TARGET_PACKAGE_NAME+="$VALUE$IFS"
+                       ;;
+               allowed_buildrequires)
+                       ALLOWED_BUILDREQUIRES+="$VALUE$IFS"
+                       ;;
+               allowed_requires)
+                       ALLOWED_REQUIRES+="$VALUE$IFS"
+                       ;;
+               check_always)
+                       CONFIGURATIONS[$KEY]="$VALUE"
+                       ;;
+               *)
+                       echo "Undefined key($KEY), skip the line: $LINE"
+                       ;;
+       esac
+done < $CONFFILE
+
+# Screen out packages that are not subject to the hal-rootstrap-checker
+SPECFILE=$(find $SOURCEDIR -name *.spec)
+if [[ $? != 0 ]]; then
+       echo "Cannot locate specfile for hal-rootstrap-checker"
+       exit 0
+fi
+
+CURRENT_PACKAGE_NAME=$(rpmspec -q --queryformat "[%{NAME}\n]" $SPECFILE | head -n 1)
+PATTERN_MATCHED=0
+for PATTERN in $TARGET_PACKAGE_NAME; do
+       if [[ $CURRENT_PACKAGE_NAME == $PATTERN ]]; then
+               PATTERN_MATCHED=1
+               break
+       fi
+done
+
+if [[ $PATTERN_MATCHED == 0 ]]; then
+       exit 0
+fi
+
+PATTERN_MATCHED=0
+for PATTERN in $EXCLUDED_TARGET_PACKAGE_NAME; do
+       if [[ $CURRENT_PACKAGE_NAME == $PATTERN ]]; then
+               PATTERN_MATCHED=1
+               break
+       fi
+done
+
+if [[ $PATTERN_MATCHED == 1 ]]; then
+       print_border
+       print_border
+
+       print_message "NOTICE: $CURRENT_PACKAGE_NAME is skipped from hal-rootstrap-checker"
+       print_message "NOTICE: as it has been specified at excluded_target_package_name."
+
+       print_border
+       print_border
+       exit 0
+fi
+
+# Parse specfile: Get BuildRequires
+SPECFILE_BUILDREQUIRES=""
+while read -r LINE; do
+       SPECFILE_BUILDREQUIRES+="$LINE$IFS"
+done <<< $(rpmspec -q --buildrequires $SPECFILE)
+
+# Parse specfile: Get Requires
+SPECFILE_REQUIRES=""
+while read -r LINE; do
+       SPECFILE_REQUIRES+="$LINE$IFS"
+done <<< $(rpmspec -q --queryformat "[%{REQUIRES}\n]" $SPECFILE)
+
+# Collect not allowed BuildRequires
+SPECFILE_NOT_ALLOWED_BUILDREQUIRES=""
+for BUILDREQUIRES in $SPECFILE_BUILDREQUIRES; do
+       IS_ALLOWED=0
+       for ALLOWED_PATTERN in $ALLOWED_BUILDREQUIRES; do
+               if [[ $BUILDREQUIRES == $ALLOWED_PATTERN ]]; then
+                       IS_ALLOWED=1
+                       break
+               fi
+       done
+
+       if [[ $IS_ALLOWED == 0 ]]; then
+               SPECFILE_NOT_ALLOWED_BUILDREQUIRES+="$BUILDREQUIRES$IFS"
+       fi
+done
+
+# Collect not allowed Requires
+SPECFILE_NOT_ALLOWED_REQUIRES=""
+for REQUIRES in $SPECFILE_REQUIRES; do
+       IS_ALLOWED=0
+       for ALLOWED_PATTERN in $ALLOWED_REQUIRES; do
+               if [[ $REQUIRES == $ALLOWED_PATTERN ]]; then
+                       IS_ALLOWED=1
+                       break
+               fi
+       done
+
+       if [[ $IS_ALLOWED == 0 ]]; then
+               SPECFILE_NOT_ALLOWED_REQUIRES+="$REQUIRES$IFS"
+       fi
+done
+
+# Check if there are not allowed BuildRequires
+if [[ ! -z $SPECFILE_NOT_ALLOWED_BUILDREQUIRES ]]; then
+       print_not_allowed_warning "BuildRequires" \
+               "$SPECFILE_NOT_ALLOWED_BUILDREQUIRES" \
+               "$ALLOWED_BUILDREQUIRES" \
+               "$CHECK_ALWAYS"
+fi
+
+# Check if there are not allowed Requires
+if [[ ! -z $SPECFILE_NOT_ALLOWED_REQUIRES ]]; then
+       print_not_allowed_warning "Requires" \
+               "$SPECFILE_NOT_ALLOWED_REQUIRES" \
+               "$ALLOWED_REQUIRES" \
+               "$CHECK_ALWAYS"
+fi
+
+# Check whether the test can be skipped
+if [[ $DISABLE_HAL_ROOTSTRAP_CHECKER != 0 && $CHECK_ALWAYS == "no" ]]; then
+       exit 0
+fi
+
+if [[ ! -z $SPECFILE_NOT_ALLOWED_BUILDREQUIRES || ! -z $SPECFILE_NOT_ALLOWED_REQUIRES ]]; then
+       exit 0 # Let them pass for now
+fi
diff --git a/packaging/hal-rootstrap-checker.yaml b/packaging/hal-rootstrap-checker.yaml
new file mode 100644 (file)
index 0000000..df94650
--- /dev/null
@@ -0,0 +1,24 @@
+# List of packages that are subject to the hal-rootstrap-checker.
+# Follow pattern matching of bash(1).
+target_package_name:
+    - hal-backend-*
+
+# List of packages that are exempt from the hal-rootstrap-checker.
+# It is applied on top of the above 'target_package_name'.
+# Follow pattern matching of bash(1).
+excluded_target_package_name:
+
+# List of packages that are allowed to be used as BuildRequires
+# Follow pattern matching of bash(1).
+allowed_buildrequires:
+    - cmake
+    - pkgconfig(hal-rootstrap)
+
+# List of packages that are allowed to be used as Requires
+# Follow pattern matching of bash(1).
+allowed_requires:
+
+# yes or no(default)
+# if no, you can skip the hal-rootstrap-checker test
+# by giving gbs build parameter, --define 'disable_hal_rootstrap_checker 1'.
+check_always: no
index 7fbb47f5f617d32249c0f4e5c453fe77d1b5e7af..56ab38d49e1d19e2537d648e5f752a27bb868df7 100644 (file)
@@ -9,6 +9,9 @@ Release:        1
 #Group: 
 License:       Apache-2.0
 Source0:       %{name}-%{version}.tar.gz
+Source1:       hal-rootstrap-checker.sh
+Source2:       hal-rootstrap-checker.yaml
+Source3:       hal-rootstrap-checker-rpmmacros
 AutoReqProv:    no
 
 BuildRequires: cmake
@@ -17,6 +20,10 @@ BuildRequires:       python3
 
 BuildRequires: hal-rootstrap-common
 
+### hal-rootstrap
+%description
+Package for rootstrap of hal
+
 ### hal-rootstrap-devel
 %package -n    %{devel_name}
 Summary:       %{name} interface
@@ -26,10 +33,14 @@ Requires:   %{name} = %{version}-%{release}
 %description -n        %{devel_name}
 %{name} Interface for product vendor developer
 
+### hal-rootstrap-checker
+%package checker
+Summary:       %{name} checker
+Group:         System/Base
+#Requires:     hal-rootstrap-checker-plugin-conf
 
-### hal-rootstrap
-%description
-Package for rootstrap of hal
+%description checker
+Checker for the hal rootstrap
 
 %prep
 %setup -q
@@ -47,6 +58,17 @@ mkdir -p %{buildroot}%{_libdir}/pkgconfig/
 cp packaging/hal-rootstrap.pc %{buildroot}%{_libdir}/pkgconfig/
 ./modify_pc.py "%{buildroot}%{_libdir}/pkgconfig/hal-rootstrap.pc" "%{buildroot}%{hal_rootstrap_install_path}/%{_libdir}/pkgconfig"
 
+mkdir -p %{buildroot}%{_sysconfdir}/hal/rootstrap
+install -m 755 %{SOURCE1} %{buildroot}%{_sysconfdir}/hal/rootstrap
+install -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/hal/rootstrap
+install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/hal/rootstrap
+
+%post checker
+ln -sf %{_sysconfdir}/hal/rootstrap/hal-rootstrap-checker-rpmmacros %{_sysconfdir}/rpm/macros.hal-rootstrap-checker
+
+%postun checker
+rm -f %{_sysconfdir}/rpm/macros.hal-rootstrap-checker
+
 %files
 %{hal_rootstrap_install_path}/etc/*
 %{hal_rootstrap_install_path}/lib*/*
@@ -58,3 +80,9 @@ cp packaging/hal-rootstrap.pc %{buildroot}%{_libdir}/pkgconfig/
 %{hal_rootstrap_install_path}/%{_includedir}/*
 %{hal_rootstrap_install_path}/%{_libdir}/pkgconfig/*.pc
 %{_libdir}/pkgconfig/*.pc
+
+%files checker
+%defattr(-,root,root,-)
+%{_sysconfdir}/hal/rootstrap/hal-rootstrap-checker.sh
+%{_sysconfdir}/hal/rootstrap/hal-rootstrap-checker.yaml
+%{_sysconfdir}/hal/rootstrap/hal-rootstrap-checker-rpmmacros