| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | require "yaml" | 
					
						
							|  |  |  |  | require "open3" | 
					
						
							|  |  |  |  | require "stringio" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | require "hbc/utils/file" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | UPDATE_CMD = "brew uninstall --force brew-cask; brew untap phinze/cask; brew untap caskroom/cask; brew update; brew cleanup; brew cask cleanup".freeze | 
					
						
							|  |  |  |  | ISSUES_URL = "https://github.com/caskroom/homebrew-cask#reporting-bugs".freeze | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | # monkeypatch Object - not a great idea | 
					
						
							|  |  |  |  | class Object | 
					
						
							|  |  |  |  |   def utf8_inspect | 
					
						
							|  |  |  |  |     return inspect unless defined?(Encoding) | 
					
						
							|  |  |  |  |     return map(&:utf8_inspect) if respond_to?(:map) | 
					
						
							|  |  |  |  |     inspect.force_encoding("UTF-8").sub(%r{\A"(.*)"\Z}, '\1') | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class Buffer < StringIO | 
					
						
							|  |  |  |  |   def initialize(tty = false) | 
					
						
							|  |  |  |  |     super() | 
					
						
							|  |  |  |  |     @tty = tty | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   def tty? | 
					
						
							|  |  |  |  |     @tty | 
					
						
							|  |  |  |  |   end | 
					
						
							|  |  |  |  | end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | # global methods | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | def odebug(title, *sput) | 
					
						
							| 
									
										
										
										
											2016-09-20 15:11:33 +02:00
										 |  |  |  |   return unless Hbc.respond_to?(:debug) | 
					
						
							|  |  |  |  |   return unless Hbc.debug | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   width = Tty.width * 4 - 6
 | 
					
						
							|  |  |  |  |   if $stdout.tty? && title.to_s.length > width | 
					
						
							|  |  |  |  |     title = title.to_s[0, width - 3] + "..." | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-09-20 15:11:33 +02:00
										 |  |  |  |   puts "#{Tty.magenta}==>#{Tty.reset} #{Tty.white}#{title}#{Tty.reset}" | 
					
						
							|  |  |  |  |   puts sput unless sput.empty? | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  | module Hbc | 
					
						
							|  |  |  |  |   module Utils | 
					
						
							|  |  |  |  |     def self.which(cmd, path = ENV["PATH"]) | 
					
						
							|  |  |  |  |       unless File.basename(cmd) == cmd.to_s | 
					
						
							|  |  |  |  |         # cmd contains a directory element | 
					
						
							|  |  |  |  |         cmd_pn = Pathname(cmd) | 
					
						
							|  |  |  |  |         return nil unless cmd_pn.absolute? | 
					
						
							|  |  |  |  |         return resolve_executable(cmd_pn) | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       path.split(File::PATH_SEPARATOR).each do |elt| | 
					
						
							|  |  |  |  |         fq_cmd = Pathname(elt).expand_path.join(cmd) | 
					
						
							|  |  |  |  |         resolved = resolve_executable fq_cmd | 
					
						
							|  |  |  |  |         return resolved if resolved | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       nil | 
					
						
							|  |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def self.resolve_executable(cmd) | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |       cmd_pn = Pathname(cmd) | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |       return nil unless cmd_pn.exist? | 
					
						
							|  |  |  |  |       return nil unless cmd_pn.executable? | 
					
						
							|  |  |  |  |       begin | 
					
						
							|  |  |  |  |         cmd_pn = Pathname(cmd_pn.realpath) | 
					
						
							|  |  |  |  |       rescue RuntimeError | 
					
						
							|  |  |  |  |         return nil | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       return nil unless cmd_pn.file? | 
					
						
							|  |  |  |  |       cmd_pn | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     def self.gain_permissions_remove(path, command: SystemCommand) | 
					
						
							|  |  |  |  |       if path.respond_to?(:rmtree) && path.exist? | 
					
						
							|  |  |  |  |         gain_permissions(path, ["-R"], command, &:rmtree) | 
					
						
							|  |  |  |  |       elsif File.symlink?(path) | 
					
						
							|  |  |  |  |         gain_permissions(path, ["-h"], command, &FileUtils.method(:rm_f)) | 
					
						
							|  |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.gain_permissions(path, command_args, command) | 
					
						
							|  |  |  |  |       tried_permissions = false | 
					
						
							|  |  |  |  |       tried_ownership = false | 
					
						
							|  |  |  |  |       begin | 
					
						
							|  |  |  |  |         yield path | 
					
						
							|  |  |  |  |       rescue StandardError | 
					
						
							|  |  |  |  |         # in case of permissions problems | 
					
						
							|  |  |  |  |         unless tried_permissions | 
					
						
							|  |  |  |  |           # TODO: Better handling for the case where path is a symlink. | 
					
						
							|  |  |  |  |           #       The -h and -R flags cannot be combined, and behavior is | 
					
						
							|  |  |  |  |           #       dependent on whether the file argument has a trailing | 
					
						
							|  |  |  |  |           #       slash.  This should do the right thing, but is fragile. | 
					
						
							|  |  |  |  |           command.run("/usr/bin/chflags", | 
					
						
							|  |  |  |  |                       must_succeed: false, | 
					
						
							|  |  |  |  |                       args:         command_args + ["--", "000", path]) | 
					
						
							|  |  |  |  |           command.run("/bin/chmod", | 
					
						
							|  |  |  |  |                       must_succeed: false, | 
					
						
							|  |  |  |  |                       args:         command_args + ["--", "u+rwx", path]) | 
					
						
							|  |  |  |  |           command.run("/bin/chmod", | 
					
						
							|  |  |  |  |                       must_succeed: false, | 
					
						
							|  |  |  |  |                       args:         command_args + ["-N", path]) | 
					
						
							|  |  |  |  |           tried_permissions = true | 
					
						
							|  |  |  |  |           retry # rmtree | 
					
						
							|  |  |  |  |         end | 
					
						
							|  |  |  |  |         unless tried_ownership | 
					
						
							|  |  |  |  |           # in case of ownership problems | 
					
						
							|  |  |  |  |           # TODO: Further examine files to see if ownership is the problem | 
					
						
							|  |  |  |  |           #       before using sudo+chown | 
					
						
							|  |  |  |  |           ohai "Using sudo to gain ownership of path '#{path}'" | 
					
						
							|  |  |  |  |           command.run("/usr/sbin/chown", | 
					
						
							|  |  |  |  |                       args: command_args + ["--", current_user, path], | 
					
						
							|  |  |  |  |                       sudo: true) | 
					
						
							|  |  |  |  |           tried_ownership = true | 
					
						
							|  |  |  |  |           # retry chflags/chmod after chown | 
					
						
							|  |  |  |  |           tried_permissions = false | 
					
						
							|  |  |  |  |           retry # rmtree | 
					
						
							|  |  |  |  |         end | 
					
						
							|  |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.current_user | 
					
						
							|  |  |  |  |       Etc.getpwuid(Process.euid).name | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     # paths that "look" descendant (textually) will still | 
					
						
							|  |  |  |  |     # return false unless both the given paths exist | 
					
						
							|  |  |  |  |     def self.file_is_descendant(file, dir) | 
					
						
							|  |  |  |  |       file = Pathname.new(file) | 
					
						
							|  |  |  |  |       dir  = Pathname.new(dir) | 
					
						
							|  |  |  |  |       return false unless file.exist? && dir.exist? | 
					
						
							|  |  |  |  |       unless dir.directory? | 
					
						
							|  |  |  |  |         onoe "Argument must be a directory: '#{dir}'" | 
					
						
							|  |  |  |  |         return false | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |       unless file.absolute? && dir.absolute? | 
					
						
							|  |  |  |  |         onoe "Both arguments must be absolute: '#{file}', '#{dir}'" | 
					
						
							|  |  |  |  |         return false | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |       while file.parent != file | 
					
						
							|  |  |  |  |         return true if File.identical?(file, dir) | 
					
						
							|  |  |  |  |         file = file.parent | 
					
						
							|  |  |  |  |       end | 
					
						
							|  |  |  |  |       false | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.path_occupied?(path) | 
					
						
							|  |  |  |  |       File.exist?(path) || File.symlink?(path) | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.error_message_with_suggestions | 
					
						
							|  |  |  |  |       <<-EOS.undent
 | 
					
						
							|  |  |  |  |         Most likely, this means you have an outdated version of Homebrew-Cask. Please run: | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |             #{Tty.green}#{UPDATE_CMD} | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |         #{Tty.reset}If this doesn’t fix the problem, please report this bug: | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |             #{Tty.em}#{ISSUES_URL}#{Tty.reset} | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |       EOS | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.method_missing_message(method, token, section = nil) | 
					
						
							|  |  |  |  |       poo = [] | 
					
						
							|  |  |  |  |       poo << "Unexpected method '#{method}' called" | 
					
						
							|  |  |  |  |       poo << "during #{section}" if section | 
					
						
							|  |  |  |  |       poo << "on Cask #{token}." | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |       opoo(poo.join(" ") + "\n" + error_message_with_suggestions) | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.nowstamp_metadata_path(container_path) | 
					
						
							|  |  |  |  |       @timenow ||= Time.now.gmtime | 
					
						
							|  |  |  |  |       if container_path.respond_to?(:join) | 
					
						
							|  |  |  |  |         precision = 3
 | 
					
						
							|  |  |  |  |         timestamp = @timenow.strftime("%Y%m%d%H%M%S") | 
					
						
							|  |  |  |  |         fraction = format("%.#{precision}f", @timenow.to_f - @timenow.to_i)[1..-1] | 
					
						
							|  |  |  |  |         timestamp.concat(fraction) | 
					
						
							|  |  |  |  |         container_path.join(timestamp) | 
					
						
							|  |  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.size_in_bytes(files) | 
					
						
							|  |  |  |  |       Array(files).reduce(0) { |a, e| a + (File.size?(e) || 0) } | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.capture_stderr | 
					
						
							|  |  |  |  |       previous_stderr = $stderr | 
					
						
							|  |  |  |  |       $stderr = StringIO.new | 
					
						
							|  |  |  |  |       yield | 
					
						
							|  |  |  |  |       $stderr.string | 
					
						
							|  |  |  |  |     ensure | 
					
						
							|  |  |  |  |       $stderr = previous_stderr | 
					
						
							|  |  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |   end | 
					
						
							|  |  |  |  | end |