lib/ruboto/util/setup.rb in ruboto-0.12.0 vs lib/ruboto/util/setup.rb in ruboto-0.13.0.rc.0
- old
+ new
@@ -1,34 +1,43 @@
+require 'pty'
require 'ruboto/sdk_versions'
module Ruboto
module Util
module Setup
- include Ruboto::SdkVersions
- # Todo: Find a way to look this up
- ANDROID_SDK_VERSION = '21.1'
+ REPOSITORY_BASE = 'https://dl-ssl.google.com/android/repository'
+ REPOSITORY_URL = "#{REPOSITORY_BASE}/repository-8.xml"
#########################################
#
# Core Set up Method
#
- def setup_ruboto
- check = check_all
+ def setup_ruboto(accept_all, api_levels = [SdkVersions::DEFAULT_TARGET_SDK])
+ @platform_sdk_loc = {}
+ api_levels = [read_project_api_level, *api_levels].compact.uniq
+ install_all(accept_all, api_levels) unless check_all(api_levels)
+ config_path(accept_all)
+ end
- if not check and RbConfig::CONFIG['host_os'] == /^windows(.*)/
- puts "\nWe can't directly install Android on Windows."
- puts 'If you would like to contribute to the setup for Windows,'
- puts 'please file an issue at https://github.com/ruboto/ruboto/issues'
- puts
- return
+ #
+ # OS independent "which"
+ # From: http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
+ #
+ 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
+ end
end
-
- install_all if not check
- config_path
+ nil
end
+ private
+
#########################################
#
# Utility Methods
#
@@ -52,17 +61,16 @@
else
"android-sdk-#{android_package_os_id}"
end
end
- def api_level
+ def read_project_api_level
begin
return $1 if File.read('project.properties') =~ /target=(.*)/
rescue
# ignored
end
- DEFAULT_TARGET_SDK
end
def path_setup_file
case RbConfig::CONFIG['host_os']
when /^darwin(.*)/ then
@@ -76,95 +84,112 @@
## Error
nil
end
end
- #
- # OS independent "which"
- # From: http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
- #
- def which(cmd)
- exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
- exts.each { |ext|
- exe = File.join(path, "#{cmd}#{ext}")
- return exe if File.executable? exe
- }
- end
- nil
+ def get_tools_version(type="tool")
+ require 'rexml/document'
+ require 'open-uri'
+
+ doc = REXML::Document.new(open(REPOSITORY_URL))
+ version = doc.root.elements["sdk:#{type}/sdk:revision/sdk:major"].text
+ minor = doc.root.elements["sdk:#{type}/sdk:revision/sdk:minor"]
+ micro = doc.root.elements["sdk:#{type}/sdk:revision/sdk:micro"]
+ version += ".#{minor.text}" if minor
+ version += ".#{micro.text}" if micro
+ version
end
#########################################
#
# Check Methods
#
- def check_all
+ def check_all(api_levels)
+ @existing_paths = []
@missing_paths = []
- @java_loc = check_for('java', 'Java')
+ @java_loc = check_for('java', 'Java runtime')
@javac_loc = check_for('javac', 'Java Compiler')
@ant_loc = check_for('ant', 'Apache ANT')
- @android_loc = check_for('android', 'Android Package Installer',
- File.join(File.expand_path('~'), android_package_directory, 'tools', 'android'))
- @emulator_loc = check_for('emulator', 'Android Emulator')
+ check_for_android_sdk
+ check_for_emulator
+ check_for_platform_tools
+ check_for_build_tools
+ api_levels.each { |api_level| check_for_android_platform(api_level) }
+
+ puts
+ ok = @java_loc && @javac_loc && @ant_loc && @android_loc && @emulator_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(File.expand_path('~'), android_package_directory, 'tools', 'emulator'))
+ end
+
+ def check_for_platform_tools
@adb_loc = check_for('adb', 'Android SDK Command adb',
File.join(File.expand_path('~'), android_package_directory, 'platform-tools', 'adb'))
- @dx_loc = check_for('dx', 'Android SDK Command dx')
- check_for_android_platform
+ end
- puts
- if @java_loc && @javac_loc && @adb_loc && @dx_loc && @emulator_loc && @platform_sdk_loc
- puts " *** Ruboto setup is OK! ***\n\n"
- true
- else
- puts " !!! Ruboto setup is NOT OK !!!\n\n"
- false
- end
+ def check_for_build_tools
+ @dx_loc = check_for('dx', 'Android SDK Command dx',
+ Dir[File.join(File.expand_path('~'), android_package_directory, 'build-tools', '*', 'dx')][-1])
end
+ def check_for_android_sdk
+ @android_loc = check_for('android', 'Android Package Installer',
+ File.join(File.expand_path('~'), android_package_directory, 'tools', 'android'))
+ end
+
def check_for(cmd, pretty_name=nil, alt_dir=nil)
rv = which(cmd)
rv = nil if rv.nil? or rv.empty?
- if rv.nil? and alt_dir and File.exists?(alt_dir)
+ if rv
+ @existing_paths << File.dirname(rv)
+ elsif alt_dir and File.exists?(alt_dir)
rv = alt_dir
ENV['PATH'] = "#{File.dirname(rv)}:#{ENV['PATH']}"
@missing_paths << "#{File.dirname(rv)}"
end
- puts "#{pretty_name || cmd}: " + (rv ? "Found at #{rv}" : 'Not found')
+ puts "#{'%-25s' % (pretty_name || cmd)}: #{(rv ? 'Found' : 'Not found')}"
rv
end
- def check_for_android_platform
+ def check_for_android_platform(api_level)
begin
- @platform_sdk_loc = File.expand_path "#{@dx_loc}/../../platforms/#{api_level}"
- if File.exists? @platform_sdk_loc
- puts "Android platform SDK: Found at #{@platform_sdk_loc}"
- else
- puts 'Android platform SDK: Not found'
- @platform_sdk_loc = nil
- end
+ @platform_sdk_loc[api_level] = File.expand_path "#{@android_loc}/../../platforms/#{api_level}"
+ found = File.exists? @platform_sdk_loc[api_level]
+ @platform_sdk_loc[api_level] = nil unless found
+ puts "#{'%-25s' % "Platform SDK #{api_level}"}: #{(found ? 'Found' : 'Not found')}"
rescue
- @platform_sdk_loc = nil
+ @platform_sdk_loc[api_level] = nil
end
end
#########################################
#
# Install Methods
#
- def install_all
- install_java
- install_android
- install_adb
- install_platform
+ 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
+ install_android_tools(accept_all) unless @dx_loc && @adb_loc && @emulator_loc # build-tools, platform-tools and tools
+ if @android_loc
+ api_levels.each do |api_level|
+ install_platform(accept_all, api_level) unless @platform_sdk_loc[api_level]
+ end
+ end
end
- def install_java
+ def install_java(accept_all)
case RbConfig::CONFIG['host_os']
when /^darwin(.*)/
when /^linux(.*)/
when /^mswin32|windows(.*)/
# FIXME(uwe): Detect and warn if we are not "elevated" with adminstrator rights.
@@ -173,37 +198,118 @@
#if %IS_ELEVATED%==0 (
# echo You must run the command prompt as administrator to install.
# exit /b 1
#)
- java_installer_file_name = 'jdk-7-windows-x64.exe'
- require 'net/http'
- require 'net/https'
- resp = nil
- @cookies = ['gpw_e24=http%3A%2F%2Fwww.oracle.com']
- puts 'Downloading...'
- Net::HTTP.start('download.oracle.com') do |http|
- resp, _ = http.get("/otn-pub/java/jdk/7/#{java_installer_file_name}", cookie_header)
- resp.body
+ puts 'Java JDK was not found.'
+ unless accept_all
+ print 'Would you like to download and install it? (Y/n): '
+ a = STDIN.gets.chomp.upcase
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
- FileUtils.rm_f java_installer_file_name
- return
+ if accept_all || a == 'Y' || a.empty?
+ java_installer_file_name = 'jdk-7-windows-x64.exe'
+ require 'net/http'
+ require 'net/https'
+ resp = nil
+ @cookies = %w(gpw_e24=http%3A%2F%2Fwww.oracle.com)
+ puts 'Downloading...'
+ Net::HTTP.start('download.oracle.com') do |http|
+ resp, _ = http.get("/otn-pub/java/jdk/7/#{java_installer_file_name}", cookie_header)
+ resp.body
+ 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
+ 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'
+ puts
+ end
+ unless check_for('javac')
+ ENV['JAVA_HOME'] = 'c:\\Program Files\\Java\\jdk1.7.0'
+ if Dir.exists?(ENV['JAVA_HOME'])
+ @javac_loc = "#{ENV['JAVA_HOME'].gsub('\\', '/')}/bin/javac"
+ puts "Setting the JAVA_HOME environment variable to #{ENV['JAVA_HOME']}"
+ 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']}"
end
end
+ def install_ant(accept_all)
+ case RbConfig::CONFIG['host_os']
+ when /^darwin(.*)/
+ when /^linux(.*)/
+ when /^mswin32|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
+ #)
+
+ puts 'Apache ANT was 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?
+ Dir.chdir Dir.home do
+ ant_package_file_name = 'apache-ant-1.9.0-bin.tar.gz'
+ require 'net/http'
+ require 'net/https'
+ puts 'Downloading...'
+ Net::HTTP.start('apache.vianett.no') do |http|
+ resp, _ = http.get("/ant/binaries/#{ant_package_file_name}")
+ open(ant_package_file_name, 'wb') { |file| file.write(resp.body) }
+ end
+ puts "Installing #{ant_package_file_name}..."
+ require 'rubygems/package'
+ require 'zlib'
+ Gem::Package::TarReader.new(Zlib::GzipReader.open(ant_package_file_name)).each do |entry|
+ puts entry.full_name
+ if entry.directory?
+ FileUtils.mkdir_p entry.full_name
+ elsif entry.file?
+ FileUtils.mkdir_p File.dirname(entry.full_name)
+ File.open(entry.full_name, 'wb') { |f| f << entry.read }
+ end
+ end
+ FileUtils.rm_f ant_package_file_name
+ end
+ else
+ puts
+ puts 'You can download and install Apache ANT manually from'
+ puts 'http://ant.apache.org/bindownload.cgi'
+ puts
+ end
+ unless check_for('ant')
+ ENV['ANT_HOME'] = File.expand_path(File.join('~', 'apache-ant-1.9.0')).gsub('/', '\\')
+ if Dir.exists?(ENV['ANT_HOME'])
+ @ant_loc = "#{ENV['ANT_HOME'].gsub('\\', '/')}/bin/ant"
+ puts "Setting the ANT_HOME environment variable to #{ENV['ANT_HOME']}"
+ system %Q{setx ANT_HOME "#{ENV['ANT_HOME']}"}
+ @missing_paths << "#{File.dirname(@ant_loc)}"
+ end
+ end
+ else
+ raise "Unknown host os: #{RbConfig::CONFIG['host_os']}"
+ end
+ end
+
def cookie_header
return {} if @cookies.empty?
{'Cookie' => @cookies.join(';')}
end
- private :cookie_header
def store_cookie(response)
return unless response['set-cookie']
header = response['set-cookie']
header.gsub! /expires=.{3},/, ''
@@ -215,11 +321,10 @@
end
@cookies << cookie_value unless cookie_value =~ /^.*?=$/
end
@cookies.uniq!
end
- private :store_cookie
def process_response(response)
store_cookie(response)
if response.code == '302'
redirect_url = response['location']
@@ -241,27 +346,28 @@
elsif response.code != '200'
raise "Got response code #{response.code}"
end
response
end
- private :process_response
- def install_android
+ def install_android_sdk(accept_all)
unless @android_loc
puts 'Android package installer not found.'
- print 'Would you like to download and install it? (Y/n): '
- a = STDIN.gets.chomp.upcase
- if a == 'Y' || a.empty?
+ 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?
Dir.chdir File.expand_path('~/') do
case RbConfig::CONFIG['host_os']
when /^darwin(.*)/
- asdk_file_name = "android-sdk_r#{ANDROID_SDK_VERSION}-#{android_package_os_id}.zip"
+ 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 #{asdk_file_name}"
+ system "unzip #{'-o ' if accept_all}#{asdk_file_name}"
system "rm #{asdk_file_name}"
when /^linux(.*)/
- asdk_file_name = "android-sdk_r#{ANDROID_SDK_VERSION}-#{android_package_os_id}.tgz"
+ asdk_file_name = "android-sdk_r#{get_tools_version}-#{android_package_os_id}.tgz"
system "wget http://dl.google.com/android/#{asdk_file_name}"
system "tar -xzf #{asdk_file_name}"
system "rm #{asdk_file_name}"
when /^mswin32|windows(.*)/
# FIXME(uwe): Detect and warn if we are not "elevated" with adminstrator rights.
@@ -270,11 +376,11 @@
#if %IS_ELEVATED%==0 (
# echo You must run the command prompt as administrator to install.
# exit /b 1
#)
- asdk_file_name = "installer_r#{ANDROID_SDK_VERSION}-#{android_package_os_id}.exe"
+ 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) }
@@ -286,73 +392,130 @@
return
else
raise "Unknown host os: #{RbConfig::CONFIG['host_os']}"
end
end
- @android_loc = File.join(File.expand_path('~'), android_package_directory, 'tools', 'android')
- ENV['PATH'] = "#{File.dirname(@android_loc)}:#{ENV['PATH']}"
+ end
+ check_for_android_sdk
+ unless @android_loc
+ ENV['ANDROID_HOME'] = @android_loc.gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
+ puts "Setting the ANDROID_HOME environment variable to #{ENV['ANDROID_HOME']}"
+ system %Q{setx ANDROID_HOME "#{ENV['ANDROID_HOME']}"}
@missing_paths << "#{File.dirname(@android_loc)}"
end
end
end
- def install_adb
- if @android_loc and not @adb_loc
- puts 'Android command adb not found.'
- print 'Would you like to download and install it? (Y/n): '
- a = STDIN.gets.chomp.upcase
- if a == 'Y' || a.empty?
- system 'android update sdk --no-ui --filter tool,platform-tool'
- @adb_loc = File.join(File.expand_path('~'), android_package_directory, 'platform-tools', 'adb')
- ENV['PATH'] = "#{File.dirname(@adb_loc)}:#{ENV['PATH']}"
- @missing_paths << "#{File.dirname(@adb_loc)}"
+ def install_android_tools(accept_all)
+ if @android_loc and (@dx_loc.nil? || @adb_loc.nil? || @emulator_loc.nil?)
+ puts 'Android tools 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 --silent update sdk --no-ui --filter build-tools-#{get_tools_version('build-tool')},platform-tool,tool --force"
+ update_sdk(update_cmd, accept_all)
+ check_for_build_tools
+ check_for_platform_tools
+ check_for_emulator
+ end
end
end
- def install_platform
- if @android_loc and not @platform_sdk_loc
- puts "Android platform SDK for #{api_level} not found."
+ 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
- if a == 'Y' || a.empty?
- system "android update sdk --no-ui --filter #{api_level},sysimg-#{api_level.slice(/\d+$/)} --all"
- @platform_sdk_loc = File.expand_path "#{@dx_loc}/../../platforms/#{api_level}"
+ end
+ if accept_all || a == 'Y' || a.empty?
+ update_cmd = "android --silent 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
+
+ def update_sdk(update_cmd, accept_all)
+ if accept_all
+ begin
+ PTY.spawn(update_cmd) do |stdin, stdout, pid|
+ begin
+ output = ''
+ question_pattern = /.*Do you accept the license '[a-z-]+-[0-9a-f]{8}' \[y\/n\]: /m
+ STDOUT.sync = true
+ stdin.each_char do |text|
+ print text
+ output << text
+ if output =~ question_pattern
+ stdout.puts 'y'
+ output.sub! question_pattern, ''
+ end
+ end
+ rescue Errno::EIO
+ # This probably just means that the process has finished giving output.
+ end
+ end
+ rescue PTY::ChildExited
+ puts 'The child process exited!'
end
+ else
+ system update_cmd
end
end
#########################################
#
# Path Config Method
#
- def config_path
+ 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"
@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(';')}"}
+ system %Q{setx PATH "%PATH%;#{@missing_paths.map { |path| path.gsub '/', '\\' }.join(';')}"}
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
- print "\nWould you like to append these lines to your configuration script? (Y/n): "
- a = STDIN.gets.chomp.upcase
- if a == 'Y' || a.empty?
- print "What script do you use to configure your PATH? (#{path_setup_file}): "
- a = STDIN.gets.chomp.downcase
-
- File.open(File.expand_path("~/#{a.empty? ? path_setup_file : a}"), 'a') do |f|
- f.puts "\n# BEGIN Ruboto PATH setup"
- @missing_paths.each { |path| f.puts %Q{export PATH="#{path}:$PATH"} }
- f.puts '# END Ruboto PATH setup'
- f.puts
+ puts
+ unless accept_all
+ print "\nWould you like to append these lines to your configuration script? (Y/n): "
+ a = STDIN.gets.chomp.upcase
+ end
+ if accept_all || a == 'Y' || a.empty?
+ unless accept_all
+ print "What script do you use to configure your PATH? (#{path_setup_file}): "
+ a = STDIN.gets.chomp.downcase
end
- puts 'Path updated. Please close your command window and reopen.'
+ rubotorc = '~/.rubotorc'
+ File.open(File.expand_path(rubotorc), 'w') do |f|
+ (@existing_paths + @missing_paths - %w(/usr/bin)).uniq.sort.each do |path|
+ f << %Q{PATH="#{path}:$PATH"\n}
+ end
+ end
+ config_file_name = File.expand_path("~/#{a.nil? || a.empty? ? path_setup_file : a}")
+ old_config = File.read(config_file_name)
+ new_config = old_config.dup
+
+ # FIXME(uwe): Remove for Ruboto > 0.13.0
+ new_config.gsub! /\n*# BEGIN Ruboto PATH setup\n.*?\n# END Ruboto PATH setup\n*/m, ''
+ # EMXIF
+
+ new_config.gsub! /\n*# BEGIN Ruboto setup\n.*?\n# END Ruboto setup\n*/m, ''
+ new_config << "\n\n# BEGIN Ruboto setup\n"
+ new_config << "source #{rubotorc}\n"
+ new_config << "# END Ruboto setup\n\n"
+ File.open(config_file_name, 'wb') { |f| f << new_config }
+ puts "Updated #{config_file_name} to load the #{rubotorc} config file."
+ puts 'Please close your command window and reopen, or run'
+ puts
+ puts " source #{rubotorc}"
+ puts
end
end
end
end
end