From c4fc96bff3a3e6fe7b11772a18fbe52affbe813a Mon Sep 17 00:00:00 2001 From: Laurent Sansonetti Date: Sat, 4 May 2013 18:59:53 +0200 Subject: [PATCH] add command-line plugins --- bin/motion | 273 +------------------------ lib/motion/project/command.rb | 96 +++++++++ lib/motion/project/command/account.rb | 40 ++++ lib/motion/project/command/activate.rb | 48 +++++ lib/motion/project/command/create.rb | 62 ++++++ lib/motion/project/command/ri.rb | 37 ++++ lib/motion/project/command/support.rb | 58 ++++++ lib/motion/project/command/update.rb | 98 +++++++++ 8 files changed, 444 insertions(+), 268 deletions(-) create mode 100644 lib/motion/project/command.rb create mode 100644 lib/motion/project/command/account.rb create mode 100644 lib/motion/project/command/activate.rb create mode 100644 lib/motion/project/command/create.rb create mode 100644 lib/motion/project/command/ri.rb create mode 100644 lib/motion/project/command/support.rb create mode 100644 lib/motion/project/command/update.rb diff --git a/bin/motion b/bin/motion index 271d4f2c..e1d561dc 100644 --- a/bin/motion +++ b/bin/motion @@ -5,279 +5,16 @@ # Agreement accompanying the package this file is a part of. require 'fileutils' -require 'uri' relative_libdir = File.expand_path(File.join(File.dirname(File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__), '../lib')) $motion_libdir = File.exist?(File.join(relative_libdir, 'motion')) ? relative_libdir : '/Library/RubyMotion/lib' $:.unshift($motion_libdir) -require 'motion/version' -require 'motion/project/app.rb' -require 'motion/project/builder.rb' -class Command - class << self - attr_accessor :name - attr_accessor :help - - def die(*msg) - $stderr.puts msg - exit 1 - end +require 'motion/project/command' - def need_root - if Process.uid != 0 - die "You need to be root to run this command." - end - end - - def read_license_key - unless File.exist?(LicensePath) - die "License file not present. Please activate RubyMotion with `motion activate' and try again." - end - File.read(LicensePath).strip - end - - def guess_email_address - # Guess the default email address from git. - URI.escape(`git config --get user.email`.strip) - end - end +command_paths = [File.join($motion_libdir, 'motion/project/command'), File.join(ENV['HOME'], 'Library/RubyMotion/command')] +command_paths.each do |path| + Dir.glob(File.join(path, '*.rb')).each { |x| require x } end -class CreateCommand < Command - self.name = 'create' - self.help = 'Create a new project' - - def self.run(args) - if args.size < 1 || args.size > 2 - end - - app_name = nil - template_name = 'ios' - args.each do |a| - case a - when /--([^=]+)=(.+)/ - opt_name = $1.to_s.strip - opt_val = $2.to_s.strip - case opt_name - when 'template' - template_name = opt_val - else - die "Incorrect option `#{opt_name}'" - end - else - if app_name - app_name = nil - break - else - app_name = a - end - end - end - - unless app_name - die "Usage: motion create [--template=] " - end - - Motion::Project::App.create(app_name, template_name) - end -end - -LicensePath = '/Library/RubyMotion/license.key' - -class ActivateCommand < Command - self.name = 'activate' - self.help = 'Activate the software license' - - def self.run(args) - if File.exist?(LicensePath) - die "Product is already activated. Delete the license file `#{LicensePath}' if you want to activate a new license." - end - - if args.size != 1 - die "Usage: motion activate " - end - - license_key = args[0] - unless license_key.match(/^[a-f0-9]{40}$/) - die "Given license key `#{license_key}' seems invalid. It should be a string of 40 hexadecimal characters. Check the mail you received after the order, or contact us if you need any help: info@hipbyte.com" - end - - need_root - File.open(LicensePath, 'w') { |io| io.write license_key } - puts "Product activated. Thanks for purchasing RubyMotion :-)" - end -end - -class AccountCommand < Command - self.name = 'account' - self.help = 'Access the software license account' - - def self.run(args) - unless args.empty? - die "Usage: motion account" - end - - license_key = read_license_key - email = guess_email_address - - system("open \"https://secure.rubymotion.com/account?license_key=#{license_key}&email=#{email}\"") - end -end - -class SupportCommand < Command - self.name = 'support' - self.help = 'Create a support ticket' - - def self.run(args) - unless args.empty? - die "Usage: motion support" - end - - license_key = read_license_key - email = guess_email_address - - # Collect details about the environment. - osx_vers = `/usr/bin/sw_vers -productVersion`.strip - rm_vers = Motion::Version - xcode_vers = begin - xcodebuild = `which xcodebuild`.strip - xcodebuild = '/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild' if xcodebuild.empty? - vers = '' - if File.exist?(xcodebuild) - vers = `#{xcodebuild} -version`.strip.scan(/Xcode\s(.+)$/).flatten[0].to_s - end - vers = 'unknown' if vers.empty? - vers - end - - environment = URI.escape("OSX #{osx_vers}, RubyMotion #{rm_vers}, Xcode #{xcode_vers}") - - system("open \"https://secure.rubymotion.com/new_support_ticket?license_key=#{license_key}&email=#{email}&environment=#{environment}\"") - end -end - -class UpdateCommand < Command - self.name = 'update' - self.help = 'Update the software' - - def self.curl(cmd) - resp = `/usr/bin/curl --connect-timeout 60 #{cmd}` - if $?.exitstatus != 0 - die "Error when connecting to the server. Check your Internet connection and try again." - end - resp - end - - def self.run(args) - check_mode = false - wanted_software_version = '' - args.each do |a| - case a - when '--check' - check_mode = true - when /--force-version=(.+)/ - wanted_software_version = $1.to_s - else - die "Usage: motion update [--force-version=X]" - end - end - - product_version = Motion::Version - if check_mode - update_check_file = File.join(ENV['TMPDIR'] || '/tmp', '.motion-update-check') - if !File.exist?(update_check_file) or (Time.now - File.mtime(update_check_file) > 60 * 60 * 24) - resp = curl("-s -d \"product=rubymotion\" -d \"current_software_version=#{product_version}\" http://secure.rubymotion.com/latest_software_version") - exit 1 unless resp.match(/^\d+\.\d+/) - File.open(update_check_file, 'w') { |io| io.write(resp) } - end - exit File.read(update_check_file) > product_version ? 2 : 0 - end - - unless File.exist?(LicensePath) - die "License file not present. Please activate RubyMotion with `motion activate' and try again." - end - - need_root - license_key = File.read(LicensePath).strip - - $stderr.puts "Connecting to the server..." - resp = curl("-s -d \"product=rubymotion\" -d \"current_software_version=#{product_version}\" -d \"wanted_software_version=#{wanted_software_version}\" -d \"license_key=#{license_key}\" https://secure.rubymotion.com/update_software") - unless resp.match(/^http:/) - die resp - end - - $stderr.puts "Downloading software update..." - url = resp - tmp_dest = '/tmp/_rubymotion_su.pkg' - curl("-# \"#{url}\" -o #{tmp_dest}") - - $stderr.puts "Installing software update..." - installer = "/usr/sbin/installer -pkg \"#{tmp_dest}\" -target / >& /tmp/installer.stderr" - unless system(installer) - die "An error happened when installing the software update: #{File.read('/tmp/installer.stderr')}" - end - FileUtils.rm_f tmp_dest - - $stderr.puts "Software update installed.\n\n" - news = File.read('/Library/RubyMotion/NEWS') - news.lines.each do |line| - if md = line.match(/^=\s+RubyMotion\s+(.+)\s+=$/) - break if md[1] <= product_version - end - $stderr.puts line - end - $stderr.puts "(See the `/Library/RubyMotion/NEWS' file for all changes.)" - - FileUtils.rm_rf Motion::Project::Builder.common_build_dir - end -end - -class RICommand < Command - self.name = 'ri' - self.help = 'Display API reference' - - def self.run(args) - if args.size <= 0 - die "Usage: motion ri " - end - - system("/Library/RubyMotion/lib/yard/bin/yri --db /Library/RubyMotion/doc/yardoc #{args[0]}") - end -end - -class MotionMainCommand - Commands = [CreateCommand, ActivateCommand, UpdateCommand, RICommand, SupportCommand, AccountCommand] - - def initialize(args) - arg = args.shift - case arg - when '-h', '--help' - usage - when '-v', '--version' - $stdout.puts Motion::Version - exit 1 - when /^-/ - $stderr.puts "Unknown option: #{arg}" - exit 1 - end - command = Commands.find { |command| command.name == arg } - usage unless command - command.run(args) - end - - def usage - $stderr.puts 'Usage:' - $stderr.puts " #{File.basename(__FILE__)} [-h, --help]" - $stderr.puts " #{File.basename(__FILE__)} [-v, --version]" - $stderr.puts " #{File.basename(__FILE__)} []" - $stderr.puts '' - $stderr.puts 'Commands:' - Commands.each do |command| - $stderr.puts " #{command.name}".ljust(15) + command.help - end - exit 1 - end -end - -MotionMainCommand.new(ARGV) +Motion::Project::Command.main(ARGV) diff --git a/lib/motion/project/command.rb b/lib/motion/project/command.rb new file mode 100644 index 00000000..840c74b2 --- /dev/null +++ b/lib/motion/project/command.rb @@ -0,0 +1,96 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'motion/version' + +module Motion; module Project + class Command + class << self + attr_accessor :name + attr_accessor :help + end + + Commands = [] + def self.inherited(klass) + Commands << klass if self == Command + end + + def self.main(args) + arg = args.shift + case arg + when '-h', '--help' + usage + when '-v', '--version' + $stdout.puts Motion::Version + exit 1 + when /^-/ + $stderr.puts "Unknown option: #{arg}" + exit 1 + end + command = Commands.find { |command| command.name == arg } + usage unless command + command.new.run(args) + end + + def self.usage + $stderr.puts 'Usage:' + $stderr.puts " motion [-h, --help]" + $stderr.puts " motion [-v, --version]" + $stderr.puts " motion []" + $stderr.puts '' + $stderr.puts 'Commands:' + Commands.each do |command| + $stderr.puts " #{command.name}".ljust(15) + command.help + end + exit 1 + end + + def run(args) + # To be implemented by subclasses. + end + + def die(*msg) + $stderr.puts msg + exit 1 + end + + def need_root + if Process.uid != 0 + die "You need to be root to run this command." + end + end + + LicensePath = '/Library/RubyMotion/license.key' + def read_license_key + unless File.exist?(LicensePath) + die "License file not present. Please activate RubyMotion with `motion activate' and try again." + end + File.read(LicensePath).strip + end + + def guess_email_address + # Guess the default email address from git. + URI.escape(`git config --get user.email`.strip) + end + end +end; end diff --git a/lib/motion/project/command/account.rb b/lib/motion/project/command/account.rb new file mode 100644 index 00000000..995043b6 --- /dev/null +++ b/lib/motion/project/command/account.rb @@ -0,0 +1,40 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module Motion; module Project + class AccountCommand < Command + self.name = 'account' + self.help = 'Access the software license account' + + def run(args) + unless args.empty? + die "Usage: motion account" + end + + license_key = read_license_key + email = guess_email_address + + system("open \"https://secure.rubymotion.com/account?license_key=#{license_key}&email=#{email}\"") + end + end +end; end diff --git a/lib/motion/project/command/activate.rb b/lib/motion/project/command/activate.rb new file mode 100644 index 00000000..b1e84e30 --- /dev/null +++ b/lib/motion/project/command/activate.rb @@ -0,0 +1,48 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module Motion; module Project + class ActivateCommand < Command + self.name = 'activate' + self.help = 'Activate the software license' + + def run(args) + if File.exist?(LicensePath) + die "Product is already activated. Delete the license file `#{LicensePath}' if you want to activate a new license." + end + + if args.size != 1 + die "Usage: motion activate " + end + + license_key = args[0] + unless license_key.match(/^[a-f0-9]{40}$/) + die "Given license key `#{license_key}' seems invalid. It should be a string of 40 hexadecimal characters. Check the mail you received after the order, or contact us if you need any help: info@hipbyte.com" + end + + need_root + File.open(LicensePath, 'w') { |io| io.write license_key } + puts "Product activated. Thanks for purchasing RubyMotion :-)" + end + end +end; end diff --git a/lib/motion/project/command/create.rb b/lib/motion/project/command/create.rb new file mode 100644 index 00000000..477fa1ba --- /dev/null +++ b/lib/motion/project/command/create.rb @@ -0,0 +1,62 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'motion/project/app' + +module Motion; module Project + class CreateCommand < Command + self.name = 'create' + self.help = 'Create a new project' + + def run(args) + app_name = nil + template_name = 'ios' + args.each do |a| + case a + when /--([^=]+)=(.+)/ + opt_name = $1.to_s.strip + opt_val = $2.to_s.strip + case opt_name + when 'template' + template_name = opt_val + else + die "Incorrect option `#{opt_name}'" + end + else + if app_name + app_name = nil + break + else + app_name = a + end + end + end + + unless app_name + die "Usage: motion create [--template=] " + end + + Motion::Project::App.create(app_name, template_name) + end + end +end; end diff --git a/lib/motion/project/command/ri.rb b/lib/motion/project/command/ri.rb new file mode 100644 index 00000000..9588a564 --- /dev/null +++ b/lib/motion/project/command/ri.rb @@ -0,0 +1,37 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module Motion; module Project + class RICommand < Command + self.name = 'ri' + self.help = 'Display API reference' + + def run(args) + if args.size <= 0 + die "Usage: motion ri " + end + + system("/Library/RubyMotion/lib/yard/bin/yri --db /Library/RubyMotion/doc/yardoc #{args[0]}") + end + end +end; end diff --git a/lib/motion/project/command/support.rb b/lib/motion/project/command/support.rb new file mode 100644 index 00000000..867c7f3f --- /dev/null +++ b/lib/motion/project/command/support.rb @@ -0,0 +1,58 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'uri' + +module Motion; module Project + class SupportCommand < Command + self.name = 'support' + self.help = 'Create a support ticket' + + def run(args) + unless args.empty? + die "Usage: motion support" + end + + license_key = read_license_key + email = guess_email_address + + # Collect details about the environment. + osx_vers = `/usr/bin/sw_vers -productVersion`.strip + rm_vers = Motion::Version + xcode_vers = begin + xcodebuild = `which xcodebuild`.strip + xcodebuild = '/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild' if xcodebuild.empty? + vers = '' + if File.exist?(xcodebuild) + vers = `#{xcodebuild} -version`.strip.scan(/Xcode\s(.+)$/).flatten[0].to_s + end + vers = 'unknown' if vers.empty? + vers + end + + environment = URI.escape("OSX #{osx_vers}, RubyMotion #{rm_vers}, Xcode #{xcode_vers}") + + system("open \"https://secure.rubymotion.com/new_support_ticket?license_key=#{license_key}&email=#{email}&environment=#{environment}\"") + end + end +end; end diff --git a/lib/motion/project/command/update.rb b/lib/motion/project/command/update.rb new file mode 100644 index 00000000..8a02d099 --- /dev/null +++ b/lib/motion/project/command/update.rb @@ -0,0 +1,98 @@ +# Copyright (c) 2012, HipByte SPRL and contributors +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require 'motion/project/builder' + +module Motion; module Project + class UpdateCommand < Command + self.name = 'update' + self.help = 'Update the software' + + def curl(cmd) + resp = `/usr/bin/curl --connect-timeout 60 #{cmd}` + if $?.exitstatus != 0 + die "Error when connecting to the server. Check your Internet connection and try again." + end + resp + end + + def run(args) + check_mode = false + wanted_software_version = '' + args.each do |a| + case a + when '--check' + check_mode = true + when /--force-version=(.+)/ + wanted_software_version = $1.to_s + else + die "Usage: motion update [--force-version=X]" + end + end + + product_version = Motion::Version + if check_mode + update_check_file = File.join(ENV['TMPDIR'] || '/tmp', '.motion-update-check') + if !File.exist?(update_check_file) or (Time.now - File.mtime(update_check_file) > 60 * 60 * 24) + resp = curl("-s -d \"product=rubymotion\" -d \"current_software_version=#{product_version}\" http://secure.rubymotion.com/latest_software_version") + exit 1 unless resp.match(/^\d+\.\d+/) + File.open(update_check_file, 'w') { |io| io.write(resp) } + end + exit File.read(update_check_file) > product_version ? 2 : 0 + end + + license_key = read_license_key + need_root + + $stderr.puts "Connecting to the server..." + resp = curl("-s -d \"product=rubymotion\" -d \"current_software_version=#{product_version}\" -d \"wanted_software_version=#{wanted_software_version}\" -d \"license_key=#{license_key}\" https://secure.rubymotion.com/update_software") + unless resp.match(/^http:/) + die resp + end + + $stderr.puts "Downloading software update..." + url = resp + tmp_dest = '/tmp/_rubymotion_su.pkg' + curl("-# \"#{url}\" -o #{tmp_dest}") + + $stderr.puts "Installing software update..." + installer = "/usr/sbin/installer -pkg \"#{tmp_dest}\" -target / >& /tmp/installer.stderr" + unless system(installer) + die "An error happened when installing the software update: #{File.read('/tmp/installer.stderr')}" + end + FileUtils.rm_f tmp_dest + + $stderr.puts "Software update installed.\n\n" + news = File.read('/Library/RubyMotion/NEWS') + news.lines.each do |line| + if md = line.match(/^=\s+RubyMotion\s+(.+)\s+=$/) + break if md[1] <= product_version + end + $stderr.puts line + end + $stderr.puts "(See the `/Library/RubyMotion/NEWS' file for all changes.)" + + FileUtils.rm_rf Motion::Project::Builder.common_build_dir + end + end +end; end