scripts/functions
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Tue Aug 02 18:28:10 2011 +0200 (2011-08-02)
changeset 2590 b64cfb67944e
parent 2589 2289c546c8e1
child 2592 4908eb2b6f17
permissions -rw-r--r--
scripts/functions: svn retrieval first tries the mirror for tarballs

The svn download helper looks for the local tarballs dir to see if it
can find a pre-downloaded tarball, and if it does not find it, does
the actual fetch to upstream via svn.

In the process, it does not even try to get a tarball from the local
mirror, which can be useful if the mirror has been pre-populated
manually (or with a previously downloaded tree).

Fake a tarball get with the standard tarball-download helper, but
without specifying any upstream URL, which makes the helper directly
try the LAN mirror.

Of course, if no mirror is specified, no URL wil be available, and
the standard svn retrieval will kick in.

Reported-by: ANDY KENNEDY <ANDY.KENNEDY@adtran.com>
Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
anthony@2155
     1
# This file contains some usefull common functions -*- sh -*-
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@136
     5
# Prepare the fault handler
yann@1
     6
CT_OnError() {
yann@2388
     7
    local ret=$?
yann@2388
     8
    local intro
yann@2388
     9
    local file
yann@2388
    10
    local line
yann@2388
    11
    local func
yann@2388
    12
    local step_depth
yann@2388
    13
yann@726
    14
    # Bail out early in subshell, the upper level shell will act accordingly.
yann@726
    15
    [ ${BASH_SUBSHELL} -eq 0 ] || exit $ret
yann@2388
    16
yann@2388
    17
    # Print steps backtrace
yann@2388
    18
    step_depth=${CT_STEP_COUNT}
yann@2388
    19
    CT_STEP_COUNT=2
yann@2388
    20
    CT_DoLog ERROR ""
yann@2388
    21
    intro="Build failed"
yann@2388
    22
    for((step=step_depth; step>1; step--)); do
yann@2388
    23
        CT_DoLog ERROR ">>  ${intro} in step '${CT_STEP_MESSAGE[${step}]}'"
yann@2388
    24
        intro="      called"
yann@2388
    25
    done
yann@2388
    26
yann@2388
    27
    # Print functions backtrace
yann@2388
    28
    intro="Error happened in"
yann@2388
    29
    offset=1
yann@2388
    30
    CT_DoLog ERROR ">>"
yann@2388
    31
    for((depth=1; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
yann@2388
    32
        file="${BASH_SOURCE[${depth}]#${CT_LIB_DIR}/}"
yann@2388
    33
        case "${depth}" in
yann@2388
    34
            1)  line="";;
yann@2388
    35
            *)  line="@${BASH_LINENO[${depth}-1]}"
yann@2388
    36
        esac
yann@2388
    37
        func="${FUNCNAME[${depth}]}"
yann@2388
    38
        CT_DoLog ERROR ">>  ${intro}: ${func}[${file}${line}]"
yann@2388
    39
        intro="      called from"
yann@2388
    40
    done
yann@2388
    41
yann@2388
    42
    # Help diagnose the error
yann@2388
    43
    CT_DoLog ERROR ">>"
yann@2388
    44
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@2388
    45
        CT_DoLog ERROR ">>  For more info on this error, look at the file: '${tmp_log_file#${CT_TOP_DIR}/}'"
yann@2388
    46
    fi
yann@2388
    47
    CT_DoLog ERROR ">>  There is a list of known issues, some with workarounds, in:"
yann@2388
    48
    CT_DoLog ERROR ">>      '${CT_DOC_DIR#${CT_TOP_DIR}/}/B - Known issues.txt'"
yann@2388
    49
yann@2388
    50
    CT_DoLog ERROR ""
yann@523
    51
    CT_DoLog ERROR "Build failed in step '${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}'"
yann@2388
    52
yann@2388
    53
    CT_DoLog ERROR ""
yann@96
    54
    CT_DoEnd ERROR
yann@1
    55
    exit $ret
yann@1
    56
}
yann@136
    57
yann@136
    58
# Install the fault handler
yann@1
    59
trap CT_OnError ERR
yann@1
    60
yann@136
    61
# Inherit the fault handler in subshells and functions
yann@1
    62
set -E
yann@136
    63
yann@136
    64
# Make pipes fail on the _first_ failed command
yann@136
    65
# Not supported on bash < 3.x, but we need it, so drop the obsoleting bash-2.x
yann@1
    66
set -o pipefail
yann@1
    67
yann@136
    68
# Don't hash commands' locations, and search every time it is requested.
yann@136
    69
# This is slow, but needed because of the static/shared core gcc which shall
yann@136
    70
# always match to shared if it exists, and only fallback to static if the
yann@136
    71
# shared is not found
yann@136
    72
set +o hashall
yann@136
    73
yann@165
    74
# Log policy:
yann@165
    75
#  - first of all, save stdout so we can see the live logs: fd #6
yann@165
    76
exec 6>&1
yann@2339
    77
#  - then point stdout to the log file
yann@2339
    78
tmp_log_file="${CT_TOP_DIR}/build.log"
yann@2339
    79
rm -f "${tmp_log_file}"
yann@165
    80
exec >>"${tmp_log_file}"
yann@165
    81
yann@1
    82
# The different log levels:
yann@1
    83
CT_LOG_LEVEL_ERROR=0
yann@1
    84
CT_LOG_LEVEL_WARN=1
yann@1
    85
CT_LOG_LEVEL_INFO=2
yann@1
    86
CT_LOG_LEVEL_EXTRA=3
anthony@2154
    87
CT_LOG_LEVEL_CFG=4
anthony@2154
    88
CT_LOG_LEVEL_FILE=5
anthony@2155
    89
CT_LOG_LEVEL_STATE=6
anthony@2155
    90
CT_LOG_LEVEL_ALL=7
anthony@2155
    91
CT_LOG_LEVEL_DEBUG=8
yann@1
    92
yann@1083
    93
# Make it easy to use \n and !
yann@1081
    94
CR=$(printf "\n")
yann@1083
    95
BANG='!'
yann@1081
    96
yann@1
    97
# A function to log what is happening
yann@1
    98
# Different log level are available:
yann@1
    99
#   - ERROR:   A serious, fatal error occurred
yann@1
   100
#   - WARN:    A non fatal, non serious error occurred, take your responsbility with the generated build
yann@1
   101
#   - INFO:    Informational messages
yann@1
   102
#   - EXTRA:   Extra informational messages
anthony@2154
   103
#   - CFG:     Output of various "./configure"-type scripts
anthony@2154
   104
#   - FILE:    File / archive unpacking.
anthony@2155
   105
#   - STATE:   State save & restore
yann@78
   106
#   - ALL:     Component's build messages
anthony@2155
   107
#   - DEBUG:   Internal debug messages
yann@1
   108
# Usage: CT_DoLog <level> [message]
yann@1
   109
# If message is empty, then stdin will be logged.
yann@1
   110
CT_DoLog() {
yann@47
   111
    local max_level LEVEL level cur_l cur_L
yann@47
   112
    local l
yann@1
   113
    eval max_level="\${CT_LOG_LEVEL_${CT_LOG_LEVEL_MAX}}"
yann@1
   114
    # Set the maximum log level to DEBUG if we have none
yann@78
   115
    [ -z "${max_level}" ] && max_level=${CT_LOG_LEVEL_DEBUG}
yann@1
   116
yann@47
   117
    LEVEL="$1"; shift
yann@1
   118
    eval level="\${CT_LOG_LEVEL_${LEVEL}}"
yann@1
   119
yann@1
   120
    if [ $# -eq 0 ]; then
yann@1
   121
        cat -
yann@1
   122
    else
yann@2096
   123
        printf "%s\n" "${*}"
yann@1081
   124
    fi |( IFS="${CR}" # We want the full lines, even leading spaces
yann@523
   125
          _prog_bar_cpt=0
yann@523
   126
          _prog_bar[0]='/'
yann@523
   127
          _prog_bar[1]='-'
yann@523
   128
          _prog_bar[2]='\'
yann@523
   129
          _prog_bar[3]='|'
yann@1
   130
          indent=$((2*CT_STEP_COUNT))
yann@1
   131
          while read line; do
yann@47
   132
              case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
yann@47
   133
                y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@112
   134
                y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
yann@47
   135
                *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@919
   136
                *"make["*"]: *** ["*)   cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
yann@47
   137
                *)                      cur_L="${LEVEL}"; cur_l="${level}";;
yann@47
   138
              esac
yann@523
   139
              # There will always be a log file (stdout, fd #1), be it /dev/null
yann@523
   140
              printf "[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}"
yann@47
   141
              if [ ${cur_l} -le ${max_level} ]; then
yann@523
   142
                  # Only print to console (fd #6) if log level is high enough.
javier@2382
   143
                  printf "${CT_LOG_PROGRESS_BAR:+\r}[%-5s]%*s%s%s\n" "${cur_L}" "${indent}" " " "${line}" >&6
yann@82
   144
              fi
yann@82
   145
              if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
yann@523
   146
                  printf "\r[%02d:%02d] %s " $((SECONDS/60)) $((SECONDS%60)) "${_prog_bar[$((_prog_bar_cpt/10))]}" >&6
yann@523
   147
                  _prog_bar_cpt=$(((_prog_bar_cpt+1)%40))
yann@1
   148
              fi
yann@1
   149
          done
yann@1
   150
        )
