mulle-bootstrap-xcode.sh
5de2fbd6
 #! /bin/sh
d7f96955
 #   Copyright (c) 2015 Nat! - Mulle kybernetiK
 #   All rights reserved.
5de2fbd6
 #
d7f96955
 #   Redistribution and use in source and binary forms, with or without
 #   modification, are permitted provided that the following conditions are met:
5de2fbd6
 #
d7f96955
 #   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
 #
 
5de2fbd6
 # this script patches the xcodeproj so that the headers and
 # lib files can be added in a sensible order
 #
8e817cc1
 
5de2fbd6
 . mulle-bootstrap-local-environment.sh
d388168a
 . mulle-bootstrap-brew.sh
5de2fbd6
 
2d8f68ea
 if [ "`uname`" != 'Darwin' ]
 then
    fail "for now xcode only works on OS X"
 fi
5de2fbd6
 
40fe269d
 usage()
 {
    cat <<EOF
422c21da
 xcode <add|remove> [xcodeproj]
40fe269d
 
    add      : add settings to Xcode project (default)
    remove   : remove settings from Xcode project
 EOF
 }
 
 
3be635de
 check_and_usage_and_help()
 {
b06853c1
 case "$COMMAND" in
    add)
    ;;
    remove)
    ;;
    *)
40fe269d
    usage >&2
b06853c1
    exit 1
    ;;
 esac
3be635de
 }
 
 
 COMMAND="${1:-add}"
2d8f68ea
 [ $# -eq 0 ] || shift
422c21da
 PROJECT="$1"
2d8f68ea
 [ $# -eq 0 ] || shift
422c21da
 
3be635de
 
 check_and_usage_and_help
 
5de2fbd6
 
 list_configurations()
 {
422c21da
    local project
 
    project="${1}"
5de2fbd6
   #
ac6ff55d
   # Figure out all configurations
5de2fbd6
   #
422c21da
    xcodebuild -list -project "${project}" 2> /dev/null | \
5de2fbd6
    grep -A100 'Build Configurations' | \
    grep -B100 'Schemes' | \
    egrep -v 'Configurations:|Schemes:' | \
    grep -v 'If no build' | \
8e817cc1
    sed 's/^[ \t]*\(.*\)/\1/' | \
    sed '/^$/d'
5de2fbd6
 }
 
 
 #
 # Figure out default configuration
 #
 list_default_configuration()
 {
    xcodebuild -list 2> /dev/null | grep 'If no build configuration' | sed 's/^.*\"\(.*\)\".*$/\1/g'
 }
 
 
d388168a
 check_for_mulle_xcode_settings()
5de2fbd6
 {
    local installed
 
    #
    # OK
    #
d388168a
    installed=`which mulle-xcode-settings`
5de2fbd6
    if [ "$installed" = "" ]
    then
d388168a
       user_say_yes "Need to install mulle-xcode-settings (via brew)
    Install mulle-xcode-settings now ?"
5de2fbd6
       [ $? -eq 0 ] || exit 1
 
7fdfcd11
       brew_update_if_needed "mulle-xcode-settings"
5de2fbd6
 
7fdfcd11
       log_info "Tapping \"mulle-kybernetik/software\""
d388168a
       brew tap "mulle-kybernetik/software"
5de2fbd6
 
d388168a
       log_info "Installing mulle-xcode-settings"
       brew install "mulle-xcode-settings" || fail "failed to install \"mulle-xcode-settings\""
5de2fbd6
    fi
 }
 
 
84a99cf5
 map_configuration()
b06853c1
 {
8e817cc1
    local xcode_configuration
    local configurations
ac6ff55d
    local default
84a99cf5
 
    configurations="$1"
    xcode_configuration="$2"
ac6ff55d
    default="$3"
84a99cf5
 
ac6ff55d
    local mapped
    local i
8e817cc1
    local old
 
ac6ff55d
    mapped=""
 
8e817cc1
    old="${IFS:-" "}"
    IFS="
 "
84a99cf5
    for i in ${configurations}
    do
       if [ "$i" = "$xcode_configuration" ]
       then
          mapped="${xcode_configuration}"
       fi
    done
8e817cc1
    IFS="${old}"
84a99cf5
 
    if [ "$mapped" = "" ]
    then
    case i in
       *ebug*)
          mapped="Debug"
          ;;
       *rofile*)
          mapped="Release"
          ;;
       *eleas*)
          mapped="Release"
          ;;
       *)
          mapped="${default}"
          ;;
    esac
    fi
    echo "${mapped}"
 }
 
 
 patch_library_configurations()
 {
    local xcode_configurations
    local configurations
b06853c1
    local i
    local mapped
ac6ff55d
    local default
b06853c1
 
    xcode_configurations="$1"
84a99cf5
    configurations="$2"
    project="$3"
ac6ff55d
    default="$4"
    flag="$5"
b06853c1
 
8e817cc1
    local old
 
    old="${IFS:-" "}"
    IFS="
 "
b06853c1
    for i in ${xcode_configurations}
    do
ac6ff55d
       mapped=`map_configuration "${configurations}" "${i}" "${default}"`
d388168a
       exekutor mulle-xcode-settings -configuration "${i}" "${flag}" "LIBRARY_CONFIGURATION" "${mapped}" "${project}" || exit 1
b06853c1
    done
8e817cc1
    IFS="${old}"
b06853c1
 }
 
 
