#!/bin/bash # test00_specsyntax -- @package@ test (syntax checks of a specfile) # Copyright (C) 2012-2013 Davide Madrisan [ -z "$BASH" ] || [ ${BASH_VERSION:0:1} -lt 2 ] && echo $"this script requires bash version 2 or better" >&2 && exit 1 me=("test00_specsyntax" "@version@" "@date@") [ -r @libdir@/libmsgmng.lib ] || { echo "$me: "$"library not found"": @libdir@/libmsgmng.lib" 1>&2 exit 1; } . @libdir@/libmsgmng.lib [ -r @libdir@/libtranslate.lib ] || { echo "$me: "$"library not found"": @libdir@/libtranslate.lib" 1>&2 exit 1; } . @libdir@/libtranslate.lib notify.debug $"loading"": \`test00_specsyntax'..." # check if all the needed tools are available for tool in cat file getopt grep sed; do [ "$(type -p $tool)" ] || notify.error $"utility not found"": \`$tool'" done # function specfile.checksyntax() # do some syntax checks in the specfile of the building package # args: # $1 : specfile name # $2, ... : execute these check numbers (optional, default = all checks) function specfile.checksyntax() { local i rpmvar specfile="$1" [[ "$specfile" ]] || notify.error $"\ (bug)"" -- $FUNCNAME: "$"missing mandatory arg"" (#1)" notify.debug "$FUNCNAME: specfile = \"$specfile\"" notify.note " * $specfile" local total_issues=0 local user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/132.0" # 0. checking if 'Source[0]' is a valid internet address # (skip this test if no '%setup' section has been found) test.skip $test_number || { notify.note "$(test.num2str). ${NOTE}"\ "url""${NORM}..." if [[ "$SPEC_URL" ]]; then { notify.debug "\ \`url': "$"checking Source URL with: ""\`curl -s -o /dev/null -w \"%{http_code}\" -A \"${user_agent}\" $SPEC_URL'" } http_code=`curl -s -o /dev/null -w "%{http_code}" -A "${user_agent}" $SPEC_URL` if [ "$http_code" != "200" ]; then if [ "${http_code:0:2}" == "30" ]; then http_effective_url=`curl -w "%{url_effective}" -I -L -s -o /dev/null -A "${user_agent}" -S $SPEC_URL` { notify.warning "\ \`url': "$"redirect detected: replacing from \`$SPEC_URL' to \`${http_effective_url}'" let "total_issues += 1"; } sed -i "s|^\(URL:[[:space:]]*\)$SPEC_URL.*|\1${http_effective_url}|" $specfile else { notify.error "\ \`url': "$"invalid return code for \`$SPEC_URL': $http_code" let "total_issues += 1"; } fi fi fi; } test_number=$(($test_number + 1)) # 1. checking if 'Source[0]' is a valid internet address # (skip this test if no '%setup' section has been found) test.skip $test_number || { grep -q "^%setup[ \t]*$\|^%setup[ \t]\+" $specfile if [ $? -eq 0 ]; then notify.note "$(test.num2str). ${NOTE}"\ "source0""${NORM}..." if [[ "$source0_name_structure" ]]; then specfile.getvars -s $specfile --verbatim SPEC_SOURCE0 if [[ "$SPEC_SOURCE0_VERBATIM" ]]; then [[ "$(echo "$SPEC_SOURCE0_VERBATIM" | \ grep -e "$source0_name_structure")" ]] || { notify.warning "\ \`Source[0]': "$"does not point to a valid internet address" let "total_issues += 1"; } fi fi fi; } test_number=$(($test_number + 1)) # 2. check if the patches have standard names # (see the 'patch_name_structure' var in the configure file) test.skip $test_number || { notify.note "$(test.num2str). ${NOTE}"\ $"patch""${NORM}..." specfile.getvars -s $specfile --verbatim SPEC_PATCH echo "${SPEC_PATCH_VERBATIM[@]}" | \ for i in `seq 1 1 ${#SPEC_PATCH_VERBATIM[@]}`; do [[ "${SPEC_PATCH_VERBATIM[$i-1]}" =~ \ $patch_name_structure ]] || { notify.warning "\ patch $i (\`${NOTE}${SPEC_PATCH_VERBATIM[$i-1]}${NORM}') " notify.warning $"\ not a standard structure (see config file)"; let "total_issues += 1"; } done; } test_number=$(($test_number + 1)) # 3. check if `%setup' have `-D' and/or `-T' options test.skip $test_number || { notify.note "$(test.num2str). ${NOTE}"\ "%setup""${NORM}..." [[ "$(cat $specfile | \ sed -n "/%setup/{/-D /p;/-T /p;/-D$/p;/-T$/p}")" ]] && { notify.warning $"\ found \`-D' and/or \`-T' option(s) in the \`%setup' directive" let "total_issues += 1"; } } test_number=$(($test_number + 1)) # 4. check if all the `%files' blocks have a `%defattr' line # note: skip commented out blocks test.skip $test_number || { notify.note "$(test.num2str). ${NOTE}"\ "%defattr""${NORM}..." [[ "$(sed -e ' # print paragraph if it contains "%files" and "%defattr" /./{H;$!d;}' -e 'x;/%files/!d;/%defattr/!d' $specfile | \ grep "^[[:space:]]*%files")" != \ "$(grep "^[[:space:]]*%files" $specfile)" ]] && { notify.error $"\ missing at least one \`%defattr' directive" let "total_issues += 1"; } } test_number=$(($test_number + 1)) # 5. check if the rpm macros %configure, %make are used # - look in the block : `%build' to `%install' test.skip $test_number || { notify.note "$(test.num2str). ${NOTE}"\ "%build, %install""${NORM}..." local token tokens sed -n '/%build/,/%install/p' $specfile | \ while read -a tokens; do # ignore comments [[ "${tokens[0]}" =~ ^\# ]] && continue for token in ${tokens[*]}; do case "$token" in configure|./configure) [[ "$rpm_macro_configure" ]] && { notify.warning $"\ use rpm macros if possible:"" \`$token' --> \`$rpm_macro_configure'" let "total_issues += 1"; } ;; make) [[ "$rpm_macro_make" ]] && { notify.warning \ $"use rpm macros if possible:""${NORM} $token --> $rpm_macro_make" let "total_issues += 1"; } ;; esac done done # do check between`%install' and `%changelog' sed -n '/%install/,/%changelog/p' $specfile | \ while read -a tokens; do # ignore comments [[ "${tokens[0]}" =~ ^\# ]] && continue for token in ${tokens[*]}; do case "$token" in "make") [[ "$rpm_macro_make" ]] && { notify.warning \ $"use rpm macros if possible:""${NORM} $([[ "$rpm_macro_makeinstall" ]] && echo " make install -> $rpm_macro_makeinstall" [[ "$rpm_macro_makeoldinstall" ]] && echo " make install -> $rpm_macro_makeoldinstall" )" } ;; esac done done; } test_number=$(($test_number + 1)) # 6. check if '%find_lang' is used when localization files are detected test.skip $test_number || { notify.note "$(test.num2str). ${NOTE}%find_lang${NORM}..." # FIXME : the test should perhaps be improved... grep -q "^[ ]*[^# ]*/share/locale/" $specfile && { notify.error $"\ "$"localization files must be packaged via \`%find_lang'""${NORM} --------------------------------------- ${NOTE}"$"Hint"":${NORM} %install ... %find_lang %{name} %files -f %{name}.lang --------------------------------------- " let "total_issues += 1"; } } test_number=$(($test_number + 1)) # 7. check for illegal 'Group's (see configuration file) test.skip $test_number || { if [ "${#rpm_allowed_groups[*]}" = 0 ]; then # 'rpm_allowed_groups' unset in the configuration files notify.note "$(test.num2str). ${NOTE}"\ $"package Groups""${NORM}..."" "$"skipped" else notify.note "$(test.num2str). ${NOTE}"\ $"package Groups""${NORM}..." local i j match for j in `seq 1 1 ${#SPEC_GROUP[*]}`; do notify.debug "\ $FUNCNAME: checking if \"${SPEC_GROUP[$j-1]}\" is a known group ..." let "match = 0" for i in `seq 1 1 ${#rpm_allowed_groups[*]}`; do notify.debug "\ $FUNCNAME: current group: \"${rpm_allowed_groups[$i-1]}\"" [ "${rpm_allowed_groups[$i-1]}" = \ "${SPEC_GROUP[$j-1]}" ] && { let "match = 1"; break; } done [ "$match" = 1 ] || { notify.error "\ "$"invalid \`Group'"" \"${SPEC_GROUP[$j-1]}\"""${NORM} --------------------------------------- ${NOTE}"$"Hint"":${NORM}"" "$"see configuration files"" (\`${NOTE}rpm_allowed_groups${NORM}') "$"or enter the command"": ${NOTE}@package@ --eval=rpm_allowed_groups${NORM} --------------------------------------- " let "total_issues += 1"; } done fi; } test_number=$(($test_number + 1)) # 8. check for no approved 'License's (see configuration file) test.skip $test_number || { if [ "${#rpm_approved_licenses[*]}" = 0 ]; then # 'rpm_approved_licenses' unset in the configuration files notify.note "$(test.num2str). ${NOTE}"\ $"approved License""${NORM}..."" "$"skipped" else notify.note "$(test.num2str). ${NOTE}"\ $"approved License""${NORM}..." local i j match for j in `seq 1 1 ${#SPEC_LICENSE[*]}`; do notify.debug "\ $FUNCNAME: checking if \"${SPEC_LICENSE[$j-1]}\" is an approved license ..." let "match = 0" for i in `seq 1 1 ${#rpm_approved_licenses[*]}`; do notify.debug "\ $FUNCNAME: current license: \"${rpm_approved_licenses[$i-1]}\"" [ "${rpm_approved_licenses[$i-1]}" = \ "${SPEC_LICENSE[$j-1]}" ] && { let "match = 1"; break; } done [ "$match" = 1 ] || { notify.warning "\ "$"not approved \`License'"" \"${NOTE}${SPEC_LICENSE[$j-1]}${NORM}\""" --------------------------------------- ${NOTE}"$"Hint"":${NORM}"" "$"see configuration files"" (\`${NOTE}rpm_approved_licenses${NORM}') "$"or enter the command"": ${NOTE}@package@ --eval=rpm_approved_licenses${NORM} --------------------------------------- " let "total_issues += 1"; } done fi; } test_number=$(($test_number + 1)) notify.note " --> "$"${NOTE}Specfile checks: ${NORM}\ ${WARN}$total_issues${NORM} ${NOTE}warnings.${NORM}"" " return $total_issues }