yann@1
   151
yann@1
   152
    return 0
yann@1
   153
}
yann@1
   154
yann@535
   155
# Execute an action, and log its messages
yann@2340
   156
# It is possible to even log local variable assignments (a-la: var=val ./cmd opts)
yann@2340
   157
# Usage: CT_DoExecLog <level> [VAR=val...] <command> [parameters...]
yann@535
   158
CT_DoExecLog() {
yann@535
   159
    local level="$1"
yann@535
   160
    shift
yann@2340
   161
    (
yann@2340
   162
    for i in "$@"; do
yann@2340
   163
        tmp_log+="'${i}' "
yann@2340
   164
    done
yann@2340
   165
    while true; do
yann@2340
   166
        case "${1}" in
yann@2340
   167
            *=*)    eval export "'${1}'"; shift;;
yann@2340
   168
            *)      break;;
yann@2340
   169
        esac
yann@2340
   170
    done
yann@2340
   171
    CT_DoLog DEBUG "==> Executing: ${tmp_log}"
yann@668
   172
    "${@}" 2>&1 |CT_DoLog "${level}"
yann@2340
   173
    )
yann@2340
   174
    # Catch failure of the sub-shell
yann@2340
   175
    [ $? -eq 0 ]
yann@535
   176
}
yann@535
   177
yann@96
   178
# Tail message to be logged whatever happens
yann@96
   179
# Usage: CT_DoEnd <level>
yann@96
   180
CT_DoEnd()
yann@96
   181
{
yann@145
   182
    local level="$1"
yann@523
   183
    CT_STOP_DATE=$(CT_DoDate +%s%N)
yann@523
   184
    CT_STOP_DATE_HUMAN=$(CT_DoDate +%Y%m%d.%H%M%S)
yann@599
   185
    if [ "${level}" != "ERROR" ]; then
yann@582
   186
        CT_DoLog "${level:-INFO}" "Build completed at ${CT_STOP_DATE_HUMAN}"
yann@582
   187
    fi
yann@96
   188
    elapsed=$((CT_STOP_DATE-CT_STAR_DATE))
yann@96
   189
    elapsed_min=$((elapsed/(60*1000*1000*1000)))
yann@523
   190
    elapsed_sec=$(printf "%02d" $(((elapsed%(60*1000*1000*1000))/(1000*1000*1000))))
yann@523
   191
    elapsed_csec=$(printf "%02d" $(((elapsed%(1000*1000*1000))/(10*1000*1000))))
yann@145
   192
    CT_DoLog ${level:-INFO} "(elapsed: ${elapsed_min}:${elapsed_sec}.${elapsed_csec})"
yann@96
   193
}
yann@96
   194
yann@2051
   195
# Remove entries referring to . and other relative paths
js@2044
   196
# Usage: CT_SanitizePath
js@2044
   197
CT_SanitizePath() {
js@2044
   198
    local new
yann@2051
   199
    local p
js@2044
   200
    local IFS=:
js@2044
   201
    for p in $PATH; do
yann@2051
   202
        # Only accept absolute paths;
yann@2051
   203
        # Note: as a special case the empty string in PATH is equivalent to .
yann@2051
   204
        if [ -n "${p}" -a -z "${p%%/*}" ]; then
js@2044
   205
            new="${new}${new:+:}${p}"
js@2044
   206
        fi
js@2044
   207
    done
js@2044
   208
    PATH="${new}"
js@2044
   209
}
js@2044
   210
yann@2280
   211
# Sanitise the directory name contained in the variable passed as argument:
yann@2280
   212
# - remove duplicate /
yann@2280
   213
# Usage: CT_SanitiseVarDir CT_PREFIX_DIR
yann@2280
   214
CT_SanitiseVarDir() {
yann@2280
   215
    local var
yann@2280
   216
    local old_dir
yann@2280
   217
    local new_dir
yann@2280
   218
yann@2280
   219
    for var in "$@"; do
yann@2280
   220
        eval "old_dir=\"\${${var}}\""
yann@2280
   221
        new_dir="$( printf "${old_dir}"     \
yann@2280
   222
                    |sed -r -e 's:/+:/:g;'  \
yann@2280
   223
                  )"
yann@2280
   224
        eval "${var}=\"${new_dir}\""
yann@2280
   225
        CT_DoLog DEBUG "Sanitised '${var}': '${old_dir}' -> '${new_dir}'"
yann@2280
   226
    done
yann@2280
   227
}
yann@2280
   228
yann@96
   229
# Abort the execution with an error message
yann@1
   230
# Usage: CT_Abort <message>
yann@1
   231
CT_Abort() {
yann@128
   232
    CT_DoLog ERROR "$1"
yann@1
   233
    exit 1
yann@1
   234
}
yann@1
   235
yann@1
   236
# Test a condition, and print a message if satisfied
yann@1
   237
# Usage: CT_Test <message> <tests>
yann@1
   238
CT_Test() {
yann@1
   239
    local ret
yann@1
   240
    local m="$1"
yann@1
   241
    shift
yann@1909
   242
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   243
    test "$@" && CT_DoLog WARN "$m"
yann@1
   244
    return 0
yann@1
   245
}
yann@1
   246
yann@1
   247
# Test a condition, and abort with an error message if satisfied
yann@1
   248
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   249
CT_TestAndAbort() {
yann@1
   250
    local m="$1"
yann@1
   251
    shift
yann@1909
   252
    CT_DoLog DEBUG "Testing '! ( $* )'"
yann@1
   253
    test "$@" && CT_Abort "$m"
yann@1
   254
    return 0
yann@1
   255
}
yann@1
   256
yann@1
   257
# Test a condition, and abort with an error message if not satisfied
yann@1
   258
# Usage: CT_TestAndAbort <message> <tests>
yann@1
   259
CT_TestOrAbort() {
yann@1
   260
    local m="$1"
yann@1
   261
    shift
yann@1909
   262
    CT_DoLog DEBUG "Testing '$*'"
yann@1
   263
    test "$@" || CT_Abort "$m"
yann@1
   264
    return 0
yann@1
   265
}
yann@1
   266
yann@1
   267
# Test the presence of a tool, or abort if not found
yann@1
   268
# Usage: CT_HasOrAbort <tool>
yann@1
   269
CT_HasOrAbort() {
yann@773
   270
    CT_TestAndAbort "'${1}' not found and needed for successful toolchain build." -z "$(CT_Which "${1}")"
yann@1
   271
    return 0
yann@1
   272
}
yann@1
   273
yann@210
   274
# Search a program: wrap "which" for those system where
yann@1226
   275
# "which" verbosely says there is no match (Mandriva is
yann@1226
   276
# such a sucker...)
yann@210
   277
# Usage: CT_Which <filename>
yann@210
   278
CT_Which() {
yann@210
   279
  which "$1" 2>/dev/null || true
yann@210
   280
}
yann@210
   281
yann@1
   282
# Get current date with nanosecond precision
yann@1
   283
# On those system not supporting nanosecond precision, faked with rounding down
yann@1
   284
# to the highest entire second
yann@1
   285
# Usage: CT_DoDate <fmt>
yann@1
   286
CT_DoDate() {
yann@2383
   287
    date "$1" |sed -r -e 's/%?N$/000000000/;'
yann@1
   288
}
yann@1
   289
yann@1
   290
CT_STEP_COUNT=1
yann@1
   291
CT_STEP_MESSAGE[${CT_STEP_COUNT}]="<none>"
yann@1
   292
# Memorise a step being done so that any error is caught
yann@1
   293
# Usage: CT_DoStep <loglevel> <message>
yann@1
   294
CT_DoStep() {
yann@523
   295
    local start=$(CT_DoDate +%s%N)
yann@1
   296
    CT_DoLog "$1" "================================================================="
yann@1
   297
    CT_DoLog "$1" "$2"
yann@1
   298
    CT_STEP_COUNT=$((CT_STEP_COUNT+1))
yann@1
   299
    CT_STEP_LEVEL[${CT_STEP_COUNT}]="$1"; shift
yann@1
   300
    CT_STEP_START[${CT_STEP_COUNT}]="${start}"
yann@1
   301
    CT_STEP_MESSAGE[${CT_STEP_COUNT}]="$1"
yann@1
   302
    return 0
yann@1
   303
}
yann@1
   304
yann@1
   305
# End the step just being done
yann@1
   306
# Usage: CT_EndStep
yann@1
   307
