mulle-bootstrap-functions.sh
5de2fbd6
 #! /bin/sh
 #
 #   Copyright (c) 2015 Nat! - Mulle kybernetiK
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
 #   modification, are permitted provided that the following conditions are met:
 #
 #   Redistributions of source code must retain the above copyright notice, this
 #   list of conditions and the following disclaimer.
 #
 #   Redistributions in binary form must reproduce the above copyright notice,
 #   this list of conditions and the following disclaimer in the documentation
 #   and/or other materials provided with the distribution.
 #
 #   Neither the name of Mulle kybernetiK nor the names of its contributors
 #   may be used to endorse or promote products derived from this software
 #   without specific prior written permission.
 #
 #   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 #   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 #   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 #   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 #   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 #   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 #   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 #   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 #   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #   POSSIBILITY OF SUCH DAMAGE.
 
56104254
 # Escape sequence and resets, should use tput here instead of ANSI
 
8e817cc1
 if [ "${MULLE_BOOTSTRAP_NO_COLOR}" != "YES" ]
 then
56104254
    case `uname` in
3882a58c
       Darwin|Linux|FreeBSD)
56104254
          C_RESET="\033[0m"
8e817cc1
 
1b26e970
          # Useable Foreground colours, for black/white white/black
          C_RED="\033[0;31m"     C_GREEN="\033[0;32m"
          C_BLUE="\033[0;34m"    C_MAGENTA="\033[0;35m"
3bbc5caf
          C_CYAN="\033[0;36m"
3be635de
 
23cfa536
          C_BR_RED="\033[0;91m"
3bbc5caf
          C_BOLD="\033[1m"
          C_FAINT="\033[2m"
d7f96955
 
1b26e970
          C_RESET_BOLD="${C_RESET}${C_BOLD}"
56104254
          trap 'printf "${C_RESET}"' TERM EXIT
          ;;
    esac
8e817cc1
 fi
 
 
1b26e970
 C_ERROR="${C_RED}${C_BOLD}"
c6e7156e
 log_error()
 {
3882a58c
    printf "${C_ERROR}%b${C_RESET}\n" "$*" >&2
c6e7156e
 }
 
 
1b26e970
 C_WARNING="${C_MAGENTA}${C_BOLD}"
c6e7156e
 log_warning()
 {
b6db9b87
    if [ "${MULLE_BOOTSTRAP_TERSE}" != "YES" ]
c6e7156e
    then
3882a58c
       printf "${C_WARNING}%b${C_RESET}\n" "$*" >&2
c6e7156e
    fi
 }
 
 
1b26e970
 C_INFO="${C_CYAN}${C_BOLD}"
c6e7156e
 log_info()
 {
b6db9b87
    if [ "${MULLE_BOOTSTRAP_TERSE}" != "YES" ]
c6e7156e
    then
3882a58c
       printf "${C_INFO}%b${C_RESET}\n" "$*" >&2
c6e7156e
    fi
 }
 
 
a75ed0ba
 C_VERBOSE="${C_GREEN}${C_BOLD}"
 log_verbose()
 {
    if [ "${MULLE_BOOTSTRAP_VERBOSE}" = "YES"  ]
    then
       printf "${C_VERBOSE}%b${C_RESET}\n" "$*" >&2
    fi
 }
 
 
3bbc5caf
 C_FLUFF="${C_GREEN}${C_BOLD}"
c6e7156e
 log_fluff()
 {
a75ed0ba
    if [ "${MULLE_BOOTSTRAP_FLUFF}" = "YES"  ]
c6e7156e
    then
3882a58c
       printf "${C_FLUFF}%b${C_RESET}\n" "$*" >&2
c6e7156e
    fi
 }
 
 
3bbc5caf
 C_TRACE="${C_FLUFF}${C_FAINT}"
c6e7156e
 log_trace()
 {
38d9a1e1
    printf "${C_TRACE}%b${C_RESET}\n" "$*" >&2
c6e7156e
 }
 
 
3bbc5caf
 C_TRACE2="${C_RESET}${C_FAINT}"
