nixenvironment 0.0.59 → 0.0.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +14 -14
  4. data/bin/Config +2 -2
  5. data/bin/nixenvironment +420 -842
  6. data/legacy/CleanWorkingCopy.sh +69 -0
  7. data/legacy/Deploy.sh +44 -0
  8. data/legacy/DeployAPK.py +58 -0
  9. data/legacy/DeployIPA.sh +125 -0
  10. data/legacy/DetectSCM.sh +11 -0
  11. data/legacy/GenerateCodeCoverageForXCTests.sh +134 -0
  12. data/legacy/GenerateCodeDuplicationReport.sh +24 -0
  13. data/legacy/IncrementBuildNumber.py +129 -0
  14. data/legacy/LoadBuildEnvVars.sh +116 -0
  15. data/legacy/MakeTag.sh +94 -0
  16. data/legacy/RemoveTemporaryFiles.sh +9 -0
  17. data/legacy/SaveRevision.sh +122 -0
  18. data/legacy/UnityBuildAndroid.py +84 -0
  19. data/legacy/UnityBuildAutomationScripts/CommandLineReader.cs +130 -0
  20. data/legacy/UnityBuildAutomationScripts/NIXBuilder.cs +105 -0
  21. data/legacy/UnityBuildEnvVars.py +41 -0
  22. data/legacy/VerifyBinarySigning.py +80 -0
  23. data/legacy/svn-clean.pl +246 -0
  24. data/legacy/svncopy.pl +1134 -0
  25. data/lib/nixenvironment.rb +5 -0
  26. data/lib/nixenvironment/archiver.rb +690 -0
  27. data/lib/nixenvironment/build_env_vars_loader.rb +24 -0
  28. data/lib/nixenvironment/cmd_executor.rb +33 -0
  29. data/lib/nixenvironment/config.rb +127 -14
  30. data/lib/nixenvironment/git.rb +107 -0
  31. data/lib/nixenvironment/plist.rb +52 -0
  32. data/lib/nixenvironment/version.rb +1 -1
  33. data/lib/nixenvironment/xcodebuild.rb +167 -0
  34. data/nixenvironment.gemspec +6 -0
  35. data/utils/XcodeIconTagger/IconTagger +0 -0
  36. data/utils/XcodeIconTagger/masks/OneLineMask.png +0 -0
  37. data/utils/XcodeIconTagger/masks/TwoLineMask.png +0 -0
  38. data/utils/aapt +0 -0
  39. data/utils/gcovr +986 -0
  40. data/utils/identitieslist +0 -0
  41. data/utils/simian-2.3.33.jar +0 -0
  42. metadata +118 -2
