| 
									
										
										
										
											2020-10-10 14:16:11 +02:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  | require "tab" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Utils | 
					
						
							| 
									
										
										
										
											2020-08-19 07:50:49 +02:00
										 |  |  |   # Helper functions for bottles. | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   # @api private | 
					
						
							|  |  |  |   module Bottles | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |     class << self | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       extend T::Sig | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       def tag | 
					
						
							| 
									
										
										
										
											2018-03-07 16:14:55 +00:00
										 |  |  |         @tag ||= "#{ENV["HOMEBREW_PROCESSOR"]}_#{ENV["HOMEBREW_SYSTEM"]}".downcase.to_sym | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def built_as?(f) | 
					
						
							| 
									
										
										
										
											2019-12-03 11:42:09 +00:00
										 |  |  |         return false unless f.latest_version_installed? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 12:10:44 -07:00
										 |  |  |         tab = Tab.for_keg(f.latest_installed_prefix) | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |         tab.built_as_bottle | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def file_outdated?(f, file) | 
					
						
							|  |  |  |         filename = file.basename.to_s | 
					
						
							|  |  |  |         return unless f.bottle && filename.match(Pathname::BOTTLE_EXTNAME_RX) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bottle_ext = filename[native_regex, 1] | 
					
						
							|  |  |  |         bottle_url_ext = f.bottle.url[native_regex, 1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bottle_ext && bottle_url_ext && bottle_ext != bottle_url_ext | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { returns(Regexp) } | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       def native_regex | 
					
						
							| 
									
										
										
										
											2016-05-08 20:35:52 +02:00
										 |  |  |         /(\.#{Regexp.escape(tag.to_s)}\.bottle\.(\d+\.)?tar\.gz)$/o | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def receipt_path(bottle_file) | 
					
						
							| 
									
										
										
										
											2017-09-25 11:10:36 -07:00
										 |  |  |         path = Utils.popen_read("tar", "-tzf", bottle_file).lines.map(&:chomp).find do |line| | 
					
						
							| 
									
										
										
										
											2016-07-29 15:54:56 -06:00
										 |  |  |           line =~ %r{.+/.+/INSTALL_RECEIPT.json} | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2017-09-25 11:10:36 -07:00
										 |  |  |         raise "This bottle does not contain the file INSTALL_RECEIPT.json: #{bottle_file}" unless path | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 11:10:36 -07:00
										 |  |  |         path | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def resolve_formula_names(bottle_file) | 
					
						
							|  |  |  |         receipt_file_path = receipt_path bottle_file | 
					
						
							|  |  |  |         receipt_file = Utils.popen_read("tar", "-xOzf", bottle_file, receipt_file_path) | 
					
						
							|  |  |  |         name = receipt_file_path.split("/").first | 
					
						
							|  |  |  |         tap = Tab.from_file_content(receipt_file, "#{bottle_file}/#{receipt_file_path}").tap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 21:15:06 +00:00
										 |  |  |         full_name = if tap.nil? || tap.core_tap? | 
					
						
							|  |  |  |           name | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2020-03-13 21:15:06 +00:00
										 |  |  |           "#{tap}/#{name}" | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         [name, full_name] | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def resolve_version(bottle_file) | 
					
						
							| 
									
										
										
										
											2018-09-17 19:44:12 +02:00
										 |  |  |         PkgVersion.parse receipt_path(bottle_file).split("/").second | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2017-09-25 22:46:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       def formula_contents(bottle_file, | 
					
						
							| 
									
										
										
										
											2019-04-30 08:44:35 +01:00
										 |  |  |                            name: resolve_formula_names(bottle_file)[0]) | 
					
						
							| 
									
										
										
										
											2017-09-25 22:46:51 -07:00
										 |  |  |         bottle_version = resolve_version bottle_file | 
					
						
							|  |  |  |         formula_path = "#{name}/#{bottle_version}/.brew/#{name}.rb" | 
					
						
							|  |  |  |         contents = Utils.popen_read "tar", "-xOzf", bottle_file, formula_path | 
					
						
							|  |  |  |         raise BottleFormulaUnavailableError.new(bottle_file, formula_path) unless $CHILD_STATUS.success? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 22:46:51 -07:00
										 |  |  |         contents | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-11-09 08:34:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       def add_bottle_stanza!(formula_contents, bottle_output) | 
					
						
							| 
									
										
										
										
											2020-12-11 12:26:45 +00:00
										 |  |  |         Homebrew.install_bundler_gems! | 
					
						
							| 
									
										
										
										
											2020-11-09 08:34:11 -08:00
										 |  |  |         require "rubocop-ast" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ruby_version = Version.new(HOMEBREW_REQUIRED_RUBY_VERSION).major_minor.to_f | 
					
						
							|  |  |  |         processed_source = RuboCop::AST::ProcessedSource.new(formula_contents, ruby_version) | 
					
						
							|  |  |  |         root_node = processed_source.ast | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         class_node = if root_node.class_type? | 
					
						
							|  |  |  |           root_node | 
					
						
							|  |  |  |         elsif root_node.begin_type? | 
					
						
							|  |  |  |           root_node.children.find do |n| | 
					
						
							|  |  |  |             n.class_type? && n.parent_class&.const_name == "Formula" | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         odie "Could not find formula class!" if class_node.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         body_node = class_node.body | 
					
						
							|  |  |  |         odie "Formula class is empty!" if body_node.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         node_before_bottle = if body_node.begin_type? | 
					
						
							|  |  |  |           body_node.children.compact.reduce do |previous_child, current_child| | 
					
						
							|  |  |  |             break previous_child unless component_before_bottle_block? current_child | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             current_child | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           body_node | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         node_before_bottle = node_before_bottle.last_argument if node_before_bottle.send_type? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expr_before_bottle = node_before_bottle.location.expression | 
					
						
							|  |  |  |         processed_source.comments.each do |comment| | 
					
						
							|  |  |  |           comment_expr = comment.location.expression | 
					
						
							|  |  |  |           distance = comment_expr.first_line - expr_before_bottle.first_line | 
					
						
							|  |  |  |           case distance | 
					
						
							|  |  |  |           when 0
 | 
					
						
							|  |  |  |             if comment_expr.last_line > expr_before_bottle.last_line || | 
					
						
							|  |  |  |                comment_expr.end_pos > expr_before_bottle.end_pos | 
					
						
							|  |  |  |               expr_before_bottle = comment_expr | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           when 1
 | 
					
						
							|  |  |  |             expr_before_bottle = comment_expr | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         tree_rewriter = Parser::Source::TreeRewriter.new(processed_source.buffer) | 
					
						
							|  |  |  |         tree_rewriter.insert_after(expr_before_bottle, "\n\n#{bottle_output.chomp}") | 
					
						
							|  |  |  |         formula_contents.replace(tree_rewriter.process) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def component_before_bottle_block?(node) | 
					
						
							|  |  |  |         require "rubocops/components_order" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         RuboCop::Cop::FormulaAudit::ComponentsOrder::COMPONENT_PRECEDENCE_LIST.each do |components| | 
					
						
							|  |  |  |           components.each do |component| | 
					
						
							|  |  |  |             return false if component[:name] == :bottle && component[:type] == :block_call | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             case component[:type] | 
					
						
							|  |  |  |             when :method_call | 
					
						
							|  |  |  |               return true if node.send_type? && node.method_name == component[:name] | 
					
						
							|  |  |  |             when :block_call | 
					
						
							|  |  |  |               return true if node.block_type? && node.method_name == component[:name] | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         false | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 07:50:49 +02:00
										 |  |  |     # Helper functions for bottles hosted on Bintray. | 
					
						
							|  |  |  |     module Bintray | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       def self.package(formula_name) | 
					
						
							| 
									
										
										
										
											2016-08-28 23:55:43 +01:00
										 |  |  |         package_name = formula_name.to_s.dup | 
					
						
							|  |  |  |         package_name.tr!("+", "x") | 
					
						
							|  |  |  |         package_name.sub!(/(.)@(\d)/, "\\1:\\2") # Handle foo@1.2 style formulae. | 
					
						
							|  |  |  |         package_name | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def self.repository(tap = nil) | 
					
						
							|  |  |  |         if tap.nil? || tap.core_tap? | 
					
						
							|  |  |  |           "bottles" | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           "bottles-#{tap.repo}" | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |     # Collector for bottle specifications. | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |     class Collector | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       extend T::Sig | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-19 11:54:42 +00:00
										 |  |  |       extend Forwardable | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def_delegators :@checksums, :keys, :[], :[]=, :key?, :each_key | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |       sig { void } | 
					
						
							| 
									
										
										
										
											2016-04-25 17:57:51 +01:00
										 |  |  |       def initialize | 
					
						
							|  |  |  |         @checksums = {} | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def fetch_checksum_for(tag) | 
					
						
							|  |  |  |         tag = find_matching_tag(tag) | 
					
						
							|  |  |  |         return self[tag], tag if tag | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       def find_matching_tag(tag) | 
					
						
							|  |  |  |         tag if key?(tag) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "extend/os/bottles" |