utilities.sh
Go to the documentation of this file.
00001 ############################################################################## 00002 # @file utilities.sh 00003 # @brief Main module of project-independent BASIS utilities. 00004 # 00005 # This module defines the default BASIS utility functions. These default 00006 # implementations are not project-specific, i.e., do not make use of particular 00007 # project attributes such as the name or version of the project. The utility 00008 # functions defined by this module are intended for use in Bash scripts that 00009 # are not build as part of a particular BASIS project. Otherwise, the 00010 # project-specific implementations should be used instead, i.e., those defined 00011 # by the basis.sh module of the project which is automatically added to the 00012 # project during the configuration of the build tree. This basis.sh module and 00013 # the submodules used by it are generated from template modules which are 00014 # customized for the particular project that is being build. 00015 # 00016 # Besides the utility functions which are common to all implementations for 00017 # the different programming languages, does this module further provide 00018 # fundamental functions for the development in Bash. 00019 # 00020 # @note In Bash, there is no concept of namespaces. Hence, the utility functions 00021 # are all defined by the utilities.sh module which is part of the BASIS 00022 # installation. By simply setting the constants to the project specific 00023 # values, these utility functions are customized for this particular 00024 # package. This, however, also means that the BASIS utilities of two 00025 # different packages cannot be used within a Bash script at the same 00026 # time in general. The order in which the basis.sh modules are sourced 00027 # matters. Therefore, in Bash, care must be taken which modules of a 00028 # BASIS-based package are being sourced and whether these in turn 00029 # source either the utilities.sh module of BASIS or the basis.sh module 00030 # which has been configured/customized for this particular package. 00031 # If all modules make only use of the utilities.sh module, there are 00032 # no conflicts. Thus, Bash should in general only be used for executable 00033 # scripts within a project, but not to provide library functions to 00034 # other developers. Therefore, consider the use of C++, Python, or Perl, 00035 # instead. 00036 # 00037 # Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br /> 00038 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file. 00039 # 00040 # Contact: SBIA Group <sbia-software at uphs.upenn.edu> 00041 # 00042 # @ingroup BasisBashUtilities 00043 ############################################################################## 00044 00045 [ "${_BASIS_UTILITIES_INCLUDED}" == 'true' ] || { 00046 _BASIS_UTILITIES_INCLUDED='true' 00047 00048 00049 # ============================================================================ 00050 # constants 00051 # ============================================================================ 00052 00053 BASIS_UTILITIES_DIR="`cd -P -- "\`dirname -- "${BASH_SOURCE}"\`" && pwd`" 00054 readonly BASIS_UTILITIES_DIR 00055 00056 # ============================================================================ 00057 # source other modules 00058 # ============================================================================ 00059 00060 . "${BASIS_UTILITIES_DIR}/core.sh" || exit 1 # core utilities, i.e., import() 00061 00062 import basis.config # constants 00063 import basis.os.path # file path manipulation 00064 import basis.shflags # command-line parsing library 00065 00066 # ============================================================================ 00067 # configuration 00068 # ============================================================================ 00069 00070 # the following contanst are set by the basis.sh module, if not, because 00071 # this module is used in a script which does not belong to a BASIS-based 00072 # project, they are initialized to project-independent defaults here 00073 00074 ## @brief Project name. 00075 [ -n "${PROJECT}" ] || readonly PROJECT='' 00076 ## @brief Project version. 00077 [ -n "${VERSION}" ] || readonly VERSION='' 00078 ## @brief Project release. 00079 [ -n "${RELEASE}" ] || readonly RELEASE='' 00080 ## @brief Default copyright of executables. 00081 [ -n "${COPYRIGHT}" ] || readonly COPYRIGHT='2011, 2012, 2013 University of Pennsylvania' 00082 ## @brief Default license of executables. 00083 [ -n "${LICENSE}" ] || readonly LICENSE='See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.' 00084 ## @brief Default contact to use for help output of executables. 00085 [ -n "${CONTACT}" ] || readonly CONTACT='SBIA Group <sbia-software at uphs.upenn.edu>' 00086 00087 00088 # common prefix of target UIDs belonging to this project 00089 [ -n "${_BASIS_TARGET_UID_PREFIX}" ] || readonly _BASIS_TARGET_UID_PREFIX='' 00090 # used to make relative paths in executable target information map absolute 00091 [ -n "${_BASIS_EXECUTABLE_TARGETS_BASE}" ] || readonly _BASIS_EXECUTABLE_TARGETS_BASE="${BASIS_UTILITIES_DIR}" 00092 00093 00094 ## @addtogroup BasisBashUtilities 00095 # @{ 00096 00097 00098 # ============================================================================ 00099 # executable information 00100 # ============================================================================ 00101 00102 # ---------------------------------------------------------------------------- 00103 ## @brief Print contact information. 00104 # 00105 # @param [in] contact Name of contact. Defaults to <tt>${CONTACT}</tt>. 00106 # 00107 # @returns Nothing. 00108 print_contact() 00109 { 00110 [ -n "$1" ] && echo -e "Contact:\n $1" || echo -e "Contact:\n ${CONTACT}" 00111 } 00112 00113 # ---------------------------------------------------------------------------- 00114 ## @brief Print version information including copyright and license notices. 00115 # 00116 # Example: 00117 # @code 00118 # print_version 'foo' '1.0' 00119 # print_version 'foo' -v '1.0' 00120 # print_version -v 1.0 -p BarStool 'foo' 00121 # print_version 'foo' -v '1.2' -c '2012 University of Pennsylvania' \ 00122 # -l 'Apache License, Version 2.0' 00123 # @endcode 00124 # 00125 # @param [in] options Function options as documented below. 00126 # @param [in] name Name of executable. Should not be set programmatically 00127 # to the first argument of the main script, but a string 00128 # literal instead. 00129 # @param [in] version Version of executable. Defaults to <tt>${RELEASE}</tt> 00130 # if defined, otherwise this argument is required. 00131 # @par Options: 00132 # <table border="0"> 00133 # <tr> 00134 # @tp @b -v, @b --version <version> @endtp 00135 # <td>Version of executable. Can be either given as option or second 00136 # positional argument after the @p name.</td> 00137 # </tr> 00138 # <tr> 00139 # @tp @b -p, @b --project <name> @endtp 00140 # <td>Name of project this executable belongs to. 00141 # Defaults to <tt>${PROJECT}</tt> if defined. 00142 # If 'none', no project information is printed.</td> 00143 # </tr> 00144 # <tr> 00145 # @tp @b -c @b --copyright <copyright> @endtp 00146 # <td>The copyright notice. Defaults to <tt>${COPYRIGHT}</tt>. 00147 # If 'none', no copyright notice is printed.</td> 00148 # </tr> 00149 # <tr> 00150 # @tp @b -l @b --license <license> @endtp 00151 # <td>Information regarding licensing. Defaults to <tt>${LICENSE}</tt>. 00152 # If 'none', no license information is printed.</td> 00153 # </tr> 00154 # </table> 00155 # 00156 # @returns Nothing. 00157 print_version() 00158 { 00159 local _basis_pv_name='' 00160 local _basis_pv_version="${RELEASE}" 00161 local _basis_pv_project="${PROJECT}" 00162 local _basis_pv_copyright="${COPYRIGHT:-}" 00163 local _basis_pv_license="${LICENSE:-}" 00164 while [ $# -gt 0 ]; do 00165 case "$1" in 00166 -v|--version) 00167 if [ -n "${_basis_pv_version}" ]; then 00168 echo "print_version(): Version specified twice!" 1>&2 00169 return 1 00170 fi 00171 if [ $# -gt 1 ]; then 00172 _basis_pv_version="$2" 00173 else 00174 echo "print_version(): Option -v, --version is missing an argument!" 1>&2 00175 return 1 00176 fi 00177 shift 00178 ;; 00179 -p|--project) 00180 if [ $# -gt 1 ]; then 00181 _basis_pv_project="$2" 00182 else 00183 echo "print_version(): Option -p, --project is missing an argument!" 1>&2 00184 return 1 00185 fi 00186 shift 00187 ;; 00188 -c|--copyright) 00189 if [ $# -gt 1 ]; then 00190 _basis_pv_copyright="$2" 00191 else 00192 echo "print_version(): Option -c, --copyright is missing an argument!" 1>&2 00193 return 1 00194 fi 00195 shift 00196 ;; 00197 -l|--license) 00198 if [ $# -gt 1 ]; then 00199 _basis_pv_license="$2" 00200 else 00201 echo "print_version(): Option -l, --license is missing an argument!" 1>&2 00202 return 1 00203 fi 00204 shift 00205 ;; 00206 *) 00207 if [ -z "${_basis_pv_name}" ]; then 00208 _basis_pv_name=$1 00209 elif [ -z "${_basis_pv_version}" ]; then 00210 _basis_pv_version=$1 00211 else 00212 echo "print_version(): Too many arguments or invalid option: $1" 1>&2 00213 return 1 00214 fi 00215 ;; 00216 esac 00217 shift 00218 done 00219 [ -n "${_basis_pv_name}" ] || { echo "print_version(): Missing name argument" 1>&2; return 1; } 00220 [ -n "${_basis_pv_version}" ] || { echo "print_version(): Missing version argument" 1>&2; return 1; } 00221 echo -n "${_basis_pv_name}" 00222 [ -n "${_basis_pv_project}" ] && [ "${_basis_pv_project}" != 'none' ] && { 00223 echo -n " (${_basis_pv_project})" 00224 } 00225 echo " ${_basis_pv_version}" 00226 [ -n "${_basis_pv_copyright}" ] && [ "${_basis_pv_copyright}" != 'none' ] && { 00227 echo -e "Copyright (c) ${_basis_pv_copyright}. All rights reserved." 00228 } 00229 [ -n "${_basis_pv_license}" ] && [ "${_basis_pv_license}" != 'none' ] && { 00230 echo -e "${_basis_pv_license}" 00231 } 00232 } 00233 00234 # ---------------------------------------------------------------------------- 00235 ## @brief Get UID of build target. 00236 # 00237 # The UID of a build target is its name prepended by a namespace identifier 00238 # which should be unique for each project. 00239 # 00240 # This function further initializes the dictionary storing the information 00241 # about the executable targets upon the first invocation. Reason to do it 00242 # here is that every access to the dictionaries first calls this function 00243 # to get the UID of a build target. Moreover, also this function needs to 00244 # have the already initialized dictionaries to ensure that an already valid 00245 # target identifier is not modified. As Bash does not provide hash tables, 00246 # dictionary data structures, the imitation of these is necessary which, 00247 # however, results in many eval() calls with noticeable impact on running time. 00248 # Therefore, to decrease the time required to source the BASIS utilities, 00249 # the required dictionary structure is initialized only upon first use. 00250 # 00251 # @param [out] uid UID of named build target. 00252 # @param [in] name Name of build target. 00253 # 00254 # @returns Nothing. 00255 # 00256 # @retval 0 On success. 00257 # @retval 1 On failure. 00258 targetuid() 00259 { 00260 [ -n "$1" ] && [ $# -eq 2 ] || return 1 00261 local _basis_targetuid_target="$2" 00262 # initialize module if not done yet - this is only done here because 00263 # whenever information is looked up about an executable target, this 00264 # function is invoked first 00265 if [ "${_BASIS_EXECUTABLETARGETINFO_INITIALIZED}" != 'true' ]; then 00266 _basis_executabletargetinfo_initialize || return 1 00267 fi 00268 # empty string as input remains unchanged 00269 [ -z "${_basis_targetuid_target}" ] && local "$1" && upvar $1 '' && return 0 00270 # in case of a leading namespace separator, do not modify target name 00271 [ "${_basis_targetuid_target:0:1}" == '.' ] && local "$1" && upvar $1 "${_basis_targetuid_target}" && return 0 00272 # project namespace 00273 local _basis_targetuid_prefix="${_BASIS_TARGET_UID_PREFIX}.DUMMY" 00274 # try prepending namespace or parts of it until target is known 00275 local _basis_targetuid_path='' 00276 while [ "${_basis_targetuid_prefix/\.*/}" != "${_basis_targetuid_prefix}" ]; do 00277 _basis_targetuid_prefix="${_basis_targetuid_prefix%\.*}" 00278 _basis_executabletargetinfo_get _basis_targetuid_path "${_basis_targetuid_prefix}.${_basis_targetuid_target}" LOCATION 00279 if [ -n "${_basis_targetuid_path}" ]; then 00280 local "$1" && upvar $1 "${_basis_targetuid_prefix}.${_basis_targetuid_target}" 00281 return 0 00282 fi 00283 done 00284 # otherwise, return target name unchanged 00285 local "$1" && upvar $1 "${_basis_targetuid_target}" 00286 } 00287 00288 # ---------------------------------------------------------------------------- 00289 ## @brief Determine whether a given build target is known. 00290 # 00291 # @param [in] target Name of build target. 00292 # 00293 # @returns Whether the named target is a known executable target. 00294 istarget() 00295 { 00296 local _basis_istarget_uid && targetuid _basis_istarget_uid "$1" 00297 [ -n "${_basis_istarget_uid}" ] || return 1 00298 local _basis_istarget_path && _basis_executabletargetinfo_get _basis_istarget_path "${_basis_istarget_uid}" LOCATION 00299 [ -n "${_basis_istarget_path}" ] 00300 } 00301 00302 # ---------------------------------------------------------------------------- 00303 ## @brief Get absolute path of executable file. 00304 # 00305 # This function determines the absolute file path of an executable. If no 00306 # arguments are given, the absolute path of this executable is returned. 00307 # If the given argument is a known build target name, the absolute path 00308 # of the executable built by this target is returned. Otherwise, the named 00309 # command is searched in the system PATH and it's absolute path returned 00310 # if found. If the given argument is neither the name of a known build target 00311 # nor an executable found on the PATH, an empty string is returned and 00312 # the return value is 1. 00313 # 00314 # @param [out] path Absolute path of executable file. 00315 # @param [in] target Name/UID of build target. If no argument is given, 00316 # the file path of the calling executable is returned. 00317 # 00318 # @returns Nothing. 00319 # 00320 # @retval 0 On success. 00321 # @retval 1 On failure. 00322 exepath() 00323 { 00324 [ -n "$1" ] && [ $# -eq 1 -o $# -eq 2 ] || return 1 00325 local _basis_exepath_path='' 00326 # if no target name given, get path of this executable 00327 if [ -z "$2" ]; then 00328 _basis_exepath_path="`realpath "$0"`" 00329 # otherwise, get path of executable built by named target 00330 else 00331 # get UID of target 00332 local _basis_exepath_uid && targetuid _basis_exepath_uid "$2" 00333 [ "${_basis_exepath_uid:0:1}" == '.' ] && _basis_exepath_uid=${_basis_exepath_uid:1} 00334 if [ -n "${_basis_exepath_uid}" ]; then 00335 # get path relative to this module 00336 _basis_executabletargetinfo_get _basis_exepath_path "${_basis_exepath_uid}" LOCATION 00337 if [ -n "${_basis_exepath_path}" ]; then 00338 # make path absolute 00339 _basis_exepath_path=`abspath "${_BASIS_EXECUTABLE_TARGETS_BASE}" "${_basis_exepath_path}"` 00340 [ $? -eq 0 ] || return 1 00341 else 00342 _basis_exepath_path=`/usr/bin/which "$2" 2> /dev/null` 00343 fi 00344 else 00345 _basis_exepath_path=`/usr/bin/which "$2" 2> /dev/null` 00346 fi 00347 fi 00348 # return path 00349 local "$1" && upvar $1 "${_basis_exepath_path}" 00350 [ $? -eq 0 ] && [ -n "${_basis_exepath_path}" ] 00351 } 00352 00353 # ---------------------------------------------------------------------------- 00354 ## @brief Get name of executable file. 00355 # 00356 # @param [out] file Name of executable file or an empty string if not found. 00357 # If @p name is not given, the name of this executable is returned. 00358 # @param [in] name Name of command or an empty string. 00359 # 00360 # @returns Whether or not the command was found. 00361 # 00362 # @retval 0 On success. 00363 # @retval 1 On failure. 00364 exename() 00365 { 00366 [ -n "$1" ] && [ $# -eq 1 -o $# -eq 2 ] || return 1 00367 local _basis_exename_path && exepath _basis_exename_path "$2" 00368 [ $? -eq 0 ] || return 1 00369 local _basis_exename_name="`basename "${_basis_exename_path}"`" 00370 local "$1" && upvar $1 "${_basis_exename_name}" 00371 } 00372 00373 # ---------------------------------------------------------------------------- 00374 ## @brief Get directory of executable file. 00375 # 00376 # @param [out] dir Directory of executable file or an empty string if not found. 00377 # If @p name is not given, the directory of this executable is returned. 00378 # @param [in] name Name of command or an empty string. 00379 # 00380 # @returns Whether or not the command was found. 00381 # 00382 # @retval 0 On success. 00383 # @retval 1 On failure. 00384 exedir() 00385 { 00386 [ -n "$1" ] && [ $# -eq 1 -o $# -eq 2 ] || return 1 00387 local _basis_exedir_path && exepath _basis_exedir_path "$2" 00388 [ $? -eq 0 ] || return 1 00389 local _basis_exedir_dir="`dirname "${_basis_exedir_path}"`" 00390 local "$1" && upvar $1 "${_basis_exedir_dir}" 00391 } 00392 00393 # ============================================================================ 00394 # command execution 00395 # ============================================================================ 00396 00397 # ---------------------------------------------------------------------------- 00398 ## @brief Build quoted string from array. 00399 # 00400 # Example: 00401 # @code 00402 # tostring str 'this' "isn't" a 'simple example of "a quoted"' 'string' 00403 # echo "${str}" 00404 # @endcode 00405 # 00406 # @param [out] var Name of result variable for quoted string. 00407 # @param [in] elements All remaining arguments are considered to be the 00408 # elements of the array to convert. 00409 # 00410 # @returns Nothing. 00411 tostring() 00412 { 00413 local _basis_tostring_str='' 00414 local _basis_tostring_element='' 00415 # GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu) 00416 # turns the array into a single string value if local is used 00417 if [ ${BASH_VERSION_MAJOR} -gt 3 ] || [ ${BASH_VERSION_MAJOR} -eq 3 -a ${BASH_VERSION_MINOR} -gt 0 ]; then 00418 local _basis_tostring_args=("$@") 00419 else 00420 _basis_tostring_args=("$@") 00421 fi 00422 local _basis_tostring_i=1 # first argument is name of return variable 00423 while [ $_basis_tostring_i -lt ${#_basis_tostring_args[@]} ]; do 00424 _basis_tostring_element="${_basis_tostring_args[$_basis_tostring_i]}" 00425 # escape double quotes 00426 _basis_tostring_element=`printf -- "${_basis_tostring_element}" | sed 's/\\"/\\\\"/g'` 00427 # surround element by double quotes if necessary 00428 match "${_basis_tostring_element}" "[' ]|^$" && _basis_tostring_element="\"${_basis_tostring_element}\"" 00429 # append element 00430 [ -n "${_basis_tostring_str}" ] && _basis_tostring_str="${_basis_tostring_str} " 00431 _basis_tostring_str="${_basis_tostring_str}${_basis_tostring_element}" 00432 # next argument 00433 let _basis_tostring_i++ 00434 done 00435 local "$1" && upvar $1 "${_basis_tostring_str}" 00436 } 00437 00438 # ---------------------------------------------------------------------------- 00439 ## @brief Split (quoted) string. 00440 # 00441 # This function can be used to split a (quoted) string into its elements. 00442 # 00443 # Example: 00444 # @code 00445 # str="'this' 'isn\'t' a \"simple example of \\\"a quoted\\\"\" 'string'" 00446 # qsplit array "${str}" 00447 # echo ${#array[@]} # 5 00448 # echo "${array[3]}" # simple example of "a quoted" 00449 # @endcode 00450 # 00451 # @param [out] var Result variable for array. 00452 # @param [in] str Quoted string. 00453 # 00454 # @returns Nothing. 00455 qsplit() 00456 { 00457 [ $# -eq 2 ] || return 1 00458 # GNU bash, version 3.00.15(1)-release (x86_64-redhat-linux-gnu) 00459 # turns the array into a single string value if local is used 00460 if [ ${BASH_VERSION_MAJOR} -gt 3 ] || [ ${BASH_VERSION_MAJOR} -eq 3 -a ${BASH_VERSION_MINOR} -gt 0 ]; then 00461 local _basis_qsplit_array=() 00462 else 00463 _basis_qsplit_array=() 00464 fi 00465 local _basis_qsplit_str=$2 00466 # match arguments from left to right 00467 while match "${_basis_qsplit_str}" "[ ]*('([^']|\\\')*[^\\]'|\"([^\"]|\\\")*[^\\]\"|[^ ]+)(.*)"; do 00468 # matched element including quotes 00469 _basis_qsplit_element="${BASH_REMATCH[1]}" 00470 # remove quotes 00471 if [[ ${_basis_qsplit_element:0:1} == '"' && ${_basis_qsplit_element: -1} == '"' ]]; then 00472 _basis_qsplit_element="${_basis_qsplit_element:1}" 00473 _basis_qsplit_element="${_basis_qsplit_element%\"}" 00474 elif [[ ${_basis_qsplit_element:0:1} == "'" && ${_basis_qsplit_element: -1} == "'" ]]; then 00475 _basis_qsplit_element="${_basis_qsplit_element:1}" 00476 _basis_qsplit_element="${_basis_qsplit_element%\'}" 00477 fi 00478 # replace quoted quotes within argument by quotes 00479 _basis_qsplit_element=`printf -- "${_basis_qsplit_element}" | sed "s/[\\]'/'/g;s/[\\]\"/\"/g"` 00480 # add to resulting array 00481 _basis_qsplit_array[${#_basis_qsplit_array[@]}]="${_basis_qsplit_element}" 00482 # continue with residual command-line 00483 _basis_qsplit_str="${BASH_REMATCH[4]}" 00484 done 00485 # return 00486 local "$1" && upvar $1 "${_basis_qsplit_array[@]}" 00487 } 00488 00489 # ---------------------------------------------------------------------------- 00490 ## @brief Execute command as subprocess. 00491 # 00492 # This function is used to execute a subprocess within a Bash script. 00493 # 00494 # Example: 00495 # @code 00496 # # the next command will exit the current shell if it fails 00497 # execute ls /not/existing 00498 # # to prevent this, provide the --allow_fail option 00499 # execute --allow_fail ls /not/existing 00500 # # to make it explicit where the command-line to execute starts, use -- 00501 # execute --allow_fail -- ls /not/existing 00502 # @endcode 00503 # 00504 # Note that the output of the command is not redirected by this function. 00505 # In order to execute the command quietly, use this function as follows: 00506 # @code 00507 # execute ls / &> /dev/null 00508 # @endcode 00509 # Or to store the command output in a variable including error messages 00510 # use it as follows: 00511 # @code 00512 # output=`execute ls / 2>&1` 00513 # @endcode 00514 # Note that in this case, the option --allow_fail has no effect as the 00515 # calling shell will never be terminated. Only the subshell in which the 00516 # command is executed will be terminated. Checking the exit code $? is 00517 # in this case required. 00518 # 00519 # @param [in] options Function options as documented below. 00520 # @param [in] cmd Executable of command to run or corresponding build 00521 # target name. This is assumed to be the first 00522 # non-option argument or the argument that follows the 00523 # special '--' argument. 00524 # @param [in] args All remaining arguments are passed as arguments to 00525 # the given command. 00526 # @par Options: 00527 # <table border="0"> 00528 # <tr> 00529 # @tp <b>-f, --allow_fail</b> @endtp 00530 # <td>Allows the command to fail. By default, if the command 00531 # returns a non-zero exit code, the exit() function is 00532 # called to terminate the current shell.</td> 00533 # </tr> 00534 # <tr> 00535 # @tp <b>-v, --verbose</b> [int] @endtp 00536 # <td>Print command-line to stdout before execution. Optionally, as it is 00537 # sometimes more convenient to pass in the value of another variable 00538 # which controls the verbosity of the parent process itself, a verbosity 00539 # value can be specified following the option flag. If this verbosity 00540 # less or equal to zero, the command-line of the subprocess is not 00541 # printed to stdout, otherwise it is.</td> 00542 # </tr> 00543 # <tr> 00544 # @tp <b>-s, --simulate</b> @endtp 00545 # <td>If this option is given, the command is not actually 00546 # executed, but the command-line printed to stdout only.</td> 00547 # </tr> 00548 # </table> 00549 # 00550 # @returns Exit code of subprocess. 00551 execute() 00552 { 00553 # parse arguments 00554 local _basis_execute_allow_fail='false' 00555 local _basis_execute_simulate='false' 00556 local _basis_execute_verbose=0 00557 local _basis_execute_args='' 00558 while [ $# -gt 0 ]; do 00559 case "$1" in 00560 -f|--allow_fail) _basis_execute_allow_fail='true'; ;; 00561 -s|--simulate) _basis_execute_simulate='true'; ;; 00562 -v|--verbose) 00563 match "$2" '^-?[0-9]+$' 00564 if [ $? -eq 0 ]; then 00565 _basis_execute_verbose=$2 00566 shift 00567 else 00568 let _basis_execute_verbose++ 00569 fi 00570 ;; 00571 --) shift; break; ;; 00572 *) break; ;; 00573 esac 00574 shift 00575 done 00576 # command to execute and its arguments 00577 local _basis_execute_command="$1"; shift 00578 [ -n "${_basis_execute_command}" ] || { echo "execute_process(): No command specified to execute" 1>&2; return 1; } 00579 # get absolute path of executable 00580 local _basis_execute_exec && exepath _basis_execute_exec "${_basis_execute_command}" 00581 [ -n "${_basis_execute_exec}" ] || { echo "${_basis_execute_command}: Command not found" 1>&2; exit 1; } 00582 # some verbose output 00583 if [ ${_basis_execute_verbose} -gt 0 ] || [ "${_basis_execute_simulate}" == 'true' ]; then 00584 tostring _basis_execute_args "$@" 00585 echo "\$ ${_basis_execute_exec} ${_basis_execute_args}" 00586 fi 00587 # execute command 00588 [ "${_basis_execute_simulate}" == 'true' ] || "${_basis_execute_exec}" "$@" 00589 local _basis_execute_status=$? 00590 # if command failed, exit 00591 [ ${_basis_execute_status} -eq 0 -o "${_basis_execute_allow_fail}" == 'true' ] || { 00592 [ -n "${_basis_execute_args}" ] || tostring _basis_execute_args "$@" 00593 echo 00594 echo "Command ${_basis_execute_exec} ${_basis_execute_args} failed" 1>&2 00595 exit 1 00596 } 00597 # return exit code 00598 return ${_basis_execute_status} 00599 } 00600 00601 00602 ## @} 00603 # end of Doxygen group 00604 00605 # ============================================================================ 00606 # private 00607 # ============================================================================ 00608 00609 # ---------------------------------------------------------------------------- 00610 # @brief Sanitize string for use in variable name. 00611 # 00612 # @param [out] out Sanitized string. 00613 # @param [in] str String to be sanitized. 00614 # 00615 # @returns Nothing. 00616 # 00617 # @retval 0 On success. 00618 # @retval 1 On failure. 00619 _basis_executabletargetinfo_sanitize() 00620 { 00621 [ $# -eq 2 ] || return 1 00622 [ -n "$2" ] || { 00623 upvar $1 '' 00624 return 0 00625 } 00626 local sane="`printf -- "$2" | tr '[:space:]' '_' | tr -c '[:alnum:]' '_'`" 00627 [ -n "${sane}" ] || { 00628 echo "_basis_executabletargetinfo_sanitize(): Failed to sanitize string '$2'" 1>&2 00629 exit 1 00630 } 00631 local "$1" && upvar $1 "${sane}" 00632 } 00633 00634 # ---------------------------------------------------------------------------- 00635 # @brief Add (key, value) pair to executable target info "hash". 00636 # 00637 # @param [in] key Hash key. 00638 # @param [in] name Name of the hash table. 00639 # @param [in] value Value associated with the given hash key. 00640 # 00641 # @returns Sets a readonly variable that represents the (key, value) entry. 00642 # 00643 # @sa _basis_executabletargetinfo_get() 00644 _basis_executabletargetinfo_add() 00645 { 00646 [ $# -eq 3 ] || return 1 00647 00648 local key && _basis_executabletargetinfo_sanitize key "$1" 00649 local name && _basis_executabletargetinfo_sanitize name "$2" 00650 [ -n "${key}" ] && [ -n "${name}" ] || { 00651 if [ -z "${key}" ] && [ -z "${name}" ]; then 00652 echo "_basis_executabletargetinfo_add(): Neither lookup table nor key specified" 1>&2 00653 elif [ -z "${key}" ]; then 00654 echo "_basis_executabletargetinfo_add(): No key specified for addition to hash table '${name}'" 1>&2 00655 else 00656 echo "_basis_executabletargetinfo_add(): No lookup table given for addition of key '${key}'" 1>&2 00657 fi 00658 exit 1 00659 } 00660 eval "readonly __BASIS_EXECUTABLETARGETINFO_${name}_${key}='$3'" 00661 if [ $? -ne 0 ]; then 00662 echo "Failed to add ${name} of key ${key} to executable target info map!" 1>&2 00663 echo "This may be caused by two CMake build target names being converted to the same key." 1>&2 00664 exit 1 00665 fi 00666 } 00667 00668 # ---------------------------------------------------------------------------- 00669 # @brief Get value from executable target info "hash". 00670 # 00671 # @param [out] value Value corresponding to given @p key 00672 # or an empty string if key is unknown. 00673 # @param [in] key Hash key. 00674 # @param [in] name Name of the hash table. 00675 # 00676 # @returns Nothing. 00677 # 00678 # @retval 0 On success. 00679 # @retval 1 On failure. 00680 # 00681 # @sa _basis_executabletargetinfo_add() 00682 _basis_executabletargetinfo_get() 00683 { 00684 [ $# -eq 3 ] || return 1 00685 00686 local key && _basis_executabletargetinfo_sanitize key "$2" 00687 local name && _basis_executabletargetinfo_sanitize name "$3" 00688 [ -n "${key}" ] && [ -n "${name}" ] || { 00689 if [ -z "${key}" ] && [ -z "${name}" ]; then 00690 echo "_basis_executabletargetinfo_get(): Neither lookup table nor key specified" 1>&2 00691 elif [ -z "${key}" ]; then 00692 echo "_basis_executabletargetinfo_get(): No key specified for lookup in hash table '${name}'" 1>&2 00693 else 00694 echo "_basis_executabletargetinfo_get(): No lookup table given for lookup of key '${key}'" 1>&2 00695 fi 00696 exit 1 00697 } 00698 eval "local value=\${__BASIS_EXECUTABLETARGETINFO_${name}_${key}}" 00699 00700 local "$1" && upvar $1 "${value}" 00701 } 00702 00703 # initialize table of executable target information upon first use 00704 # this function is redefined by the basis.sh module, see targetuid() 00705 _basis_executabletargetinfo_initialize() 00706 { 00707 [ $# -eq 0 ] || return 1 00708 _BASIS_EXECUTABLETARGETINFO_INITIALIZED='true' 00709 return 0 00710 } 00711 00712 00713 } # _BASIS_UTILITIES_INCLUDED