run_loop_tcc 2.1.3
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/bin/run-loop +19 -0
- data/lib/run_loop/abstract.rb +18 -0
- data/lib/run_loop/app.rb +372 -0
- data/lib/run_loop/cache/cache.rb +68 -0
- data/lib/run_loop/cli/cli.rb +48 -0
- data/lib/run_loop/cli/codesign.rb +24 -0
- data/lib/run_loop/cli/errors.rb +11 -0
- data/lib/run_loop/cli/instruments.rb +160 -0
- data/lib/run_loop/cli/locale.rb +31 -0
- data/lib/run_loop/cli/simctl.rb +257 -0
- data/lib/run_loop/cli/tcc.rb +139 -0
- data/lib/run_loop/codesign.rb +76 -0
- data/lib/run_loop/core.rb +902 -0
- data/lib/run_loop/core_simulator.rb +960 -0
- data/lib/run_loop/detect_aut/detect.rb +185 -0
- data/lib/run_loop/detect_aut/errors.rb +126 -0
- data/lib/run_loop/detect_aut/xamarin_studio.rb +46 -0
- data/lib/run_loop/detect_aut/xcode.rb +157 -0
- data/lib/run_loop/device.rb +722 -0
- data/lib/run_loop/device_agent/app/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/bin/xctestctl +0 -0
- data/lib/run_loop/device_agent/cbxrunner.rb +156 -0
- data/lib/run_loop/device_agent/frameworks/Frameworks.zip +0 -0
- data/lib/run_loop/device_agent/frameworks.rb +65 -0
- data/lib/run_loop/device_agent/ipa/CBX-Runner.app.zip +0 -0
- data/lib/run_loop/device_agent/launcher.rb +51 -0
- data/lib/run_loop/device_agent/xcodebuild.rb +91 -0
- data/lib/run_loop/device_agent/xctestctl.rb +109 -0
- data/lib/run_loop/directory.rb +179 -0
- data/lib/run_loop/dnssd.rb +148 -0
- data/lib/run_loop/dot_dir.rb +87 -0
- data/lib/run_loop/dylib_injector.rb +145 -0
- data/lib/run_loop/encoding.rb +56 -0
- data/lib/run_loop/environment.rb +361 -0
- data/lib/run_loop/fifo.rb +40 -0
- data/lib/run_loop/host_cache.rb +128 -0
- data/lib/run_loop/http/error.rb +15 -0
- data/lib/run_loop/http/request.rb +44 -0
- data/lib/run_loop/http/retriable_client.rb +166 -0
- data/lib/run_loop/http/server.rb +17 -0
- data/lib/run_loop/instruments.rb +436 -0
- data/lib/run_loop/ipa.rb +142 -0
- data/lib/run_loop/l10n.rb +93 -0
- data/lib/run_loop/language.rb +63 -0
- data/lib/run_loop/lipo.rb +132 -0
- data/lib/run_loop/lldb.rb +52 -0
- data/lib/run_loop/locale.rb +101 -0
- data/lib/run_loop/logging.rb +111 -0
- data/lib/run_loop/otool.rb +76 -0
- data/lib/run_loop/patches/awesome_print.rb +17 -0
- data/lib/run_loop/physical_device/life_cycle.rb +268 -0
- data/lib/run_loop/plist_buddy.rb +189 -0
- data/lib/run_loop/process_terminator.rb +128 -0
- data/lib/run_loop/process_waiter.rb +117 -0
- data/lib/run_loop/regex.rb +19 -0
- data/lib/run_loop/shell.rb +103 -0
- data/lib/run_loop/sim_control.rb +1264 -0
- data/lib/run_loop/simctl.rb +275 -0
- data/lib/run_loop/sqlite.rb +61 -0
- data/lib/run_loop/strings.rb +88 -0
- data/lib/run_loop/tcc/TCC.db +0 -0
- data/lib/run_loop/tcc/tcc.rb +240 -0
- data/lib/run_loop/template.rb +61 -0
- data/lib/run_loop/version.rb +182 -0
- data/lib/run_loop/xcode.rb +318 -0
- data/lib/run_loop/xcrun.rb +107 -0
- data/lib/run_loop/xcuitest.rb +550 -0
- data/lib/run_loop.rb +230 -0
- data/plists/simctl/com.apple.UIAutomation.plist +0 -0
- data/plists/simctl/com.apple.UIAutomationPlugIn.plist +0 -0
- data/scripts/calabash_script_uia.js +28184 -0
- data/scripts/lib/json2.min.js +26 -0
- data/scripts/lib/log.js +26 -0
- data/scripts/lib/on_alert.js +224 -0
- data/scripts/read-cmd.sh +2 -0
- data/scripts/run_dismiss_location.js +89 -0
- data/scripts/run_loop_basic.js +34 -0
- data/scripts/run_loop_fast_uia.js +188 -0
- data/scripts/run_loop_host.js +117 -0
- data/scripts/run_loop_shared_element.js +125 -0
- data/scripts/timeout3 +23 -0
- data/scripts/udidetect +0 -0
- data/vendor-licenses/FBSimulatorControl.LICENSE +30 -0
- data/vendor-licenses/xctestctl.LICENSE +32 -0
- metadata +443 -0
data/lib/run_loop/ipa.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
module RunLoop
|
2
|
+
# A model of the an .ipa - a application binary for iOS devices.
|
3
|
+
class Ipa
|
4
|
+
|
5
|
+
# The path to this .ipa.
|
6
|
+
# @!attribute [r] path
|
7
|
+
# @return [String] A path to this .ipa.
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
# Create a new ipa instance.
|
11
|
+
# @param [String] path_to_ipa The path the .ipa file.
|
12
|
+
# @return [Calabash::Ipa] A new ipa instance.
|
13
|
+
# @raise [RuntimeError] If the file does not exist.
|
14
|
+
# @raise [RuntimeError] If the file does not end in .ipa.
|
15
|
+
def initialize(path_to_ipa)
|
16
|
+
unless File.exist? path_to_ipa
|
17
|
+
raise "Expected an ipa at '#{path_to_ipa}'"
|
18
|
+
end
|
19
|
+
|
20
|
+
unless path_to_ipa.end_with?('.ipa')
|
21
|
+
raise "Expected '#{path_to_ipa}' to be an .ipa"
|
22
|
+
end
|
23
|
+
@path = path_to_ipa
|
24
|
+
end
|
25
|
+
|
26
|
+
# @!visibility private
|
27
|
+
def to_s
|
28
|
+
cf_bundle_version = bundle_version
|
29
|
+
cf_bundle_short_version = short_bundle_version
|
30
|
+
|
31
|
+
if cf_bundle_version && cf_bundle_short_version
|
32
|
+
version = "#{cf_bundle_version.to_s}/#{cf_bundle_short_version}"
|
33
|
+
elsif cf_bundle_version
|
34
|
+
version = cf_bundle_version.to_s
|
35
|
+
elsif cf_bundle_short_version
|
36
|
+
version = cf_bundle_short_version
|
37
|
+
else
|
38
|
+
version = ""
|
39
|
+
end
|
40
|
+
|
41
|
+
"#<IPA #{bundle_identifier} #{version} #{path}>"
|
42
|
+
end
|
43
|
+
|
44
|
+
# @!visibility private
|
45
|
+
def inspect
|
46
|
+
to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
# The bundle identifier of this ipa.
|
50
|
+
# @return [String] A string representation of this ipa's CFBundleIdentifier
|
51
|
+
def bundle_identifier
|
52
|
+
app.bundle_identifier
|
53
|
+
end
|
54
|
+
|
55
|
+
# Inspects the app's Info.plist for the executable name.
|
56
|
+
# @return [String] The value of CFBundleExecutable.
|
57
|
+
def executable_name
|
58
|
+
app.executable_name
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the arches for the binary.
|
62
|
+
def arches
|
63
|
+
app.arches
|
64
|
+
end
|
65
|
+
|
66
|
+
# Inspects the app's executables for the server version
|
67
|
+
# @return[RunLoop::Version] a version instance
|
68
|
+
def calabash_server_version
|
69
|
+
app.calabash_server_version
|
70
|
+
end
|
71
|
+
|
72
|
+
# @!visibility private
|
73
|
+
def codesign_info
|
74
|
+
app.codesign_info
|
75
|
+
end
|
76
|
+
|
77
|
+
# @!visibility private
|
78
|
+
def developer_signed?
|
79
|
+
app.developer_signed?
|
80
|
+
end
|
81
|
+
|
82
|
+
# @!visibility private
|
83
|
+
def distribution_signed?
|
84
|
+
app.distribution_signed?
|
85
|
+
end
|
86
|
+
|
87
|
+
# @!visibility private
|
88
|
+
def marketing_version
|
89
|
+
app.marketing_version
|
90
|
+
end
|
91
|
+
|
92
|
+
# See #marketing_version
|
93
|
+
alias_method :short_bundle_version, :marketing_version
|
94
|
+
|
95
|
+
# @!visibility private
|
96
|
+
def build_version
|
97
|
+
app.build_version
|
98
|
+
end
|
99
|
+
|
100
|
+
# See #build_version
|
101
|
+
alias_method :bundle_version, :build_version
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
# @!visibility private
|
106
|
+
def tmpdir
|
107
|
+
@tmpdir ||= Dir.mktmpdir
|
108
|
+
end
|
109
|
+
|
110
|
+
# @!visibility private
|
111
|
+
def payload_dir
|
112
|
+
@payload_dir ||= lambda do
|
113
|
+
FileUtils.cp(path, tmpdir)
|
114
|
+
zip_path = File.join(tmpdir, File.basename(path))
|
115
|
+
Dir.chdir(tmpdir) do
|
116
|
+
system('unzip', *['-q', zip_path])
|
117
|
+
end
|
118
|
+
File.join(tmpdir, 'Payload')
|
119
|
+
end.call
|
120
|
+
end
|
121
|
+
|
122
|
+
# @!visibility private
|
123
|
+
def bundle_dir
|
124
|
+
@bundle_dir ||= lambda do
|
125
|
+
Dir.glob(File.join(payload_dir, '*')).detect do |f|
|
126
|
+
File.directory?(f) && f.end_with?('.app')
|
127
|
+
end
|
128
|
+
end.call
|
129
|
+
end
|
130
|
+
|
131
|
+
# @!visibility private
|
132
|
+
def app
|
133
|
+
@app ||= RunLoop::App.new(bundle_dir)
|
134
|
+
end
|
135
|
+
|
136
|
+
# @!visibility private
|
137
|
+
def plist_buddy
|
138
|
+
@plist_buddy ||= RunLoop::PlistBuddy.new
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module RunLoop
|
2
|
+
class L10N
|
3
|
+
|
4
|
+
# Find the localized name for a given key_code
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# lookup_localization_name('delete.key', 'da') => 'Slet'
|
8
|
+
#
|
9
|
+
# @param [String] key_code the localization signifier, e.g. 'delete.key'
|
10
|
+
# @param [String] localized_lang an iso language code returned by calabash ios server
|
11
|
+
#
|
12
|
+
# @return [String] the localized name
|
13
|
+
def lookup_localization_name(key_code, localized_lang)
|
14
|
+
lookup_table_dir = lang_dir(localized_lang)
|
15
|
+
return nil unless lookup_table_dir
|
16
|
+
|
17
|
+
key_name_lookup_table(lookup_table_dir)[key_code]
|
18
|
+
end
|
19
|
+
|
20
|
+
UIKIT_AXBUNDLE_PATH_CORE_SIM = 'Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/AccessibilityBundles/UIKit.axbundle/'
|
21
|
+
|
22
|
+
LANG_CODE_TO_LANG_NAME_MAP = {
|
23
|
+
'en' => 'English',
|
24
|
+
'nl' => 'Dutch',
|
25
|
+
'fr' => 'French',
|
26
|
+
'de' => 'German',
|
27
|
+
'es' => 'Spanish',
|
28
|
+
'it' => 'Italian',
|
29
|
+
'jp' => 'Japanese'
|
30
|
+
}
|
31
|
+
|
32
|
+
# @!visibility private
|
33
|
+
def to_s
|
34
|
+
"#<L10N #{uikit_bundle_l10n_path}>"
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!visibility private
|
38
|
+
def inspect
|
39
|
+
to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
# maps the ios keyboard localization to a language directory where we can
|
43
|
+
# find a key-code -> localized-label mapping
|
44
|
+
def lang_dir(localized_lang)
|
45
|
+
l10n_path = uikit_bundle_l10n_path
|
46
|
+
|
47
|
+
## 2 char + _ + sub localization
|
48
|
+
# en_GB.lproj
|
49
|
+
lang_dir_name = "#{localized_lang}.lproj".sub('-','_')
|
50
|
+
if File.exists?(File.join(l10n_path, lang_dir_name))
|
51
|
+
return lang_dir_name
|
52
|
+
end
|
53
|
+
|
54
|
+
# 2 char iso language code
|
55
|
+
# vi.lproj
|
56
|
+
two_char_country_code = localized_lang.split('-')[0]
|
57
|
+
lang_dir_name = "#{two_char_country_code}.lproj"
|
58
|
+
if File.exists?(File.join(l10n_path, lang_dir_name))
|
59
|
+
return lang_dir_name
|
60
|
+
end
|
61
|
+
|
62
|
+
# Full name
|
63
|
+
# e.g. Dutch.lproj
|
64
|
+
lang_dir_name = "#{LANG_CODE_TO_LANG_NAME_MAP[two_char_country_code]}.lproj"
|
65
|
+
if is_full_name?(two_char_country_code) &&
|
66
|
+
File.exists?(File.join(l10n_path, lang_dir_name))
|
67
|
+
return lang_dir_name
|
68
|
+
end
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def uikit_bundle_l10n_path
|
73
|
+
File.join(xcode.developer_dir, UIKIT_AXBUNDLE_PATH_CORE_SIM)
|
74
|
+
end
|
75
|
+
|
76
|
+
def is_full_name?(two_letter_country_code)
|
77
|
+
LANG_CODE_TO_LANG_NAME_MAP.has_key?(two_letter_country_code)
|
78
|
+
end
|
79
|
+
|
80
|
+
def key_name_lookup_table(lang_dir_name)
|
81
|
+
path = File.join(uikit_bundle_l10n_path, lang_dir_name, 'Accessibility.strings')
|
82
|
+
JSON.parse(`plutil -convert json #{path} -o -`)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @!visibility private
|
86
|
+
attr_reader :xcode
|
87
|
+
|
88
|
+
# @!visibility private
|
89
|
+
def xcode
|
90
|
+
@xcode ||= RunLoop::Xcode.new
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module RunLoop
|
2
|
+
# @!visibility private
|
3
|
+
class Language
|
4
|
+
|
5
|
+
# @!visibility private
|
6
|
+
# Is the lang_code valid for this device?
|
7
|
+
def self.valid_code_for_device?(lang_code, device)
|
8
|
+
valid_codes = self.codes_for_device(device)
|
9
|
+
if valid_codes.nil?
|
10
|
+
false
|
11
|
+
else
|
12
|
+
valid_codes.include?(lang_code)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @!visibility private
|
17
|
+
# Returns a list of known language codes for a device based on iOS version
|
18
|
+
#
|
19
|
+
# @param [RunLoop::Device] device
|
20
|
+
#
|
21
|
+
# @return [Array<String>] an array of language codes for the device
|
22
|
+
#
|
23
|
+
# @raise [ArgumentError] if there are no codes for a device version
|
24
|
+
def self.codes_for_device(device)
|
25
|
+
major_version = device.version.major
|
26
|
+
key = RunLoop::Version.new("#{major_version}.0")
|
27
|
+
LANGUAGE_CODES[key]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# @!visibility private
|
33
|
+
#
|
34
|
+
# Generated with:
|
35
|
+
#
|
36
|
+
# NSArray *identifiers = [[NSLocale availableLocaleIdentifiers]
|
37
|
+
# sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
|
38
|
+
# NSMutableOrderedSet *set = [NSMutableOrderedSet new];
|
39
|
+
# for (NSString *localeId in identifiers) {
|
40
|
+
# NSString *langCode = [NSLocale canonicalLanguageIdentifierFromString:localeId];
|
41
|
+
# [set addObject:langCode];
|
42
|
+
# }
|
43
|
+
#
|
44
|
+
# for (NSString *langCode in set) {
|
45
|
+
# printf("\"%s\",", [langCode cStringUsingEncoding:NSUTF8StringEncoding]);
|
46
|
+
# }
|
47
|
+
LANGUAGE_CODES = {
|
48
|
+
RunLoop::Version.new("10.0") => [
|
49
|
+
"af","af-NA","af-ZA","agq","agq-CM","ak","ak-GH","am","am-ET","ar","ar-001","ar-AE","ar-BH","ar-DJ","ar-DZ","ar-EG","ar-EH","ar-ER","ar-IL","ar-IQ","ar-JO","ar-KM","ar-KW","ar-LB","ar-LY","ar-MA","ar-MR","ar-OM","ar-PS","ar-QA","ar-SA","ar-SD","ar-SO","ar-SS","ar-SY","ar-TD","ar-TN","ar-YE","ars","as","as-IN","asa","asa-TZ","ast","ast-ES","az","az-Cyrl","az-Cyrl-AZ","az-AZ","bas","bas-CM","be","be-BY","bem","bem-ZM","bez","bez-TZ","bg","bg-BG","bm","bm-ML","bn","bn-BD","bn-IN","bo","bo-CN","bo-IN","br","br-FR","brx","brx-IN","bs","bs-Cyrl","bs-Cyrl-BA","bs-BA","ca","ca-AD","ca-ES","ca-FR","ca-IT","ce","ce-RU","cgg","cgg-UG","chr","chr-US","ckb","ckb-IQ","ckb-IR","cs","cs-CZ","cy","cy-GB","da","da-DK","da-GL","dav","dav-KE","de","de-AT","de-BE","de-CH","de-DE","de-LI","de-LU","dje","dje-NE","dsb","dsb-DE","dua","dua-CM","dyo","dyo-SN","dz","dz-BT","ebu","ebu-KE","ee","ee-GH","ee-TG","el","el-CY","el-GR","en","en-001","en-150","en-AD","en-AG","en-AI","en-AL","en-AS","en-AT","en-AU","en-BA","en-BB","en-BE","en-BI","en-BM","en-BR","en-BS","en-BW","en-BZ","en-CA","en-CC","en-CH","en-CK","en-CM","en-CN","en-CX","en-CY","en-CZ","en-DE","en-DG","en-DK","en-DM","en-EE","en-ER","en-ES","en-FI","en-FJ","en-FK","en-FM","en-FR","en-GB","en-GD","en-GG","en-GH","en-GI","en-GM","en-GR","en-GU","en-GY","en-HK","en-HR","en-HU","en-IE","en-IL","en-IM","en-IN","en-IO","en-IS","en-IT","en-JE","en-JM","en-JP","en-KE","en-KI","en-KN","en-KR","en-KY","en-LC","en-LR","en-LS","en-LT","en-LU","en-LV","en-ME","en-MG","en-MH","en-MO","en-MP","en-MS","en-MT","en-MU","en-MV","en-MW","en-MY","en-NA","en-NF","en-NG","en-NL","en-NO","en-NR","en-NU","en-NZ","en-PG","en-PH","en-PK","en-PL","en-PN","en-PR","en-PT","en-PW","en-RO","en-RU","en-RW","en-SB","en-SC","en-SD","en-SE","en-SG","en-SH","en-SI","en-SK","en-SL","en-SS","en-SX","en-SZ","en-TC","en-TK","en-TO","en-TR","en-TT","en-TV","en-TW","en-TZ","en-UG","en-UM","en-US","en-US-POSIX","en-VC","en-VG","en-VI","en-VU","en-WS","en-ZA","en-ZM","en-ZW","eo","es","es-419","es-AR","es-BO","es-CL","es-CO","es-CR","es-CU","es-DO","es-EA","es-EC","es-ES","es-GQ","es-GT","es-HN","es-IC","es-MX","es-NI","es-PA","es-PE","es-PH","es-PR","es-PY","es-SV","es-US","es-UY","es-VE","et","et-EE","eu","eu-ES","ewo","ewo-CM","fa","fa-AF","fa-IR","ff","ff-CM","ff-GN","ff-MR","ff-SN","fi","fi-FI","fil","fil-PH","fo","fo-DK","fo-FO","fr","fr-BE","fr-BF","fr-BI","fr-BJ","fr-BL","fr-CA","fr-CD","fr-CF","fr-CG","fr-CH","fr-CI","fr-CM","fr-DJ","fr-DZ","fr-FR","fr-GA","fr-GF","fr-GN","fr-GP","fr-GQ","fr-HT","fr-KM","fr-LU","fr-MA","fr-MC","fr-MF","fr-MG","fr-ML","fr-MQ","fr-MR","fr-MU","fr-NC","fr-NE","fr-PF","fr-PM","fr-RE","fr-RW","fr-SC","fr-SN","fr-SY","fr-TD","fr-TG","fr-TN","fr-VU","fr-WF","fr-YT","fur","fur-IT","fy","fy-NL","ga","ga-IE","gd","gd-GB","gl","gl-ES","gsw","gsw-CH","gsw-FR","gsw-LI","gu","gu-IN","guz","guz-KE","gv","gv-IM","ha","ha-GH","ha-NE","ha-NG","haw","haw-US","he","he-IL","hi","hi-IN","hr","hr-BA","hr-HR","hsb","hsb-DE","hu","hu-HU","hy","hy-AM","id","id-ID","ig","ig-NG","ii","ii-CN","is","is-IS","it","it-CH","it-IT","it-SM","iu","iu-CA","ja","ja-JP","jgo","jgo-CM","jmc","jmc-TZ","ka","ka-GE","kab","kab-DZ","kam","kam-KE","kde","kde-TZ","kea","kea-CV","khq","khq-ML","ki","ki-KE","kk","kk-KZ","kkj","kkj-CM","kl","kl-GL","kln","kln-KE","km","km-KH","kn","kn-IN","ko","ko-KP","ko-KR","kok","kok-IN","ks","ks-IN","ksb","ksb-TZ","ksf","ksf-CM","ksh","ksh-DE","kw","kw-GB","ky","ky-KG","lag","lag-TZ","lb","lb-LU","lg","lg-UG","lkt","lkt-US","ln","ln-AO","ln-CD","ln-CF","ln-CG","lo","lo-LA","lrc","lrc-IQ","lrc-IR","lt","lt-LT","lu","lu-CD","luo","luo-KE","luy","luy-KE","lv","lv-LV","mas","mas-KE","mas-TZ","mer","mer-KE","mfe","mfe-MU","mg","mg-MG","mgh","mgh-MZ","mgo","mgo-CM","mk","mk-MK","ml","ml-IN","mn","mn-MN","mr","mr-IN","ms","ms-Arab","ms-Arab-BN","ms-Arab-MY","ms-BN","ms-MY","ms-SG","mt","mt-MT","mua","mua-CM","my","my-MM","mzn","mzn-IR","naq","naq-NA","nb","nb-NO","nb-SJ","nd","nd-ZW","ne","ne-IN","ne-NP","nl","nl-AW","nl-BE","nl-BQ","nl-CW","nl-NL","nl-SR","nl-SX","nmg","nmg-CM","nn","nn-NO","nnh","nnh-CM","nus","nus-SS","nyn","nyn-UG","om","om-ET","om-KE","or","or-IN","os","os-GE","os-RU","pa","pa-Arab","pa-Arab-PK","pa-IN","pl","pl-PL","ps","ps-AF","pt","pt-AO","pt-BR","pt-CV","pt-GW","pt-MO","pt-MZ","pt-PT","pt-ST","pt-TL","qu","qu-BO","qu-EC","qu-PE","rm","rm-CH","rn","rn-BI","ro","ro-MD","ro-RO","rof","rof-TZ","ru","ru-BY","ru-KG","ru-KZ","ru-MD","ru-RU","ru-UA","rw","rw-RW","rwk","rwk-TZ","sah","sah-RU","saq","saq-KE","sbp","sbp-TZ","se","se-FI","se-NO","se-SE","seh","seh-MZ","ses","ses-ML","sg","sg-CF","shi","shi-MA","shi-Tfng","shi-Tfng-MA","si","si-LK","sk","sk-SK","sl","sl-SI","smn","smn-FI","sn","sn-ZW","so","so-DJ","so-ET","so-KE","so-SO","sq","sq-AL","sq-MK","sq-XK","sr","sr-BA","sr-ME","sr-RS","sr-XK","sr-Latn","sr-Latn-BA","sr-Latn-ME","sr-Latn-RS","sr-Latn-XK","sv","sv-AX","sv-FI","sv-SE","sw","sw-CD","sw-KE","sw-TZ","sw-UG","ta","ta-IN","ta-LK","ta-MY","ta-SG","te","te-IN","teo","teo-KE","teo-UG","tg","tg-TJ","th","th-TH","ti","ti-ER","ti-ET","tk","tk-TM","to","to-TO","tr","tr-CY","tr-TR","twq","twq-NE","tzm","tzm-MA","ug","ug-CN","uk","uk-UA","ur","ur-IN","ur-PK","uz","uz-Arab","uz-Arab-AF","uz-UZ","uz-Latn","uz-Latn-UZ","vai","vai-Latn","vai-Latn-LR","vai-LR","vi","vi-VN","vun","vun-TZ","wae","wae-CH","xog","xog-UG","yav","yav-CM","yi","yi-001","yo","yo-BJ","yo-NG","yue","yue-HK","zgh","zgh-MA","zh","zh-Hans","zh-Hans-CN","zh-Hans-HK","zh-Hans-MO","zh-Hans-SG","zh-Hant","zh-Hant-HK","zh-Hant-MO","zh-Hant-TW","zu","zu-ZA"
|
50
|
+
],
|
51
|
+
|
52
|
+
RunLoop::Version.new("9.0") => [
|
53
|
+
"af","af-NA","af-ZA","agq","agq-CM","ak","ak-GH","am","am-ET","ar","ar-001","ar-AE","ar-BH","ar-DJ","ar-DZ","ar-EG","ar-EH","ar-ER","ar-IL","ar-IQ","ar-JO","ar-KM","ar-KW","ar-LB","ar-LY","ar-MA","ar-MR","ar-OM","ar-PS","ar-QA","ar-SA","ar-SD","ar-SO","ar-SS","ar-SY","ar-TD","ar-TN","ar-YE","as","as-IN","asa","asa-TZ","az","az-Cyrl","az-Cyrl-AZ","az-AZ","bas","bas-CM","be","be-BY","bem","bem-ZM","bez","bez-TZ","bg","bg-BG","bm","bm-ML","bn","bn-BD","bn-IN","bo","bo-CN","bo-IN","br","br-FR","brx","brx-IN","bs","bs-Cyrl","bs-Cyrl-BA","bs-BA","ca","ca-AD","ca-ES","ca-FR","ca-IT","cgg","cgg-UG","chr","chr-US","ckb","ckb-IQ","ckb-IR","cs","cs-CZ","cy","cy-GB","da","da-DK","da-GL","dav","dav-KE","de","de-AT","de-BE","de-CH","de-DE","de-LI","de-LU","dje","dje-NE","dsb","dsb-DE","dua","dua-CM","dyo","dyo-SN","dz","dz-BT","ebu","ebu-KE","ee","ee-GH","ee-TG","el","el-CY","el-GR","en","en-001","en-150","en-AD","en-AG","en-AI","en-AL","en-AS","en-AT","en-AU","en-BA","en-BB","en-BE","en-BM","en-BS","en-BW","en-BZ","en-CA","en-CC","en-CH","en-CK","en-CM","en-CX","en-CY","en-CZ","en-DE","en-DG","en-DK","en-DM","en-EE","en-ER","en-ES","en-FI","en-FJ","en-FK","en-FM","en-FR","en-GB","en-GD","en-GG","en-GH","en-GI","en-GM","en-GR","en-GU","en-GY","en-HK","en-HR","en-HU","en-IE","en-IL","en-IM","en-IN","en-IO","en-IS","en-IT","en-JE","en-JM","en-KE","en-KI","en-KN","en-KY","en-LC","en-LR","en-LS","en-LT","en-LU","en-LV","en-ME","en-MG","en-MH","en-MO","en-MP","en-MS","en-MT","en-MU","en-MW","en-MY","en-NA","en-NF","en-NG","en-NL","en-NO","en-NR","en-NU","en-NZ","en-PG","en-PH","en-PK","en-PL","en-PN","en-PR","en-PT","en-PW","en-RO","en-RU","en-RW","en-SB","en-SC","en-SD","en-SE","en-SG","en-SH","en-SI","en-SK","en-SL","en-SS","en-SX","en-SZ","en-TC","en-TK","en-TO","en-TR","en-TT","en-TV","en-TZ","en-UG","en-UM","en-US","en-US-POSIX","en-VC","en-VG","en-VI","en-VU","en-WS","en-ZA","en-ZM","en-ZW","eo","es","es-419","es-AR","es-BO","es-CL","es-CO","es-CR","es-CU","es-DO","es-EA","es-EC","es-ES","es-GQ","es-GT","es-HN","es-IC","es-MX","es-NI","es-PA","es-PE","es-PH","es-PR","es-PY","es-SV","es-US","es-UY","es-VE","et","et-EE","eu","eu-ES","ewo","ewo-CM","fa","fa-AF","fa-IR","ff","ff-CM","ff-GN","ff-MR","ff-SN","fi","fi-FI","fil","fil-PH","fo","fo-FO","fr","fr-BE","fr-BF","fr-BI","fr-BJ","fr-BL","fr-CA","fr-CD","fr-CF","fr-CG","fr-CH","fr-CI","fr-CM","fr-DJ","fr-DZ","fr-FR","fr-GA","fr-GF","fr-GN","fr-GP","fr-GQ","fr-HT","fr-KM","fr-LU","fr-MA","fr-MC","fr-MF","fr-MG","fr-ML","fr-MQ","fr-MR","fr-MU","fr-NC","fr-NE","fr-PF","fr-PM","fr-RE","fr-RW","fr-SC","fr-SN","fr-SY","fr-TD","fr-TG","fr-TN","fr-VU","fr-WF","fr-YT","fur","fur-IT","fy","fy-NL","ga","ga-IE","gd","gd-GB","gl","gl-ES","gsw","gsw-CH","gsw-FR","gsw-LI","gu","gu-IN","guz","guz-KE","gv","gv-IM","ha","ha-GH","ha-NE","ha-NG","haw","haw-US","he","he-IL","hi","hi-IN","hr","hr-BA","hr-HR","hsb","hsb-DE","hu","hu-HU","hy","hy-AM","id","id-ID","ig","ig-NG","ii","ii-CN","is","is-IS","it","it-CH","it-IT","it-SM","iu","iu-Cans","iu-Cans-CA","ja","ja-JP","jgo","jgo-CM","jmc","jmc-TZ","ka","ka-GE","kab","kab-DZ","kam","kam-KE","kde","kde-TZ","kea","kea-CV","khq","khq-ML","ki","ki-KE","kk","kk-KZ","kkj","kkj-CM","kl","kl-GL","kln","kln-KE","km","km-KH","kn","kn-IN","ko","ko-KP","ko-KR","kok","kok-IN","ks","ks-Arab","ks-Arab-IN","ksb","ksb-TZ","ksf","ksf-CM","ksh","ksh-DE","kw","kw-GB","ky","ky-KG","lag","lag-TZ","lb","lb-LU","lg","lg-UG","lkt","lkt-US","ln","ln-AO","ln-CD","ln-CF","ln-CG","lo","lo-LA","lt","lt-LT","lu","lu-CD","luo","luo-KE","luy","luy-KE","lv","lv-LV","mas","mas-KE","mas-TZ","mer","mer-KE","mfe","mfe-MU","mg","mg-MG","mgh","mgh-MZ","mgo","mgo-CM","mk","mk-MK","ml","ml-IN","mn","mn-MN","mr","mr-IN","ms","ms-Arab","ms-Arab-BN","ms-Arab-MY","ms-BN","ms-MY","ms-SG","mt","mt-MT","mua","mua-CM","my","my-MM","naq","naq-NA","nb","nb-NO","nb-SJ","nd","nd-ZW","ne","ne-IN","ne-NP","nl","nl-AW","nl-BE","nl-BQ","nl-CW","nl-NL","nl-SR","nl-SX","nmg","nmg-CM","nn","nn-NO","nnh","nnh-CM","nus","nus-SD","nyn","nyn-UG","om","om-ET","om-KE","or","or-IN","os","os-GE","os-RU","pa","pa-Arab","pa-Arab-PK","pa-IN","pl","pl-PL","ps","ps-AF","pt","pt-AO","pt-BR","pt-CV","pt-GW","pt-MO","pt-MZ","pt-PT","pt-ST","pt-TL","qu","qu-BO","qu-EC","qu-PE","rm","rm-CH","rn","rn-BI","ro","ro-MD","ro-RO","rof","rof-TZ","ru","ru-BY","ru-KG","ru-KZ","ru-MD","ru-RU","ru-UA","rw","rw-RW","rwk","rwk-TZ","sah","sah-RU","saq","saq-KE","sbp","sbp-TZ","se","se-FI","se-NO","se-SE","seh","seh-MZ","ses","ses-ML","sg","sg-CF","shi","shi-MA","shi-Tfng","shi-Tfng-MA","si","si-LK","sk","sk-SK","sl","sl-SI","smn","smn-FI","sn","sn-ZW","so","so-DJ","so-ET","so-KE","so-SO","sq","sq-AL","sq-MK","sq-XK","sr","sr-BA","sr-ME","sr-RS","sr-XK","sr-Latn","sr-Latn-BA","sr-Latn-ME","sr-Latn-RS","sr-Latn-XK","sv","sv-AX","sv-FI","sv-SE","sw","sw-CD","sw-KE","sw-TZ","sw-UG","ta","ta-IN","ta-LK","ta-MY","ta-SG","te","te-IN","teo","teo-KE","teo-UG","tg","tg-TJ","th","th-TH","ti","ti-ER","ti-ET","tk","tk-TM","to","to-TO","tr","tr-CY","tr-TR","twq","twq-NE","tzm","tzm-MA","ug","ug-Arab","ug-Arab-CN","uk","uk-UA","ur","ur-IN","ur-PK","uz","uz-Arab","uz-Arab-AF","uz-UZ","uz-Latn","uz-Latn-UZ","vai","vai-Latn","vai-Latn-LR","vai-LR","vi","vi-VN","vun","vun-TZ","wae","wae-CH","xog","xog-UG","yav","yav-CM","yi","yi-001","yo","yo-BJ","yo-NG","zgh","zgh-MA","zh","zh-Hans","zh-Hans-CN","zh-Hans-HK","zh-Hans-MO","zh-Hans-SG","zh-Hant","zh-Hant-HK","zh-Hant-MO","zh-Hant-TW","zu","zu-ZA",
|
54
|
+
],
|
55
|
+
|
56
|
+
RunLoop::Version.new("8.0") => [
|
57
|
+
"af","af-NA","af-ZA","agq","agq-CM","ak","ak-GH","am","am-ET","ar","ar-001","ar-AE","ar-BH","ar-DJ","ar-DZ","ar-EG","ar-EH","ar-ER","ar-IL","ar-IQ","ar-JO","ar-KM","ar-KW","ar-LB","ar-LY","ar-MA","ar-MR","ar-OM","ar-PS","ar-QA","ar-SA","ar-SD","ar-SO","ar-SS","ar-SY","ar-TD","ar-TN","ar-YE","as","as-IN","asa","asa-TZ","az","az-Cyrl","az-Cyrl-AZ","az-AZ","bas","bas-CM","be","be-BY","bem","bem-ZM","bez","bez-TZ","bg","bg-BG","bm","bm-ML","bn","bn-BD","bn-IN","bo","bo-CN","bo-IN","br","br-FR","brx","brx-IN","bs","bs-Cyrl","bs-Cyrl-BA","bs-BA","ca","ca-AD","ca-ES","ca-FR","ca-IT","cgg","cgg-UG","chr","chr-US","ckb","cs","cs-CZ","cy","cy-GB","da","da-DK","da-GL","dav","dav-KE","de","de-AT","de-BE","de-CH","de-DE","de-LI","de-LU","dje","dje-NE","dua","dua-CM","dyo","dyo-SN","dz","dz-BT","ebu","ebu-KE","ee","ee-GH","ee-TG","el","el-CY","el-GR","en","en-001","en-150","en-AD","en-AG","en-AI","en-AL","en-AS","en-AT","en-AU","en-BA","en-BB","en-BE","en-BM","en-BS","en-BW","en-BZ","en-CA","en-CC","en-CH","en-CK","en-CM","en-CX","en-CY","en-CZ","en-DE","en-DG","en-DK","en-DM","en-EE","en-ER","en-ES","en-FI","en-FJ","en-FK","en-FM","en-FR","en-GB","en-GD","en-GG","en-GH","en-GI","en-GM","en-GU","en-GY","en-HK","en-HR","en-HU","en-IE","en-IM","en-IN","en-IO","en-IS","en-IT","en-JE","en-JM","en-KE","en-KI","en-KN","en-KY","en-LC","en-LR","en-LS","en-LT","en-LU","en-LV","en-ME","en-MG","en-MH","en-MO","en-MP","en-MS","en-MT","en-MU","en-MW","en-NA","en-NF","en-NG","en-NL","en-NO","en-NR","en-NU","en-NZ","en-PG","en-PH","en-PK","en-PL","en-PN","en-PR","en-PT","en-PW","en-RO","en-RU","en-RW","en-SB","en-SC","en-SD","en-SE","en-SG","en-SH","en-SI","en-SK","en-SL","en-SS","en-SX","en-SZ","en-TC","en-TK","en-TO","en-TR","en-TT","en-TV","en-TZ","en-UG","en-UM","en-US","en-US-POSIX","en-VC","en-VG","en-VI","en-VU","en-WS","en-ZA","en-ZM","en-ZW","eo","es","es-419","es-AR","es-BO","es-CL","es-CO","es-CR","es-CU","es-DO","es-EA","es-EC","es-ES","es-GQ","es-GT","es-HN","es-IC","es-MX","es-NI","es-PA","es-PE","es-PH","es-PR","es-PY","es-SV","es-US","es-UY","es-VE","et","et-EE","eu","eu-ES","ewo","ewo-CM","fa","fa-AF","fa-IR","ff","ff-SN","fi","fi-FI","fil","fil-PH","fo","fo-FO","fr","fr-BE","fr-BF","fr-BI","fr-BJ","fr-BL","fr-CA","fr-CD","fr-CF","fr-CG","fr-CH","fr-CI","fr-CM","fr-DJ","fr-DZ","fr-FR","fr-GA","fr-GF","fr-GN","fr-GP","fr-GQ","fr-HT","fr-KM","fr-LU","fr-MA","fr-MC","fr-MF","fr-MG","fr-ML","fr-MQ","fr-MR","fr-MU","fr-NC","fr-NE","fr-PF","fr-PM","fr-RE","fr-RW","fr-SC","fr-SN","fr-SY","fr-TD","fr-TG","fr-TN","fr-VU","fr-WF","fr-YT","ga","ga-IE","gl","gl-ES","gsw","gsw-CH","gsw-LI","gu","gu-IN","guz","guz-KE","gv","gv-IM","ha","ha-GH","ha-NE","ha-NG","haw","haw-US","he","he-IL","hi","hi-IN","hr","hr-BA","hr-HR","hu","hu-HU","hy","hy-AM","id","id-ID","ig","ig-NG","ii","ii-CN","is","is-IS","it","it-CH","it-IT","it-SM","iu","iu-Cans","iu-Cans-CA","ja","ja-JP","jgo","jgo-CM","jmc","jmc-TZ","ka","ka-GE","kab","kab-DZ","kam","kam-KE","kde","kde-TZ","kea","kea-CV","khq","khq-ML","ki","ki-KE","kk","kk-KZ","kkj","kkj-CM","kl","kl-GL","kln","kln-KE","km","km-KH","kn","kn-IN","ko","ko-KP","ko-KR","kok","kok-IN","ks","ks-Arab","ks-Arab-IN","ksb","ksb-TZ","ksf","ksf-CM","kw","kw-GB","ky","ky-KG","lag","lag-TZ","lg","lg-UG","lkt","lkt-US","ln","ln-AO","ln-CD","ln-CF","ln-CG","lo","lo-LA","lt","lt-LT","lu","lu-CD","luo","luo-KE","luy","luy-KE","lv","lv-LV","mas","mas-KE","mas-TZ","mer","mer-KE","mfe","mfe-MU","mg","mg-MG","mgh","mgh-MZ","mgo","mgo-CM","mk","mk-MK","ml","ml-IN","mn","mn-MN","mr","mr-IN","ms","ms-Arab","ms-Arab-BN","ms-Arab-MY","ms-BN","ms-MY","ms-SG","mt","mt-MT","mua","mua-CM","my","my-MM","naq","naq-NA","nb","nb-NO","nb-SJ","nd","nd-ZW","ne","ne-IN","ne-NP","nl","nl-AW","nl-BE","nl-BQ","nl-CW","nl-NL","nl-SR","nl-SX","nmg","nmg-CM","nn","nn-NO","nnh","nnh-CM","nus","nus-SD","nyn","nyn-UG","om","om-ET","om-KE","or","or-IN","pa","pa-Arab","pa-Arab-PK","pa-IN","pl","pl-PL","ps","ps-AF","pt","pt-AO","pt-BR","pt-CV","pt-GW","pt-MO","pt-MZ","pt-PT","pt-ST","pt-TL","rm","rm-CH","rn","rn-BI","ro","ro-MD","ro-RO","rof","rof-TZ","ru","ru-BY","ru-KG","ru-KZ","ru-MD","ru-RU","ru-UA","rw","rw-RW","rwk","rwk-TZ","saq","saq-KE","sbp","sbp-TZ","seh","seh-MZ","ses","ses-ML","sg","sg-CF","shi","shi-MA","shi-Tfng","shi-Tfng-MA","si","si-LK","sk","sk-SK","sl","sl-SI","sn","sn-ZW","so","so-DJ","so-ET","so-KE","so-SO","sq","sq-AL","sq-MK","sq-XK","sr","sr-BA","sr-ME","sr-RS","sr-XK","sr-Latn","sr-Latn-BA","sr-Latn-ME","sr-Latn-RS","sr-Latn-XK","sv","sv-AX","sv-FI","sv-SE","sw","sw-KE","sw-TZ","sw-UG","swc","swc-CD","ta","ta-IN","ta-LK","ta-MY","ta-SG","te","te-IN","teo","teo-KE","teo-UG","tg","tg-TJ","th","th-TH","ti","ti-ER","ti-ET","tk","tk-TM","to","to-TO","tr","tr-CY","tr-TR","twq","twq-NE","tzm","tzm-MA","ug","ug-Arab","ug-Arab-CN","uk","uk-UA","ur","ur-IN","ur-PK","uz","uz-Arab","uz-Arab-AF","uz-UZ","uz-Latn","uz-Latn-UZ","vai","vai-Latn","vai-Latn-LR","vai-LR","vi","vi-VN","vun","vun-TZ","xog","xog-UG","yav","yav-CM","yo","yo-BJ","yo-NG","zgh","zgh-MA","zh","zh-Hans","zh-Hans-CN","zh-Hans-HK","zh-Hans-MO","zh-Hans-SG","zh-Hant","zh-Hant-HK","zh-Hant-MO","zh-Hant-TW","zu","zu-ZA",
|
58
|
+
]
|
59
|
+
}.freeze
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module RunLoop
|
4
|
+
|
5
|
+
# An error class for signaling an incompatible architecture.
|
6
|
+
class IncompatibleArchitecture < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# A class for interacting with the lipo command-line tool to verify that an
|
10
|
+
# executable is valid for the test target (device or simulator).
|
11
|
+
#
|
12
|
+
# @note All lipo commands are run in the context of `xcrun`.
|
13
|
+
class Lipo
|
14
|
+
|
15
|
+
# The path to the application bundle we are inspecting.
|
16
|
+
# @!attribute [wr] bundle_path
|
17
|
+
# @return [String] The path to the application bundle (.app).
|
18
|
+
attr_accessor :bundle_path
|
19
|
+
|
20
|
+
def initialize(bundle_path)
|
21
|
+
@bundle_path = bundle_path
|
22
|
+
@plist_buddy = RunLoop::PlistBuddy.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @!visibility private
|
26
|
+
def to_s
|
27
|
+
"#<Lipo #{bundle_path}>"
|
28
|
+
end
|
29
|
+
|
30
|
+
# @!visibility private
|
31
|
+
def inspect
|
32
|
+
to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
# Inspect the `CFBundleExecutable` in the app bundle path with `lipo` and
|
36
|
+
# compare the result with the target device's instruction set.
|
37
|
+
#
|
38
|
+
# **Simulators**
|
39
|
+
#
|
40
|
+
# If the target is a simulator and the binary contains an i386 slice, the
|
41
|
+
# app will launch on the 64-bit simulators.
|
42
|
+
#
|
43
|
+
# If the target is a simulator and the binary contains _only_ an x86_64
|
44
|
+
# slice, the app will not launch on these simulators:
|
45
|
+
#
|
46
|
+
# ```
|
47
|
+
# iPhone 4S, iPad 2, iPhone 5, and iPad Retina.
|
48
|
+
# ```
|
49
|
+
#
|
50
|
+
# All other simulators are 64-bit.
|
51
|
+
#
|
52
|
+
# **Devices**
|
53
|
+
#
|
54
|
+
# @see {https://www.innerfence.com/howto/apple-ios-devices-dates-versions-instruction-sets}
|
55
|
+
#
|
56
|
+
# ```
|
57
|
+
# armv7 <== 3gs, 4s, iPad 2, iPad mini, iPad 3, iPod 3, iPod 4, iPod 5
|
58
|
+
# armv7s <== 5, 5c, iPad 4
|
59
|
+
# arm64 <== 5s, 6, 6 Plus, Air, Air 2, iPad Mini Retina, iPad Mini 3
|
60
|
+
# ```
|
61
|
+
#
|
62
|
+
# @note At the moment, we are focusing on simulator compatibility. Since we
|
63
|
+
# don't have an automated way of installing an .ipa on local device, we
|
64
|
+
# don't require an .ipa path. Without an .ipa path, we cannot verify the
|
65
|
+
# architectures. Further, we would need to adopt a third-party tool like
|
66
|
+
# ideviceinfo to find the target device's instruction set.
|
67
|
+
# @param [RunLoop::Device] device The test target.
|
68
|
+
# @raise [RuntimeError] Raises an error if the device is a physical device.
|
69
|
+
# @raise [RunLoop::IncompatibleArchitecture] Raises an error if the instruction set of the target
|
70
|
+
# device is not compatible with the executable in the application.
|
71
|
+
def expect_compatible_arch(device)
|
72
|
+
if device.physical_device?
|
73
|
+
raise 'Ensuring compatible arches for physical devices is NYI'
|
74
|
+
else
|
75
|
+
arches = self.info
|
76
|
+
# An i386 binary will run on any simulator.
|
77
|
+
return true if arches.include?('i386')
|
78
|
+
|
79
|
+
instruction_set = device.instruction_set
|
80
|
+
unless arches.include?(instruction_set)
|
81
|
+
raise RunLoop::IncompatibleArchitecture,
|
82
|
+
['Binary at:',
|
83
|
+
binary_path,
|
84
|
+
'does not contain a compatible architecture for target device.',
|
85
|
+
"Expected '#{instruction_set}' but found #{arches}."].join("\n")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns a list of architecture in the binary.
|
91
|
+
# @return [Array<String>] A list of architecture.
|
92
|
+
# @raise [RuntimeError] If the output of lipo cannot be parsed.
|
93
|
+
def info
|
94
|
+
execute_lipo("-info \"#{binary_path}\"") do |stdout, stderr, wait_thr|
|
95
|
+
output = stdout.read.strip
|
96
|
+
begin
|
97
|
+
output.split(':')[-1].strip.split
|
98
|
+
rescue StandardError => e
|
99
|
+
msg = ['Expected to be able to parse the output of lipo.',
|
100
|
+
"cmd: 'lipo -info \"#{binary_path}\"'",
|
101
|
+
"stdout: '#{output}'",
|
102
|
+
"stderr: '#{stderr.read.strip}'",
|
103
|
+
"exit code: '#{wait_thr.value}'",
|
104
|
+
e.message]
|
105
|
+
raise msg.join("\n")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# Caller is responsible for correctly escaping arguments.
|
113
|
+
# For example, the caller must proper quote `"` paths to avoid errors
|
114
|
+
# when dealing with paths that contain spaces.
|
115
|
+
# @todo #execute_lipo should take an [] of arguments
|
116
|
+
def execute_lipo(argument)
|
117
|
+
command = "xcrun lipo #{argument}"
|
118
|
+
Open3.popen3(command) do |_, stdout, stderr, wait_thr|
|
119
|
+
yield stdout, stderr, wait_thr
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def plist_path
|
124
|
+
File.join(@bundle_path, 'Info.plist');
|
125
|
+
end
|
126
|
+
|
127
|
+
def binary_path
|
128
|
+
binary_relative_path = @plist_buddy.plist_read('CFBundleExecutable', plist_path)
|
129
|
+
File.join(@bundle_path, binary_relative_path)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RunLoop
|
2
|
+
|
3
|
+
# A class for interacting with the lldb command-line tool
|
4
|
+
class LLDB
|
5
|
+
|
6
|
+
# Returns a list of lldb pids.
|
7
|
+
# @return [Array<Integer>] An array of integer pids.
|
8
|
+
def self.lldb_pids
|
9
|
+
ps_output = `#{LLDB_FIND_PIDS_CMD}`.strip
|
10
|
+
lines = ps_output.lines("\n").map { |line| line.strip }
|
11
|
+
lldb_processes = lines.select { |line| self.is_lldb_process?(line) }
|
12
|
+
lldb_processes.map do |ps_description|
|
13
|
+
tokens = ps_description.strip.split(' ').map { |token| token.strip }
|
14
|
+
pid = tokens.fetch(0, nil)
|
15
|
+
if pid.nil?
|
16
|
+
nil
|
17
|
+
else
|
18
|
+
pid.to_i
|
19
|
+
end
|
20
|
+
end.compact.sort
|
21
|
+
end
|
22
|
+
|
23
|
+
# @!visibility private
|
24
|
+
# Is the process described an lldb process?
|
25
|
+
#
|
26
|
+
# @param [String] ps_details Details about a process as returned by `ps`
|
27
|
+
# @return [Boolean] True if the details describe an lldb process.
|
28
|
+
def self.is_lldb_process?(ps_details)
|
29
|
+
return false if ps_details.nil?
|
30
|
+
ps_details[/Contents\/Developer\/usr\/bin\/lldb/, 0] != nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Attempts to gracefully kill all running lldb processes.
|
34
|
+
def self.kill_lldb_processes
|
35
|
+
self.lldb_pids.each do |pid|
|
36
|
+
self.kill_with_signal(pid, 'KILL')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @!visibility private
|
43
|
+
LLDB_FIND_PIDS_CMD = 'ps x -o pid,command | grep -v grep | grep lldb'
|
44
|
+
|
45
|
+
# @!visibility private
|
46
|
+
def self.kill_with_signal(pid, signal)
|
47
|
+
options = {:timeout => 1.0, :delay => 0.1}
|
48
|
+
RunLoop::ProcessTerminator.new(pid, signal, 'lldb', options).kill_process
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|