c6e7156e
 log_trace2()
 {
38d9a1e1
    printf "${C_TRACE2}%b${C_RESET}\n" "$*" >&2
c6e7156e
 }
 
 
5de2fbd6
 #
 # some common functions
 #
 fail()
 {
c6e7156e
    log_error "$@"
5de2fbd6
    exit 1
 }
 
 
 internal_fail()
 {
7fdfcd11
    fail "${C_RED}*** internal error: ${C_BR_RED}$*"
5de2fbd6
 }
 
 
8e817cc1
 
 eval_exekutor()
 {
93bd7113
    if [ "${MULLE_BOOTSTRAP_DRY_RUN}" = "YES" -o "${MULLE_BOOTSTRAP_TRACE}" = "YES" ]
8e817cc1
    then
23cfa536
       echo "==> " "$@" >&2
8e817cc1
    fi
 
93bd7113
    if [ "${MULLE_BOOTSTRAP_DRY_RUN}" != "YES" ]
8e817cc1
    then
       eval "$@"
    fi
 }
 
3c8ec4d2
 
422c21da
 logging_eval_exekutor()
 {
23cfa536
    echo "==>" "$@"
422c21da
    eval_exekutor "$@"
 }
 
 
8e817cc1
 exekutor()
 {
93bd7113
    if [ "${MULLE_BOOTSTRAP_DRY_RUN}" = "YES" -o "${MULLE_BOOTSTRAP_TRACE}" = "YES" ]
8e817cc1
    then
23cfa536
       echo "==>" "$@" >&2
8e817cc1
    fi
 
93bd7113
    if [ "${MULLE_BOOTSTRAP_DRY_RUN}" != "YES" ]
8e817cc1
    then
       "$@"
    fi
 }
 
 
422c21da
 logging_exekutor()
 {
23cfa536
    echo "==>" "$@"
422c21da
    exekutor "$@"
 }
 
 
b06853c1
 is_yes()
 {
    local s
 
e3e80f18
    s=`echo "${1}" | tr '[:lower:]' '[:upper:]'`
b06853c1
    case "${s}" in
       YES|Y|1)
          return 0
       ;;
       NO|N|0|"")
          return 1
       ;;
 
       *)
          fail "$2 should contain YES or NO (or be empty)"
       ;;
    esac
 }
 
 
 concat()
 {
    local i
    local s
 
    for i in "$@"
    do
       if [ "${i}" != "" ]
       then
          if [ "${s}" != "" ]
          then
             s="${s} ${i}"
          else
             s="${i}"
          fi
       fi
    done
 
    echo "${s}"
 }
 
 
5de2fbd6
 path_depth()
 {
    local name
    local depth
 
    name="$1"
    depth=0
 
    if [ "${name}" != "" ]
    then
       while [ "$name" != "." ]
       do
a203984b
          name=`dirname -- "$name"`
5de2fbd6
          depth=`expr $depth + 1`
       done
    fi
e3e80f18
    echo "$depth"
5de2fbd6
 }
 
 
7fdfcd11
 extension_less_basename()
 {
    local  file
 
a203984b
    file="`basename -- "$1"`"
7fdfcd11
    echo "${file%.*}"
 }
 
 
