mulle-bootstrap
b8b33348
 #! /usr/bin/env bash
5de2fbd6
 #
bba581f8
 #   Copyright (c) 2015-2017 Nat! - Mulle kybernetiK
5de2fbd6
 #   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.
4eff2e57
 #
0fc9abbe
 MULLE_EXECUTABLE_VERSION_MAJOR=3
0a7ec5a3
 MULLE_EXECUTABLE_VERSION_MINOR=12
7c0e5de0
 MULLE_EXECUTABLE_VERSION_PATCH=4
5de2fbd6
 
0fc9abbe
 MULLE_EXECUTABLE_VERSION="${MULLE_EXECUTABLE_VERSION_MAJOR}.${MULLE_EXECUTABLE_VERSION_MINOR}.${MULLE_EXECUTABLE_VERSION_PATCH}"
5de2fbd6
 
0921857b
 
b535bf57
 MULLE_EXECUTABLE_FUNCTIONS_MIN="3.12"
0921857b
 MULLE_EXECUTABLE_FUNCTIONS_MAX="4"
 
 
5de2fbd6
 #
 # This is the main user interface to mulle-bootstrap
 # sorta like git
 #
d2100287
 
8e31b74a
 trap_fail()
 {
    exit 1
 }
 
 
e400db11
 SHOWN_COMMANDS="\
    bootstrap     : does install and build recursively [default]
    build         : builds fetched repositories
    clean         : cleans mulle-bootstrap produced files.
    defer         : join a master mulle-bootstrap project
    emancipate    : emancipate from a master mulle-bootstrap project
    paths         : get include and library paths
    init          : initializes a bootstrap project
    update        : updates repositories (fetch).
    upgrade       : updates and checks out repositories (pull).
    show          : show repositories and brews"
 
 DARWIN_COMMANDS="\
    xcode         : sets up xcodeproj settings"
 HIDDEN_COMMANDS="\
    config        : read or edit config settings
    expansion     : read or edit fetch expansions
    git           : run git commands on fetched repositories
    library-path  : print path to mulle-bootstrap libexec
    project-path  : print path to folder containing .bootstrap
f543b0c7
    run           : run command with proper dependencies PATHs
e400db11
    setting       : read or edit build settings
    status        : show status of repositories and brews
56231345
    systeminstall : install dependencies as system libraries/headers
e400db11
    tag           : tag fetched repositories
    uname         : mulle-bootstraps simplified uname(1)
    version       : print mulle-bootstrap version"
 
 
 print_commands()
 {
    local  show_all="${1:-NO}"
 
    echo "${SHOWN_COMMANDS}"
 
    if [ "${UNAME}" = 'darwin' ]
    then
       echo "${DARWIN_COMMANDS}"
    fi
 
    if [ "${show_all}" != "NO" ]
    then
       echo "${HIDDEN_COMMANDS}"
    fi
 }
 
818b5aa7
 
 mulle_bootstrap_usage()
 {
e400db11
    local  verbose="${1:-NO}"
 
818b5aa7
    cat <<EOF
4eff2e57
 Usage:
    ${MULLE_BOOTSTAP_EXECUTABLE} [flags] [command] [options]
 
 Flags:
818b5aa7
    -a -y     : default answer to questions (scripts wont be checked)
                -a (clone preferred) -y (local copy/symlink preferred)
    -f        : force operation
    -n        : do nothing creative or destructive
db28bb90
    --no-defer: do not defer to master, if project is a minion
818b5aa7
    -v        : -v to be more verbose (-vv or -vvv for more verbosity)
    -V        : verbose build
db28bb90
    -DKEY=VAL : define local expansion key/value C style
818b5aa7
 EOF
 
    bootstrap_technical_option_usage
0c0a21db
 
    cat <<EOF
40fe269d
 
4eff2e57
 Commands:
2d8f68ea
 EOF
 
e400db11
    print_commands "${verbose}" | sort
 
 
    if [ "${verbose}" = "NO" ]
2d8f68ea
    then
       cat <<EOF
e400db11
       (use mulle-bootstrap -v help to show more commands)
e5b54e85
 EOF
    fi
 
e400db11
    cat <<EOF
4eff2e57
 Options are command specific. Use mulle-bootstrap <command> -h for help.
2d8f68ea
 EOF
d5a9eaee
 
eecd842e
    exit 1
40fe269d
 }
 
5de2fbd6
 
4805e856
 _bootstrap_main()
