| 
									
										
										
										
											2011-03-16 02:46:46 +01:00
										 |  |  | require 'pathname' | 
					
						
							| 
									
										
										
										
											2011-09-14 12:18:35 -07:00
										 |  |  | require 'exceptions' | 
					
						
							| 
									
										
										
										
											2013-10-18 12:56:51 -05:00
										 |  |  | require 'os/mac' | 
					
						
							| 
									
										
										
										
											2013-06-22 16:51:08 -05:00
										 |  |  | require 'utils/json' | 
					
						
							| 
									
										
										
										
											2013-07-11 21:55:02 -05:00
										 |  |  | require 'utils/inreplace' | 
					
						
							| 
									
										
										
										
											2013-05-22 19:51:15 -05:00
										 |  |  | require 'open-uri' | 
					
						
							| 
									
										
										
										
											2011-03-16 02:46:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-15 14:42:19 +01:00
										 |  |  | class Tty | 
					
						
							| 
									
										
										
										
											2013-03-31 15:18:38 -05:00
										 |  |  |   class << self | 
					
						
							| 
									
										
										
										
											2009-10-15 14:42:19 +01:00
										 |  |  |     def blue; bold 34; end | 
					
						
							|  |  |  |     def white; bold 39; end | 
					
						
							|  |  |  |     def red; underline 31; end | 
					
						
							| 
									
										
										
										
											2014-03-01 18:13:15 -08:00
										 |  |  |     def yellow; underline 33; end | 
					
						
							| 
									
										
										
										
											2009-10-15 14:42:19 +01:00
										 |  |  |     def reset; escape 0; end | 
					
						
							| 
									
										
										
										
											2009-11-11 18:36:50 +00:00
										 |  |  |     def em; underline 39; end | 
					
						
							| 
									
										
										
										
											2014-03-01 18:13:15 -08:00
										 |  |  |     def green; bold 32; end | 
					
						
							|  |  |  |     def gray; bold 30; end | 
					
						
							| 
									
										
										
										
											2011-08-23 23:19:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def width | 
					
						
							|  |  |  |       `/usr/bin/tput cols`.strip.to_i | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2011-07-25 10:21:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-31 15:18:38 -05:00
										 |  |  |     def truncate(str) | 
					
						
							|  |  |  |       str.to_s[0, width - 4] | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-15 14:42:19 +01:00
										 |  |  |     def color n | 
					
						
							|  |  |  |       escape "0;#{n}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     def bold n | 
					
						
							|  |  |  |       escape "1;#{n}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     def underline n | 
					
						
							|  |  |  |       escape "4;#{n}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     def escape n | 
					
						
							|  |  |  |       "\033[#{n}m" if $stdout.tty? | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-16 19:29:43 +01:00
										 |  |  | def ohai title, *sput | 
					
						
							| 
									
										
										
										
											2013-03-31 15:18:38 -05:00
										 |  |  |   title = Tty.truncate(title) if $stdout.tty? && !ARGV.verbose? | 
					
						
							| 
									
										
										
										
											2009-10-15 14:42:19 +01:00
										 |  |  |   puts "#{Tty.blue}==>#{Tty.white} #{title}#{Tty.reset}" | 
					
						
							| 
									
										
										
										
											2010-10-25 21:11:45 -07:00
										 |  |  |   puts sput unless sput.empty? | 
					
						
							| 
									
										
										
										
											2009-07-31 02:51:17 +01:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2009-07-31 03:56:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-23 23:19:32 +01:00
										 |  |  | def oh1 title | 
					
						
							| 
									
										
										
										
											2013-03-31 15:18:38 -05:00
										 |  |  |   title = Tty.truncate(title) if $stdout.tty? && !ARGV.verbose? | 
					
						
							| 
									
										
										
										
											2012-11-13 12:50:24 +01:00
										 |  |  |   puts "#{Tty.green}==>#{Tty.white} #{title}#{Tty.reset}" | 
					
						
							| 
									
										
										
										
											2011-08-23 23:19:32 +01:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-31 03:56:46 +01:00
										 |  |  | def opoo warning | 
					
						
							| 
									
										
										
										
											2013-03-31 15:18:47 -05:00
										 |  |  |   STDERR.puts "#{Tty.red}Warning#{Tty.reset}: #{warning}" | 
					
						
							| 
									
										
										
										
											2009-08-10 16:48:30 +01:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def onoe error | 
					
						
							| 
									
										
										
										
											2013-03-31 15:18:47 -05:00
										 |  |  |   lines = error.to_s.split("\n") | 
					
						
							|  |  |  |   STDERR.puts "#{Tty.red}Error#{Tty.reset}: #{lines.shift}" | 
					
						
							|  |  |  |   STDERR.puts lines unless lines.empty? | 
					
						
							| 
									
										
										
										
											2009-08-10 16:48:30 +01:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-14 17:17:16 +10:00
										 |  |  | def ofail error | 
					
						
							| 
									
										
										
										
											2012-04-30 14:08:59 +10:00
										 |  |  |   onoe error | 
					
						
							|  |  |  |   Homebrew.failed = true | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def odie error | 
					
						
							| 
									
										
										
										
											2012-04-14 17:17:16 +10:00
										 |  |  |   onoe error | 
					
						
							|  |  |  |   exit 1
 | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2010-11-09 13:00:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-10 16:48:30 +01:00
										 |  |  | def pretty_duration s | 
					
						
							| 
									
										
										
										
											2009-09-03 20:58:33 +01:00
										 |  |  |   return "2 seconds" if s < 3 # avoids the plural problem ;) | 
					
						
							|  |  |  |   return "#{s.to_i} seconds" if s < 120
 | 
					
						
							|  |  |  |   return "%.1f minutes" % (s/60) | 
					
						
							| 
									
										
										
										
											2009-08-10 16:48:30 +01:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-20 10:01:49 -07:00
										 |  |  | def interactive_shell f=nil | 
					
						
							|  |  |  |   unless f.nil? | 
					
						
							|  |  |  |     ENV['HOMEBREW_DEBUG_PREFIX'] = f.prefix | 
					
						
							|  |  |  |     ENV['HOMEBREW_DEBUG_INSTALL'] = f.name | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-29 17:47:42 -05:00
										 |  |  |   Process.wait fork { exec ENV['SHELL'] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 17:44:29 +00:00
										 |  |  |   unless $?.success? | 
					
						
							|  |  |  |     puts "Aborting due to non-zero exit status" | 
					
						
							|  |  |  |     exit $? | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2009-07-31 03:56:46 +01:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2009-08-11 12:20:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  | module Homebrew | 
					
						
							|  |  |  |   def self.system cmd, *args | 
					
						
							|  |  |  |     puts "#{cmd} #{args*' '}" if ARGV.verbose? | 
					
						
							| 
									
										
										
										
											2014-03-29 02:24:01 -05:00
										 |  |  |     pid = fork do | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  |       yield if block_given? | 
					
						
							|  |  |  |       args.collect!{|arg| arg.to_s} | 
					
						
							| 
									
										
										
										
											2013-01-21 10:33:56 +01:00
										 |  |  |       exec(cmd.to_s, *args) rescue nil | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  |       exit! 1 # never gets here unless exec failed | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2014-03-29 02:24:01 -05:00
										 |  |  |     Process.wait(pid) | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  |     $?.success? | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-10 17:03:17 +00:00
										 |  |  | def with_system_path | 
					
						
							|  |  |  |   old_path = ENV['PATH'] | 
					
						
							|  |  |  |   ENV['PATH'] = '/usr/bin:/bin' | 
					
						
							|  |  |  |   yield | 
					
						
							|  |  |  | ensure | 
					
						
							|  |  |  |   ENV['PATH'] = old_path | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-11 12:20:55 -07:00
										 |  |  | # Kernel.system but with exceptions | 
					
						
							|  |  |  | def safe_system cmd, *args | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  |   unless Homebrew.system cmd, *args | 
					
						
							| 
									
										
										
										
											2011-03-14 13:30:46 -07:00
										 |  |  |     args = args.map{ |arg| arg.to_s.gsub " ", "\\ " } * " " | 
					
						
							| 
									
										
										
										
											2011-09-19 23:29:07 +01:00
										 |  |  |     raise ErrorDuringExecution, "Failure while executing: #{cmd} #{args}" | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # prints no output | 
					
						
							|  |  |  | def quiet_system cmd, *args | 
					
						
							|  |  |  |   Homebrew.system(cmd, *args) do | 
					
						
							| 
									
										
										
										
											2012-07-06 12:56:18 -08:00
										 |  |  |     # Redirect output streams to `/dev/null` instead of closing as some programs | 
					
						
							|  |  |  |     # will fail to execute if they can't write to an open stream. | 
					
						
							|  |  |  |     $stdout.reopen('/dev/null') | 
					
						
							|  |  |  |     $stderr.reopen('/dev/null') | 
					
						
							| 
									
										
										
										
											2009-11-09 17:44:29 +00:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2009-08-11 12:20:55 -07:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-04 15:28:18 +01:00
										 |  |  | def curl *args | 
					
						
							| 
									
										
										
										
											2011-09-14 12:18:35 -07:00
										 |  |  |   curl = Pathname.new '/usr/bin/curl' | 
					
						
							| 
									
										
										
										
											2011-09-19 23:29:07 +01:00
										 |  |  |   raise "#{curl} is not executable" unless curl.exist? and curl.executable? | 
					
						
							| 
									
										
										
										
											2011-09-14 12:18:35 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-18 16:03:44 -05:00
										 |  |  |   flags = HOMEBREW_CURL_ARGS | 
					
						
							|  |  |  |   flags = flags.delete("#") if ARGV.verbose? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   args = [flags, HOMEBREW_USER_AGENT, *args] | 
					
						
							| 
									
										
										
										
											2013-12-14 18:13:11 +00:00
										 |  |  |   # See https://github.com/Homebrew/homebrew/issues/6103 | 
					
						
							| 
									
										
										
										
											2013-10-22 20:47:37 -05:00
										 |  |  |   args << "--insecure" if MacOS.version < "10.6" | 
					
						
							| 
									
										
										
										
											2011-12-07 19:09:00 -06:00
										 |  |  |   args << "--verbose" if ENV['HOMEBREW_CURL_VERBOSE'] | 
					
						
							| 
									
										
										
										
											2012-02-10 17:47:39 -06:00
										 |  |  |   args << "--silent" unless $stdout.tty? | 
					
						
							| 
									
										
										
										
											2011-08-26 13:27:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-19 23:29:07 +01:00
										 |  |  |   safe_system curl, *args | 
					
						
							| 
									
										
										
										
											2009-08-11 12:20:55 -07:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2009-09-04 15:22:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-01 00:49:05 +00:00
										 |  |  | def puts_columns items, star_items=[] | 
					
						
							| 
									
										
										
										
											2009-12-18 16:28:30 -08:00
										 |  |  |   return if items.empty? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-01 00:49:05 +00:00
										 |  |  |   if star_items && star_items.any? | 
					
						
							|  |  |  |     items = items.map{|item| star_items.include?(item) ? "#{item}*" : item} | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-22 20:43:06 +02:00
										 |  |  |   if $stdout.tty? | 
					
						
							| 
									
										
										
										
											2009-11-14 13:43:07 +13:00
										 |  |  |     # determine the best width to display for different console sizes | 
					
						
							| 
									
										
										
										
											2010-01-16 13:12:38 +00:00
										 |  |  |     console_width = `/bin/stty size`.chomp.split(" ").last.to_i | 
					
						
							|  |  |  |     console_width = 80 if console_width <= 0
 | 
					
						
							| 
									
										
										
										
											2009-11-14 13:43:07 +13:00
										 |  |  |     longest = items.sort_by { |item| item.length }.last | 
					
						
							|  |  |  |     optimal_col_width = (console_width.to_f / (longest.length + 2).to_f).floor | 
					
						
							|  |  |  |     cols = optimal_col_width > 1 ? optimal_col_width : 1
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-06 03:11:30 +02:00
										 |  |  |     IO.popen("/usr/bin/pr -#{cols} -t -w#{console_width}", "w"){|io| io.puts(items) } | 
					
						
							| 
									
										
										
										
											2009-09-22 20:43:06 +02:00
										 |  |  |   else | 
					
						
							| 
									
										
										
										
											2010-10-25 21:11:45 -07:00
										 |  |  |     puts items | 
					
						
							| 
									
										
										
										
											2009-09-22 20:43:06 +02:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2009-09-04 15:22:25 -07:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2009-09-05 14:03:41 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-09 20:39:17 -05:00
										 |  |  | def which cmd, path=ENV['PATH'] | 
					
						
							| 
									
										
										
										
											2014-03-16 11:52:11 -07:00
										 |  |  |   path.split(File::PATH_SEPARATOR).find do |p| | 
					
						
							| 
									
										
										
										
											2014-03-13 17:20:36 -04:00
										 |  |  |     pcmd = File.join(p, cmd) | 
					
						
							| 
									
										
										
										
											2014-03-16 16:05:05 -07:00
										 |  |  |     return Pathname.new(pcmd) if File.executable?(pcmd) && !File.directory?(pcmd) | 
					
						
							| 
									
										
										
										
											2014-03-16 11:52:11 -07:00
										 |  |  |   end | 
					
						
							|  |  |  |   return nil | 
					
						
							| 
									
										
										
										
											2012-03-03 15:50:24 -08:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-16 14:27:58 -08:00
										 |  |  | def which_editor | 
					
						
							| 
									
										
										
										
											2013-07-09 20:12:53 -05:00
										 |  |  |   editor = ENV.values_at('HOMEBREW_EDITOR', 'VISUAL', 'EDITOR').compact.first | 
					
						
							| 
									
										
										
										
											2011-12-16 14:27:58 -08:00
										 |  |  |   # If an editor wasn't set, try to pick a sane default | 
					
						
							|  |  |  |   return editor unless editor.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Find Textmate | 
					
						
							| 
									
										
										
										
											2012-05-07 20:32:04 -05:00
										 |  |  |   return 'mate' if which "mate" | 
					
						
							| 
									
										
										
										
											2013-11-28 11:21:54 -08:00
										 |  |  |   # Find BBEdit / TextWrangler | 
					
						
							| 
									
										
										
										
											2012-05-07 20:32:04 -05:00
										 |  |  |   return 'edit' if which "edit" | 
					
						
							| 
									
										
										
										
											2011-12-16 14:27:58 -08:00
										 |  |  |   # Default to vim | 
					
						
							|  |  |  |   return '/usr/bin/vim' | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-05 14:03:41 -04:00
										 |  |  | def exec_editor *args | 
					
						
							| 
									
										
										
										
											2010-11-08 13:06:45 +00:00
										 |  |  |   return if args.to_s.empty? | 
					
						
							| 
									
										
										
										
											2012-12-27 23:34:29 -06:00
										 |  |  |   safe_exec(which_editor, *args) | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def exec_browser *args | 
					
						
							|  |  |  |   browser = ENV['HOMEBREW_BROWSER'] || ENV['BROWSER'] || "open" | 
					
						
							|  |  |  |   safe_exec(browser, *args) | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2010-11-08 13:06:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-27 23:34:29 -06:00
										 |  |  | def safe_exec cmd, *args | 
					
						
							|  |  |  |   # This buys us proper argument quoting and evaluation | 
					
						
							|  |  |  |   # of environment variables in the cmd parameter. | 
					
						
							|  |  |  |   exec "/bin/sh", "-i", "-c", cmd + ' "$@"', "--", *args | 
					
						
							| 
									
										
										
										
											2009-09-05 14:03:41 -04:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2009-09-08 15:31:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-09 13:00:33 +00:00
										 |  |  | # GZips the given paths, and returns the gzipped paths | 
					
						
							| 
									
										
										
										
											2010-09-12 22:55:52 +02:00
										 |  |  | def gzip *paths | 
					
						
							|  |  |  |   paths.collect do |path| | 
					
						
							| 
									
										
										
										
											2013-08-24 10:02:40 -04:00
										 |  |  |     with_system_path { safe_system 'gzip', path } | 
					
						
							| 
									
										
										
										
											2010-11-09 13:00:33 +00:00
										 |  |  |     Pathname.new("#{path}.gz") | 
					
						
							| 
									
										
										
										
											2010-09-12 22:55:52 +02:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-01-29 10:15:33 -08:00
										 |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-10 10:14:20 -07:00
										 |  |  | # Returns array of architectures that the given command or library is built for. | 
					
						
							| 
									
										
										
										
											2010-01-13 11:14:58 +00:00
										 |  |  | def archs_for_command cmd | 
					
						
							| 
									
										
										
										
											2012-05-28 20:39:05 -05:00
										 |  |  |   cmd = which(cmd) unless Pathname.new(cmd).absolute? | 
					
						
							|  |  |  |   Pathname.new(cmd).archs | 
					
						
							| 
									
										
										
										
											2009-09-08 15:31:28 -07:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2009-10-15 12:36:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-11 20:59:59 -04:00
										 |  |  | def ignore_interrupts(opt = nil) | 
					
						
							|  |  |  |   std_trap = trap("INT") do | 
					
						
							| 
									
										
										
										
											2012-09-27 16:21:39 -05:00
										 |  |  |     puts "One sec, just cleaning up" unless opt == :quietly | 
					
						
							| 
									
										
										
										
											2012-09-11 20:59:59 -04:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2009-11-06 17:09:14 +00:00
										 |  |  |   yield | 
					
						
							|  |  |  | ensure | 
					
						
							|  |  |  |   trap("INT", std_trap) | 
					
						
							|  |  |  | end | 
					
						
							| 
									
										
										
										
											2009-11-09 18:24:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def nostdout | 
					
						
							|  |  |  |   if ARGV.verbose? | 
					
						
							|  |  |  |     yield | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     begin | 
					
						
							|  |  |  |       require 'stringio' | 
					
						
							|  |  |  |       real_stdout = $stdout | 
					
						
							|  |  |  |       $stdout = StringIO.new | 
					
						
							|  |  |  |       yield | 
					
						
							|  |  |  |     ensure | 
					
						
							|  |  |  |       $stdout = real_stdout | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-01-13 09:00:51 +00:00
										 |  |  | end | 
					
						
							| 
									
										
										
										
											2010-04-07 21:01:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-15 20:11:17 -07:00
										 |  |  | def paths | 
					
						
							|  |  |  |   @paths ||= ENV['PATH'].split(File::PATH_SEPARATOR).collect do |p| | 
					
						
							|  |  |  |     begin | 
					
						
							|  |  |  |       File.expand_path(p).chomp('/') | 
					
						
							|  |  |  |     rescue ArgumentError | 
					
						
							|  |  |  |       onoe "The following PATH component is invalid: #{p}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end.uniq.compact | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  | module GitHub extend self | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  |   ISSUES_URI = URI.parse("https://api.github.com/search/issues") | 
					
						
							| 
									
										
										
										
											2013-06-22 22:46:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |   Error = Class.new(RuntimeError) | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  |   HTTPNotFoundError = Class.new(Error) | 
					
						
							| 
									
										
										
										
											2013-07-01 16:58:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |   class RateLimitExceededError < Error | 
					
						
							|  |  |  |     def initialize(reset, error) | 
					
						
							|  |  |  |       super <<-EOS.undent
 | 
					
						
							|  |  |  |         GitHub #{error} | 
					
						
							|  |  |  |         Try again in #{pretty_ratelimit_reset(reset)}, or create an API token: | 
					
						
							|  |  |  |           https://github.com/settings/applications | 
					
						
							|  |  |  |         and then set HOMEBREW_GITHUB_API_TOKEN. | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def pretty_ratelimit_reset(reset) | 
					
						
							|  |  |  |       if (seconds = Time.at(reset) - Time.now) > 180
 | 
					
						
							|  |  |  |         "%d minutes %d seconds" % [seconds / 60, seconds % 60] | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         "#{seconds} seconds" | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |   class AuthenticationFailedError < Error | 
					
						
							|  |  |  |     def initialize(error) | 
					
						
							|  |  |  |       super <<-EOS.undent
 | 
					
						
							|  |  |  |         GitHub #{error} | 
					
						
							|  |  |  |         HOMEBREW_GITHUB_API_TOKEN may be invalid or expired, check: | 
					
						
							|  |  |  |           https://github.com/settings/applications | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-07 14:07:25 -04:00
										 |  |  |   def open url, headers={}, &block | 
					
						
							| 
									
										
										
										
											2013-10-22 16:18:31 -07:00
										 |  |  |     # This is a no-op if the user is opting out of using the GitHub API. | 
					
						
							|  |  |  |     return if ENV['HOMEBREW_NO_GITHUB_API'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-02 18:18:34 -05:00
										 |  |  |     require 'net/https' # for exception classes below | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  |     default_headers = { | 
					
						
							|  |  |  |       "User-Agent" => HOMEBREW_USER_AGENT, | 
					
						
							|  |  |  |       "Accept"     => "application/vnd.github.v3+json", | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-22 19:58:11 -05:00
										 |  |  |     default_headers['Authorization'] = "token #{HOMEBREW_GITHUB_API_TOKEN}" if HOMEBREW_GITHUB_API_TOKEN | 
					
						
							| 
									
										
										
										
											2014-02-08 16:04:53 -05:00
										 |  |  |     Kernel.open(url, default_headers.merge(headers)) do |f| | 
					
						
							|  |  |  |       yield Utils::JSON.load(f.read) | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-05-22 19:58:11 -05:00
										 |  |  |   rescue OpenURI::HTTPError => e | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |     handle_api_error(e) | 
					
						
							|  |  |  |   rescue SocketError, OpenSSL::SSL::SSLError => e | 
					
						
							|  |  |  |     raise Error, "Failed to connect to: #{url}\n#{e.message}", e.backtrace | 
					
						
							|  |  |  |   rescue Utils::JSON::Error => e | 
					
						
							|  |  |  |     raise Error, "Failed to parse JSON response\n#{e.message}", e.backtrace | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def handle_api_error(e) | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |     if e.io.meta["x-ratelimit-remaining"].to_i <= 0
 | 
					
						
							|  |  |  |       reset = e.io.meta.fetch("x-ratelimit-reset").to_i | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |       error = Utils::JSON.load(e.io.read)["message"] | 
					
						
							|  |  |  |       raise RateLimitExceededError.new(reset, error) | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case e.io.status.first | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |     when "401", "403" | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |       raise AuthenticationFailedError.new(e.message) | 
					
						
							| 
									
										
										
										
											2014-02-16 22:24:33 -05:00
										 |  |  |     when "404" | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  |       raise HTTPNotFoundError, e.message, e.backtrace | 
					
						
							| 
									
										
										
										
											2013-05-22 19:58:11 -05:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-02-08 16:04:53 -05:00
										 |  |  |       raise Error, e.message, e.backtrace | 
					
						
							| 
									
										
										
										
											2013-05-14 10:42:46 -04:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2013-05-07 14:07:25 -04:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2013-06-22 22:46:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 17:39:53 -05:00
										 |  |  |   def issues_matching(query, qualifiers={}) | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  |     uri = ISSUES_URI.dup | 
					
						
							| 
									
										
										
										
											2014-02-13 17:39:53 -05:00
										 |  |  |     uri.query = build_query_string(query, qualifiers) | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  |     open(uri) { |json| json["items"] } | 
					
						
							| 
									
										
										
										
											2013-06-22 22:46:39 -05:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 17:39:53 -05:00
										 |  |  |   def build_query_string(query, qualifiers) | 
					
						
							|  |  |  |     s = "q=#{uri_escape(query)}+" | 
					
						
							|  |  |  |     s << build_search_qualifier_string(qualifiers) | 
					
						
							|  |  |  |     s << "&per_page=100" | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def build_search_qualifier_string(qualifiers) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       :repo => "Homebrew/homebrew", | 
					
						
							|  |  |  |       :in => "title", | 
					
						
							|  |  |  |     }.update(qualifiers).map { |qualifier, value| | 
					
						
							|  |  |  |       "#{qualifier}:#{value}" | 
					
						
							|  |  |  |     }.join("+") | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-10 17:32:15 -06:00
										 |  |  |   def uri_escape(query) | 
					
						
							|  |  |  |     if URI.respond_to?(:encode_www_form_component) | 
					
						
							|  |  |  |       URI.encode_www_form_component(query) | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       require "erb" | 
					
						
							|  |  |  |       ERB::Util.url_encode(query) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  |   def issues_for_formula name | 
					
						
							| 
									
										
										
										
											2014-02-13 17:39:53 -05:00
										 |  |  |     issues_matching(name, :state => "open") | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2012-01-11 20:49:08 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 23:14:30 -05:00
										 |  |  |   def print_pull_requests_matching(query) | 
					
						
							| 
									
										
										
										
											2014-03-13 09:09:18 +00:00
										 |  |  |     return [] if ENV['HOMEBREW_NO_GITHUB_API'] | 
					
						
							| 
									
										
										
										
											2014-01-20 17:46:33 -08:00
										 |  |  |     puts "Searching pull requests..." | 
					
						
							| 
									
										
										
										
											2013-10-22 16:18:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 17:39:53 -05:00
										 |  |  |     open_or_closed_prs = issues_matching(query, :type => "pr") | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     open_prs = open_or_closed_prs.select {|i| i["state"] == "open" } | 
					
						
							| 
									
										
										
										
											2014-01-20 17:46:33 -08:00
										 |  |  |     if open_prs.any? | 
					
						
							|  |  |  |       puts "Open pull requests:" | 
					
						
							|  |  |  |       prs = open_prs | 
					
						
							|  |  |  |     elsif open_or_closed_prs.any? | 
					
						
							|  |  |  |       puts "Closed pull requests:" | 
					
						
							|  |  |  |       prs = open_or_closed_prs | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 23:14:30 -05:00
										 |  |  |     prs.each { |i| puts "#{i["title"]} (#{i["html_url"]})" } | 
					
						
							| 
									
										
										
										
											2012-01-11 20:49:08 -06:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2014-02-08 20:41:11 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   def private_repo?(user, repo) | 
					
						
							|  |  |  |     uri = URI.parse("https://api.github.com/repos/#{user}/#{repo}") | 
					
						
							|  |  |  |     open(uri) { |json| json["private"] } | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  | end |