xcode-install 1.0.1 → 1.1.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 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