CT_EndStep() {
yann@523
   308
    local stop=$(CT_DoDate +%s%N)
yann@523
   309
    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@582
   310
    local elapsed=$(printf "%02d:%02d" $((SECONDS/60)) $((SECONDS%60)))
yann@1
   311
    local level="${CT_STEP_LEVEL[${CT_STEP_COUNT}]}"
yann@1
   312
    local message="${CT_STEP_MESSAGE[${CT_STEP_COUNT}]}"
yann@1
   313
    CT_STEP_COUNT=$((CT_STEP_COUNT-1))
yann@582
   314
    CT_DoLog "${level}" "${message}: done in ${duration}s (at ${elapsed})"
yann@1
   315
    return 0
yann@1
   316
}
yann@1
   317
yann@1
   318
# Pushes into a directory, and pops back
yann@1
   319
CT_Pushd() {
yann@1
   320
    pushd "$1" >/dev/null 2>&1
yann@1
   321
}
yann@1
   322
CT_Popd() {
yann@1
   323
    popd >/dev/null 2>&1
yann@1
   324
}
yann@1
   325
yann@1
   326
# Creates a temporary directory
yann@1
   327
# $1: variable to assign to
yann@1
   328
# Usage: CT_MktempDir foo
yann@1
   329
CT_MktempDir() {
yann@1
   330
    # Some mktemp do not allow more than 6 Xs
yann@1113
   331
    eval "$1"=$(mktemp -q -d "${CT_BUILD_DIR}/tmp.XXXXXX")
yann@1
   332
    CT_TestOrAbort "Could not make temporary directory" -n "${!1}" -a -d "${!1}"
yann@787
   333
    CT_DoLog DEBUG "Made temporary directory '${!1}'"
yann@787
   334
    return 0
yann@1
   335
}
yann@1
   336
yann@1148
   337
# Removes one or more directories, even if it is read-only, or its parent is
yann@1138
   338
# Usage: CT_DoForceRmdir dir [...]
yann@1138
   339
CT_DoForceRmdir() {
yann@1148
   340
    local dir
yann@1148
   341
    local mode
yann@1148
   342
    for dir in "${@}"; do
yann@1148
   343
        [ -d "${dir}" ] || continue
titus@1956
   344
        case "$CT_SYS_OS" in
yann@2029
   345
            Linux|CYGWIN*)
titus@1956
   346
                mode="$(stat -c '%a' "$(dirname "${dir}")")"
titus@1956
   347
                ;;
titus@1956
   348
            Darwin|*BSD)
titus@1956
   349
                mode="$(stat -f '%Lp' "$(dirname "${dir}")")"
titus@1956
   350
                ;;
titus@1956
   351
            *)
titus@1956
   352
                CT_Abort "Unhandled host OS $CT_SYS_OS"
titus@1956
   353
                ;;
titus@1956
   354
        esac
yann@1185
   355
        CT_DoExecLog ALL chmod u+w "$(dirname "${dir}")"
yann@1185
   356
        CT_DoExecLog ALL chmod -R u+w "${dir}"
yann@1148
   357
        CT_DoExecLog ALL rm -rf "${dir}"
yann@1185
   358
        CT_DoExecLog ALL chmod ${mode} "$(dirname "${dir}")"
yann@1148
   359
    done
yann@1138
   360
}
yann@1138
   361
yann@1
   362
# Echoes the specified string on stdout until the pipe breaks.
yann@1
   363
# Doesn't fail
yann@1
   364
# $1: string to echo
yann@1
   365
# Usage: CT_DoYes "" |make oldconfig
yann@1
   366
CT_DoYes() {
yann@1
   367
    yes "$1" || true
yann@1
   368
}
yann@63
   369
yann@1391
   370
# Add the specified directory to LD_LIBRARY_PATH, and export it
yann@1391
   371
# If the specified patch is already present, just export
yann@1391
   372
# $1: path to add
yann@1391
   373
# $2: add as 'first' or 'last' path, 'first' is assumed if $2 is empty
yann@1391
   374
# Usage CT_SetLibPath /some/where/lib [first|last]
yann@1391
   375
CT_SetLibPath() {
yann@1391
   376
    local path="$1"
yann@1391
   377
    local pos="$2"
yann@1391
   378
yann@1391
   379
    case ":${LD_LIBRARY_PATH}:" in
yann@1391
   380
        *:"${path}":*)  ;;
yann@1391
   381
        *)  case "${pos}" in
yann@1391
   382
                last)
yann@1391
   383
                    CT_DoLog DEBUG "Adding '${path}' at end of LD_LIBRARY_PATH"
yann@1391
   384
                    LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${path}"
yann@1391
   385
                    ;;
yann@1391
   386
                first|"")
yann@1391
   387
                    CT_DoLog DEBUG "Adding '${path}' at start of LD_LIBRARY_PATH"
yann@1391
   388
                    LD_LIBRARY_PATH="${path}${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
yann@1391
   389
                    ;;
yann@1391
   390
                *)
yann@1391
   391
                    CT_Abort "Incorrect position '${pos}' to add '${path}' to LD_LIBRARY_PATH"
yann@1391
   392
                    ;;
yann@1391
   393
            esac
yann@1391
   394
            ;;
yann@1391
   395
    esac
yann@1391
   396
    CT_DoLog DEBUG "==> LD_LIBRARY_PATH='${LD_LIBRARY_PATH}'"
yann@1391
   397
    export LD_LIBRARY_PATH
yann@1391
   398
}
yann@1391
   399
yann@85
   400
# Get the file name extension of a component
yann@719
   401
# Usage: CT_GetFileExtension <component_name-component_version> [extension]
yann@1690
   402
# If found, echoes the extension to stdout, and return 0
yann@1690
   403
# If not found, echoes nothing on stdout, and return !0.
yann@85
   404
