lib/xcode/install.rb in xcode-install-2.1.1 vs lib/xcode/install.rb in xcode-install-2.2.0

- old
+ new

@@ -18,20 +18,29 @@ uri = URI.parse(url) output ||= File.basename(uri.path) output = (Pathname.new(directory) + Pathname.new(output)) if directory + retry_options = ['--retry', '3'] progress = progress ? '--progress-bar' : '--silent' - command = ['curl', *options, '--location', '--continue-at', '-', progress, '--output', output, url].map(&:to_s) - io = IO.popen(command) - io.each { |line| puts line } - io.close + command = ['curl', *options, *retry_options, '--location', '--continue-at', '-', progress, '--output', output, url].map(&:to_s) - result = $?.exitstatus == 0 + # Run the curl command in a loop, retry when curl exit status is 18 + # "Partial file. Only a part of the file was transferred." + # https://curl.haxx.se/mail/archive-2008-07/0098.html + # https://github.com/KrauseFx/xcode-install/issues/210 + 3.times do + io = IO.popen(command) + io.each { |line| puts line } + io.close + exit_code = $?.exitstatus + return exit_code.zero? unless exit_code == 18 + end + false + ensure FileUtils.rm_f(COOKIES_PATH) - result end end class Installer attr_reader :xcodes @@ -111,11 +120,11 @@ `sudo -p "#{prompt}" ditto "#{source}" "#{xcode_path}"` `umount "/Volumes/Xcode"` end unless verify_integrity(xcode_path) - `sudo rm -f #{xcode_path}` + `sudo rm -rf #{xcode_path}` return end enable_developer_mode xcode = InstalledXcode.new(xcode_path) @@ -249,11 +258,11 @@ search: 'false').body) names = @xcodes.map(&:name) @xcodes += prereleases.reject { |pre| names.include?(pre.name) } - File.open(LIST_FILE, 'w') do |f| + File.open(LIST_FILE, 'wb') do |f| f << Marshal.dump(xcodes) end xcodes end @@ -296,15 +305,15 @@ link + [nil] end end links = links.map { |pre| Xcode.new_prerelease(pre[2].strip.gsub(/.*Xcode /, ''), pre[0], pre[3]) } - if links.count == 0 + if links.count.zero? rg = %r{platform-title.*Xcode.* beta.*<\/p>} scan = body.scan(rg) - if scan.count == 0 + if scan.count.zero? rg = %r{Xcode.* GM.*<\/p>} scan = body.scan(rg) end return [] if scan.empty? @@ -323,18 +332,18 @@ xcodes || fetch_seedlist end def verify_integrity(path) puts `/usr/sbin/spctl --assess --verbose=4 --type execute #{path}` - $?.exitstatus == 0 + $?.exitstatus.zero? end def hdiutil(*args) io = IO.popen(['hdiutil', *args]) result = io.read io.close - unless $?.exitstatus == 0 + unless $?.exitstatus.zero? file_path = args[-1] if `file -b #{file_path}`.start_with?('HTML') fail Informative, "Failed to mount #{file_path}, logging into your account from a browser should tell you what is going wrong." end fail Informative, 'Failed to invoke hdiutil.' @@ -377,17 +386,17 @@ s.version == version end end end - def download - result = Curl.new.fetch(source, CACHE_DIR) + def download(progress) + result = Curl.new.fetch(source, CACHE_DIR, nil, nil, progress) result ? dmg_path : nil end - def install - download unless dmg_path.exist? + def install(progress) + download(progress) prepare_package unless pkg_path.exist? puts "Please authenticate to install #{name}..." `sudo installer -pkg #{pkg_path} -target /` fail Informative, "Could not install #{name}, please try again" unless installed? source_receipts_dir = '/private/var/db/receipts' @@ -489,15 +498,23 @@ def available_simulators @available_simulators ||= JSON.parse(`curl -Ls #{downloadable_index_url} | plutil -convert json -o - -`)['downloadables'].map do |downloadable| Simulator.new(downloadable) end + rescue JSON::ParserError + return [] end def install_components - Dir.glob("#{@path}/Contents/Resources/Packages/*.pkg").each do |pkg| - `sudo installer -pkg #{pkg} -target /` + # starting with Xcode 9, we have `xcodebuild -runFirstLaunch` available to do package + # postinstalls using a documented option + if Gem::Version.new(@version) >= Gem::Version.new('9') + `sudo #{@path}/Contents/Developer/usr/bin/xcodebuild -runFirstLaunch` + else + Dir.glob("#{@path}/Contents/Resources/Packages/*.pkg").each do |pkg| + `sudo installer -pkg #{pkg} -target /` + end end osx_build_version = `sw_vers -buildVersion`.chomp tools_version = `/usr/libexec/PlistBuddy -c "Print :ProductBuildVersion" "#{@path}/Contents/version.plist"`.chomp cache_dir = `getconf DARWIN_USER_CACHE_DIR`.chomp `touch #{cache_dir}com.apple.dt.Xcode.InstallCheckCache_#{osx_build_version}_#{tools_version}` @@ -509,10 +526,10 @@ `/usr/libexec/PlistBuddy -c "Print :#{keypath}" "#{path}/Contents/Info.plist"`.chomp end def fetch_version output = `DEVELOPER_DIR='' "#{@path}/Contents/Developer/usr/bin/xcodebuild" -version` - return '0.0' if output.nil? # ¯\_(ツ)_/¯ + return '0.0' if output.nil? || output.empty? # ¯\_(ツ)_/¯ output.split("\n").first.split(' ')[1] end end class Xcode