5de2fbd6
 patch_xcode_project()
 {
    local name
    local project
    local mapped
    local configurations
    local xcode_configurations
422c21da
    local terse
 
 
    read_yes_no_config_setting "terse" "NO"
    terse=$?
5de2fbd6
 
a203984b
    name=`basename -- "${PWD}"`
422c21da
 
    if [ ! -z "${PROJECT}" ]
5de2fbd6
    then
422c21da
       [ -d "${PROJECT}" ] || fail "xcodeproj ${PROJECT} not found"
       project="${PROJECT}"
    else
    project=`find_xcodeproj "${name}"`
       if [ "${project}" = "" ]
       then
          fail "no xcodeproj found"
       fi
5de2fbd6
    fi
 
a203984b
    projectname="`basename -- "${project}"`"
5de2fbd6
 
8e817cc1
    # mod_pbxproj can only do Debug/Release/All...
 
d388168a
    check_for_mulle_xcode_settings
5de2fbd6
 
c6e7156e
    configurations=`read_build_root_setting "configurations" "Debug
5de2fbd6
 Release"`
 
    #
    # Add LIBRARY_CONFIGURATION mapping
    #
    xcode_configurations=`list_configurations "${project}"`
    if [ "$xcode_configurations" = "" ]
    then
       xcode_configurations="Debug
 Release"
    fi
 
b06853c1
    local flag
5de2fbd6
 
b06853c1
    if [ "$COMMAND" = "add" ]
    then
d388168a
       flag="add"
422c21da
 
       if [ $terse -ne 0 ]
       then
3bbc5caf
          #         012345678901234567890123456789012345678901234567890123456789
          log_info "Settings will be added to ${C_MAGENTA}${projectname}${C_RESET}."
          log_info "In the long term it may be more useful to copy/paste the "
          log_info "following lines into a set of local .xcconfig file, that is "
          log_info "inherited by all configurations."
422c21da
       fi
b06853c1
    else
d388168a
       flag="remove"
422c21da
 
       if [ $terse -ne 0 ]
       then
3bbc5caf
          #         012345678901234567890123456789012345678901234567890123456789
          log_info "Settings will be removed from ${projectname}."
          log_info "You may want to check afterwards, that this has worked out"
          log_info "OK :)."
422c21da
       fi
b06853c1
    fi
5de2fbd6
 
    local dependencies_dir
    local header_search_paths
    local library_search_paths
    local framework_search_paths
 
c6e7156e
    #  figure out a way to make this nicer
    local absolute
8d41d7c7
    local absolute2
c6e7156e
    local relative_subdir
 
8d41d7c7
    absolute="`realpath "${project}"`"
a203984b
    absolute="`dirname -- "${absolute}"`"
8d41d7c7
    absolute2="`pwd -P`/${DEPENDENCY_SUBDIR}"
    relative_subdir="`relative_path_between "${absolute2}" "${absolute}" `"
c6e7156e
 
8d41d7c7
    dependencies_dir='$(PROJECT_DIR)/'"${relative_subdir}"
5de2fbd6
 
3c8ec4d2
    header_search_paths="\$(DEPENDENCIES_DIR)/${HEADER_DIR_NAME}"
5de2fbd6
    header_search_paths="${header_search_paths} /usr/local/include"
b06853c1
    header_search_paths="${header_search_paths} \$(inherited)"
5de2fbd6
 
ac6ff55d
    local default
 
    default=`echo "${configurations}" | tail -1 | sed 's/^[ \t]*//;s/[ \t]*$//'`
 
3c8ec4d2
    library_search_paths="\$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/\$(LIBRARY_CONFIGURATION)\$(EFFECTIVE_PLATFORM_NAME)"
    library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/\$(LIBRARY_CONFIGURATION)"
    library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/${default}\$(EFFECTIVE_PLATFORM_NAME)"
    library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}/${default}"
    library_search_paths="${library_search_paths} \$(DEPENDENCIES_DIR)/${LIBRARY_DIR_NAME}"
5de2fbd6
    library_search_paths="${library_search_paths} /usr/local/lib"
b06853c1
    library_search_paths="${library_search_paths} \$(inherited)"
5de2fbd6
 
 
3c8ec4d2
    framework_search_paths="\$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/\$(LIBRARY_CONFIGURATION)\$(EFFECTIVE_PLATFORM_NAME)"
    framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/\$(LIBRARY_CONFIGURATION)"
    framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/${default}\$(EFFECTIVE_PLATFORM_NAME)"
    framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}/${default}"
    framework_search_paths="${framework_search_paths} \$(DEPENDENCIES_DIR)/${FRAMEWORK_DIR_NAME}"