@@ -0,0 +1,24 @@
1
+ module Nixenvironment
2
+ class BuildEnvVarsLoader
3
+ def self.load
4
+ cmd_output = %x[ source \"#{LOAD_BUILD_ENV_VARS_SCRIPT_PATH}\" ].strip!
5
+ build_env_vars = {}
6
+
7
+ vars_list = cmd_output.split(/\n/).reject(&:empty?)
8
+ if vars_list.present?
9
+ vars_to_strip = Hash[vars_list.map { |it| it.split('=', 2) }]
10
+ vars_to_strip.each do |key, value|
11
+ if key.present? && value.present?
12
+ stripped_key = key.strip
13
+ stripped_value = value.strip
14
+
15
+ puts "#{stripped_key} : #{stripped_value}"
16
+ build_env_vars[stripped_key] = stripped_value
17
+ end
18
+ end
19
+ end
20
+
21
+ build_env_vars
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ module Nixenvironment
2
+ class CmdExecutor
3
+ @binary_name = nil
4
+
5
+ @last_cmd_success = nil
6
+ @last_cmd_exitstatus = nil
7
+
8
+ def self.last_cmd_success?
9
+ @last_cmd_success
10
+ end
11
+
12
+ def self.last_cmd_exitstatus
13
+ @last_cmd_exitstatus
14
+ end
15
+
16
+ def self.execute(cmd, opts = [], silent = false)
17
+ input = "#{@binary_name}"
18
+ input << " #{cmd}" if cmd.present?
19
+ input << " #{opts.join(' ')}" if opts.present?
20
+ output = ''
21
+
22
+ IO.popen(input).each do |line|
23
+ puts line unless silent
24
+ output << line
25
+ end.close
26
+
27
+ @last_cmd_success = $?.success?
28
+ @last_cmd_exitstatus = $?.exitstatus
29
+
30
+ output
31
+ end
32
+ end
33
+ end
@@ -1,23 +1,136 @@
1
1
  module Nixenvironment
2
- NIXENV_ROOT = '.nixenvironment'
3
- BUILD_SCRIPTS = 'ninbas'
2
+ # template peojects repositories
3
+ TEMPLATES_REPO_LIST = {
4
+ 'objc' => 'https://bitbucket.org/nixsolutions/np.git',
5
+ 'swift' => 'https://bitbucket.org/nixsolutions/nps.git',
6
+ 'unity' => 'https://bitbucket.org/nixsolutions/nup.git'
7
+ }
8
+
9
+ # config
10
+ CONFIG_SETTINGS_FILE_NAME = 'Config'
11
+
12
+ # ninbas legacy
13
+ BUILD_SCRIPTS_PATH = File.expand_path('../../../legacy', __FILE__)
14
+ SAVE_REVISION_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'SaveRevision.sh')
15
+ UNITY_BUILD_ANDROID_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'UnityBuildAndroid.py')
16
+ LOAD_BUILD_ENV_VARS_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'LoadBuildEnvVars.sh')
17
+ REMOVE_TEMPORARY_FILES_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'RemoveTemporaryFiles.sh')
18
+ CODE_COVERAGE_REPORT_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'GenerateCodeCoverageForXCTests.sh')
19
+ CODE_DUPLICATION_REPORT_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'GenerateCodeDuplicationReport.sh')
20
+ MAKE_TAG_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'MakeTag.sh')
21
+ CLEAN_WORKING_COPY_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'CleanWorkingCopy.sh')
22
+ DEPLOY_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'Deploy.sh')
23
+ DEPLOY_IPA_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'DeployIPA.sh')
24
+ DEPLOY_APK_SCRIPT_PATH = File.join(BUILD_SCRIPTS_PATH, 'DeployAPK.py')
25
+
26
+ # utils
27
+ UTILS_PATH = File.expand_path('../../../utils', __FILE__)
28
+ IDENTITIESLIST_UTILITY_PATH = File.join(UTILS_PATH, 'identitieslist')
29
+ TAGGER_UTILITY_DIRECTORY = File.join(UTILS_PATH, 'XcodeIconTagger')
30
+ TAGGER_UTILITY_PATH = File.join(TAGGER_UTILITY_DIRECTORY, 'IconTagger')
31
+
32
+ # macos
33
+ MACOS_PROJECTS_DEPLOY_PATH = 'Projects/macOSProjects'
34
+
35
+ # file extensions
36
+ APP_EXT = '.app'
37
+ APPEX_EXT = '.appex'
38
+ DSYM_EXT = '.dSYM'
39
+ ZIP_EXT = '.zip'
40
+ GIT_EXT = '.git'
41
+
42
+ # watch, extensions, widgets
43
+ WATCHKIT_APP_KEY = 'WatchKit App'
44
+ WATCHKIT_EXTENSION_KEY = 'WatchKit Extension'
45
+ WIDGET_KEY = 'Widget'
4
46
 
5
- BUILD_SCRIPTS_PATH = File.join(Dir.home, NIXENV_ROOT, BUILD_SCRIPTS)
47
+ WATCHKIT_APP_PREFIX = WATCHKIT_APP_KEY + ' '
48
+ WATCHKIT_EXTENSION_PREFIX = WATCHKIT_EXTENSION_KEY + ' '
49
+ WIDGET_PREFIX = WIDGET_KEY + ' '
6
50
 
