| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | require "yaml" | 
					
						
							|  |  |  |  | require "open3" | 
					
						
							|  |  |  |  | require "stringio" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | require "hbc/utils/file" | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-14 12:21:35 -05:00
										 |  |  |  | PREBUG_URL = "https://github.com/caskroom/homebrew-cask/blob/master/doc/reporting_bugs/pre_bug_report.md".freeze | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2016-10-14 20:03:34 +02:00
										 |  |  |  |     inspect.force_encoding("UTF-8").sub(/\A"(.*)"\Z/, '\1') | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |   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 | 
					
						
							| 
									
										
										
										
											2016-08-30 21:38:13 +02:00
										 |  |  |  |   puts Formatter.headline(title, color: :magenta) | 
					
						
							| 
									
										
										
										
											2016-09-20 15:11:33 +02:00
										 |  |  |  |   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.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
 | 
					
						
							| 
									
										
										
										
											2016-11-03 02:51:22 +00:00
										 |  |  |  |         Follow the instructions here: | 
					
						
							| 
									
										
										
										
											2016-10-14 12:21:35 -05:00
										 |  |  |  |           #{Formatter.url(PREBUG_URL)} | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-26 16:04:47 +02:00
										 |  |  |  |         If this doesn’t fix the problem, please report this bug: | 
					
						
							| 
									
										
										
										
											2016-08-30 21:38:13 +02:00
										 |  |  |  |           #{Formatter.url(ISSUES_URL)} | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2016-10-24 17:07:57 +02:00
										 |  |  |  |       return unless 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) | 
					
						
							| 
									
										
										
										
											2016-08-18 22:11:42 +03:00
										 |  |  |  |     end | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     def self.size_in_bytes(files) | 
					
						
							| 
									
										
										
										
											2016-11-13 23:36:04 +01:00
										 |  |  |  |       Array(files).reduce(0) { |acc, elem| acc + (File.size?(elem) || 0) } | 
					
						
							| 
									
										
										
										
											2016-09-24 13:52:43 +02:00
										 |  |  |  |     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 |