lib/xcode/install.rb in xcode-install-0.9.6 vs lib/xcode/install.rb in xcode-install-1.0.0

- old
+ new

@@ -42,16 +42,16 @@ def current_symlink File.symlink?(SYMLINK_PATH) ? SYMLINK_PATH : nil end - def download(version, progress) - return unless exist?(version) + def download(version, progress, url = nil) + return unless exist?(version) || url xcode = seedlist.find { |x| x.name == version } - dmg_file = Pathname.new(File.basename(xcode.path)) + dmg_file = Pathname.new(File.basename(url || xcode.path)) - result = Curl.new.fetch(xcode.url, CACHE_DIR, spaceship.cookie, dmg_file, progress) + result = Curl.new.fetch(url || xcode.url, CACHE_DIR, spaceship.cookie, dmg_file, progress) result ? CACHE_DIR + dmg_file : nil end def exist?(version) list_versions.include?(version) @@ -73,15 +73,16 @@ `hdiutil mount -nobrowse -noverify #{dmgPath}` puts 'Please authenticate for Xcode installation...' source = Dir.glob('/Volumes/Xcode/Xcode*.app').first if source.nil? - $stderr.puts <<-HELP + out <<-HELP No `Xcode.app` found in DMG. Please remove #{dmgPath} if you suspect a corrupted -download or run `xcode-install update` to see if the version you tried to install +download or run `xcversion update` to see if the version you tried to install has been pulled by Apple. If none of this is true, please open a new GH issue. HELP + $stderr.puts out.gsub("\n", ' ') return end `sudo ditto "#{source}" "#{xcode_path}"` `umount "/Volumes/Xcode"` @@ -90,11 +91,11 @@ `sudo rm -f #{xcode_path}` return end enable_developer_mode - `sudo xcodebuild -license accept` unless xcode_license_approved? + InstalledXcode.new(xcode_path).approve_license if switch `sudo rm -f #{SYMLINK_PATH}` unless current_symlink.nil? `sudo ln -sf #{xcode_path} #{SYMLINK_PATH}` unless SYMLINK_PATH.exist? @@ -103,18 +104,25 @@ end FileUtils.rm_f(dmgPath) if clean end - def install_version(version, switch = true, clean = true, install = true, progress = true) - return if version.nil? - dmg_path = get_dmg(version, progress) + def install_version(version, switch = true, clean = true, install = true, progress = true, url = nil) + dmg_path = get_dmg(version, progress, url) fail Informative, "Failed to download Xcode #{version}." if dmg_path.nil? install_dmg(dmg_path, "-#{version.split(' ')[0]}", switch, clean) if install + + open_release_notes_url(version) end + def open_release_notes_url(version) + return if version.nil? + xcode = seedlist.find { |x| x.name == version } + `open #{xcode.release_notes_url}` unless xcode.nil? || xcode.release_notes_url.nil? + end + def list_current stable_majors = list_versions.reject { |v| /beta/i =~ v }.map { |v| v.split('.')[0] }.map { |v| v.split(' ')[0] } latest_stable_major = stable_majors.select { |v| v.length == 1 }.uniq.sort.last.to_i list_versions.select { |v| v.split('.')[0].to_i >= latest_stable_major }.sort.join("\n") end @@ -169,17 +177,21 @@ def enable_developer_mode `sudo /usr/sbin/DevToolsSecurity -enable` `sudo /usr/sbin/dseditgroup -o edit -t group -a staff _developer` end - def get_dmg(version, progress = true) + def get_dmg(version, progress = true, url = nil) + if url + path = Pathname.new(url) + return path if path.exist? + end if ENV.key?('XCODE_INSTALL_CACHE_DIR') cache_path = Pathname.new(ENV['XCODE_INSTALL_CACHE_DIR']) + Pathname.new("xcode-#{version}.dmg") return cache_path if cache_path.exist? end - download(version, progress) + download(version, progress, url) end def fetch_seedlist @xcodes = parse_seedlist(spaceship.send(:request, :get, '/services-account/QH65B2/downloadws/listDownloads.action', { start: "0", @@ -209,11 +221,11 @@ `mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'" 2>/dev/null`.split("\n") end def parse_seedlist(seedlist) - seeds = seedlist['downloads'].select do |t| + seeds = Array(seedlist['downloads']).select do |t| /^Xcode [0-9]/.match(t['name']) end xcodes = seeds.map { |x| Xcode.new(x) }.reject { |x| x.version < MINIMUM_VERSION }.sort do |a, b| a.date_modified <=> b.date_modified @@ -228,12 +240,20 @@ end def prereleases body=spaceship.send(:request, :get, '/xcode/download/').body links=body.scan(/<a.+?href="(.+?.dmg)".*>(.*)<\/a>/) - - links.map { |pre| Xcode.new_prelease(pre[1].strip.gsub(/.*Xcode /, ''), pre[0]) } + links = links.map do |link| + parent = link[0].scan(/path=(\/.*\/.*\/)/).first.first + match = body.scan(/#{Regexp.quote(parent)}(.+?.pdf)/).first + if match + link += [parent + match.first] + else + link += [nil] + end + end + links.map { |pre| Xcode.new_prerelease(pre[1].strip.gsub(/.*Xcode /, ''), pre[0], pre[2]) } end def seedlist @xcodes = Marshal.load(File.read(LIST_FILE)) if LIST_FILE.exist? && xcodes.nil? xcodes || fetch_seedlist @@ -241,14 +261,10 @@ def verify_integrity(path) puts `/usr/sbin/spctl --assess --verbose=4 --type execute #{path}` $?.exitstatus == 0 end - - def xcode_license_approved? - !(`/usr/bin/xcrun clang 2>&1` =~ /license/ && !$CHILD_STATUS.success?) - end end class InstalledXcode attr_reader :path attr_reader :version @@ -256,10 +272,19 @@ def initialize(path) @path = Pathname.new(path) @version = get_version(path) end + def approve_license + license_path = "#{@path}/Contents/Resources/English.lproj/License.rtf" + license_id = IO.read(license_path).match(/^EA\d{4}/) + license_plist_path = '/Library/Preferences/com.apple.dt.Xcode.plist' + `sudo rm -rf #{license_plist_path}` + `sudo /usr/libexec/PlistBuddy -c "add :IDELastGMLicenseAgreedTo string #{license_id}" #{license_plist_path}` + `sudo /usr/libexec/PlistBuddy -c "add :IDEXcodeVersionForAgreedToGMLicense string #{@version}" #{license_plist_path}` + end + :private def get_version(xcode_path) output = `DEVELOPER_DIR='' "#{xcode_path}/Contents/Developer/usr/bin/xcodebuild" -version` return '0.0' if output.nil? # ¯\_(ツ)_/¯ @@ -271,16 +296,19 @@ attr_reader :date_modified attr_reader :name attr_reader :path attr_reader :url attr_reader :version + attr_reader :release_notes_url def initialize(json) @date_modified = json['dateModified'].to_i @name = json['name'].gsub(/^Xcode /, '') @path = json['files'].first['remotePath'] - @url = "https://developer.apple.com/devcenter/download.action?path=#{@path}" + url_prefix = 'https://developer.apple.com/devcenter/download.action?path=' + @url = "#{url_prefix}#{@path}" + @release_notes_url = "#{url_prefix}#{json['release_notes_path']}" if json['release_notes_path'] begin @version = Gem::Version.new(@name.split(' ')[0]) rescue @version = Installer::MINIMUM_VERSION @@ -294,12 +322,13 @@ def ==(other) date_modified == other.date_modified && name == other.name && path == other.path && \ url == other.url && version == other.version end - def self.new_prelease(version, url) + def self.new_prerelease(version, url, release_notes_path) new('name' => version, 'dateModified' => Time.now.to_i, - 'files' => [{ 'remotePath' => url.split('=').last }]) + 'files' => [{ 'remotePath' => url.split('=').last }], + 'release_notes_path' => release_notes_path) end end end