51
+ WATCHKIT_APP_SUFFIX = ' ' + WATCHKIT_APP_KEY
52
+ WATCHKIT_EXTENSION_SUFFIX = ' ' + WATCHKIT_EXTENSION_KEY
53
+ WIDGET_SUFFIX = ' ' + WIDGET_KEY
54
+
55
+ WATCHKIT_APP_SUFFIX_WITH_EXT = WATCHKIT_APP_SUFFIX + APP_EXT
56
+ WATCHKIT_EXTENSION_SUFFIX_WITH_EXT = WATCHKIT_EXTENSION_SUFFIX + APPEX_EXT
57
+ WIDGET_SUFFIX_WITH_EXT = WIDGET_SUFFIX + APPEX_EXT
58
+
59
+ IOS_BUILDS_FOLDER_NAME = 'build'
60
+ IOS_PLUGINS_FOLDER_NAME = 'PlugIns'
61
+
62
+ # unity
63
+ UNITY_BUILDS_IOS_PATH = 'Builds/iOS'
64
+ UNITY_BUILDS_IOS_PROJECT = 'Unity-iPhone.xcodeproj'
65
+ UNITY_BUILDS_IOS_SCHEME = 'Unity-iPhone'
66
+ UNITY_BUILDS_ICONS_PATH = 'Unity-iPhone/Images.xcassets'
67
+ UNITY_BUILD_SCRIPTS_PATH = 'UnityBuildAutomationScripts'
68
+ UNITY_ASSETS_EDITOR_PATH = 'Assets/Editor'
69
+ UNITY_BUILD_SCRIPTS_DIR = File.join(BUILD_SCRIPTS_PATH, UNITY_BUILD_SCRIPTS_PATH)
70
+ UNITY_EDITOR_DIR = File.join(Dir.pwd, UNITY_ASSETS_EDITOR_PATH)
71
+ UNITY_IOS_PROJECT_PATH = File.join(Dir.pwd, UNITY_BUILDS_IOS_PATH)
72
+
73
+ # project adjuster
7
74
  ADJUSTER_WORKING_COPY_PATH = '/tmp/NIXProjectAdjuster'
8
75
  ADJUSTER_TEMP_PROJECT_NAME = 'newProj'
9
76
 
10
- UNITY_BUILDS_IOS_PATH = 'Builds/iOS'
77
+ # tests
78
+ TESTS_AND_COVERAGE_TIMEOUT = 10
11
79
 
