scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue May 01 16:49:15 2007 +0000 (2007-05-01)
changeset 56 07a6a48962b7
parent 1 eeea35fbf182
child 63 89b41dbffe8d
permissions -rw-r--r--
Merge patches sent by Robert P. J. Day <rpjday@mindspring.com>.
Warning: the buildroot folks purposedly removed the skip-comment patch but didn't really said why. Keeping it for the sake of having it in svn just in case (removing it will be easier thant not having it at all).
yann@1
     1
# This file contains some usefull common functions
yann@1
     2
# Copyright 2007 Yann E. MORIN
yann@1
     3
# Licensed under the GPL v2. See COPYING in the root of this package
yann@1
     4
yann@1
     5
CT_OnError() {
yann@1
     6
    ret=$?
yann@1
     7
    CT_DoLog ERROR "Build failed in step \"${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}\""
yann@1
     8
    for((step=(CT_STEP_COUNT-1); step>1; step--)); do
yann@1
     9
        CT_DoLog ERROR "      called in step \"${CT_STEP_MESSAGE[${step}]}\""
yann@1
    10
    done
yann@1
    11
    CT_DoLog ERROR "Error happened in \"${BASH_SOURCE[1]}\" in function \"${FUNCNAME[1]}\" (line unknown, sorry)"
yann@1
    12
    for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
yann@1
    13
        CT_DoLog ERROR "      called from \"${BASH_SOURCE[${depth}]}\" at line # ${BASH_LINENO[${depth}-1]} in function \"${FUNCNAME[${depth}]}\""
yann@1
    14
    done
yann@1
    15
    CT_DoLog ERROR "Look at \"${CT_ACTUAL_LOG_FILE}\" for more info on this error."
yann@1
    16
    exit $ret
yann@1
    17
}
yann@1
    18
trap CT_OnError ERR
yann@1
    19
yann@1
    20
set -E
yann@1
    21
set -o pipefail
yann@1
    22
yann@1
    23
# This is crosstool-ng-0.0.1
yann@1
    24
CT_VERSION=ng-0.0.1
yann@1
    25
yann@1
    26
# The different log levels:
yann@1
    27
CT_LOG_LEVEL_ERROR=0
yann@1
    28
CT_LOG_LEVEL_WARN=1
yann@1
    29
CT_LOG_LEVEL_INFO=2
yann@1
    30
CT_LOG_LEVEL_EXTRA=3
yann@1
    31
CT_LOG_LEVEL_DEBUG=4
yann@1
    32
yann@1
    33
# Attributes
yann@1
    34
_A_NOR="\\033[0m"
yann@1
    35
_A_BRI="\\033[1m"
yann@1
    36
_A_DIM="\\033[2m"
yann@1
    37
_A_UND="\\033[4m"
yann@1
    38
_A_BRB="\\033[5m"
yann@1
    39
_A_REV="\\033[7m"
yann@1
    40
_A_HID="\\033[8m"
yann@1
    41
yann@1
    42
# Fore colors
yann@1
    43
_F_BLK="\\033[30m"
yann@1
    44
_F_RED="\\033[31m"
yann@1
    45
_F_GRN="\\033[32m"
yann@1
    46
_F_YEL="\\033[33m"
yann@1
    47
_F_BLU="\\033[34m"
yann@1
    48
_F_MAG="\\033[35m"
yann@1
    49
_F_CYA="\\033[36m"
yann@1
    50
_F_WHI="\\033[37m"
yann@1
    51
yann@1
    52
# A function to log what is happening
yann@1
    53
# Different log level are available:
yann@1
    54
#   - ERROR:   A serious, fatal error occurred
yann@1
    55
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
yann@1
    56
#   - INFO:    Informational messages
yann@1
    57
#   - EXTRA:   Extra informational messages
yann@1
    58
#   - DEBUG:   Debug messages
yann@1
    59
# Usage: CT_DoLog <level> [message]
yann@1
    60
# If message is empty, then stdin will be logged.
yann@1
    61
CT_DoLog() {
yann@47
    62
    local max_level LEVEL level cur_l cur_L
yann@47
    63
    local l
yann@1
    64
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
yann@1
    65
    # Set the maximum log level to DEBUG if we have none
yann@1
    66
    [ -z ${max_level} ] && max_level=${CT_LOG_LEVEL_DEBUG}
yann@1
    67
yann@47
    68
    LEVEL="$1"; shift
yann@1
    69
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
    70
yann@1
    71
    if [ $# -eq 0 ]; then
yann@1
    72
        cat -
yann@1
    73
    else
yann@1
    74
        echo "${1}"
yann@1
    75
    fi |( IFS="\n" # We want the full lines, even leading spaces
yann@1
    76
          cpt=0
yann@1
    77
          indent=$((2*CT_STEP_COUNT))
yann@1
    78
          while read line; do
yann@47
    79
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
yann@47
    80
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@47
    81
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
    82
                "make["?*"]:"*"Stop.")  cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
    83
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
yann@47
    84
              esac
yann@47
    85
              l="`printf \"[%-5s]%*s%s%s\" \"${cur_L}\" \"${indent}\" \" \" \"${line}\"`"
yann@1
    86
              # There will always be a log file, be it /dev/null
yann@1
    87
              echo -e "${l}" >>"${CT_ACTUAL_LOG_FILE}"
yann@47
    88
              color="CT_${cur_L}_COLOR"
yann@1
    89
              normal="CT_NORMAL_COLOR"
yann@47
    90
              if [ ${cur_l} -le ${max_level} ]; then
yann@1
    91
                  echo -e "${!color}${l}${!normal}"
yann@1
    92
              else
yann@1
    93
                  ${CT_PROG_BAR}
yann@1
    94
              fi
yann@1
    95
          done
yann@1
    96
        )
yann@1
    97
yann@1
    98
    return 0
yann@1
    99
}
yann@1
   100