8d41d7c7
 #
 # stolen from:
 # http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
 # ----
 #
 _prepend_path_if_relative()
 {
    case "$2" in
       /* )
          echo "$2"
          ;;
       * )
          echo "$1/$2"
          ;;
    esac
 }
 
 
 resolve_symlinks()
 {
    local dir_context path
 
    path="`readlink "$1"`"
    if [ $? -eq 0 ]
    then
a203984b
       dir_context=`dirname -- "$1"`
8d41d7c7
       resolve_symlinks "`_prepend_path_if_relative "$dir_context" "$path"`"
    else
       echo "$1"
    fi
 }
 
 
 _canonicalize_dir_path()
 {
     (cd "$1" 2>/dev/null && pwd -P)
 }
 
 
 _canonicalize_file_path()
 {
     local dir file
 
     dir="` dirname "$1"`"
a203984b
     file="`basename -- "$1"`"
8d41d7c7
     (cd "${dir}" 2>/dev/null && echo "`pwd -P`/${file}")
 }
 
 
 canonicalize_path()
 {
    if [ -d "$1" ]
    then
       _canonicalize_dir_path "$1"
    else
       _canonicalize_file_path "$1"
    fi
 }
 
 
 realpath()
 {
    canonicalize_path "`resolve_symlinks "$1"`"
 }
 
 # ----
fd52b354
 # stolen from: https://stackoverflow.com/questions/2564634/convert-absolute-path-into-relative-path-given-a-current-directory-using-bash
 # because the python dependency irked me
 #
407cfaef
 _relative_path_between()
c6e7156e
 {
fd52b354
     [ $# -ge 1 ] && [ $# -le 2 ] || return 1
     current="${2:+"$1"}"
     target="${2:-"$1"}"
     [ "$target" != . ] || target=/
     target="/${target##/}"
     [ "$current" != . ] || current=/
     current="${current:="/"}"
     current="/${current##/}"
     appendix="${target##/}"
     relative=''
     while appendix="${target#"$current"/}"
         [ "$current" != '/' ] && [ "$appendix" = "$target" ]; do
         if [ "$current" = "$appendix" ]; then
             relative="${relative:-.}"
             echo "${relative#/}"
             return 0
         fi
         current="${current%/*}"
         relative="$relative${relative:+/}.."
     done
     relative="$relative${relative:+${appendix:+/}}${appendix#/}"
     echo "$relative"
c6e7156e
 }
 
 
407cfaef
 relative_path_between()
 {
96c19760
    _relative_path_between "$2" "$1"
407cfaef
 }
 
 
5de2fbd6
 compute_relative()
 {
    local depth
    local relative
    local name
 
    name="$1"
 
    depth=`path_depth "${name}"`
    if [ "${depth}" -gt 0 ]
    then
       relative=".."
       while [ "$depth" -gt 1 ]
       do
          relative="${relative}/.."
          depth=`expr $depth - 1`
       done
    fi
fe01cf28
 
 #   if [ -z "$relative" ]
 #   then
 #      relative="."
 #   fi
 
5de2fbd6
    echo "${relative}"
 }
 
 
e3e80f18
 remove_absolute_path_prefix_up_to()
 {
    local s
    local prefix
 
    s="$1"
    prefix="$2"
 
a203984b
    if [ "`basename -- "${s}"`" = "${prefix}" ]
e3e80f18
    then
       return 0
    fi
 
    echo "${s}" | sed "s|^.*/${prefix}/\(.*\)*|\1|g"
 }
 
 
151d8edd
 escaped_spaces()
 {
    echo "$1" | sed 's/ /\\ /g'
 }
 
 
 combined_escaped_search_path()
 {
7a4ae0c8
    local i
    local path
 
151d8edd
    for i in "$@"
    do
       if [ ! -z "$i" ]
       then
          i="`escaped_spaces "$i"`"
          if [ -z "$path" ]
          then
             path="$i"
          else
             path="$path $i"
          fi
       fi
    done
 
    echo "${path}"
 }
 
 
3be635de
 mkdir_if_missing()
 {
    if [ ! -d "${1}" ]
    then
7fdfcd11
       log_fluff "Creating \"$1\" (`pwd -P`)"
28ed6b30
       exekutor mkdir -p "$1" || fail "failed to create directory \"$1\""
3be635de
    fi
 }
 
 
602ae7d9
 create_file_if_missing()
 {
fa4c23d6
    local dir
 
602ae7d9
    if [ ! -f "${1}" ]
    then
fa4c23d6
       dir="`dirname "${1}"`"
       if [ ! -z "${dir}" ]
       then
          mkdir_if_missing "${dir}"
       fi
 
602ae7d9
       log_fluff "Creating \"$1\" (`pwd -P`)"
       exekutor touch "$1" || fail "failed to create \"$1\""
    fi
 }
 
 
 remove_file_if_present()
 {
    if [ -f "${1}" ]
    then
       log_fluff "Removing \"$1\" (`pwd -P`)"
821cd36e
       exekutor chmod u+w "$1" || fail "Failed to make $1 writable"
602ae7d9
       exekutor rm -f "$1" || fail "failed to remove \"$1\""
    fi
 }
 
 
