| 
									
										
										
										
											2025-02-01 23:54:35 +00:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2023-04-04 19:55:15 -07:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "rubocops/extend/formula_cop" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module RuboCop | 
					
						
							|  |  |  |   module Cop | 
					
						
							|  |  |  |     module FormulaAudit | 
					
						
							|  |  |  |       # This cop audits the service block. | 
					
						
							|  |  |  |       class Service < FormulaCop | 
					
						
							|  |  |  |         extend AutoCorrector | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-01 23:54:35 +00:00
										 |  |  |         CELLAR_PATH_AUDIT_CORRECTIONS = T.let( | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             bin:      :opt_bin, | 
					
						
							|  |  |  |             libexec:  :opt_libexec, | 
					
						
							|  |  |  |             pkgshare: :opt_pkgshare, | 
					
						
							|  |  |  |             prefix:   :opt_prefix, | 
					
						
							|  |  |  |             sbin:     :opt_sbin, | 
					
						
							|  |  |  |             share:    :opt_share, | 
					
						
							|  |  |  |           }.freeze, | 
					
						
							|  |  |  |           T::Hash[Symbol, Symbol], | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-04-30 07:39:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |         # At least one of these methods must be defined in a service block. | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  |         REQUIRED_METHOD_CALLS = [:run, :name].freeze | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-07 15:18:29 -04:00
										 |  |  |         sig { override.params(formula_nodes: FormulaNodes).void } | 
					
						
							|  |  |  |         def audit_formula(formula_nodes) | 
					
						
							|  |  |  |           service_node = find_block(formula_nodes.body_node, :service) | 
					
						
							| 
									
										
										
										
											2023-04-04 19:55:15 -07:00
										 |  |  |           return if service_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |           method_calls = service_node.each_descendant(:send).group_by(&:method_name) | 
					
						
							|  |  |  |           method_calls.delete(:service) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           # NOTE: Solving the first problem here might solve the second one too | 
					
						
							| 
									
										
										
										
											2024-04-26 20:55:51 +02:00
										 |  |  |           #       so we don't show both of them at the same time. | 
					
						
							| 
									
										
										
										
											2024-01-18 14:11:43 +00:00
										 |  |  |           if !method_calls.keys.intersect?(REQUIRED_METHOD_CALLS) | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |             offending_node(service_node) | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  |             problem "Service blocks require `run` or `name` to be defined." | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |           elsif !method_calls.key?(:run) | 
					
						
							| 
									
										
										
										
											2024-03-19 08:46:47 +00:00
										 |  |  |             other_method_calls = method_calls.keys - [:name, :require_root] | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |             if other_method_calls.any? | 
					
						
							|  |  |  |               offending_node(service_node) | 
					
						
							| 
									
										
										
										
											2023-05-13 12:35:50 -07:00
										 |  |  |               problem "`run` must be defined to use methods other than `name` like #{other_method_calls}." | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-30 07:39:25 +08:00
										 |  |  |           # This check ensures that cellar paths like `bin` are not referenced | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |           # because their `opt_` variants are more portable and work with the API. | 
					
						
							| 
									
										
										
										
											2023-04-30 07:39:25 +08:00
										 |  |  |           CELLAR_PATH_AUDIT_CORRECTIONS.each do |path, opt_path| | 
					
						
							| 
									
										
										
										
											2023-05-07 12:51:46 -07:00
										 |  |  |             next unless method_calls.key?(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             method_calls.fetch(path).each do |node| | 
					
						
							| 
									
										
										
										
											2023-04-30 07:39:25 +08:00
										 |  |  |               offending_node(node) | 
					
						
							|  |  |  |               problem "Use `#{opt_path}` instead of `#{path}` in service blocks." do |corrector| | 
					
						
							|  |  |  |                 corrector.replace(node.source_range, opt_path) | 
					
						
							|  |  |  |               end | 
					
						
							| 
									
										
										
										
											2023-04-04 19:55:15 -07:00
										 |  |  |             end | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |