#! /usr/bin/env bash # # Copyright (c) 2015-2017 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. # MULLE_EXECUTABLE_VERSION_MAJOR=3 MULLE_EXECUTABLE_VERSION_MINOR=8 MULLE_EXECUTABLE_VERSION_PATCH=1 MULLE_EXECUTABLE_VERSION="${MULLE_EXECUTABLE_VERSION_MAJOR}.${MULLE_EXECUTABLE_VERSION_MINOR}.${MULLE_EXECUTABLE_VERSION_PATCH}" # # This is the main user interface to mulle-bootstrap # sorta like git # trap_fail() { exit 1 } 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 run : run command with proper dependencies PATHs setting : read or edit build settings status : show status of repositories and brews systeminstall : install dependencies as system libraries/headers 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 } mulle_bootstrap_usage() { local verbose="${1:-NO}" cat <<EOF Usage: ${MULLE_BOOTSTAP_EXECUTABLE} [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 --no-defer: do not defer to master, if project is a minion -v : -v to be more verbose (-vv or -vvv for more verbosity) -V : verbose build -DKEY=VAL : define local expansion key/value C style EOF bootstrap_technical_option_usage cat <<EOF Commands: EOF print_commands "${verbose}" | sort if [ "${verbose}" = "NO" ] then cat <<EOF (use mulle-bootstrap -v help to show more commands) EOF fi cat <<EOF Options are command specific. Use mulle-bootstrap <command> -h for help. EOF exit 1 } _bootstrap_main() { local command log_debug "::: bootstrap begin :::" . mulle-bootstrap-fetch.sh . mulle-bootstrap-build.sh . mulle-bootstrap-warn-scripts.sh # used for option handling only MULLE_BOOTSTRAP_WILL_BUILD="YES" warn_scripts_main "${BOOTSTRAP_DIR}" || exit 1 if fetch_needed then MULLE_EXECUTABLE_FAIL_PREFIX="mulle-bootstrap fetch" fetch_main "$@" || exit 1 # used for option handling only MULLE_BOOTSTRAP_DID_FETCH="YES" else log_verbose "No fetch needed" fi if build_needed then MULLE_EXECUTABLE_FAIL_PREFIX="mulle-bootstrap build" build_main "$@" || exit 1 else log_verbose "No build needed" fi log_debug "::: bootstrap end :::" } # # 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 } bootstrap_libexec_path() { local path="$1" local exedir local exedirpath local prefix local libexecpath path="`resolve_symlinks "${path}"`" exedirpath="`dirname "${path}"`" prefix="`dirname "${exedirpath}"`" libexecpath="${prefix}/libexec/mulle-bootstrap" if [ ! -x "${libexecpath}/mulle-bootstrap-functions.sh" ] then libexecpath="${exedirpath}/src" fi if [ -x "${libexecpath}/mulle-bootstrap-functions.sh" ] then echo "${libexecpath}" fi } bootstrap_init() { local libexecpath libexecpath="`bootstrap_libexec_path "$0"`" if [ -z "${libexecpath}" ] then echo "Fatal Error: Could not find libexec for ${MULLE_EXECUTABLE}" >&2 exit 1 fi PATH="${libexecpath}:$PATH" export PATH if [ ! -z "${MULLE_BOOTSTRAP_LIBEXEC_TRACE}" ] then echo "PATH=$PATH" >&2 fi # # shell export commands with minimal # trap setup # case "${1}" in library-path) echo "${libexecpath}" exit 0 ;; version) echo "${MULLE_EXECUTABLE_VERSION}" exit 0 ;; esac # set -e # more pain then gain in the end # set -u # doesn't work with my style # now include this first to get # logging and UNAME . mulle-bootstrap-logging.sh . mulle-bootstrap-local-environment.sh || fail "not loaded" trap trap_fail INT # source_environment } 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 } bootstrap_main() { local command local ps4string local MULLE_FLAG_ANSWER="ASK" local MULLE_FLAG_MAGNUM_FORCE="NONE" local MULLE_FLAG_IGNORE_GRAVEYARD="NO" local MULLE_FLAG_VERBOSE_BUILD="NO" # technical flags local MULLE_FLAG_DONT_DEFER="NO" local MULLE_FLAG_EXEKUTOR_DRY_RUN="NO" local MULLE_FLAG_FOLLOW_SYMLINKS="YES" local MULLE_FLAG_LOG_CACHE="NO" local MULLE_FLAG_LOG_DEBUG="NO" local MULLE_FLAG_LOG_EXEKUTOR="NO" 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_LOG_MERGE="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" # # simple option handling # while [ $# -ne 0 ] do if bootstrap_technical_flags "$1" then shift continue fi case "$1" in -a|--prefer-origin) MULLE_FLAG_ANSWER="NO" ;; -y|--prefer-local) MULLE_FLAG_ANSWER="YES" ;; --no-defer) MULLE_FLAG_DONT_DEFER="YES" ;; # used persistently throughout so it's global --follow-symlinks) MULLE_FLAG_FOLLOW_SYMLINKS="YES" ;; -f|--force) MULLE_FLAG_MAGNUM_FORCE="BOTH" ;; --ignore-graveyard) MULLE_FLAG_IGNORE_GRAVEYARD="YES" ;; -h|--help) mulle_bootstrap_usage "${MULLE_TRACE}" ;; -D*) # just like C # define key values (by putting them into .bootstrap.local) bootstrap_define_expansion "`echo "$1" | sed s'/^-D[ ]*//'`" ;; -V|--verbose-build) MULLE_FLAG_VERBOSE_BUILD="YES" ;; --version) echo "${MULLE_EXECUTABLE_VERSION}" exit 0 ;; -*) log_error "${MULLE_EXECUTABLE_FAIL_PREFIX}: Unknown option \"$1\"" mulle_bootstrap_usage ;; *) break ;; esac shift done bootstrap_setup_trace "${MULLE_TRACE}" # source in environment now local_environment_main # # some commands only run when we have a .bootstrap folder # 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) # command="${1:-bootstrap}" case "${command}" in help|init|uname) ;; project-path) if ! bootstrap_cd_projectpath then exit 1 fi echo "`pwd -P`" exit 0 ;; *) if ! bootstrap_cd_projectpath then fail "There is no ${BOOTSTRAP_DIR} or ${BOOTSTRAP_DIR}.local folder here ($orgpwd), can't continue" fi ;; esac if bootstrap_should_defer_to_master "$@" then return 1 fi # # some commands are only valid, if the fetch went through # defer/emancipate clean, so that's ok # 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 MULLE_EXECUTABLE_FAIL_PREFIX="${MULLE_EXECUTABLE} ${command}" [ $# -eq 0 ] || shift MULLE_EXECUTABLE_OPTIONS="$@" case "${command}" in bootstrap) _bootstrap_main "$@" ;; build) . mulle-bootstrap-build.sh build_main "$@" || exit 1 ;; clean) . mulle-bootstrap-clean.sh clean_main "$@" || exit 1 ;; config) . mulle-bootstrap-settings.sh config_main "$@" || exit 1 ;; defer) . mulle-bootstrap-defer.sh defer_main "$@" || exit 1 ;; dist) . mulle-bootstrap-clean.sh clean_main "dist" || exit 1 ;; emancipate) . mulle-bootstrap-defer.sh emancipate_main "$@" || exit 1 ;; expansion) . mulle-bootstrap-settings.sh expansion_main "$@" || exit 1 ;; paths) . mulle-bootstrap-paths.sh paths_main "$@" || exit 1 ;; git) . mulle-bootstrap-scm.sh git_main "$@" || exit 1 ;; help) mulle_bootstrap_usage "${MULLE_TRACE}" || exit 1 ;; init) . mulle-bootstrap-init.sh init_main "$@" || exit 1 ;; install|fetch) . mulle-bootstrap-fetch.sh DONT_ASK_AFTER_WARNING=YES fetch_main "$@" || exit 1 ;; library-path) echo "$PATH" | tr ':' '\012' | head -1 return 0 ;; run) . mulle-bootstrap-paths.sh run_main "$@" || exit 1 ;; setting) . mulle-bootstrap-settings.sh setting_main "$@" || exit 1 ;; systeminstall) . mulle-bootstrap-systeminstall.sh systeminstall_main "$@" || exit 1 ;; show) [ -z "${MULLE_BOOTSTRAP_SHOW_SH}" ] && . mulle-bootstrap-show.sh show_main "$@" || exit 1 ;; status) . mulle-bootstrap-status.sh local rval status_main "$@" rval="$?" [ "$rval" -eq 0 ] || exit $rval ;; tag) . mulle-bootstrap-tag.sh tag_main "$@" || exit 1 ;; type) if is_minion_bootstrap_project then echo "Minion" else if is_master_bootstrap_project then echo "Master" else echo "Freeman" fi fi ;; uname) echo "${UNAME}" exit 0 ;; update) . mulle-bootstrap-fetch.sh update_main "$@" || exit 1 ;; upgrade) . mulle-bootstrap-fetch.sh upgrade_main "$@" || exit 1 ;; version) echo "${MULLE_EXECUTABLE_VERSION}" return 0 ;; xcode|setup-xcode) . mulle-bootstrap-xcode.sh MULLE_EXECUTABLE_FAIL_PREFIX="mulle-bootstrap xcode" xcode_main "$@" || exit 1 ;; *) log_error "${MULLE_EXECUTABLE_FAIL_PREFIX}: Unknown command \"${command}\"" mulle_bootstrap_usage ;; esac } # # service both names # MULLE_EXECUTABLE="`basename -- "$0"`" MULLE_ARGUMENTS="$@" MULLE_EXECUTABLE_FAIL_PREFIX="${MULLE_EXECUTABLE}" MULLE_EXECUTABLE_PID="$$" export MULLE_EXECUTABLE_PID MULLE_EXECUTABLE_FUNCTIONS_MIN="3.5" MULLE_EXECUTABLE_FUNCTIONS_MAX="4" bootstrap_init "$@" # needs params main() { if ! bootstrap_main "$@" then # just do it again, but cd has been set differently main "$@" exit $? fi } main "$@" trap - TERM EXIT