run_loop 2.6.6 → 2.7.0
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 +5 -5
- data/ThirdPartyNotices.txt +119 -0
- data/lib/run_loop/core.rb +3 -1
- data/lib/run_loop/device.rb +26 -0
- data/lib/run_loop/device_agent/Frameworks.zip +0 -0
- data/lib/run_loop/device_agent/bin/iOSDeviceManager +0 -0
- data/lib/run_loop/device_agent/bin/iOSDeviceManager.LICENSE +21 -0
- data/lib/run_loop/device_agent/client.rb +9 -0
- data/lib/run_loop/directory.rb +18 -7
- data/lib/run_loop/instruments.rb +6 -2
- data/lib/run_loop/ipa.rb +17 -3
- data/lib/run_loop/physical_device/ios_device_manager.rb +124 -32
- data/lib/run_loop/physical_device/life_cycle.rb +28 -46
- data/lib/run_loop/shell.rb +11 -10
- data/lib/run_loop/version.rb +1 -1
- data/lib/run_loop/xcode.rb +16 -0
- metadata +25 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: efa428373fed36e57c707789351dddb5c6019d52985b0f4503b32f857a3fb9a0
|
4
|
+
data.tar.gz: d20c552c8130a4921c0505f9f50a88079e9acd401680495c9d51fd6134ce819d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b750e02559f0b0656c435c7a11e16b13ef5ef58f2dd54127a5a6ebabeb6318de80b130e6cb04b3166d24b6d7c9e284334a7dcfa4597019bde83ee120188fdd2
|
7
|
+
data.tar.gz: d441a636cb58d67099a59ad32fae2410b2aec38a8e41256d56821c4b9c6b2105ba4857601b546fcededf6420ba297f38cc2238a87472b13d72285f97d9400390
|
@@ -0,0 +1,119 @@
|
|
1
|
+
run-loop incorporates third party material from the projects listed
|
2
|
+
below. The original copyright notice and the license under which Microsoft
|
3
|
+
received such third party material are set forth below. Microsoft reserves all
|
4
|
+
other rights not expressly granted, whether by implication, estoppel or
|
5
|
+
otherwise.
|
6
|
+
|
7
|
+
===
|
8
|
+
|
9
|
+
The MIT License (MIT)
|
10
|
+
|
11
|
+
For iOSDeviceManager software
|
12
|
+
|
13
|
+
Copyright (c) 2016 Microsoft Corporation
|
14
|
+
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
16
|
+
this software and associated documentation files (the "Software"), to deal in
|
17
|
+
the Software without restriction, including without limitation the rights to
|
18
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
19
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
20
|
+
so, subject to the following conditions:
|
21
|
+
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
23
|
+
copies or substantial portions of the Software.
|
24
|
+
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
31
|
+
SOFTWARE.
|
32
|
+
|
33
|
+
===
|
34
|
+
|
35
|
+
The MIT License (MIT)
|
36
|
+
|
37
|
+
For DeviceAgent.iOS software
|
38
|
+
|
39
|
+
Copyright (c) Microsoft Corporation
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
42
|
+
this software and associated documentation files (the "Software"), to deal in
|
43
|
+
the Software without restriction, including without limitation the rights to
|
44
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
45
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
46
|
+
so, subject to the following conditions:
|
47
|
+
|
48
|
+
The above copyright notice and this permission notice shall be included in all
|
49
|
+
copies or substantial portions of the Software.
|
50
|
+
|
51
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
52
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
53
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
54
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
55
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
56
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
57
|
+
SOFTWARE.
|
58
|
+
|
59
|
+
===
|
60
|
+
|
61
|
+
BSD License
|
62
|
+
|
63
|
+
For FBSimulatorControl software
|
64
|
+
|
65
|
+
Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
|
66
|
+
|
67
|
+
Redistribution and use in source and binary forms, with or without modification,
|
68
|
+
are permitted provided that the following conditions are met:
|
69
|
+
|
70
|
+
* Redistributions of source code must retain the above copyright notice, this
|
71
|
+
list of conditions and the following disclaimer.
|
72
|
+
|
73
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
74
|
+
this list of conditions and the following disclaimer in the documentation
|
75
|
+
and/or other materials provided with the distribution.
|
76
|
+
|
77
|
+
* Neither the name Facebook nor the names of its contributors may be used to
|
78
|
+
endorse or promote products derived from this software without specific prior
|
79
|
+
written permission.
|
80
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
81
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
82
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
83
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
84
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
85
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
86
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
87
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
88
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
89
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
90
|
+
|
91
|
+
===
|
92
|
+
|
93
|
+
BSD License
|
94
|
+
|
95
|
+
For CocoaLumberjack software
|
96
|
+
|
97
|
+
Copyright (c) 2010-present, Deusty, LLC. All rights reserved.
|
98
|
+
|
99
|
+
Redistribution and use of this software in source and binary forms, with or
|
100
|
+
without modification, are permitted provided that the following conditions are
|
101
|
+
met:
|
102
|
+
|
103
|
+
* Redistributions of source code must retain the above copyright notice, this
|
104
|
+
list of conditions and the following disclaimer.
|
105
|
+
|
106
|
+
* Neither the name of Deusty nor the names of its contributors may be used to
|
107
|
+
endorse or promote products derived from this software without specific prior
|
108
|
+
written permission of Deusty, LLC.
|
109
|
+
|
110
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
111
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
112
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
113
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
114
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
115
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
116
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
117
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
118
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
119
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/lib/run_loop/core.rb
CHANGED
@@ -320,7 +320,9 @@ Logfile: #{log_file}
|
|
320
320
|
# version.
|
321
321
|
def self.default_simulator(xcode=RunLoop::Xcode.new)
|
322
322
|
|
323
|
-
if xcode.
|
323
|
+
if xcode.version_gte_94?
|
324
|
+
"iPhone 8 (11.4)"
|
325
|
+
elsif xcode.version_gte_93?
|
324
326
|
"iPhone 8 (11.3)"
|
325
327
|
elsif xcode.version_gte_92?
|
326
328
|
"iPhone 8 (11.2)"
|
data/lib/run_loop/device.rb
CHANGED
@@ -228,6 +228,32 @@ version: #{version}
|
|
228
228
|
!physical_device?
|
229
229
|
end
|
230
230
|
|
231
|
+
# Is the iOS version installed on this device compatible with an Xcode
|
232
|
+
# version?
|
233
|
+
def compatible_with_xcode_version?(xcode_version)
|
234
|
+
ios_version = version
|
235
|
+
|
236
|
+
if ios_version.major < (xcode_version.major + 2)
|
237
|
+
if physical_device?
|
238
|
+
return true
|
239
|
+
else
|
240
|
+
# iOS 8 simulators are available in Xcode 9
|
241
|
+
# iOS 7 simulators are not available in Xcode 9
|
242
|
+
if ios_version.major <= (xcode_version.major - 2)
|
243
|
+
return false
|
244
|
+
else
|
245
|
+
return true
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
if ios_version.major == (xcode_version.major + 2)
|
251
|
+
return ios_version.minor <= xcode_version.minor
|
252
|
+
end
|
253
|
+
|
254
|
+
false
|
255
|
+
end
|
256
|
+
|
231
257
|
# Return the instruction set for this device.
|
232
258
|
#
|
233
259
|
# **Simulator**
|
Binary file
|
Binary file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Microsoft Corporation
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -125,6 +125,15 @@ module RunLoop
|
|
125
125
|
core_sim.install
|
126
126
|
end
|
127
127
|
|
128
|
+
if !RunLoop::Environment.xtc?
|
129
|
+
if device.physical_device? && app
|
130
|
+
if reset_options
|
131
|
+
idm = RunLoop::PhysicalDevice::IOSDeviceManager.new(device)
|
132
|
+
idm.reset_app_sandbox(app)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
128
137
|
cbx_launcher = Client.detect_cbx_launcher(merged_options, device)
|
129
138
|
|
130
139
|
code_sign_identity = options[:code_sign_identity]
|
data/lib/run_loop/directory.rb
CHANGED
@@ -52,7 +52,7 @@ found '#{handle_errors_by}'
|
|
52
52
|
raise ArgumentError, "Expected '#{path}' to be a directory"
|
53
53
|
end
|
54
54
|
|
55
|
-
entries = self.recursive_glob_for_entries(path)
|
55
|
+
entries = self.recursive_glob_for_entries(path).sort
|
56
56
|
|
57
57
|
if entries.empty?
|
58
58
|
raise ArgumentError, "Expected a non-empty dir at '#{path}' found '#{entries}'"
|
@@ -60,11 +60,16 @@ found '#{handle_errors_by}'
|
|
60
60
|
|
61
61
|
debug = RunLoop::Environment.debug?
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
file_shas = []
|
64
|
+
cumulative = OpenSSL::Digest::SHA256.new
|
65
|
+
entries.each do |path|
|
66
|
+
if !self.skip_file?(path, "SHA256", debug)
|
66
67
|
begin
|
67
|
-
|
68
|
+
file_sha = OpenSSL::Digest::SHA256.new
|
69
|
+
contents = File.read(path, {mode: "rb"})
|
70
|
+
file_sha << contents
|
71
|
+
cumulative << contents
|
72
|
+
file_shas << [file_sha.hexdigest]
|
68
73
|
rescue => e
|
69
74
|
case handle_errors_by
|
70
75
|
when :logging
|
@@ -75,7 +80,7 @@ found '#{handle_errors_by}'
|
|
75
80
|
|
76
81
|
while trying to find the SHA of this file:
|
77
82
|
|
78
|
-
#{
|
83
|
+
#{path}
|
79
84
|
|
80
85
|
This is not a fatal error; it can be ignored.
|
81
86
|
}
|
@@ -90,7 +95,13 @@ This is not a fatal error; it can be ignored.
|
|
90
95
|
end
|
91
96
|
end
|
92
97
|
end
|
93
|
-
|
98
|
+
digest_of_digests = OpenSSL::Digest::SHA256.new
|
99
|
+
digest_of_digests << file_shas.join("\n")
|
100
|
+
# We have at least one example where the cumulative digest has an
|
101
|
+
# unexpected value when computing the digest of an installed .app on an
|
102
|
+
# iOS Simulator. I want return the cumulative.hexdigest in case there is
|
103
|
+
# a client (end user) who is using this method.
|
104
|
+
return digest_of_digests.hexdigest, cumulative.hexdigest
|
94
105
|
end
|
95
106
|
|
96
107
|
def self.size(path, format)
|
data/lib/run_loop/instruments.rb
CHANGED
@@ -218,8 +218,12 @@ module RunLoop
|
|
218
218
|
udid = line[DEVICE_UDID_REGEX, 0]
|
219
219
|
if udid
|
220
220
|
version = line[VERSION_REGEX, 0]
|
221
|
-
|
222
|
-
|
221
|
+
if version
|
222
|
+
name = line.split('(').first.strip
|
223
|
+
if name
|
224
|
+
RunLoop::Device.new(name, version, udid)
|
225
|
+
end
|
226
|
+
end
|
223
227
|
else
|
224
228
|
nil
|
225
229
|
end
|
data/lib/run_loop/ipa.rb
CHANGED
@@ -2,6 +2,20 @@ module RunLoop
|
|
2
2
|
# A model of the an .ipa - a application binary for iOS devices.
|
3
3
|
class Ipa
|
4
4
|
|
5
|
+
require "run_loop/shell"
|
6
|
+
|
7
|
+
# Return true if the path_to_ipa to a zip archive
|
8
|
+
def self.is_zip_archive?(path_to_ipa)
|
9
|
+
hash = RunLoop::Shell.run_shell_command(["file", path_to_ipa],
|
10
|
+
{log_cmd: true})
|
11
|
+
hash[:out][/Zip archive data/]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Return true if the path_to_ipa is probably an .ipa
|
15
|
+
def self.is_ipa?(path_to_ipa)
|
16
|
+
path_to_ipa.end_with?('.ipa') || RunLoop::Ipa.is_zip_archive?(path_to_ipa)
|
17
|
+
end
|
18
|
+
|
5
19
|
# The path to this .ipa.
|
6
20
|
# @!attribute [r] path
|
7
21
|
# @return [String] A path to this .ipa.
|
@@ -13,12 +27,12 @@ module RunLoop
|
|
13
27
|
# @raise [RuntimeError] If the file does not exist.
|
14
28
|
# @raise [RuntimeError] If the file does not end in .ipa.
|
15
29
|
def initialize(path_to_ipa)
|
16
|
-
|
30
|
+
if !File.exist? path_to_ipa
|
17
31
|
raise "Expected an ipa at '#{path_to_ipa}'"
|
18
32
|
end
|
19
33
|
|
20
|
-
|
21
|
-
raise "Expected '#{path_to_ipa}'
|
34
|
+
if !RunLoop::Ipa.is_ipa?(path_to_ipa)
|
35
|
+
raise "Expected '#{path_to_ipa}' have extension .ipa or be a zip archive"
|
22
36
|
end
|
23
37
|
@path = path_to_ipa
|
24
38
|
end
|
@@ -5,6 +5,17 @@ module RunLoop
|
|
5
5
|
require "run_loop/physical_device/life_cycle"
|
6
6
|
class IOSDeviceManager < RunLoop::PhysicalDevice::LifeCycle
|
7
7
|
|
8
|
+
require "fileutils"
|
9
|
+
require "run_loop/dot_dir"
|
10
|
+
require "run_loop/device_agent/frameworks"
|
11
|
+
require "run_loop/device_agent/ios_device_manager"
|
12
|
+
|
13
|
+
NOT_INSTALLED_EXIT_CODE = 2
|
14
|
+
|
15
|
+
DEFAULTS = {
|
16
|
+
install_timeout: RunLoop::Environment.ci? ? 240 : 120
|
17
|
+
}
|
18
|
+
|
8
19
|
# Is the tool installed?
|
9
20
|
def self.tool_is_installed?
|
10
21
|
File.exist?(IOSDeviceManager.executable_path)
|
@@ -22,67 +33,148 @@ module RunLoop
|
|
22
33
|
RunLoop::DeviceAgent::Frameworks.instance.install
|
23
34
|
end
|
24
35
|
|
25
|
-
def
|
36
|
+
def raise_error_on_failure(error_klass, message, app, device, hash)
|
37
|
+
if hash[:exit_status] == 0
|
38
|
+
true
|
39
|
+
else
|
40
|
+
raise error_klass, %Q[
|
41
|
+
#{message}
|
42
|
+
|
43
|
+
app: #{app}
|
44
|
+
device: #{device}
|
45
|
+
exit status: #{hash[:exit_status]}
|
46
|
+
|
47
|
+
#{hash[:out]}
|
48
|
+
|
49
|
+
]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def app_installed?(app)
|
54
|
+
bundle_id = app
|
55
|
+
if is_ipa?(app) || is_app?(app)
|
56
|
+
bundle_id = app.bundle_identifier
|
57
|
+
end
|
58
|
+
|
26
59
|
args = [
|
27
60
|
IOSDeviceManager.executable_path,
|
28
|
-
"
|
29
|
-
|
30
|
-
"-
|
61
|
+
"is-installed",
|
62
|
+
bundle_id,
|
63
|
+
"-d", device.udid
|
31
64
|
]
|
32
65
|
|
33
66
|
options = { :log_cmd => true }
|
34
67
|
hash = run_shell_command(args, options)
|
35
68
|
|
36
|
-
|
37
|
-
|
69
|
+
exit_status = hash[:exit_status]
|
70
|
+
|
71
|
+
if exit_status != 0 && exit_status != NOT_INSTALLED_EXIT_CODE
|
72
|
+
raise_error_on_failure(
|
73
|
+
RuntimeError,
|
74
|
+
"Encountered an error checking if app is installed on device",
|
75
|
+
app, device, hash
|
76
|
+
)
|
77
|
+
else
|
78
|
+
RunLoop::log_debug("Took #{hash[:seconds_elapsed]} seconds to check " +
|
79
|
+
"app was installed")
|
80
|
+
hash[:exit_status] == 0
|
81
|
+
end
|
38
82
|
end
|
39
83
|
|
40
84
|
def install_app(app_or_ipa)
|
41
|
-
|
42
|
-
|
43
|
-
app = app_or_ipa.app
|
44
|
-
end
|
85
|
+
install_app_internal(app_or_ipa, ["--force"])
|
86
|
+
end
|
45
87
|
|
46
|
-
|
47
|
-
|
48
|
-
|
88
|
+
def ensure_newest_installed(app_or_ipa)
|
89
|
+
install_app_internal(app_or_ipa)
|
90
|
+
end
|
91
|
+
|
92
|
+
def uninstall_app(app_or_ipa)
|
93
|
+
bundle_identifier = app_or_ipa.bundle_identifier
|
94
|
+
if !app_installed?(bundle_identifier)
|
95
|
+
return :was_not_installed
|
49
96
|
end
|
50
97
|
|
51
98
|
args = [
|
52
99
|
IOSDeviceManager.executable_path,
|
53
|
-
"
|
54
|
-
|
55
|
-
"-
|
56
|
-
"-c", code_sign_identity
|
100
|
+
"uninstall",
|
101
|
+
bundle_identifier,
|
102
|
+
"-d", device.udid
|
57
103
|
]
|
58
104
|
|
59
105
|
options = { :log_cmd => true }
|
60
106
|
hash = run_shell_command(args, options)
|
61
107
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
108
|
+
raise_error_on_failure(
|
109
|
+
UninstallError,
|
110
|
+
"Could not remove app from device",
|
111
|
+
app_or_ipa, device, hash
|
112
|
+
)
|
113
|
+
hash[:out]
|
114
|
+
end
|
115
|
+
|
116
|
+
def can_reset_app_sandbox?
|
117
|
+
true
|
118
|
+
end
|
119
|
+
|
120
|
+
def reset_app_sandbox(app_or_ipa)
|
121
|
+
args = [IOSDeviceManager.executable_path,
|
122
|
+
"clear-app-data",
|
123
|
+
app_or_ipa.path,
|
124
|
+
device.udid]
|
125
|
+
|
126
|
+
options = { :log_cmd => true }
|
127
|
+
hash = run_shell_command(args, options)
|
128
|
+
|
129
|
+
raise_error_on_failure(
|
130
|
+
ResetAppSandboxError,
|
131
|
+
"Could not clear app data",
|
132
|
+
app_or_ipa, device, hash
|
133
|
+
)
|
134
|
+
|
135
|
+
hash[:out]
|
69
136
|
end
|
70
137
|
|
71
|
-
|
72
|
-
|
138
|
+
=begin
|
139
|
+
Private Methods
|
140
|
+
=end
|
141
|
+
|
142
|
+
private
|
73
143
|
|
144
|
+
def install_app_internal(app_or_ipa, additional_args=[])
|
74
145
|
args = [
|
75
146
|
IOSDeviceManager.executable_path,
|
76
|
-
"
|
77
|
-
|
78
|
-
"-
|
147
|
+
"install",
|
148
|
+
app_or_ipa.path,
|
149
|
+
"-d", device.udid
|
79
150
|
]
|
80
151
|
|
81
|
-
|
152
|
+
args = args + additional_args
|
153
|
+
|
154
|
+
code_sign_identity = RunLoop::Environment.code_sign_identity
|
155
|
+
if code_sign_identity
|
156
|
+
args = args + ["-c", code_sign_identity]
|
157
|
+
end
|
158
|
+
|
159
|
+
provisioning_profile = RunLoop::Environment.provisioning_profile
|
160
|
+
if provisioning_profile
|
161
|
+
args = args + ["-p", provisioning_profile]
|
162
|
+
end
|
163
|
+
|
164
|
+
options = {
|
165
|
+
:log_cmd => true,
|
166
|
+
timeout: DEFAULTS[:install_timeout]
|
167
|
+
}
|
82
168
|
hash = run_shell_command(args, options)
|
83
169
|
|
84
|
-
|
85
|
-
|
170
|
+
raise_error_on_failure(
|
171
|
+
InstallError,
|
172
|
+
"Could not install app on device",
|
173
|
+
app_or_ipa, device, hash
|
174
|
+
)
|
175
|
+
|
176
|
+
RunLoop::log_debug("Took #{hash[:seconds_elapsed]} seconds to install app")
|
177
|
+
hash[:out]
|
86
178
|
end
|
87
179
|
end
|
88
180
|
end
|
@@ -8,6 +8,9 @@ module RunLoop
|
|
8
8
|
# Raised when uninstall fails.
|
9
9
|
class UninstallError < RuntimeError; end
|
10
10
|
|
11
|
+
# Raised when clear app data fails
|
12
|
+
class ResetAppSandboxError < RuntimeError; end
|
13
|
+
|
11
14
|
# Raised when tool cannot perform task.
|
12
15
|
class NotImplementedError < StandardError; end
|
13
16
|
|
@@ -65,37 +68,31 @@ must be a physical device.]
|
|
65
68
|
|
66
69
|
# Is the app installed?
|
67
70
|
#
|
68
|
-
# @param [String]
|
71
|
+
# @param [RunLoop::Ipa, RunLoop::App, String] app an App, Ipa, or a bundle
|
72
|
+
# identifier.
|
69
73
|
# @return [Boolean] true or false
|
70
|
-
def app_installed?(
|
74
|
+
def app_installed?(app)
|
71
75
|
abstract_method!
|
72
76
|
end
|
73
77
|
|
74
78
|
# Install the app or ipa.
|
75
79
|
#
|
76
80
|
# If the app is already installed, it will be reinstalled from disk;
|
77
|
-
# no version check is performed.
|
81
|
+
# no version check is performed. This is a force reinstall.
|
78
82
|
#
|
79
83
|
# App data is never preserved. If you want to preserve the app data,
|
80
84
|
# call `ensure_newest_installed`.
|
81
85
|
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
# * :reinstalled => app was installed, but app data was not preserved.
|
85
|
-
# * :installed => app was not installed.
|
86
|
-
#
|
87
|
-
# @param [RunLoop::Ipa, RunLoop::App] app_or_ipa The ipa to install.
|
88
|
-
# The caller is responsible for validating the ipa for the device by
|
89
|
-
# checking that the codesign and instruction set is correct.
|
86
|
+
# @param [RunLoop::Ipa, RunLoop::App] app The ipa to install.
|
90
87
|
#
|
91
88
|
# @raise [InstallError] If app was not installed.
|
92
89
|
#
|
93
|
-
# @return [
|
94
|
-
def install_app(
|
90
|
+
# @return [Boolean] true or false
|
91
|
+
def install_app(app)
|
95
92
|
abstract_method!
|
96
93
|
end
|
97
94
|
|
98
|
-
# Uninstall the app
|
95
|
+
# Uninstall the app.
|
99
96
|
#
|
100
97
|
# App data is never preserved. If you want to install a new version of
|
101
98
|
# an app and preserve app data (upgrade testing), call
|
@@ -103,16 +100,12 @@ must be a physical device.]
|
|
103
100
|
#
|
104
101
|
# Possible return values:
|
105
102
|
#
|
106
|
-
#
|
107
|
-
# * :uninstall => app was uninstalled
|
108
|
-
#
|
109
|
-
# @param [String] bundle_id The CFBundleIdentifier of an app.
|
103
|
+
# @param [RunLoop::Ipa, RunLoop::App] app the App or Ipa
|
110
104
|
#
|
111
105
|
# @raise [UninstallError] If the app cannot be uninstalled, usually
|
112
106
|
# because it is a system app.
|
113
|
-
#
|
114
|
-
|
115
|
-
def uninstall_app(bundle_id)
|
107
|
+
# @return [String] Output from the shell command
|
108
|
+
def uninstall_app(app)
|
116
109
|
abstract_method!
|
117
110
|
end
|
118
111
|
|
@@ -124,26 +117,15 @@ must be a physical device.]
|
|
124
117
|
# the CFBundleShortVersionString. If either are different, then the
|
125
118
|
# app should be reinstalled.
|
126
119
|
#
|
127
|
-
# If possible, the app data should be preserved across
|
128
|
-
#
|
129
|
-
# Possible return values:
|
120
|
+
# If possible, the app data should be preserved across re-installation.
|
130
121
|
#
|
131
|
-
#
|
132
|
-
# * :upgraded => app was stale; newer version from disk was installed and
|
133
|
-
# app data was preserved.
|
134
|
-
# * :reinstalled => app was stale; newer version from disk was installed,
|
135
|
-
# but app data was not preserved.
|
136
|
-
# * :installed => app was not installed.
|
137
|
-
#
|
138
|
-
# @param [RunLoop::Ipa, RunLoop::App] app_or_ipa The ipa to install.
|
139
|
-
# The caller is responsible for validating the ipa for the device by
|
140
|
-
# checking that the codesign and instruction set is correct.
|
122
|
+
# @param [RunLoop::Ipa, RunLoop::App] app The App or Ipa to install.
|
141
123
|
#
|
142
124
|
# @raise [InstallError] If the app could not be installed.
|
143
125
|
# @raise [UninstallError] If the app could not be uninstalled.
|
144
126
|
#
|
145
|
-
# @return [
|
146
|
-
def ensure_newest_installed(
|
127
|
+
# @return [String] Output from the shell command
|
128
|
+
def ensure_newest_installed(app)
|
147
129
|
abstract_method!
|
148
130
|
end
|
149
131
|
|
@@ -153,12 +135,10 @@ must be a physical device.]
|
|
153
135
|
# the CFBundleShortVersionString. If either are different, then this
|
154
136
|
# method returns false.
|
155
137
|
#
|
156
|
-
# @param [RunLoop::Ipa, RunLoop::App]
|
157
|
-
# The caller is responsible for validating the ipa for the device by
|
158
|
-
# checking that the codesign and instruction set is correct.
|
138
|
+
# @param [RunLoop::Ipa, RunLoop::App] app The Ipa or App to install.
|
159
139
|
#
|
160
140
|
# @raise [RuntimeError] If app is not already installed.
|
161
|
-
def installed_app_same_as?(
|
141
|
+
def installed_app_same_as?(app)
|
162
142
|
abstract_method!
|
163
143
|
end
|
164
144
|
|
@@ -176,11 +156,11 @@ must be a physical device.]
|
|
176
156
|
#
|
177
157
|
# Does not clear Keychain. Use the Calabash iOS Keychain API.
|
178
158
|
#
|
179
|
-
# @param [
|
159
|
+
# @param [RunLoop::Ipa, RunLoop::App] app The App or Ipa
|
180
160
|
#
|
181
161
|
# @raise [RunLoop::PhysicalDevice::NotImplementedError] If this tool
|
182
|
-
# cannot reset the app sandbox without
|
183
|
-
def reset_app_sandbox(
|
162
|
+
# cannot reset the app sandbox without uninstalling the app.
|
163
|
+
def reset_app_sandbox(app)
|
184
164
|
abstract_method!
|
185
165
|
end
|
186
166
|
|
@@ -190,7 +170,9 @@ must be a physical device.]
|
|
190
170
|
end
|
191
171
|
|
192
172
|
# Is the app or ipa compatible with the architecture of the device?
|
193
|
-
|
173
|
+
#
|
174
|
+
# @param [RunLoop::Ipa, RunLoop::App] app The App or Ipa
|
175
|
+
def app_has_compatible_architecture?(app)
|
194
176
|
abstract_method!
|
195
177
|
end
|
196
178
|
|
@@ -199,7 +181,7 @@ must be a physical device.]
|
|
199
181
|
abstract_method!
|
200
182
|
end
|
201
183
|
|
202
|
-
# Return
|
184
|
+
# Return true if the device is an iPad.
|
203
185
|
def ipad?
|
204
186
|
abstract_method!
|
205
187
|
end
|
@@ -209,7 +191,7 @@ must be a physical device.]
|
|
209
191
|
abstract_method!
|
210
192
|
end
|
211
193
|
|
212
|
-
#
|
194
|
+
# Side-load data into the app's sandbox.
|
213
195
|
#
|
214
196
|
# These directories exist in the application sandbox.
|
215
197
|
#
|
data/lib/run_loop/shell.rb
CHANGED
@@ -63,11 +63,14 @@ IO.popen requires all arguments to be Strings.
|
|
63
63
|
RunLoop.log_unix_cmd(cmd) if merged_options[:log_cmd]
|
64
64
|
|
65
65
|
hash = {}
|
66
|
+
shell_start_time = Time.now
|
66
67
|
|
67
|
-
|
68
|
+
environment = options.fetch(:environment, {})
|
68
69
|
|
69
|
-
|
70
|
-
command_output = CommandRunner.run(args,
|
70
|
+
begin
|
71
|
+
command_output = CommandRunner.run(args,
|
72
|
+
timeout: timeout,
|
73
|
+
environment: environment)
|
71
74
|
|
72
75
|
out = ensure_command_output_utf8(command_output[:out], cmd)
|
73
76
|
process_status = command_output[:status]
|
@@ -83,7 +86,7 @@ IO.popen requires all arguments to be Strings.
|
|
83
86
|
rescue RunLoop::Encoding::UTF8Error => e
|
84
87
|
raise e
|
85
88
|
rescue => e
|
86
|
-
elapsed = "%0.2f" % (Time.now -
|
89
|
+
elapsed = "%0.2f" % (Time.now - shell_start_time)
|
87
90
|
raise Error,
|
88
91
|
%Q{Encountered an error after #{elapsed} seconds:
|
89
92
|
|
@@ -93,14 +96,14 @@ executing this command:
|
|
93
96
|
|
94
97
|
#{cmd}
|
95
98
|
}
|
99
|
+
ensure
|
100
|
+
hash[:seconds_elapsed] = Time.now - shell_start_time
|
96
101
|
end
|
97
102
|
|
98
|
-
now = Time.now
|
99
|
-
|
100
103
|
if hash[:exit_status].nil?
|
101
|
-
elapsed = "%0.2f" % (
|
104
|
+
elapsed = "%0.2f" % (hash[:seconds_elapsed])
|
102
105
|
|
103
|
-
if timeout_exceeded?(
|
106
|
+
if timeout_exceeded?(shell_start_time, timeout)
|
104
107
|
raise TimeoutError,
|
105
108
|
%Q[
|
106
109
|
Timed out after #{elapsed} seconds executing
|
@@ -123,7 +126,6 @@ The command generated this output:
|
|
123
126
|
|
124
127
|
end
|
125
128
|
end
|
126
|
-
|
127
129
|
hash
|
128
130
|
end
|
129
131
|
|
@@ -134,4 +136,3 @@ The command generated this output:
|
|
134
136
|
end
|
135
137
|
end
|
136
138
|
end
|
137
|
-
|
data/lib/run_loop/version.rb
CHANGED
data/lib/run_loop/xcode.rb
CHANGED
@@ -26,6 +26,14 @@ module RunLoop
|
|
26
26
|
to_s
|
27
27
|
end
|
28
28
|
|
29
|
+
# Returns a version instance for Xcode 9.4; used to check for the
|
30
|
+
# availability of features and paths to various items on the filesystem
|
31
|
+
#
|
32
|
+
# @return [RunLoop::Version] 9.4
|
33
|
+
def v94
|
34
|
+
fetch_version(:v94)
|
35
|
+
end
|
36
|
+
|
29
37
|
# Returns a version instance for Xcode 9.3; used to check for the
|
30
38
|
# availability of features and paths to various items on the filesystem
|
31
39
|
#
|
@@ -177,6 +185,14 @@ module RunLoop
|
|
177
185
|
def v50
|
178
186
|
fetch_version(:v50)
|
179
187
|
end
|
188
|
+
|
189
|
+
# Is the active Xcode version 9.3 or above?
|
190
|
+
#
|
191
|
+
# @return [Boolean] `true` if the current Xcode version is >= 9.3
|
192
|
+
def version_gte_94?
|
193
|
+
version >= v94
|
194
|
+
end
|
195
|
+
|
180
196
|
# Is the active Xcode version 9.3 or above?
|
181
197
|
#
|
182
198
|
# @return [Boolean] `true` if the current Xcode version is >= 9.3
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: run_loop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karl Krukow
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-04-
|
12
|
+
date: 2018-04-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -133,14 +133,14 @@ dependencies:
|
|
133
133
|
requirements:
|
134
134
|
- - "~>"
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version: '0.
|
136
|
+
version: '0.3'
|
137
137
|
type: :development
|
138
138
|
prerelease: false
|
139
139
|
version_requirements: !ruby/object:Gem::Requirement
|
140
140
|
requirements:
|
141
141
|
- - "~>"
|
142
142
|
- !ruby/object:Gem::Version
|
143
|
-
version: '0.
|
143
|
+
version: '0.3'
|
144
144
|
- !ruby/object:Gem::Dependency
|
145
145
|
name: luffa
|
146
146
|
requirement: !ruby/object:Gem::Requirement
|
@@ -203,28 +203,42 @@ dependencies:
|
|
203
203
|
requirements:
|
204
204
|
- - "~>"
|
205
205
|
- !ruby/object:Gem::Version
|
206
|
-
version: '4.
|
206
|
+
version: '4.0'
|
207
207
|
type: :development
|
208
208
|
prerelease: false
|
209
209
|
version_requirements: !ruby/object:Gem::Requirement
|
210
210
|
requirements:
|
211
211
|
- - "~>"
|
212
212
|
- !ruby/object:Gem::Version
|
213
|
-
version: '4.
|
213
|
+
version: '4.0'
|
214
|
+
- !ruby/object:Gem::Dependency
|
215
|
+
name: terminal-notifier
|
216
|
+
requirement: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - "~>"
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: '2.0'
|
221
|
+
type: :development
|
222
|
+
prerelease: false
|
223
|
+
version_requirements: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - "~>"
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '2.0'
|
214
228
|
- !ruby/object:Gem::Dependency
|
215
229
|
name: terminal-notifier-guard
|
216
230
|
requirement: !ruby/object:Gem::Requirement
|
217
231
|
requirements:
|
218
232
|
- - "~>"
|
219
233
|
- !ruby/object:Gem::Version
|
220
|
-
version: '1.
|
234
|
+
version: '1.0'
|
221
235
|
type: :development
|
222
236
|
prerelease: false
|
223
237
|
version_requirements: !ruby/object:Gem::Requirement
|
224
238
|
requirements:
|
225
239
|
- - "~>"
|
226
240
|
- !ruby/object:Gem::Version
|
227
|
-
version: '1.
|
241
|
+
version: '1.0'
|
228
242
|
- !ruby/object:Gem::Dependency
|
229
243
|
name: guard-bundler
|
230
244
|
requirement: !ruby/object:Gem::Requirement
|
@@ -317,6 +331,7 @@ files:
|
|
317
331
|
- "./vendor-licenses/Facebook-WebDriverAgent.LICENSE"
|
318
332
|
- "./vendor-licenses/RoutingHTTPServer.LICENSE"
|
319
333
|
- LICENSE
|
334
|
+
- ThirdPartyNotices.txt
|
320
335
|
- bin/run-loop
|
321
336
|
- lib/run_loop.rb
|
322
337
|
- lib/run_loop/abstract.rb
|
@@ -339,6 +354,7 @@ files:
|
|
339
354
|
- lib/run_loop/device_agent/Frameworks.zip
|
340
355
|
- lib/run_loop/device_agent/app/DeviceAgent-Runner.app.zip
|
341
356
|
- lib/run_loop/device_agent/bin/iOSDeviceManager
|
357
|
+
- lib/run_loop/device_agent/bin/iOSDeviceManager.LICENSE
|
342
358
|
- lib/run_loop/device_agent/client.rb
|
343
359
|
- lib/run_loop/device_agent/frameworks.rb
|
344
360
|
- lib/run_loop/device_agent/ios_device_manager.rb
|
@@ -415,7 +431,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
415
431
|
version: '0'
|
416
432
|
requirements: []
|
417
433
|
rubyforge_project:
|
418
|
-
rubygems_version: 2.6
|
434
|
+
rubygems_version: 2.7.6
|
419
435
|
signing_key:
|
420
436
|
specification_version: 4
|
421
437
|
summary: The bridge between Calabash iOS and Xcode command-line tools like instruments
|