From 60fba634600d0e20726c02d88735cc3d71ff0103 Mon Sep 17 00:00:00 2001 From: Lucio Andrés Illanes Albornoz Date: Mar 13 2020 15:33:05 +0000 Subject: Implements ./pkgtool.sh -[irt] options. etc/{README.md,pkgtool.usage}: updated. subr/ex_pkg.subr:ex_pkg_{find_package,get_packages}(): initial implementation. subr/ex_pkg.subr:ex_pkg_unfold_{,r}depends(): split from ex_pkg_expand_packages(). subr/ex_pkg{,_dispatch}.subr: removes ${EX_PKG_COMPLETE} scoped global. subr/ex_pkg_dispatch.subr:exp_pkg_dispatch_expand_packages(): split from subr/ex_pkg.subr. subr/rtl_list.subr:rtl_lsort(): initial implementation. --- diff --git a/etc/README.md b/etc/README.md index 9278610..290a6dd 100644 --- a/etc/README.md +++ b/etc/README.md @@ -17,6 +17,7 @@ internal repositories required in order to build Midipix. 3.3. [Addressing build failure](#33-addressing-build-failure) 3.4. [Patches and ``vars`` files](#34-patches-and-vars-files) 3.5. [``pkgtool.sh``](#35-pkgtoolsh) + 3.5.1. [``-s``: package build shell environment](#351-s-package-build-shell-environment) 4. [Build variables](#4-build-variables) 4.1. [Build steps](#41-build-steps) 4.2. [Package variables](#42-package-variables) @@ -84,19 +85,18 @@ amount of logical processors on the build host divided by two (2). [//]: # "{{{ 2.1. Build-time dependencies" ### 2.1. Build-time dependencies -* **Alpine Linux**: binutils bzip2 cmake coreutils curl findutils g++ gawk gcc +* **Alpine Linux**: awk binutils bzip2 cmake coreutils curl findutils g++ gcc git grep gzip libc-dev linux-headers lzip make musl-dev net-tools patch perl perl-xml-parser procps sed tar util-linux wget xz zip -* **Debian/-derived Linux**: binutils bzip2 clzip cmake coreutils curl findutils - g++ gawk gcc git grep gzip hostname libc6-dev - libxml-parser-perl lzma make patch perl procps sed - tar util-linux wget xz-utils zip +* **Debian/-derived Linux**: awk binutils bzip2 clzip cmake coreutils curl findutils + g++ gcc git grep gzip hostname libc6-dev libxml-parser-perl + lzma make patch perl procps sed tar util-linux wget xz-utils zip * **OpenSUSE Linux**: binutils bzip2 cmake coreutils curl findutils gawk gcc gcc-c++ git grep gzip hostname linux-glibc-devel lzip make patch perl perl-XML-Parser procps sed tar util-linux wget xz zip - + > N.B. Busybox is not supported. [Back to top](#table-of-contents) @@ -117,12 +117,16 @@ defective. On successful completion of the build, a ZIP archive containing the Midipix distribution will be created inside ``${PREFIX}`` (see section [4](#4-build-variables).) -Extract its contents on the target machine, run ``bash.bat``, and then -``/install.sh`` inside the resulting self-contained Midipix installation shell -window. +Create a directory on the target machine and extract the contents of the distribution +ZIP archive into it, run ``bash.bat``, and then ``/install.sh`` inside the resulting +self-contained Midipix installation shell window. > N.B. The pathname of the target directory containing ``bash.bat`` and all other -distribution files must not contain whitespaces. +distribution files must not contain whitespaces. + +> N.B. The Midipix installer defaults to ``/dev/fs/c/midipix (C:\midipix)``. If left +unchanged, the distribution ZIP archive must not be extracted into a directory of the +same pathname. [Back to top](#table-of-contents) @@ -287,7 +291,7 @@ in, most usually, ``${PKG_BUILD_DIR}/config.log``. If ``--dump-on-abort`` was specified, a subset of the variables set and environment variables exported will be written to ``${BUILD_WORKDIR}/${PKG_NAME}.dump``, which may subsequently be used in order to obtain a package build shell environment with the -``pkgtool.sh`` script (see section [3.5](#35-pkgtoolsh).) +``pkgtool.sh`` script (see sections [3.5](#35-pkgtoolsh)[3.5.1](#351-s-package-build-shell-environment).) [Back to top](#table-of-contents) @@ -322,13 +326,43 @@ for a list of package build steps and how they are overriden. [//]: # "{{{ 3.5. ``pkgtool.sh``" ## 3.5. ``pkgtool.sh`` +``` +usage: ./pkgtool.sh [-a nt32|nt64] [-b debug|release] [-i|-r|-s|-t] + [=[ ..]] name + + -a nt32|nt64 Selects 32-bit or 64-bit architecture; defaults to nt64. + -b debug|release Selects debug or release build; defaults to debug. + -i List package variables and dependencies of single named package. + -r List reverse dependencies of single named package. + -s Enter interactive package build shell environment for single + named package; requires a package dump file. If the package + has not been built yet or built successfully, it will be rebuilt + at build steps up until, by default, the `build' build step and + forcibly aborted and dumped prior to enterting the shell. + -t Produce tarball of package build root directory and build log + file for the purpose of distribution given build failure. + + =[ ..] + Override build variable. +``` + +> N.B. When using ``pkgtool.sh`` on a build w/ build variables (see section [4](#4-build-variables)) +overriden on the command line or via the environment, ensure that they are included in the +``pkgtool.sh`` command line, preceding the package name, or exported, respectively. + +[Back to top](#table-of-contents) + +[//]: # "}}}" +[//]: # "{{{ 3.5.1. -s: package build shell environment" +### 3.5.1. -s: package build shell environment + When ``build.sh`` is executed with the ``--dump-on-abort`` option, a subset of the variables set and environment variables exported will be written to ``${BUILD_WORKDIR}/${PKG_NAME}.dump`` on build failure, which may subsequently be used in order to obtain a package build shell environment with the ``pkgtool.sh`` script, e.g.: ``` -midipix_build@sandbox:(src/midipix_build)> $ ./pkgtool.sh -a nt64 -b debug mc +midipix_build@sandbox:(src/midipix_build)> $ ./pkgtool.sh -a nt64 -b debug -s mc ==> 2020/03/11 15:46:28 Launching shell `/usr/bin/zsh' within package environment and `/home/midipix_build/midipix/nt64/debug/tmp'. ==> 2020/03/11 15:46:28 Run $R to rebuild `mc'. ==> 2020/03/11 15:46:28 Run $RS to restart the specified build step of `mc' @@ -345,10 +379,6 @@ Consult sections [3.2](#32-adding-a-package), [3.4](#34-patches-and-vars-files), [4.1](#41-build-steps), and [4.2](#42-package-variables) for further information concerning the package build process. -> N.B. When using ``pkgtool.sh`` on a build w/ build variables (see section [4](#4-build-variables)) -overriden on the command line or via the environment, ensure that they are included in the -``pkgtool.sh`` command line, preceding the package name, or exported, respectively. - [Back to top](#table-of-contents) [//]: # "}}}" diff --git a/etc/pkgtool.usage b/etc/pkgtool.usage new file mode 100644 index 0000000..aeed47b --- /dev/null +++ b/etc/pkgtool.usage @@ -0,0 +1,17 @@ +usage: ./pkgtool.sh [-a nt32|nt64] [-b debug|release] [-i|-r|-s|-t] + [=[ ..]] name + + -a nt32|nt64 Selects 32-bit or 64-bit architecture; defaults to nt64. + -b debug|release Selects debug or release build; defaults to debug. + -i List package variables and dependencies of single named package. + -r List reverse dependencies of single named package. + -s Enter interactive package build shell environment for single + named package; requires a package dump file. If the package + has not been built yet or built successfully, it will be rebuilt + at build steps up until, by default, the `build' build step and + forcibly aborted and dumped prior to enterting the shell. + -t Produce tarball of package build root directory and build log + file for the purpose of distribution given build failure. + + =[ ..] + Override build variable. diff --git a/pkgtool.sh b/pkgtool.sh index 2241f4a..e6768e8 100755 --- a/pkgtool.sh +++ b/pkgtool.sh @@ -1,7 +1,35 @@ #!/bin/sh -# Copyright (c) 2019 Lucio Andrés Illanes Albornoz +# Copyright (c) 2020 Lucio Andrés Illanes Albornoz # +pkgtoolp_info() { + local _group_name="" _pkg_name_uc="$(rtl_toupper "${PKG_NAME}")" _pkg_names="" \ + EX_PKG_DISABLED=""; EX_PKG_FINISHED=""; EX_PKG_NAMES=""; + if ! _group_name="$(ex_pkg_find_package "${BUILD_GROUPS}" "${PKG_NAME}")"; then + rtl_log_msg failexit "Error: unknown package \`${PKG_NAME}'."; + elif ! _pkg_names="$(ex_pkg_get_packages "${_group_name}")"; then + rtl_log_msg failexit "Error: failed to expand package list of build group \`${_group_name}'."; + elif ! ex_pkg_env "${DEFAULT_BUILD_STEPS}" "${DEFAULT_BUILD_VARS}" \ + "${_group_name}" 1 "${PKG_NAME}" "" "${BUILD_WORKDIR}"; then + rtl_log_msg failexit "Error: failed to set package environment for \`${PKG_NAME}'."; + else rtl_log_env_vars "package" $(set | awk -F= '/^PKG_'"${_pkg_name_uc}"'_/{print $1}' | sort); + if [ -z "${PKG_DEPENDS}" ]; then + rtl_log_msg info "Package \`${PKG_NAME}' has no dependencies."; + else rtl_log_msg info "Direct dependencies of \`${PKG_NAME}': ${PKG_DEPENDS}"; + if ! ex_pkg_unfold_depends "${_group_name}" "${_pkg_names}" "${PKG_NAME}" 2 0; then + rtl_log_msg warn "Warning: failed to unfold dependency-expanded package name list for \`${PKG_NAME}'."; + else EX_PKG_NAMES="$(rtl_lfilter "${EX_PKG_NAMES}" "${PKG_NAME}")"; + if [ -n "${EX_PKG_NAMES}" ]; then + rtl_log_msg info "Full dependencies of \`${PKG_NAME}': $(rtl_lsort "${EX_PKG_NAMES}")"; + fi; + if [ -n "${EX_PKG_DISABLED}" ]; then + rtl_log_msg info "Full dependencies of \`${PKG_NAME}' (disabled packages:) $(rtl_lsort "${EX_PKG_DISABLED}")"; + fi; + fi; + fi; + fi; +}; + pkgtoolp_restart_at() { case "${ARG_RESTART_AT}" in ALL) "${MIDIPIX_BUILD_PWD}/build.sh" -P -r "${PKG_NAME}" -v; ;; @@ -9,7 +37,27 @@ pkgtoolp_restart_at() { esac; }; +pkgtoolp_rdepends() { + local _group_name="" _pkg_names="" EX_PKG_DISABLED=""; EX_PKG_FINISHED=""; EX_PKG_NAMES=""; + if ! _group_name="$(ex_pkg_find_package "${BUILD_GROUPS}" "${PKG_NAME}")"; then + rtl_log_msg failexit "Error: unknown package \`${PKG_NAME}'."; + elif ! _pkg_names="$(ex_pkg_get_packages "${_group_name}")"; then + rtl_log_msg failexit "Error: failed to expand package list of build group \`${_group_name}'."; + elif ! ex_pkg_unfold_rdepends "${_group_name}" "${_pkg_names}" "${PKG_NAME}" 0; then + rtl_log_msg failexit "Error: failed to unfold reverse dependency-expanded package name list for \`${PKG_NAME}'."; + elif [ -z "${EX_PKG_NAMES}" ] && [ -z "${EX_PKG_DISABLED}" ]; then + rtl_log_msg info "Package \`${PKG_NAME}' has no reverse dependencies."; + else if [ -n "${EX_PKG_NAMES}" ]; then + rtl_log_msg info "Reverse dependencies of \`${PKG_NAME}': $(rtl_lsort "${EX_PKG_NAMES}")"; + fi; + if [ -n "${EX_PKG_DISABLED}" ]; then + rtl_log_msg info "Reverse dependencies of \`${PKG_NAME}' (disabled packages:) $(rtl_lsort "${EX_PKG_DISABLED}")"; + fi; + fi; +}; + pkgtoolp_shell() { + rtl_log_env_vars "build" $(set | awk -F= '/^PKG_/{print $1}' | sort); rtl_log_msg info "Launching shell \`${SHELL}' within package environment and \`${PKG_BUILD_DIR}'."; rtl_log_msg info "Run \$R to rebuild \`${PKG_NAME}'."; rtl_log_msg info "Run \$RS to restart the specified build step of \`${PKG_NAME}'"; @@ -27,6 +75,35 @@ pkgtoolp_shell() { "${SHELL}"; }; +pkgtoolp_tarball() { + local _date="" _group_name="" _hname="" _pkg_name_full="" _pkg_version="" _tarball_fname=""; + if ! _group_name="$(ex_pkg_find_package "${BUILD_GROUPS}" "${PKG_NAME}")"; then + rtl_log_msg failexit "Error: unknown package \`${PKG_NAME}'."; + elif ! ex_pkg_env "${DEFAULT_BUILD_STEPS}" "${DEFAULT_BUILD_VARS}" \ + "${_group_name}" "${PKG_NAME}" "" "${BUILD_WORKDIR}"; then + rtl_log_msg failexit "Error: failed to set package environment for \`${PKG_NAME}'."; + elif ! _date="$(date +%Y%m%d_%H%M%S)"; then + rtl_log_msg failexit "Error: failed to call date(1)."; + elif ! _hname="$(hostname -f)"; then + rtl_log_msg failexit "Error: failed to call hostname(1)."; + else if [ -n "${PKG_VERSION}" ]; then + _pkg_name_full="${PKG_NAME}-${PKG_VERSION}"; + else + _pkg_name_full="${PKG_NAME}"; + fi; + _tarball_fname="${_pkg_name_full}@${_hname}-${_date}.tbz2"; + rtl_log_msg info "Creating compressed tarball of \`${PKG_BASE_DIR}' and \`${PKG_NAME}_stderrout.log'..."; + if ! tar -C "${BUILD_WORKDIR}" -cpf - \ + "${PKG_BASE_DIR#${BUILD_WORKDIR%/}/}" \ + "${PKG_NAME}_stderrout.log" |\ + bzip2 -c -9 - > "${_tarball_fname}"; then + rtl_log_msg failexit "Error: failed to create compressed tarball of \`${PKG_BASE_DIR}' and \`${PKG_NAME}_stderrout.log'."; + else + rtl_log_msg info "Created compressed tarball of \`${PKG_BASE_DIR}' and \`${PKG_NAME}_stderrout.log'."; + fi; + fi; +}; + pkgtoolp_update_diff() { local _diff_fname_dst="" _diff_fname_src="" _fname="" _fname_base=""; if [ -n "${PKG_VERSION}" ]; then @@ -56,43 +133,24 @@ pkgtoolp_update_diff() { fi; }; -pkgtoolp_env() { - local _rc=0; _status=""; - if [ ! -e "${BUILD_WORKDIR}/${PKG_NAME}.dump" ]; then - rtl_log_msg fail "Warning: failed to locate environment dump for package \`${PKG_NAME}' in \`${BUILD_WORKDIR}'."; - rtl_log_msg info "Rebuilding package \`${PKG_NAME}' w/ --dump-in build..."; - (export ARCH BUILD \ - BUILD_DLCACHEDIR BUILD_WORKDIR \ - PREFIX PREFIX_CROSS PREFIX_MINGW32 PREFIX_MINIPIX \ - PREFIX_NATIVE PREFIX_ROOT PREFIX_RPM; - ./build.sh -a "${ARCH}" -b "${BUILD}" --dump-in build -P -r "${PKG_NAME}" -v); - if [ ! -e "${BUILD_WORKDIR}/${PKG_NAME}.dump" ]; then - _rc=1; _status="Error: failed to locate environment dump for package \`${PKG_NAME}' in \`${BUILD_WORKDIR}'."; - fi; - else - _rc=0; - fi; - if [ "${_rc:-0}" -eq 0 ]\ - && ! . "${BUILD_WORKDIR}/${PKG_NAME}.dump"; then - _rc=1; _status="Error: failed to source environment dump for package \`${PKG_NAME}' from \`${BUILD_WORKDIR}'."; - fi; return "${_rc}"; -}; - pkgtool() { local _status=""; if ! cd "$(dirname "${0}")"\ || ! . ./subr/pkgtool_init.subr\ || ! pkgtool_init "${@}"; then printf "Error: failed to setup environment.\n"; exit 1; - elif ! pkgtoolp_env; then - rtl_log_msg failexit "${_status}"; - elif ! rtl_fileop cd "${PKG_BUILD_DIR}"; then - rtl_log_msg failexit "Error: failed to change working directory to \`${PKG_BUILD_DIR}'."; elif [ -n "${ARG_RESTART_AT}" ]; then pkgtoolp_restart_at; elif [ "${ARG_UPDATE_DIFF:-0}" -eq 1 ]; then pkgtoolp_update_diff; - else pkgtoolp_shell; + elif [ "${ARG_INFO:-0}" -eq 1 ]; then + pkgtoolp_info; + elif [ "${ARG_RDEPENDS:-0}" -eq 1 ]; then + pkgtoolp_rdepends; + elif [ "${ARG_SHELL:-0}" -eq 1 ]; then + pkgtoolp_shell; + elif [ "${ARG_TARBALL:-0}" -eq 1 ]; then + pkgtoolp_tarball; fi; }; diff --git a/subr/ex_pkg.subr b/subr/ex_pkg.subr index 68587dd..497e89c 100644 --- a/subr/ex_pkg.subr +++ b/subr/ex_pkg.subr @@ -4,7 +4,8 @@ # # ex_pkg_check_depends() - check single named package for unsatisfied dependencies -# @_pkg_complete: list of completed packages +# @_pkg_disabled: list of disabled packages +# @_pkg_finished: list of finished packages # @_pkg_name: single package name # @_pkg_wait: list of in-progress packages # @_restart_recursive: optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2,) forcibly rebuild reverse dependencies (3.) @@ -12,15 +13,18 @@ # Return: zero (0) given no outstanding dependencies, non-zero (>0) otherwise # ex_pkg_check_depends() { - local _pkg_complete="${1}" _pkg_name="${2}" _pkg_wait="${3}" _restart_recursive="${4}" \ + local _pkg_disabled="${1}" _pkg_finished="${2}" _pkg_name="${3}" \ + _pkg_wait="${4}" _restart_recursive="${5}" \ _pkg_depends="" _pkg_name_depend="" _dependfl=0; - if _pkg_depends="$(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' $(rtl_get_var_unsafe -u "PKG_"${_pkg_name}"_DEPENDS"))"\ + if _pkg_depends="$(rtl_uniq $(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' $(rtl_get_var_unsafe -u "PKG_"${_pkg_name}"_DEPENDS")))"\ && [ -n "${_pkg_depends}" ]; then if [ -z "${_restart}" ]\ || [ "${_restart_recursive:-0}" -ge 1 ]; then for _pkg_name_depend in $(rtl_uniq ${_pkg_depends}); do - if ! rtl_lmatch "${_pkg_complete}" "${_pkg_name_depend}"\ - || rtl_lmatch "${_pkg_wait}" "${_pkg_name_depend}"; then + if ! rtl_lmatch "${_pkg_disabled}" "${_pkg_name_depend}"\ + && ! rtl_lmatch "${_pkg_finished}" "${_pkg_name_depend}"; then + _dependfl=1; break; + elif rtl_lmatch "${_pkg_wait}" "${_pkg_name_depend}"; then _dependfl=1; break; fi; done; @@ -30,89 +34,137 @@ ex_pkg_check_depends() { }; # -# ex_pkg_expand_packages() - expand build group name to list of packages ordered and filtered according to dependency and restart constraints +# ex_pkg_find_package() - find build group a single named package belongs to +# @_group_names: build group names +# @_pkg_name: single named package +# +# Return: zero (0) on success, non-zero (>0) if package not found, group name on stdout if package was found. +# +ex_pkg_find_package() { + local _group_names="${1}" _pkg_name="${2}" _group_name="" _pkg_names=""; + for _group_name in ${_group_names}; do + if _pkg_names="$(rtl_get_var_unsafe -u "${_group_name}_PACKAGES")"\ + && [ -n "${_pkg_names}" ]\ + && rtl_lmatch "${_pkg_names}" "${_pkg_name}"; then + _foundfl=1; break; + fi; + done; + case "${_foundfl:-0}" in + 0) return 1; ;; + 1) echo "${_group_name}"; return 0; ;; + esac; +}; + +# +# ex_pkg_get_packages() - get list of packages belonging to single named build group +# @_group_name: build group name +# +# Return: zero (0) on success, non-zero (>0) on failure, list of package names on stdout on success. +# +ex_pkg_get_packages() { + local _group_name="${1}" _pkg_names=""; + if _pkg_names="$(rtl_get_var_unsafe -u "${_group_name}_PACKAGES")"\ + && [ -n "${_pkg_names}" ]; then + echo "${_pkg_names}"; return 0; + else + return 1; + fi; +}; + +# +# ex_pkg_unfold_depends() - unfold list of package names into dependency-expanded set of complete, disabled, finished, and outstanding package names # @_group_name: build group name +# @_pkg_names: list of package names # @_restart: optional whitespace-separated list of package names to rebuild # @_restart_recursive: optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2,) forcibly rebuild reverse dependencies (3.) +# @_test_finished: only exclude disabled packages from ${EX_PKG_NAMES} (0,) split finished packages into ${EX_PKG_FINISHED} # -# Return: zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_COMPLETE}, ${EXP_PKG_DISABLED}, ${EXP_PKG_FINISHED}, and ${EXP_PKG_NAMES} set post-return. +# Return: zero (0) on success, non-zero (>0) on failure, ${EX_PKG_DISABLED}, ${EX_PKG_FINISHED}, and ${EX_PKG_NAMES} set post-return. # -ex_pkg_expand_packages() { - local _group_name="${1}" _restart="${2}" _restart_recursive="${3}" \ - _pkg_depends="" _pkg_name="" _pkg_name_depend="" _pkg_names="" \ - _pkg_rdepends="" _restartfl=0; - EXP_PKG_COMPLETE=""; EXP_PKG_DISABLED=""; EXP_PKG_FINISHED=""; EXP_PKG_NAMES=""; - if _pkg_names="$(rtl_get_var_unsafe -u "${_group_name}_PACKAGES")"\ - && [ -n "${_pkg_names}" ]; then - if [ "${_restart_recursive:-0}" -ne 3 ]; then - if [ -n "${_restart}" ] && ! rtl_lmatch "${_restart}" "ALL LAST"; then - _pkg_names="$(rtl_lsearch "${_pkg_names}" "${_restart}")"; - fi; - if [ -n "${_restart}" ]\ - && [ "${_restart_recursive:-0}" -ge 1 ]\ - && [ "${_restart_recursive:-0}" -le 2 ]; then - _pkg_names="$(rtl_uniq $(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' ${_pkg_names}))"; +ex_pkg_unfold_depends() { + local _group_name="${1}" _pkg_names="${2}" _restart="${3}" \ + _restart_recursive="${4}" _test_finished="${5}" \ + _pkg_name="" _restartfl=0; + if [ -n "${_restart}" ] && ! rtl_lmatch "${_restart}" "ALL LAST"; then + _pkg_names="$(rtl_lsearch "${_pkg_names}" "${_restart}")"; + fi; + if [ -n "${_restart}" ]\ + && [ "${_restart_recursive:-0}" -ge 1 ]\ + && [ "${_restart_recursive:-0}" -le 2 ]; then + _pkg_names="$(rtl_uniq $(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' ${_pkg_names}))"; + fi; + for _pkg_name in ${_pkg_names}; do + if [ "${_restart}" = "ALL" ]\ + || rtl_lmatch "${_restart}" "${_pkg_name}"; then + _restartfl=1; + else + _restartfl=0; + fi; + if [ "x$(rtl_get_var_unsafe -u "PKG_${_pkg_name}_DISABLED")" = "x1" ]; then + EX_PKG_DISABLED="$(rtl_lconcat "${EX_PKG_DISABLED}" "${_pkg_name}")"; + _pkg_names="$(rtl_lfilter "${_pkg_names}" "${_pkg_name}")"; + elif [ "${_test_finished:-1}" -eq 1 ]\ + && ex_pkg_state_test "${_pkg_name}" finish\ + && [ "${_restartfl:-0}" -eq 0 ]\ + && [ "${_restart_recursive:-0}" -ne 2 ]\ + && [ "x$(rtl_get_var_unsafe -u "${_group_name}_FORCE")" != "x1" ]; then + EX_PKG_FINISHED="$(rtl_lconcat "${EX_PKG_FINISHED}" "${_pkg_name}")"; + _pkg_names="$(rtl_lfilter "${_pkg_names}" "${_pkg_name}")"; + fi; + done; + EX_PKG_DISABLED="$(rtl_uniq ${EX_PKG_DISABLED})"; + EX_PKG_FINISHED="$(rtl_uniq ${EX_PKG_FINISHED})"; + EX_PKG_NAMES="$(rtl_uniq ${_pkg_names})"; +}; + +# +# ex_pkg_unfold_rdepends() - unfold list of package names into reverse dependency-expanded set of complete, disabled, finished, and outstanding package names +# @_group_name: build group name +# @_pkg_names: list of package names +# @_restart: optional whitespace-separated list of package names to rebuild +# @_restart_recursive: optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2,) forcibly rebuild reverse dependencies (3.) +# @_test_finished: only exclude disabled packages from ${EX_PKG_NAMES} (0,) split finished packages into ${EX_PKG_FINISHED} +# +# Return: zero (0) on success, non-zero (>0) on failure, ${EX_PKG_DISABLED}, ${EX_PKG_FINISHED}, and ${EX_PKG_NAMES} set post-return. +# +ex_pkg_unfold_rdepends() { + local _group_name="${1}" _pkg_names="${2}" _restart="${3}" _test_finished="${4}" \ + _pkg_depends="" _pkg_name="" _pkg_name_depend="" _pkg_rdepends="" _restartfl=0; + for _pkg_name_depend in ${_restart}; do + for _pkg_name in ${_pkg_names}; do + if [ "${_pkg_name}" != "${_pkg_name_depend}" ]\ + && [ "x$(rtl_get_var_unsafe -u "PKG_${_pkg_name}_DISABLED")" != "x1" ]\ + && _pkg_depends="$(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' $(rtl_get_var_unsafe -u "PKG_"${_pkg_name}"_DEPENDS"))"\ + && [ -n "${_pkg_depends}" ]\ + && rtl_lmatch "${_pkg_depends}" "${_pkg_name_depend}"; then + _pkg_rdepends="$(rtl_lconcat "${_pkg_rdepends}" "${_pkg_name}")"; fi; - for _pkg_name in ${_pkg_names}; do - if [ "${_restart}" = "ALL" ]\ - || rtl_lmatch "${_restart}" "${_pkg_name}"; then - _restartfl=1; - else - _restartfl=0; - fi; - if [ "x$(rtl_get_var_unsafe -u "PKG_${_pkg_name}_DISABLED")" = "x1" ]; then - EXP_PKG_COMPLETE="$(rtl_lconcat "${EXP_PKG_COMPLETE}" "${_pkg_name}")"; - EXP_PKG_DISABLED="$(rtl_lconcat "${EXP_PKG_DISABLED}" "${_pkg_name}")"; - _pkg_names="$(rtl_lfilter "${_pkg_names}" "${_pkg_name}")"; - elif ex_pkg_state_test "${_pkg_name}" finish\ - && [ "${_restartfl:-0}" -eq 0 ]\ - && [ "${_restart_recursive:-0}" -ne 2 ]\ - && [ "x$(rtl_get_var_unsafe -u "${_group_name}_FORCE")" != "x1" ]; then - EXP_PKG_COMPLETE="$(rtl_lconcat "${EXP_PKG_COMPLETE}" "${_pkg_name}")"; - EXP_PKG_FINISHED="$(rtl_lconcat "${EXP_PKG_FINISHED}" "${_pkg_name}")"; - _pkg_names="$(rtl_lfilter "${_pkg_names}" "${_pkg_name}")"; + done; + done; + _pkg_names=""; + for _pkg_name in ${_pkg_rdepends}; do + if _pkg_depends="$(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' $(rtl_get_var_unsafe -u "PKG_"${_pkg_name}"_DEPENDS"))"\ + && [ -n "${_pkg_depends}" ]; then + for _pkg_name_depend in ${_pkg_depends}; do + if [ "x$(rtl_get_var_unsafe -u "PKG_${_pkg_name_depend}_DISABLED")" = "x1" ]; then + EX_PKG_DISABLED="$(rtl_lconcat "${EX_PKG_DISABLED}" "${_pkg_name_depend}")"; + elif [ "${_test_finished:-1}" -eq 1 ]\ + && ex_pkg_state_test "${_pkg_name_depend}" finish\ + && [ "x$(rtl_get_var_unsafe -u "${_group_name}_FORCE")" != "x1" ]\ + && ! rtl_lmatch "${_pkg_rdepends}" "${_pkg_name_depend}"; then + EX_PKG_FINISHED="$(rtl_lconcat "${EX_PKG_FINISHED}" "${_pkg_name_depend}")"; + elif [ "${_test_finished:-1}" -eq 0 ]\ + || ! ex_pkg_state_test "${_pkg_name_depend}" finish\ + || [ "x$(rtl_get_var_unsafe -u "${_group_name}_FORCE")" = "x1" ]; then + _pkg_names="$(rtl_lconcat "${_pkg_names}" "${_pkg_name_depend}")"; fi; done; - else for _pkg_name_depend in ${_restart}; do - for _pkg_name in ${_pkg_names}; do - if [ "${_pkg_name}" != "${_pkg_name_depend}" ]\ - && [ "x$(rtl_get_var_unsafe -u "PKG_${_pkg_name}_DISABLED")" != "x1" ]\ - && _pkg_depends="$(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' $(rtl_get_var_unsafe -u "PKG_"${_pkg_name}"_DEPENDS"))"\ - && [ -n "${_pkg_depends}" ]\ - && rtl_lmatch "${_pkg_depends}" "${_pkg_name_depend}"; then - _pkg_rdepends="$(rtl_lconcat "${_pkg_rdepends}" "${_pkg_name}")"; - fi; - done; - done; - _pkg_names=""; - for _pkg_name in ${_pkg_rdepends}; do - if _pkg_depends="$(rtl_lunfold_depends 'PKG_${_name}_DEPENDS' $(rtl_get_var_unsafe -u "PKG_"${_pkg_name}"_DEPENDS"))"\ - && [ -n "${_pkg_depends}" ]; then - for _pkg_name_depend in ${_pkg_depends}; do - if [ "x$(rtl_get_var_unsafe -u "PKG_${_pkg_name_depend}_DISABLED")" = "x1" ]; then - EXP_PKG_COMPLETE="$(rtl_lconcat "${EXP_PKG_COMPLETE}" "${_pkg_name_depend}")"; - EXP_PKG_DISABLED="$(rtl_lconcat "${EXP_PKG_DISABLED}" "${_pkg_name_depend}")"; - elif ex_pkg_state_test "${_pkg_name_depend}" finish\ - && [ "x$(rtl_get_var_unsafe -u "${_group_name}_FORCE")" != "x1" ]\ - && ! rtl_lmatch "${_pkg_rdepends}" "${_pkg_name_depend}"; then - EXP_PKG_COMPLETE="$(rtl_lconcat "${EXP_PKG_COMPLETE}" "${_pkg_name_depend}")"; - EXP_PKG_FINISHED="$(rtl_lconcat "${EXP_PKG_FINISHED}" "${_pkg_name_depend}")"; - elif ! ex_pkg_state_test "${_pkg_name_depend}" finish\ - || [ "x$(rtl_get_var_unsafe -u "${_group_name}_FORCE")" = "x1" ]; then - _pkg_names="$(rtl_lconcat "${_pkg_names}" "${_pkg_name_depend}")"; - fi; - done; - fi; - _pkg_names="$(rtl_lconcat "${_pkg_names}" "${_pkg_name}")"; - done; - EXP_PKG_COMPLETE="$(rtl_uniq ${EXP_PKG_COMPLETE})"; - EXP_PKG_DISABLED="$(rtl_uniq ${EXP_PKG_DISABLED})"; - EXP_PKG_FINISHED="$(rtl_uniq ${EXP_PKG_FINISHED})"; - _pkg_names="$(rtl_uniq ${_pkg_names})"; fi; - EXP_PKG_NAMES="${_pkg_names}"; - fi; - return 0; + _pkg_names="$(rtl_lconcat "${_pkg_names}" "${_pkg_name}")"; + done; + EX_PKG_DISABLED="$(rtl_uniq ${EX_PKG_DISABLED})"; + EX_PKG_FINISHED="$(rtl_uniq ${EX_PKG_FINISHED})"; + EX_PKG_NAMES="$(rtl_uniq ${_pkg_names})"; }; # vim:filetype=sh textwidth=0 diff --git a/subr/ex_pkg_dispatch.subr b/subr/ex_pkg_dispatch.subr index 5274d3f..5426b8d 100644 --- a/subr/ex_pkg_dispatch.subr +++ b/subr/ex_pkg_dispatch.subr @@ -22,6 +22,27 @@ exp_pkg_dispatch_complete() { }; # +# exp_pkg_dispatch_expand_packages() - expand build group name to list of packages ordered and filtered according to dependency and restart constraints +# @_group_name: build group name +# @_restart: optional whitespace-separated list of package names to rebuild +# @_restart_recursive: optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2,) forcibly rebuild reverse dependencies (3.) +# +# Return: zero (0) on success, non-zero (>0) on failure, ${EX_PKG_DISABLED}, ${EX_PKG_FINISHED}, and ${EX_PKG_NAMES} set post-return. +# +exp_pkg_dispatch_expand_packages() { + local _group_name="${1}" _restart="${2}" _restart_recursive="${3}" _pkg_names=""; + EX_PKG_DISABLED=""; EX_PKG_FINISHED=""; EX_PKG_NAMES=""; + if _pkg_names="$(rtl_get_var_unsafe -u "${_group_name}_PACKAGES")"\ + && [ -n "${_pkg_names}" ]; then + if [ "${_restart_recursive:-0}" -ne 3 ]; then + ex_pkg_unfold_depends "${_group_name}" "${_pkg_names}" "${_restart}" "${_restart_recursive}" 1; + else ex_pkg_unfold_rdepends "${_group_name}" "${_pkg_names}" "${_restart}" 1; + fi; + fi; + return 0; +}; + +# # exp_pkg_dispatch_group() - dispatch a single build group # @_build_steps_default: list of default build steps # @_build_vars_default: list of default build variables @@ -43,18 +64,19 @@ exp_pkg_dispatch_group() { while true; do while [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -gt 0 ] && read _pipe_msg; do case "${_pipe_msg%% *}" in - done) : $((EXP_PKG_DISPATCH_NJOBS-=1)); _pkg_name="${_pipe_msg#done * }"; + done) _pkg_name="${_pipe_msg#done * }"; : $((EXP_PKG_DISPATCH_NJOBS-=1)); + EX_PKG_FINISHED="$(rtl_lconcat "${EX_PKG_FINISHED}" "${_pkg_name}")"; "${_dispatch_fn}" finish_pkg ${_pipe_msg#done }; - EXP_PKG_COMPLETE="$(rtl_lconcat "${EXP_PKG_COMPLETE}" "${_pkg_name}")"; - EXP_PKG_NAMES="$(rtl_lfilter "${EXP_PKG_NAMES}" "${_pkg_name}")"; + EX_PKG_NAMES="$(rtl_lfilter "${EX_PKG_NAMES}" "${_pkg_name}")"; EX_PKG_DISPATCH_WAIT="$(rtl_lfilter "${EX_PKG_DISPATCH_WAIT}" "${_pkg_name}")"; - if [ -n "${EXP_PKG_NAMES}" ] && [ "${_rc}" -eq 0 ]; then + if [ -n "${EX_PKG_NAMES}" ] && [ "${_rc}" -eq 0 ]; then if [ "${EXP_PKG_DISPATCH_NJOBS}" -ne "${_njobs_max}" ]; then exp_pkg_dispatch_packages "${_build_steps_default}" \ "${_build_vars_default}" "${_dispatch_fn}" \ "${_group_name}" "${_njobs_max}" \ - "${_pipe_path}" "${EXP_PKG_COMPLETE}" \ - "${_restart_at}" "${_restart_recursive}" "${_workdir}"; + "${_pipe_path}" "${EX_PKG_DISABLED}" \ + "${EX_PKG_FINISHED}" "${_restart_at}" \ + "${_restart_recursive}" "${_workdir}"; fi; elif [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -eq 0 ]; then break; @@ -65,13 +87,14 @@ exp_pkg_dispatch_group() { "${_dispatch_fn}" msg_pkg ${_pipe_msg#msg_pkg }; ;; step) "${_dispatch_fn}" step_pkg ${_pipe_msg#step }; ;; esac; done <>"${_pipe_path}"; - if [ -n "${EXP_PKG_NAMES}" ] && [ "${_rc}" -eq 0 ]; then + if [ -n "${EX_PKG_NAMES}" ] && [ "${_rc}" -eq 0 ]; then if [ "${EXP_PKG_DISPATCH_NJOBS}" -ne "${_njobs_max}" ]; then exp_pkg_dispatch_packages "${_build_steps_default}" \ "${_build_vars_default}" "${_dispatch_fn}" \ "${_group_name}" "${_njobs_max}" "${_pipe_path}" \ - "${EXP_PKG_COMPLETE}" "${_restart_at}" \ - "${_restart_recursive}" "${_workdir}"; + "${EX_PKG_DISABLED}" "${EX_PKG_FINISHED}" \ + "${_restart_at}" "${_restart_recursive}" \ + "${_workdir}"; fi; elif [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -eq 0 ]; then break; @@ -91,7 +114,7 @@ exp_pkg_dispatch_group() { # @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL # @_workdir: pathname to build-specific temporary directory # -# Return: zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_DISPATCH_NJOBS}, ${EXP_PKG_DISPATCH_COUNT}, ${EXP_PKG_NAMES}, and ${EX_PKG_DISPATCH_WAIT} may be mutated post-return. +# Return: zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_DISPATCH_NJOBS}, ${EXP_PKG_DISPATCH_COUNT}, ${EX_PKG_NAMES}, and ${EX_PKG_DISPATCH_WAIT} may be mutated post-return. # exp_pkg_dispatch_package() { local _build_steps_default="${1}" _build_vars_default="${2}" _dispatch_fn="${3}" \ @@ -100,7 +123,7 @@ exp_pkg_dispatch_package() { : $((EXP_PKG_DISPATCH_NJOBS+=1)); : $((EXP_PKG_DISPATCH_COUNT+=1)); EX_PKG_DISPATCH_WAIT="$(rtl_lconcat "${EX_PKG_DISPATCH_WAIT}" "${_pkg_name}")"; (set +o errexit -o noglob; BUILD_IS_PARENT=0; if ex_pkg_env "${_build_steps_default}" "${_build_vars_default}" \ - "${_group_name}" "${_pkg_name}" "${_restart_at}" "${_workdir}"; then + "${_group_name}" 0 "${_pkg_name}" "${_restart_at}" "${_workdir}"; then ex_pkg_exec "${_dispatch_fn}" "${_group_name}" "${_pkg_name}" "${_restart_at}"; else return 1; @@ -118,24 +141,27 @@ exp_pkg_dispatch_package() { # @_group_name: build group name # @_njobs_max: maximum count of simultaneous jobs # @_pipe_path: pathname to parent-child process FIFO -# @_pkg_complete: list of completed packages +# @_pkg_disabled: list of disabled packages +# @_pkg_finished: list of finished packages # @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL # @_restart_recursive: optional flag specifiying either no dependency expansion (0,) dependency expansion (1,) dependency expansion and forcibly rebuild (2,) forcibly rebuild reverse dependencies (3.) # @_workdir: pathname to build-specific temporary directory # -# Return: zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_DISPATCH_NJOBS}, ${EXP_PKG_DISPATCH_COUNT}, ${EXP_PKG_NAMES}, and ${EX_PKG_DISPATCH_WAIT} may be mutated post-return. +# Return: zero (0) on success, non-zero (>0) on failure, ${EXP_PKG_DISPATCH_NJOBS}, ${EXP_PKG_DISPATCH_COUNT}, ${EX_PKG_NAMES}, and ${EX_PKG_DISPATCH_WAIT} may be mutated post-return. # exp_pkg_dispatch_packages() { local _build_steps_default="${1}" _build_vars_default="${2}" _dispatch_fn="${3}" \ - _group_name="${4}" _njobs_max="${5}" _pipe_path="${6}" _pkg_complete="${7}" \ - _restart_at="${8}" _restart_recursive="${9}" _workdir="${10}" \ + _group_name="${4}" _njobs_max="${5}" _pipe_path="${6}" _pkg_disabled="${7}" \ + _pkg_finished="${8}" _restart_at="${9}" _restart_recursive="${10}" _workdir="${11}" \ _foundfl=0 _njob=0 _pkg_depends="" _pkg_name=""; while [ "${EXP_PKG_DISPATCH_NJOBS:-0}" -lt "${_njobs_max}" ]; do _foundfl=0; - for _pkg_name in ${EXP_PKG_NAMES}; do - if ! rtl_lmatch "${_pkg_complete}" "${_pkg_name}"\ + for _pkg_name in ${EX_PKG_NAMES}; do + if ! rtl_lmatch "${_pkg_disabled}" "${_pkg_name}"\ + && ! rtl_lmatch "${_pkg_finished}" "${_pkg_name}"\ && ! rtl_lmatch "${EX_PKG_DISPATCH_WAIT}" "${_pkg_name}"\ - && ex_pkg_check_depends "${_pkg_complete}" "${_pkg_name}" "${EX_PKG_DISPATCH_WAIT}" "${_restart_recursive}"; then + && ex_pkg_check_depends "${_pkg_disabled}" "${_pkg_finished}" "${_pkg_name}" \ + "${EX_PKG_DISPATCH_WAIT}" "${_restart_recursive}"; then exp_pkg_dispatch_package "${_build_steps_default}" \ "${_build_vars_default}" "${_dispatch_fn}" \ "${_group_name}" "${_pkg_name}" "${_restart_at}" \ @@ -169,25 +195,23 @@ ex_pkg_dispatch() { _group_names="${4}" _groups_inhibit_deps="${5}" _njobs_max="${6}" _pipe_path="${7}" \ _restart="${8}" _restart_at="${9}" _restart_recursive="${10}" _workdir="${11}" \ _pkg_name="" _pkg_names="" _rc=0 \ - EXP_PKG_COMPLETE EXP_PKG_DISABLED EXP_PKG_FINISHED EXP_PKG_DISPATCH_COUNT \ - EXP_PKG_DISPATCH_COUNT_MAX EXP_PKG_DISPATCH_NJOBS EXP_PKG_NAMES; - EX_PKG_DISPATCH_WAIT=""; + EX_PKG_DISABLED EX_PKG_FINISHED EX_PKG_NAMES EXP_PKG_DISPATCH_COUNT \ + EXP_PKG_DISPATCH_COUNT_MAX EXP_PKG_DISPATCH_NJOBS; EX_PKG_DISPATCH_WAIT=""; if [ "${_groups_inhibit_deps:-0}" -eq 0 ]; then _group_names="$(rtl_uniq $(rtl_lunfold_depends '${_name}_GROUP_DEPENDS' ${_group_names}))"; fi; for _group_name in ${_group_names}; do - EXP_PKG_COMPLETE="" EXP_PKG_DISABLED="" EXP_PKG_FINISHED=""; - EXP_PKG_DISPATCH_COUNT=0 EXP_PKG_DISPATCH_COUNT_MAX=0 EXP_PKG_DISPATCH_NJOBS=0; - EXP_PKG_NAMES="" EX_PKG_DISPATCH_WAIT=""; + EX_PKG_DISABLED=""; EX_PKG_DISPATCH_WAIT=""; EX_PKG_FINISHED=""; EX_PKG_NAMES=""; + EXP_PKG_DISPATCH_COUNT=0; EXP_PKG_DISPATCH_COUNT_MAX=0; EXP_PKG_DISPATCH_NJOBS=0; if "${_dispatch_fn}" start_group "${_group_name}" ""; then if rtl_fileop mkdir "${_workdir}"\ && rtl_log_msg vnfo "Resolving \`${_group_name}' dependencies..."\ - && ex_pkg_expand_packages "${_group_name}" "${_restart}" "${_restart_recursive}"\ - && exp_pkg_dispatch_complete "${_dispatch_fn}" "${_group_name}" "${EXP_PKG_DISABLED}" "${EXP_PKG_FINISHED}"\ + && exp_pkg_dispatch_expand_packages "${_group_name}" "${_restart}" "${_restart_recursive}"\ + && exp_pkg_dispatch_complete "${_dispatch_fn}" "${_group_name}" "${EX_PKG_DISABLED}" "${EX_PKG_FINISHED}"\ && rtl_log_msg vnfo "Resolved \`${_group_name}' dependencies."\ - && EXP_PKG_DISPATCH_COUNT_MAX="$(rtl_llength "${EXP_PKG_NAMES}")"\ + && EXP_PKG_DISPATCH_COUNT_MAX="$(rtl_llength "${EX_PKG_NAMES}")"\ && [ "${EXP_PKG_DISPATCH_COUNT_MAX}" -gt 0 ]; then - _pkg_names="$(rtl_lconcat "${_pkg_names}" "${EXP_PKG_NAMES}")"; + _pkg_names="$(rtl_lconcat "${_pkg_names}" "${EX_PKG_NAMES}")"; exp_pkg_dispatch_group "${_build_steps_default}" \ "${_build_vars_default}" "${_dispatch_fn}" "${_group_name}" \ "${_njobs_max}" "${_pipe_path}" "${_restart_at}" \ diff --git a/subr/ex_pkg_env.subr b/subr/ex_pkg_env.subr index b4e1810..edb5e8d 100644 --- a/subr/ex_pkg_env.subr +++ b/subr/ex_pkg_env.subr @@ -40,6 +40,7 @@ exp_pkg_env_defaults() { # exp_pkg_env_set() - set package variables for single named package # @_build_vars_default: list of default build variables # @_group_name: build group name +# @_nounset: don't clear package variable namespace # @_pkg_name: single package name # # Sets package variables from either defaults, defaults specific to build type, @@ -50,27 +51,30 @@ exp_pkg_env_defaults() { # Return: zero (0) on success, non-zero (>0) on failure # exp_pkg_env_set() { - local _build_vars_default="${1}" _group_name="${2}" _pkg_name="${3}" _var_prefixes="" _vars_set="" _vname=""; + local _build_vars_default="${1}" _group_name="${2}" _nounset="${3}" \ + _pkg_name="${4}" _var_prefixes="" _vars_set="" _vname=""; rtl_set_vars _vars_set BUILD_TYPE "DEFAULT ${_group_name} PKG_${_pkg_name}"; rtl_set_vars _vars_set INHERIT_FROM "PKG_${_pkg_name}"; _var_prefixes="$(rtl_toupper "DEFAULT DEFAULT_${PKG_BUILD_TYPE} ${_group_name}")"; for _vname in $(rtl_lfilter "${_build_vars_default}" BUILD_TYPE); do if [ -n "${PKG_INHERIT_FROM}" ]; then - rtl_set_vars _vars_set "${_vname}" \ - "$(rtl_lconcat "${_var_prefixes}" \ + rtl_set_vars _vars_set "${_vname}" \ + "$(rtl_lconcat "${_var_prefixes}" \ "$(rtl_toupper "PKG_${PKG_INHERIT_FROM} PKG_${_pkg_name}")")" else - rtl_set_vars _vars_set "${_vname}" \ - "$(rtl_lconcat "${_var_prefixes}" \ + rtl_set_vars _vars_set "${_vname}" \ + "$(rtl_lconcat "${_var_prefixes}" \ "$(rtl_toupper "PKG_${_pkg_name}")")"; fi; done; rtl_push_IFS :; for _vname in ${PKG_ENV_VARS_EXTRA}; do export "${_vname}"; done; rtl_pop_IFS; - rtl_unset_vars $(rtl_lfilter \ - "$(set | sed -ne '/^PKG_[^=]*=/s/=.*$//p')" \ - "${_vars_set}"); + if [ "${_nounset:-0}" -eq 0 ]; then + rtl_unset_vars $(rtl_lfilter \ + "$(set | sed -ne '/^PKG_[^=]*=/s/=.*$//p')" \ + "${_vars_set}"); + fi; }; # @@ -78,6 +82,7 @@ exp_pkg_env_set() { # @_build_steps_default: list of default build steps # @_build_vars_default: list of default build variables # @_group_name: build group name +# @_nounset: don't clear package variable namespace # @_pkg_name: single package name # @_restart_at: optional comma-separated list of build steps at which to rebuild or ALL # @_workdir: pathname to build-specific temporary directory @@ -86,9 +91,9 @@ exp_pkg_env_set() { # ex_pkg_env() { local _build_steps_default="${1}" _build_vars_default="${2}" _group_name="${3}" \ - _pkg_name="${4}" _restart_at="${5}" _workdir="${6}" _vname=""; + _nounset="${4}" _pkg_name="${5}" _restart_at="${6}" _workdir="${7}" _vname=""; rtl_fileop source_opt "vars/${_pkg_name}.vars" "${_group_name}/${_pkg_name}.${_group_name}"; - if ! exp_pkg_env_set "${_build_vars_default}" "${_group_name}" "${_pkg_name}"\ + if ! exp_pkg_env_set "${_build_vars_default}" "${_group_name}" "${_nounset}" "${_pkg_name}"\ || ! exp_pkg_env_defaults "${_build_steps_default}" "${_pkg_name}" "${_workdir}"; then return 1; fi; diff --git a/subr/pkgtool_init.subr b/subr/pkgtool_init.subr index da6a664..c0e26ac 100644 --- a/subr/pkgtool_init.subr +++ b/subr/pkgtool_init.subr @@ -5,7 +5,38 @@ pkgtoolp_init_defaults() { : ${ARCH:="nt64"}; : ${BUILD:="debug"}; : ${PKG_NAME:=""}; : ${BUILD_WORKDIR:=""}; : ${PREFIX=""}; - ARG_RESTART_AT=""; ARG_UPDATE_DIFF=0; + ARG_INFO=0; ARG_RESTART_AT=""; ARG_RDEPENDS=0; + ARG_UPDATE_DIFF=0; ARG_SHELL=0; ARG_TARBALL=0; + BUILD_GROUPS=""; +}; + +pkgtoolp_init_dump() { + local _rc=0; _status=""; + if [ -n "${ARG_RESTART_AT}" ]\ + || [ "${ARG_UPDATE_DIFF:-0}" -eq 1 ]\ + || [ "${ARG_SHELL:-0}" -eq 1 ]; then + if [ ! -e "${BUILD_WORKDIR}/${PKG_NAME}.dump" ]; then + rtl_log_msg warn "Warning: failed to locate environment dump for package \`${PKG_NAME}' in \`${BUILD_WORKDIR}'."; + rtl_log_msg info "Rebuilding package \`${PKG_NAME}' w/ --dump-in build..."; + (export ARCH BUILD \ + BUILD_DLCACHEDIR BUILD_WORKDIR \ + PREFIX PREFIX_CROSS PREFIX_MINGW32 PREFIX_MINIPIX \ + PREFIX_NATIVE PREFIX_ROOT PREFIX_RPM; + ./build.sh -a "${ARCH}" -b "${BUILD}" --dump-in build -P -r "${PKG_NAME}" -v); + if [ ! -e "${BUILD_WORKDIR}/${PKG_NAME}.dump" ]; then + _rc=1; _status="Error: failed to locate environment dump for package \`${PKG_NAME}' in \`${BUILD_WORKDIR}'."; + fi; + else + _rc=0; + fi; + if [ "${_rc:-0}" -eq 0 ]\ + && ! . "${BUILD_WORKDIR}/${PKG_NAME}.dump"; then + _rc=1; _status="Error: failed to source environment dump for package \`${PKG_NAME}' from \`${BUILD_WORKDIR}'."; + elif [ "${_rc:-0}" -eq 0 ]\ + && ! rtl_fileop cd "${PKG_BUILD_DIR}"; then + _rc=1; _status="Error: failed to change working directory to \`${PKG_BUILD_DIR}'."; + fi; + fi; return "${_rc}"; }; pkgtoolp_init_env() { @@ -39,18 +70,30 @@ pkgtoolp_init_getopts() { break; elif [ "${_shiftfl:-0}" -gt 0 ]; then shift "${_shiftfl}"; continue; - elif getopts a:b:C:D:Fhp:Pr:R _opt; then + elif getopts a:b:hirst _opt; then case "${_opt}" in a) ARCH="${OPTARG}"; ;; b) BUILD="${OPTARG}"; ;; - h) pkgtoolp_usage; exit 0; ;; - *) pkgtoolp_usage; exit 1; ;; + h) cat etc/pkgtool.usage; exit 0; ;; + i) ARG_INFO=1; ;; + r) ARG_RDEPENDS=1; ;; + s) ARG_SHELL=1; ;; + t) ARG_TARBALL=1; ;; + *) cat etc/pkgtool.usage; exit 1; ;; esac; shift $((${OPTIND}-1)); OPTIND=1; else break; fi; done; if [ "${_rc}" -eq 0 ]; then + if [ "$((${ARG_INFO:-0} + ${ARG_RDEPENDS:-0} + ${ARG_SHELL:-0} + ${ARG_TARBALL:-0}))" -gt 1 ]; then + cat etc/pkgtool.usage; rtl_log_msg failexit "Error: only one of -i, -r, -s, or -t must be specified."; + elif [ "$((${ARG_INFO:-0} + ${ARG_RDEPENDS:-0} + ${ARG_SHELL:-0} + ${ARG_TARBALL:-0}))" -eq 0 ]; then + if [ -z "${ARG_RESTART_AT}" ]\ + && [ "${ARG_UPDATE_DIFF:-0}" -eq 0 ]; then + cat etc/pkgtool.usage; rtl_log_msg failexit "Error: one of -i, -r, -s, or -t must be specified."; + fi; + fi; while [ "${#}" -gt 0 ]; do case "${1}" in *=*) rtl_set_var_unsafe "${1%%=*}" "${1#*=}"; ;; @@ -70,24 +113,71 @@ pkgtoolp_init_getopts() { return "${_rc}"; }; +pkgtoolp_init_groups() { + local _default_build_groups="" _fname="" _group="" _groups="" _rc=0; _status=""; + if [ "${ARG_INFO:-0}" -eq 1 ]\ + || [ "${ARG_RDEPENDS:-0}" -eq 1 ]\ + || [ "${ARG_TARBALL:-0}" -eq 1 ]; then + for _fname in $(find ./groups -name *.group | sort); do + rtl_fileop source_opt "${_fname}"; + if [ -n "${GROUP_TARGET}" ]; then + _group="${GROUP_TARGET}"; unset GROUP_TARGET; + else + _group="${_fname##*/}"; _group="${_group%.group}"; _group="${_group#*.}"; + fi; + if ! rtl_lmatch "${_groups}" "${_group}"; then + _groups="$(rtl_lconcat "${_groups}" "${_group}")"; + if [ -n "${GROUP_AUTO}" ]; then + if [ "${GROUP_AUTO:-0}" -ne 0 ]; then + _default_build_groups="$(rtl_lconcat "${_default_build_groups}" "${_group}")"; + fi; + unset GROUP_AUTO; + else + _default_build_groups="$(rtl_lconcat "${_default_build_groups}" "${_group}")"; + fi; + fi; + done; + _default_build_groups="$(rtl_uniq "${_default_build_groups}")"; + BUILD_GROUPS="${_default_build_groups}"; + fi; return "${_rc}"; +}; + +pkgtoolp_init_package() { + local _foundfl=0 _group_name="" _pkg_names="" _rc=0; _status=""; + if [ "${ARG_INFO:-0}" -eq 1 ]\ + || [ "${ARG_RDEPENDS:-0}" -eq 1 ]\ + || [ "${ARG_TARBALL:-0}" -eq 1 ]; then + for _group_name in ${BUILD_GROUPS}; do + if ! _pkg_names="$(rtl_get_var_unsafe -u "${_group_name}_PACKAGES")"\ + || [ -z "${_pkg_names}" ]; then + rtl_log_msg warn "Warning: ignoring non-existent or invalid build group \`${_build_group}'."; + elif rtl_lmatch "${_pkg_names}" "${PKG_NAME}"; then + _foundfl=1; + fi; + done; + if [ "${_foundfl:-0}" -eq 0 ]; then + _rc=1; _status="Error: package \`${PKG_NAME}' unknown."; + fi; + fi; return "${_rc}"; +}; + pkgtoolp_init_prereqs() { local _cmd="" _cmds_missing="" _rc=0; _status=""; for _cmd in \ - awk bunzip2 cat chmod cmake cp date find flock g++ \ - gcc git grep gunzip gzip hostname install kill \ - ln lzip make mkdir mkfifo mv paste patch perl \ - pgrep pkill printf readlink rm sed seq sha256sum \ - sort stat tail tar test touch tr wget xz zip; do + awk bunzip2 bzip2 cat chmod cmake cp date find flock \ + g++ gcc git grep gunzip gzip hostname install kill \ + ln lzip make mkdir mkfifo mktemp mv paste patch perl \ + pgrep pkill printf readlink rm sed sha256sum sort \ + tail tar test touch tr uniq wget xz zip; do if ! which "${_cmd}" >/dev/null 2>&1; then _cmds_missing="${_cmds_missing:+${_cmds_missing} }${_cmd}"; fi; done; if [ -n "${_cmds_missing}" ]; then _rc=1; _status="Error: missing prerequisite package(s): ${_cmds_missing}"; - elif ! awk -V 2>/dev/null | grep -q "^GNU Awk "; then - _rc=1; _status="Error: awk(1) in \$PATH must be GNU Awk."; - elif ! sed --version 2>/dev/null | grep -q "^GNU sed "; then - _rc=1; _status="Error: sed(1) in \$PATH must be GNU sed."; + elif ! (FNAME="$(mktemp)" && { trap "rm -f \"\${FNAME}\"" EXIT; \ + sed -i'' -e '' "${FNAME}" >/dev/null 2>&1; }); then + _rc=1; _status="Error: sed(1) in \${PATH} does not support the \`-i' option."; fi; return "${_rc}"; }; @@ -111,17 +201,16 @@ pkgtoolp_init_vars() { return "${_rc}"; }; -pkgtoolp_usage() { - echo "usage: ./pkgtool.sh [-a nt32|nt64] [-b debug|release] name" >&2; -}; - pkgtool_init() { local _fname="" _rc=0 _status=""; if ! pkgtoolp_init_env \ || ! pkgtoolp_init_defaults \ || ! pkgtoolp_init_getopts "${@}" \ || ! pkgtoolp_init_prereqs \ - || ! pkgtoolp_init_vars; then + || ! pkgtoolp_init_vars \ + || ! pkgtoolp_init_dump \ + || ! pkgtoolp_init_groups \ + || ! pkgtoolp_init_package; then _rc="${?}"; rtl_log_msg fail "${_status}"; exit "${_rc}"; elif [ -n "${_status}" ]; then rtl_log_msg info "${_status}"; exit 0; diff --git a/subr/rtl_list.subr b/subr/rtl_list.subr index 479b0fd..f57a3ee 100644 --- a/subr/rtl_list.subr +++ b/subr/rtl_list.subr @@ -65,6 +65,11 @@ rtl_lsearch() { echo "${_lnew}"; }; +rtl_lsort() { + local _list="${1}" _sep="${2:- }"; + printf "%s" "${_list}" | tr "${_sep}" "\n" | sort | paste -s -d "${_sep}"; +}; + rtl_lunfold_depends() { local _vname_template="${1}" _depends="" _name="" _names=""; shift; for _name in "${@}"; do