Skip to content

Instantly share code, notes, and snippets.

@ctreffs
Created February 5, 2021 13:31
Show Gist options
  • Save ctreffs/a59688b1804c1c9b325f57efc851f75b to your computer and use it in GitHub Desktop.
Save ctreffs/a59688b1804c1c9b325f57efc851f75b to your computer and use it in GitHub Desktop.
Generate Swift & Objective-C Xcode config file from environment variables
#!/bin/sh
# generate-global-app-config.sh
# DPAG-DHL
#
# Created by Christian Treffs on 26.01.17.
#
# This is a script to aggregate all export constants into *.h/*.m and *.swift global configuration files.
# It allows access to Xcode build settings that are managed via *.xcconfig files or the build settings tab.
# A maintaned version may be found at https://gitlab.7p-group.com/snippets/6
#
# WARNING: Xcode Version < 8.3 contain a bug, where you need to restart Xcode in some cases
# for xcconfig files to take effect. See: http://stackoverflow.com/a/41845248/6043526
#
# ==== setup ====
# fail fast & fail uninizialized
set -eu
# the name of the global configuration file sans extension
CONFIG_FILE_NAME="GlobalAppConfiguration"
# paths to the files that are generated
CURRENT_CONFIG_FILE_OBJC_H="$SRCROOT/Paket/Config/$CONFIG_FILE_NAME.h"
CURRENT_CONFIG_FILE_OBJC_M="$SRCROOT/Paket/Config/$CONFIG_FILE_NAME.m"
CURRENT_CONFIG_FILE_SWIFT="$SRCROOT/Paket/Config/$CONFIG_FILE_NAME.swift"
# log file for build config
BUILD_LOG_DIR="$SRCROOT/build/log"
BUILD_LOG_FILE="$BUILD_LOG_DIR/build.config.log"
# current date and time
DATE_GENERATED="$(date +"%Y-%m-%d %T")"
# grep filter to preprocess 'export .*' for faulty lines
GREP_FILTER='^export [^_][A-Z_]\+=.\+$'
# pattern for sed to convert 'export .*' to objective-c .h and .m content
CONVERT_REGEX_OBJC_M='s/\(export \)\([^=]*\)\(=\)\(.*\)/NSString *const k\2 = @\4;/g'
#CONVERT_REGEX_OBJC_M='s/\(export \)\([^=]*\)\(=\)\(.*\)/#define k\2 @\4;/g'
CONVERT_REGEX_OBJC_H='s/\([^=]*\)\( \)\(=\).*$/extern \1;/g'
# pattern for sed to convert 'export .*' to swift content
CONVERT_REGEX_SWIFT='s/\(export \)\([^=]*\)\(=\)\(.*\)/ static let \2: String = \4/g'
# string to bool conversion sed pattern
CONVERT_STRING_YES_TO_BOOL_FALSE_OBJC='/\(NSString\)\(.*\)\(\@"YES"\)/ s/\(NSString \*\)\(.*\)\(\@"YES"\)/BOOL \2YES/'
CONVERT_STRING_NO_TO_BOOL_FALSE_OBJC='/\(NSString\)\(.*\)\(\@"NO"\)/ s/\(NSString \*\)\(.*\)\(\@"NO"\)/BOOL \2NO/'
CONVERT_STRING_YES_TO_BOOL_TRUE_SWIFT='/\(.*\)\(String = \)\("YES"\)$/ s/\(.*\)\(String = \)\("YES"\)$/\1Bool = true/'
CONVERT_STRING_NO_TO_BOOL_FALSE_SWIFT='/\(.*\)\(String = \)\("NO"\)$/ s/\(.*\)\(String = \)\("NO"\)$/\1Bool = false/'
# string escape resolve
RESOLVE_ESCAPED_STRINGS='s/\([^\\]\)\\ /\1 /g'
RESOLVE_ESCAPED_STRINGS_SINGLE_DOUBLE_BACKSLASH='s/\(.*[^\\\"]\)\\\([^\\\"]\)/\1\\\\\2/g'
APPCODE_FIX='s/\(.*static let PROMPT_COMMAND: String = .*\)/\/\/ \1/g'
CI_REMOVER='s/\(.*static let CI_[A-Z_]*: String = .*\)/\/\/ \1/g'
CI_REMOVER_OBJC_M='s/\(.*NSString \*const kCI_[A-Z_]* = .*\)/\/\/ \1/g'
LCM_REMOVER='s/\(.*static let LCM_[A-Z_]*: String = .*\)/\/\/ \1/g'
LCM_REMOVER_OBJC_M='s/\(.*NSString \*const kLCM_[A-Z_]* = .*\)/\/\/ \1/g'
UNTERMINATED_REMOVER='s/\(.*static let [A-Z_]*: String = "$\)/\/\/ \1/g'
UNTERMINATED_REMOVER_OBJC_M='s/\(.*NSString \*const k[A-Z_]* = @";$\)/\/\/ \1/g'
COMMENT_REMOVER_OBJC_H='s/extern \/\/ \(.*\)/\/\/ extern \1/g'
# ==== processing ====
# remove previously generated config files
rm -f $CURRENT_CONFIG_FILE_OBJC_H $CURRENT_CONFIG_FILE_OBJC_M $CURRENT_CONFIG_FILE_SWIFT
# extract information and convert it to content variables
CONTENT_OBJC_M=$(export | grep -o "$GREP_FILTER" | sed "$CONVERT_REGEX_OBJC_M" | sed "$CI_REMOVER_OBJC_M" | sed "$UNTERMINATED_REMOVER_OBJC_M" | sed "$LCM_REMOVER_OBJC_M" | sed "$CONVERT_STRING_YES_TO_BOOL_FALSE_OBJC" | sed "$CONVERT_STRING_NO_TO_BOOL_FALSE_OBJC")
CONTENT_OBJC_H=$(echo "$CONTENT_OBJC_M" | sed "$CONVERT_REGEX_OBJC_H" | sed "$COMMENT_REMOVER_OBJC_H")
CONTENT_SWIFT=$(export | grep -o "$GREP_FILTER" | sed "$CONVERT_REGEX_SWIFT" | sed "$CONVERT_STRING_YES_TO_BOOL_TRUE_SWIFT" | sed "$CONVERT_STRING_NO_TO_BOOL_FALSE_SWIFT")
# assemble file header, first-, last-line and footer
FILE_HEADER="// THIS IS AN AUTOMATICALLY GENERATED CONFIGURATION FILE.\n// ANY CHANGES APPLIED TO THIS FILE WILL BE RESET WITH THE NEXT BUILD ACTION.\n//\n// CONFIGURATION:\t$CONFIGURATION\n// GENERATED BY:\t$USER\n// DATE:\t\t\t$DATE_GENERATED\n"
FILE_FIRST_LINE='#import <Foundation/Foundation.h>\n'
FILE_LAST_LINE=""
FILE_FOOTER=""
# output - objective-c config file .h
echo "$FILE_HEADER\n$FILE_FIRST_LINE\n$CONTENT_OBJC_H\n$FILE_LAST_LINE\n$FILE_FOOTER" > $CURRENT_CONFIG_FILE_OBJC_H
# output - objective-c config file .m
FILE_FIRST_LINE="#import \"$CONFIG_FILE_NAME.h\"\n"
echo "$FILE_HEADER\n$FILE_FIRST_LINE\n$CONTENT_OBJC_M\n$FILE_LAST_LINE\n$FILE_FOOTER" | sed "$RESOLVE_ESCAPED_STRINGS" | sed "$RESOLVE_ESCAPED_STRINGS_SINGLE_DOUBLE_BACKSLASH" > $CURRENT_CONFIG_FILE_OBJC_M
# output - swift config file .swift
FILE_FIRST_LINE="struct $CONFIG_FILE_NAME {"
FILE_LAST_LINE="}"
echo "$FILE_HEADER\n$FILE_FIRST_LINE\n$CONTENT_SWIFT\n$FILE_LAST_LINE\n$FILE_FOOTER" | sed "$APPCODE_FIX" | sed "$CI_REMOVER" | sed "$UNTERMINATED_REMOVER" | sed "$LCM_REMOVER" | sed "$RESOLVE_ESCAPED_STRINGS" | sed "$RESOLVE_ESCAPED_STRINGS_SINGLE_DOUBLE_BACKSLASH" > $CURRENT_CONFIG_FILE_SWIFT
# log build config essentials to file
mkdir -p "${BUILD_LOG_DIR}"
rm -f "${BUILD_LOG_FILE}"
touch "${BUILD_LOG_FILE}"
echo "DATE_GENERATED: ${DATE_GENERATED}" >> "${BUILD_LOG_FILE}"
echo "CONFIGURATION: ${CONFIGURATION}" >> "${BUILD_LOG_FILE}"
echo "PRODUCT_NAME: ${PRODUCT_NAME}" >> "${BUILD_LOG_FILE}"
echo "PRODUCT_BUNDLE_IDENTIFIER: ${PRODUCT_BUNDLE_IDENTIFIER}" >> "${BUILD_LOG_FILE}"
echo "OTHER_SWIFT_FLAGS: ${OTHER_SWIFT_FLAGS}" >> "${BUILD_LOG_FILE}"
echo "GCC_PREPROCESSOR_DEFINITIONS: ${GCC_PREPROCESSOR_DEFINITIONS}" >> "${BUILD_LOG_FILE}"
# terminal notification
## note: a 'bug' prevents notification to be shown when -sender com.apple.dt.Xcode is added; -activate 'com.apple.dt.Xcode' -sender 'com.apple.dt.Xcode'
terminal-notifier -timeout 4 -title "Xcode: global app config ${CONFIGURATION}" -subtitle "${PRODUCT_NAME} | ${CONFIGURATION}" -message "${PRODUCT_BUNDLE_IDENTIFIER} | ${DATE_GENERATED}" -group ${CONFIGURATION} -contentImage $SRCROOT/Paket/Resources/AppIcons.xcassets/$ASSETCATALOG_COMPILER_APPICON_NAME.appiconset/[email protected]
# apple script notification
# osascript -e 'display notification "'"${CONFIGURATION}"' | '"${DATE_GENERATED}"' \n'"${PRODUCT_BUNDLE_IDENTIFIER}"' | '"${PRODUCT_NAME}"'" with title "Xcode: global app config ['"${CONFIGURATION}"']"'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment