# https://github.com/jcampbell05/xcake
# http://www.rubydoc.info/github/jcampbell05/xcake/master/file/docs/Cakefile.md

# this is a sample Cakefile for a fictional project that is called "CakeMania"

#===

# just helper variables to use these values in a consistent way across whole file

iOSdeploymentTarget = "8.0"
currentSwiftVersion = "4.2"
companyIdentifier = "com.CakeMania"
developmentTeamId = "XYZXYZ" # for automatic debug signing in Xcode 8
testSuffix = "Tst"
testSuffixUI = "UI" + testSuffix

provProfAdHoc = "XXX"
provProfAppStore = "YYY"

#=== 3d-party integration keys (global variables)

# The values below will be used to set "user-defined" build settings
# for build configurations on target level,
# so we can reuse the same, lets say, "test" FB key
# within several "test" configurations (for example, the same test key
# would be used for "Debug" and "Staging" configurations), and can easily
# see what is the value/key we use for testing and production,
# and even update it in future if needed.

# "FACEBOOK_KEY"

facebookProdKey = "888888888888888"
facebookTestKey = "999999999999999"

#===

# lets define high level project settings

project.name = "CakeMania"
project.class_prefix = "CMN"
project.organization = "CakeMania Inc."

#===

# Below we explicitly define the list of project build configurations.
# If you do not define it explicitly, Xcake will implicitly define default ones,
# that are equivalent to this:
#
# project.debug_configuration :Debug
# project.release_configuration :Release
#

project.debug_configuration :Debug # for local development/debugging only, pointing to "test.*" API server
project.release_configuration :Staging # for alpha and beta AdHoc builds, pointing to "test.*" API server
project.release_configuration :RC # for release candidate AdHoc builds, pointing to "rc.*" API server
project.release_configuration :Production # for App Store ready AdHoc builds, pointing to "www." API server
project.release_configuration :AppStore # for App Store builds, pointing to "www." API server

# Note, that Xcake will also automatically create set of project "Schemes" -
# one for each build configuration, their names will be constructed from 
# project name and configuration name, separated by dash, like this:
#
# "<project_name>-<configuration_name>"
#
# NOTE: every scheme will have the same build configiuration
# for all phases (Run, Test, Profile, Archive). If you need different build configurations
# based on phase - lets say one configuration for Run, but different one for Archive -
# consider to have different build configurations (and as result - build shemes) for these purposes
# (as proposed in this sample file).
#
# For this example, shemes will be:
#
# "CakeMania-Debug"
# "CakeMania-Staging"
# "CakeMania-RC"
# "CakeMania-Production"
# "CakeMania-AppStore"

#=== DEFAULT target settings

# Below we define "project level" build configurations.
# REMEMBER this entiire file is just an interpretable script,
# and the structure below is just a loop.
# At every iteration we have reference to one
# of the build configurations defined above explicitly or implicitly.

# In this case, we set the same build settings to each configuration,
# but, if we need to have some settings to be different for different
# configurations, then you can use "if" expression to set different build settings
# dependiong on "configuration.name" (we will see example of that in target settings below in this document).

project.all_configurations.each do |configuration|

    # the settings listed below are just a copy
    # of what Xcode sets explicitly in a newly created Xcode
    # project file in comparison with default values
    # (the values that are marked with bold font).

    configuration.settings["ENABLE_BITCODE"] = "YES"

    configuration.settings["SDKROOT"] = "iphoneos"
    configuration.settings["GCC_DYNAMIC_NO_PIC"] = "NO"
    configuration.settings["OTHER_CFLAGS"] = "$(inherited) -DNS_BLOCK_ASSERTIONS=1"
    configuration.settings["GCC_C_LANGUAGE_STANDARD"] = "gnu99"
    configuration.settings["CLANG_ENABLE_MODULES"] = "YES"
    configuration.settings["CLANG_ENABLE_OBJC_ARC"] = "YES"
    configuration.settings["ENABLE_NS_ASSERTIONS"] = "NO"
    configuration.settings["ENABLE_STRICT_OBJC_MSGSEND"] = "YES"
    configuration.settings["CLANG_WARN_EMPTY_BODY"] = "YES"
    configuration.settings["CLANG_WARN_BOOL_CONVERSION"] = "YES"
    configuration.settings["CLANG_WARN_CONSTANT_CONVERSION"] = "YES"
    configuration.settings["GCC_WARN_64_TO_32_BIT_CONVERSION"] = "YES"
    configuration.settings["CLANG_WARN_INT_CONVERSION"] = "YES"
    configuration.settings["GCC_WARN_ABOUT_RETURN_TYPE"] = "YES_ERROR"
    configuration.settings["GCC_WARN_UNINITIALIZED_AUTOS"] = "YES_AGGRESSIVE"
    configuration.settings["CLANG_WARN_UNREACHABLE_CODE"] = "YES"
    configuration.settings["GCC_WARN_UNUSED_FUNCTION"] = "YES"
    configuration.settings["GCC_WARN_UNUSED_VARIABLE"] = "YES"
    configuration.settings["CLANG_WARN_DIRECT_OBJC_ISA_USAGE"] = "YES_ERROR"
    configuration.settings["CLANG_WARN__DUPLICATE_METHOD_MATCH"] = "YES"
    configuration.settings["GCC_WARN_UNDECLARED_SELECTOR"] = "YES"
    configuration.settings["CLANG_WARN_OBJC_ROOT_CLASS"] = "YES_ERROR"

    configuration.settings["CURRENT_PROJECT_VERSION"] = "1" # just default non-empty value

    configuration.settings["DEFINES_MODULE"] = "YES" # http://stackoverflow.com/a/27251979

    configuration.settings["SWIFT_OPTIMIZATION_LEVEL"] = "-Onone"

    configuration.settings["CLANG_WARN_INFINITE_RECURSION"] = "YES" # Xcode 8
    configuration.settings["CLANG_WARN_SUSPICIOUS_MOVE"] = "YES" # Xcode 8
    configuration.settings["ENABLE_STRICT_OBJC_MSGSEND"] = "YES" # Xcode 8
    configuration.settings["GCC_NO_COMMON_BLOCKS"] = "YES"
    configuration.settings["ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES"] = "$(inherited)" # "YES"

    configuration.settings["SWIFT_VERSION"] = currentSwiftVersion

    #===

    if configuration.name == "RC" || configuration.name == "AppStore"

        configuration.settings["DEBUG_INFORMATION_FORMAT"] = "dwarf-with-dsym"
        configuration.settings["SWIFT_OPTIMIZATION_LEVEL"] = "-Owholemodule" # Xcode 8

    end
end

#=== Targets

# So far, we've defined poject settings and
# project level build configuration settings
# (which define defaults for target level build configurations).
#
# Now it's time to define target-level build settings.

# Below we define "application"-type target and
# put all it's settings (including definition or related unit test targets)
# inside "application_for ... do ... end" structure.

target do |target|

    target.name = project.name
    target.language = :swift
    target.type = :application
    target.platform = :ios
    target.deployment_target = iOSdeploymentTarget

    #===

    # Now lets set target-level build settigns.
    # Again, the structure below is just a loop,
    # everything between "target.all_configurations.each do |configuration|"
    # and corresponding "end" (see below on the same level in the very bottom of the file)
    # is body of this loop, that repeats every iteration. This loop goes through
    # the list of build configurations (defined above) and on each iteration
    # we have variable "configuration" that contains reference to one
    # of the build configurations in CONTEXT of the TARGET. This is equivalent of setting
    # build settings on target-level in Xcode (you can access it if you choose to
    # see build settigns by "Levels", not "Combined").

    # Imagine we have project folder structure like this:
    #
    # - Cakefile
    # - Info/
    # | - CakeMania.plist
    # | - CakeManiaTst.plist
    # | - CakeManiaUITst.plist
    # - Lib/
    # | - ...
    # - Res/
    # | - CakeMania.entitlements
    # | - CakeMania-test.entitlements
    # | - ...
    # | - CakeMania.xcassets/
    #   | - ...
    #   | - AppIcon.appiconset/
    #     | - ...
    #   | - ...
    # - Src/
    # | - ...
    # | - ObjC/
    #   | - Prefix.pch
    #   | - CakeMania-Bridging-Header.h
    # | - ...
    # - Tst/
    # | - ...
    # - UITst/
    # | - ...
    #

    target.all_configurations.each do |configuration|

        #=== Build Settings - Core

        configuration.product_bundle_identifier = companyIdentifier + "." + target.name
        configuration.supported_devices = :universal
        configuration.settings["INFOPLIST_FILE"] = "Info/" + target.name + ".plist"
        configuration.settings["PRODUCT_NAME"] = "$(TARGET_NAME)"

        configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania.entitlements"
        configuration.settings["GCC_PREFIX_HEADER"] = "Src/ObjC/Prefix.pch"
        # configuration.settings["FRAMEWORK_SEARCH_PATHS"] = "$(inherited)"
        configuration.settings["LIBRARY_SEARCH_PATHS"] = "$(inherited) $(SRCROOT)/Lib/**"
        configuration.settings["ASSETCATALOG_COMPILER_APPICON_NAME"] = "AppIcon"
        # configuration.settings["ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME"] = "Brand Assets"
        configuration.settings["SWIFT_OBJC_BRIDGING_HEADER"] = "Src/ObjC/CakeMania-Bridging-Header.h"
        configuration.settings["OTHER_LDFLAGS"] = "$(inherited) -ObjC"

        # make configuration name available in run time:
        configNameFlag = "CONFIG_" + configuration.name.upcase
        configuration.settings["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) " + configNameFlag + "=1" # Obj-C support
        configuration.settings["OTHER_SWIFT_FLAGS"] = "$(inherited) -D" + configNameFlag # Swift support
        
        # This will show "Automatic" in Xcode,
        # relies on proper/valid "PROVISIONING_PROFILE" value:
        # configuration.settings["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = nil # DEPRECATED

        # Xcode 8 automati c signing support
        configuration.settings["CODE_SIGN_IDENTITY[sdk=iphoneos*]"] = "iPhone Developer"
        configuration.settings["DEVELOPMENT_TEAM"] = developmentTeamId

        #=== Build Settings - Per-configuration

        # NOTE: any configuration-specific settings below will override
        # common settings that you already applied above inside this
        # "target.all_configurations.each do |configuration|" block

        if configuration.name == "Debug"

            #=== Config

            configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania-test.entitlements"

            #=== Config - User Defined Build Settings
            
            configuration.settings["FACEBOOK_KEY"] = facebookTestKey

        end

        #===

        if configuration.name == "Staging"

            #=== Config
    
            configuration.settings["PROVISIONING_PROFILE"] = provProfAdHoc

            configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania-test.entitlements"
            
            #=== Config - User Defined Build Settings
            
            configuration.settings["FACEBOOK_KEY"] = facebookTestKey

        end

        #===

        if configuration.name == "RC"

            #=== Config
        
            configuration.settings["PROVISIONING_PROFILE"] = provProfAdHoc

            configuration.settings["CODE_SIGN_ENTITLEMENTS"] = "Res/CakeMania-test.entitlements"
            
            #=== Config - User Defined Build Settings
            
            configuration.settings["FACEBOOK_KEY"] = facebookTestKey

        end

        #===

        if configuration.name == "Production"

            #=== Config
        
            configuration.settings["PROVISIONING_PROFILE"] = provProfAdHoc # AdHoc

            #=== Config - User Defined Build Settings
            
            configuration.settings["FACEBOOK_KEY"] = facebookProdKey

        end

        #===

        if configuration.name == "AppStore"

            #=== Config
        
            configuration.settings["PROVISIONING_PROFILE"] = provProfAppStore

            #=== Config - User Defined Build Settings

            configuration.settings["FACEBOOK_KEY"] = facebookProdKey

        end

    end

    #=== Extra System Frameworks

    # Here is how we tell Xcake to include Apple system framework
    # into the target.

    # NOTE: "target.system_frameworks" is an array, that always have at least
    # "Foundation" and "UIKit", os it's always non-empty and we should not initialize it
    # before adding something there, so we jsut add values, one at a time (one per each line below).

    target.system_frameworks << "AdSupport"
    target.system_frameworks << "QuartzCore"

    #=== Source Files

    # Here is how we tell Xcake where to look for source files
    # which need to be added into the target. Moreover, the folder struture
    # will be re-created with Xcode groups.

    # NOTE: "target.include_files" is an array, that is empty by default
    # (no source files will be added to the target). So it's our responsibility
    # to initialize this array (with "=" operand) before adding values/elements
    # into it (with "<<" operand). Remember, this file is a Ruby script, and
    # that's just how Ruby works.

    target.include_files = ["Src/**/*.*"] # initialize array with 1 element
    target.include_files << "Lib/**/*.*"  # add value into already non-empty array

    target.include_files << "Res/**/*.*"  # add another value

    #=== Tests
    
    # Below we define unit tests target for the application target.
    # "unit_tests_for" is a reserved word, then you put variable that contains reference
    # to the application target that you want to create unit tests for, it's "target" in our case.
    # The "test_target" is reference to the newly created unit test target
    # so we can configure it as we want - set name, build configurations (at least info plist file)
    # and its source files, or course. The rules of how we work with test target (set its settings)
    # are the same, as we work with application target.

    unit_tests_for target do |test_target|
        
        test_target.name = target.name + testSuffix

        test_target.all_configurations.each do |configuration|

            configuration.settings["INFOPLIST_FILE"] = "Info/" + test_target.name + ".plist"

        end

        #=== Source Files

        test_target.include_files = [testSuffix + "/**/*.*"] # we set array with 1 element here!

    end

    #===

    # Below we define UI tests target for the application target.
    # See https://github.com/jcampbell05/xcake/issues/44

    ui_tests_for target do |test_target|

        test_target.name = target.name + testSuffixUI

        test_target.all_configurations.each do |configuration|

            configuration.settings["INFOPLIST_FILE"] = "Info/" + test_target.name + ".plist"

        end

        #=== Source Files

        test_target.include_files = [testSuffixUI + "/**/*.*"] # we set array with 1 element here!

    end

end