CT_GetFileExtension() {
yann@85
   405
    local ext
yann@85
   406
    local file="$1"
yann@719
   407
    shift
yann@719
   408
    local first_ext="$1"
yann@85
   409
yann@160
   410
    # we need to also check for an empty extension for those very
yann@160
   411
    # peculiar components that don't have one (such as sstrip from
yann@160
   412
    # buildroot).
yann@1763
   413
    for ext in ${first_ext} .tar.gz .tar.bz2 .tgz .tar /.git ''; do
yann@1763
   414
        if [ -e "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@85
   415
            echo "${ext}"
yann@1690
   416
            exit 0
yann@85
   417
        fi
yann@85
   418
    done
yann@85
   419
yann@1690
   420
    exit 1
yann@85
   421
}
yann@85
   422
yann@2204
   423
# Try to retrieve the specified URL (HTTP or FTP)
yann@2204
   424
# Usage: CT_DoGetFile <URL>
yann@2204
   425
# This functions always returns true (0), as it can be legitimate not
yann@2204
   426
# to find the requested URL (think about snapshots, different layouts
yann@2204
   427
# for different gcc versions, etc...).
yann@2204
   428
CT_DoGetFile() {
yann@2501
   429
    local url="${1}"
yann@2501
   430
    local dest="${CT_TARBALLS_DIR}/${url##*/}"
yann@2205
   431
    local tmp="${dest}.tmp-dl"
yann@2204
   432
    # OK, just look if we have them...
yann@2204
   433
    # We are sure at least one is available, ./configure checked for it.
yann@2204
   434
    local _curl=$(CT_Which curl)
yann@2204
   435
    local _wget=$(CT_Which wget)
yann@2204
   436
    _curl="${_curl:-false}"
yann@2204
   437
    _wget="${_wget:-false}"
yann@2204
   438
yann@2205
   439
    # Remove potential left-over from a previous run
yann@2205
   440
    rm -f "${tmp}"
yann@2205
   441
yann@63
   442
    # Some (very old!) FTP server might not support the passive mode, thus
yann@2204
   443
    # retry without.
yann@2204
   444
    # We also retry a few times, in case there is a transient error (eg. behind
yann@2204
   445
    # a dynamic IP that changes during the transfer...)
yann@2204
   446
    # With automated download as we are doing, it can be very dangerous to
yann@2204
   447
    # continue the downloads. It's far better to simply overwrite the
yann@2204
   448
    # destination file.
yann@492
   449
    # Some company networks have firewalls to connect to the internet, but it's
yann@1113
   450
    # not easy to detect them, and wget does not timeout by default while
yann@492
   451
    # connecting, so force a global ${CT_CONNECT_TIMEOUT}-second timeout.
yann@2204
   452
    # For curl, no good progress indicator is available. So, be silent.
yann@2501
   453
    if CT_DoExecLog ALL "${_curl}" --ftp-pasv    --retry 3 --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f -s -o "${tmp}"   "${url}"  \
yann@2501
   454
    || CT_DoExecLog ALL "${_curl}"               --retry 3 --connect-timeout ${CT_CONNECT_TIMEOUT} -L -f -s -o "${tmp}"   "${url}"  \
yann@2501
   455
    || CT_DoExecLog ALL "${_wget}" --passive-ftp --tries=3 -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary -O "${tmp}" "${url}"  \
yann@2501
   456
    || CT_DoExecLog ALL "${_wget}"               --tries=3 -T ${CT_CONNECT_TIMEOUT} -nc --progress=dot:binary -O "${tmp}" "${url}"  \
yann@2205
   457
    ; then
yann@2205
   458
        # One of them succeeded, good!
yann@2205
   459
        mv "${tmp}" "${dest}"
yann@2205
   460
    else
yann@2205
   461
        # Woops...
yann@2205
   462
        rm -f "${tmp}"
yann@2205
   463
    fi
yann@63
   464
}
yann@63
   465
yann@1113
   466
# This function tries to retrieve a tarball form a local directory
yann@1113
   467
# Usage: CT_GetLocal <basename> [.extension]
yann@1113
   468
CT_GetLocal() {
yann@1113
   469
    local basename="$1"
yann@1113
   470
    local first_ext="$2"
yann@1113
   471
    local ext
yann@1113
   472
yann@1113
   473
    # Do we already have it in *our* tarballs dir?
yann@1690
   474
    if ext="$( CT_GetFileExtension "${basename}" ${first_ext} )"; then
yann@1113
   475
        CT_DoLog DEBUG "Already have '${basename}'"
yann@1113
   476
        return 0
yann@1113
   477
    fi
yann@1113
   478
yann@1113
   479
    if [ -n "${CT_LOCAL_TARBALLS_DIR}" ]; then
yann@1113
   480
        CT_DoLog DEBUG "Trying to retrieve an already downloaded copy of '${basename}'"
yann@1113
   481
        # We'd rather have a bzip2'ed tarball, then gzipped tarball, plain tarball,
yann@1113
   482
        # or, as a failover, a file without extension.
yann@1113
   483
        for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@1113
   484
            CT_DoLog DEBUG "Trying '${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}'"
yann@1113
   485
            if [ -r "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" -a \
yann@1113
   486
                 "${CT_FORCE_DOWNLOAD}" != "y" ]; then
yann@1113
   487
                CT_DoLog DEBUG "Got '${basename}' from local storage"
yann@1113
   488
                CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}${ext}" "${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1113
   489
                return 0
yann@1113
   490
            fi
yann@1113
   491
        done
yann@1113
   492
    fi
yann@1113
   493
    return 1
yann@1113
   494
}
yann@1113
   495
yann@1113
   496
# This function saves the specified to local storage if possible,
yann@1113
   497
# and if so, symlinks it for later usage
yann@1113
   498
# Usage: CT_SaveLocal </full/path/file.name>
yann@1113
   499
CT_SaveLocal() {
yann@1113
   500
    local file="$1"
yann@1113
   501
    local basename="${file##*/}"
yann@1113
   502
yann@1113
   503
    if [ "${CT_SAVE_TARBALLS}" = "y" ]; then
yann@1134
   504
        CT_DoLog EXTRA "Saving '${basename}' to local storage"
yann@1113
   505
        # The file may already exist if downloads are forced: remove it first
yann@1113
   506
        CT_DoExecLog ALL rm -f "${CT_LOCAL_TARBALLS_DIR}/${basename}"
yann@1113
   507
        CT_DoExecLog ALL mv -f "${file}" "${CT_LOCAL_TARBALLS_DIR}"
yann@1113
   508
        CT_DoExecLog ALL ln -s "${CT_LOCAL_TARBALLS_DIR}/${basename}" "${file}"
yann@1113
   509
    fi
yann@1113
   510
}
yann@1113
   511
yann@63
   512
# Download the file from one of the URLs passed as argument
yann@1113
   513
# Usage: CT_GetFile <basename> [.extension] <url> [url ...]
yann@63
   514
CT_GetFile() {
yann@63
   515
    local ext
yann@1179
   516
    local url URLS LAN_URLS
yann@63
   517
    local file="$1"
yann@1113
   518
    local first_ext
yann@63
   519
    shift
yann@712
   520
    # If next argument starts with a dot, then this is not an URL,
yann@712
   521
    # and we can consider that it is a preferred extension.
yann@242
   522
    case "$1" in
yann@712
   523
        .*) first_ext="$1"
yann@242
   524
            shift
yann@242
   525
            ;;
yann@242
   526
    esac
yann@63
   527
yann@1113
   528
    # Does it exist localy?
yann@1113
   529
    CT_GetLocal "${file}" ${first_ext} && return 0 || true
yann@1113
   530
    # No, it does not...
yann@63
   531
yann@754
   532
    # Try to retrieve the file
yann@788
   533
    CT_DoLog EXTRA "Retrieving '${file}'"
yann@754
   534
yann@1179
   535
    URLS="$@"
yann@1179
   536
yann@1022
   537
    # Add URLs on the LAN mirror
yann@1022
   538
    LAN_URLS=
yann@1022
   539
    if [ "${CT_USE_MIRROR}" = "y" ]; then
yann@1294
   540
        CT_TestOrAbort "Please set the mirror base URL" -n "${CT_MIRROR_BASE_URL}"
yann@1294
   541
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}/${file%-*}"
yann@1294
   542
        LAN_URLS="${LAN_URLS} ${CT_MIRROR_BASE_URL}"
yann@695
   543
yann@1134
   544
        if [ "${CT_PREFER_MIRROR}" = "y" ]; then
yann@1134
   545
            CT_DoLog DEBUG "Pre-pending LAN mirror URLs"
yann@1179
   546
            URLS="${LAN_URLS} ${URLS}"
yann@1134
   547
        else
yann@1134
   548
            CT_DoLog DEBUG "Appending LAN mirror URLs"
yann@1179
   549
            URLS="${URLS} ${LAN_URLS}"
yann@1134
   550
        fi
yann@1022
   551
    fi
yann@1022
   552
yann@1022
   553
    # Scan all URLs in turn, and try to grab a tarball from there
yann@1763
   554
    # Do *not* try git trees (ext=/.git), this is handled in a specific
yann@1763
   555
    # wrapper, below
yann@242
   556
    for ext in ${first_ext} .tar.bz2 .tar.gz .tgz .tar ''; do
yann@102
   557
        # Try all urls in turn
yann@1022
   558
        for url in ${URLS}; do
yann@2589
   559
            [ -n "${url}" ] || continue
yann@523
   560
            CT_DoLog DEBUG "Trying '${url}/${file}${ext}'"
yann@265
   561
            CT_DoGetFile "${url}/${file}${ext}"
yann@2492
   562
            if [ -f "${CT_TARBALLS_DIR}/${file}${ext}" ]; then
yann@799
   563
                CT_DoLog DEBUG "Got '${file}' from the Internet"
yann@1113
   564
                CT_SaveLocal "${CT_TARBALLS_DIR}/${file}${ext}"
yann@265
   565
                return 0
yann@265
   566
            fi
yann@102
   567
        done
yann@102
   568
    done
yann@63
   569
yann@2492
   570
    # Just warn, someone may want to catch and handle the error
yann@2492
   571
    # (eg. glibc/eglibc add-ons can be missing).
yann@2492
   572
    CT_DoLog WARN "Could not retrieve '${file}'."
yann@2492
   573
    return 1
yann@63
   574
}
yann@63
   575
yann@1113
   576
# Checkout from CVS, and build the associated tarball
yann@1113
   577
# The tarball will be called ${basename}.tar.bz2
yann@1113
   578
# Prerequisite: either the server does not require password,
yann@1113
   579
# or the user must already be logged in.
yann@1113
   580
# 'tag' is the tag to retrieve. Must be specified, but can be empty.
yann@1113
   581
# If dirname is specified, then module will be renamed to dirname
yann@1113
   582
# prior to building the tarball.
yann@1592
   583
# Usage: CT_GetCVS <basename> <url> <module> <tag> [dirname[=subdir]]
yann@1592
   584
# Note: if '=subdir' is given, then it is used instead of 'module'.
yann@1113
   585
CT_GetCVS() {
yann@1113
   586
    local basename="$1"
yann@1113
   587
    local uri="$2"
yann@1113
   588
    local module="$3"
yann@1113
   589
    local tag="${4:+-r ${4}}"
yann@1113
   590
    local dirname="$5"
yann@1113
   591
    local tmp_dir
yann@1113
   592
yann@1113
   593
    # Does it exist localy?
yann@1113
   594
    CT_GetLocal "${basename}" && return 0 || true
yann@1113
   595
    # No, it does not...
yann@1113
   596
yann@1113
   597
    CT_DoLog EXTRA "Retrieving '${basename}'"
yann@1113
   598
yann@1113
   599
    CT_MktempDir tmp_dir
yann@1113
   600
    CT_Pushd "${tmp_dir}"
yann@1113
   601
yann@1113
   602
    CT_DoExecLog ALL cvs -z 9 -d "${uri}" co -P ${tag} "${module}"
yann@1592
   603
    if [ -n "${dirname}" ]; then
yann@1592
   604
        case "${dirname}" in
yann@1592
   605
            *=*)
yann@1593
   606
                CT_DoExecLog DEBUG mv "${dirname#*=}" "${dirname%%=*}"
yann@1593
   607
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname%%=*}"
yann@1592
   608
                ;;
yann@1592
   609
            *)
yann@1592
   610
                CT_DoExecLog ALL mv "${module}" "${dirname}"
yann@1592
   611
                CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${dirname:-${module}}"
yann@1592
   612
                ;;
yann@1592
   613
        esac
yann@1592
   614
    fi
yann@1113
   615
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1113
   616
yann@1113
   617
    CT_Popd
yann@1113
   618
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1113
   619
}
yann@1113
   620
yann@1244
   621
# Check out from SVN, and build the associated tarball
yann@1244
   622
# The tarball will be called ${basename}.tar.bz2
yann@1244
   623
# Prerequisite: either the server does not require password,
yann@1244
   624
# or the user must already be logged in.
yann@1244
   625
# 'rev' is the revision to retrieve
yann@1244
   626
# Usage: CT_GetSVN <basename> <url> [rev]
yann@1244
   627
CT_GetSVN() {
yann@1244
   628
    local basename="$1"
yann@1244
   629
    local uri="$2"
yann@1244
   630
    local rev="$3"
yann@1244
   631
yann@2590
   632
    # First try locally, then the mirror
yann@2590
   633
    if CT_GetFile "${basename}"; then
yann@2590
   634
        # Got it! Return early! :-)
yann@2590
   635
        return 0
yann@2590
   636
    fi
yann@1244
   637
yann@1244
   638
    CT_MktempDir tmp_dir
yann@1244
   639
    CT_Pushd "${tmp_dir}"
yann@1244
   640
yann@2494
   641
    if ! CT_DoExecLog ALL svn export ${rev:+-r ${rev}} "${uri}" "${basename}"; then
yann@2494
   642
        CT_DoLog WARN "Could not retrieve '${basename}'"
yann@2494
   643
        return 1
yann@2494
   644
    fi
yann@1244
   645
    CT_DoExecLog ALL tar cjf "${CT_TARBALLS_DIR}/${basename}.tar.bz2" "${basename}"
yann@1244
   646
    CT_SaveLocal "${CT_TARBALLS_DIR}/${basename}.tar.bz2"
yann@1244
   647
yann@1244
   648
    CT_Popd
yann@1244
   649
    CT_DoExecLog ALL rm -rf "${tmp_dir}"
yann@1244
   650
}
yann@1244
   651
yann@1763
   652
# Clone a git tree
yann@1763
   653
# Tries the given URLs in turn until one can get cloned. No tarball will be created.
yann@1763
   654
# Prerequisites: either the server does not require password,
yann@1763
   655
# or the user has already taken any action to authenticate to the server.
yann@1763
   656
# The cloned tree will *not* be stored in the local tarballs dir!
yann@1763
   657
# Usage: CT_GetGit <basename> <url [url ...]>
yann@1763
   658
CT_GetGit() {
yann@1763
   659
    local basename="$1"; shift
yann@1763
   660
    local url
yann@1763
   661
    local cloned=0
yann@1763
   662
yann@1763
   663
    # Do we have it in our tarballs dir?
yann@1763
   664
    if [ -d "${CT_TARBALLS_DIR}/${basename}/.git" ]; then
yann@1763
   665
        CT_DoLog EXTRA "Updating git tree '${basename}'"
yann@1763
   666
        CT_Pushd "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   667
        CT_DoExecLog ALL git pull
yann@1763
   668
        CT_Popd
yann@1763
   669
    else
yann@1763
   670
        CT_DoLog EXTRA "Retrieving git tree '${basename}'"
yann@1763
   671
        for url in "${@}"; do
yann@1763
   672
            CT_DoLog ALL "Trying to clone from '${url}'"
yann@1763
   673
            CT_DoForceRmdir "${CT_TARBALLS_DIR}/${basename}"
yann@1763
   674
            if git clone "${url}" "${CT_TARBALLS_DIR}/${basename}" 2>&1 |CT_DoLog ALL; then
yann@1763
   675
                cloned=1
yann@1763
   676
                break
yann@1763
   677
            fi
yann@1763
   678
        done
yann@1763
   679
        CT_TestOrAbort "Could not clone '${basename}'" ${cloned} -ne 0
yann@1763
   680
    fi
yann@1763
   681
}
yann@1763
   682
yann@1126
   683
# Extract a tarball
yann@63
   684
# Some tarballs need to be extracted in specific places. Eg.: glibc addons
yann@63
   685
# must be extracted in the glibc directory; uCLibc locales must be extracted
yann@1123
   686
# in the extra/locale sub-directory of uClibc. This is taken into account
yann@1123
   687
# by the caller, that did a 'cd' into the correct path before calling us
yann@1123
   688
# and sets nochdir to 'nochdir'.
yann@1763
   689
# Note also that this function handles the git trees!
yann@1763
   690
# Usage: CT_Extract <basename> [nochdir] [options]
yann@1763
   691
# where 'options' are dependent on the source (eg. git branch/tag...)
yann@1126
   692
CT_Extract() {
yann@1761
   693
    local nochdir="$1"
yann@1761
   694
    local basename
yann@1690
   695
    local ext
yann@1690
   696
yann@1761
   697
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   698
        shift
yann@1761
   699
        nochdir="$(pwd)"
yann@1761
   700
    else
yann@1761
   701
        nochdir="${CT_SRC_DIR}"
yann@1761
   702
    fi
yann@1761
   703
yann@1761
   704
    basename="$1"
yann@1761
   705
    shift
yann@1761
   706
yann@1690
   707
    if ! ext="$(CT_GetFileExtension "${basename}")"; then
yann@2493
   708
        CT_DoLog WARN "'${basename}' not found in '${CT_TARBALLS_DIR}'"
yann@2493
   709
        return 1
yann@1690
   710
    fi
yann@1126
   711
    local full_file="${CT_TARBALLS_DIR}/${basename}${ext}"
yann@1126
   712
yann@1718
   713
    # Check if already extracted
yann@1718
   714
    if [ -e "${CT_SRC_DIR}/.${basename}.extracted" ]; then
yann@1718
   715
        CT_DoLog DEBUG "Already extracted '${basename}'"
yann@1718
   716
        return 0
yann@1718
   717
    fi
yann@1718
   718
yann@1691
   719
    # Check if previously partially extracted
yann@1691
   720
    if [ -e "${CT_SRC_DIR}/.${basename}.extracting" ]; then
yann@1691
   721
        CT_DoLog ERROR "The '${basename}' sources were partially extracted."
yann@1691
   722
        CT_DoLog ERROR "Please remove first:"
yann@1691
   723
        CT_DoLog ERROR " - the source dir for '${basename}', in '${CT_SRC_DIR}'"
yann@1691
   724
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${basename}.extracting'"
yann@1691
   725
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1691
   726
    fi
yann@1691
   727
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracting"
yann@1691
   728
yann@1761
   729
    CT_Pushd "${nochdir}"
yann@63
   730
yann@1126
   731
    CT_DoLog EXTRA "Extracting '${basename}'"
benoit@2574
   732
    CT_DoExecLog FILE mkdir -p "${basename}"
yann@63
   733
    case "${ext}" in
benoit@2574
   734
        .tar.bz2)     CT_DoExecLog FILE tar --strip-components=1 -C "${basename}" -xvjf "${full_file}";;
benoit@2574
   735
        .tar.gz|.tgz) CT_DoExecLog FILE tar --strip-components=1 -C "${basename}" -xvzf "${full_file}";;
benoit@2574
   736
        .tar)         CT_DoExecLog FILE tar --strip-components=1 -C "${basename}" -xvf "${full_file}";;
yann@1763
   737
        /.git)        CT_ExtractGit "${basename}" "${@}";;
yann@2493
   738
        *)            CT_DoLog WARN "Don't know how to handle '${basename}${ext}': unknown extension"
yann@2493
   739
                      return 1
yann@2493
   740
                      ;;
yann@63
   741
    esac
yann@63
   742
yann@1763
   743
    # Don't mark as being extracted for git
yann@1763
   744
    case "${ext}" in
yann@1763
   745
        /.git)  ;;
yann@1763
   746
        *)      CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${basename}.extracted";;
yann@1763
   747
    esac
yann@1691
   748
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${basename}.extracting"
yann@1126
   749
yann@1761
   750
    CT_Popd
yann@1126
   751
}
yann@1126
   752
yann@1763
   753
# Create a working git clone
yann@1763
   754
# Usage: CT_ExtractGit <basename> [ref]
yann@1763
   755
# where 'ref' is the reference to use:
yann@1763
   756
#   the full name of a branch, like "remotes/origin/branch_name"
yann@1763
   757
#   a date as understandable by git, like "YYYY-MM-DD[ hh[:mm[:ss]]]"
yann@1763
   758
#   a tag name
yann@1763
   759