b78c95b8
 {
    local command
 
9339a58a
    log_debug "::: bootstrap begin :::"
b78c95b8
 
    . mulle-bootstrap-fetch.sh
    . mulle-bootstrap-build.sh
    . mulle-bootstrap-warn-scripts.sh
 
751a6002
    # used for option handling only
    MULLE_BOOTSTRAP_WILL_BUILD="YES"
 
bba581f8
    warn_scripts_main "${BOOTSTRAP_DIR}" || exit 1
096b64ec
 
151c6f06
    if fetch_needed
b78c95b8
    then
f67f6857
       MULLE_EXECUTABLE_FAIL_PREFIX="mulle-bootstrap fetch"
4805e856
       fetch_main "$@" || exit 1
5ec25abc
       # used for option handling only
       MULLE_BOOTSTRAP_DID_FETCH="YES"
f1f83418
    else
       log_verbose "No fetch needed"
b78c95b8
    fi
 
5ec25abc
    if build_needed
    then
f67f6857
       MULLE_EXECUTABLE_FAIL_PREFIX="mulle-bootstrap build"
1461fe52
       MULLE_BOOTSTRAP_DID_BUILD="YES"
5ec25abc
       build_main "$@" || exit 1
f1f83418
    else
       log_verbose "No build needed"
5ec25abc
    fi
a0247021
 
1461fe52
    #
    # only show for default "bootstrap" action
    #
    if [ "${MULLE_BOOTSTRAP_DID_FETCH}" = "YES" ]
    then
       if [ -f "${BOOTSTRAP_DIR}.auto/motd" ]
       then
          log_fluff "Show motd"
 
          cat "${BOOTSTRAP_DIR}.auto/motd" >&2
       fi
    fi
 
9339a58a
    log_debug "::: bootstrap end :::"
b78c95b8
 }
 
 
f04bc0b7
 #
 # 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"
1461fe52
       ;;
f04bc0b7
       *)
          echo "$1/$2"
1461fe52
       ;;
f04bc0b7
    esac
 }
 
 
 resolve_symlinks()
 {
    local dir_context
    local linkpath
 
    if linkpath="`readlink "$1"`"
    then
       dir_context=`dirname -- "$1"`
       resolve_symlinks "`_prepend_path_if_relative "${dir_context}" "${linkpath}"`"
    else
       echo "$1"
    fi
 }
 
 
