xcode-install 2.4.0 → 2.6.7
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/.circleci/config.yml +33 -0
- data/.github/workflows/ci.yml +36 -0
- data/README.md +5 -3
- data/lib/xcode/install/cli.rb +4 -1
- data/lib/xcode/install/install.rb +10 -3
- data/lib/xcode/install/select.rb +1 -1
- data/lib/xcode/install/version.rb +1 -1
- data/lib/xcode/install.rb +124 -41
- 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 +12 -4
- data/spec/installer_spec.rb +116 -90
- data/spec/json_spec.rb +14 -4
- data/spec/list_spec.rb +56 -3
- data/xcode-install.gemspec +1 -1
- metadata +12 -12
- data/circle.yml +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0fea81231fe9d81aed11e53e9340d8749cb90b12b61cf455ef216c4659beaf85
|
|
4
|
+
data.tar.gz: d385404265a3453ff25f3f6c2c532235ca7ed9769e0c1b808c64749f930f6eca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4147ef290648e0f0ac2122be32a2cc0d4fd26d3c9509767661107527fe20e58534bab89c505d992a876202a40effa7913b3901e24f504952839e5f416d011503
|
|
7
|
+
data.tar.gz: fa470926afe6472b552bd7be37619542024913101997df6e00a47064714199594c6c0dafbf1a41c07aa79ea1cb22e35f3cca75a1bbce8bb068b9453ec7bc6a6d
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
jobs:
|
|
4
|
+
build:
|
|
5
|
+
macos:
|
|
6
|
+
xcode: "9.0"
|
|
7
|
+
working_directory: ~/xcode-install
|
|
8
|
+
shell: /bin/bash --login -eo pipefail
|
|
9
|
+
steps:
|
|
10
|
+
- checkout
|
|
11
|
+
|
|
12
|
+
# See Also: https://discuss.circleci.com/t/circleci-2-0-ios-error-installing-gems/23291/4
|
|
13
|
+
- run:
|
|
14
|
+
name: Set Ruby Version
|
|
15
|
+
command: echo "ruby-2.4" > ~/.ruby-version
|
|
16
|
+
|
|
17
|
+
- run:
|
|
18
|
+
name: Install ruby dependencies
|
|
19
|
+
command: bundle install
|
|
20
|
+
|
|
21
|
+
- run:
|
|
22
|
+
name: Run test
|
|
23
|
+
command: bundle exec rake spec
|
|
24
|
+
|
|
25
|
+
- run:
|
|
26
|
+
name: Run lint
|
|
27
|
+
command: bundle exec rake rubocop
|
|
28
|
+
|
|
29
|
+
workflows:
|
|
30
|
+
version: 2
|
|
31
|
+
build_and_test:
|
|
32
|
+
jobs:
|
|
33
|
+
- build
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: "CI"
|
|
2
|
+
on: [pull_request]
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
build:
|
|
6
|
+
strategy:
|
|
7
|
+
fail-fast: false
|
|
8
|
+
matrix:
|
|
9
|
+
ruby: ["2.5", "2.6"]
|
|
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 ruby version
|
|
23
|
+
run: |
|
|
24
|
+
ruby --version
|
|
25
|
+
bundler --version
|
|
26
|
+
|
|
27
|
+
# Prepare
|
|
28
|
+
- name: Install bundler 1.7
|
|
29
|
+
run: gem install bundler -v "~> 1.7"
|
|
30
|
+
- name: Install ruby dependencies
|
|
31
|
+
run: bundle install -j4 --clean --path=vendor
|
|
32
|
+
|
|
33
|
+
- name: Run test
|
|
34
|
+
run: bundle exec rake spec
|
|
35
|
+
- name: Run lint
|
|
36
|
+
run: bundle exec rake rubocop
|
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://circleci.com/gh/xcpretty/xcode-install)
|
|
4
4
|
|
|
5
5
|
Install and update your Xcodes automatically.
|
|
6
6
|
|
|
@@ -149,9 +149,11 @@ XcodeInstall automatically installs additional components so that it is immediat
|
|
|
149
149
|
commandline. Unfortunately, Xcode will load third-party plugins even in that situation, which leads
|
|
150
150
|
to a dialog popping up. Feel free to dupe [the radar][5]. 📡
|
|
151
151
|
|
|
152
|
-
XcodeInstall
|
|
152
|
+
XcodeInstall normally relies on the Spotlight index to locate installed versions of Xcode. If you use it while
|
|
153
153
|
indexing is happening, it might show inaccurate results and it will not be able to see installed
|
|
154
|
-
versions on unindexed volumes.
|
|
154
|
+
versions on unindexed volumes.
|
|
155
|
+
|
|
156
|
+
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.
|
|
155
157
|
|
|
156
158
|
## Thanks
|
|
157
159
|
|
data/lib/xcode/install/cli.rb
CHANGED
|
@@ -5,7 +5,10 @@ module XcodeInstall
|
|
|
5
5
|
self.summary = 'Installs Xcode Command Line Tools.'
|
|
6
6
|
|
|
7
7
|
def run
|
|
8
|
-
|
|
8
|
+
if installed?
|
|
9
|
+
print 'Xcode CLI Tools are already installed.'
|
|
10
|
+
exit(0)
|
|
11
|
+
end
|
|
9
12
|
install
|
|
10
13
|
end
|
|
11
14
|
|
|
@@ -17,12 +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
|
|
27
|
+
@version ||= File.read('.xcode-version') if File.exist?('.xcode-version')
|
|
26
28
|
@url = argv.option('url')
|
|
27
29
|
@force = argv.flag?('force', false)
|
|
28
30
|
@should_clean = argv.flag?('clean', true)
|
|
@@ -30,6 +32,7 @@ module XcodeInstall
|
|
|
30
32
|
@should_switch = argv.flag?('switch', true)
|
|
31
33
|
@progress = argv.flag?('progress', true)
|
|
32
34
|
@show_release_notes = argv.flag?('show-release-notes', true)
|
|
35
|
+
@retry_download_count = argv.option('retry-download-count', '3')
|
|
33
36
|
super
|
|
34
37
|
end
|
|
35
38
|
|
|
@@ -37,14 +40,18 @@ module XcodeInstall
|
|
|
37
40
|
super
|
|
38
41
|
|
|
39
42
|
help! 'A VERSION argument is required.' unless @version
|
|
40
|
-
|
|
43
|
+
if @installer.installed?(@version) && !@force
|
|
44
|
+
print "Version #{@version} already installed."
|
|
45
|
+
exit(0)
|
|
46
|
+
end
|
|
41
47
|
fail Informative, "Version #{@version} doesn't exist." unless @url || @installer.exist?(@version)
|
|
42
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?
|
|
43
50
|
end
|
|
44
51
|
|
|
45
52
|
def run
|
|
46
53
|
@installer.install_version(@version, @should_switch, @should_clean, @should_install,
|
|
47
|
-
@progress, @url, @show_release_notes)
|
|
54
|
+
@progress, @url, @show_release_notes, nil, @retry_download_count.to_i)
|
|
48
55
|
end
|
|
49
56
|
end
|
|
50
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,7 +8,10 @@ require 'xcode/install/command'
|
|
|
8
8
|
require 'xcode/install/version'
|
|
9
9
|
require 'shellwords'
|
|
10
10
|
require 'open3'
|
|
11
|
-
require '
|
|
11
|
+
require 'fastlane'
|
|
12
|
+
require 'fastlane/helper/sh_helper'
|
|
13
|
+
require 'fastlane/action'
|
|
14
|
+
require 'fastlane/actions/verify_xcode'
|
|
12
15
|
|
|
13
16
|
module XcodeInstall
|
|
14
17
|
CACHE_DIR = Pathname.new("#{ENV['HOME']}/Library/Caches/XcodeInstall")
|
|
@@ -22,13 +25,15 @@ module XcodeInstall
|
|
|
22
25
|
# @param progress: parse and show the progress?
|
|
23
26
|
# @param progress_block: A block that's called whenever we have an updated progress %
|
|
24
27
|
# the parameter is a single number that's literally percent (e.g. 1, 50, 80 or 100)
|
|
28
|
+
# @param retry_download_count: A count to retry the downloading Xcode dmg/xip
|
|
25
29
|
# rubocop:disable Metrics/AbcSize
|
|
26
30
|
def fetch(url: nil,
|
|
27
31
|
directory: nil,
|
|
28
32
|
cookies: nil,
|
|
29
33
|
output: nil,
|
|
30
34
|
progress: nil,
|
|
31
|
-
progress_block: nil
|
|
35
|
+
progress_block: nil,
|
|
36
|
+
retry_download_count: 3)
|
|
32
37
|
options = cookies.nil? ? [] : ['--cookie', cookies, '--cookie-jar', COOKIES_PATH]
|
|
33
38
|
|
|
34
39
|
uri = URI.parse(url)
|
|
@@ -57,6 +62,7 @@ module XcodeInstall
|
|
|
57
62
|
retry_options = ['--retry', '3']
|
|
58
63
|
command = [
|
|
59
64
|
'curl',
|
|
65
|
+
'--disable',
|
|
60
66
|
*options,
|
|
61
67
|
*retry_options,
|
|
62
68
|
'--location',
|
|
@@ -74,7 +80,7 @@ module XcodeInstall
|
|
|
74
80
|
# "Partial file. Only a part of the file was transferred."
|
|
75
81
|
# https://curl.haxx.se/mail/archive-2008-07/0098.html
|
|
76
82
|
# https://github.com/KrauseFx/xcode-install/issues/210
|
|
77
|
-
|
|
83
|
+
retry_download_count.times do
|
|
78
84
|
# Non-blocking call of Open3
|
|
79
85
|
# We're not using the block based syntax, as the bacon testing
|
|
80
86
|
# library doesn't seem to support writing tests for it
|
|
@@ -95,7 +101,7 @@ module XcodeInstall
|
|
|
95
101
|
|
|
96
102
|
# Call back the block for other processes that might be interested
|
|
97
103
|
matched = progress_content.match(/^\s*(\d+)/)
|
|
98
|
-
next unless matched.length == 2
|
|
104
|
+
next unless matched && matched.length == 2
|
|
99
105
|
percent = matched[1].to_i
|
|
100
106
|
progress_block.call(percent) if progress_block
|
|
101
107
|
end
|
|
@@ -131,7 +137,7 @@ module XcodeInstall
|
|
|
131
137
|
File.symlink?(SYMLINK_PATH) ? SYMLINK_PATH : nil
|
|
132
138
|
end
|
|
133
139
|
|
|
134
|
-
def download(version, progress, url = nil, progress_block = nil)
|
|
140
|
+
def download(version, progress, url = nil, progress_block = nil, retry_download_count = 3)
|
|
135
141
|
xcode = find_xcode_version(version) if url.nil?
|
|
136
142
|
return if url.nil? && xcode.nil?
|
|
137
143
|
|
|
@@ -143,7 +149,8 @@ module XcodeInstall
|
|
|
143
149
|
cookies: url ? nil : spaceship.cookie,
|
|
144
150
|
output: dmg_file,
|
|
145
151
|
progress: progress,
|
|
146
|
-
progress_block: progress_block
|
|
152
|
+
progress_block: progress_block,
|
|
153
|
+
retry_download_count: retry_download_count
|
|
147
154
|
)
|
|
148
155
|
result ? CACHE_DIR + dmg_file : nil
|
|
149
156
|
end
|
|
@@ -164,8 +171,12 @@ module XcodeInstall
|
|
|
164
171
|
|
|
165
172
|
seedlist.each do |current_seed|
|
|
166
173
|
return current_seed if current_seed.name == version
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
seedlist.each do |current_seed|
|
|
167
177
|
return current_seed if parsed_version && current_seed.version == parsed_version
|
|
168
178
|
end
|
|
179
|
+
|
|
169
180
|
nil
|
|
170
181
|
end
|
|
171
182
|
|
|
@@ -206,18 +217,17 @@ module XcodeInstall
|
|
|
206
217
|
current_xcode.installed = cached_installed_versions.include?(current_xcode.version)
|
|
207
218
|
end
|
|
208
219
|
|
|
209
|
-
all_xcodes.sort_by
|
|
220
|
+
all_xcodes.sort_by { |seed| [seed.version, -seed.date_modified] }.reverse
|
|
210
221
|
end
|
|
211
222
|
|
|
212
223
|
def install_dmg(dmg_path, suffix = '', switch = true, clean = true)
|
|
213
|
-
archive_util = '/System/Library/CoreServices/Applications/Archive Utility.app/Contents/MacOS/Archive Utility'
|
|
214
224
|
prompt = "Please authenticate for Xcode installation.\nPassword: "
|
|
215
225
|
xcode_path = "/Applications/Xcode#{suffix}.app"
|
|
216
226
|
|
|
217
227
|
if dmg_path.extname == '.xip'
|
|
218
|
-
`
|
|
219
|
-
xcode_orig_path =
|
|
220
|
-
xcode_beta_path =
|
|
228
|
+
`xip -x #{dmg_path}`
|
|
229
|
+
xcode_orig_path = File.join(Dir.pwd, 'Xcode.app')
|
|
230
|
+
xcode_beta_path = File.join(Dir.pwd, 'Xcode-beta.app')
|
|
221
231
|
if Pathname.new(xcode_orig_path).exist?
|
|
222
232
|
`sudo -p "#{prompt}" mv "#{xcode_orig_path}" "#{xcode_path}"`
|
|
223
233
|
elsif Pathname.new(xcode_beta_path).exist?
|
|
@@ -250,13 +260,14 @@ HELP
|
|
|
250
260
|
`umount "/Volumes/Xcode"`
|
|
251
261
|
end
|
|
252
262
|
|
|
253
|
-
|
|
263
|
+
xcode = InstalledXcode.new(xcode_path)
|
|
264
|
+
|
|
265
|
+
unless xcode.verify_integrity
|
|
254
266
|
`sudo rm -rf #{xcode_path}`
|
|
255
267
|
return
|
|
256
268
|
end
|
|
257
269
|
|
|
258
270
|
enable_developer_mode
|
|
259
|
-
xcode = InstalledXcode.new(xcode_path)
|
|
260
271
|
xcode.approve_license
|
|
261
272
|
xcode.install_components
|
|
262
273
|
|
|
@@ -272,12 +283,12 @@ HELP
|
|
|
272
283
|
end
|
|
273
284
|
|
|
274
285
|
# rubocop:disable Metrics/ParameterLists
|
|
275
|
-
def install_version(version, switch = true, clean = true, install = true, progress = true, url = nil, show_release_notes = true, progress_block = nil)
|
|
276
|
-
dmg_path = get_dmg(version, progress, url, progress_block)
|
|
286
|
+
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)
|
|
287
|
+
dmg_path = get_dmg(version, progress, url, progress_block, retry_download_count)
|
|
277
288
|
fail Informative, "Failed to download Xcode #{version}." if dmg_path.nil?
|
|
278
289
|
|
|
279
290
|
if install
|
|
280
|
-
install_dmg(dmg_path, "-#{version.to_s.split(' ')
|
|
291
|
+
install_dmg(dmg_path, "-#{version.to_s.split(' ').join('.')}", switch, clean)
|
|
281
292
|
else
|
|
282
293
|
puts "Downloaded Xcode #{version} to '#{dmg_path}'"
|
|
283
294
|
end
|
|
@@ -292,12 +303,21 @@ HELP
|
|
|
292
303
|
end
|
|
293
304
|
|
|
294
305
|
def list_annotated(xcodes_list)
|
|
295
|
-
installed = installed_versions.map(&:
|
|
296
|
-
|
|
306
|
+
installed = installed_versions.map(&:appname_version)
|
|
307
|
+
|
|
308
|
+
xcodes_list.map do |x|
|
|
309
|
+
xcode_version = x.split(' ') # split version and "beta N", "for Lion"
|
|
310
|
+
xcode_version[0] << '.0' unless xcode_version[0].include?('.')
|
|
311
|
+
|
|
312
|
+
# to match InstalledXcode.appname_version format
|
|
313
|
+
version = Gem::Version.new(xcode_version.join('.'))
|
|
314
|
+
|
|
315
|
+
installed.include?(version) ? "#{x} (installed)" : x
|
|
316
|
+
end.join("\n")
|
|
297
317
|
end
|
|
298
318
|
|
|
299
319
|
def list
|
|
300
|
-
list_annotated(list_versions.sort)
|
|
320
|
+
list_annotated(list_versions.sort { |first, second| compare_versions(first, second) })
|
|
301
321
|
end
|
|
302
322
|
|
|
303
323
|
def rm_list_cache
|
|
@@ -353,17 +373,18 @@ HELP
|
|
|
353
373
|
`sudo /usr/sbin/dseditgroup -o edit -t group -a staff _developer`
|
|
354
374
|
end
|
|
355
375
|
|
|
356
|
-
def get_dmg(version, progress = true, url = nil, progress_block = nil)
|
|
376
|
+
def get_dmg(version, progress = true, url = nil, progress_block = nil, retry_download_count = 3)
|
|
357
377
|
if url
|
|
358
378
|
path = Pathname.new(url)
|
|
359
379
|
return path if path.exist?
|
|
360
380
|
end
|
|
361
381
|
if ENV.key?('XCODE_INSTALL_CACHE_DIR')
|
|
362
|
-
|
|
363
|
-
|
|
382
|
+
Pathname.glob(ENV['XCODE_INSTALL_CACHE_DIR'] + '/*').each do |fpath|
|
|
383
|
+
return fpath if /^xcode_#{version}\.dmg|xip$/ =~ fpath.basename.to_s
|
|
384
|
+
end
|
|
364
385
|
end
|
|
365
386
|
|
|
366
|
-
download(version, progress, url, progress_block)
|
|
387
|
+
download(version, progress, url, progress_block, retry_download_count)
|
|
367
388
|
end
|
|
368
389
|
|
|
369
390
|
def fetch_seedlist
|
|
@@ -381,11 +402,13 @@ HELP
|
|
|
381
402
|
end
|
|
382
403
|
|
|
383
404
|
def installed
|
|
384
|
-
|
|
385
|
-
|
|
405
|
+
result = `mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'" 2>/dev/null`.split("\n")
|
|
406
|
+
if result.empty?
|
|
407
|
+
result = `find /Applications -maxdepth 1 -name '*.app' -type d -exec sh -c \
|
|
408
|
+
'if [ "$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" \
|
|
409
|
+
"{}/Contents/Info.plist" 2>/dev/null)" == "com.apple.dt.Xcode" ]; then echo "{}"; fi' ';'`.split("\n")
|
|
386
410
|
end
|
|
387
|
-
|
|
388
|
-
`mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'" 2>/dev/null`.split("\n")
|
|
411
|
+
result
|
|
389
412
|
end
|
|
390
413
|
|
|
391
414
|
def parse_seedlist(seedlist)
|
|
@@ -433,7 +456,7 @@ HELP
|
|
|
433
456
|
return [] if scan.empty?
|
|
434
457
|
|
|
435
458
|
version = scan.first.gsub(/<.*?>/, '').gsub(/.*Xcode /, '')
|
|
436
|
-
link = body.scan(%r{<button .*"(.+?.xip)".*</button>}).first.first
|
|
459
|
+
link = body.scan(%r{<button .*"(.+?.(dmg|xip))".*</button>}).first.first
|
|
437
460
|
notes = body.scan(%r{<a.+?href="(/go/\?id=xcode-.+?)".*>(.*)</a>}).first.first
|
|
438
461
|
links << Xcode.new(version, link, notes)
|
|
439
462
|
end
|
|
@@ -441,9 +464,25 @@ HELP
|
|
|
441
464
|
links
|
|
442
465
|
end
|
|
443
466
|
|
|
444
|
-
def
|
|
445
|
-
|
|
446
|
-
|
|
467
|
+
def compare_versions(first, second)
|
|
468
|
+
# Sort by version number
|
|
469
|
+
numeric_comparation = first.to_f <=> second.to_f
|
|
470
|
+
return numeric_comparation if numeric_comparation != 0
|
|
471
|
+
|
|
472
|
+
# Return beta versions before others
|
|
473
|
+
is_first_beta = first.include?('beta')
|
|
474
|
+
is_second_beta = second.include?('beta')
|
|
475
|
+
return -1 if is_first_beta && !is_second_beta
|
|
476
|
+
return 1 if !is_first_beta && is_second_beta
|
|
477
|
+
|
|
478
|
+
# Return GM versions before others
|
|
479
|
+
is_first_gm = first.include?('GM')
|
|
480
|
+
is_second_gm = second.include?('GM')
|
|
481
|
+
return -1 if is_first_gm && !is_second_gm
|
|
482
|
+
return 1 if !is_first_gm && is_second_gm
|
|
483
|
+
|
|
484
|
+
# Sort alphabetically
|
|
485
|
+
first <=> second
|
|
447
486
|
end
|
|
448
487
|
|
|
449
488
|
def hdiutil(*args)
|
|
@@ -497,12 +536,13 @@ HELP
|
|
|
497
536
|
end
|
|
498
537
|
end
|
|
499
538
|
|
|
500
|
-
def download(progress, progress_block = nil)
|
|
539
|
+
def download(progress, progress_block = nil, retry_download_count = 3)
|
|
501
540
|
result = Curl.new.fetch(
|
|
502
541
|
url: source,
|
|
503
542
|
directory: CACHE_DIR,
|
|
504
543
|
progress: progress,
|
|
505
|
-
progress_block: progress_block
|
|
544
|
+
progress_block: progress_block,
|
|
545
|
+
retry_download_count: retry_download_count
|
|
506
546
|
)
|
|
507
547
|
result ? dmg_path : nil
|
|
508
548
|
end
|
|
@@ -587,7 +627,18 @@ HELP
|
|
|
587
627
|
end
|
|
588
628
|
|
|
589
629
|
def bundle_version
|
|
590
|
-
@bundle_version ||= Gem::Version.new(
|
|
630
|
+
@bundle_version ||= Gem::Version.new(bundle_version_string)
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
def appname_version
|
|
634
|
+
appname = @path.basename('.app').to_s
|
|
635
|
+
version_string = appname.split('-').last
|
|
636
|
+
begin
|
|
637
|
+
Gem::Version.new(version_string)
|
|
638
|
+
rescue ArgumentError
|
|
639
|
+
puts 'Unable to determine Xcode version from path name, installed list may not correctly identify installed betas'
|
|
640
|
+
Gem::Version.new(nil)
|
|
641
|
+
end
|
|
591
642
|
end
|
|
592
643
|
|
|
593
644
|
def uuid
|
|
@@ -606,12 +657,18 @@ HELP
|
|
|
606
657
|
|
|
607
658
|
def approve_license
|
|
608
659
|
if Gem::Version.new(version) < Gem::Version.new('7.3')
|
|
609
|
-
|
|
610
|
-
license_id =
|
|
660
|
+
license_info_path = File.join(@path, 'Contents/Resources/LicenseInfo.plist')
|
|
661
|
+
license_id = `/usr/libexec/PlistBuddy -c 'Print :licenseID' #{license_info_path}`
|
|
662
|
+
license_type = `/usr/libexec/PlistBuddy -c 'Print :licenseType' #{license_info_path}`
|
|
611
663
|
license_plist_path = '/Library/Preferences/com.apple.dt.Xcode.plist'
|
|
612
664
|
`sudo rm -rf #{license_plist_path}`
|
|
613
|
-
|
|
614
|
-
|
|
665
|
+
if license_type == 'GM'
|
|
666
|
+
`sudo /usr/libexec/PlistBuddy -c "add :IDELastGMLicenseAgreedTo string #{license_id}" #{license_plist_path}`
|
|
667
|
+
`sudo /usr/libexec/PlistBuddy -c "add :IDEXcodeVersionForAgreedToGMLicense string #{version}" #{license_plist_path}`
|
|
668
|
+
else
|
|
669
|
+
`sudo /usr/libexec/PlistBuddy -c "add :IDELastBetaLicenseAgreedTo string #{license_id}" #{license_plist_path}`
|
|
670
|
+
`sudo /usr/libexec/PlistBuddy -c "add :IDEXcodeVersionForAgreedToBetaLicense string #{version}" #{license_plist_path}`
|
|
671
|
+
end
|
|
615
672
|
else
|
|
616
673
|
`sudo #{@path}/Contents/Developer/usr/bin/xcodebuild -license accept`
|
|
617
674
|
end
|
|
@@ -628,7 +685,7 @@ HELP
|
|
|
628
685
|
def install_components
|
|
629
686
|
# starting with Xcode 9, we have `xcodebuild -runFirstLaunch` available to do package
|
|
630
687
|
# postinstalls using a documented option
|
|
631
|
-
if Gem::Version.new(
|
|
688
|
+
if Gem::Version.new(version) >= Gem::Version.new('9')
|
|
632
689
|
`sudo #{@path}/Contents/Developer/usr/bin/xcodebuild -runFirstLaunch`
|
|
633
690
|
else
|
|
634
691
|
Dir.glob("#{@path}/Contents/Resources/Packages/*.pkg").each do |pkg|
|
|
@@ -648,11 +705,36 @@ HELP
|
|
|
648
705
|
output.split("\n").first.split(' ')[1]
|
|
649
706
|
end
|
|
650
707
|
|
|
708
|
+
def verify_integrity
|
|
709
|
+
verify_app_security_assessment && verify_app_cert
|
|
710
|
+
end
|
|
711
|
+
|
|
651
712
|
:private
|
|
652
713
|
|
|
714
|
+
def bundle_version_string
|
|
715
|
+
digits = plist_entry(':DTXcode').to_i.to_s
|
|
716
|
+
if digits.length < 3
|
|
717
|
+
digits.split(//).join('.')
|
|
718
|
+
else
|
|
719
|
+
"#{digits[0..-3]}.#{digits[-2]}.#{digits[-1]}"
|
|
720
|
+
end
|
|
721
|
+
end
|
|
722
|
+
|
|
653
723
|
def plist_entry(keypath)
|
|
654
724
|
`/usr/libexec/PlistBuddy -c "Print :#{keypath}" "#{path}/Contents/Info.plist"`.chomp
|
|
655
725
|
end
|
|
726
|
+
|
|
727
|
+
def verify_app_security_assessment
|
|
728
|
+
puts `/usr/bin/codesign --verify --verbose #{@path}`
|
|
729
|
+
$?.exitstatus.zero?
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def verify_app_cert
|
|
733
|
+
Fastlane::Actions::VerifyXcodeAction.run(xcode_path: @path.to_s)
|
|
734
|
+
true
|
|
735
|
+
rescue
|
|
736
|
+
false
|
|
737
|
+
end
|
|
656
738
|
end
|
|
657
739
|
|
|
658
740
|
# A version of Xcode we fetched from the Apple Developer Portal
|
|
@@ -660,7 +742,7 @@ HELP
|
|
|
660
742
|
#
|
|
661
743
|
# Sample object:
|
|
662
744
|
# <XcodeInstall::Xcode:0x007fa1d451c390
|
|
663
|
-
# @date_modified=
|
|
745
|
+
# @date_modified=1573661580,
|
|
664
746
|
# @name="6.4",
|
|
665
747
|
# @path="/Developer_Tools/Xcode_6.4/Xcode_6.4.dmg",
|
|
666
748
|
# @url=
|
|
@@ -683,7 +765,7 @@ HELP
|
|
|
683
765
|
|
|
684
766
|
def initialize(json, url = nil, release_notes_url = nil)
|
|
685
767
|
if url.nil?
|
|
686
|
-
@date_modified = json['dateModified'].to_i
|
|
768
|
+
@date_modified = DateTime.strptime(json['dateModified'], '%m/%d/%y %H:%M').strftime('%s').to_i
|
|
687
769
|
@name = json['name'].gsub(/^Xcode /, '')
|
|
688
770
|
@path = json['files'].first['remotePath']
|
|
689
771
|
url_prefix = 'https://developer.apple.com/devcenter/download.action?path='
|
|
@@ -715,6 +797,7 @@ HELP
|
|
|
715
797
|
|
|
716
798
|
def self.new_prerelease(version, url, release_notes_path)
|
|
717
799
|
new('name' => version,
|
|
800
|
+
'dateModified' => '01/01/70 00:00',
|
|
718
801
|
'files' => [{ 'remotePath' => url.split('=').last }],
|
|
719
802
|
'release_notes_path' => release_notes_path)
|
|
720
803
|
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
|
}
|