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.
0fc9abbe
 MULLE_EXECUTABLE_VERSION_MAJOR=3
cbad10ec
 MULLE_EXECUTABLE_VERSION_MINOR=2
4a9f82b9
 MULLE_EXECUTABLE_VERSION_PATCH=3
5de2fbd6
 
0fc9abbe
 MULLE_EXECUTABLE_VERSION="${MULLE_EXECUTABLE_VERSION_MAJOR}.${MULLE_EXECUTABLE_VERSION_MINOR}.${MULLE_EXECUTABLE_VERSION_PATCH}"
5de2fbd6
 
 #
 # This is the main user interface to mulle-bootstrap
 # sorta like git
 #
d2100287
 
8e31b74a
 trap_fail()
 {
    exit 1
 }
 
 
818b5aa7
 
 mulle_bootstrap_usage()
 {
    cat <<EOF
 usage: mulle-bootstrap [flags] [command] [options]
  Flags:
    -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
 
5c06c0e8
  Commands:
8f951e19
    bootstrap     : does install and build recursively [default]
    build         : builds fetched repositories
    clean         : cleans mulle-bootstrap produced files.
0b9e9e49
    defer         : join a master mulle-bootstrap project
    emancipate    : emancipate from a master mulle-bootstrap project
4d45dff2
    paths         : get include and library paths
e5b54e85
    init          : initializes a bootstrap project
8f951e19
    update        : updates repositories (fetch).
    upgrade       : updates and checks out repositories (pull).
e5b54e85
    show          : show repositories and brews
5447bf9a
 
  Options are command specific. Use mulle-bootstrap <command> -h for help.
2d8f68ea
 EOF
 
8f77be37
    if [ "${UNAME}" = 'darwin' ]
2d8f68ea
    then
       cat <<EOF
e5b54e85
    xcode         : sets up xcodeproj settings
 EOF
    fi
 
    if [ !  -z "${MULLE_TRACE}" ]
    then
       cat <<EOF
 
    systeminstall : install dependencies as system headers
    git           : run git commands on fetched repositories
    status        : show status of repositories and brews
    tag           : tag fetched repositories
2d8f68ea
 EOF
    fi
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"
5ec25abc
       build_main "$@" || exit 1
f1f83418
    else
       log_verbose "No build needed"
5ec25abc
    fi
a0247021
 
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"
          ;;
       *)
          echo "$1/$2"
          ;;
    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
 
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
 
    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
f04bc0b7
       echo "Fatal Error: Could not find libexec for mulle-bootstrap" >&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
       ;;
    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
 
4805e856
    # source_environment
818b5aa7
 }
1c1494ca
 
 
818b5aa7
 bootstrap_main()
 {
    local command
    local ps4string
83ce7c54
 
ea74a237
    local MULLE_FLAG_ANSWER="ASK"
550b5448
    local MULLE_FLAG_MAGNUM_FORCE="NO"
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"
    local MULLE_FLAG_MERGE_LOG="NO"
    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"
          ;;
 
818b5aa7
          -f|--force-fetch)
550b5448
             MULLE_FLAG_MAGNUM_FORCE="YES"
1c1494ca
          ;;
 
db28bb90
          --ignore-graveyard)
f67f6857
             MULLE_FLAG_IGNORE_GRAVEYARD="YES"
1c1494ca
          ;;
 
8f77be37
          -h|--help)
818b5aa7
             mulle_bootstrap_usage
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
          ;;
 
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
 
550b5448
    if [ "${MULLE_FLAG_MAGNUM_FORCE}" = "YES" ]
151c6f06
    then
       set_fetch_needed
       set_build_needed
    fi
 
4d45dff2
    case "${command}" in
3466e2d3
       help|init|uname)
4d45dff2
       ;;
 
       *)
          local  orgpwd
 
          orgpwd="$PWD"
 
          while ! is_bootstrap_project
          do
             local old
 
             old="$PWD"
             cd ..
 
             if [ "$PWD" = "${old}" ]
             then
                fail "There is no ${BOOTSTRAP_DIR} or ${BOOTSTRAP_DIR}.local folder here ($orgpwd), can't continue"
             fi
          done
       ;;
    esac
 
    if bootstrap_should_defer_to_master "$@"
28ed6b30
    then
4d45dff2
       return 1
    fi
 
    if [ "${MULLE_FLAG_MAGNUM_FORCE}" = "NO" ]
    then
       case "${command}" in
cbad10ec
          clean|config|dist-clean|expansion|init|status|show|paths|setting|uname)
bba581f8
          ;;
 
          *)
4d45dff2
             bootstrap_ensure_consistency
bba581f8
          ;;
7a4ae0c8
       esac
c164fc7e
    fi
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
       ;;
 
       config)
          . 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
       ;;
 
e5b54e85
       expansion)
          . mulle-bootstrap-settings.sh
 
          expansion_main "$@" || exit 1
       ;;
 
4d45dff2
       paths)
          . 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)
          mulle_bootstrap_usage "$@" || exit 1
       ;;
 
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
       ;;
 
4805e856
       setting)
          . mulle-bootstrap-settings.sh
a3018cdd
 
4805e856
          setting_main "$@" || exit 1
eecd842e
       ;;
40fe269d
 
8f951e19
       systeminstall)
          . mulle-bootstrap-install.sh
 
          install_main "$@" || exit 1
       ;;
 
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
 
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
 }
 
818b5aa7
 
 
 #
 # service both names
 #
0fc9abbe
 MULLE_EXECUTABLE="`basename -- "$0"`"
 MULLE_ARGUMENTS="$@"
 MULLE_EXECUTABLE_FAIL_PREFIX="${MULLE_EXECUTABLE}"
f67f6857
 MULLE_EXECUTABLE_PID="$$"
 export MULLE_EXECUTABLE_PID
4805e856
 
 
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