12
- REPO_LIST = {
13
- BUILD_SCRIPTS => 'https://bitbucket.org/nixsolutions/ninbas.git',
14
- # 'nixipl' => 'https://bitbucket.org/nixsolutions/nixipl.git',
15
- # 'nocl' => 'https://bitbucket.org/nixsolutions/nocl.git'
16
- }
80
+ # config keys
81
+ PROJECT_TO_BUILD_KEY = 'PROJECT_TO_BUILD'
82
+ PROJECT_TARGET_TO_BUILD_KEY = 'PROJECT_TARGET_TO_BUILD'
83
+ PROJECT_TARGET_TO_TEST_KEY = 'PROJECT_TARGET_TO_TEST'
84
+ WORKSPACE_TO_BUILD_KEY = 'WORKSPACE_TO_BUILD'
85
+ WORKSPACE_SCHEME_TO_BUILD_KEY = 'WORKSPACE_SCHEME_TO_BUILD'
86
+ WORKSPACE_SCHEME_TO_TEST_KEY = 'WORKSPACE_SCHEME_TO_TEST'
87
+ SDK_KEY = 'SDK'
88
+ SDK_FOR_TESTS_KEY = 'SDK_FOR_TESTS'
89
+ EXCLUDE_PATTERN_FOR_CODE_COVERAGE_KEY = 'EXCLUDE_PATTERN_FOR_CODE_COVERAGE'
90
+ EXCLUDE_PATTERN_FOR_CODE_DUPLICATION_KEY = 'EXCLUDE_PATTERN_FOR_CODE_DUPLICATION'
91
+ DEPLOY_HOST_KEY = 'DEPLOY_HOST'
92
+ DEPLOY_PATH_KEY = 'DEPLOY_PATH'
93
+ DEPLOY_USERNAME_KEY = 'DEPLOY_USERNAME'
94
+ DEPLOY_PASSWORD_KEY = 'DEPLOY_PASSWORD'
95
+ DEPLOY_ITUNESCONNECT_USERNAME_KEY = 'DEPLOY_ITUNESCONNECT_USERNAME'
96
+ ICONS_PATH_KEY = 'ICONS_PATH'
97
+ XCTEST_DESTINATION_DEVICE_KEY = 'XCTEST_DESTINATION_DEVICE'
98
+ CONFIGURATION_FILES_PATH_KEY = 'CONFIGURATION_FILES_PATH'
99
+ CODE_COVERAGE_CONFIGURATION_KEY = 'CODE_COVERAGE_CONFIGURATION'
100
+ CODE_COVERAGE_OUTPUT_DIRECTORY_KEY = 'CODE_COVERAGE_OUTPUT_DIRECTORY'
101
+ ENV_VAR_PREFIX_KEY = 'ENV_VAR_PREFIX'
102
+ BUNDLE_ID_KEY = 'BUNDLE_ID'
103
+ RESIGNED_BUNDLE_ID_KEY = 'RESIGNED_BUNDLE_ID'
104
+ RESIGNED_WATCHKIT_APP_BUNDLE_ID_KEY = 'RESIGNED_WATCHKIT_APP_BUNDLE_ID'
105
+ RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID_KEY = 'RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID'
106
+ RESIGNED_WIDGET_BUNDLE_ID_KEY = 'RESIGNED_WIDGET_BUNDLE_ID'
107
+ RESIGNED_BUNDLE_NAME_KEY = 'RESIGNED_BUNDLE_NAME'
108
+ RESIGNED_ENTITLEMENTS_PATH_KEY = 'RESIGNED_ENTITLEMENTS_PATH'
109
+ RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH_KEY = 'RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH'
110
+ RESIGNED_WIDGET_ENTITLEMENTS_PATH_KEY = 'RESIGNED_WIDGET_ENTITLEMENTS_PATH'
17
111
 
18
- TEMPLATES_REPO_LIST = {
19
- 'objc' => 'https://bitbucket.org/nixsolutions/np.git',
20
- 'swift' => 'https://bitbucket.org/nixsolutions/nps.git',
21
- 'unity' => 'https://bitbucket.org/nixsolutions/nup.git'
22
- }
112
+ # env keys
113
+ PRODUCT_SETTINGS_PATH_KEY = 'PRODUCT_SETTINGS_PATH'
114
+ CONFIGURATION_BUILD_DIR_KEY = 'CONFIGURATION_BUILD_DIR'
115
+ DWARF_DSYM_FOLDER_PATH_KEY = 'DWARF_DSYM_FOLDER_PATH'
116
+ BUILT_PRODUCTS_DIR_KEY = 'BUILT_PRODUCTS_DIR'
117
+ EXECUTABLE_NAME_KEY = 'EXECUTABLE_NAME'
118
+ PROJECT_KEY = 'PROJECT'
119
+ OBJECT_FILE_DIR_NORMAL_KEY = 'OBJECT_FILE_DIR_normal'
120
+ EMBEDDED_PROFILE_NAME_KEY = 'EMBEDDED_PROFILE_NAME'
121
+ TARGET_NAME_KEY = 'TARGET_NAME'
122
+ CONFIGURATION_KEY = 'CONFIGURATION'
123
+ APP_PRODUCT_KEY = 'APP_PRODUCT'
124
+ SDK_NAME_KEY = 'SDK_NAME'
125
+ IPA_BUNDLE_ID_KEY = 'IPA_BUNDLE_ID'
126
+ CURRENT_APP_VERSION_KEY = 'CURRENT_APP_VERSION'
127
+ CURRENT_BUILD_VERSION_KEY = 'CURRENT_BUILD_VERSION'
128
+ NAME_FOR_DEPLOYMENT_KEY = 'NAME_FOR_DEPLOYMENT'
129
+ IPA_PRODUCT_KEY = 'IPA_PRODUCT'
130
+ APP_DSYM_KEY = 'APP_DSYM'
131
+ SCM_USERNAME_KEY = 'SCM_USERNAME'
132
+ SCM_PASSWORD_KEY = 'SCM_PASSWORD'
133
+ WATCHKIT_EXTENSION_PRODUCT_SETTINGS_PATH_KEY = 'WATCHKIT_EXTENSION_' + PRODUCT_SETTINGS_PATH_KEY
134
+ WATCHKIT_APP_PRODUCT_SETTINGS_PATH_KEY = 'WATCHKIT_APP_' + PRODUCT_SETTINGS_PATH_KEY
135
+ WIDGET_PRODUCT_SETTINGS_PATH_KEY = 'WIDGET_' + PRODUCT_SETTINGS_PATH_KEY
23
136
  end
