xcode-install 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7ba5033bc9c7837468a6579fbcf957d5e5e9f46
4
- data.tar.gz: 09b92821948c600fc8bf6f5bb317f709bd50890e
3
+ metadata.gz: 6400b83c001ff5429ba066cb709c7c48a3ee52d3
4
+ data.tar.gz: d03b8a2ca220319f47e47883cff2b240bcdd6697
5
5
  SHA512:
6
- metadata.gz: 19bf9ad9bd1f501769d2953a02c37d57e4c019e5fea462758d3a5751a648168549dfcd94832536cf66cac91828779e761c71238f5875728f1254b3853ec0dcfd
7
- data.tar.gz: 170995f06db15fc32642dee98b68a4a461bd34a594721b2b15124a014ab2e78bf22f27849fe92b60866970e87d51d1904929038a52c7c0f7b5b00caeaf91f358
6
+ metadata.gz: 7f670c8560447440ae2b048c481a91addf64752bbc083c0f849a92bc46a403eb09f7d58c05eaaa2714a9d7b005287821d01340bf78a4cc91f89be8e0875687b1
7
+ data.tar.gz: 1c116c302f03f011a924f6bd764967703fcc00af5578554318be11bc96045e28ec210a6e310e8059d04c20473d26af21e763e3b1e57a28986077a92f76f14549
data/README.md CHANGED
@@ -69,6 +69,35 @@ they have to be installed using the full name, e.g. `xcversion install '7 GM see
69
69
 
70
70
  XcodeInstall can also install Xcode's Command Line Tools by calling `xcversion install-cli-tools`.
71
71
 
72
+ ### Simulators
73
+
74
+ XcodeInstall can also manage your local simulators using the `simulators` command.
75
+
76
+ ```bash
77
+ $ xcode-install simulators
78
+ Xcode 6.4.0 (/Applications/Xcode.app)
79
+ iOS 7.1 Simulator (installed)
80
+ iOS 8.1 Simulator (not installed)
81
+ iOS 8.2 Simulator (not installed)
82
+ iOS 8.3 Simulator (installed)
83
+ Xcode 7.0.0 (/Applications/Xcode-beta.app)
84
+ iOS 8.1 Simulator (not installed)
85
+ iOS 8.2 Simulator (not installed)
86
+ iOS 8.3 Simulator (installed)
87
+ iOS 8.4 Simulator (installed)
88
+ ```
89
+
90
+ To install a simulator, simply:
91
+
92
+ ```bash
93
+ $ xcode-install simulators --install=8.4
94
+ ########################################################### 82.1%
95
+ ######################################################################## 100.0%
96
+ Please authenticate to install iOS 8.4 Simulator...
97
+
98
+ Successfully installed iOS 8.4 Simulator
99
+ ```
100
+
72
101
  ## Limitations
73
102
 
74
103
  Unfortunately, the installation size of Xcodes downloaded will be bigger than when downloading via the Mac App Store, see [#10](/../../issues/10) and feel free to dupe the radar. 📡
@@ -22,6 +22,7 @@ module XcodeInstall
22
22
  require 'xcode/install/selected'
23
23
  require 'xcode/install/uninstall'
24
24
  require 'xcode/install/update'
25
+ require 'xcode/install/simulators'
25
26
 
26
27
  self.abstract_command = true
27
28
  self.command = 'xcversion'
@@ -0,0 +1,58 @@
1
+ require 'claide'
2
+
3
+ module XcodeInstall
4
+ class Command
5
+ class Simulators < Command
6
+ self.command = 'simulators'
7
+ self.summary = 'List or install iOS simulators.'
8
+
9
+ def self.options
10
+ [['--install=version', 'Install simulator with the given version.']].concat(super)
11
+ end
12
+
13
+ def initialize(argv)
14
+ @installed_xcodes = Installer.new.installed_versions
15
+ @install = argv.option('install')
16
+ super
17
+ end
18
+
19
+ def run
20
+ @install ? install : list
21
+ end
22
+ end
23
+
24
+ :private
25
+
26
+ def install
27
+ filtered_simulators = @installed_xcodes.map { |x| x.available_simulators }.flatten.select do |sim|
28
+ sim.version.to_s.start_with?(@install)
29
+ end
30
+ if filtered_simulators.count == 0
31
+ puts "[!] No simulator matching #{@install} was found. Please specify a version from the following available simulators:".ansi.red
32
+ list
33
+ exit 1
34
+ elsif filtered_simulators.count == 1
35
+ simulator = filtered_simulators.first
36
+ fail Informative, "#{simulator.name} is already installed." if simulator.installed?
37
+ puts "Installing #{simulator.name} for Xcode #{simulator.xcode.bundle_version}..."
38
+ simulator.install
39
+ else
40
+ puts "[!] More than one simulator matching #{@install} was found. Please specify the full version.".ansi.red
41
+ filtered_simulators.each do |simulator|
42
+ puts "Xcode #{simulator.xcode.bundle_version} (#{simulator.xcode.path})".ansi.green
43
+ puts "xcode-install simulator --install=#{simulator.version}"
44
+ end
45
+ exit 1
46
+ end
47
+ end
48
+
49
+ def list
50
+ @installed_xcodes.each do |xcode|
51
+ puts "Xcode #{xcode.version} (#{xcode.path})".ansi.green
52
+ xcode.available_simulators.each do |simulator|
53
+ puts simulator.to_s
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,3 +1,3 @@
1
1
  module XcodeInstall
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/xcode/install.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  require 'fileutils'
2
2
  require 'pathname'
3
3
  require 'spaceship'
4
+ require 'json'
4
5
  require 'rubygems/version'
5
6
  require 'xcode/install/command'
6
7
  require 'xcode/install/version'
7
8
 
8
9
  module XcodeInstall
10
+ CACHE_DIR = Pathname.new("#{ENV['HOME']}/Library/Caches/XcodeInstall")
9
11
  class Curl
10
12
  COOKIES_PATH = Pathname.new('/tmp/curl-cookies.txt')
11
13
 
@@ -171,7 +173,6 @@ HELP
171
173
  end
172
174
  end
173
175
 
174
- CACHE_DIR = Pathname.new("#{ENV['HOME']}/Library/Caches/XcodeInstall")
175
176
  LIST_FILE = CACHE_DIR + Pathname.new('xcodes.bin')
176
177
  MINIMUM_VERSION = Gem::Version.new('4.3')
177
178
  SYMLINK_PATH = Pathname.new('/Applications/Xcode.app')
@@ -267,13 +268,133 @@ HELP
267
268
  end
268
269
  end
269
270
 
271
+ class Simulator
272
+ attr_reader :version
273
+ attr_reader :name
274
+ attr_reader :identifier
275
+ attr_reader :source
276
+ attr_reader :xcode
277
+
278
+ def initialize(downloadable)
279
+ @version = Gem::Version.new(downloadable['version'])
280
+ @install_prefix = apply_variables(downloadable['userInfo']['InstallPrefix'])
281
+ @name = apply_variables(downloadable['name'])
282
+ @identifier = apply_variables(downloadable['identifier'])
283
+ @source = apply_variables(downloadable['source'])
284
+ end
285
+
286
+ def installed?
287
+ # FIXME: use downloadables' `InstalledIfAllReceiptsArePresentOrNewer` key
288
+ File.directory?(@install_prefix)
289
+ end
290
+
291
+ def installed_string
292
+ installed? ? 'installed' : 'not installed'
293
+ end
294
+
295
+ def to_s
296
+ "#{name} (#{installed_string})"
297
+ end
298
+
299
+ def xcode
300
+ Installer.new.installed_versions.find do |x|
301
+ x.available_simulators.find do |s|
302
+ s.version == version
303
+ end
304
+ end
305
+ end
306
+
307
+ def download
308
+ result = Curl.new.fetch(source, CACHE_DIR)
309
+ result ? dmg_path : nil
310
+ end
311
+
312
+ def install
313
+ download unless dmg_path.exist?
314
+ prepare_package unless pkg_path.exist?
315
+ puts "Please authenticate to install #{name}..."
316
+ `sudo installer -pkg #{pkg_path} -target /`
317
+ fail Informative, "Could not install #{name}, please try again" unless installed?
318
+ source_receipts_dir = '/private/var/db/receipts'
319
+ target_receipts_dir = "#{@install_prefix}/System/Library/Receipts"
320
+ FileUtils.mkdir_p(target_receipts_dir)
321
+ FileUtils.cp("#{source_receipts_dir}/#{@identifier}.bom", target_receipts_dir)
322
+ FileUtils.cp("#{source_receipts_dir}/#{@identifier}.plist", target_receipts_dir)
323
+ puts "Successfully installed #{name}"
324
+ end
325
+
326
+ :private
327
+
328
+ def prepare_package
329
+ puts 'Mounting DMG'
330
+ mount_location = `hdiutil mount -nobrowse -noverify #{dmg_path}`.scan(/\/Volumes.*\n/).first.chomp
331
+ puts 'Expanding pkg'
332
+ expanded_pkg_path = CACHE_DIR + identifier
333
+ FileUtils.rm_rf(expanded_pkg_path)
334
+ `pkgutil --expand #{mount_location}/*.pkg #{expanded_pkg_path}`
335
+ puts "Expanded pkg into #{expanded_pkg_path}"
336
+ puts 'Unmounting DMG'
337
+ `umount #{mount_location}`
338
+ puts 'Setting package installation location'
339
+ package_info_path = expanded_pkg_path + 'PackageInfo'
340
+ package_info_contents = File.read(package_info_path)
341
+ File.open(package_info_path, 'w') do |f|
342
+ f << package_info_contents.sub('pkg-info', %(pkg-info install-location="#{@install_prefix}"))
343
+ end
344
+ puts 'Rebuilding package'
345
+ `pkgutil --flatten #{expanded_pkg_path} #{pkg_path}`
346
+ FileUtils.rm_rf(expanded_pkg_path)
347
+ end
348
+
349
+ def dmg_path
350
+ CACHE_DIR + Pathname.new(source).basename
351
+ end
352
+
353
+ def pkg_path
354
+ CACHE_DIR + "#{identifier}.pkg"
355
+ end
356
+
357
+ def apply_variables(template)
358
+ variable_map = {
359
+ '$(DOWNLOADABLE_VERSION_MAJOR)' => version.to_s.split('.')[0],
360
+ '$(DOWNLOADABLE_VERSION_MINOR)' => version.to_s.split('.')[1],
361
+ '$(DOWNLOADABLE_IDENTIFIER)' => identifier,
362
+ '$(DOWNLOADABLE_VERSION)' => version.to_s
363
+ }.freeze
364
+ variable_map.each do |key, value|
365
+ next unless template.include?(key)
366
+ template.sub!(key, value)
367
+ end
368
+ template
369
+ end
370
+ end
371
+
270
372
  class InstalledXcode