bba581f8
 bootstrap_libexec_path()
 {
f04bc0b7
    local path="$1"
 
bba581f8
    local exedir
    local exedirpath
    local prefix
    local libexecpath
 
1461fe52
    case "${path}" in
       \.*|/*|~*)
       ;;
 
       *)
          path="`command -v "${path}"`"
       ;;
    esac
 
f04bc0b7
    path="`resolve_symlinks "${path}"`"
    exedirpath="`dirname "${path}"`"
bba581f8
    prefix="`dirname "${exedirpath}"`"
818b5aa7
    libexecpath="${prefix}/libexec/mulle-bootstrap"
bba581f8
 
    if [ ! -x "${libexecpath}/mulle-bootstrap-functions.sh" ]
    then
       libexecpath="${exedirpath}/src"
    fi
 
57935531
    case "$libexecpath" in
       /*|~*)
       ;;
 
       *)
          libexecpath="$PWD/$libexecpath"
       ;;
    esac
 
bba581f8
    if [ -x "${libexecpath}/mulle-bootstrap-functions.sh" ]
    then
       echo "${libexecpath}"
    fi
 }
 
 
818b5aa7
 bootstrap_init()
40fe269d
 {
bba581f8
    local libexecpath
28ed6b30
 
bba581f8
    libexecpath="`bootstrap_libexec_path "$0"`"
    if [ -z "${libexecpath}" ]
    then
1461fe52
       echo "Fatal Error: Could not find libexec for ${MULLE_EXECUTABLE} ($PWD)" >&2
bba581f8
       exit 1
    fi
8f77be37
 
bba581f8
    PATH="${libexecpath}:$PATH"
8f77be37
    export PATH
 
bba581f8
    if [ ! -z "${MULLE_BOOTSTRAP_LIBEXEC_TRACE}" ]
    then
       echo "PATH=$PATH" >&2
    fi
 
128e6b71
    #
    # shell export commands with minimal
    # trap setup
    #
    case "${1}" in
       library-path)
8f951e19
          echo "${libexecpath}"
128e6b71
          exit 0
       ;;
 
       version)
0fc9abbe
          echo "${MULLE_EXECUTABLE_VERSION}"
128e6b71
          exit 0
       ;;
1461fe52
 
       shell)
          fail "shell has moved to mulle-sde"
       ;;
128e6b71
    esac
 
8f951e19
    #  set -e # more pain then gain in the end
    #  set -u # doesn't work with my style
 
8f77be37
    # now include this first to get
    # logging and UNAME
 
ec2b9bc2
    . mulle-bootstrap-logging.sh
70f9762c
    . mulle-bootstrap-local-environment.sh || fail "not loaded"
8f77be37
 
    trap trap_fail INT
0921857b
    set -o pipefail
818b5aa7
 }
1c1494ca
 
0921857b
 
cbe9e1a7
 bootstrap_cd_projectpath()
 {
    local  orgpwd
 
    orgpwd="$PWD"
 
    while ! is_bootstrap_project
    do
       local old
 
       old="$PWD"
       cd ..
 
       if [ "$PWD" = "${old}" ]
       then
          if [ "${command}" = "seting" ]
          then
             cd "${orgpwd}"
          else
             return 1
          fi
       fi
    done
 }
 
1c1494ca
 
818b5aa7
 bootstrap_main()
 {
    local command
    local ps4string
83ce7c54
 
ea74a237
    local MULLE_FLAG_ANSWER="ASK"
06ffde28
    local MULLE_FLAG_MAGNUM_FORCE="NONE"
ea74a237
    local MULLE_FLAG_IGNORE_GRAVEYARD="NO"
    local MULLE_FLAG_VERBOSE_BUILD="NO"
 
    # technical flags
e3244671
    local MULLE_FLAG_DONT_DEFER="NO"
    local MULLE_FLAG_EXEKUTOR_DRY_RUN="NO"
ed001110
    local MULLE_FLAG_FOLLOW_SYMLINKS="YES"
0fc9abbe
    local MULLE_FLAG_LOG_CACHE="NO"
ea74a237
    local MULLE_FLAG_LOG_DEBUG="NO"
e3244671
    local MULLE_FLAG_LOG_EXEKUTOR="NO"
ea74a237
    local MULLE_FLAG_LOG_FLUFF="NO"
    local MULLE_FLAG_LOG_SCRIPTS="NO"
    local MULLE_FLAG_LOG_SETTINGS="NO"
    local MULLE_FLAG_LOG_VERBOSE="NO"
0d78d4c5
    local MULLE_FLAG_LOG_MERGE="NO"
ea74a237
    local MULLE_TRACE_PATHS_FLIP_X="NO"
    local MULLE_TRACE_POSTPONE="NO"
    local MULLE_TRACE_RESOLVER_FLIP_X="NO"
    local MULLE_TRACE_SETTINGS_FLIP_X="NO"
 
818b5aa7
    #
    # simple option handling
    #
    while [ $# -ne 0 ]
    do
f67f6857
       if bootstrap_technical_flags "$1"
818b5aa7
       then
          shift
          continue
       fi
1c1494ca
 
818b5aa7
       case "$1" in
          -a|--prefer-origin)
f67f6857
             MULLE_FLAG_ANSWER="NO"
818b5aa7
           ;;
1c1494ca
 
818b5aa7
          -y|--prefer-local)
f67f6857
             MULLE_FLAG_ANSWER="YES"
1c1494ca
          ;;
 
db28bb90
          --no-defer)
             MULLE_FLAG_DONT_DEFER="YES"
          ;;
 
ed001110
          # used persistently throughout so it's global
          --follow-symlinks)
             MULLE_FLAG_FOLLOW_SYMLINKS="YES"
          ;;
 
e400db11
          -f|--force)
06ffde28
             MULLE_FLAG_MAGNUM_FORCE="BOTH"
1c1494ca
          ;;
 
db28bb90
          --ignore-graveyard)
f67f6857
             MULLE_FLAG_IGNORE_GRAVEYARD="YES"
1c1494ca
          ;;
 
8f77be37
          -h|--help)
e400db11
             mulle_bootstrap_usage "${MULLE_TRACE}"
8f77be37
          ;;
 
d9c7fdec
          -D*)  # just like C
             # define key values (by putting them into .bootstrap.local)
0fc9abbe
             bootstrap_define_expansion "`echo "$1" | sed s'/^-D[ ]*//'`"
d9c7fdec
          ;;
 
          -V|--verbose-build)
f67f6857
             MULLE_FLAG_VERBOSE_BUILD="YES"
d9c7fdec
          ;;
 
a0d90111
          --version)
             echo "${MULLE_EXECUTABLE_VERSION}"
             exit 0
          ;;
 
1c1494ca
          -*)
f67f6857
             log_error "${MULLE_EXECUTABLE_FAIL_PREFIX}: Unknown option \"$1\""
4805e856
             mulle_bootstrap_usage
