diff options
-rwxr-xr-x | bin/bootstrap-mysql | 112 | ||||
-rwxr-xr-x | bin/build-master-status-from-mysql | 54 | ||||
-rwxr-xr-x | bin/common-functions | 27 | ||||
-rwxr-xr-x | bin/db-update | 60 | ||||
-rwxr-xr-x | bin/delete-packages | 2 | ||||
-rwxr-xr-x | bin/get-assignment | 15 | ||||
-rwxr-xr-x | bin/get-package-updates | 39 | ||||
-rwxr-xr-x | bin/ii-connect | 12 | ||||
-rwxr-xr-x | bin/mysql-functions | 266 | ||||
-rwxr-xr-x | bin/opcode | 49 | ||||
-rwxr-xr-x | bin/return-assignment | 115 | ||||
-rwxr-xr-x | bin/sanity-check | 8 | ||||
-rwxr-xr-x | bin/seed-build-list | 7 | ||||
-rwxr-xr-x | bin/slave-build-connect | 9 | ||||
-rwxr-xr-x | conf/default.conf | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | lib/opcode_list (renamed from conf/Opcode_list) | 0 | ||||
-rw-r--r-- | web-scripts/broken-packages.php | 157 | ||||
-rw-r--r-- | web-scripts/build-slaves.php | 44 | ||||
-rw-r--r-- | web-scripts/packages.php | 20 | ||||
-rw-r--r-- | web-scripts/statistics.php | 179 |
20 files changed, 948 insertions, 229 deletions
diff --git a/bin/bootstrap-mysql b/bin/bootstrap-mysql index 3069863..46678f7 100755 --- a/bin/bootstrap-mysql +++ b/bin/bootstrap-mysql @@ -2,12 +2,26 @@ # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" -# shellcheck source=bin/mysql-functions -. "${base_dir}/bin/mysql-functions" tmp_dir=$(mktemp -d 'tmp.bootstrap-mysql.XXXXXXXXXX' --tmpdir) trap 'rm -rf --one-file-system "${tmp_dir}"' EXIT +exec 9> "${build_list_lock_file}" +if ! flock -n 9; then + >&2 echo 'Cannot get build-list lock.' + exit 1 +fi +exec 8> "${sanity_check_lock_file}" +if ! flock -s -n 9; then + >&2 echo 'Cannot get sanity-check lock.' + exit 1 +fi +exec 7> "${package_database_lock_file}" +if ! flock -s -n 7; then + >&2 echo 'Cannot get package-database lock.' + exit 1 +fi + for dir in $(ls_master_mirror 'i686'); do ls_master_mirror "i686/${dir}" | \ sed ' @@ -49,8 +63,8 @@ if [ ! "$1" = 'slim' ]; then ' is_tested BIT' \ ' pkgname VARCHAR(64)' \ ' architecture SMALLINT :architectures' \ - ' UNIQUE content build_assignment sub_pkgrel pkgname architecture' \ - ' UNIQUE file_name pkgname epoch pkgver pkgrel sub_pkgrel architecture' \ + ' UNIQUE content build_assignment sub_pkgrel pkgname architecture repository' \ + ' UNIQUE file_name pkgname epoch pkgver pkgrel sub_pkgrel architecture repository' \ 'repositories MEDIUMINT' \ ' name VARCHAR(64)' \ ' stability MEDIUMINT :repository_stabilities' \ @@ -97,7 +111,18 @@ if [ ! "$1" = 'slim' ]; then ' head VARCHAR(40)' \ ' UNIQUE name' \ ' UNIQUE url' \ - ' UNIQUE directory' + ' UNIQUE directory' \ + 'fail_reasons SMALLINT' \ + ' name VARCHAR(32)' \ + ' identifier VARCHAR(64)' \ + ' severity SMALLINT' \ + ' UNIQUE name' \ + 'failed_builds MEDIUMINT' \ + ' build_slave MEDIUMINT :build_slaves' \ + ' build_assignment BIGINT :build_assignments' \ + ' date DATETIME' \ + ' reason SMALLINT :fail_reasons' \ + ' log_file VARCHAR(512)' ) { @@ -195,6 +220,9 @@ if [ ! "$1" = 'slim' ]; then 'SELECT' 'buildmaster.*' \ 'UPDATE' 'buildmaster.*' \ 'RELOAD' '*.*' + printf 'GRANT %s ON %s TO '"'"'http'"'"'@'"'"'localhost'"'"';\n' \ + 'SHOW VIEW' 'buildmaster.*' \ + 'SELECT' 'buildmaster.*' printf 'FLUSH PRIVILEGES;\n' } | \ mysql -u root -p buildmaster @@ -208,6 +236,47 @@ fi sed 's|,$||' printf ';\n' # shellcheck disable=SC2016 + printf 'INSERT IGNORE INTO `fail_reasons` (`identifier`,`name`,`severity`) VALUES ' + printf '(from_base64("%s"),"%s",%s),' \ + "$( + printf '%s' '==> ERROR: A failure occurred in build()\.' | \ + base64 -w0 + )" 'build()' 0 \ + "$( + printf '%s' '==> ERROR: Could not download sources\.' | \ + base64 -w0 + )" 'source' 1 \ + "$( + printf '%s' '.*error: failed to commit transaction (invalid or corrupted package)' | \ + base64 -w0 + )" 'package-cache' 2 \ + "$( + printf '%s' '==> ERROR: A failure occurred in prepare()\.' | \ + base64 -w0 + )" 'prepare()' 2 \ + "$( + printf '%s' '==> ERROR: A failure occurred in package\(_\S\+\)\?()\.' | \ + base64 -w0 + )" 'package()' 3 \ + "$( + printf '%s' '==> ERROR: A failure occurred in check()\.' | \ + base64 -w0 + )" 'check()' 4 \ + "$( + printf '%s' '==> ERROR: '"'"'pacman'"'"' failed to install missing dependencies\.' | \ + base64 -w0 + )" 'dependencies' 1 \ + "$( + printf '%s' '==> ERROR: Running makepkg as root is not allowed as it can cause permanent,.*' | \ + base64 -w0 + )" 'run-as-root' 1 \ + "$( + printf '.*' | \ + base64 -w0 + )" 'unknown' 100 | \ + sed 's|,$||' + printf ';\n' + # shellcheck disable=SC2016 printf 'INSERT IGNORE INTO `git_repositories` (`name`,`url`,`directory`,`head`) VALUES' { for repo in ${repo_names}; do @@ -307,7 +376,8 @@ fi 'testing' '"Packages:Testing"' \ 'staging' 'NULL' \ 'standalone' 'NULL' \ - 'unbuilt' '"Packages:Build-list"' + 'unbuilt' '"Packages:Build-list"' \ + 'forbidden' 'NULL' printf ';\n' } | \ sed 's|,;|;|' @@ -321,7 +391,8 @@ fi 'community-testing:testing:AQ==' \ 'staging:staging:AQ==' \ 'community-staging:staging:AQ==' \ - 'build-list:unbuilt:AA=='; do + 'build-list:unbuilt:AA==' \ + 'deletion-list:forbidden:AA=='; do # shellcheck disable=SC2016 printf 'INSERT IGNORE INTO `repositories` (`name`,`stability`,`is_on_master_mirror`) SELECT' # shellcheck disable=SC2016 @@ -363,6 +434,7 @@ find "${work_dir}/package-states" \ -name '*.tested' \ \) \ -exec sed ' + 1!d s@^.*-\([^-]\+\)-\([^-.]\+\)\.pkg\.tar\.xz$@{} \1 \2 \0@ s@^\S*/@@ s/^\(\S\+\)\.\(done\|testing\|tested\) /\1 / @@ -390,6 +462,32 @@ tr ' ' '.' < \ mysql_generate_package_metadata "${state_file}" done +# shellcheck disable=SC2016 +find "${work_dir}/package-states" -name '*.blocked' -printf '%p %f\n' | \ + sed ' + s|\.\([^. ]\+\)\.\([^. ]\+\)\.\([^. ]\+\)\.blocked$| \1 \2 \3| + ' | \ + while read -r state_file pkgbase git_revision mod_git_revision repository; do + printf 'UPDATE `build_assignments`' + printf ' JOIN `%s` ON `%s`.`id`=`%s`.`%s`' \ + 'package_sources' 'package_sources' 'build_assignments' 'package_source' \ + 'upstream_repositories' 'upstream_repositories' 'package_sources' 'upstream_package_repository' + printf ' SET `build_assignments`.`is_blocked`=from_base64("%s")' \ + "$( + tr -d '\n' < \ + "${state_file}" | \ + base64 -w0 + )" + printf ' WHERE' + printf ' `package_sources`.`%s`=from_base64("%s") AND' \ + 'pkgbase' "$(printf '%s' "${pkgbase}" | base64 -w0)" \ + 'git_revision' "$(printf '%s' "${git_revision}" | base64 -w0)" \ + 'mod_git_revision' "$(printf '%s' "${mod_git_revision}" | base64 -w0)" + printf ' `upstream_repositories`.`name`=from_base64("%s");\n' \ + "$(printf '%s' "${repository}" | base64 -w0)" + done | \ + ${mysql_command} + grep '^\('"$( # shellcheck disable=SC2086 printf '%s\\|' ${standalone_package_repositories} ${stable_package_repositories} diff --git a/bin/build-master-status-from-mysql b/bin/build-master-status-from-mysql index 6dacc5e..a0c2b4f 100755 --- a/bin/build-master-status-from-mysql +++ b/bin/build-master-status-from-mysql @@ -4,36 +4,32 @@ # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" -# shellcheck source=bin/mysql-functions -. "${base_dir}/bin/mysql-functions" -# shellcheck disable=SC2016 -${mysql_command} -e ' - SELECT `build_slaves`.`name`,`build_slaves`.`operator`,`package_sources`.`pkgbase`,`build_slaves`.`last_connection` - FROM `build_slaves` - LEFT JOIN `build_assignments` ON - `build_slaves`.`currently_building`=`build_assignments`.`id` - LEFT JOIN `package_sources` ON - `build_assignments`.`package_source`=`package_sources`.`id` - ORDER BY `build_slaves`.`last_connection` -' --html | \ - sed ' - s,</TR>,\0\n,g - ' | \ - sed ' - \,</TH></TR>$, { - s,<TH>pkgbase</TH>,<TH>currently building</TH>, - y,_, , - } - \,</TH></TR>$, ! { - s,<TD>NULL</TD>,<TD>\ </TD>, - } - 1 i <html><head><title>list of build slaves</title></head><body> - $ a </body></html> - ' | \ - sponge "${webserver_directory}/build-slaves.html" - -mysql_sanity_check | \ +{ + mysql_sanity_check || true + { + # shellcheck disable=SC2016 + { + printf 'SELECT `package_sources`.`pkgbase`,`package_sources`.`git_revision`,`package_sources`.`mod_git_revision`,`upstream_repositories`.`name`' + printf ' FROM `package_sources`' + printf ' JOIN `%s` ON `%s`.`%s`=`%s`.`id`' \ + 'upstream_repositories' 'package_sources' 'upstream_package_repository' 'upstream_repositories' \ + 'build_assignments' 'build_assignments' 'package_source' 'package_sources' \ + 'binary_packages' 'binary_packages' 'build_assignment' 'build_assignments' \ + 'repositories' 'binary_packages' 'repository' 'repositories' + printf ' WHERE `repositories`.`name`="build-list"' + } | \ + ${mysql_command} --batch | \ + sed ' + 1d + y/\t/ / + s/^/+ / + ' + sed 's/^/- /' "${work_dir}/build-list" + } | \ + sort -k2 -k1,1 | \ + uniq -uf1 +} | \ sed ' s,^-.*$,<font color="#FF0000">\0</font>, s,^+.*$,<font color="#00FF00">\0</font>, diff --git a/bin/common-functions b/bin/common-functions index 1fd5db7..d5b6eaa 100755 --- a/bin/common-functions +++ b/bin/common-functions @@ -522,7 +522,7 @@ remove_old_package_versions() { ' | \ sort -u > \ "${tmp_dir}/packages-to-delete" - # this file contains a list of packages to be delete, one on each line: + # this file contains a list of packages to be deleted, one on each line: # $architecture-directory $repository-directory $package-name $pkgver-$pkgrel-$package-architecture.pkg.tar.xz cut -d' ' -f1,2 < \ @@ -560,6 +560,30 @@ remove_old_package_versions() { done < \ "${tmp_dir}/repositories-to-modify" + # shellcheck disable=SC2016 + sed ' + s/\.pkg\.tar\.xz$// + s/^\S\+ // + s/-\([^-. ]\+\)\(-[^- ]\+\)$/-\1.0\2/ + s/ \([^-: ]\+\(-[^- ]\+\)\{2\}\)$/ 0:\1/ + s/ \([^-.]\+\):\([^-:]\+\)-\([^-.]\+\)\.\([^-.]\+\)-\([^-]\+\)$/ \1 \2 \3 \4 \5/ + ' "${tmp_dir}/packages-to-delete" | \ + while read -r repo pkgname epoch pkgver pkgrel sub_pkgrel arch; do + printf 'DELETE FROM `binary_packages` WHERE' + printf ' `binary_packages`.`%s`=(SELECT `%s`.`id` FROM `%s` WHERE `%s`.`name`=from_base64("%s")) AND' \ + 'architecture' 'architectures' 'architectures' 'architectures' "$(printf '%s' "${arch}" | base64 -w0)" \ + 'repository' 'repositories' 'repositories' 'repositories' "$(printf '%s' "${repo}" | base64 -w0)" + printf ' `binary_packages`.`%s`=from_base64("%s") AND' \ + 'pkgname' "$(printf '%s' "${pkgname}" | base64 -w0)" \ + 'epoch' "$(printf '%s' "${epoch}" | base64 -w0)" \ + 'pkgver' "$(printf '%s' "${pkgver}" | base64 -w0)" \ + 'pkgrel' "$(printf '%s' "${pkgrel}" | base64 -w0)" \ + 'sub_pkgrel' "$(printf '%s' "${sub_pkgrel}" | base64 -w0)" | \ + sed 's/ AND$//' + printf ';\n' + done | \ + ${mysql_command} + sed ' s| \(\S\+\)$|-\1| y| |/| @@ -1233,6 +1257,7 @@ next_sub_pkgrel() { git_repo=$(find_git_repository_to_package_repository "${repository}") temp_dir=$(mktemp -d 'tmp.common-functions.next_sub_pkgrel.XXXXXXXXXX' --tmpdir) + trap 'rm -rf --one-file-system "${temp_dir}"' EXIT find_pkgbuilds "${package}" "${repository}" "${git_repo}" "${git_revision}" "${mod_git_revision}" extract_source_directory "${git_repo}" "${git_revision}" "${mod_git_revision}" "${temp_dir}" '0' diff --git a/bin/db-update b/bin/db-update index 827dc05..fe45f41 100755 --- a/bin/db-update +++ b/bin/db-update @@ -20,6 +20,12 @@ # track packages in stable, too # know _exactly_ in which repository the packages are +# TODO: fully integrate database (in other scripts too) - e.g. rely on +# info in db instead of state-files + +# TODO: add possibility to manually clone a (binary) package (e.g. +# for build-support) - this should also be possible via email + # shellcheck disable=SC2039 # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" @@ -160,7 +166,7 @@ move_packages() { exit 2 fi done < \ - "${tmp_dir}/tmp/${package}.parts" + "${tmp_dir}/tmp/${package}.parts_and_signatures" mkdir -p "${tmp_dir}/tmp/${from_repo}" mkdir -p "${tmp_dir}/tmp/${to_repo}" @@ -323,9 +329,55 @@ move_packages() { done < \ "${tmp_dir}/tmp/packages" - if ! ${no_action}; then - ${dummynator} trigger_mirror_refreshs - fi + # shellcheck disable=SC2016 + while read -r package; do + while read -r part; do + printf 'UPDATE `binary_packages`' + printf ' JOIN `repositories` ON `binary_packages`.`repository`=`repositories`.`id`' + printf ' JOIN `architectures` ON `binary_packages`.`architecture`=`architectures`.`id`' + printf ' SET `binary_packages`.`repository`=(SELECT `repositories`.`id` FROM `repositories` WHERE `repositories`.`name`=from_base64("%s"))' \ + "$( + base64_encode_each < \ + "${tmp_dir}/tmp/${package}.to_repo" + )" + printf ' WHERE' + printf ' `repositories`.`name`=from_base64("%s")' \ + "$( + base64_encode_each < \ + "${tmp_dir}/tmp/${package}.from_repo" + )" + printf '%s\n' "${part}" | \ + sed ' + s/\.pkg\.tar\.xz$// + s/-\([^-.]\+\)\(-[^-]\+\)$/-\1.0\2/ + s/-\([^-:]\+\)\(\(-[^-]\+\)\{2\}\)$/-0:\1\2/ + s/^\(.\+\)-\([^-:]\+\):\([^-:]\+\)-\([^-.]\+\)\.\([^-.]\+\)-\([^-]\+\)$/\1\n\2\n\3\n\4\n\5\n\6/ + ' | \ + base64_encode_each | \ + tr '\n' ' ' | \ + sed ' + s,\(\S\+\) \(\S\+\) \(\S\+\) \(\S\+\) \(\S\+\) \(\S\+\) $,'"$( + printf ' AND `binary_packages`.`%s`=from_base64("%s")' \ + 'pkgname' '\1' \ + 'epoch' '\2' \ + 'pkgver' '\3' \ + 'pkgrel' '\4' \ + 'sub_pkgrel' '\5' + printf ' AND `architectures`.`name`=from_base64("\\6")' + )"', + ' + printf ';\n' + done < \ + "${tmp_dir}/tmp/${package}.parts" + done < \ + "${tmp_dir}/tmp/packages" | \ + if ${no_action}; then + sed 's|^|mysql: |' + else + ${mysql_command} + fi + + ${dummynator} trigger_mirror_refreshs rm -rf --one-file-system "${tmp_dir:?}/tmp" diff --git a/bin/delete-packages b/bin/delete-packages index a6e3f14..26d323a 100755 --- a/bin/delete-packages +++ b/bin/delete-packages @@ -13,6 +13,8 @@ # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" +# TODO: finish this + # shellcheck disable=SC2016 usage() { >&2 echo '' diff --git a/bin/get-assignment b/bin/get-assignment index a81a54d..d256248 100755 --- a/bin/get-assignment +++ b/bin/get-assignment @@ -50,33 +50,26 @@ hand_out_assignment() { } | \ sort -u | \ sponge "${work_dir}/package-states/$1.$2.$3.$4.locked" - ${mysql_command} -e "$( - # shellcheck disable=SC2016 + # shellcheck disable=SC2016 + { printf 'UPDATE `build_slaves`' - # shellcheck disable=SC2016 printf ' SET `currently_building` = (' - # shellcheck disable=SC2016 printf ' SELECT `build_assignments`.`id`' - # shellcheck disable=SC2016 printf ' FROM `build_assignments`' - # shellcheck disable=SC2016 printf ' JOIN `package_sources` ON `build_assignments`.`package_source`=`package_sources`.`id`' - # shellcheck disable=SC2016 printf ' JOIN `upstream_repositories` ON `package_sources`.`upstream_package_repository`=`upstream_repositories`.`id`' printf ' WHERE' - # shellcheck disable=SC2016 printf ' `package_sources`.`%s` = from_base64("%s") AND' \ 'pkgbase' "$(printf '%s' "$1" | base64 -w0)" \ 'git_revision' "$(printf '%s' "$2" | base64 -w0)" \ 'mod_git_revision' "$(printf '%s' "$3" | base64 -w0)" - # shellcheck disable=SC2016 printf ' `upstream_repositories`.`name` = from_base64("%s")' \ "$(printf '%s' "$4" | base64 -w0)" printf ')' - # shellcheck disable=SC2016 printf ' WHERE `build_slaves`.`name`=from_base64("%s");' \ "$(printf '%s' "${slave}" | base64 -w0)" - )" + } | \ + ${mysql_command} # lock every loop this package breaks find "${work_dir}/build-list.loops" -maxdepth 1 -regextype grep \ diff --git a/bin/get-package-updates b/bin/get-package-updates index cbe8b14..801aadd 100755 --- a/bin/get-package-updates +++ b/bin/get-package-updates @@ -9,6 +9,10 @@ # TODO: Find out, why sometimes package updates are missed. +# TODO: mark loops in mysql database + +# TODO: test_exclusion does not yet cooperate with the database + # shellcheck disable=SC2016 usage() { >&2 echo '' @@ -54,7 +58,7 @@ do -x|--test-exclusion) shift if [ -n "${test_exclusion}" ]; then - >&2 printf 'I already have --test-exlusion=%s and you gave me another one.\n' "${test_exclusion}" + >&2 printf 'I already have --test-exclusion=%s and you gave me another one.\n' "${test_exclusion}" >&2 printf 'But I can only handle one exclusion test at a time.\n' exit 2 fi @@ -88,6 +92,20 @@ delete_package() { echo "$1" >> \ "${work_dir}/deletion-list.new" sed -i "/^$(str_to_regex "${1}") /d" "${work_dir}/build-list.new" + # shellcheck disable=SC2016 + { + printf 'UPDATE `binary_packages`' + printf ' JOIN `%s` ON `%s`.`id`=`binary_packages`.`%s`' \ + 'repositories' 'repositories' 'repository' \ + 'build_assignments' 'build_assignments' 'build_assignment' + printf ' JOIN `%s` ON `%s`.`id`=`%s`.`%s`' \ + 'package_sources' 'package_sources' 'build_assignments' 'package_source' + printf ' SET `binary_packages`.`repository`=(SELECT `repositories`.`id` FROM `repositories` WHERE `repositories`.`name`="deletion-list")' + printf ' WHERE `repositories`.`name`="build-list"' + printf ' AND `package_sources`.`pkgbase`=from_base64("%s");' \ + "$(printf '%s' "$1" | base64 -w0)" + } | \ + ${mysql_command} } # create tmp_dir and trap @@ -268,6 +286,25 @@ done | \ echo "${package} ${git_revision} ${new_repo_revisions__archlinux32} ${repository}" >> \ "${work_dir}/build-list.new" sed -i "/^$(str_to_regex "${package}")\$/d" "${work_dir}/deletion-list.new" + # shellcheck disable=SC2016 + { + # delete old build assignment and associated binary packages + # which are not yet build or on the deletion list + printf 'DELETE `build_assignments`,`binary_packages`' + printf ' FROM `binary_packages`' + printf ' JOIN `%s` ON `%s`.`id`=`%s`.`%s`' \ + 'build_assignments' 'build_assignments' 'binary_packages' 'build_assignment' \ + 'package_sources' 'package_sources' 'build_assignments' 'package_source' \ + 'repositories' 'repositories' 'binary_packages' 'repository' + printf ' WHERE `package_sources`.`pkgbase`=from_base64("%s")' \ + "$( + printf '%s' "${package}" | \ + base64 -w0 + )" + printf ' AND (`repositories`.`name`="build-list" OR `repositories`.`name`="deletion-list");\n' + } | \ + ${mysql_command} + mysql_generate_package_metadata "${package}" "${git_revision}" "${new_repo_revisions__archlinux32}" "${repository}" continue fi diff --git a/bin/ii-connect b/bin/ii-connect index b703d77..54e1eb0 100755 --- a/bin/ii-connect +++ b/bin/ii-connect @@ -15,8 +15,8 @@ fi # register if not yet done if tail -n1 "${irc_dir}/nickserv/out" 2> /dev/null | \ grep -qF 'This nickname is registered. Please choose a different nickname'; then - printf 'identify %s\n' "${irc_password}" > \ - "${irc_dir}/nickserv/in" + printf 'identify %s\n' "${irc_password}" | \ + sponge "${irc_dir}/nickserv/in" fi # join #archlinux-ports if not yet done @@ -26,8 +26,8 @@ if ! grep ' buildmaster\.archlinux32\.org .* buildmaster$' "${irc_dir}/out" | \ { echo '/j #archlinux-ports' echo '/WHO buildmaster' - } > \ - "${irc_dir}/in" + } | \ + sponge "${irc_dir}/in" fi # start watch daemon if not running yet @@ -69,8 +69,8 @@ if [ "$1" = 'watch' ]; then echo "${reason}" | \ head -n5 printf '... (%s lines total)\n' "$(echo "${reason}" | wc -l)" - fi > \ - "${out_file%/out}/in" + fi | \ + sponge "${out_file%/out}/in" done sed -i "/${regex}/d" "${out_file}" fi diff --git a/bin/mysql-functions b/bin/mysql-functions index 7b9e724..ec2bf4c 100755 --- a/bin/mysql-functions +++ b/bin/mysql-functions @@ -37,20 +37,19 @@ mysql_add_package_source() { done values="${values% }" - ${mysql_command} -e "$( + { printf 'INSERT IGNORE INTO package_sources' - { - printf ' (' - printf '`%s`, ' ${names} - printf ') SELECT' - printf ' from_base64("%s"), ' ${values% *} - printf ' `upstream_repositories`.`id`' - printf ' FROM `upstream_repositories`' - printf ' WHERE `upstream_repositories`.`name` = from_base64("%s");' \ - "${values##* }" - } | \ - sed 's|, )|)|g' - )" + printf ' (' + printf '`%s`, ' ${names} + printf ') SELECT' + printf ' from_base64("%s"), ' ${values% *} + printf ' `upstream_repositories`.`id`' + printf ' FROM `upstream_repositories`' + printf ' WHERE `upstream_repositories`.`name` = from_base64("%s");' \ + "${values##* }" + } | \ + sed 's|, )|)|g' | \ + ${mysql_command} } # mysql_add_binary_package $pkgbase $git_revision $mod_git_revision $upstream_package_repository $pkgname $sub_pkgrel $architecture $repository @@ -68,33 +67,32 @@ mysql_add_binary_package() { shift done - ${mysql_command} -e "$( + { printf 'INSERT IGNORE INTO binary_packages' - { - printf ' (' - printf '`%s`, ' 'sub_pkgrel' 'pkgname' 'package_source' 'repository' 'architecture' - printf ') SELECT' - printf ' from_base64("%s"), ' "${sub_pkgrel}" "${pkgname}" - printf ' `%s`.`id`,' 'package_sources' 'repositories' 'architectures' - printf ' FROM' - printf ' `%s` JOIN' 'package_sources' 'repositories' 'architectures' - printf ' `upstream_repositories` ON `package_sources`.`upstream_package_repository` = `upstream_repositories`.`id`' - printf ' WHERE' - printf ' `%s`.`name` = from_base64("%s") AND' \ - 'repositories' "${repository}" \ - 'architectures' "${architecture}" - printf ' `package_sources`.`%s` = from_base64("%s") AND' \ - 'pkgbase' "${pkgbase}" \ - 'git_revision' "${git_revision}" \ - 'mod_git_revision' "${mod_git_revision}" - printf ' `upstream_repositories`.`name` = from_base64("%s")' \ - "${upstream_package_repository}" - } | \ - sed ' - s|, )|)|g - s|, FROM| FROM|g - ' - )" + printf ' (' + printf '`%s`, ' 'sub_pkgrel' 'pkgname' 'package_source' 'repository' 'architecture' + printf ') SELECT' + printf ' from_base64("%s"), ' "${sub_pkgrel}" "${pkgname}" + printf ' `%s`.`id`,' 'package_sources' 'repositories' 'architectures' + printf ' FROM' + printf ' `%s` JOIN' 'package_sources' 'repositories' 'architectures' + printf ' `upstream_repositories` ON `package_sources`.`upstream_package_repository` = `upstream_repositories`.`id`' + printf ' WHERE' + printf ' `%s`.`name` = from_base64("%s") AND' \ + 'repositories' "${repository}" \ + 'architectures' "${architecture}" + printf ' `package_sources`.`%s` = from_base64("%s") AND' \ + 'pkgbase' "${pkgbase}" \ + 'git_revision' "${git_revision}" \ + 'mod_git_revision' "${mod_git_revision}" + printf ' `upstream_repositories`.`name` = from_base64("%s")' \ + "${upstream_package_repository}" + } | \ + sed ' + s|, )|)|g + s|, FROM| FROM|g + ' | \ + ${mysql_command} } # mysql_show_binary_package $pkgname $pkgver $pkgrel $sub_pkgrel @@ -113,45 +111,44 @@ mysql_show_binary_package() { done local joint - ${mysql_command} -e "$( - { - printf 'SELECT' - printf ' `%s`.`%s`,' \ - 'repositories' 'name' \ - 'binary_packages' 'pkgname' \ - 'package_sources' 'pkgver' \ - 'package_sources' 'pkgrel' \ - 'binary_packages' 'sub_pkgrel' \ - 'architectures' 'name' \ - 'package_sources' 'pkgbase' \ - 'package_sources' 'git_revision' \ - 'package_sources' 'mod_git_revision' \ - 'upstream_repositories' 'name' - printf ' FROM `binary_packages`' - for joint in \ - 'architectures:binary_packages:architecture' \ - 'package_sources:binary_packages:package_source' \ - 'repositories:binary_packages:repository' \ - 'upstream_repositories:package_sources:upstream_package_repository'; do - printf ' JOIN `%s` ON `%s`.`id` =' \ - "${joint%%:*}" "${joint%%:*}" - joint="${joint#*:}" - printf ' `%s`.`%s`' \ - "${joint%:*}" "${joint#*:}" - done - printf ' WHERE' - printf ' `%s`.`%s` = from_base64("%s") AND' \ - 'binary_packages' 'pkgname' "${pkgname}" \ - 'binary_packages' 'sub_pkgrel' "${sub_pkgrel}" \ - 'package_sources' 'pkgver' "${pkgver}" \ - 'package_sources' 'pkgrel' "${pkgrel}" - printf ';' - } | \ - sed ' - s|, FROM| FROM|g - s|AND;|;|g - ' - )" --html + { + printf 'SELECT' + printf ' `%s`.`%s`,' \ + 'repositories' 'name' \ + 'binary_packages' 'pkgname' \ + 'package_sources' 'pkgver' \ + 'package_sources' 'pkgrel' \ + 'binary_packages' 'sub_pkgrel' \ + 'architectures' 'name' \ + 'package_sources' 'pkgbase' \ + 'package_sources' 'git_revision' \ + 'package_sources' 'mod_git_revision' \ + 'upstream_repositories' 'name' + printf ' FROM `binary_packages`' + for joint in \ + 'architectures:binary_packages:architecture' \ + 'package_sources:binary_packages:package_source' \ + 'repositories:binary_packages:repository' \ + 'upstream_repositories:package_sources:upstream_package_repository'; do + printf ' JOIN `%s` ON `%s`.`id` =' \ + "${joint%%:*}" "${joint%%:*}" + joint="${joint#*:}" + printf ' `%s`.`%s`' \ + "${joint%:*}" "${joint#*:}" + done + printf ' WHERE' + printf ' `%s`.`%s` = from_base64("%s") AND' \ + 'binary_packages' 'pkgname' "${pkgname}" \ + 'binary_packages' 'sub_pkgrel' "${sub_pkgrel}" \ + 'package_sources' 'pkgver' "${pkgver}" \ + 'package_sources' 'pkgrel' "${pkgrel}" + printf ';' + } | \ + sed ' + s|, FROM| FROM|g + s|AND;|;|g + ' | \ + ${mysql_command} --html } # mysql_add_install_target $install_target @@ -164,12 +161,12 @@ mysql_add_install_target() { base64 -w0 ) - ${mysql_command} -e "$( + { printf 'INSERT IGNORE INTO `install_targets` (`name`)' printf ' VALUES (from_base64("%s"))' \ "${install_target}" - printf '\n' - )" + } | \ + ${mysql_command} } # mysql_generate_package_metadata $package $git_revision $mod_git_revision $repository @@ -191,16 +188,19 @@ mysql_generate_package_metadata() { ''|*[!0-9]*) unset forced_sub_pkgrel current_repository=$( - echo 'build-list' | \ - base64_encode_each + printf 'build-list' | \ + base64 -w0 ) ;; *) - forced_sub_pkgrel="$1" + forced_sub_pkgrel=$( + printf '%s' "$1" | \ + base64 -w0 + ) shift current_repository=$( - echo "$1" | \ - base64_encode_each + printf '%s' "$1" | \ + base64 -w0 ) shift ;; @@ -292,7 +292,7 @@ mysql_generate_package_metadata() { } | \ while read -r arch; do printf 'INSERT IGNORE INTO `build_assignments` (`package_source`,`architecture`,`is_blocked`)' - printf ' SELECT `package_sources`.`id`,`architectures`.`id`,0' + printf ' SELECT `package_sources`.`id`,`architectures`.`id`,NULL' printf ' FROM `architectures` JOIN `package_sources`' printf ' WHERE `architectures`.`name` = from_base64("%s")' \ "$( @@ -400,30 +400,45 @@ mysql_generate_package_metadata() { sed 's/[<>=].*$//' | \ base64_encode_each ) - sub_pkgrel=$( - if [ -n "${forced_sub_pkgrel}" ]; then - echo "${forced_sub_pkgrel}" - else - ${mysql_command} -e "$( - printf 'SELECT count(*) FROM `binary_packages` JOIN `architectures` ON `binary_packages`.`architecture`=`architectures`.`id` WHERE' - printf ' `binary_packages`.`%s`=from_base64("%s") AND' \ - 'epoch' "${epoch}" \ - 'pkgver' "${pkgver}" \ - 'pkgrel' "${pkgrel}" \ - 'pkgname' "${pkgname}" - if printf '%s' "${arch}" | base64 -d | grep -qxF 'any'; then - # 'any' gets higher sub_pkgrel than any architecture - printf ' 1' - else - # not-'any' gets higher sub_pkgrel than same or 'any' architecture - printf ' (`architectures`.`name`=from_base64("%s") OR `architectures`.`name`="any")' \ - "${arch}" - fi - )" | \ - tail -n1 - fi | \ - base64_encode_each - ) + if [ -n "${forced_sub_pkgrel}" ]; then + sub_pkgrel='from_base64("'"${forced_sub_pkgrel}"'")' + else + sub_pkgrel=$( + printf '(SELECT COALESCE(' + # do not add binary packages which are currently on the build-list + printf '(SELECT `sub_pkgrel` FROM `binary_packages`' + printf ' JOIN `architectures` ON `binary_packages`.`architecture`=`architectures`.`id`' + printf ' JOIN `repositories` ON `binary_packages`.`repository`=`repositories`.`id`' + printf ' WHERE' + printf ' `binary_packages`.`%s`=from_base64("%s") AND' \ + 'epoch' "${epoch}" \ + 'pkgver' "${pkgver}" \ + 'pkgrel' "${pkgrel}" \ + 'pkgname' "${pkgname}" + printf ' `architectures`.`name`=from_base64("%s")' \ + "${arch}" + printf ' AND `repositories`.`name`="build-list"),' + # max(sub_pkgrel)+1 + printf '(SELECT 1+MAX(`binary_packages`.`sub_pkgrel`) FROM `binary_packages`' + printf ' JOIN `architectures` ON `binary_packages`.`architecture`=`architectures`.`id`' + printf ' WHERE' + printf ' `binary_packages`.`%s`=from_base64("%s") AND' \ + 'epoch' "${epoch}" \ + 'pkgver' "${pkgver}" \ + 'pkgrel' "${pkgrel}" \ + 'pkgname' "${pkgname}" + if printf '%s' "${arch}" | base64 -d | grep -qxF 'any'; then + # 'any' gets higher sub_pkgrel than any architecture + printf ' 1' + else + # not-'any' gets higher sub_pkgrel than same or 'any' architecture + printf ' (`architectures`.`name`=from_base64("%s") OR `architectures`.`name`="any")' \ + "${arch}" + fi + printf ')' + printf ',0))' + ) + fi { printf 'INSERT IGNORE INTO `binary_packages` (' printf '`%s`,' \ @@ -433,8 +448,8 @@ mysql_generate_package_metadata() { 'epoch' \ 'pkgver' \ 'pkgrel' \ - 'sub_pkgrel' \ 'pkgname' \ + 'sub_pkgrel' \ 'has_issues' \ 'is_tested' printf ') SELECT ' @@ -446,9 +461,9 @@ mysql_generate_package_metadata() { "${epoch}" \ "${pkgver}" \ "${pkgrel}" \ - "${sub_pkgrel}" \ "${pkgname}" - printf '0,0 FROM' + printf '%s,0,0 FROM' \ + "${sub_pkgrel}" printf ' `%s` JOIN' \ 'repositories' \ 'architectures' \ @@ -547,8 +562,9 @@ mysql_generate_package_metadata() { 'epoch' "${epoch}" \ 'pkgver' "${pkgver}" \ 'pkgrel' "${pkgrel}" \ - 'sub_pkgrel' "${sub_pkgrel}" \ 'pkgname' "${pkgname}" + printf ' `binary_packages`.`sub_pkgrel` = %s AND' \ + "${sub_pkgrel}" printf ' `architectures`.`name` = from_base64("%s") AND' \ "${arch}" printf ' `repositories`.`name` = from_base64("%s");\n' \ @@ -564,7 +580,7 @@ mysql_generate_package_metadata() { done printf '.' >&2 - ${mysql_command} -e "$( + { if [ -s "${temp_dir}/add-build-assignments-command" ]; then cat "${temp_dir}/add-build-assignments-command" fi @@ -574,7 +590,8 @@ mysql_generate_package_metadata() { if [ -s "${temp_dir}/add-install-targets-command" ]; then cat "${temp_dir}/add-install-targets-command" fi - )" + } | \ + ${mysql_command} printf '.' >&2 ) @@ -603,13 +620,14 @@ mysql_sanity_check() { "${temp_dir}/master-mirror-listing" # shellcheck disable=SC2016 - ${mysql_command} -e ' - SELECT `repositories`.`name`,`pkgname`,`epoch`,`pkgver`,`pkgrel`,`sub_pkgrel`,`architectures`.`name` - FROM `binary_packages` - JOIN `architectures` ON `binary_packages`.`architecture`=`architectures`.`id` - JOIN `repositories` ON `binary_packages`.`repository`=`repositories`.`id` - WHERE `repositories`.`is_on_master_mirror` - ' --batch | \ + { + printf 'SELECT `repositories`.`name`,`pkgname`,`epoch`,`pkgver`,`pkgrel`,`sub_pkgrel`,`architectures`.`name`' + printf ' FROM `binary_packages`' + printf ' JOIN `architectures` ON `binary_packages`.`architecture`=`architectures`.`id`' + printf ' JOIN `repositories` ON `binary_packages`.`repository`=`repositories`.`id`' + printf ' WHERE `repositories`.`is_on_master_mirror`' + } | \ + ${mysql_command} --batch | \ sed ' 1d s,\t,/, @@ -24,6 +24,9 @@ # with Opcode_WILLAMETTE_Base # * Remove all line in Opcode_ARM_THUMB # return values + +# shellcheck disable=SC2001,SC2034,SC2086 + EXIT_FOUND=0 EXIT_NOT_FOUND=1 EXIT_USAGE=2 @@ -42,7 +45,8 @@ Line_Numbers=false Leading_Context=0 Trailing_Context=0 -source "${0%/*}/../conf/Opcode_list" # include opcodes from a separate file +# shellcheck source=lib/opcode_list +source "${0%/*}/../lib/opcode_list" # include opcodes from a separate file # GAS-specific opcodes (unofficial names) belonging to the x64 instruction set. # They are generated by GNU tools (e.g. GDB, objdump) and specify a variant of ordinal opcodes like NOP and MOV. @@ -162,7 +166,7 @@ usage() { echo "The script uses Intel opcode syntax. When used in conjunction with objdump, \`-M intel' must be set in order to prevent opcode translation using AT&T syntax." echo echo "BE AWARE THAT THE LIST OF KNOWN INSTRUCTIONS OR INSTRUCTIONS SUPPORTED BY PARTICULAR ARCHITECTURES (ESPECIALLY AMD'S) IS ONLY TENTATIVE AND MAY CONTAIN MISTAKES!" - kill -TRAP $TOP_PID + kill -TRAP "$TOP_PID" } list_contains() { # Returns 0 if $2 is in array $1, 1 otherwise. @@ -175,25 +179,25 @@ list_contains() { # Returns 0 if $2 is in array $1, 1 otherwise. build_instruction_set() { # $1 = enum { Arch, InstSet }, $2 = architecture or instruction set as obtained using -L or -l, $3 = "architecture"/"instruction set" to be used in error message local e - list_contains "`eval echo \\\$${1}List`" "$2" || (echo "$2 is not a valid $3."; usage) # Test if the architecture/instruction set is valid. - if [ -n "`eval echo \\\$${1}_${2}`" ]; then # Add the instruction set(s) if any. - for e in `eval echo \\\$${1}_${2}`; do # Skip duplicates. + list_contains "$(eval echo \\\$${1}List)" "$2" || (echo "$2 is not a valid $3."; usage) # Test if the architecture/instruction set is valid. + if [ -n "$(eval echo \\\$${1}_${2})" ]; then # Add the instruction set(s) if any. + for e in $(eval echo \\\$${1}_${2}); do # Skip duplicates. list_contains "$InstSet_Base" $e || InstSet_Base="$e $InstSet_Base" done fi if [ $Recursive = true ]; then - for a in `eval echo \\\$${1}Dep_$2`; do + for a in $(eval echo \\\$${1}Dep_$2); do build_instruction_set $1 $a "$3" done fi - InstSet_Base="`echo $InstSet_Base | sed 's/$ *//'`" # Remove trailing space. + InstSet_Base=$(echo $InstSet_Base | sed 's/$ *//') # Remove trailing space. } -trap "exit $EXIT_USAGE" TRAP # Allow usage() function to abort script execution. +trap 'exit $EXIT_USAGE' TRAP # Allow usage() function to abort script execution. export TOP_PID=$$ # PID of executing process. # Parse command line arguments. -while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do +while getopts ":ra:s:LliIcf:d:D:CvVm:nB:A:h" o; do case $o in r) Recursive=true ;; a) build_instruction_set Arch "$OPTARG" "architecture" ;; @@ -205,19 +209,19 @@ while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do echo $InstSet_Base exit $EXIT_USAGE else - echo -e "No instruction set or architecture set.\n" + echo -e "No instruction set or architecture set.\\n" usage fi ;; I) if [ -n "$InstSet_Base" ]; then for s in $InstSet_Base; do - echo -ne "\e[31;1m$s:\e[0m " + echo -ne "\\e[31;1m$s:\\e[0m " eval echo "\$Opcode_$s" done exit $EXIT_USAGE else - echo -e "No instruction set or architecture set.\n" + echo -e "No instruction set or architecture set.\\n" usage fi ;; @@ -226,12 +230,12 @@ while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do # Unlike architectures, instruction sets are disjoint. Found=false for s in $InstSetList; do - for b in `eval echo \\\$InstSet_$s`; do + for b in $(eval echo \\\$InstSet_$s); do Found_In_Base=false - for i in `eval echo \\\$Opcode_$b`; do + for i in $(eval echo \\\$Opcode_$b); do if [[ "$i" =~ ^$OPTARG$ ]]; then - $Found_In_Base || echo -ne "Instruction set \e[33;1m$s\e[0m (base instruction set \e[32;1m$b\e[0m):" - echo -ne " \e[31;1m$i\e[0m" + $Found_In_Base || echo -ne "Instruction set \\e[33;1m$s\\e[0m (base instruction set \\e[32;1m$b\\e[0m):" + echo -ne " \\e[31;1m$i\\e[0m" Found_In_Base=true Found=true fi @@ -240,7 +244,7 @@ while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do done done if [ $Found = false ]; then - echo -e "Operation code \e[31;1m$OPTARG\e[0m has not been found in the database of known instructions." \ + echo -e "Operation code \\e[31;1m$OPTARG\\e[0m has not been found in the database of known instructions." \ "Perhaps it is translated using other than Intel syntax. If obtained from objdump, check if the \`-M intel' flag is set." \ "Be aware that the search is case sensitive by default (you may use the -C flag, otherwise only lower case opcodes are accepted)." exit $EXIT_NOT_FOUND @@ -259,13 +263,13 @@ while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do A) Trailing_Context=$OPTARG ;; h) usage ;; \?) - echo -e "Unknown option: -$OPTARG\n" + echo -e "Unknown option: -$OPTARG\\n" usage ;; esac done shift $((OPTIND-1)) -[ -n "$1" ] && echo -e "Unknown command line parameter: $1\n" && usage +[ -n "$1" ] && echo -e "Unknown command line parameter: $1\\n" && usage [ -z "$InstSet_Base" ] && usage # Create list of grep parameters. @@ -279,12 +283,13 @@ Grep_Params="--color=auto -B $Leading_Context -A $Trailing_Context" # Build regular expression for use in grep. RegEx="" for s in $InstSet_Base; do - eval RegEx=\"$RegEx \$Opcode_$s\" + eval 'RegEx="$RegEx $Opcode_'"$s"'"' done # Add leading and trailing opcode separators to prevent false positives. -RegEx="$Leading_Separator`echo $RegEx | sed "s/ /$(echo "$Trailing_Separator"|sed 's/[\/&]/\\\&/g')|$(echo "$Leading_Separator"|sed 's/[\/&]/\\\&/g')/g"`$Trailing_Separator" +RegEx="$Leading_Separator$(echo $RegEx | sed "s/ /$(echo "$Trailing_Separator"|sed 's/[\/&]/\\\&/g')|$(echo "$Leading_Separator"|sed 's/[\/&]/\\\&/g')/g")$Trailing_Separator" -[ $Verbose = true -a $Count_Matching = false ] && RegEx="$RegEx|\$" +[ $Verbose = true ] && [ $Count_Matching = false ] && RegEx="$RegEx|\$" +# shellcheck disable=SC2086 # The actual search. grep $Grep_Params -E "$RegEx" && exit $EXIT_FOUND || exit $EXIT_NOT_FOUND diff --git a/bin/return-assignment b/bin/return-assignment index ebaa73a..cd6d30e 100755 --- a/bin/return-assignment +++ b/bin/return-assignment @@ -60,12 +60,14 @@ if [ "$5" = 'ERROR' ]; then fi # save sent build logs - tar -x \ - -C "${build_log_directory}/error" \ - --wildcards \ - --no-wildcards-match-slash \ - --transform="s|^|$1.$2.$3.$4.|" \ - '*.build-log.gz' + saved_build_logs=$( + tar -vx \ + -C "${build_log_directory}/error" \ + --wildcards \ + --no-wildcards-match-slash \ + --transform="s|^|$1.$2.$3.$4.|" \ + '*.build-log.gz' + ) if [ -f "${work_dir}/package-states/$1.$2.$3.$4.broken" ]; then was_broken_before=true @@ -76,20 +78,76 @@ if [ "$5" = 'ERROR' ]; then # shellcheck disable=SC2154 echo "${slave}" >> \ "${work_dir}/package-states/$1.$2.$3.$4.broken" - ${mysql_command} -e "$( - # shellcheck disable=SC2016 + # shellcheck disable=SC2016 + { + if [ -n "${saved_build_logs}" ]; then + printf 'CREATE TEMPORARY TABLE `failures` (' + printf '`%s` %s,' \ + 'date' 'DATETIME' \ + 'reason' 'SMALLINT' \ + 'log_file' 'VARCHAR(512)' | \ + sed 's/,$//' + printf ');\n' + printf 'INSERT INTO `failures` (`date`,`reason`,`log_file`) VALUES' + fail_reason_identifiers=$( + { + printf 'SELECT `fail_reasons`.`id`,replace(to_base64(`fail_reasons`.`identifier`),"\\n","")' + printf ' FROM `fail_reasons` ORDER BY `fail_reasons`.`severity`' + } | \ + ${mysql_command} --raw --batch | \ + sed '1d' + ) + for saved_build_log in ${saved_build_logs}; do + printf '%s' "${fail_reason_identifiers}" | \ + while read -r reason_id identifier; do + if zgrep -q "^$( + printf '%s' "${identifier}" | \ + base64 -d + )\$" \ + "${build_log_directory}/error/$1.$2.$3.$4.${saved_build_log}"; then + + printf ' (from_base64("%s"),%s,from_base64("%s")),' \ + "$( + printf '%s' "${saved_build_log}" | \ + sed 's|\.build-log\.gz$||;s|^.*\.||' | \ + base64 -w0 + )" \ + "${reason_id}" \ + "$( + printf '%s' "$1.$2.$3.$4.${saved_build_log}" | \ + base64 -w0 + )" + break + fi + done + done | \ + sed 's/,$//' + printf ';\n' + printf 'INSERT INTO `failed_builds` (`build_slave`,`build_assignment`,`date`,`reason`,`log_file`)' + printf ' SELECT ' + printf '`build_slaves`.`%s`,' \ + 'id' 'currently_building' + printf '`failures`.`%s`,' \ + 'date' 'reason' 'log_file' | \ + sed 's/,$//' + printf ' FROM `build_slaves` JOIN `failures`' + printf ' WHERE `build_slaves`.`name`=from_base64("%s");\n' \ + "$( + printf '%s' "${slave}" | \ + base64 -w0 + )" + printf 'DROP TABLE `failures`;\n' + fi printf 'UPDATE `build_assignments`' - # shellcheck disable=SC2016 printf ' JOIN `build_slaves` ON `build_slaves`.`currently_building`=`build_assignments`.`id`' - # shellcheck disable=SC2016 printf ' SET `build_assignments`.`is_broken`=1, `build_slaves`.`currently_building`=NULL' - # shellcheck disable=SC2016 printf ' WHERE `build_slaves`.`name`=from_base64("%s");\n' \ "$( printf '%s' "${slave}" | \ base64 -w0 )" - )" + } | \ + ${mysql_command} # shellcheck disable=SC2154 sed -i ' @@ -163,9 +221,8 @@ if [ "$5" = 'ERROR' ]; then sed 's/,$/./' fi printf '\n' - } | tee /dev/stderr > \ - "${irc_dir}/#archlinux-ports/in" - # why do we need tee there in order for the redirection to work??? + } | \ + sponge "${irc_dir}/#archlinux-ports/in" fi fi @@ -368,6 +425,34 @@ if ! [ "${destination}" = 'build-support' ]; then printf '%s\n' ${packages} > \ "${work_dir}/package-states/$1.$2.$3.$4.done" fi +# shellcheck disable=SC2016 +{ + printf 'UPDATE `build_assignments`' + printf ' JOIN `build_slaves` ON `build_slaves`.`currently_building`=`build_assignments`.`id`' + printf ' JOIN `binary_packages` ON `binary_packages`.`build_assignment`=`build_assignments`.`id`' + printf ' SET' + printf ' `build_assignments`.`is_broken`=0,' + printf ' `binary_packages`.`repository`=(SELECT `repositories`.`id` FROM `repositories` WHERE `repositories`.`name`=from_base64("%s")),' \ + "$( + printf '%s' "${destination}" | \ + base64 -w0 + )" + printf ' `binary_packages`.`has_issues`=0,' + printf ' `binary_packages`.`is_tested`=0' + printf ' WHERE `build_slaves`.`name`=from_base64("%s");\n' \ + "$( + printf '%s' "${slave}" | \ + base64 -w0 + )" + printf 'UPDATE `build_slaves` SET' + printf ' `build_slaves`.`currently_building`=NULL' + printf ' WHERE `build_slaves`.`name`=from_base64("%s");\n' \ + "$( + printf '%s' "${slave}" | \ + base64 -w0 + )" +} | \ + ${mysql_command} rm -f \ "${work_dir}/package-states/$1.$2.$3.$4.locked" \ "${work_dir}/package-states/$1.$2.$3.$4.broken" diff --git a/bin/sanity-check b/bin/sanity-check index 65ac5f3..8736d47 100755 --- a/bin/sanity-check +++ b/bin/sanity-check @@ -19,8 +19,8 @@ usage() { i_am_insane() { if [ ! -s "${work_dir}/build-master-sanity" ]; then - printf '\001ACTION goes insane.\001\n' > \ - "${irc_dir}/#archlinux-ports/in" + printf '\001ACTION goes insane.\001\n' | \ + sponge "${irc_dir}/#archlinux-ports/in" fi echo 'build master is insane' > \ "${work_dir}/build-master-sanity" @@ -398,6 +398,6 @@ done if [ -f "${work_dir}/build-master-sanity" ]; then rm "${work_dir}/build-master-sanity" - printf '\001ACTION resumes sanity.\001\n' > \ - "${irc_dir}/#archlinux-ports/in" + printf '\001ACTION resumes sanity.\001\n' | \ + sponge "${irc_dir}/#archlinux-ports/in" fi diff --git a/bin/seed-build-list b/bin/seed-build-list index feea704..acf25c3 100755 --- a/bin/seed-build-list +++ b/bin/seed-build-list @@ -5,6 +5,8 @@ # shellcheck source=conf/default.conf . "${0%/*}/../conf/default.conf" +# TODO: put new packages also in mysql database + # shellcheck disable=SC2016 usage() { >&2 echo '' @@ -282,6 +284,11 @@ if ${update}; then "${tmp_dir}/build-list.new" | \ tee -a "${work_dir}/build-list" + while read -r git_revision mod_git_revision repository pkgbase; do + mysql_generate_package_metadata "${pkgbase}" "${git_revision}" "${mod_git_revision}" "${repository}" + done < \ + "${tmp_dir}/build-list.new" + # Remove the lock file rm -f "${build_list_lock_file}" diff --git a/bin/slave-build-connect b/bin/slave-build-connect index 86ab14b..2ca72a3 100755 --- a/bin/slave-build-connect +++ b/bin/slave-build-connect @@ -18,18 +18,17 @@ if [ "${SSH_ORIGINAL_COMMAND%% *}" = "get-assignment" ] || \ printf '%s %s %s\n' "$(date '+%F %T')" "$1" "${SSH_ORIGINAL_COMMAND}" >> \ "${work_dir}/ssh-log" - ${mysql_command} -e "$( - # shellcheck disable=SC2016 + # shellcheck disable=SC2016 + { printf 'UPDATE `build_slaves`' - # shellcheck disable=SC2016 printf ' SET `build_slaves`.`last_connection`=NOW()' - # shellcheck disable=SC2016 printf ' WHERE `build_slaves`.`name`=from_base64("%s")\n' \ "$( printf '%s' "$1" | \ base64 -w0 )" - )" + } | \ + ${mysql_command} slave="$1" /bin/sh -c "${base_dir}/bin/${SSH_ORIGINAL_COMMAND}" diff --git a/conf/default.conf b/conf/default.conf index b2882ac..6ee991b 100755 --- a/conf/default.conf +++ b/conf/default.conf @@ -16,6 +16,8 @@ fi # shellcheck source=bin/common-functions . "${base_dir}/bin/common-functions" +# shellcheck source=bin/mysql-functions +. "${base_dir}/bin/mysql-functions" work_dir="${base_dir}/work" diff --git a/conf/Opcode_list b/lib/opcode_list index 213321f..213321f 100644..100755 --- a/conf/Opcode_list +++ b/lib/opcode_list diff --git a/web-scripts/broken-packages.php b/web-scripts/broken-packages.php new file mode 100644 index 0000000..268e296 --- /dev/null +++ b/web-scripts/broken-packages.php @@ -0,0 +1,157 @@ +<html> +<head> +<title>List of broken package builds</title> +<link rel="stylesheet" type="text/css" href="/static/style.css"> +</head> +<body> +<a href="build-logs/">build logs</a><br> +<?php + +$mysql = new mysqli("localhost", "webserver", "empty", "buildmaster"); +if ($mysql->connect_error) { + die("Connection failed: " . $mysql->connect_error); +} + +$result = $mysql -> query( + "SELECT " . + "`build_assignments`.`id`," . + "`build_assignments`.`is_blocked`," . + "`package_sources`.`pkgbase`," . + "`package_sources`.`git_revision`," . + "`package_sources`.`mod_git_revision`," . + "`upstream_repositories`.`name`," . + "EXISTS (SELECT * " . + "FROM `binary_packages` `broken_bin` " . + "JOIN `dependencies` ON `dependencies`.`dependent` = `broken_bin`.`id` " . + "JOIN `install_target_providers` ON `install_target_providers`.`install_target` = `dependencies`.`depending_on` " . + "JOIN `binary_packages` `to_be_built` ON `to_be_built`.`id` = `install_target_providers`.`package` " . + "JOIN `repositories` ON `to_be_built`.`repository` = `repositories`.`id` " . + "WHERE `broken_bin`.`build_assignment`=`build_assignments`.`id` ". + "AND `repositories`.`name`=\"community-testing\"" . + ") AS `dependencies_pending`," . + "(SELECT count(*) " . + "FROM `build_dependency_loops` " . + "WHERE `build_dependency_loops`.`build_assignment`=`build_assignments`.`id`" . + ") AS `loops` " . + "FROM `build_assignments` " . + "JOIN `package_sources` ON `build_assignments`.`package_source` = `package_sources`.`id` " . + "JOIN `upstream_repositories` ON `package_sources`.`upstream_package_repository` = `upstream_repositories`.`id` " . + "WHERE `build_assignments`.`is_broken` OR `build_assignments`.`is_blocked` IS NOT NULL" +); +if ($result -> num_rows > 0) { + + $count = 0; + + while($row = $result->fetch_assoc()) { + +foreach ($row as $key => $val) + + $fail_result = $mysql -> query( + "SELECT " . + "`fail_reasons`.`name`, " . + "`failed_builds`.`log_file` " . + "FROM `failed_builds` " . + "JOIN `build_assignments` ON `failed_builds`.`build_assignment`=`build_assignments`.`id` ". + "JOIN `fail_reasons` ON `failed_builds`.`reason`=`fail_reasons`.`id` ". + "WHERE `build_assignments`.`id`=".$row["id"]." " . + "ORDER BY `failed_builds`.`date`" + ); + + unset($reasons); + unset($last_log); + $rows[$count]["trials"] = $fail_result -> num_rows; + if ($rows[$count]["trials"] > 0) { + while($fail_row = $fail_result->fetch_assoc()) { + $reasons[$fail_row["name"]] = $fail_row["name"]; + $last_log = $fail_row["log_file"]; + } + } + if (isset($reasons)) { + $to_print=""; + foreach ($reasons as $reason) { + $to_print=$to_print.", ".$reason; + } + $rows[$count]["fail_reasons"]=substr($to_print,2); + } else { + $rows[$count]["fail_reasons"]=" "; + } + + $rows[$count]["loops"] = $row["loops"]; + $rows[$count]["pkgbase"] = $row["pkgbase"]; + if ($row["dependencies_pending"]=="1") + $rows[$count]["pkgbase_print"] = "(" . $rows[$count]["pkgbase"] . ")"; + else + $rows[$count]["pkgbase_print"] = $rows[$count]["pkgbase"]; + $rows[$count]["git_revision"] = $row["git_revision"]; + $rows[$count]["mod_git_revision"] = $row["mod_git_revision"]; + $rows[$count]["name"] = $row["name"]; + if (isset($last_log)) + $rows[$count]["print_trials"]="<a href=\"/build-logs/error/".$last_log."\">". $rows[$count]["trials"] ."</a>"; + else + $rows[$count]["print_trials"]=$rows[$count]["trials"]; + if ($row["is_blocked"]=="") { + $rows[$count]["is_blocked"]=" "; + } + else { + $rows[$count]["is_blocked"] = preg_replace( + array ( + "/FS32#(\\d+)/", + "/FS#(\\d+)/" + ), + array ( + "<a href=\"https://bugs.archlinux32.org/index.php?do=details&task_id=$1\">$0</a>", + "<a href=\"https://bugs.archlinux.org/task/$1\">$0</a>" + ), + $row["is_blocked"] + ); + } + $count++; + } + + usort( + $rows, + function (array $a, array $b) { + if ($a["trials"] < $b["trials"]) + return -1; + if ($a["trials"] > $b["trials"]) + return 1; + return strcmp($a["pkgbase"],$b["pkgbase"]); + } + ); + + print "<table>\n"; + print "<tr>"; + print "<th>package</th>"; + print "<th>git revision</th>"; + print "<th>modification git revision</th>"; + print "<th>package repository</th>"; + print "<th>compilations</th>"; + print "<th>loops</th>"; +// print "<th>dependent</th>"; + print "<th>build error</th>"; + print "<th>blocked</th>"; + print "</tr>\n"; + + foreach($rows as $row) { + + print "<tr>"; + + print "<td><a href=\"/graphs/".$row["pkgbase"].".png\">".$row["pkgbase_print"]."</a></td>"; + print "<td><p style=\"font-size:8px\">".$row["git_revision"]."</p></td>"; + print "<td><p style=\"font-size:8px\">".$row["mod_git_revision"]."</p></td>"; + print "<td>".$row["name"]."</td>"; + print "<td>".$row["print_trials"]."</td>"; + print "<td>".$row["loops"]."</td>"; +// <td>0</td> + print "<td>".$row["fail_reasons"]."</td>"; + print "<td>".$row["is_blocked"]."</td>"; + + print "</tr>\n"; + } + + print "</table>\n"; +} + +?> +</body> +</html> diff --git a/web-scripts/build-slaves.php b/web-scripts/build-slaves.php new file mode 100644 index 0000000..0b8ae6a --- /dev/null +++ b/web-scripts/build-slaves.php @@ -0,0 +1,44 @@ +<html><head><title>list of build slaves</title></head><body> +<?php + + $conn = new mysqli("localhost","http","http","buildmaster"); + if ($conn->connect_error) { + die("Connection to mysql database failed: " . $conn->connect_error); + } + + $result = + $conn->query( + "SELECT" . + " `build_slaves`.`name`," . + "`build_slaves`.`operator`," . + "`package_sources`.`pkgbase`," . + "`build_slaves`.`last_connection`" . + " FROM `build_slaves`" . + " LEFT JOIN `build_assignments` ON" . + " `build_slaves`.`currently_building`=`build_assignments`.`id`" . + " LEFT JOIN `package_sources` ON" . + " `build_assignments`.`package_source`=`package_sources`.`id`" . + " ORDER BY `build_slaves`.`last_connection`" + ); + + print "<table border=1>\n"; + if ($result->num_rows > 0) { + print "<tr><th>name</th><th>operator</th><th>currently building</th><th>last connection</th></tr>\n"; + while ($row = $result -> fetch_assoc()) { + foreach ($row as $key => $value) { + if ($value=="") { + $row[$key]=" "; + } + } + print "<tr>"; + print "<td>".$row["name"]."</td>"; + print "<td>".$row["operator"]."</td>"; + print "<td>".$row["pkgbase"]."</td>"; + print "<td>".$row["last_connection"]."</td>"; + print "</tr>\n"; + } + } + print "</table>\n"; + +?> +</body></html> diff --git a/web-scripts/packages.php b/web-scripts/packages.php new file mode 100644 index 0000000..b8b5dda --- /dev/null +++ b/web-scripts/packages.php @@ -0,0 +1,20 @@ +<?php + + $mysql = new mysqli("localhost", "http", "http"); + if ($mysql->connect_error) { + die("Connection to mysql database failed: " . $mysql->connect_error); + } + + $result = $mysql -> query("SELECT * FROM buildmaster.binary_packages"); + if ($result -> num_rows > 0) { + while($row = $result->fetch_assoc()) { + foreach ($row as $key => $val) { + print $key .": ".$val." - "; + } + print "<br>\n"; + } + } + + print 'OK'; + +?> diff --git a/web-scripts/statistics.php b/web-scripts/statistics.php new file mode 100644 index 0000000..279aa39 --- /dev/null +++ b/web-scripts/statistics.php @@ -0,0 +1,179 @@ +<?php + +$columns = array( + 'stable', + 'tasks', + 'pending_packages', + 'staging', + 'testing', + 'broken', + 'loops', + 'looped_packages', + 'locked', + 'blocked', + 'next_pending', + 'tested' +); + +$print_columns = array( + 'tasks', + 'pending_packages', + 'staging', + 'testing', + 'tested', + 'broken', + 'loops', + 'looped_packages', + 'locked', + 'blocked', + 'next_pending' +); + +$t_min = -1; +$t_max = -1; +$val_max = -1; + +foreach (explode("\n",trim(file_get_contents('/srv/http/statistics'))) as $val) { + $val = explode(" ",$val); + if (($t_min == -1) || ($t_min > $val[0])) + $t_min = $val[0]; + if (($t_max == -1) || ($t_max < $val[0])) + $t_max = $val[0]; + foreach ($columns as $id => $column) { + if (count($val) > $id+1) + $values[$column][$val[0]] = $val[$id+1]; + }; + foreach ($print_columns as $column) { + if (array_key_exists($column,$values)) + if (($val_max == -1) || ($val_max < $values[$column][$val[0]])) + $val_max = $values[$column][$val[0]]; + } +}; + +$max_len = 0; +foreach ($print_columns as $column) { + $len = strlen($values[$column][$t_max])+1; + if ($len > $max_len) + $max_len = $len; +} + +$width = 1600; +$height = 600; +$border = 5; +$legend_line_length = 10; +$legend_height = 3 * ImageFontHeight(5) + $legend_line_length; + +$im = @ImageCreate ($width + $legend_line_length + $max_len * ImageFontWidth(5), $height + $legend_height) + or die ("Cannot create new gd-image-stream"); + +$background_color = ImageColorAllocate ($im, 255, 255, 255); +$foreground_color = ImageColorAllocate ($im, 0, 0, 0); + +$colors['stable'] = ImageColorAllocate ($im, 0, 0, 0); +$colors['tasks'] = ImageColorAllocate ($im, 0, 0, 128); +$colors['pending_packages'] = ImageColorAllocate ($im, 0, 0, 255); +$colors['staging'] = ImageColorAllocate ($im, 0, 100, 0); +$colors['testing'] = ImageColorAllocate ($im, 0, 200, 0); +$colors['tested'] = ImageColorAllocate ($im, 100, 255, 0); +$colors['broken'] = ImageColorAllocate ($im, 255, 0, 0); +$colors['loops'] = ImageColorAllocate ($im, 128, 128, 0); +$colors['looped_packages'] = ImageColorAllocate ($im, 255, 128, 128); +$colors['locked'] = ImageColorAllocate ($im, 128, 128, 128); +$colors['blocked'] = ImageColorAllocate ($im, 128, 0, 0); +$colors['next_pending'] = ImageColorAllocate ($im, 0, 255, 255); + +function scale($x, $x_min, $x_max, $scale, $log) { + if ($log) { + $x = log($x + 10); + $x_min = log($x_min + 10); + $x_max = log($x_max + 10); + }; + if ($x_max == $x_min) + $frac = 0; + else + $frac = ($x - $x_min)/($x_max - $x_min); + if ($scale < 0) + return ($frac-1) * $scale; + else + return $frac * $scale; +}; + +function print_graph($data, $color) { + global $width, $height, $im, $t_min, $t_max, $val_max, $border, $legend_line_length; + ksort($data); + $last_t = -1; + $last_val = -1; + foreach ($data as $t => $val) { + if ($last_t != -1) + ImageLine( + $im, + scale($last_t,$t_min,$t_max,$width-2*$border,false)+$border+$legend_line_length, + scale($last_val,0,$val_max,-$height+2*$border,isset($_GET["log"]))+$border, + scale($t,$t_min,$t_max,$width-2*$border,false)+$border+$legend_line_length, + scale($val,0,$val_max,-$height+2*$border,isset($_GET["log"]))+$border, + $color + ); + $last_t = $t; + $last_val = $val; + } + ImageString( + $im, + 5, + $width+$legend_line_length, + scale($last_val,0,$val_max,-$height+2*$border,isset($_GET["log"]))+$border - ImageFontHeight(5)/2, + " ".$data[$t_max], + $color + ); +}; + +ImageRectangle($im, $legend_line_length, 0, $width-1+$legend_line_length, $height-1, $foreground_color); + +ImageString($im, 5, $legend_line_length, $height + $legend_line_length + 2*ImageFontHeight(5), "( ".trim(shell_exec("uptime | sed 's|^.*\\s\\(load\\)|\\1|'"))." )", $foreground_color); + +$xpos = $legend_line_length; +foreach ($print_columns as $column) { + print_graph($values[$column], $colors[$column]); + ImageString($im, 5, $xpos, $height + $legend_line_length + ImageFontHeight(5), $column, $colors[$column]); + $xpos += (strlen($column) + 1.75) * ImageFontWidth(5); +} + +ImageString($im, 5, $legend_line_length, $height + $legend_line_length, date('Y-m-d H:i', $t_min), $foreground_color); +$s = date('Y-m-d H:i', $t_max); +ImageString($im, 5, $width+$legend_line_length - strlen($s)*ImageFontWidth(5), $height + $legend_line_length, $s, $foreground_color); + +for ($t=ceil($t_min/24/60/60); $t<=floor($t_max/24/60/60); $t++) + ImageLine( + $im, + scale($t*24*60*60,$t_min,$t_max,$width-2*$border,false)+$border+$legend_line_length, + $height, + scale($t*24*60*60,$t_min,$t_max,$width-2*$border,false)+$border+$legend_line_length, + $height+$legend_line_length, + $foreground_color + ); + +for ($val=0; $val<=$val_max;) { + ImageLine( + $im, + 0, + scale($val,0,$val_max,-$height+2*$border,isset($_GET["log"]))+$border, + $legend_line_length, + scale($val,0,$val_max,-$height+2*$border,isset($_GET["log"]))+$border, + $foreground_color + ); + if (! isset($_GET["log"])) + $val+=pow(10,round(log($val_max)/log(10))-1); + elseif ($val==0) + $val++; + else + $val=$val*10; +} + +// ImageString ($im, 1, 5, 5, "Test-String ".rand(), $foreground_color); + +header ("Content-type: image/png"); + +ImagePNG ($im); + +// passthru('wc -l /srv/http/statistics'); + +?> |