lib/ruboto/util/setup.rb in ruboto-0.15.0 vs lib/ruboto/util/setup.rb in ruboto-0.16.0

- old
+ new

@@ -6,10 +6,13 @@ module Setup include Ruboto::Util::Verify REPOSITORY_BASE = 'http://dl-ssl.google.com/android/repository' REPOSITORY_URL = "#{REPOSITORY_BASE}/repository-8.xml" + RUBOTO_GEM_ROOT = File.expand_path '../../../..', __FILE__ + WINDOWS_ELEVATE_CMD = "#{RUBOTO_GEM_ROOT}/bin/elevate_32.exe -c -w" + ######################################### # # Core Set up Method # @@ -27,11 +30,14 @@ def which(cmd) exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| exts.each do |ext| exe = File.join(path, "#{cmd}#{ext}") - return exe if File.executable? exe + if File.executable? exe + exe.gsub!('\\', '/') if windows? + return exe + end end end nil end @@ -40,41 +46,50 @@ ######################################### # # Utility Methods # + MAC_OS_X = 'macosx' + WINDOWS = 'windows' + LINUX = 'linux' + def android_package_os_id case RbConfig::CONFIG['host_os'] - when /^darwin(.*)/ then - 'macosx' - when /linux/ then - 'linux' - when /^mswin32|windows(.*)/ then - 'windows' + when /^darwin(.*)/ + MAC_OS_X + when /linux/ + LINUX + when /^mswin32|windows|mingw32/ + WINDOWS else ## Error nil end end + def mac_os_x? + android_package_os_id == MAC_OS_X + end + + def windows? + android_package_os_id == WINDOWS + end + def android_package_directory - if RbConfig::CONFIG['host_os'] =~ /^mswin32|windows(.*)/ - 'AppData/Local/Android/android-sdk' - else - ENV['ANDROID_HOME'] ? ENV['ANDROID_HOME'] : File.join(File.expand_path('~'), "android-sdk-#{android_package_os_id}") - end + return ENV['ANDROID_HOME'] if ENV['ANDROID_HOME'] + File.join File.expand_path('~'), windows? ? 'AppData/Local/Android/android-sdk' : "android-sdk-#{android_package_os_id}" end def path_setup_file - case RbConfig::CONFIG['host_os'] - when /^darwin(.*)/ then + case android_package_os_id + when MAC_OS_X '.profile' - when /linux/ then + when LINUX '.bashrc' - when /^mswin32|windows(.*)/ then - 'windows' + when WINDOWS ## Error + 'windows' else ## Error nil end end @@ -82,74 +97,112 @@ def get_tools_version(type='tool') require 'rexml/document' require 'open-uri' doc = REXML::Document.new(open(REPOSITORY_URL)) - doc.root.elements.to_a("sdk:#{type}/sdk:revision").map do |t| + version = doc.root.elements.to_a("sdk:#{type}/sdk:revision").map do |t| major = t.elements['sdk:major'] minor = t.elements['sdk:minor'] micro = t.elements['sdk:micro'] version = major.text version += ".#{minor.text}" if minor version += ".#{micro.text}" if micro version - end.sort_by{|v| Gem::Version.new(v)}.last + end.sort_by { |v| Gem::Version.new(v) }.last + + # FIXME(uwe): Temporary fix for bug in build-tools 19.0.0 + return '18.1.1' if type == 'build-tool' && version == '19.0.0' + # EMXIF + + version end ######################################### # # Check Methods # def check_all(api_levels) - @existing_paths = [] - @missing_paths = [] + @existing_paths ||= [] + @missing_paths ||= [] - @java_loc = check_for('java', 'Java runtime') - @javac_loc = check_for('javac', 'Java Compiler') + @java_loc = check_for('java', 'Java runtime', ENV['JAVA_HOME'] && "#{ENV['JAVA_HOME']}/bin/java") + @javac_loc = check_for('javac', 'Java Compiler', ENV['JAVA_HOME'] && "#{ENV['JAVA_HOME']}/bin/javac") @ant_loc = check_for('ant', 'Apache ANT') check_for_android_sdk check_for_emulator + check_for_haxm check_for_platform_tools check_for_build_tools api_levels.each { |api_level| check_for_android_platform(api_level) } + @existing_paths.uniq! + @missing_paths.uniq! + puts - ok = @java_loc && @javac_loc && @ant_loc && @android_loc && @emulator_loc && @adb_loc && @dx_loc && @platform_sdk_loc.all? { |_, path| !path.nil? } + ok = @java_loc && @javac_loc && @ant_loc && @android_loc && @emulator_loc && @haxm_kext_loc && @adb_loc && @dx_loc && @platform_sdk_loc.all? { |_, path| !path.nil? } puts " #{ok ? '*** Ruboto setup is OK! ***' : '!!! Ruboto setup is NOT OK !!!'}\n\n" ok end def check_for_emulator @emulator_loc = check_for('emulator', 'Android Emulator', File.join(android_package_directory, 'tools', 'emulator')) end + def check_for_haxm + case android_package_os_id + when MAC_OS_X + @haxm_kext_loc = '/System/Library/Extensions/intelhaxm.kext' + found = File.exists?(@haxm_kext_loc) + @haxm_kext_loc = nil unless found + puts "#{'%-25s' % 'Intel HAXM'}: #{(found ? 'Found' : 'Not found')}" + @haxm_installer_loc = File.join(android_package_directory, 'extras', 'intel', 'Hardware_Accelerated_Execution_Manager', 'IntelHAXM.dmg') + @haxm_installer_loc = nil unless File.exists?(@haxm_installer_loc) + when LINUX + @haxm_installer_loc = 'Not supported, yet.' + @haxm_kext_loc = 'Not supported, yet.' + return + when WINDOWS + @haxm_kext_loc = `sc query intelhaxm` + found = ($? == 0) + @haxm_kext_loc = nil unless found + puts "#{'%-25s' % 'Intel HAXM'}: #{(found ? 'Found' : 'Not found')}" + @haxm_installer_loc = File.join(android_package_directory, 'extras', 'intel', 'Hardware_Accelerated_Execution_Manager', 'IntelHaxm.exe') + @haxm_installer_loc = nil unless File.exists?(@haxm_installer_loc) + return + end + end + def check_for_platform_tools @adb_loc = check_for('adb', 'Android SDK Command adb', - File.join(android_package_directory, 'platform-tools', 'adb')) + File.join(android_package_directory, 'platform-tools', windows? ? 'adb.exe' : 'adb')) end def check_for_build_tools @dx_loc = check_for('dx', 'Android SDK Command dx', - Dir[File.join(android_package_directory, 'build-tools', '*', 'dx')][-1]) + Dir[File.join android_package_directory, 'build-tools', '*', windows? ? 'dx.bat' : 'dx'][-1]) end def check_for_android_sdk @android_loc = check_for('android', 'Android Package Installer', - File.join(android_package_directory, 'tools', 'android')) + File.join(android_package_directory, 'tools', windows? ? 'android.bat' : 'android')) end def check_for(cmd, pretty_name=nil, alt_dir=nil) rv = which(cmd) - rv = nil if rv.nil? or rv.empty? + rv = nil if rv && rv.empty? if rv @existing_paths << File.dirname(rv) - elsif alt_dir and File.exists?(alt_dir) + elsif alt_dir && File.exists?(alt_dir) rv = alt_dir - ENV['PATH'] = "#{File.dirname(rv)}:#{ENV['PATH']}" + if windows? + ENV['PATH'] = "#{File.dirname(rv).gsub('/', '\\')};#{ENV['PATH']}" + else + ENV['PATH'] = "#{File.dirname(rv)}:#{ENV['PATH']}" + end @missing_paths << "#{File.dirname(rv)}" end puts "#{'%-25s' % (pretty_name || cmd)}: #{(rv ? 'Found' : 'Not found')}" rv @@ -173,24 +226,28 @@ def install_all(accept_all, api_levels) install_java(accept_all) unless @java_loc && @javac_loc install_ant(accept_all) unless @ant_loc install_android_sdk(accept_all) unless @android_loc - check_all(api_levels) - install_android_tools(accept_all) unless @dx_loc && @adb_loc && @emulator_loc # build-tools, platform-tools and tools + + # build-tools, platform-tools, tools, and haxm + install_android_tools(accept_all) unless @dx_loc && @adb_loc && @emulator_loc && @haxm_installer_loc + install_haxm(accept_all) unless @haxm_kext_loc + if @android_loc api_levels.each do |api_level| install_platform(accept_all, api_level) unless @platform_sdk_loc[api_level] end end + check_all(api_levels) end def install_java(accept_all) - case RbConfig::CONFIG['host_os'] - when /^darwin(.*)/ - when /linux/ - when /^mswin32|windows(.*)/ + case android_package_os_id + when MAC_OS_X + when LINUX + when WINDOWS # FIXME(uwe): Detect and warn if we are not "elevated" with adminstrator rights. #set IS_ELEVATED=0 #whoami /groups | findstr /b /c:"Mandatory Label\High Mandatory Level" | findstr /c:"Enabled group" > nul: && set IS_ELEVATED=1 #if %IS_ELEVATED%==0 ( # echo You must run the command prompt as administrator to install. @@ -215,11 +272,11 @@ end resp = process_response(resp) open(java_installer_file_name, 'wb') { |file| file.write(resp.body) } puts "Installing #{java_installer_file_name}..." system java_installer_file_name - raise "Unexpected exit code while installing Java: #{$?}" unless $? == 0 + raise "Unexpected exit code while installing Java: #{$?.exitstatus}" unless $? == 0 FileUtils.rm_f java_installer_file_name else puts puts 'You can download and install the Java JDK manually from' puts 'http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html' @@ -233,19 +290,19 @@ system %Q{setx JAVA_HOME "#{ENV['JAVA_HOME']}"} @missing_paths << "#{File.dirname(@javac_loc)}" end end else - raise "Unknown host os: #{RbConfig::CONFIG['host_os']}" + raise "Unknown host os: #{android_package_os_id}" end end def install_ant(accept_all) - case RbConfig::CONFIG['host_os'] - when /^darwin(.*)/ - when /linux/ - when /^mswin32|windows(.*)/ + case android_package_os_id + when MAC_OS_X + when LINUX + when WINDOWS # FIXME(uwe): Detect and warn if we are not "elevated" with adminstrator rights. #set IS_ELEVATED=0 #whoami /groups | findstr /b /c:"Mandatory Label\High Mandatory Level" | findstr /c:"Enabled group" > nul: && set IS_ELEVATED=1 #if %IS_ELEVATED%==0 ( # echo You must run the command prompt as administrator to install. @@ -353,40 +410,35 @@ print 'Would you like to download and install it? (Y/n): ' a = STDIN.gets.chomp.upcase end if accept_all || a == 'Y' || a.empty? Dir.chdir File.expand_path('~/') do - case RbConfig::CONFIG['host_os'] - when /^darwin(.*)/ + case android_package_os_id + when MAC_OS_X asdk_file_name = "android-sdk_r#{get_tools_version}-#{android_package_os_id}.zip" - system "wget http://dl.google.com/android/#{asdk_file_name}" - system "unzip #{'-o ' if accept_all}#{asdk_file_name}" - system "rm #{asdk_file_name}" - when /linux/ + download(asdk_file_name) + unzip(accept_all, asdk_file_name) + FileUtils.rm_f asdk_file_name + when LINUX asdk_file_name = "android-sdk_r#{get_tools_version}-#{android_package_os_id}.tgz" - system "wget http://dl.google.com/android/#{asdk_file_name}" + download asdk_file_name system "tar -xzf #{asdk_file_name}" - system "rm #{asdk_file_name}" - when /^mswin32|windows(.*)/ + FileUtils.rm_f asdk_file_name + when WINDOWS # FIXME(uwe): Detect and warn if we are not "elevated" with adminstrator rights. #set IS_ELEVATED=0 #whoami /groups | findstr /b /c:"Mandatory Label\High Mandatory Level" | findstr /c:"Enabled group" > nul: && set IS_ELEVATED=1 #if %IS_ELEVATED%==0 ( # echo You must run the command prompt as administrator to install. # exit /b 1 #) asdk_file_name = "installer_r#{get_tools_version}-#{android_package_os_id}.exe" - require 'net/http' - Net::HTTP.start('dl.google.com') do |http| - puts 'Downloading...' - resp = http.get("/android/#{asdk_file_name}") - open(asdk_file_name, 'wb') { |file| file.write(resp.body) } - end + download(asdk_file_name) puts "Installing #{asdk_file_name}..." - system asdk_file_name - raise "Unexpected exit code while installing the Android SDK: #{$?}" unless $? == 0 + system "#{WINDOWS_ELEVATE_CMD} #{asdk_file_name}" + raise "Unexpected exit code while installing the Android SDK: #{$?.exitstatus}" unless $? == 0 FileUtils.rm_f asdk_file_name return else raise "Unknown host os: #{RbConfig::CONFIG['host_os']}" end @@ -394,43 +446,99 @@ end check_for_android_sdk unless @android_loc.nil? ENV['ANDROID_HOME'] = (File.expand_path File.dirname(@android_loc)+'/..').gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR) puts "Setting the ANDROID_HOME environment variable to #{ENV['ANDROID_HOME']}" - if RbConfig::CONFIG['host_os'] =~ /^mswin32|windows(.*)/ + if windows? system %Q{setx ANDROID_HOME "#{ENV['ANDROID_HOME']}"} end @missing_paths << "#{File.dirname(@android_loc)}" end end end + def download(asdk_file_name) + print "Downloading #{asdk_file_name}: \r" + uri = URI("http://dl.google.com/android/#{asdk_file_name}") + body = '' + Net::HTTP.new(uri.host, uri.port).request_get(uri.path) do |response| + length = response['Content-Length'].to_i + response.read_body do |fragment| + body << fragment + print "Downloading #{asdk_file_name}: #{body.length / 1024**2}MB/#{length / 1024**2}MB #{(body.length * 100) / length}%\r" + end + puts + end + File.open(asdk_file_name, 'wb') { |f| f << body } + end + + def unzip(accept_all, asdk_file_name) + require 'zip' + Zip::File.open(asdk_file_name) do |zipfile| + zipfile.each do |f| + f.restore_permissions = true + f.extract { accept_all } + end + end + end + def install_android_tools(accept_all) - if @android_loc and (@dx_loc.nil? || @adb_loc.nil? || @emulator_loc.nil?) + if @android_loc and (@dx_loc.nil? || @adb_loc.nil? || @emulator_loc.nil? || @haxm_installer_loc.nil?) puts 'Android tools not found.' unless accept_all - print 'Would you like to download and install it? (Y/n): ' + print 'Would you like to download and install them? (Y/n): ' a = STDIN.gets.chomp.upcase end if accept_all || a == 'Y' || a.empty? - update_cmd = "android --silent update sdk --no-ui --filter build-tools-#{get_tools_version('build-tool')},platform-tool,tool -a --force" + android_cmd = windows? ? 'android.bat' : 'android' + update_cmd = "#{android_cmd} --silent update sdk --no-ui --filter build-tools-#{get_tools_version('build-tool')},extra-intel-Hardware_Accelerated_Execution_Manager,platform-tool,tool -a" update_sdk(update_cmd, accept_all) check_for_build_tools check_for_platform_tools check_for_emulator + check_for_haxm end end end + def install_haxm(accept_all) + if @haxm_installer_loc && @haxm_kext_loc.nil? + puts 'HAXM not installed.' + unless accept_all + print 'Would you like to install HAXM? (Y/n): ' + a = STDIN.gets.chomp.upcase + end + if accept_all || a == 'Y' || a.empty? + case android_package_os_id + when MAC_OS_X + system "hdiutil attach #{@haxm_installer_loc}" + # FIXME(uwe): Detect volume + # FIXME(uwe): Detect mpkg file with correct version. + system 'sudo -S installer -pkg /Volumes/IntelHAXM_1.0.6/IntelHAXM_1.0.6.mpkg -target /' + when LINUX + puts ' HAXM installation on Linux is not supported, yet.' + return + when WINDOWS + cmd = @haxm_installer_loc.gsub('/', "\\") + puts "Running the HAXM installer" + system %Q{#{WINDOWS_ELEVATE_CMD} "#{cmd}"} + raise "Unexpected return code: #{$?.exitstatus}" unless $? == 0 + return + end + end + end + end + def install_platform(accept_all, api_level) puts "Android platform SDK for #{api_level} not found." unless accept_all print 'Would you like to download and install it? (Y/n): ' a = STDIN.gets.chomp.upcase end if accept_all || a == 'Y' || a.empty? - update_cmd = "android update sdk --no-ui --filter #{api_level},sysimg-#{api_level.slice(/\d+$/)} --all" + android_cmd = windows? ? 'android.bat' : 'android' + update_cmd = "#{android_cmd} update sdk --no-ui --filter #{api_level},sysimg-#{api_level.slice(/\d+$/)} --all" update_sdk(update_cmd, accept_all) check_for_android_platform(api_level) end end @@ -463,17 +571,24 @@ # Path Config Method # def config_path(accept_all) unless @missing_paths.empty? - if RbConfig::CONFIG['host_os'] =~ /^mswin32|windows(.*)/ - puts "\nYou are missing some paths. Execute these lines to add them:\n\n" + puts "\nYou are missing some paths. Execute these lines to add them:\n\n" + if windows? @missing_paths.each do |path| puts %Q{ set PATH="#{path.gsub '/', '\\'};%PATH%"} end - system %Q{setx PATH "%PATH%;#{@missing_paths.map { |path| path.gsub '/', '\\' }.join(';')}"} + old_path = ENV['PATH'].split(';') + new_path = (@missing_paths.map { |path| path.gsub '/', '\\' } + old_path).uniq.join(';') + if new_path.size <= 1024 + system %Q{setx PATH "#{new_path}"} + else + puts "\nYour path is HUGE: #{new_path.size} characters. It cannot be saved permanently:\n\n" + puts new_path.gsub(';', "\n") + puts + end else - puts "\nYou are missing some paths. Execute these lines to add them:\n\n" @missing_paths.each do |path| puts %Q{ export PATH="#{path}:$PATH"} end puts unless accept_all