6a672446
 modification_timestamp()
 {
    case "`uname`" in
       Linux )
          stat --printf "%Y\n" "$1"
          ;;
       * )
          stat -f "%m" "$1"
          ;;
    esac
 }
 
602ae7d9
 
61fc7238
 simplify_path()
 {
    local file
 
    file="${1}"
 
    local modification
 
    # foo/ -> foo
    modification="`echo "${1}" | sed 's|^\(.*\)/$|\1|'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    # ./foo -> foo
    modification="`echo "${1}" | sed 's|^\./\(.*\)$|\1|'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    # foo/. -> foo
    modification="`echo "${1}" | sed 's|^\(.*\)/\.$|\1|'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    # bar/./foo -> bar/foo
    modification="`echo "${1}" | sed 's|^\(.*\)/\./\(.*\)$|\1/\2|'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    # bar/.. -> ""
    modification="`echo "${1}" | sed 's|^\([^/]*\)/\.\.$||'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    # bar/../foo -> foo
    modification="`echo "${1}" | sed 's|^\([^/]*\)/\.\./\(.*\)$|\2|'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    # bar/baz/../foo -> bar/foo
    modification="`echo "${1}" | sed 's|^\(.*\)/\([^/]*\)/\.\./\(.*\)$|\1/\3|'`"
    if  [ "${modification}" != "${file}" ]
    then
       simplify_path "${modification}"
       return
    fi
 
    echo "${modification}"
 }
 
 