CT_ExtractGit() {
yann@1763
   760
    local basename="${1}"
yann@1763
   761
    local ref="${2}"
yann@1763
   762
    local clone_dir
yann@1763
   763
    local ref_type
yann@1763
   764
yann@1763
   765
    # pushd now to be able to get git revlist in case ref is a date
yann@1763
   766
    clone_dir="${CT_TARBALLS_DIR}/${basename}"
yann@1763
   767
    CT_Pushd "${clone_dir}"
yann@1763
   768
yann@1763
   769
    # What kind of reference is ${ref} ?
yann@1763
   770
    if [ -z "${ref}" ]; then
yann@1763
   771
        # Don't update the clone, keep as-is
yann@1763
   772
        ref_type=none
yann@1763
   773
    elif git tag |grep -E "^${ref}$" >/dev/null 2>&1; then
yann@1763
   774
        ref_type=tag
yann@1763
   775
    elif git branch -a --no-color |grep -E "^. ${ref}$" >/dev/null 2>&1; then
yann@1763
   776
        ref_type=branch
yann@1763
   777
    elif date -d "${ref}" >/dev/null 2>&1; then
yann@1763
   778
        ref_type=date
yann@1763
   779
        ref=$(git rev-list -n1 --before="${ref}")
yann@1763
   780
    else
yann@1763
   781
        CT_Abort "Reference '${ref}' is an incorrect git reference: neither tag, branch nor date"
yann@1763
   782
    fi
yann@1763
   783
yann@1763
   784
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/${basename}"
yann@1763
   785
    CT_DoExecLog ALL ln -sf "${clone_dir}" "${CT_SRC_DIR}/${basename}"
yann@1763
   786
yann@1763
   787
    case "${ref_type}" in
yann@1763
   788
        none)   ;;
anthony@2154
   789
        *)      CT_DoExecLog FILE git checkout "${ref}";;
yann@1763
   790
    esac
yann@1763
   791
yann@1763
   792
    CT_Popd
yann@1763
   793
}
yann@1763
   794
yann@1126
   795
# Patches the specified component
yann@1761
   796
# See CT_Extract, above, for explanations on 'nochdir'
yann@1901
   797
# Usage: CT_Patch [nochdir] <packagename> <packageversion>
yann@1901
   798
# If the package directory is *not* packagename-packageversion, then
yann@1901
   799
# the caller must cd into the proper directory first, and call us
yann@1901
   800
# with nochdir
yann@1126
   801
CT_Patch() {
yann@1761
   802
    local nochdir="$1"
yann@1901
   803
    local pkgname
yann@1901
   804
    local version
yann@1901
   805
    local pkgdir
yann@1761
   806
    local base_file
yann@1761
   807
    local ver_file
yann@1507
   808
    local d
yann@1507
   809
    local -a patch_dirs
yann@1507
   810
    local bundled_patch_dir
yann@1507
   811
    local local_patch_dir
yann@1126
   812
yann@1761
   813
    if [ "${nochdir}" = "nochdir" ]; then
yann@1761
   814
        shift
yann@1906
   815
        pkgname="$1"
yann@1906
   816
        version="$2"
yann@1906
   817
        pkgdir="${pkgname}-${version}"
yann@1761
   818
        nochdir="$(pwd)"
yann@1761
   819
    else
yann@1906
   820
        pkgname="$1"
yann@1906
   821
        version="$2"
yann@1906
   822
        pkgdir="${pkgname}-${version}"
yann@1901
   823
        nochdir="${CT_SRC_DIR}/${pkgdir}"
yann@1761
   824
    fi
yann@1761
   825
yann@1126
   826
    # Check if already patched
yann@1901
   827
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patched" ]; then
yann@1901
   828
        CT_DoLog DEBUG "Already patched '${pkgdir}'"
yann@1126
   829
        return 0
yann@63
   830
    fi
yann@63
   831
yann@1271
   832
    # Check if already partially patched
yann@1901
   833
    if [ -e "${CT_SRC_DIR}/.${pkgdir}.patching" ]; then
yann@1901
   834
        CT_DoLog ERROR "The '${pkgdir}' sources were partially patched."
yann@1271
   835
        CT_DoLog ERROR "Please remove first:"
yann@1901
   836
        CT_DoLog ERROR " - the source dir for '${pkgdir}', in '${CT_SRC_DIR}'"
yann@1901
   837
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.extracted'"
yann@1901
   838
        CT_DoLog ERROR " - the file '${CT_SRC_DIR}/.${pkgdir}.patching'"
yann@1271
   839
        CT_Abort "I'll stop now to avoid any carnage..."
yann@1271
   840
    fi
yann@1901
   841
    touch "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1271
   842
yann@1761
   843
    CT_Pushd "${nochdir}"
yann@1123
   844
yann@1901
   845
    CT_DoLog EXTRA "Patching '${pkgdir}'"
yann@63
   846
yann@1901
   847
    bundled_patch_dir="${CT_LIB_DIR}/patches/${pkgname}/${version}"
yann@1901
   848
    local_patch_dir="${CT_LOCAL_PATCH_DIR}/${pkgname}/${version}"
yann@1507
   849
yann@1507
   850
    case "${CT_PATCH_ORDER}" in
yann@1507
   851
        bundled)        patch_dirs=("${bundled_patch_dir}");;
yann@1507
   852
        local)          patch_dirs=("${local_patch_dir}");;
yann@1507
   853
        bundled,local)  patch_dirs=("${bundled_patch_dir}" "${local_patch_dir}");;
yann@1508
   854
        local,bundled)  patch_dirs=("${local_patch_dir}" "${bundled_patch_dir}");;
yann@1630
   855
        none)           patch_dirs=;;
yann@1507
   856
    esac
yann@1507
   857
yann@1507
   858
    for d in "${patch_dirs[@]}"; do
yann@1507
   859
        CT_DoLog DEBUG "Looking for patches in '${d}'..."
yann@1507
   860
        if [ -n "${d}" -a -d "${d}" ]; then
