run_loop 1.1.1.pre7 → 1.1.1.pre8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/run_loop.rb +2 -0
- data/lib/run_loop/core.rb +51 -8
- data/lib/run_loop/device.rb +36 -12
- data/lib/run_loop/lipo.rb +107 -0
- data/lib/run_loop/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9340394da27267a6ea43ce6a61c2cb018faf97ff
|
4
|
+
data.tar.gz: 54d9b6db6739d00d5895b7d6108b8fd374f51aa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9cbcdcee2fe866606caff3ec4609375777617a2de2ea216f314662539b2addda8ae42562bba6b624355a8398500568e442f7f8ac4980cd96e08dccfd047b54cf
|
7
|
+
data.tar.gz: 83bb516e414e2e1c05a1cc63f45e32194c2dbc3359c52894a406f48fd9b93b759f3adc5aef026060d0a4a66c5f8900a24e5be2b183a2f9c055c1c120eda3f8b2
|
data/lib/run_loop.rb
CHANGED
data/lib/run_loop/core.rb
CHANGED
@@ -83,6 +83,48 @@ module RunLoop
|
|
83
83
|
nil
|
84
84
|
end
|
85
85
|
|
86
|
+
# Raise an error if the application binary is not compatible with the
|
87
|
+
# target simulator.
|
88
|
+
#
|
89
|
+
# @note This method is implemented for CoreSimulator environments only;
|
90
|
+
# for Xcode < 6.0 this method does nothing.
|
91
|
+
#
|
92
|
+
# @param [Hash] launch_options These options need to contain the app bundle
|
93
|
+
# path and a udid that corresponds to a simulator name or simulator udid.
|
94
|
+
# In practical terms: call this after merging the original launch
|
95
|
+
# options with those options that are discovered.
|
96
|
+
#
|
97
|
+
# @param [RunLoop::SimControl] sim_control A simulator control object.
|
98
|
+
# @raise [RuntimeError] Raises an error if the `launch_options[:udid]`
|
99
|
+
# cannot be used to find a simulator.
|
100
|
+
# @raise [RunLoop::IncompatibleArchitecture] Raises an error if the
|
101
|
+
# application binary is not compatible with the target simulator.
|
102
|
+
def self.expect_compatible_simulator_architecture(launch_options, sim_control)
|
103
|
+
if sim_control.xcode_version_gte_6?
|
104
|
+
sim_identifier = launch_options[:udid]
|
105
|
+
simulator = sim_control.simulators.find do |simulator|
|
106
|
+
[simulator.instruments_identifier(sim_control.xctools),
|
107
|
+
simulator.udid].include?(sim_identifier)
|
108
|
+
end
|
109
|
+
|
110
|
+
if simulator.nil?
|
111
|
+
raise "Could not find simulator with identifier '#{sim_identifier}'"
|
112
|
+
end
|
113
|
+
|
114
|
+
lipo = RunLoop::Lipo.new(launch_options[:bundle_dir_or_bundle_id])
|
115
|
+
lipo.expect_compatible_arch(simulator)
|
116
|
+
if ENV['DEBUG'] == '1'
|
117
|
+
puts "Simulator instruction set '#{simulator.instruction_set}' is compatible with #{lipo.info}"
|
118
|
+
end
|
119
|
+
true
|
120
|
+
else
|
121
|
+
if ENV['DEBUG'] == '1'
|
122
|
+
puts "Xcode #{sim_control.xctools.xcode_version} detected; skipping simulator architecture check."
|
123
|
+
end
|
124
|
+
false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
86
128
|
def self.run_with_options(options)
|
87
129
|
before = Time.now
|
88
130
|
|
@@ -91,11 +133,6 @@ module RunLoop
|
|
91
133
|
|
92
134
|
RunLoop::Instruments.new.kill_instruments(xctools)
|
93
135
|
|
94
|
-
if self.simulator_target?(options, sim_control)
|
95
|
-
# @todo only enable accessibility on the targeted simulator
|
96
|
-
sim_control.enable_accessibility_on_sims({:verbose => false})
|
97
|
-
end
|
98
|
-
|
99
136
|
device_target = options[:udid] || options[:device_target] || detect_connected_device || 'simulator'
|
100
137
|
if device_target && device_target.to_s.downcase == 'device'
|
101
138
|
device_target = detect_connected_device
|
@@ -150,7 +187,7 @@ module RunLoop
|
|
150
187
|
log_file ||= File.join(results_dir, 'run_loop.out')
|
151
188
|
|
152
189
|
after = Time.now
|
153
|
-
if ENV['DEBUG']=='1'
|
190
|
+
if ENV['DEBUG'] == '1'
|
154
191
|
puts "Preparation took #{after-before} seconds"
|
155
192
|
end
|
156
193
|
|
@@ -166,6 +203,12 @@ module RunLoop
|
|
166
203
|
}
|
167
204
|
merged_options = options.merge(discovered_options)
|
168
205
|
|
206
|
+
if self.simulator_target?(merged_options, sim_control)
|
207
|
+
# @todo only enable accessibility on the targeted simulator
|
208
|
+
sim_control.enable_accessibility_on_sims({:verbose => false})
|
209
|
+
self.expect_compatible_simulator_architecture(merged_options, sim_control)
|
210
|
+
end
|
211
|
+
|
169
212
|
self.log_run_loop_options(merged_options, xctools)
|
170
213
|
|
171
214
|
cmd = instruments_command(merged_options, xctools)
|
@@ -819,9 +862,9 @@ module RunLoop
|
|
819
862
|
script
|
820
863
|
end
|
821
864
|
|
822
|
-
def self.log_info(
|
865
|
+
def self.log_info(logger, message)
|
823
866
|
msg = "#{Time.now}: #{message}"
|
824
|
-
if
|
867
|
+
if logger && logger.respond_to?(:info)
|
825
868
|
logger.info(msg)
|
826
869
|
else
|
827
870
|
puts msg if ENV['DEBUG'] == '1'
|
data/lib/run_loop/device.rb
CHANGED
@@ -17,18 +17,6 @@ module RunLoop
|
|
17
17
|
@udid = udid
|
18
18
|
end
|
19
19
|
|
20
|
-
# Is this device a simulator?
|
21
|
-
# @return [Boolean] Return true if this device is a simulator.
|
22
|
-
def simulator?
|
23
|
-
not physical_device?
|
24
|
-
end
|
25
|
-
|
26
|
-
# Is this is a physical device?
|
27
|
-
# @return [Boolean] Return true if this is a physical device.
|
28
|
-
def physical_device?
|
29
|
-
(self.udid =~ /[a-f0-9]{40}/) == 0
|
30
|
-
end
|
31
|
-
|
32
20
|
# Returns and instruments-ready device identifier that is a suitable value
|
33
21
|
# for DEVICE_TARGET environment variable.
|
34
22
|
#
|
@@ -50,5 +38,41 @@ module RunLoop
|
|
50
38
|
"#{self.name} (#{version_part} Simulator)"
|
51
39
|
end
|
52
40
|
end
|
41
|
+
|
42
|
+
# Is this a physical device?
|
43
|
+
# @return [Boolean] Returns true if this is a device.
|
44
|
+
def physical_device?
|
45
|
+
not self.udid[/[a-f0-9]{40}/, 0].nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
# Is this a simulator?
|
49
|
+
# @return [Boolean] Returns true if this is a simulator.
|
50
|
+
def simulator?
|
51
|
+
not self.physical_device?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return the instruction set for this device.
|
55
|
+
#
|
56
|
+
# **Simulator**
|
57
|
+
# The simulator instruction set will be i386 or x86_64 depending on the
|
58
|
+
# the (marketing) name of the device.
|
59
|
+
#
|
60
|
+
# @note Finding the instruction set of a device requires a third-party tool
|
61
|
+
# like ideviceinfo. Example:
|
62
|
+
# `$ ideviceinfo -u 89b59 < snip > ab7ba --key 'CPUArchitecture' => arm64`
|
63
|
+
#
|
64
|
+
# @raise [RuntimeError] Raises an error if this device is a physical device.
|
65
|
+
# @return [String] An instruction set.
|
66
|
+
def instruction_set
|
67
|
+
if self.simulator?
|
68
|
+
if ['iPhone 4s', 'iPhone 5', 'iPad 2', 'iPad Retina'].include?(self.name)
|
69
|
+
'i386'
|
70
|
+
else
|
71
|
+
'x86_64'
|
72
|
+
end
|
73
|
+
else
|
74
|
+
raise 'Finding the instruction set of a device requires a third-party tool like ideviceinfo'
|
75
|
+
end
|
76
|
+
end
|
53
77
|
end
|
54
78
|
end
|
@@ -0,0 +1,107 @@
|
|
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
|
+
# Inspect the `CFBundleExecutable` in the app bundle path with `lipo` and
|
26
|
+
# compare the result with the target device's instruction set.
|
27
|
+
#
|
28
|
+
# **Simulators**
|
29
|
+
#
|
30
|
+
# If the target is a simulator and the binary contains an i386 slice, the
|
31
|
+
# app will launch on the 64-bit simulators.
|
32
|
+
#
|
33
|
+
# If the target is a simulator and the binary contains _only_ an x86_64
|
34
|
+
# slice, the app will not launch on these simulators:
|
35
|
+
#
|
36
|
+
# ```
|
37
|
+
# iPhone 4S, iPad 2, iPhone 5, and iPad Retina.
|
38
|
+
# ```
|
39
|
+
#
|
40
|
+
# All other simulators are 64-bit.
|
41
|
+
#
|
42
|
+
# **Devices**
|
43
|
+
#
|
44
|
+
# @see {https://www.innerfence.com/howto/apple-ios-devices-dates-versions-instruction-sets}
|
45
|
+
#
|
46
|
+
# ```
|
47
|
+
# armv7 <== 3gs, 4s, iPad 2, iPad mini, iPad 3, iPod 3, iPod 4, iPod 5
|
48
|
+
# armv7s <== 5, 5c, iPad 4
|
49
|
+
# arm64 <== 5s, 6, 6 Plus, Air, Air 2, iPad Mini Retina, iPad Mini 3
|
50
|
+
# ```
|
51
|
+
#
|
52
|
+
# @note At the moment, we are focusing on simulator compatibility. Since we
|
53
|
+
# don't have an automated way of installing an .ipa on local device, we
|
54
|
+
# don't require an .ipa path. Without an .ipa path, we cannot verify the
|
55
|
+
# architectures. Further, we would need to adopt a third-party tool like
|
56
|
+
# ideviceinfo to find the target device's instruction set.
|
57
|
+
# @param [RunLoop::Device] device The test target.
|
58
|
+
# @raise [RuntimeError] Raises an error if the device is a physical device.
|
59
|
+
# @raise [RunLoop::IncompatibleArchitecture] Raises an error if the instruction set of the target
|
60
|
+
# device is not compatible with the executable in the application.
|
61
|
+
def expect_compatible_arch(device)
|
62
|
+
if device.physical_device?
|
63
|
+
raise 'Ensuring compatible arches for physical devices is NYI'
|
64
|
+
else
|
65
|
+
arches = self.info
|
66
|
+
# An i386 binary will run on any simulator.
|
67
|
+
return true if arches.include?('i386')
|
68
|
+
|
69
|
+
instruction_set = device.instruction_set
|
70
|
+
unless arches.include?(instruction_set)
|
71
|
+
raise RunLoop::IncompatibleArchitecture,
|
72
|
+
['Binary at:',
|
73
|
+
binary_path,
|
74
|
+
"does not contain a compatible architecture for target device.",
|
75
|
+
"Expected '#{instruction_set}' but found #{arches}."].join("\n")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns a list of architecture in the binary.
|
81
|
+
# @return [Array<String>] A list of architecture.
|
82
|
+
def info
|
83
|
+
execute_lipo("-info #{binary_path}") do |stdout, _, _|
|
84
|
+
output = stdout.read.strip
|
85
|
+
output.split(':')[-1].strip.split
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def execute_lipo(argument)
|
92
|
+
command = "xcrun lipo #{argument}"
|
93
|
+
Open3.popen3(command) do |_, stdout, stderr, wait_thr|
|
94
|
+
yield stdout, stderr, wait_thr
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def plist_path
|
99
|
+
File.join(@bundle_path, 'Info.plist');
|
100
|
+
end
|
101
|
+
|
102
|
+
def binary_path
|
103
|
+
binary_relative_path = @plist_buddy.plist_read('CFBundleExecutable', plist_path)
|
104
|
+
File.join(@bundle_path, binary_relative_path)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/run_loop/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: run_loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.1.
|
4
|
+
version: 1.1.1.pre8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -222,6 +222,7 @@ files:
|
|
222
222
|
- lib/run_loop/core.rb
|
223
223
|
- lib/run_loop/device.rb
|
224
224
|
- lib/run_loop/instruments.rb
|
225
|
+
- lib/run_loop/lipo.rb
|
225
226
|
- lib/run_loop/plist_buddy.rb
|
226
227
|
- lib/run_loop/sim_control.rb
|
227
228
|
- lib/run_loop/version.rb
|