3be635de
 #
 # consider . .. ~ or absolute paths as unsafe
 # anything starting with a $ is probably also bad
 # this just catches some obvious problems, not all
 #
 assert_sane_subdir_path()
 {
61fc7238
    local file
 
    file="`simplify_path "${1}"`"
 
    if [ -z "${file}" ]
    then
          log_error "refuse unsafe subdirectory path \"$1\""
          exit 1
    fi
 
    case "$file"  in
       \$*|~|..|.|/*)
          log_error "refuse unsafe subdirectory path \"$1\""
3be635de
          exit 1
       ;;
    esac
 }
 
 
 assert_sane_path()
 {
61fc7238
    local file
 
    file="`simplify_path "${1}"`"
 
    if [ -z "${file}" ]
    then
          log_error "refuse unsafe path \"$1\""
          exit 1
    fi
 
    case "$file"  in
       \$*|~|${HOME}|..|.|/)
7fdfcd11
          log_error "refuse unsafe path \"$1\""
3be635de
          exit 1
       ;;
    esac
 }
 
 
 rmdir_safer()
 {
    if [ -d "$1" ]
    then
       assert_sane_path "$1"
a7b563e1
       exekutor chmod -R u+w "$1" || fail "Failed to make $1 writable"
3be635de
       exekutor rm -rf "$1" || fail "failed to remove ${1}"
    fi
 }
 
 
50fec60e
 # returns 0 if said yes
5de2fbd6
 user_say_yes()
 {
   local  x
 
a7b563e1
   x=`read_config_setting "answer" "ASK"`
   while [ "$x" != "Y" -a "$x" != "YES" -a  "$x" != "N"  -a  "$x" != "NO"  -a "$x" != "" ]
5de2fbd6
   do
1b26e970
      printf "${C_WARNING}%b${C_RESET} (y/${C_GREEN}N${C_RESET}) > " "$*" >&2
5de2fbd6
      read x
a7b563e1
      x=`echo "${x}" | tr '[:lower:]' '[:upper:]'`
5de2fbd6
   done
 
a7b563e1
   [ "$x" = "Y" -o "$x" = "YES" ]
5de2fbd6
   return $?
 }
 
 
28ed6b30
 dir_can_be_rmdir()
5de2fbd6
 {
    local empty
 
28ed6b30
    if [ ! -d "$1" ]
    then
       return 2
    fi
 
    empty="`ls -A "$1" 2> /dev/null`"
5de2fbd6
    [ "$empty" = "" ]
 }
 
 
28ed6b30
 # this does not check for hidden files
5de2fbd6
 dir_has_files()
 {
    local empty
3be635de
    local result
5de2fbd6
 
    empty=`ls "$1"/* 2> /dev/null` 2> /dev/null
    [ "$empty" != "" ]
3be635de
    result=$?
 
    if [ "$result" -eq 1 ]
    then
28ed6b30
       log_fluff "Directory \"$1\" has no files"
3be635de
    else
28ed6b30
       log_fluff "Directory \"$1\" has files"
3be635de
    fi
    return "$result"
5de2fbd6
 }
 
 
 #
 # first find a project with matching name, otherwise find
 # first nearest project
 #
 find_xcodeproj()
 {
    local found
    local expect
    local depth
 
    found=""
    expect="$1"
    depth=1000
    #     IFS='\0'
 
7a4ae0c8
    local match
    local new_depth
 
5de2fbd6
    for i in `find . -name "*.xcodeproj" -print`
    do
a203984b
       match=`basename -- "${i}" .xcodeproj`
5de2fbd6
       if [ "$match" = "$expect" ]
       then
          echo "$i"
          return 0
       fi
 
       new_depth=`path_depth "$i"`
       if [ "$new_depth" -lt "$depth" ]
       then
          found="${i}"
          depth="$new_depth"
       fi
    done
 
    if [ "$found" != "" ]
    then
       echo "${found}"
       return 0
    fi
 
    return 1
 }
 
 
5fb25a38
 
 #
 # expands ${LOGNAME} and ${LOGNAME:-foo}
 #
 expand_environment_variables()
 {
     local string
 
     string="$1"
 
     local key
     local value
     local prefix
     local suffix
     local next
 
     key="`echo "${string}" | sed -n 's/^\(.*\)\${\([A-Za-z_][A-Za-z0-9_:-]*\)}\(.*\)$/\2/p'`"
     if [ ! -z "${key}" ]
     then
        prefix="`echo "${string}" | sed 's/^\(.*\)\${\([A-Za-z_][A-Za-z0-9_:-]*\)}\(.*\)$/\1/'`"
        suffix="`echo "${string}" | sed 's/^\(.*\)\${\([A-Za-z_][A-Za-z0-9_:-]*\)}\(.*\)$/\3/'`"
        value="`eval echo \$\{${key}\}`"
        next="${prefix}${value}${suffix}"
        if [ "${next}" != "${string}" ]
        then
           expand_environment_variables "${prefix}${value}${suffix}"
           return
        fi
     fi
     echo "$1"
 }
 
 
602ae7d9
 # deal with stuff like
 # foo
 # https://www./foo.git
 # host:foo
 #
5fb25a38
 
cbead75b
 canonical_clone_name()
7fdfcd11
 {
602ae7d9
    local  url
 
    url="$1"
 
5fb25a38
 
602ae7d9
    # cut off scheme part
 
    case "$url" in
       *:*)
          url="`echo "$@" | sed 's/^\(.*\):\(.*\)/\2/'`"
          ;;
    esac
 
    extension_less_basename "$url"
7fdfcd11
 }
 
 
602ae7d9
 count_clone_components()
 {
   echo "$@" | tr ';' '\012' | wc -l | awk '{ print $1 }'
 }
 
7fdfcd11
 
 url_from_clone()
 {
bf4c7902
    echo "$@" | cut '-d;' -f 1
7fdfcd11
 }
 
 
 _name_part_from_clone()
 {
bf4c7902
    echo "$@" | cut '-d;' -f 2
602ae7d9
 }
 
 
 _branch_part_from_clone()
 {
bf4c7902
    echo "$@" | cut '-d;' -f 3
 }
 
 
 _scm_part_from_clone()
 {
    echo "$@" | cut '-d;' -f 4
7fdfcd11
 }
 
 
 canonical_name_from_clone()
cbead75b
 {
    local url
7fdfcd11
    local name
602ae7d9
    local branch
7fdfcd11
 
    url="`url_from_clone "$@"`"
    name="`_name_part_from_clone "$@"`"
cbead75b
 
602ae7d9
    if [ ! -z "${name}" -a "${name}" != "${url}" ]
7fdfcd11
    then
       canonical_clone_name "${name}"
       return
    fi
cbead75b
 
7fdfcd11
    canonical_clone_name "${url}"
cbead75b
 }
 
 
602ae7d9
 branch_from_clone()
 {
    local count
 
    count="`count_clone_components "$@"`"
    if [ "$count" -ge 3 ]
    then
       _branch_part_from_clone "$@"
    fi
 }
 
 
bf4c7902
 scm_from_clone()
 {
    local count
 
    count="`count_clone_components "$@"`"
    if [ "$count" -ge 4 ]
    then
       _scm_part_from_clone "$@"
    fi
 }
 
602ae7d9
 
8e817cc1
 # http://askubuntu.com/questions/152001/how-can-i-get-octal-file-permissions-from-command-line
 lso()
5de2fbd6
 {
8e817cc1
    ls -aldG "$@" | \
    awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf(" %0o ",k);print }' | \
    awk '{print $1}'
5de2fbd6
 }
40fe269d
 
 
 run_script()
 {
    local script
 
    script="$1"
    shift
 
d7f96955
    [ ! -z "$script" ] || internal_fail "script is empty"
40fe269d
 
    if [ -x "${script}" ]
    then
a75ed0ba
       log_verbose "Executing script ${C_RESET_BOLD}${script}${C_VERBOSE} $1 ..."
40fe269d
       exekutor "${script}" "$@" || fail "script \"${script}\" did not run successfully"
    else
       if [ ! -e "${script}" ]
       then
d7f96955
          fail "script \"${script}\" not found ($PWD)"
40fe269d
       else
          fail "script \"${script}\" not executable"
       fi
    fi
 }
422c21da
 
 
 run_log_script()
 {
    echo "$@"
    run_script "$@"
 }
7a4ae0c8
 
 
a75ed0ba
 has_usr_local_include()
 {
    local name
 
    name="${1}"
    if [ -d "/usr/local/include/${name}" ]
    then
       return 0
    fi
 
    local include_name
 
    include_name="`echo "${name}" | tr '-' '_'`"
    [ -d "/usr/local/include/${include_name}" ]
 }
 
 
7a4ae0c8
 ensure_clones_directory()
 {
    if [ ! -d "${CLONESFETCH_SUBDIR}" ]
    then
       if [ "${COMMAND}" = "update" ]
       then
          fail "install first before upgrading"
       fi
       mkdir_if_missing "${CLONESFETCH_SUBDIR}"
    fi
 }
f146fd2e
 
602ae7d9
 
 ensure_consistency()
 {
    if [ -f "${CLONESFETCH_SUBDIR}/.fetch_update_started" ]
    then
       log_error "A previous fetch or update was incomplete.
fd52b354
 Suggested resolution (in $PWD):
602ae7d9
     ${C_RESET_BOLD}mulle-bootstrap clean dist${C_ERROR}
     ${C_RESET_BOLD}mulle-bootstrap${C_ERROR}
 
61fc7238
 Or do you feel lucky ?
    ${C_RESET_BOLD}rm ${CLONESFETCH_SUBDIR}/.fetch_update_started${C_ERROR}
602ae7d9
 and try again. But you've gotta ask yourself one question: Do I feel lucky ?
 Well, do ya, punk? "
       exit 1
    fi
 }
61fc7238
 
 
 get_core_count()
 {
     count="`nproc 2> /dev/null`"
     if [ -z "$count" ]
     then
        count="`sysctl -n hw.ncpu 2> /dev/null`"
     fi
 
     if [ -z "$count" ]
     then
        count=2
     fi
     echo $count
 }