@@ -0,0 +1,107 @@
1
+ # This is very basic git wrapper for internal Nixenvironment gem needs
2
+ # It's used instead of popular 'git' gem (https://rubygems.org/gems/git)
3
+ # because 'git' gem is redundant and also doesn't satisfy all Nixenvironment gem needs
4
+
5
+ require_relative 'cmd_executor'
6
+
7
+ module Nixenvironment
8
+ class Git < CmdExecutor
9
+ @binary_name = 'git'
10
+
11
+ HEAD = 'HEAD'
12
+ REMOTE_MASTER = 'refs/heads/master'
13
+ DEFAULT_REFSPEC = "#{HEAD}:#{REMOTE_MASTER}"
14
+
15
+ CLONE_CMD = 'clone'
16
+ FETCH_CMD = 'fetch'
17
+ CHECKOUT_CMD = 'checkout'
18
+ COMMIT_CMD = 'commit'
19
+ PUSH_CMD = 'push'
20
+ REMOTE_ADD_CMD = 'remote add'
21
+ STATUS_CMD = 'status'
22
+ TAG_CMD = 'tag'
23
+
24
+ RECURSIVE_OPT = '--recursive'
25
+ TAGS_OPT = '--tags'
26
+ ORPHAN_OPT = '--orphan'
27
+ MESSAGE_OPT = '--message'
28
+ FORCE_OPT = '--force'
29
+ PORCELAIN_OPT = '--porcelain'
30
+
31
+ # options
32
+ # :recursive, :r => after the clone is created, initialize all submodules within
33
+ def self.clone(url, working_dir = nil, options = {})
34
+ arr_opts = []
35
+ arr_opts << RECURSIVE_OPT if options[:recursive] || options[:r]
36
+ arr_opts << url
37
+ arr_opts << working_dir if working_dir.present?
38
+
39
+ execute(CLONE_CMD, arr_opts)
40
+ end
41
+
42
+ # options
43
+ # :tags, :t => fetch tags
44
+ def self.fetch(options = {})
45
+ arr_opts = []
46
+ arr_opts << TAGS_OPT if options[:tags] || options[:t]
47
+
48
+ execute(FETCH_CMD, arr_opts)
49
+ end
50
+
51
+ # options
52
+ # :orphan => orphan branch
53
+ def self.checkout(branch, options = {})
54
+ arr_opts = []
55
+ arr_opts << ORPHAN_OPT if options[:orphan]
56
+ arr_opts << branch
57
+
58
+ execute(CHECKOUT_CMD, arr_opts)
59
+ end
60
+
61
+ # options
62
+ # :message, :m => commit message
63
+ def self.commit(options = {})
64
+ message = options[:message] || options[:m]
65
+ arr_opts = []
66
+ arr_opts << "#{MESSAGE_OPT} '#{message}'" if message
67
+
68
+ execute(COMMIT_CMD, arr_opts)
69
+ end
70
+
71
+ # options
72
+ # :force, :f => force push, ignore checks
73
+ def self.push(remote = nil, refspec = nil, options = {})
74
+ arr_opts = []
75
+ arr_opts << FORCE_OPT if options[:force] || options[:f]
76
+ arr_opts << remote if remote.present?
77
+ arr_opts << refspec if refspec.present?
78
+
79
+ execute(PUSH_CMD, arr_opts)
80
+ end
81
+
82
+ def self.remote_add(name, url)
83
+ arr_opts = []
84
+ arr_opts << name
85
+ arr_opts << url
86
+
87
+ execute(REMOTE_ADD_CMD, arr_opts)
88
+ end
89
+
90
+ # options
91
+ # :porcelain => give the output in an easy-to-parse format
92
+ def self.status(options = {})
93
+ arr_opts = []
94
+ arr_opts << PORCELAIN_OPT if options[:porcelain]
95
+
96
+ execute(STATUS_CMD, arr_opts)
97
+ end
98
+
99
+ def self.tag
100
+ tags = execute(TAG_CMD).lines
101
+ tags.map!(&:strip!)
102
+ tags.sort_by!(&:to_i)
103
+ end
104
+
105
+ private_class_method :execute
106
+ end
107
+ end
@@ -0,0 +1,52 @@
1
+ require 'cfpropertylist'
2
+
3
+ module Nixenvironment
4
+ class Plist
5
+ FORMAT_BINARY = CFPropertyList::List::FORMAT_BINARY
6
+ FORMAT_XML = CFPropertyList::List::FORMAT_XML
7
+ FORMAT_PLAIN = CFPropertyList::List::FORMAT_PLAIN
8
+ FORMAT_AUTO = CFPropertyList::List::FORMAT_AUTO
9
+
10
+ def self.from_file(path)
11
+ new(CFPropertyList::List.new(:file => path))
12
+ end
13
+
14
+ def self.from_hash(hash)
15
+ plist = CFPropertyList::List.new
16
+ plist.value = CFPropertyList.guess(hash)
17
+ plist.format = FORMAT_XML
18
+ new(plist)
19
+ end
20
+
21
+ def self.from_str(str)
22
+ plist = CFPropertyList::List.new
23
+ plist.load_str(str)
24
+ new(plist)
25
+ end
26
+
27
+ def initialize(plist)
28
+ @plist = plist
29
+ @path = @plist.filename
30
+ @data = CFPropertyList.native_types(@plist.value)
31
+ end
32
+
33
+ def [](key)
34
+ @data[key]
35
+ end
36
+
37
+ def []=(key, value)
38
+ @data[key] = value
39
+ @plist.value = CFPropertyList.guess(@data)
40
+ end
41
+
42
+ def save(path = nil, format = nil, formatted = true)
43
+ path ||= @path
44
+ raise 'Path to save plist is not specified!' unless path
45
+ @plist.save(path, format, :formatted => formatted)
46
+ end
47
+
48
+ def to_s(format = FORMAT_AUTO, formatted = true)
49
+ @plist.to_str(format, :formatted => formatted)
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module Nixenvironment
2
- VERSION = '0.0.59'
2
+ VERSION = '0.0.60'
3
3
  end