yann@1507
   861
            for p in "${d}"/*.patch; do
yann@63
   862
                if [ -f "${p}" ]; then
yann@523
   863
                    CT_DoLog DEBUG "Applying patch '${p}'"
yann@1765
   864
                    CT_DoExecLog ALL patch --no-backup-if-mismatch -g0 -F1 -p1 -f <"${p}"
yann@63
   865
                fi
yann@63
   866
            done
yann@1509
   867
            if [ "${CT_PATCH_SINGLE}" = "y" ]; then
yann@1509
   868
                break
yann@1509
   869
            fi
yann@63
   870
        fi
yann@63
   871
    done
yann@63
   872
yann@508
   873
    if [ "${CT_OVERIDE_CONFIG_GUESS_SUB}" = "y" ]; then
yann@508
   874
        CT_DoLog ALL "Overiding config.guess and config.sub"
yann@508
   875
        for cfg in config_guess config_sub; do
yann@1101
   876
            eval ${cfg}="${CT_LIB_DIR}/scripts/${cfg/_/.}"
yann@1101
   877
            [ -e "${CT_TOP_DIR}/scripts/${cfg/_/.}" ] && eval ${cfg}="${CT_TOP_DIR}/scripts/${cfg/_/.}"
yann@776
   878
            # Can't use CT_DoExecLog because of the '{} \;' to be passed un-mangled to find
yann@508
   879
            find . -type f -name "${cfg/_/.}" -exec cp -v "${!cfg}" {} \; |CT_DoLog ALL
yann@508
   880
        done
yann@508
   881
    fi
yann@508
   882
yann@1903
   883
    CT_DoExecLog DEBUG touch "${CT_SRC_DIR}/.${pkgdir}.patched"
yann@1903
   884
    CT_DoExecLog DEBUG rm -f "${CT_SRC_DIR}/.${pkgdir}.patching"
yann@1126
   885
yann@1761
   886
    CT_Popd
yann@63
   887
}
yann@63
   888
yann@182
   889
# Two wrappers to call config.(guess|sub) either from CT_TOP_DIR or CT_LIB_DIR.
yann@182
   890
# Those from CT_TOP_DIR, if they exist, will be be more recent than those from CT_LIB_DIR.
yann@182
   891
CT_DoConfigGuess() {
yann@1101
   892
    if [ -x "${CT_TOP_DIR}/scripts/config.guess" ]; then
yann@1101
   893
        "${CT_TOP_DIR}/scripts/config.guess"
yann@182
   894
    else
yann@1101
   895
        "${CT_LIB_DIR}/scripts/config.guess"
yann@182
   896
    fi
yann@182
   897
}
yann@182
   898
yann@182
   899
CT_DoConfigSub() {
yann@1101
   900
    if [ -x "${CT_TOP_DIR}/scripts/config.sub" ]; then
yann@1101
   901
        "${CT_TOP_DIR}/scripts/config.sub" "$@"
yann@182
   902
    else
yann@1101
   903
        "${CT_LIB_DIR}/scripts/config.sub" "$@"
yann@182
   904
    fi
yann@182
   905
}
yann@182
   906
yann@335
   907
# Compute the target tuple from what is provided by the user
yann@335
   908
# Usage: CT_DoBuildTargetTuple
yann@63
   909
# In fact this function takes the environment variables to build the target
yann@335
   910
# tuple. It is needed both by the normal build sequence, as well as the
yann@63
   911
# sample saving sequence.
yann@335
   912
CT_DoBuildTargetTuple() {
yann@383
   913
    # Set the endianness suffix, and the default endianness gcc option
yann@63
   914
    case "${CT_ARCH_BE},${CT_ARCH_LE}" in
yann@383
   915
        y,) target_endian_eb=eb
yann@383
   916
            target_endian_el=
yann@391
   917
            CT_ARCH_ENDIAN_CFLAG="-mbig-endian"
yann@527
   918
            CT_ARCH_ENDIAN_LDFLAG="-EB"
yann@383
   919
            ;;
yann@383
   920
        ,y) target_endian_eb=
yann@383
   921
            target_endian_el=el
yann@391
   922
            CT_ARCH_ENDIAN_CFLAG="-mlittle-endian"
yann@527
   923
            CT_ARCH_ENDIAN_LDFLAG="-EL"
yann@383
   924
            ;;
yann@63
   925
    esac
yann@383
   926
yann@965
   927
    # Build the default architecture tuple part
yann@965
   928
    CT_TARGET_ARCH="${CT_ARCH}"
yann@965
   929
yann@383
   930
    # Set defaults for the system part of the tuple. Can be overriden
yann@383
   931
    # by architecture-specific values.
yann@383
   932
    case "${CT_LIBC}" in
yann@787
   933
        *glibc) CT_TARGET_SYS=gnu;;
yann@383
   934
        uClibc) CT_TARGET_SYS=uclibc;;
yann@1591
   935
        *)      CT_TARGET_SYS=elf;;
yann@63
   936
    esac
yann@383
   937
yann@391
   938
    # Set the default values for ARCH, ABI, CPU, TUNE, FPU and FLOAT
yann@497
   939
    unset CT_ARCH_ARCH_CFLAG CT_ARCH_ABI_CFLAG CT_ARCH_CPU_CFLAG CT_ARCH_TUNE_CFLAG CT_ARCH_FPU_CFLAG CT_ARCH_FLOAT_CFLAG
yann@497
   940
    unset CT_ARCH_WITH_ARCH CT_ARCH_WITH_ABI CT_ARCH_WITH_CPU CT_ARCH_WITH_TUNE CT_ARCH_WITH_FPU CT_ARCH_WITH_FLOAT
yann@391
   941
    [ "${CT_ARCH_ARCH}"     ] && { CT_ARCH_ARCH_CFLAG="-march=${CT_ARCH_ARCH}";  CT_ARCH_WITH_ARCH="--with-arch=${CT_ARCH_ARCH}"; }
yann@391
   942
    [ "${CT_ARCH_ABI}"      ] && { CT_ARCH_ABI_CFLAG="-mabi=${CT_ARCH_ABI}";     CT_ARCH_WITH_ABI="--with-abi=${CT_ARCH_ABI}";    }
yann@391
   943
    [ "${CT_ARCH_CPU}"      ] && { CT_ARCH_CPU_CFLAG="-mcpu=${CT_ARCH_CPU}";     CT_ARCH_WITH_CPU="--with-cpu=${CT_ARCH_CPU}";    }
yann@405
   944
    [ "${CT_ARCH_TUNE}"     ] && { CT_ARCH_TUNE_CFLAG="-mtune=${CT_ARCH_TUNE}";  CT_ARCH_WITH_TUNE="--with-tune=${CT_ARCH_TUNE}"; }
yann@391
   945
    [ "${CT_ARCH_FPU}"      ] && { CT_ARCH_FPU_CFLAG="-mfpu=${CT_ARCH_FPU}";     CT_ARCH_WITH_FPU="--with-fpu=${CT_ARCH_FPU}";    }
yann@412
   946
    [ "${CT_ARCH_FLOAT_SW}" ] && { CT_ARCH_FLOAT_CFLAG="-msoft-float";           CT_ARCH_WITH_FLOAT="--with-float=soft";          }
yann@391
   947
yann@965
   948
    # Build the default kernel tuple part
yann@965
   949
    CT_TARGET_KERNEL="${CT_KERNEL}"
yann@964
   950
yann@965
   951
    # Overide the default values with the components specific settings
yann@964
   952
    CT_DoArchTupleValues
yann@965
   953
    CT_DoKernelTupleValues
yann@383
   954
yann@391
   955
    # Finish the target tuple construction
bartvdrmeulen@1896
   956
    CT_TARGET="${CT_TARGET_ARCH}"
bartvdrmeulen@1896
   957
    CT_TARGET="${CT_TARGET}${CT_TARGET_VENDOR:+-${CT_TARGET_VENDOR}}"
bartvdrmeulen@1896
   958
    CT_TARGET="${CT_TARGET}${CT_TARGET_KERNEL:+-${CT_TARGET_KERNEL}}"
bartvdrmeulen@1896
   959
    CT_TARGET="${CT_TARGET}${CT_TARGET_SYS:+-${CT_TARGET_SYS}}"
yann@1094
   960
yann@1094
   961
    # Sanity checks
yann@1094
   962
    __sed_alias=""
yann@1094
   963
    if [ -n "${CT_TARGET_ALIAS_SED_EXPR}" ]; then
yann@1094
   964
        __sed_alias=$(echo "${CT_TARGET}" |sed -r -e "${CT_TARGET_ALIAS_SED_EXPR}")
yann@1094
   965
    fi
yann@1094
   966
    case ":${CT_TARGET_VENDOR}:${CT_TARGET_ALIAS}:${__sed_alias}:" in
yann@1094
   967
      :*" "*:*:*:) CT_Abort "Don't use spaces in the vendor string, it breaks things.";;
yann@1094
   968
      :*"-"*:*:*:) CT_Abort "Don't use dashes in the vendor string, it breaks things.";;
yann@1094
   969
      :*:*" "*:*:) CT_Abort "Don't use spaces in the target alias, it breaks things.";;
yann@1094
   970
      :*:*:*" "*:) CT_Abort "Don't use spaces in the target sed transform, it breaks things.";;
yann@1094
   971
    esac
yann@1094
   972
yann@1094
   973
    # Canonicalise it
yann@1094
   974
    CT_TARGET=$(CT_DoConfigSub "${CT_TARGET}")
yann@391
   975
    # Prepare the target CFLAGS
yann@767
   976
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ENDIAN_CFLAG}"
yann@527
   977
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ARCH_CFLAG}"
yann@397
   978
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_ABI_CFLAG}"
yann@397
   979
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_CPU_CFLAG}"
yann@397
   980
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_TUNE_CFLAG}"
yann@397
   981
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FPU_CFLAG}"
yann@397
   982
    CT_ARCH_TARGET_CFLAGS="${CT_ARCH_TARGET_CFLAGS} ${CT_ARCH_FLOAT_CFLAG}"
yann@527
   983
yann@527
   984
    # Now on for the target LDFLAGS
yann@767
   985
    CT_ARCH_TARGET_LDFLAGS="${CT_ARCH_TARGET_LDFLAGS} ${CT_ARCH_ENDIAN_LDFLAG}"
yann@63
   986
}
yann@121
   987
yann@121
   988
# This function does pause the build until the user strikes "Return"
yann@121
   989
# Usage: CT_DoPause [optional_message]
yann@121
   990
CT_DoPause() {
yann@121
   991
    local foo
yann@121
   992
    local message="${1:-Pausing for your pleasure}"
yann@121
   993
    CT_DoLog INFO "${message}"
yann@523
   994
    read -p "Press 'Enter' to continue, or Ctrl-C to stop..." foo >&6
yann@121
   995
    return 0
yann@121
   996
}
yann@121
   997
yann@1907
   998
# This function creates a tarball of the specified directory, but
yann@1907
   999
# only if it exists
yann@1907
  1000
# Usage: CT_DoTarballIfExists <dir> <tarball_basename> [extra_tar_options [...]]
yann@1907
  1001
CT_DoTarballIfExists() {
yann@1907
  1002
    local dir="$1"
yann@1907
  1003
    local tarball="$2"
yann@1907
  1004
    shift 2
yann@1907
  1005
    local -a extra_tar_opts=( "$@" )
yann@1908
  1006
    local -a compress
yann@1907
  1007
yann@1907
  1008
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1009
        y)  compress=( gzip -c -3 - ); tar_ext=.gz;;
yann@1908
  1010
        *)  compress=( cat - );        tar_ext=;;
yann@1907
  1011
    esac
yann@1907
  1012
yann@1907
  1013
    if [ -d "${dir}" ]; then
yann@1907
  1014
        CT_DoLog DEBUG "  Saving '${dir}'"
yann@1908
  1015
        { tar c -C "${dir}" -v -f - "${extra_tar_opts[@]}" .    \
yann@1908
  1016
          |"${compress[@]}" >"${tarball}.tar${tar_ext}"         ;
anthony@2155
  1017
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1018
    else
anthony@2155
  1019
        CT_DoLog STATE "  Not saving '${dir}': does not exist"
yann@1907
  1020
    fi
yann@1907
  1021
}
yann@1907
  1022
yann@1907
  1023
# This function extracts a tarball to the specified directory, but
yann@1907
  1024
# only if the tarball exists
anthony@2155
  1025
# Usage: CT_DoExtractTarballIfExists <tarball_basename> <dir> [extra_tar_options [...]]
yann@1907
  1026
CT_DoExtractTarballIfExists() {
yann@1907
  1027
    local tarball="$1"
yann@1907
  1028
    local dir="$2"
yann@1907
  1029
    shift 2
yann@1907
  1030
    local -a extra_tar_opts=( "$@" )
yann@1908
  1031
    local -a uncompress
yann@1907
  1032
yann@1907
  1033
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@1908
  1034
        y)  uncompress=( gzip -c -d ); tar_ext=.gz;;
yann@1908
  1035
        *)  uncompress=( cat );        tar_ext=;;
yann@1907
  1036
    esac
yann@1907
  1037
yann@1907
  1038
    if [ -f "${tarball}.tar${tar_ext}" ]; then
yann@1907
  1039
        CT_DoLog DEBUG "  Restoring '${dir}'"
yann@1907
  1040
        CT_DoForceRmdir "${dir}"
yann@1907
  1041
        CT_DoExecLog DEBUG mkdir -p "${dir}"
yann@1908
  1042
        { "${uncompress[@]}" "${tarball}.tar${tar_ext}"     \
yann@1908
  1043
          |tar x -C "${dir}" -v -f - "${extra_tar_opts[@]}" ;
anthony@2155
  1044
        } 2>&1 |sed -r -e 's/^/    /;' |CT_DoLog STATE
yann@1907
  1045
    else
anthony@2155
  1046
        CT_DoLog STATE "  Not restoring '${dir}': does not exist"
yann@1907
  1047
    fi
yann@1907
  1048
}
yann@1907
  1049
yann@121
  1050
# This function saves the state of the toolchain to be able to restart
yann@121
  1051
# at any one point
yann@121
  1052
# Usage: CT_DoSaveState <next_step_name>
yann@121
  1053
CT_DoSaveState() {
yann@121
  1054
	[ "${CT_DEBUG_CT_SAVE_STEPS}" = "y" ] || return 0
yann@121
  1055
    local state_name="$1"
yann@121
  1056
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@121
  1057
yann@1266
  1058
    # Log this to the log level required by the user
yann@1266
  1059
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Saving state to restart at step '${state_name}'..."
yann@1134
  1060
yann@121
  1061
    rm -rf "${state_dir}"
yann@121
  1062
    mkdir -p "${state_dir}"
yann@121
  1063
anthony@2155
  1064
    CT_DoLog STATE "  Saving environment and aliases"
yann@738
  1065
    # We must omit shell functions, and some specific bash variables
yann@738
  1066
    # that break when restoring the environment, later. We could do
yann@1299
  1067
    # all the processing in the awk script, but a sed is easier...
yann@1299
  1068
    set |awk '
yann@1017
  1069
              BEGIN { _p = 1; }
yann@1017
  1070
              $0~/^[^ ]+ \(\)/ { _p = 0; }
yann@1017
  1071
              _p == 1
yann@1017
  1072
              $0 == "}" { _p = 1; }
yann@1017
  1073
              ' |sed -r -e '/^BASH_(ARGC|ARGV|LINENO|SOURCE|VERSINFO)=/d;
yann@738
  1074
                           /^(UID|EUID)=/d;
yann@738
  1075
                           /^(FUNCNAME|GROUPS|PPID|SHELLOPTS)=/d;' >"${state_dir}/env.sh"
yann@121
  1076
yann@2308
  1077
    CT_DoTarballIfExists "${CT_BUILDTOOLS_PREFIX_DIR}" "${state_dir}/buildtools_dir"
yann@2502
  1078
    CT_DoTarballIfExists "${CT_COMPLIBS_DIR}" "${state_dir}/complibs_dir"
yann@1907
  1079
    CT_DoTarballIfExists "${CT_CONFIG_DIR}" "${state_dir}/config_dir"
yann@1907
  1080
    CT_DoTarballIfExists "${CT_CC_CORE_STATIC_PREFIX_DIR}" "${state_dir}/cc_core_static_prefix_dir"
yann@1907
  1081
    CT_DoTarballIfExists "${CT_CC_CORE_SHARED_PREFIX_DIR}" "${state_dir}/cc_core_shared_prefix_dir"
yann@1907
  1082
    CT_DoTarballIfExists "${CT_PREFIX_DIR}" "${state_dir}/prefix_dir" --exclude '*.log'
yann@121
  1083
yann@2339
  1084
    CT_DoLog STATE "  Saving log file"
yann@2339
  1085
    exec >/dev/null
yann@2339
  1086
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@2339
  1087
        y)  gzip -3 -c "${tmp_log_file}"  >"${state_dir}/log.gz";;
yann@2339
  1088
        *)  cat "${tmp_log_file}" >"${state_dir}/log";;
yann@2339
  1089
    esac
yann@2339
  1090
    exec >>"${tmp_log_file}"
yann@121
  1091
}
yann@121
  1092
yann@136
  1093
# This function restores a previously saved state
yann@121
  1094
# Usage: CT_DoLoadState <state_name>
yann@121
  1095
CT_DoLoadState(){
yann@121
  1096
    local state_name="$1"
yann@121
  1097
    local state_dir="${CT_STATE_DIR}/${state_name}"
yann@135
  1098
    local old_RESTART="${CT_RESTART}"
yann@135
  1099
    local old_STOP="${CT_STOP}"
yann@121
  1100
yann@523
  1101
    CT_TestOrAbort "The previous build did not reach the point where it could be restarted at '${CT_RESTART}'" -d "${state_dir}"
yann@141
  1102
yann@121
  1103
    # We need to do something special with the log file!
yann@121
  1104
    if [ "${CT_LOG_TO_FILE}" = "y" ]; then
yann@121
  1105
        exec >"${state_dir}/tail.log"
yann@121
  1106
    fi
yann@1266
  1107
yann@1266
  1108
    # Log this to the log level required by the user
yann@1266
  1109
    CT_DoLog ${CT_LOG_LEVEL_MAX} "Restoring state at step '${state_name}', as requested."
yann@121
  1110
yann@1907
  1111
    CT_DoExtractTarballIfExists "${state_dir}/prefix_dir" "${CT_PREFIX_DIR}"
yann@1907
  1112
    CT_DoExtractTarballIfExists "${state_dir}/cc_core_shared_prefix_dir" "${CT_CC_CORE_SHARED_PREFIX_DIR}"
yann@1907
  1113
    CT_DoExtractTarballIfExists "${state_dir}/cc_core_static_prefix_dir" "${CT_CC_CORE_STATIC_PREFIX_DIR}"
yann@1907
  1114
    CT_DoExtractTarballIfExists "${state_dir}/config_dir" "${CT_CONFIG_DIR}"
yann@2502
  1115
    CT_DoExtractTarballIfExists "${state_dir}/complibs_dir" "${CT_COMPLIBS_DIR}"
yann@2308
  1116
    CT_DoExtractTarballIfExists "${state_dir}/buildtools_dir" "${CT_BUILDTOOLS_PREFIX_DIR}"
yann@1894
  1117
yann@121
  1118
    # Restore the environment, discarding any error message
yann@121
  1119
    # (for example, read-only bash internals)
anthony@2155
  1120
    CT_DoLog STATE "  Restoring environment"
yann@121
  1121
    . "${state_dir}/env.sh" >/dev/null 2>&1 || true
yann@121
  1122
yann@135
  1123
    # Restore the new RESTART and STOP steps
yann@135
  1124
    CT_RESTART="${old_RESTART}"
yann@135
  1125
    CT_STOP="${old_STOP}"
yann@135
  1126
    unset old_stop old_restart
yann@135
  1127
yann@2339
  1128
    CT_DoLog STATE "  Restoring log file"
yann@2339
  1129
    exec >/dev/null
yann@2339
  1130
    case "${CT_DEBUG_CT_SAVE_STEPS_GZIP}" in
yann@2339
  1131
        y)  zcat "${state_dir}/log.gz" >"${tmp_log_file}";;
yann@2339
  1132
        *)  cat "${state_dir}/log" >"${tmp_log_file}";;
yann@2339
  1133
    esac
yann@2339
  1134
    cat "${state_dir}/tail.log" >>"${tmp_log_file}"
yann@2339
  1135
    exec >>"${tmp_log_file}"
yann@2339
  1136
    rm -f "${state_dir}/tail.log"
yann@121
  1137
}