1c1494ca
          ;;
 
          *)
             break
          ;;
       esac
 
       shift
22174806
    done
1c1494ca
 
f67f6857
    bootstrap_setup_trace "${MULLE_TRACE}"
d2100287
 
fcf4306a
    # source in environment now
 
    local_environment_main
 
7a4ae0c8
    #
    # some commands only run when we have a .bootstrap folder
4d45dff2
    # we do it somewhat like git, and progress up the directory
    # hierarchy until we find a .bootstrap or .bootstrap.local folder
    # this is useful for `mulle-bootstrap paths` (with absolute paths)
7a4ae0c8
    #
3ee7ef17
    command="${1:-bootstrap}"
6704c86d
 
4d45dff2
    case "${command}" in
3466e2d3
       help|init|uname)
4d45dff2
       ;;
 
e400db11
       project-path)
cbe9e1a7
          if ! bootstrap_cd_projectpath
          then
             exit 1
          fi
e400db11
          echo "`pwd -P`"
          exit 0
       ;;
cbe9e1a7
 
       *)
          if ! bootstrap_cd_projectpath
          then
             fail "There is no ${BOOTSTRAP_DIR} or ${BOOTSTRAP_DIR}.local folder here ($orgpwd), can't continue"
          fi
       ;;
e400db11
    esac
 
4d45dff2
    if bootstrap_should_defer_to_master "$@"
28ed6b30
    then
4d45dff2
       return 1
    fi
 
e400db11
    #
    # some commands are only valid, if the fetch went through
    # defer/emancipate clean, so that's ok
    #
4eff2e57
    case "${MULLE_FLAG_MAGNUM_FORCE}" in
       "BOTH")
          set_fetch_needed
       ;;
 
       "NONE")
          case "${command}" in
             bootstrap|build|systeminstall|tag|update|upgrade)
                bootstrap_ensure_consistency
             ;;
          esac
       ;;
    esac
0c9ccfb6
 
0fc9abbe
    MULLE_EXECUTABLE_FAIL_PREFIX="${MULLE_EXECUTABLE} ${command}"
4805e856
    [ $# -eq 0 ] || shift
1c1494ca
 
e5b54e85
    MULLE_EXECUTABLE_OPTIONS="$@"
 
40fe269d
    case "${command}" in
4805e856
       bootstrap)
          _bootstrap_main "$@"
eecd842e
       ;;
40fe269d
 
       build)
f36a470f
          . mulle-bootstrap-build.sh
a3018cdd
 
0e39049a
          build_main "$@" || exit 1
eecd842e
       ;;
1b26e970
 
40fe269d
       clean)
f36a470f
          . mulle-bootstrap-clean.sh
a3018cdd
 
096b64ec
          clean_main "$@" || exit 1
       ;;
 
9cc4ab74
       config|configs|configurations)
096b64ec
          . mulle-bootstrap-settings.sh
fcf4306a
 
096b64ec
          config_main "$@" || exit 1
eecd842e
       ;;
40fe269d
 
4805e856
       defer)
          . mulle-bootstrap-defer.sh
8f951e19
 
4805e856
          defer_main "$@" || exit 1
8f951e19
       ;;
 
085db3f3
       dist)
f36a470f
          . mulle-bootstrap-clean.sh
a3018cdd
 
096b64ec
          clean_main "dist" || exit 1
eecd842e
       ;;
a7b563e1
 
4805e856
       emancipate)
          . mulle-bootstrap-defer.sh
 
          emancipate_main "$@" || exit 1
       ;;
 
9cc4ab74
       expansion|expansions)
e5b54e85
          . mulle-bootstrap-settings.sh
 
          expansion_main "$@" || exit 1
       ;;
 
9cc4ab74
       path|paths)
4d45dff2
          . mulle-bootstrap-paths.sh
c8f0ab29
 
4d45dff2
          paths_main "$@" || exit 1
c8f0ab29
       ;;
 
8f951e19
       git)
          . mulle-bootstrap-scm.sh
a3018cdd
 
8f951e19
          git_main "$@" || exit 1
eecd842e
       ;;
40fe269d
 
e5b54e85
       help)
e400db11
          mulle_bootstrap_usage "${MULLE_TRACE}" || exit 1
e5b54e85
       ;;
 
096b64ec
       init)
          . mulle-bootstrap-init.sh
 
          init_main "$@" || exit 1
       ;;
 
8f951e19
       install|fetch)
          . mulle-bootstrap-fetch.sh
096b64ec
 
8f951e19
          DONT_ASK_AFTER_WARNING=YES fetch_main "$@" || exit 1
