xcode-install 2.6.0 → 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 +4 -4
- data/.github/workflows/ci.yml +42 -0
- data/.gitignore +1 -0
- data/README.md +13 -3
- data/XCODE_VERSION.md +49 -0
- data/lib/xcode/install/install.rb +6 -3
- data/lib/xcode/install/select.rb +1 -1
- data/lib/xcode/install/version.rb +1 -1
- data/lib/xcode/install.rb +115 -59
- data/spec/fixtures/xcode.json +30 -1
- data/spec/fixtures/xcode_63.json +28 -44
- data/spec/fixtures/yolo.json +1 -1
- data/spec/install_spec.rb +5 -5
- data/spec/installer_spec.rb +116 -91
- data/spec/json_spec.rb +14 -4
- data/spec/list_spec.rb +32 -3
- data/xcode-install.gemspec +2 -2
- metadata +19 -12
- data/.circleci/config.yml +0 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f5f95c1ec6494fb1482c6862a786fd3f149327096468dbfd01886d6a320ab31f
|
|
4
|
+
data.tar.gz: ef0e89795d7a5169a97adb29467025693644db1a8805e1ae395cd76066ae2569
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4fa023f63479190d92da8f7a54d9ac0a9556eab534e4e4ea4a784f6bbd10837678910570dd9665d409214d52e47432ebafa99aaae0a9022097bde4540d42390f
|
|
7
|
+
data.tar.gz: 73c28ae14d7081a62376ce4611cae869987b8e2681325770b20d8d5f3be153abc02c7c0e3b94828c703ab786dd5960a62c6f3b097b162b82be39cf197e031d99
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: "CI"
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
build:
|
|
6
|
+
strategy:
|
|
7
|
+
fail-fast: false
|
|
8
|
+
matrix:
|
|
9
|
+
ruby: ["2.5", "2.6", "2.7"]
|
|
10
|
+
|
|
11
|
+
runs-on: macos-latest
|
|
12
|
+
steps:
|
|
13
|
+
# Setup env
|
|
14
|
+
- uses: actions/checkout@v2
|
|
15
|
+
- uses: actions/setup-ruby@v1
|
|
16
|
+
with:
|
|
17
|
+
ruby-version: "${{ matrix.ruby }}"
|
|
18
|
+
|
|
19
|
+
# Show env
|
|
20
|
+
- name: Show macOS version
|
|
21
|
+
run: sw_vers
|
|
22
|
+
- name: Show env versions
|
|
23
|
+
run: |
|
|
24
|
+
ruby --version
|
|
25
|
+
bundler --version
|
|
26
|
+
echo $HOME
|
|
27
|
+
|
|
28
|
+
# Prepare
|
|
29
|
+
- name: Install bundler 2.2.14
|
|
30
|
+
run: gem install bundler -v "~> 2.2.14"
|
|
31
|
+
- name: Install ruby dependencies
|
|
32
|
+
run: |
|
|
33
|
+
bundle config --local clean 'true'
|
|
34
|
+
bundle config --local path '.vendor'
|
|
35
|
+
bundle config --local jobs 8
|
|
36
|
+
bundle config --local without 'system_tests'
|
|
37
|
+
bundle install
|
|
38
|
+
|
|
39
|
+
- name: Run test
|
|
40
|
+
run: bundle exec rake spec
|
|
41
|
+
- name: Run lint
|
|
42
|
+
run: bundle exec rake rubocop
|
data/.gitignore
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Xcode::Install
|
|
2
2
|
|
|
3
|
-
[](http://badge.fury.io/rb/xcode-install) [](http://badge.fury.io/rb/xcode-install) [](https://github.com/xcpretty/xcode-install/actions)
|
|
4
4
|
|
|
5
5
|
Install and update your Xcodes automatically.
|
|
6
6
|
|
|
@@ -87,6 +87,16 @@ $ xcversion list
|
|
|
87
87
|
|
|
88
88
|
They have to be installed using the full name, e.g. `xcversion install '7 GM seed'`.
|
|
89
89
|
|
|
90
|
+
#### `.xcode-version`
|
|
91
|
+
|
|
92
|
+
We recommend the creation of a `.xcode-version` file to explicitly declare and store the Xcode version to be used by your CI environment as well as your team.
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
12.5
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Read [the proposal](/XCODE_VERSION.md) of `.xcode-version`.
|
|
99
|
+
|
|
90
100
|
### Select
|
|
91
101
|
|
|
92
102
|
To see the currently selected version, run
|
|
@@ -151,7 +161,7 @@ to a dialog popping up. Feel free to dupe [the radar][5]. 📡
|
|
|
151
161
|
|
|
152
162
|
XcodeInstall normally relies on the Spotlight index to locate installed versions of Xcode. If you use it while
|
|
153
163
|
indexing is happening, it might show inaccurate results and it will not be able to see installed
|
|
154
|
-
versions on unindexed volumes.
|
|
164
|
+
versions on unindexed volumes.
|
|
155
165
|
|
|
156
166
|
To workaround the Spotlight limitation, XcodeInstall searches `/Applications` folder to locate Xcodes when Spotlight is disabled on the machine, or when Spotlight query for Xcode does not return any results. But it still won't work if your Xcodes are not located under `/Applications` folder.
|
|
157
167
|
|
|
@@ -165,7 +175,7 @@ project, especially [@henrikhodne][6] and [@lacostej][7] for making XcodeInstall
|
|
|
165
175
|
|
|
166
176
|
## Contributing
|
|
167
177
|
|
|
168
|
-
1. Fork it ( https://github.com/
|
|
178
|
+
1. Fork it ( https://github.com/xcpretty/xcode-install/fork )
|
|
169
179
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
170
180
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
171
181
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/XCODE_VERSION.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# `.xcode-version`
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
This is a proposal for a new standard for the iOS community: a text-based file that defines the Xcode version to use to compile and package a given iOS project.
|
|
6
|
+
|
|
7
|
+
This will be used by this gem, however it's designed in a way that any tool in the future can pick it up, no matter if it's Ruby based, Swift, JavaScript, etc.
|
|
8
|
+
|
|
9
|
+
Similar to the [.ruby-version file](https://en.wikipedia.org/wiki/Ruby_Version_Manager), the `.xcode-version` file allows any CI system or IDE to automatically install and switch to the Xcode version needed for a given project to successfully compile your project.
|
|
10
|
+
|
|
11
|
+
## Filename
|
|
12
|
+
|
|
13
|
+
The filename must always be `.xcode-version`.
|
|
14
|
+
|
|
15
|
+
## File location
|
|
16
|
+
|
|
17
|
+
The file must be located in the same directory as your Xcode project/workspace, and you should add it to your versioning system (e.g. git).
|
|
18
|
+
|
|
19
|
+
## File content
|
|
20
|
+
|
|
21
|
+
The file content must be a simple string in a text file. The file may or may not end with an empty new line, this gem is responsible for stripping out the trailing `\n` (if used).
|
|
22
|
+
|
|
23
|
+
### Sample files
|
|
24
|
+
|
|
25
|
+
To define an official Xcode release
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
9.3
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
7.2.1
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You can also use pre-releases
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
11.5 GM Seed
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
12 beta 6
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Always following the same version naming listed by `xcversion list`.
|
|
46
|
+
|
|
47
|
+
**Note**: Be aware that pre-releases might be eventually taken down from Apple's servers, meaning that it won't allow you to have fully reproducible builds as you won't be able to download the Xcode release once it's gone.
|
|
48
|
+
|
|
49
|
+
It is recommended to only use non-beta releases in an `.xcode-version` file to have fully reproducible builds that you'll be able to run in a few years also.
|
|
@@ -17,13 +17,14 @@ module XcodeInstall
|
|
|
17
17
|
['--no-install', 'Only download DMG, but do not install it.'],
|
|
18
18
|
['--no-progress', 'Don’t show download progress.'],
|
|
19
19
|
['--no-clean', 'Don’t delete DMG after installation.'],
|
|
20
|
-
['--no-show-release-notes', 'Don’t open release notes in browser after installation.']
|
|
20
|
+
['--no-show-release-notes', 'Don’t open release notes in browser after installation.'],
|
|
21
|
+
['--retry-download-count', 'Count of retrying download when curl is failed.']].concat(super)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def initialize(argv)
|
|
24
25
|
@installer = Installer.new
|
|
25
26
|
@version = argv.shift_argument
|
|
26
|
-
@version ||= File.read('.xcode-version') if File.exist?('.xcode-version')
|
|
27
|
+
@version ||= File.read('.xcode-version').strip if File.exist?('.xcode-version')
|
|
27
28
|
@url = argv.option('url')
|
|
28
29
|
@force = argv.flag?('force', false)
|
|
29
30
|
@should_clean = argv.flag?('clean', true)
|
|
@@ -31,6 +32,7 @@ module XcodeInstall
|
|
|
31
32
|
@should_switch = argv.flag?('switch', true)
|
|
32
33
|
@progress = argv.flag?('progress', true)
|
|
33
34
|
@show_release_notes = argv.flag?('show-release-notes', true)
|
|
35
|
+
@retry_download_count = argv.option('retry-download-count', '3')
|
|
34
36
|
super
|
|
35
37
|
end
|
|
36
38
|
|
|
@@ -44,11 +46,12 @@ module XcodeInstall
|
|
|
44
46
|
end
|
|
45
47
|
fail Informative, "Version #{@version} doesn't exist." unless @url || @installer.exist?(@version)
|
|
46
48
|
fail Informative, "Invalid URL: `#{@url}`" unless !@url || @url =~ /\A#{URI.regexp}\z/
|
|
49
|
+
fail Informative, "Invalid Retry: `#{@retry_download_count} is not positive number.`" if (@retry_download_count =~ /\A[0-9]*\z/).nil?
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def run
|
|
50
53
|
@installer.install_version(@version, @should_switch, @should_clean, @should_install,
|
|
51
|
-
@progress, @url, @show_release_notes)
|
|
54
|
+
@progress, @url, @show_release_notes, nil, @retry_download_count.to_i)
|
|
52
55
|
end
|
|
53
56
|
end
|
|
54
57
|
end
|
data/lib/xcode/install/select.rb
CHANGED
|
@@ -28,7 +28,7 @@ module XcodeInstall
|
|
|
28
28
|
|
|
29
29
|
def run
|
|
30
30
|
xcode = @installer.installed_versions.detect { |v| v.version == @version }
|
|
31
|
-
`sudo xcode-select --switch #{xcode.path}`
|
|
31
|
+
`sudo xcode-select --switch "#{xcode.path}"`
|
|
32
32
|
@installer.symlink xcode.version if @should_symlink
|
|
33
33
|
end
|
|
34
34
|
end
|
data/lib/xcode/install.rb
CHANGED
|
@@ -8,8 +8,10 @@ require 'xcode/install/command'
|
|
|
8
8
|
require 'xcode/install/version'
|
|
9
9
|
require 'shellwords'
|
|
10
10
|
require 'open3'
|
|
11
|
+
require 'fastlane'
|
|
12
|
+
require 'fastlane/helper/sh_helper'
|
|
11
13
|
require 'fastlane/action'
|
|
12
|
-
require 'fastlane/actions/
|
|
14
|
+
require 'fastlane/actions/verify_xcode'
|
|
13
15
|
|
|
14
16
|
module XcodeInstall
|
|
15
17
|
CACHE_DIR = Pathname.new("#{ENV['HOME']}/Library/Caches/XcodeInstall")
|
|
@@ -23,13 +25,14 @@ module XcodeInstall
|
|
|
23
25
|
# @param progress: parse and show the progress?
|
|
24
26
|
# @param progress_block: A block that's called whenever we have an updated progress %
|
|
25
27
|
# the parameter is a single number that's literally percent (e.g. 1, 50, 80 or 100)
|
|
26
|
-
#
|
|
28
|
+
# @param retry_download_count: A count to retry the downloading Xcode dmg/xip
|
|
27
29
|
def fetch(url: nil,
|
|
28
30
|
directory: nil,
|
|
29
31
|
cookies: nil,
|
|
30
32
|
output: nil,
|
|
31
33
|
progress: nil,
|
|
32
|
-
progress_block: nil
|
|
34
|
+
progress_block: nil,
|
|
35
|
+
retry_download_count: 3)
|
|
33
36
|
options = cookies.nil? ? [] : ['--cookie', cookies, '--cookie-jar', COOKIES_PATH]
|
|
34
37
|
|
|
35
38
|
uri = URI.parse(url)
|
|
@@ -76,38 +79,8 @@ module XcodeInstall
|
|
|
76
79
|
# "Partial file. Only a part of the file was transferred."
|
|
77
80
|
# https://curl.haxx.se/mail/archive-2008-07/0098.html
|
|
78
81
|
# https://github.com/KrauseFx/xcode-install/issues/210
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# We're not using the block based syntax, as the bacon testing
|
|
82
|
-
# library doesn't seem to support writing tests for it
|
|
83
|
-
stdin, stdout, stderr, wait_thr = Open3.popen3(command_string)
|
|
84
|
-
|
|
85
|
-
# Poll the file and see if we're done yet
|
|
86
|
-
while wait_thr.alive?
|
|
87
|
-
sleep(0.5) # it's not critical for this to be real-time
|
|
88
|
-
next unless File.exist?(progress_log_file) # it might take longer for it to be created
|
|
89
|
-
|
|
90
|
-
progress_content = File.read(progress_log_file).split("\r").last
|
|
91
|
-
|
|
92
|
-
# Print out the progress for the CLI
|
|
93
|
-
if progress
|
|
94
|
-
print "\r#{progress_content}%"
|
|
95
|
-
$stdout.flush
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Call back the block for other processes that might be interested
|
|
99
|
-
matched = progress_content.match(/^\s*(\d+)/)
|
|
100
|
-
next unless matched && matched.length == 2
|
|
101
|
-
percent = matched[1].to_i
|
|
102
|
-
progress_block.call(percent) if progress_block
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# as we're not making use of the block-based syntax
|
|
106
|
-
# we need to manually close those
|
|
107
|
-
stdin.close
|
|
108
|
-
stdout.close
|
|
109
|
-
stderr.close
|
|
110
|
-
|
|
82
|
+
retry_download_count.times do
|
|
83
|
+
wait_thr = poll_file(command_string: command_string, progress_log_file: progress_log_file, progress: progress, progress_block: progress_block)
|
|
111
84
|
return wait_thr.value.success? if wait_thr.value.success?
|
|
112
85
|
end
|
|
113
86
|
false
|
|
@@ -115,6 +88,41 @@ module XcodeInstall
|
|
|
115
88
|
FileUtils.rm_f(COOKIES_PATH)
|
|
116
89
|
FileUtils.rm_f(progress_log_file)
|
|
117
90
|
end
|
|
91
|
+
|
|
92
|
+
def poll_file(command_string:, progress_log_file:, progress: nil, progress_block: nil)
|
|
93
|
+
# Non-blocking call of Open3
|
|
94
|
+
# We're not using the block based syntax, as the bacon testing
|
|
95
|
+
# library doesn't seem to support writing tests for it
|
|
96
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(command_string)
|
|
97
|
+
|
|
98
|
+
# Poll the file and see if we're done yet
|
|
99
|
+
while wait_thr.alive?
|
|
100
|
+
sleep(0.5) # it's not critical for this to be real-time
|
|
101
|
+
next unless File.exist?(progress_log_file) # it might take longer for it to be created
|
|
102
|
+
|
|
103
|
+
progress_content = File.read(progress_log_file).split("\r").last || ''
|
|
104
|
+
|
|
105
|
+
# Print out the progress for the CLI
|
|
106
|
+
if progress
|
|
107
|
+
print "\r#{progress_content}%"
|
|
108
|
+
$stdout.flush
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Call back the block for other processes that might be interested
|
|
112
|
+
matched = progress_content.match(/^\s*(\d+)/)
|
|
113
|
+
next unless matched && matched.length == 2
|
|
114
|
+
percent = matched[1].to_i
|
|
115
|
+
progress_block.call(percent) if progress_block
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# as we're not making use of the block-based syntax
|
|
119
|
+
# we need to manually close those
|
|
120
|
+
stdin.close
|
|
121
|
+
stdout.close
|
|
122
|
+
stderr.close
|
|
123
|
+
|
|
124
|
+
wait_thr
|
|
125
|
+
end
|
|
118
126
|
end
|
|
119
127
|
|
|
120
128
|
# rubocop:disable Metrics/ClassLength
|
|
@@ -133,7 +141,7 @@ module XcodeInstall
|
|
|
133
141
|
File.symlink?(SYMLINK_PATH) ? SYMLINK_PATH : nil
|
|
134
142
|
end
|
|
135
143
|
|
|
136
|
-
def download(version, progress, url = nil, progress_block = nil)
|
|
144
|
+
def download(version, progress, url = nil, progress_block = nil, retry_download_count = 3)
|
|
137
145
|
xcode = find_xcode_version(version) if url.nil?
|
|
138
146
|
return if url.nil? && xcode.nil?
|
|
139
147
|
|
|
@@ -145,7 +153,8 @@ module XcodeInstall
|
|
|
145
153
|
cookies: url ? nil : spaceship.cookie,
|
|
146
154
|
output: dmg_file,
|
|
147
155
|
progress: progress,
|
|
148
|
-
progress_block: progress_block
|
|
156
|
+
progress_block: progress_block,
|
|
157
|
+
retry_download_count: retry_download_count
|
|
149
158
|
)
|
|
150
159
|
result ? CACHE_DIR + dmg_file : nil
|
|
151
160
|
end
|
|
@@ -166,8 +175,12 @@ module XcodeInstall
|
|
|
166
175
|
|
|
167
176
|
seedlist.each do |current_seed|
|
|
168
177
|
return current_seed if current_seed.name == version
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
seedlist.each do |current_seed|
|
|
169
181
|
return current_seed if parsed_version && current_seed.version == parsed_version
|
|
170
182
|
end
|
|
183
|
+
|
|
171
184
|
nil
|
|
172
185
|
end
|
|
173
186
|
|
|
@@ -208,7 +221,7 @@ module XcodeInstall
|
|
|
208
221
|
current_xcode.installed = cached_installed_versions.include?(current_xcode.version)
|
|
209
222
|
end
|
|
210
223
|
|
|
211
|
-
all_xcodes.sort_by
|
|
224
|
+
all_xcodes.sort_by { |seed| [seed.version, -seed.date_modified] }.reverse
|
|
212
225
|
end
|
|
213
226
|
|
|
214
227
|
def install_dmg(dmg_path, suffix = '', switch = true, clean = true)
|
|
@@ -274,8 +287,8 @@ HELP
|
|
|
274
287
|
end
|
|
275
288
|
|
|
276
289
|
# rubocop:disable Metrics/ParameterLists
|
|
277
|
-
def install_version(version, switch = true, clean = true, install = true, progress = true, url = nil, show_release_notes = true, progress_block = nil)
|
|
278
|
-
dmg_path = get_dmg(version, progress, url, progress_block)
|
|
290
|
+
def install_version(version, switch = true, clean = true, install = true, progress = true, url = nil, show_release_notes = true, progress_block = nil, retry_download_count = 3)
|
|
291
|
+
dmg_path = get_dmg(version, progress, url, progress_block, retry_download_count)
|
|
279
292
|
fail Informative, "Failed to download Xcode #{version}." if dmg_path.nil?
|
|
280
293
|
|
|
281
294
|
if install
|
|
@@ -294,17 +307,21 @@ HELP
|
|
|
294
307
|
end
|
|
295
308
|
|
|
296
309
|
def list_annotated(xcodes_list)
|
|
297
|
-
installed = installed_versions.map(&:
|
|
310
|
+
installed = installed_versions.map(&:appname_version)
|
|
311
|
+
|
|
298
312
|
xcodes_list.map do |x|
|
|
299
|
-
xcode_version = x.split(' ')
|
|
300
|
-
xcode_version << '.0' unless xcode_version.include?('.')
|
|
313
|
+
xcode_version = x.split(' ') # split version and "beta N", "for Lion"
|
|
314
|
+
xcode_version[0] << '.0' unless xcode_version[0].include?('.')
|
|
301
315
|
|
|
302
|
-
|
|
316
|
+
# to match InstalledXcode.appname_version format
|
|
317
|
+
version = Gem::Version.new(xcode_version.join('.'))
|
|
318
|
+
|
|
319
|
+
installed.include?(version) ? "#{x} (installed)" : x
|
|
303
320
|
end.join("\n")
|
|
304
321
|
end
|
|
305
322
|
|
|
306
323
|
def list
|
|
307
|
-
list_annotated(list_versions.
|
|
324
|
+
list_annotated(list_versions.sort { |first, second| compare_versions(first, second) })
|
|
308
325
|
end
|
|
309
326
|
|
|
310
327
|
def rm_list_cache
|
|
@@ -360,7 +377,7 @@ HELP
|
|
|
360
377
|
`sudo /usr/sbin/dseditgroup -o edit -t group -a staff _developer`
|
|
361
378
|
end
|
|
362
379
|
|
|
363
|
-
def get_dmg(version, progress = true, url = nil, progress_block = nil)
|
|
380
|
+
def get_dmg(version, progress = true, url = nil, progress_block = nil, retry_download_count = 3)
|
|
364
381
|
if url
|
|
365
382
|
path = Pathname.new(url)
|
|
366
383
|
return path if path.exist?
|
|
@@ -371,7 +388,7 @@ HELP
|
|
|
371
388
|
end
|
|
372
389
|
end
|
|
373
390
|
|
|
374
|
-
download(version, progress, url, progress_block)
|
|
391
|
+
download(version, progress, url, progress_block, retry_download_count)
|
|
375
392
|
end
|
|
376
393
|
|
|
377
394
|
def fetch_seedlist
|
|
@@ -451,6 +468,35 @@ HELP
|
|
|
451
468
|
links
|
|
452
469
|
end
|
|
453
470
|
|
|
471
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
472
|
+
def compare_versions(first, second)
|
|
473
|
+
# Sort by version number
|
|
474
|
+
numeric_comparation = first.to_f <=> second.to_f
|
|
475
|
+
return numeric_comparation if numeric_comparation != 0
|
|
476
|
+
|
|
477
|
+
# Return beta versions before others
|
|
478
|
+
is_first_beta = first.include?('beta')
|
|
479
|
+
is_second_beta = second.include?('beta')
|
|
480
|
+
return -1 if is_first_beta && !is_second_beta
|
|
481
|
+
return 1 if !is_first_beta && is_second_beta
|
|
482
|
+
|
|
483
|
+
# Return GM versions before others
|
|
484
|
+
is_first_gm = first.include?('GM')
|
|
485
|
+
is_second_gm = second.include?('GM')
|
|
486
|
+
return -1 if is_first_gm && !is_second_gm
|
|
487
|
+
return 1 if !is_first_gm && is_second_gm
|
|
488
|
+
|
|
489
|
+
# Return Release Candidate versions before others
|
|
490
|
+
is_first_rc = first.include?('RC') || first.include?('Release Candidate')
|
|
491
|
+
is_second_rc = second.include?('RC') || second.include?('Release Candidate')
|
|
492
|
+
return -1 if is_first_rc && !is_second_rc
|
|
493
|
+
return 1 if !is_first_rc && is_second_rc
|
|
494
|
+
|
|
495
|
+
# Sort alphabetically
|
|
496
|
+
first <=> second
|
|
497
|
+
end
|
|
498
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
499
|
+
|
|
454
500
|
def hdiutil(*args)
|
|
455
501
|
io = IO.popen(['hdiutil', *args])
|
|
456
502
|
result = io.read
|
|
@@ -502,12 +548,13 @@ HELP
|
|
|
502
548
|
end
|
|
503
549
|
end
|
|
504
550
|
|
|
505
|
-
def download(progress, progress_block = nil)
|
|
551
|
+
def download(progress, progress_block = nil, retry_download_count = 3)
|
|
506
552
|
result = Curl.new.fetch(
|
|
507
553
|
url: source,
|
|
508
554
|
directory: CACHE_DIR,
|
|
509
555
|
progress: progress,
|
|
510
|
-
progress_block: progress_block
|
|
556
|
+
progress_block: progress_block,
|
|
557
|
+
retry_download_count: retry_download_count
|
|
511
558
|
)
|
|
512
559
|
result ? dmg_path : nil
|
|
513
560
|
end
|
|
@@ -576,9 +623,6 @@ HELP
|
|
|
576
623
|
end
|
|
577
624
|
|
|
578
625
|
class InstalledXcode
|
|
579
|
-
TEAM_IDENTIFIER = '59GAB85EFG'.freeze
|
|
580
|
-
AUTHORITY = 'Software Signing'.freeze
|
|
581
|
-
|
|
582
626
|
attr_reader :path
|
|
583
627
|
attr_reader :version
|
|
584
628
|
attr_reader :bundle_version
|
|
@@ -598,6 +642,17 @@ HELP
|
|
|
598
642
|
@bundle_version ||= Gem::Version.new(bundle_version_string)
|
|
599
643
|
end
|
|
600
644
|
|
|
645
|
+
def appname_version
|
|
646
|
+
appname = @path.basename('.app').to_s
|
|
647
|
+
version_string = appname.split('-').last
|
|
648
|
+
begin
|
|
649
|
+
Gem::Version.new(version_string)
|
|
650
|
+
rescue ArgumentError
|
|
651
|
+
puts 'Unable to determine Xcode version from path name, installed list may not correctly identify installed betas'
|
|
652
|
+
Gem::Version.new(nil)
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
601
656
|
def uuid
|
|
602
657
|
@uuid ||= plist_entry(':DVTPlugInCompatibilityUUID')
|
|
603
658
|
end
|
|
@@ -682,15 +737,15 @@ HELP
|
|
|
682
737
|
end
|
|
683
738
|
|
|
684
739
|
def verify_app_security_assessment
|
|
685
|
-
puts `/usr/
|
|
740
|
+
puts `/usr/bin/codesign --verify --verbose #{@path}`
|
|
686
741
|
$?.exitstatus.zero?
|
|
687
742
|
end
|
|
688
743
|
|
|
689
744
|
def verify_app_cert
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
745
|
+
Fastlane::Actions::VerifyXcodeAction.run(xcode_path: @path.to_s)
|
|
746
|
+
true
|
|
747
|
+
rescue
|
|
748
|
+
false
|
|
694
749
|
end
|
|
695
750
|
end
|
|
696
751
|
|
|
@@ -699,7 +754,7 @@ HELP
|
|
|
699
754
|
#
|
|
700
755
|
# Sample object:
|
|
701
756
|
# <XcodeInstall::Xcode:0x007fa1d451c390
|
|
702
|
-
# @date_modified=
|
|
757
|
+
# @date_modified=1573661580,
|
|
703
758
|
# @name="6.4",
|
|
704
759
|
# @path="/Developer_Tools/Xcode_6.4/Xcode_6.4.dmg",
|
|
705
760
|
# @url=
|
|
@@ -722,7 +777,7 @@ HELP
|
|
|
722
777
|
|
|
723
778
|
def initialize(json, url = nil, release_notes_url = nil)
|
|
724
779
|
if url.nil?
|
|
725
|
-
@date_modified = json['dateModified'].to_i
|
|
780
|
+
@date_modified = DateTime.strptime(json['dateModified'], '%m/%d/%y %H:%M').strftime('%s').to_i
|
|
726
781
|
@name = json['name'].gsub(/^Xcode /, '')
|
|
727
782
|
@path = json['files'].first['remotePath']
|
|
728
783
|
url_prefix = 'https://developer.apple.com/devcenter/download.action?path='
|
|
@@ -754,6 +809,7 @@ HELP
|
|
|
754
809
|
|
|
755
810
|
def self.new_prerelease(version, url, release_notes_path)
|
|
756
811
|
new('name' => version,
|
|
812
|
+
'dateModified' => '01/01/70 00:00',
|
|
757
813
|
'files' => [{ 'remotePath' => url.split('=').last }],
|
|
758
814
|
'release_notes_path' => release_notes_path)
|
|
759
815
|
end
|
data/spec/fixtures/xcode.json
CHANGED
|
@@ -1 +1,30 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "Xcode 9.3",
|
|
3
|
+
"description": "This is the complete Xcode developer toolset for Apple Watch, Apple TV, iPhone, iPad, and Mac. It includes the Xcode IDE, iOS Simulator, and all required tools and frameworks for building iOS, watchOS, tvOS and macOS apps.",
|
|
4
|
+
"isReleased": 1,
|
|
5
|
+
"datePublished": "03/23/18 09:47",
|
|
6
|
+
"dateCreated": "11/01/19 12:00",
|
|
7
|
+
"dateModified": "11/01/19 12:58",
|
|
8
|
+
"categories": [
|
|
9
|
+
{
|
|
10
|
+
"id": 187,
|
|
11
|
+
"name": "Developer Tools",
|
|
12
|
+
"sortOrder": 28
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"filename": "Xcode 9.3.xip",
|
|
18
|
+
"displayName": "Xcode 9.3",
|
|
19
|
+
"remotePath": "/Developer_Tools/Xcode_9.3/Xcode_9.3.xip",
|
|
20
|
+
"fileSize": 5235094775,
|
|
21
|
+
"sortOrder": 0,
|
|
22
|
+
"dateCreated": "11/01/19 19:00",
|
|
23
|
+
"dateModified": "11/01/19 19:58",
|
|
24
|
+
"fileFormat": {
|
|
25
|
+
"extension": ".xip",
|
|
26
|
+
"description": "XIP"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
data/spec/fixtures/xcode_63.json
CHANGED
|
@@ -1,46 +1,30 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"description": "Disk Image",
|
|
31
|
-
"extension": ".dmg",
|
|
32
|
-
"id": 12
|
|
33
|
-
},
|
|
34
|
-
"id": 35240,
|
|
35
|
-
"name": "Xcode 6.3",
|
|
36
|
-
"remotePath": "/Developer_Tools/Xcode_6.2/Xcode_6.2.dmg",
|
|
37
|
-
"sortOrder": null,
|
|
38
|
-
"state": "ENABLED"
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"id": 23600,
|
|
42
|
-
"name": "Xcode 6.3",
|
|
43
|
-
"prerelease": false,
|
|
44
|
-
"releasedSeed": true,
|
|
45
|
-
"state": "ENABLED"
|
|
2
|
+
"name": "Xcode 6.3",
|
|
3
|
+
"description": "This is the complete Xcode developer toolset for Apple Watch, iPhone, iPad, and Mac. It includes the Xcode IDE, iOS Simulator, and all required tools and frameworks for building OS X and iOS apps.",
|
|
4
|
+
"isReleased": 1,
|
|
5
|
+
"datePublished": "04/08/15 14:36",
|
|
6
|
+
"dateCreated": "12/11/19 13:41",
|
|
7
|
+
"dateModified": "12/11/19 14:28",
|
|
8
|
+
"categories": [
|
|
9
|
+
{
|
|
10
|
+
"id": 187,
|
|
11
|
+
"name": "Developer Tools",
|
|
12
|
+
"sortOrder": 28
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"filename": "Xcode 6.3.dmg",
|
|
18
|
+
"displayName": "Xcode 6.3",
|
|
19
|
+
"remotePath": "/Developer_Tools/Xcode_6.3/Xcode_6.3.dmg",
|
|
20
|
+
"fileSize": 2685818165,
|
|
21
|
+
"sortOrder": 0,
|
|
22
|
+
"dateCreated": "12/11/19 21:41",
|
|
23
|
+
"dateModified": "12/11/19 22:28",
|
|
24
|
+
"fileFormat": {
|
|
25
|
+
"extension": ".dmg",
|
|
26
|
+
"description": "Disk Image"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
46
30
|
}
|