summaryrefslogtreecommitdiff
path: root/scripts/functions
blob: f7d087911d03d1240a3310640c411e0ca7cab801 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# This file contains some usefull common functions
# Copyright 2007 Yann E. MORIN
# Licensed under the GPL v2. See COPYING in the root of this package

CT_OnError() {
    ret=$?
    CT_DoLog ERROR "Build failed in step \"${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}\""
    for((step=(CT_STEP_COUNT-1); step>1; step--)); do
        CT_DoLog ERROR "      called in step \"${CT_STEP_MESSAGE[${step}]}\""
    done
    CT_DoLog ERROR "Error happened in \"${BASH_SOURCE[1]}\" in function \"${FUNCNAME[1]}\" (line unknown, sorry)"
    for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
        CT_DoLog ERROR "      called from \"${BASH_SOURCE[${depth}]}\" at line # ${BASH_LINENO[${depth}-1]} in function \"${FUNCNAME[${depth}]}\""
    done
    CT_DoLog ERROR "Look at \"${CT_ACTUAL_LOG_FILE}\" for more info on this error."
    exit $ret
}
trap CT_OnError ERR

set -E
set -o pipefail

# This is crosstool-ng-0.0.1
CT_VERSION=ng-0.0.1

# The different log levels:
CT_LOG_LEVEL_ERROR=0
CT_LOG_LEVEL_WARN=1
CT_LOG_LEVEL_INFO=2
CT_LOG_LEVEL_EXTRA=3
CT_LOG_LEVEL_DEBUG=4

# Attributes
_A_NOR="\\033[0m"
_A_BRI="\\033[1m"
_A_DIM="\\033[2m"
_A_UND="\\033[4m"
_A_BRB="\\033[5m"
_A_REV="\\033[7m"
_A_HID="\\033[8m"

# Fore colors
_F_BLK="\\033[30m"
_F_RED="\\033[31m"
_F_GRN="\\033[32m"
_F_YEL="\\033[33m"
_F_BLU="\\033[34m"
_F_MAG="\\033[35m"
_F_CYA="\\033[36m"
_F_WHI="\\033[37m"

# A function to log what is happening
# Different log level are available:
#   - ERROR:   A serious, fatal error occurred
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
#   - INFO:    Informational messages
#   - EXTRA:   Extra informational messages
#   - DEBUG:   Debug messages
# Usage: CT_DoLog <level> [message]
# If message is empty, then stdin will be logged.
CT_DoLog() {
    local max_level LEVEL level cur_l cur_L
    local l
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
    # Set the maximum log level to DEBUG if we have none
    [ -z ${max_level} ] && max_level=${CT_LOG_LEVEL_DEBUG}

    LEVEL="$1"; shift
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"

    if [ $# -eq 0 ]; then
        cat -
    else
        echo "${1}"
    fi |( IFS="\n" # We want the full lines, even leading spaces
          cpt=0
          indent=$((2*CT_STEP_COUNT))
          while read line; do
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
                "make["?*"]:"*"Stop.")  cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
              esac
              l="`printf \"[%-5s]%*s%s%s\" \"${cur_L}\" \"${indent}\" \" \" \"${line}\"`"
              # There will always be a log file, be it /dev/null
              echo -e "${l}" >>"${CT_ACTUAL_LOG_FILE}"
              color="CT_${cur_L}_COLOR"
              normal="CT_NORMAL_COLOR"
              if [ ${cur_l} -le ${max_level} ]; then
                  echo -e "${!color}${l}${!normal}"
              else
                  ${CT_PROG_BAR}
              fi
          done
        )

    return 0
}

# Abort the execution with a error message
# Usage: CT_Abort <message>
CT_Abort() {
    CT_DoLog ERROR "$1" >&2
    exit 1
}

# Test a condition, and print a message if satisfied
# Usage: CT_Test <message> <tests>
CT_Test() {
    local ret
    local m="$1"
    shift
    test "$@" && CT_DoLog WARN "$m"
    return 0
}

# Test a condition, and abort with an error message if satisfied
# Usage: CT_TestAndAbort <message> <tests>
CT_TestAndAbort() {
    local m="$1"
    shift
    test "$@" && CT_Abort "$m"
    return 0
}

# Test a condition, and abort with an error message if not satisfied
# Usage: CT_TestAndAbort <message> <tests>
CT_TestOrAbort() {
    local m="$1"
    shift
    test "$@" || CT_Abort "$m"
    return 0
}

# Test the presence of a tool, or abort if not found
# Usage: CT_HasOrAbort <tool>
CT_HasOrAbort() {
    CT_TestAndAbort "\"${1}\" not found and needed for successfull toolchain build." -z "`which \"${1}\"`"
    return 0
}

# Get current date with nanosecond precision
# On those system not supporting nanosecond precision, faked with rounding down
# to the highest entire second
# Usage: CT_DoDate <fmt>
CT_DoDate() {
    date "$1" |sed -r -e 's/%N$/000000000/;'
}

CT_STEP_COUNT=1
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
# Memorise a step being done so that any error is caught
# Usage: CT_DoStep <loglevel> <message>
CT_DoStep() {
    local start=`CT_DoDate +%s%N`
    CT_DoLog "$1" "================================================================="
    CT_DoLog "$1" "$2"
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
    return 0
}

# End the step just being done
# Usage: CT_EndStep
CT_EndStep() {
    local stop=`CT_DoDate +%s%N`
    local duration=`printf "%032d" $((stop-${CT_STEP_START[${CT_STEP_COUNT}]})) |sed -r -e 's/([[:digit:]]{2})[[:digit:]]{7}$/\.\1/; s/^0+//; s/^\./0\./;'`
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
    CT_DoLog "${level}" "${message}: done in ${duration}s"
    return 0
}

# Pushes into a directory, and pops back
CT_Pushd() {
    pushd "$1" >/dev/null 2>&1
}
CT_Popd() {
    popd >/dev/null 2>&1
}

# Makes a path absolute
# Usage: CT_MakeAbsolutePath path
CT_MakeAbsolutePath() {
    # Try to cd in that directory
    if [ -d "$1" ]; then
        CT_Pushd "$1"
        pwd
        CT_Popd
    else
        # No such directory, fail back to guessing
        case "$1" in
            /*)  echo "$1";;
            *)   echo "`pwd`/$1";;
        esac
    fi
    
    return 0
}

# Creates a temporary directory
# $1: variable to assign to
# Usage: CT_MktempDir foo
CT_MktempDir() {
    # Some mktemp do not allow more than 6 Xs
    eval "$1"="`mktemp -q -d \"${CT_BUILD_DIR}/.XXXXXX\"`"
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
}

# Echoes the specified string on stdout until the pipe breaks.
# Doesn't fail
# $1: string to echo
# Usage: CT_DoYes "" |make oldconfig
CT_DoYes() {
    yes "$1" || true
}