271
373
  attr_reader :path
272
374
  attr_reader :version
375
+ attr_reader :bundle_version
376
+ attr_reader :uuid
377
+ attr_reader :downloadable_index_url
378
+ attr_reader :available_simulators
273
379
 
274
380
  def initialize(path)
275
381
  @path = Pathname.new(path)
276
- @version = get_version
382
+ end
383
+
384
+ def version
385
+ @version ||= get_version
386
+ end
387
+
388
+ def bundle_version
389
+ @bundle_version ||= Gem::Version.new(plist_entry(':DTXcode').to_i.to_s.split(//).join('.'))
390
+ end
391
+
392
+ def uuid
393
+ @uuid ||= plist_entry(':DVTPlugInCompatibilityUUID')
394
+ end
395
+
396
+ def downloadable_index_url
397
+ @downloadable_index_url ||= "https://devimages.apple.com.edgekey.net/downloads/xcode/simulators/index-#{bundle_version}-#{uuid}.dvtdownloadableindex"
277
398
  end
278
399
 
279
400
  def approve_license
@@ -285,6 +406,12 @@ HELP
285
406
  `sudo /usr/libexec/PlistBuddy -c "add :IDEXcodeVersionForAgreedToGMLicense string #{@version}" #{license_plist_path}`
286
407
  end
287
408
 
409
+ def available_simulators
410
+ @available_simulators ||= JSON.parse(`curl -Ls #{downloadable_index_url} | plutil -convert json -o - -`)['downloadables'].map do |downloadable|
411
+ Simulator.new(downloadable)
412
+ end
413
+ end
414
+
288
415
  def install_components
289
416
  `sudo installer -pkg #{@path}/Contents/Resources/Packages/MobileDevice.pkg -target /`
290
417
  osx_build_version = `sw_vers -buildVersion`.chomp
@@ -295,6 +422,10 @@ HELP
295
422
 
296
423
  :private
297
424
 
425
+ def plist_entry(keypath)
426
+ `/usr/libexec/PlistBuddy -c "Print :#{keypath}" "#{path}/Contents/Info.plist"`.chomp
427
+ end
428
+
298
429
  def get_version
299
430
  output = `DEVELOPER_DIR='' "#{@path}/Contents/Developer/usr/bin/xcodebuild" -version`
300
431
  return '0.0' if output.nil? # ¯\_(ツ)_/¯
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcode-install
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boris Bügling
@@ -102,6 +102,7 @@ files:
102
102
  - lib/xcode/install/list.rb
103
103
  - lib/xcode/install/select.rb
104
104
  - lib/xcode/install/selected.rb
105
+ - lib/xcode/install/simulators.rb
105
106
  - lib/xcode/install/uninstall.rb
106
107
  - lib/xcode/install/update.rb
107
108
  - lib/xcode/install/version.rb