yann@1
   101
# Abort the execution with a error message
yann@1
   102
# Usage: CT_Abort <message>
yann@1
   103
CT_Abort() {
yann@1
   104
    CT_DoLog ERROR "$1" >&2
yann@1
   105
    exit 1
yann@1
   106
}
yann@1
   107
yann@1
   108
# Test a condition, and print a message if satisfied
yann@1
   109
# Usage: CT_Test <message> <tests>
yann@1
   110
CT_Test() {
yann@1
   111
    local ret
yann@1
   112
    local m="$1"
yann@1
   113
    shift
yann@1
   114
    test "$@" && CT_DoLog WARN "$m"
yann@1
   115
    return 0
yann@1
   116
}
yann@1
   117
yann@1
   118
# Test a condition, and abort with an error message if satisfied
yann@1
   119
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   120
CT_TestAndAbort() {
yann@1
   121
    local m="$1"
yann@1
   122
    shift
yann@1
   123
    test "$@" && CT_Abort "$m"
yann@1
   124
    return 0
yann@1
   125
}
yann@1
   126
yann@1
   127
# Test a condition, and abort with an error message if not satisfied
yann@1
   128
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   129
CT_TestOrAbort() {
yann@1
   130
    local m="$1"
yann@1
   131
    shift
yann@1
   132
    test "$@" || CT_Abort "$m"
yann@1
   133
    return 0
yann@1
   134
}
yann@1
   135
yann@1
   136
# Test the presence of a tool, or abort if not found
yann@1
   137
# Usage: CT_HasOrAbort <tool>
yann@1
   138
CT_HasOrAbort() {
yann@1
   139
    CT_TestAndAbort "\"${1}\" not found and needed for successfull toolchain build." -z "`which \"${1}\"`"
yann@1
   140
    return 0
yann@1
   141
}
yann@1
   142
yann@1
   143
# Get current date with nanosecond precision
yann@1
   144
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   145
# to the highest entire second
yann@1
   146
# Usage: CT_DoDate <fmt>
yann@1
   147
CT_DoDate() {
yann@1
   148
    date "$1" |sed -r -e 's/%N$/000000000/;'
yann@1
   149
}
yann@1
   150
yann@1
   151
CT_STEP_COUNT=1
yann@1
   152
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
yann@1
   153
# Memorise a step being done so that any error is caught
yann@1
   154
# Usage: CT_DoStep <loglevel> <message>
yann@1
   155
CT_DoStep() {
yann@1
   156
    local start=`CT_DoDate +%s%N`
yann@1
   157
    CT_DoLog "$1" "================================================================="
yann@1
   158
    CT_DoLog "$1" "$2"
yann@1
   159
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   160
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   161
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   162
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   163
    return 0
yann@1
   164
}
yann@1
   165
yann@1
   166
# End the step just being done
yann@1
   167
# Usage: CT_EndStep
yann@1
   168
CT_EndStep() {
yann@1
   169
    local stop=`CT_DoDate +%s%N`
yann@1
   170
    local duration=`printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;'`
yann@1
   171
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   172
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   173
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@1
   174
    CT_DoLog "${level}" "${message}: done in ${duration}s"
yann@1
   175
    return 0
yann@1
   176
}
yann@1
   177
yann@1
   178
# Pushes into a directory, and pops back
yann@1
   179
CT_Pushd() {
yann@1
   180
    pushd "$1" >/dev/null 2>&1
yann@1
   181
}
yann@1
   182
CT_Popd() {
yann@1
   183
    popd >/dev/null 2>&1
yann@1
   184
}
yann@1
   185
yann@1
   186
# Makes a path absolute
yann@1
   187
# Usage: CT_MakeAbsolutePath path
yann@1
   188
CT_MakeAbsolutePath() {
yann@1
   189
    # Try to cd in that directory
yann@1
   190
    if [ -d "$1" ]; then
yann@1
   191
        CT_Pushd "$1"
yann@1
   192
        pwd
yann@1
   193
        CT_Popd
yann@1
   194
    else
yann@1
   195
        # No such directory, fail back to guessing
yann@1
   196
        case "$1" in
yann@1
   197
            /*)  echo "$1";;
yann@1
   198
            *)   echo "`pwd`/$1";;
yann@1
   199
        esac
yann@1
   200
    fi
yann@1
   201
    
yann@1
   202
    return 0
yann@1
   203
}
yann@1
   204
yann@1
   205
# Creates a temporary directory
yann@1
   206
# $1: variable to assign to
yann@1
   207
# Usage: CT_MktempDir foo
yann@1
   208
CT_MktempDir() {
yann@1
   209
    # Some mktemp do not allow more than 6 Xs
yann@1
   210
    eval "$1"="`mktemp -q -d \"${CT_BUILD_DIR}/.XXXXXX\"`"
yann@1
   211
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@1
   212
}
yann@1
   213
yann@1
   214
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   215
# Doesn't fail
yann@1
   216
# $1: string to echo
yann@1
   217
# Usage: CT_DoYes "" |make oldconfig
yann@1
   218
CT_DoYes() {
yann@1
   219
    yes "$1" || true
yann@1
   220
}