b06853c1
    framework_search_paths="${framework_search_paths} \$(inherited)"
5de2fbd6
 
b06853c1
    local query
 
    if [ "$COMMAND" = "add" ]
    then
422c21da
       if [ $terse -ne 0 ]
       then
          local mapped
          local i
84a99cf5
 
3bbc5caf
          printf  "${C_RESET_BOLD}-----------------------------------------------------------\n${C_RESET}" >&2
84a99cf5
 
422c21da
          #  make these echos easily grabable by stdout
          #     012345678901234567890123456789012345678901234567890123456789
3bbc5caf
          printf "${C_RESET_BOLD}Common.xcconfig:${C_RESET}\n"
          printf "${C_RESET_BOLD}-----------------------------------------------------------\n${C_RESET}" >&2
422c21da
          echo "DEPENDENCIES_DIR=${dependencies_dir}"
          echo "HEADER_SEARCH_PATHS=${header_search_paths}"
          echo "LIBRARY_SEARCH_PATHS=${library_search_paths}"
          echo "FRAMEWORK_SEARCH_PATHS=${framework_search_paths}"
3bbc5caf
          printf  "${C_RESET_BOLD}-----------------------------------------------------------\n${C_RESET}" >&2
84a99cf5
 
422c21da
          local old
8e817cc1
 
422c21da
          old="${IFS:-" "}"
          IFS="
8e817cc1
 "
422c21da
          for i in ${xcode_configurations}
          do
             mapped=`map_configuration "${configurations}" "${i}"`
 
             #     012345678901234567890123456789012345678901234567890123456789
3bbc5caf
             printf "${C_RESET_BOLD}${i}.xcconfig:${C_RESET}\n"
             printf "${C_RESET_BOLD}-----------------------------------------------------------\n${C_RESET}" >&2
422c21da
             echo "#include \"Common.xcconfig\""
3bbc5caf
             echo ""
422c21da
             echo "LIBRARY_CONFIGURATION=${mapped}"
3bbc5caf
             printf  "${C_RESET_BOLD}-----------------------------------------------------------\n${C_RESET}" >&2
422c21da
          done
 
          IFS="${old}"
       fi
84a99cf5
 
1b26e970
       query="Add ${C_CYAN}${DEPENDENCY_SUBDIR}/${LIBRARY_DIR_NAME}${C_MAGENTA} and friends to search paths of ${C_MAGENTA}${projectname}${C_YELLOW} ?"
b06853c1
    else
1b26e970
       query="Remove ${C_CYAN}${DEPENDENCY_SUBDIR}/${LIBRARY_DIR_NAME}${C_MAGENTA} and friends from search paths of ${C_MAGENTA}${projectname}${C_YELLOW} ?"
b06853c1
    fi
 
    user_say_yes "$query"
    [ $? -eq 0 ] || exit 1
 
 
ac6ff55d
    patch_library_configurations "${xcode_configurations}" "${configurations}" "${project}" "${default}" "${flag}"
b06853c1
 
d388168a
    exekutor mulle-xcode-settings "${flag}" "DEPENDENCIES_DIR" "${dependencies_dir}" "${project}"  || exit 1
    exekutor mulle-xcode-settings "${flag}" "HEADER_SEARCH_PATHS" "${header_search_paths}" "${project}"  || exit 1
    exekutor mulle-xcode-settings "${flag}" "LIBRARY_SEARCH_PATHS" "${library_search_paths}" "${project}"  || exit 1
    exekutor mulle-xcode-settings "${flag}" "FRAMEWORK_SEARCH_PATHS" "${framework_search_paths}" "${project}" || exit 1
b06853c1
 
 
    if [ "$COMMAND" = "add" ]
    then
422c21da
       if [ $terse -ne 0 ]
       then
          #     012345678901234567890123456789012345678901234567890123456789
3bbc5caf
          printf "${C_RESET_BOLD}${C_CYAN}\n" >&2
          echo "Hint:" >&2
          echo "If you add a configuration to your project, remember to" >&2
          echo "edit the ${C_RESET_BOLD}LIBRARY_CONFIGURATION${C_CYAN} setting for that" >&2
          echo "configuration." >&2
          echo "You can rerun \"mulle-bootstrap xcode add\" at later times" >&2
          echo "and it should not unduly duplicate setting contents." >&2
          printf "\n${C_RESET}" >&2
422c21da
       fi
b06853c1
    fi
5de2fbd6
 }
 
422c21da
 
5de2fbd6
 main()
 {
3c8ec4d2
    log_fluff "::: xcode :::"
40fe269d
 
    patch_xcode_project "$@"
5de2fbd6
 }
 
 
40fe269d
 main "$@"