096b64ec
       ;;
 
       library-path)
          echo "$PATH" | tr ':' '\012' | head -1
70f9762c
          return 0
096b64ec
       ;;
 
1461fe52
       master-path)
          echo "${PWD}"
          return 0
       ;;
 
f543b0c7
       run)
          . mulle-bootstrap-paths.sh
 
          run_main "$@" || exit 1
       ;;
 
9cc4ab74
       setting|settings)
4805e856
          . mulle-bootstrap-settings.sh
a3018cdd
 
4805e856
          setting_main "$@" || exit 1
eecd842e
       ;;
40fe269d
 
8f951e19
       systeminstall)
96879641
          . mulle-bootstrap-systeminstall.sh
8f951e19
 
96879641
          systeminstall_main "$@" || exit 1
8f951e19
       ;;
 
e5b54e85
       show)
db28bb90
          [ -z "${MULLE_BOOTSTRAP_SHOW_SH}" ] && . mulle-bootstrap-show.sh
e5b54e85
 
          show_main "$@" || exit 1
       ;;
 
4805e856
       status)
          . mulle-bootstrap-status.sh
 
0fc9abbe
          local rval
 
          status_main "$@"
          rval="$?"
 
          [ "$rval" -eq 0 ] || exit $rval
4805e856
       ;;
 
40fe269d
       tag)
f36a470f
          . mulle-bootstrap-tag.sh
a3018cdd
 
3c4acfba
          tag_main "$@" || exit 1
eecd842e
       ;;
40fe269d
 
402c4cb7
       type)
          if is_minion_bootstrap_project
          then
             echo "Minion"
          else
             if is_master_bootstrap_project
             then
                echo "Master"
             else
                echo "Freeman"
             fi
          fi
       ;;
 
8f951e19
       uname)
          echo "${UNAME}"
          exit 0
108c932f
       ;;
 
4805e856
       update)
          . mulle-bootstrap-fetch.sh
 
          update_main "$@" || exit 1
       ;;
 
       upgrade)
          . mulle-bootstrap-fetch.sh
 
          upgrade_main "$@" || exit 1
       ;;
 
fa860fc9
       version)
0fc9abbe
          echo "${MULLE_EXECUTABLE_VERSION}"
70f9762c
          return 0
eecd842e
       ;;
fa860fc9
 
4805e856
       xcode|setup-xcode)
          . mulle-bootstrap-xcode.sh
 
f67f6857
          MULLE_EXECUTABLE_FAIL_PREFIX="mulle-bootstrap xcode"
4805e856
          xcode_main "$@" || exit 1
       ;;
 
40fe269d
       *)
f67f6857
          log_error "${MULLE_EXECUTABLE_FAIL_PREFIX}: Unknown command \"${command}\""
4805e856
          mulle_bootstrap_usage
eecd842e
       ;;
f36a470f
    esac
ee17b9c7
    log_debug ":bootstrap_main done:"
f36a470f
 }
 
818b5aa7
 
fb1a33b8
 #
 # leading backslash ? looks like we're getting called from
 # mingw via a .BAT or so
 #
 case "$PATH" in
    '\\'*)
       PATH="`tr '\\' '/' <<< "${PATH}"`"
    ;;
 esac
818b5aa7
 
 #
 # service both names
 #
57935531
 MULLE_EXECUTABLE_PATH="$0"
 case "$MULLE_EXECUTABLE_PATH" in
    /*|~*)
    ;;
 
    *)
       MULLE_EXECUTABLE_PATH="$PWD/$MULLE_EXECUTABLE_PATH"
    ;;
 esac
 
 
0fc9abbe
 MULLE_EXECUTABLE="`basename -- "$0"`"
 MULLE_ARGUMENTS="$@"
c8c107a7
 MULLE_EXECUTABLE_ENV_PATH="$PATH"
0fc9abbe
 MULLE_EXECUTABLE_FAIL_PREFIX="${MULLE_EXECUTABLE}"
f67f6857
 MULLE_EXECUTABLE_PID="$$"
 export MULLE_EXECUTABLE_PID
4805e856
 
 
ab0f5bba
 
 
0b9e9e49
 bootstrap_init "$@" # needs params
818b5aa7
 
0fc9abbe
 
3ee7ef17
 main()
 {
0fc9abbe
    if ! bootstrap_main "$@"
    then
       # just do it again, but cd has been set differently
       main "$@"
       exit $?
    fi
3ee7ef17
 }
70f9762c
 
3ee7ef17
 main "$@"
70f9762c
 
3ee7ef17
 trap - TERM EXIT