@@ -0,0 +1,167 @@
1
+ # This is very basic xcodebuild wrapper for internal Nixenvironment gem needs
2
+ # It's used instead of popular 'xcodeproj' gem (https://github.com/cocoapods/xcodeproj)
3
+ # because 'xcodeproj' gem is redundant and also doesn't satisfy all Nixenvironment gem needs
4
+
5
+ require_relative 'cmd_executor'
6
+
7
+ module Nixenvironment
8
+ class Xcodebuild < CmdExecutor
9
+ @binary_name = 'xcodebuild'
10
+
11
+ @config_settings = {}
12
+ @info = {}
13
+
14
+ def self.contains_config?(config)
15
+ configurations = @info['Build Configurations']
16
+ configurations && configurations.include?(config)
17
+ end
18
+
19
+ def self.contains_scheme?(scheme)
20
+ schemes = @info['Schemes']
21
+ schemes && schemes.include?(scheme)
22
+ end
23
+
24
+ def self.clean_all_targets
25
+ execute(nil, %w(-alltargets clean))
26
+ end
27
+
28
+ # other => other args to be passed to xcodebuild
29
+ def self.build(sdk = nil, config = nil, project = nil, target = nil, workspace = nil, scheme = nil, env_var_prefix = nil, other = {})
30
+ build_args = []
31
+ build_args << "-sdk '#{sdk}'" if sdk.present?
32
+ build_args << "-configuration '#{config}'" if config.present?
33
+ build_args << "-project '#{project}'" if project.present?
34
+ build_args << "-target '#{target}'" if target.present?
35
+ build_args << "-workspace '#{workspace}'" if workspace.present?
36
+ build_args << "-scheme '#{scheme}'" if scheme.present?
37
+
38
+ if env_var_prefix.present?
39
+ vars_to_define = ''
40
+
41
+ ENV.each do |key, value|
42
+ if key.start_with?(env_var_prefix)
43
+ vars_to_define += ' ' + key
44
+ puts "Environment variable '#{key}' will be defined with value: #{value}"
45
+ end
46
+ end
47
+
48
+ build_args << "GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS#{vars_to_define}'" if vars_to_define.present?
49
+ end
50
+
51
+ # set "Precompile Prefix Header" flag to "NO";
52
+ # otherwise it can throw error ".pch.pch has been modified since the precompiled header"
53
+ build_args << 'GCC_PRECOMPILE_PREFIX_HEADER=NO'
54
+ build_args << other.map { |key, value| "#{key}='#{value}'" }.join(' ')
55
+ build_args << '| xcpretty -c; exit ${PIPESTATUS[0]}'
56
+
57
+ execute(nil, build_args)
58
+ end
59
+
60
+ def self.test(sdk = nil, config = nil, workspace = nil, scheme = nil, code_coverage_config = nil)
61
+ build_args = []
62
+ build_args << "-sdk '#{sdk}'" if sdk.present?
63
+ build_args << "-configuration '#{config}'" if config.present?
64
+ build_args << "-workspace '#{workspace}'" if workspace.present?
65
+ build_args << "-scheme '#{scheme}'" if scheme.present?
66
+ build_args << "-xcconfig '#{code_coverage_config}'" if code_coverage_config.present?
67
+ build_args << "-destination-timeout '#{timeout}'" if timeout.present?
68
+ build_args << "-destination '#{destination}'" if destination.present?
69
+ build_args << " | ocunit2junit"
70
+
71
+ execute('test', build_args)
72
+ end
73
+
74
+ def self.read_config_settings(workspace = nil, project = nil, scheme = nil, target = nil, sdk = nil, config = nil)
75
+ read_info
76
+
77
+ raise "Scheme #{scheme} doesn't exist!" if scheme.present? && !contains_scheme?(scheme)
78
+ raise "Configuration #{config} doesn't exist!" if config.present? && !contains_config?(config)
79
+ raise "Either #{PROJECT_TO_BUILD_KEY} or #{WORKSPACE_TO_BUILD_KEY} must be specified!" if project.blank? && workspace.blank?
80
+
81
+ build_args = []
82
+ build_args << "-sdk '#{sdk}'" if sdk.present?
83
+ build_args << "-configuration '#{config}'" if config.present?
84
+ build_args << "-project '#{project}'" if project.present?
85
+ build_args << "-target '#{target}'" if target.present?
86
+ build_args << "-workspace '#{workspace}'" if workspace.present?
87
+ build_args << "-scheme '#{scheme}'" if scheme.present?
88
+ build_args << '-showBuildSettings'
89
+
90
+ puts 'Reading config settings ...'
91
+ cmd_output = execute(nil, build_args, true)
92
+
93
+ env_vars_list = cmd_output.split(/\n/).reject(&:empty?)
94
+ if env_vars_list.present?
95
+ build_settings_to_strip = Hash[env_vars_list.map { |it| it.split('=', 2) }]
96
+ build_settings_to_strip.each do |key, value|
97
+ @config_settings[key.strip] ||= value.strip if key.present? && value.present?
98
+ end
99
+ end
100
+
101
+ if workspace.present?
102
+ @config_settings[WATCHKIT_EXTENSION_PRODUCT_SETTINGS_PATH_KEY] = product_settings_path(workspace, scheme, WATCHKIT_EXTENSION_SUFFIX)
103
+ @config_settings[WATCHKIT_APP_PRODUCT_SETTINGS_PATH_KEY] = product_settings_path(workspace, scheme, WATCHKIT_APP_SUFFIX)
104
+ @config_settings[WIDGET_PRODUCT_SETTINGS_PATH_KEY] = product_settings_path(workspace, scheme, WIDGET_SUFFIX)
105
+ end
106
+
107
+ build_directory = File.join(Dir.pwd, IOS_BUILDS_FOLDER_NAME)
108
+ @config_settings[CONFIGURATION_BUILD_DIR_KEY] = build_directory
109
+ @config_settings[BUILT_PRODUCTS_DIR_KEY] = build_directory
110
+ @config_settings[DWARF_DSYM_FOLDER_PATH_KEY] = build_directory
111
+
112
+ plist_path = @config_settings[PRODUCT_SETTINGS_PATH_KEY]
113
+ info_plist = Plist.from_file(plist_path)
114
+ @config_settings[RESIGNED_BUNDLE_NAME_KEY] ||= info_plist['CFBundleDisplayName']
115
+ end
116
+
117
+ def self.product_settings_path(workspace, scheme, scheme_suffix)
118
+ scheme += scheme_suffix
119
+ if contains_scheme?(scheme)
120
+ build_args = []
121
+ build_args << "-workspace '#{workspace}'"
122
+ build_args << "-scheme '#{scheme}'"
123
+ build_args << '-showBuildSettings'
124
+
125
+ puts "Getting product settings path for scheme '#{scheme}' ..."
126
+ cmd_output = execute(nil, build_args, true)
127
+
128
+ env_vars_list = cmd_output.split(/\n/).reject(&:empty?)
129
+ if env_vars_list.present?
130
+ build_settings_to_strip = Hash.new.compare_by_identity
131
+ env_vars_list.each do |it|
132
+ key_value = it.split('=', 2)
133
+ build_settings_to_strip[key_value.first] = key_value.last
134
+ end
135
+
136
+ build_settings_to_strip.each do |key, value|
137
+ if key.present? && value.present?
138
+ stripped_key = key.strip
139
+ stripped_value = value.strip
140
+ return stripped_value if stripped_key == PRODUCT_SETTINGS_PATH_KEY && stripped_value.include?(scheme_suffix)
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ nil
147
+ end
148
+
149
+ def self.read_info
150
+ cmd_output = execute(nil, %w(-list 2>&1))
151
+ raise "Getting xcode_project_info error! #{cmd_output}" if cmd_output.include?('error')
152
+
153
+ cmd_output = cmd_output.lines[1..-1].join.split(/\n\n/)
154
+ cmd_output.each do |pair|
155
+ key, value = pair.split(/:/)
156
+ next unless key.present? && value.present?
157
+ @info[key.strip] = value.lines.map(&:strip).reject(&:empty?)
158
+ end
159
+ end
160
+
161
+ def self.config_settings
162
+ @config_settings
163
+ end
164
+
165
+ private_class_method :product_settings_path, :read_info, :execute
166
+ end
167
+ end