scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Apr 10 15:49:38 2007 +0000 (2007-04-10)
changeset 25 b1d9951b9933
child 47 7e2539937b6e
permissions -rw-r--r--
While migrating the samples to use ${CT_TOP_DIR}/build as base for the build directories, the Makefile rules stoped working.
This is because 'all' depends on 'build', which does exist, and make believes there's noting to do.
Work this around by using a rule named '_ct_build' instead of plain 'build'.
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@1
    62
    local max_level
yann@1
    63
    local level
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@1
    68
    local LEVEL="$1"
yann@1
    69
    shift
yann@1
    70
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
    71
yann@1
    72
    if [ $# -eq 0 ]; then
yann@1
    73
        cat -
yann@1
    74
    else
yann@1
    75
        echo "${1}"
yann@1
    76
    fi |( IFS="\n" # We want the full lines, even leading spaces
yann@1
    77
          cpt=0
yann@1
    78
          indent=$((2*CT_STEP_COUNT))
yann@1
    79
          while read line; do
yann@1
    80
              l="`printf \"[%-5s]%*s%s%s\" \"${LEVEL}\" \"${indent}\" \" \" \"${line}\"`"
yann@1
    81
              # There will always be a log file, be it /dev/null
yann@1
    82
              echo -e "${l}" >>"${CT_ACTUAL_LOG_FILE}"
yann@1
    83
              color="CT_${LEVEL}_COLOR"
yann@1
    84
              normal="CT_NORMAL_COLOR"
yann@1
    85
              if [ ${level} -le ${max_level} ]; then
yann@1
    86
                  echo -e "${!color}${l}${!normal}"
yann@1
    87
              else
yann@1
    88
                  ${CT_PROG_BAR}
yann@1
    89
              fi
yann@1
    90
          done
yann@1
    91
        )
yann@1
    92
yann@1
    93
    return 0
yann@1
    94
}
yann@1
    95
yann@1
    96
# Abort the execution with a error message
yann@1
    97
# Usage: CT_Abort <message>
yann@1
    98
CT_Abort() {
yann@1
    99
    CT_DoLog ERROR "$1" >&2
yann@1
   100
    exit 1
yann@1
   101
}
yann@1
   102
yann@1
   103
# Test a condition, and print a message if satisfied
yann@1
   104
# Usage: CT_Test <message> <tests>
yann@1
   105
CT_Test() {
yann@1
   106
    local ret
yann@1
   107
    local m="$1"
yann@1
   108
    shift
yann@1
   109
    test "$@" && CT_DoLog WARN "$m"
yann@1
   110
    return 0
yann@1
   111
}
yann@1
   112
yann@1
   113
# Test a condition, and abort with an error message if satisfied
yann@1
   114
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   115
CT_TestAndAbort() {
yann@1
   116
    local m="$1"
yann@1
   117
    shift
yann@1
   118
    test "$@" && CT_Abort "$m"
yann@1
   119
    return 0
yann@1
   120
}
yann@1
   121
yann@1
   122
# Test a condition, and abort with an error message if not satisfied
yann@1
   123
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   124
CT_TestOrAbort() {
yann@1
   125
    local m="$1"
yann@1
   126
    shift
yann@1
   127
    test "$@" || CT_Abort "$m"
yann@1
   128
    return 0
yann@1
   129
}
yann@1
   130
yann@1
   131
# Test the presence of a tool, or abort if not found
yann@1
   132
# Usage: CT_HasOrAbort <tool>
yann@1
   133
CT_HasOrAbort() {
yann@1
   134
    CT_TestAndAbort "\"${1}\" not found and needed for successfull toolchain build." -z "`which \"${1}\"`"
yann@1
   135
    return 0
yann@1
   136
}
yann@1
   137
yann@1
   138
# Get current date with nanosecond precision
yann@1
   139
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   140
# to the highest entire second
yann@1
   141
# Usage: CT_DoDate <fmt>
yann@1
   142
CT_DoDate() {
yann@1
   143
    date "$1" |sed -r -e 's/%N$/000000000/;'
yann@1
   144
}
yann@1
   145
yann@1
   146
CT_STEP_COUNT=1
yann@1
   147
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
yann@1
   148
# Memorise a step being done so that any error is caught
yann@1
   149
# Usage: CT_DoStep <loglevel> <message>
yann@1
   150
CT_DoStep() {
yann@1
   151
    local start=`CT_DoDate +%s%N`
yann@1
   152
    CT_DoLog "$1" "================================================================="
yann@1
   153
    CT_DoLog "$1" "$2"
yann@1
   154
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   155
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   156
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   157
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   158
    return 0
yann@1
   159
}
yann@1
   160
yann@1
   161
# End the step just being done
yann@1
   162
# Usage: CT_EndStep
yann@1
   163
CT_EndStep() {
yann@1
   164
    local stop=`CT_DoDate +%s%N`
yann@1
   165
    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
   166
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   167
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   168
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@1
   169
    CT_DoLog "${level}" "${message}: done in ${duration}s"
yann@1
   170
    return 0
yann@1
   171
}
yann@1
   172
yann@1
   173
# Pushes into a directory, and pops back
yann@1
   174
CT_Pushd() {
yann@1
   175
    pushd "$1" >/dev/null 2>&1
yann@1
   176
}
yann@1
   177
CT_Popd() {
yann@1
   178
    popd >/dev/null 2>&1
yann@1
   179
}
yann@1
   180
yann@1
   181
# Makes a path absolute
yann@1
   182
# Usage: CT_MakeAbsolutePath path
yann@1
   183
CT_MakeAbsolutePath() {
yann@1
   184
    # Try to cd in that directory
yann@1
   185
    if [ -d "$1" ]; then
yann@1
   186
        CT_Pushd "$1"
yann@1
   187
        pwd
yann@1
   188
        CT_Popd
yann@1
   189
    else
yann@1
   190
        # No such directory, fail back to guessing
yann@1
   191
        case "$1" in
yann@1
   192
            /*)  echo "$1";;
yann@1
   193
            *)   echo "`pwd`/$1";;
yann@1
   194
        esac
yann@1
   195
    fi
yann@1
   196
    
yann@1
   197
    return 0
yann@1
   198
}
yann@1
   199
yann@1
   200
# Creates a temporary directory
yann@1
   201
# $1: variable to assign to
yann@1
   202
# Usage: CT_MktempDir foo
yann@1
   203
CT_MktempDir() {
yann@1
   204
    # Some mktemp do not allow more than 6 Xs
yann@1
   205
    eval "$1"="`mktemp -q -d \"${CT_BUILD_DIR}/.XXXXXX\"`"
yann@1
   206
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@1
   207
}
yann@1
   208
yann@1
   209
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   210
# Doesn't fail
yann@1
   211
# $1: string to echo
yann@1
   212
# Usage: CT_DoYes "" |make oldconfig
yann@1
   213
CT_DoYes() {
yann@1
   214
    yes "$1" || true
yann@1
   215
}