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
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'run_loop'
|
3
|
+
require 'run_loop/cli/errors'
|
4
|
+
|
5
|
+
module RunLoop
|
6
|
+
module CLI
|
7
|
+
class Instruments < Thor
|
8
|
+
|
9
|
+
attr_accessor :signal
|
10
|
+
|
11
|
+
desc 'quit', 'Send a kill signal to all instruments processes.'
|
12
|
+
|
13
|
+
method_option 'signal',
|
14
|
+
:desc => 'The kill signal to send.',
|
15
|
+
:aliases => '-s',
|
16
|
+
:required => false,
|
17
|
+
:default => 'TERM',
|
18
|
+
:type => :string
|
19
|
+
|
20
|
+
method_option 'debug',
|
21
|
+
:desc => 'Enable debug logging.',
|
22
|
+
:aliases => '-v',
|
23
|
+
:required => false,
|
24
|
+
:default => false,
|
25
|
+
:type => :boolean
|
26
|
+
|
27
|
+
|
28
|
+
def quit
|
29
|
+
signal = options[:signal]
|
30
|
+
ENV['DEBUG'] = '1' if options[:debug]
|
31
|
+
instruments = RunLoop::Instruments.new
|
32
|
+
instruments.instruments_pids.each do |pid|
|
33
|
+
terminator = RunLoop::ProcessTerminator.new(pid, signal, 'instruments')
|
34
|
+
unless terminator.kill_process
|
35
|
+
terminator = RunLoop::ProcessTerminator.new(pid, 'KILL', 'instruments')
|
36
|
+
terminator.kill_process
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
desc 'launch [--app | [--ipa | --bundle-id]] [OPTIONS]', 'Launch an app with instruments.'
|
43
|
+
|
44
|
+
# This is the description we want, but Thor doesn't handle newlines well(?).
|
45
|
+
# long_desc <<EOF
|
46
|
+
# # Launch App.app on a simulator.
|
47
|
+
# $ be run-loop instruments launch --app /path/to/App.app
|
48
|
+
#
|
49
|
+
# # Launch App.ipa on a device; bundle id will be extracted.
|
50
|
+
# $ be run-loop instruments launch --ipa /path/to/App.ipa
|
51
|
+
#
|
52
|
+
# # Launch the app with bundle id on a device.
|
53
|
+
# $ be run-loop instruments launch --bundle-id com.example.MyApp-cal
|
54
|
+
#
|
55
|
+
# You can pass arguments to application as a comma separated list.
|
56
|
+
# --args -NSShowNonLocalizedStrings,YES,-AppleLanguages,(de)
|
57
|
+
# --args -com.apple.CoreData.SQLDebug,3'
|
58
|
+
# EOF
|
59
|
+
|
60
|
+
method_option 'device',
|
61
|
+
:desc => 'The device UDID or simulator identifier.',
|
62
|
+
:aliases => '-d',
|
63
|
+
:required => false,
|
64
|
+
:type => :string
|
65
|
+
|
66
|
+
method_option 'app',
|
67
|
+
:desc => 'Path to a .app bundle to launch on simulator.',
|
68
|
+
:aliases => '-a',
|
69
|
+
:required => false,
|
70
|
+
:type => :string
|
71
|
+
|
72
|
+
method_option 'bundle-id',
|
73
|
+
:desc => 'Bundle id of app to launch on device.',
|
74
|
+
:aliases => '-b',
|
75
|
+
:required => false,
|
76
|
+
:type => :string
|
77
|
+
|
78
|
+
method_option 'template',
|
79
|
+
:desc => 'Path to an automation template.',
|
80
|
+
:aliases => '-t',
|
81
|
+
:required => false,
|
82
|
+
:type => :string
|
83
|
+
|
84
|
+
method_option 'args',
|
85
|
+
:desc => 'Arguments to pass to the app.',
|
86
|
+
:required => false,
|
87
|
+
:type => :string
|
88
|
+
|
89
|
+
method_option 'debug',
|
90
|
+
:desc => 'Enable debug logging.',
|
91
|
+
:aliases => '-v',
|
92
|
+
:required => false,
|
93
|
+
:default => false,
|
94
|
+
:type => :boolean
|
95
|
+
|
96
|
+
def launch
|
97
|
+
|
98
|
+
debug = options[:debug]
|
99
|
+
original_value = ENV['DEBUG']
|
100
|
+
|
101
|
+
ENV['DEBUG'] = '1' if debug
|
102
|
+
|
103
|
+
begin
|
104
|
+
launch_options = {
|
105
|
+
:args => parse_app_launch_args(options),
|
106
|
+
:udid => detect_device_udid_from_options(options),
|
107
|
+
:app => detect_bundle_id_or_bundle_path(options)
|
108
|
+
}
|
109
|
+
run_loop = RunLoop.run(launch_options)
|
110
|
+
puts JSON.generate(run_loop)
|
111
|
+
ensure
|
112
|
+
ENV['DEBUG'] = original_value if debug
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
no_commands do
|
117
|
+
def parse_app_launch_args(options)
|
118
|
+
args = options[:args]
|
119
|
+
if args.nil?
|
120
|
+
[]
|
121
|
+
else
|
122
|
+
args.split(',')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def detect_bundle_id_or_bundle_path(options)
|
127
|
+
app = options[:app]
|
128
|
+
ipa = options[:ipa]
|
129
|
+
bundle_id = options[:bundle_id]
|
130
|
+
|
131
|
+
if app && ipa
|
132
|
+
raise RunLoop::CLI::ValidationError,
|
133
|
+
"--app #{app} and --ipa #{ipa} are mutually exclusive arguments. Pass one or the other, not both."
|
134
|
+
end
|
135
|
+
|
136
|
+
if app && bundle_id
|
137
|
+
raise RunLoop::CLI::ValidationError,
|
138
|
+
"--app #{app} and --bundle-id #{bundle_id} are mutually exclusive arguments. Pass one or the other, not both."
|
139
|
+
end
|
140
|
+
|
141
|
+
if ipa && bundle_id
|
142
|
+
raise RunLoop::CLI::ValidationError,
|
143
|
+
"--ipa #{ipa} and --bundle-id #{bundle_id} are mutually exclusive arguments. Pass one or the other, not both."
|
144
|
+
end
|
145
|
+
app || bundle_id
|
146
|
+
end
|
147
|
+
|
148
|
+
def detect_device_udid_from_options(options)
|
149
|
+
device = options[:device]
|
150
|
+
app = options[:app]
|
151
|
+
if app && !device
|
152
|
+
RunLoop::Core.default_simulator
|
153
|
+
else
|
154
|
+
device
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "run_loop"
|
3
|
+
require "run_loop/cli/errors"
|
4
|
+
|
5
|
+
module RunLoop
|
6
|
+
module CLI
|
7
|
+
class Locale < Thor
|
8
|
+
|
9
|
+
desc "print-alert-regexes", "Print privacy alert regular expressions"
|
10
|
+
|
11
|
+
def print_alert_regexes
|
12
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
13
|
+
scripts_dir = File.join(dir, "..", "..", "..", "scripts")
|
14
|
+
on_alert = File.join(scripts_dir, "lib", "on_alert.js")
|
15
|
+
|
16
|
+
lines = []
|
17
|
+
File.read(on_alert).force_encoding("UTF-8").split($-0).each do |line|
|
18
|
+
if line[/\[\".+\", \/.+\/\]/, 0]
|
19
|
+
line.chomp!
|
20
|
+
if line[-1,1] == ","
|
21
|
+
line = line[0, line.length - 1]
|
22
|
+
end
|
23
|
+
lines << line
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
puts lines.join(",#{$-0}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'run_loop'
|
3
|
+
require 'run_loop/cli/errors'
|
4
|
+
|
5
|
+
module RunLoop
|
6
|
+
module CLI
|
7
|
+
class Simctl < Thor
|
8
|
+
|
9
|
+
attr_reader :simctl
|
10
|
+
|
11
|
+
desc 'tail', 'Tail the log file of the booted simulator'
|
12
|
+
def tail
|
13
|
+
tail_booted
|
14
|
+
end
|
15
|
+
|
16
|
+
no_commands do
|
17
|
+
def tail_booted
|
18
|
+
device = booted_device
|
19
|
+
if device.nil?
|
20
|
+
version = xcode.version
|
21
|
+
puts "No simulator for active Xcode (version #{version}) is booted."
|
22
|
+
else
|
23
|
+
log_file = device.simulator_log_file_path
|
24
|
+
exec('tail', *['-F', log_file])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'booted', 'Prints details about the booted simulator'
|
30
|
+
def booted
|
31
|
+
device = booted_device
|
32
|
+
if device.nil?
|
33
|
+
version = xcode.version
|
34
|
+
puts "No simulator for active Xcode (version #{version}) is booted."
|
35
|
+
else
|
36
|
+
puts device
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'doctor', 'EXPERIMENTAL: Prepare the CoreSimulator environment for testing'
|
41
|
+
|
42
|
+
method_option 'debug',
|
43
|
+
:desc => 'Enable debug logging.',
|
44
|
+
:aliases => '-v',
|
45
|
+
:required => false,
|
46
|
+
:default => false,
|
47
|
+
:type => :boolean
|
48
|
+
|
49
|
+
method_option 'device',
|
50
|
+
:desc => 'The simulator UDID or name.',
|
51
|
+
:aliases => '-d',
|
52
|
+
:required => false,
|
53
|
+
:type => :string
|
54
|
+
|
55
|
+
def doctor
|
56
|
+
debug = options[:debug]
|
57
|
+
device = options[:device]
|
58
|
+
|
59
|
+
manage_processes
|
60
|
+
|
61
|
+
if device
|
62
|
+
RunLoop::Environment.with_debugging(debug) do
|
63
|
+
RunLoop::CoreSimulator.erase(device)
|
64
|
+
launch_simulator(device, xcode)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
RunLoop::Environment.with_debugging(debug) do
|
68
|
+
erase_and_launch_each_simulator
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
no_commands do
|
75
|
+
def erase_and_launch_each_simulator
|
76
|
+
simctl.simulators.each do |simulator|
|
77
|
+
RunLoop::CoreSimulator.erase(simulator)
|
78
|
+
launch_simulator(simulator, xcode)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def launch_simulator(simulator, xcode)
|
83
|
+
core_sim = RunLoop::CoreSimulator.new(simulator, nil,
|
84
|
+
{:xcode => xcode})
|
85
|
+
core_sim.launch_simulator
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
desc 'manage-processes', 'Manage CoreSimulator processes by quiting stale processes'
|
90
|
+
|
91
|
+
method_option 'debug',
|
92
|
+
:desc => 'Enable debug logging.',
|
93
|
+
:aliases => '-v',
|
94
|
+
:required => false,
|
95
|
+
:default => false,
|
96
|
+
:type => :boolean
|
97
|
+
|
98
|
+
def manage_processes
|
99
|
+
debug = options[:debug]
|
100
|
+
original_value = ENV['DEBUG']
|
101
|
+
|
102
|
+
ENV['DEBUG'] = '1' if debug
|
103
|
+
|
104
|
+
begin
|
105
|
+
RunLoop::CoreSimulator.terminate_core_simulator_processes
|
106
|
+
process_name = "com.apple.CoreSimulator.CoreSimulatorService"
|
107
|
+
RunLoop::ProcessWaiter.new(process_name).pids.each do |pid|
|
108
|
+
kill_options = { :timeout => 0.5 }
|
109
|
+
RunLoop::ProcessTerminator.new(pid, 'KILL', process_name, kill_options)
|
110
|
+
end
|
111
|
+
ensure
|
112
|
+
ENV['DEBUG'] = original_value if debug
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
no_commands do
|
117
|
+
def simctl
|
118
|
+
@simctl ||= RunLoop::Simctl.new
|
119
|
+
end
|
120
|
+
|
121
|
+
def xcode
|
122
|
+
@xcode ||= RunLoop::Xcode.new
|
123
|
+
end
|
124
|
+
|
125
|
+
def xcrun
|
126
|
+
@xcrun ||= RunLoop::Xcrun.new
|
127
|
+
end
|
128
|
+
|
129
|
+
def booted_device
|
130
|
+
simctl.simulators.detect(nil) do |device|
|
131
|
+
device.state == 'Booted'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
desc 'install --app [OPTIONS]', 'Installs an app on a device.'
|
137
|
+
|
138
|
+
method_option 'app',
|
139
|
+
:desc => 'Path to a .app bundle to launch on simulator.',
|
140
|
+
:aliases => '-a',
|
141
|
+
:required => true,
|
142
|
+
:type => :string
|
143
|
+
|
144
|
+
method_option 'device',
|
145
|
+
:desc => 'The simulator UDID or name.',
|
146
|
+
:aliases => '-d',
|
147
|
+
:required => false,
|
148
|
+
:type => :string
|
149
|
+
|
150
|
+
method_option 'debug',
|
151
|
+
:desc => 'Enable debug logging.',
|
152
|
+
:aliases => '-v',
|
153
|
+
:required => false,
|
154
|
+
:default => false,
|
155
|
+
:type => :boolean
|
156
|
+
|
157
|
+
method_option 'reset-app-sandbox',
|
158
|
+
:desc => 'If the app is already installed, erase the app data.',
|
159
|
+
:aliases => '-r',
|
160
|
+
:default => false,
|
161
|
+
:type => :boolean
|
162
|
+
|
163
|
+
method_option 'force',
|
164
|
+
:desc => 'Force a re-install the existing app. Deprecated 1.5.6.',
|
165
|
+
:aliases => '-f',
|
166
|
+
:required => false,
|
167
|
+
:default => false,
|
168
|
+
:type => :boolean
|
169
|
+
|
170
|
+
def install
|
171
|
+
debug = options[:debug]
|
172
|
+
|
173
|
+
device = expect_device(options)
|
174
|
+
app = expect_app(options, device)
|
175
|
+
|
176
|
+
core_sim = RunLoop::CoreSimulator.new(device, app)
|
177
|
+
|
178
|
+
RunLoop::Environment.with_debugging(debug) do
|
179
|
+
if options['reset-app-sandbox']
|
180
|
+
|
181
|
+
if core_sim.app_is_installed?
|
182
|
+
RunLoop.log_debug('Resetting the app sandbox')
|
183
|
+
core_sim.uninstall_app_and_sandbox
|
184
|
+
else
|
185
|
+
RunLoop.log_debug('App is not installed; skipping sandbox reset')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
core_sim.install
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
no_commands do
|
193
|
+
def expect_device(options)
|
194
|
+
device_from_options = options[:device]
|
195
|
+
simulators = simctl.simulators
|
196
|
+
if device_from_options.nil?
|
197
|
+
default_name = RunLoop::Core.default_simulator
|
198
|
+
device = simulators.find do |sim|
|
199
|
+
sim.instruments_identifier(xcode) == default_name
|
200
|
+
end
|
201
|
+
|
202
|
+
if device.nil?
|
203
|
+
raise RunLoop::CLI::ValidationError,
|
204
|
+
"Could not find a simulator with name that matches '#{device_from_options}'"
|
205
|
+
end
|
206
|
+
else
|
207
|
+
device = simulators.find do |sim|
|
208
|
+
sim.udid == device_from_options ||
|
209
|
+
sim.instruments_identifier(xcode) == device_from_options
|
210
|
+
end
|
211
|
+
|
212
|
+
if device.nil?
|
213
|
+
raise RunLoop::CLI::ValidationError,
|
214
|
+
"Could not find a simulator with name or UDID that matches '#{device_from_options}'"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
device
|
218
|
+
end
|
219
|
+
|
220
|
+
def expect_app(options, device_obj)
|
221
|
+
app_bundle_path = options[:app]
|
222
|
+
unless File.exist?(app_bundle_path)
|
223
|
+
raise RunLoop::CLI::ValidationError, "Expected '#{app_bundle_path}' to exist."
|
224
|
+
end
|
225
|
+
|
226
|
+
unless File.directory?(app_bundle_path)
|
227
|
+
raise RunLoop::CLI::ValidationError,
|
228
|
+
"Expected '#{app_bundle_path}' to be a directory."
|
229
|
+
end
|
230
|
+
|
231
|
+
unless File.extname(app_bundle_path) == '.app'
|
232
|
+
raise RunLoop::CLI::ValidationError,
|
233
|
+
"Expected '#{app_bundle_path}' to end in .app."
|
234
|
+
end
|
235
|
+
|
236
|
+
app = RunLoop::App.new(app_bundle_path)
|
237
|
+
|
238
|
+
begin
|
239
|
+
app.bundle_identifier
|
240
|
+
app.executable_name
|
241
|
+
rescue RuntimeError => e
|
242
|
+
raise RunLoop::CLI::ValidationError, e.message
|
243
|
+
end
|
244
|
+
|
245
|
+
lipo = RunLoop::Lipo.new(app.path)
|
246
|
+
begin
|
247
|
+
lipo.expect_compatible_arch(device_obj)
|
248
|
+
rescue RunLoop::IncompatibleArchitecture => e
|
249
|
+
raise RunLoop::CLI::ValidationError, e.message
|
250
|
+
end
|
251
|
+
|
252
|
+
app
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "run_loop"
|
3
|
+
require "run_loop/cli/errors"
|
4
|
+
|
5
|
+
module RunLoop
|
6
|
+
module CLI
|
7
|
+
class TCC < Thor
|
8
|
+
|
9
|
+
desc "services", "Print known services"
|
10
|
+
|
11
|
+
def services
|
12
|
+
RunLoop::TCC::PRIVACY_SERVICES.each do |key, _|
|
13
|
+
puts key
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "open", "Open the TCC.db of a device in an editor EXPERIMENTAL"
|
18
|
+
|
19
|
+
method_option "device",
|
20
|
+
:desc => "Device name or identifier.",
|
21
|
+
:aliases => "-d",
|
22
|
+
:required => true,
|
23
|
+
:type => :string
|
24
|
+
|
25
|
+
def open
|
26
|
+
device = expect_device(options)
|
27
|
+
|
28
|
+
tcc_db = device.simulator_tcc_db
|
29
|
+
|
30
|
+
return false if tcc_db.nil?
|
31
|
+
|
32
|
+
args = ['open', tcc_db]
|
33
|
+
|
34
|
+
pid = Process.spawn(*args)
|
35
|
+
Process.detach(pid)
|
36
|
+
pid
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "allow", "Prevent a Privacy Alert from appearing (Sim only)"
|
40
|
+
|
41
|
+
method_option "device",
|
42
|
+
:desc => "Device name or identifier. If undefined, operation will be on all devices",
|
43
|
+
:aliases => "-d",
|
44
|
+
:required => false,
|
45
|
+
:type => :string
|
46
|
+
|
47
|
+
method_option "app",
|
48
|
+
:desc => "App bundle id to allow service on",
|
49
|
+
:aliases => "-a",
|
50
|
+
:required => true,
|
51
|
+
:type => :string
|
52
|
+
|
53
|
+
method_option "service",
|
54
|
+
:desc => "Service to allow. If undefined, all known services will be allowed",
|
55
|
+
:aliases => "-s",
|
56
|
+
:required => false,
|
57
|
+
:type => :string
|
58
|
+
|
59
|
+
method_option 'debug',
|
60
|
+
:desc => 'Enable debug logging.',
|
61
|
+
:aliases => '-v',
|
62
|
+
:required => false,
|
63
|
+
:default => false,
|
64
|
+
:type => :boolean
|
65
|
+
|
66
|
+
def allow
|
67
|
+
debug = options[:debug]
|
68
|
+
|
69
|
+
device = options[:device]
|
70
|
+
if device
|
71
|
+
devices = [expect_device(options)]
|
72
|
+
else
|
73
|
+
devices = sim_control.simulators
|
74
|
+
end
|
75
|
+
|
76
|
+
service = options[:service]
|
77
|
+
|
78
|
+
if service
|
79
|
+
services = [service]
|
80
|
+
else
|
81
|
+
services = RunLoop::TCC::PRIVACY_SERVICES.map do |key, _|
|
82
|
+
key
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
app = options[:app]
|
87
|
+
|
88
|
+
RunLoop::Environment.with_debugging(debug) do
|
89
|
+
devices.each do |_device|
|
90
|
+
tcc = RunLoop::TCC.new(_device, app)
|
91
|
+
services.each do |_service|
|
92
|
+
tcc.allow_service(_service)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
true
|
97
|
+
end
|
98
|
+
|
99
|
+
no_commands do
|
100
|
+
def expect_device(options)
|
101
|
+
device_from_options = options[:device]
|
102
|
+
simulators = sim_control.simulators
|
103
|
+
if device_from_options.nil?
|
104
|
+
default_name = RunLoop::Core.default_simulator
|
105
|
+
device = simulators.find do |sim|
|
106
|
+
sim.instruments_identifier(xcode) == default_name
|
107
|
+
end
|
108
|
+
|
109
|
+
if device.nil?
|
110
|
+
raise RunLoop::CLI::ValidationError,
|
111
|
+
"Could not find a simulator with name that matches '#{device_from_options}'"
|
112
|
+
end
|
113
|
+
else
|
114
|
+
device = simulators.find do |sim|
|
115
|
+
sim.udid == device_from_options ||
|
116
|
+
sim.instruments_identifier(xcode) == device_from_options
|
117
|
+
end
|
118
|
+
|
119
|
+
if device.nil?
|
120
|
+
raise RunLoop::CLI::ValidationError,
|
121
|
+
"Could not find a simulator with name or UDID that matches '#{device_from_options}'"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
device
|
125
|
+
end
|
126
|
+
|
127
|
+
def sim_control
|
128
|
+
@sim_control ||= RunLoop::SimControl.new
|
129
|
+
end
|
130
|
+
|
131
|
+
def xcode
|
132
|
+
@xcode ||= RunLoop::Xcode.new
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module RunLoop
|
2
|
+
# @!visibility private
|
3
|
+
# A wrapper around codesign command line tool
|
4
|
+
class Codesign
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
DEV_REGEX = /Authority=iPhone Developer:/
|
8
|
+
|
9
|
+
# @!visibility private
|
10
|
+
APP_STORE_REGEX = /Authority=Apple iPhone OS Application Signing/
|
11
|
+
|
12
|
+
# @!visibility private
|
13
|
+
DISTR_REGEX = /Authority=iPhone Distribution:/
|
14
|
+
|
15
|
+
# @!visibility private
|
16
|
+
NOT_SIGNED_REGEX = /code object is not signed at all/
|
17
|
+
|
18
|
+
# @!visibility private
|
19
|
+
def self.info(path)
|
20
|
+
self.expect_path_exists(path)
|
21
|
+
self.run_codesign_command(["--display", "--verbose=4", path])
|
22
|
+
end
|
23
|
+
|
24
|
+
# @!visibility private
|
25
|
+
#
|
26
|
+
# True if the asset is signed.
|
27
|
+
def self.signed?(path)
|
28
|
+
info = self.info(path)
|
29
|
+
info[NOT_SIGNED_REGEX, 0] == nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# @!visibility private
|
33
|
+
#
|
34
|
+
# True if the asset is signed with anything other than a dev cert.
|
35
|
+
def self.distribution?(path)
|
36
|
+
info = self.info(path)
|
37
|
+
|
38
|
+
info[NOT_SIGNED_REGEX, 0] == nil &&
|
39
|
+
info[DEV_REGEX, 0] == nil
|
40
|
+
end
|
41
|
+
|
42
|
+
# @!visibility private
|
43
|
+
#
|
44
|
+
# True if the asset is signed with a dev cert
|
45
|
+
def self.developer?(path)
|
46
|
+
info = self.info(path)
|
47
|
+
info[DEV_REGEX, 0] != nil
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def self.expect_path_exists(path)
|
53
|
+
if !File.exist?(path)
|
54
|
+
raise ArgumentError,
|
55
|
+
%Q{There is no file or directory at path:
|
56
|
+
|
57
|
+
#{path}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.run_codesign_command(args)
|
63
|
+
if !args.is_a?(Array)
|
64
|
+
raise ArgumentError, "Expected args: '#{args}' to be an Array"
|
65
|
+
end
|
66
|
+
|
67
|
+
xcrun = RunLoop::Xcrun.new
|
68
|
+
cmd = ["codesign"] + args
|
69
|
+
options = {:log_cmd => true}
|
70
|
+
hash = xcrun.run_command_in_context(cmd, options)
|
71
|
+
|
72
|
+
hash[:out]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|