version_constraint.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #!/bin/bash
  2. ## configuration ##
  3. # NOTE: test data versions are extremely brittle - these will need adjustments routinely.
  4. # usually, these values will be the reported failed 'actual'. - `pacman -Syu` first!
  5. readonly OPENEXR_VER_MIN_PR_1=3
  6. readonly OPENEXR_VER_MIN_PR_2=3.2
  7. readonly OPENEXR_VER_MIN_PR_3=3.2.4
  8. readonly OPENEXR_VER_MIN_FULL=3.2.4-1
  9. readonly OPENSHADINGLANGUAGE_VER_MIN_PR_1=1
  10. readonly OPENSHADINGLANGUAGE_VER_MIN_PR_2=1.13
  11. readonly OPENSHADINGLANGUAGE_VER_MIN_PR_3=1.13.9
  12. readonly OPENSHADINGLANGUAGE_VER_MIN_PR_4=1.13.9.0
  13. readonly OPENSHADINGLANGUAGE_VER_MIN_FULL=1.13.9.0-1
  14. readonly WEBKIT2GTK_VER_MIN_FULL=2.44.2-1
  15. readonly QT5BASE_VER_MIN_PR_3=5.15.14
  16. readonly QT5BASE_VER_MIN_FULL=5.15.14+kde+r141-1
  17. readonly OPENCASCADE_VER_MIN_FULL=1:7.7.2-6
  18. readonly RED='\033[01;31m'
  19. readonly GREEN='\033[00;32m'
  20. readonly AQUA='\033[00;36m'
  21. readonly CEND='\033[00m'
  22. ## main function for PKGBUILDs ##
  23. # NOTE: A single `pacman` command for $full_version would fail, either for
  24. # $dep_pkgname with slash (-Ss) or for a circular dependency (-S --print).
  25. # PkgVersion() accommodates each, but still will fail for circular dependencies
  26. # with slash in $dep_pkgname. Those must be avoided.
  27. # FWIW, there is no package which pins to a dep package in an explicit repo.
  28. # Some (eg: libxfce4ui) do have the circular dependency use-case though.
  29. # TODO: There is no normal way to test for the circular dependency condition with pacman,
  30. # which would be distinguishable from the 'non-existent dep package' test.
  31. # Namely, that test should fail (empty result) for the right reason, where testing
  32. # for an actual example of the circular dependency (eg: libxfce4ui) would either
  33. # pass for the wrong reason most of the time (ie: it is satisfiable), or would fail
  34. # for the wrong reason if specifying a dep with a non-existent second-order dep.
  35. # This would need a different tool such as expac, or a prepared/contrived package DB.
  36. # The latter especially is a decent idea; because it would eliminate the maintenance
  37. # of the versioned test data constants.
  38. _version_constraint() # (dep_pkgname [precision])
  39. {
  40. Log() { [[ "${FUNCNAME[2]}" == package ]] && echo "$@" >&2 || : ; }
  41. PkgVersion()
  42. {
  43. if [[ "${dep_pkgname}" =~ / ]]
  44. then pacman -S --print-format='%v' ${dep_pkgname} 2> /dev/null | tail -n 1
  45. else pacman -Ss ^${dep_pkgname}$ | head -n 1 | cut -d ' ' -f 2
  46. fi
  47. }
  48. local dep_pkgname=$1
  49. declare -i req_precision=$2
  50. local full_version=$(PkgVersion)
  51. local n_dots=$(tmp=${full_version%-*} ; tmp=${tmp//[^\.]} ; echo "${#tmp}" ;)
  52. local def_precision=$(( n_dots + 1 ))
  53. local is_prec_valid=$(( req_precision > 0 && req_precision <= def_precision ))
  54. local precision=$((( is_prec_valid )) && echo ${req_precision} || echo ${def_precision})
  55. local epoch_rx='[0-9]+:'
  56. local pkgver_rx='[0-9A-Za-z_]+'
  57. pkgver_rx=$(sed 's|\]|\+]|' <<<${pkgver_rx}) # according to the wiki, '+' is not allowed,
  58. # but some pkgver have it (eg: 5.15.10+kde+r130)
  59. local subver_rx='\.'${pkgver_rx}
  60. local pkgrel_rx='[0-9]+'
  61. local garbage_rx='[^0-9].*'
  62. local capture_rx=${pkgver_rx}
  63. for (( n_dots=1 ; n_dots < precision ; ++n_dots )) ; do capture_rx+=${subver_rx} ; done ;
  64. local epoch version pkgrel has_dot_char version_min version_max constraint_string
  65. declare -i subver subver_inc pkgrel_inc
  66. if [[ "${full_version}" =~ ^(${epoch_rx})*(${capture_rx})(${subver_rx})*-(${pkgrel_rx}).*$ ]]
  67. then epoch=${BASH_REMATCH[1]} # optional epoch
  68. version=${BASH_REMATCH[2]} # pkgver cut to the requested precision
  69. #unused=${BASH_REMATCH[3]} # discarded pkgver segments
  70. pkgrel=${BASH_REMATCH[4]} # pkgrel with non-numerics right-trimmed
  71. has_dot_char=$([[ "${version}" =~ \. ]] ; echo $(( ! $? )) ; )
  72. subver=$(sed "s|${garbage_rx}||" <<<${version##*.}) # right-trim from any non-numeric
  73. version=$( (( has_dot_char )) && echo ${version%.*}.${subver} || echo ${subver} )
  74. version=${epoch}${version}
  75. subver_inc=$(( subver + 1 ))
  76. pkgrel_inc=$(( pkgrel + 1 ))
  77. version_min=$( (( ! is_prec_valid )) && echo ${full_version%-*}-${pkgrel} || \
  78. echo ${version} )
  79. version_max=$( ( (( ! is_prec_valid )) && echo ${full_version%-*}-${pkgrel_inc} ) || \
  80. ( [[ "${version}" =~ \. ]] && echo ${version%.*}.${subver_inc} ) || \
  81. echo ${subver_inc} )
  82. constraint_string="${dep_pkgname}>=${version_min} ${dep_pkgname}<${version_max}"
  83. Log "Applied version constraint: '${constraint_string}'"
  84. else Log "ERROR: in _version_constraint() parsing: dep_pkgname='${dep_pkgname}' full_version='${full_version}'"
  85. exit 1
  86. fi
  87. unset -f Log PkgVersion
  88. echo -n "${constraint_string}"
  89. }
  90. ## tests ##
  91. VerIncrement() # (version_string)
  92. {
  93. # NOTE This is not the same parsing logic as _version_constraint().
  94. # It is intended to be as simple as possible, only for the mock data.
  95. # Write a new test to verify anything novel or peculiar.
  96. local version_string=$1
  97. local has_pkgrel=$([[ "$1" =~ \- ]] ; echo $((! $?)) ;)
  98. local split_char=$((( has_pkgrel )) && echo '-' || echo '.')
  99. local has_split_char=$([[ "$1" =~ "${split_char}" ]] ; echo $(( ! $? )) ; )
  100. local unchanged_segment=${version_string%${split_char}*}
  101. declare -i incremented_segment=$(( ${version_string##*${split_char}} + 1 ))
  102. (( ! has_split_char )) || echo -n ${unchanged_segment}${split_char}
  103. echo ${incremented_segment}
  104. }
  105. readonly OPENEXR_VER_MAX_PR_1=$( VerIncrement ${OPENEXR_VER_MIN_PR_1} )
  106. readonly OPENEXR_VER_MAX_PR_2=$( VerIncrement ${OPENEXR_VER_MIN_PR_2} )
  107. readonly OPENEXR_VER_MAX_PR_3=$( VerIncrement ${OPENEXR_VER_MIN_PR_3} )
  108. readonly OPENEXR_VER_MAX_FULL=$( VerIncrement ${OPENEXR_VER_MIN_FULL} )
  109. readonly OPENSHADINGLANGUAGE_VER_MAX_PR_1=$(VerIncrement ${OPENSHADINGLANGUAGE_VER_MIN_PR_1})
  110. readonly OPENSHADINGLANGUAGE_VER_MAX_PR_2=$(VerIncrement ${OPENSHADINGLANGUAGE_VER_MIN_PR_2})
  111. readonly OPENSHADINGLANGUAGE_VER_MAX_PR_3=$(VerIncrement ${OPENSHADINGLANGUAGE_VER_MIN_PR_3})
  112. readonly OPENSHADINGLANGUAGE_VER_MAX_PR_4=$(VerIncrement ${OPENSHADINGLANGUAGE_VER_MIN_PR_4})
  113. readonly OPENSHADINGLANGUAGE_VER_MAX_FULL=$(VerIncrement ${OPENSHADINGLANGUAGE_VER_MIN_FULL})
  114. readonly WEBKIT2GTK_VER_MAX_FULL=$( VerIncrement ${WEBKIT2GTK_VER_MIN_FULL} )
  115. readonly QT5BASE_VER_MAX_PR_3=$( VerIncrement ${QT5BASE_VER_MIN_PR_3} )
  116. readonly QT5BASE_VER_MAX_FULL=$( VerIncrement ${QT5BASE_VER_MIN_FULL} )
  117. readonly OPENCASCADE_VER_MAX_FULL=$( VerIncrement ${OPENCASCADE_VER_MIN_FULL} )
  118. TestVersionConstraint() # ("pkgname" "precision" "expected_res")
  119. {
  120. PkgVersion()
  121. {
  122. if [[ "${dep_pkgname}" =~ / ]]
  123. then pacman -S --print-format='%v' ${dep_pkgname} 2> /dev/null | tail -n 1
  124. else pacman -Ss ^${dep_pkgname}$ | head -n 1 | cut -d ' ' -f 2
  125. fi
  126. }
  127. local dep_pkgname="$1"
  128. local precision="$2"
  129. local expected_res="$3"
  130. local actual_res="$(_version_constraint "${dep_pkgname}" "${precision}")"
  131. local full_version=$(PkgVersion)
  132. if [[ "${actual_res}" == "${expected_res}" ]]
  133. then echo -e "${GREEN}PASS <- ${dep_pkgname}${CEND}"
  134. else echo -e "${RED}FAIL <- ${dep_pkgname}${CEND}"
  135. echo -e "${AQUA} expected='${expected_res}'\n actual ='${actual_res}'${CEND}"
  136. echo "the current version of ${dep_pkgname} is ${full_version}"
  137. echo "note that the test data constants need routine tweaking"
  138. return 1
  139. fi
  140. }
  141. RunTests()
  142. {
  143. set -e
  144. precision=1 ; echo -e "\n=== precision='${precision}' ===" ;
  145. TestVersionConstraint 'openexr' "${precision}" "openexr>=${OPENEXR_VER_MIN_PR_1} openexr<${OPENEXR_VER_MAX_PR_1}"
  146. TestVersionConstraint 'openshadinglanguage' "${precision}" "openshadinglanguage>=${OPENSHADINGLANGUAGE_VER_MIN_PR_1} openshadinglanguage<${OPENSHADINGLANGUAGE_VER_MAX_PR_1}"
  147. precision=2 ; echo -e "\n=== precision='${precision}' ===" ;
  148. TestVersionConstraint 'openexr' "${precision}" "openexr>=${OPENEXR_VER_MIN_PR_2} openexr<${OPENEXR_VER_MAX_PR_2}"
  149. TestVersionConstraint 'openshadinglanguage' "${precision}" "openshadinglanguage>=${OPENSHADINGLANGUAGE_VER_MIN_PR_2} openshadinglanguage<${OPENSHADINGLANGUAGE_VER_MAX_PR_2}"
  150. precision=3 ; echo -e "\n=== precision='${precision}' ===" ;
  151. TestVersionConstraint 'openexr' "${precision}" "openexr>=${OPENEXR_VER_MIN_PR_3} openexr<${OPENEXR_VER_MAX_PR_3}"
  152. TestVersionConstraint 'openshadinglanguage' "${precision}" "openshadinglanguage>=${OPENSHADINGLANGUAGE_VER_MIN_PR_3} openshadinglanguage<${OPENSHADINGLANGUAGE_VER_MAX_PR_3}"
  153. precision=4 ; echo -e "\n=== precision='${precision}' ===" ;
  154. TestVersionConstraint 'openexr' "${precision}" "openexr>=${OPENEXR_VER_MIN_FULL} openexr<${OPENEXR_VER_MAX_FULL}"
  155. TestVersionConstraint 'openshadinglanguage' "${precision}" "openshadinglanguage>=${OPENSHADINGLANGUAGE_VER_MIN_PR_4} openshadinglanguage<${OPENSHADINGLANGUAGE_VER_MAX_PR_4}"
  156. precision= ; echo -e "\n=== full precision (default) ===" ;
  157. TestVersionConstraint 'openexr' "${precision}" "openexr>=${OPENEXR_VER_MIN_FULL} openexr<${OPENEXR_VER_MAX_FULL}"
  158. TestVersionConstraint 'openshadinglanguage' "${precision}" "openshadinglanguage>=${OPENSHADINGLANGUAGE_VER_MIN_FULL} openshadinglanguage<${OPENSHADINGLANGUAGE_VER_MAX_FULL}"
  159. precision= ; echo -e "\n=== non-existent dep package ===" ;
  160. TestVersionConstraint 'non-existent-package' "${precision}" ''
  161. precision= ; echo -e "\n=== specific repo ===" ;
  162. TestVersionConstraint 'extra/webkit2gtk' "${precision}" "extra/webkit2gtk>=${WEBKIT2GTK_VER_MIN_FULL} extra/webkit2gtk<${WEBKIT2GTK_VER_MAX_FULL}"
  163. precision=3 ; echo -e "\n=== non-numeric version ===" ;
  164. TestVersionConstraint 'qt5-base' "${precision}" "qt5-base>=${QT5BASE_VER_MIN_PR_3} qt5-base<${QT5BASE_VER_MAX_PR_3}"
  165. precision= ; echo -e "\n=== non-numeric version - full precision (default) ===" ;
  166. TestVersionConstraint 'qt5-base' "${precision}" "qt5-base>=${QT5BASE_VER_MIN_FULL} qt5-base<${QT5BASE_VER_MAX_FULL}"
  167. precision= ; echo -e "\n=== version with epoch ===" ;
  168. TestVersionConstraint 'opencascade' "${precision}" "opencascade>=${OPENCASCADE_VER_MIN_FULL} opencascade<${OPENCASCADE_VER_MAX_FULL}"
  169. # TODO:
  170. # precision= ; echo -e "\n=== pinned circular dependency ===" ;
  171. # TestVersionConstraint 'unsatisfiable-dep' "${precision}" "circular-dep>=${CIRCULARDEP_VER_MIN_FULL} circular-dep>=${CIRCULARDEP_VER_MAX_FULL}"
  172. }
  173. RunTests