2025-02-01 23:54:35 +00:00
|
|
|
# typed: strict
|
2021-01-28 12:36:44 -08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2023-02-20 10:22:39 -08:00
|
|
|
require "rubocops/extend/formula_cop"
|
2021-01-28 12:36:44 -08:00
|
|
|
|
|
|
|
module RuboCop
|
|
|
|
module Cop
|
|
|
|
module FormulaAudit
|
|
|
|
# This cop audits the `bottle` block in formulae.
|
2023-02-20 18:10:59 -08:00
|
|
|
class BottleFormat < FormulaCop
|
2021-01-28 12:36:44 -08:00
|
|
|
extend AutoCorrector
|
|
|
|
|
2024-07-07 15:18:29 -04:00
|
|
|
sig { override.params(formula_nodes: FormulaNodes).void }
|
|
|
|
def audit_formula(formula_nodes)
|
|
|
|
bottle_node = find_block(formula_nodes.body_node, :bottle)
|
2021-01-28 12:36:44 -08:00
|
|
|
return if bottle_node.nil?
|
|
|
|
|
|
|
|
sha256_nodes = find_method_calls_by_name(bottle_node.body, :sha256)
|
|
|
|
cellar_node = find_node_method_by_name(bottle_node.body, :cellar)
|
|
|
|
cellar_source = cellar_node&.first_argument&.source
|
|
|
|
|
|
|
|
if sha256_nodes.present? && cellar_node.present?
|
|
|
|
offending_node(cellar_node)
|
|
|
|
problem "`cellar` should be a parameter to `sha256`" do |corrector|
|
|
|
|
corrector.remove(range_by_whole_lines(cellar_node.source_range, include_final_newline: true))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
sha256_nodes.each do |sha256_node|
|
|
|
|
sha256_hash = sha256_node.last_argument
|
|
|
|
sha256_pairs = sha256_hash.pairs
|
|
|
|
next if sha256_pairs.count != 1
|
|
|
|
|
|
|
|
sha256_pair = sha256_pairs.first
|
|
|
|
sha256_key = sha256_pair.key
|
|
|
|
sha256_value = sha256_pair.value
|
|
|
|
next unless sha256_value.sym_type?
|
|
|
|
|
|
|
|
tag = sha256_value.value
|
|
|
|
digest_source = sha256_key.source
|
|
|
|
sha256_line = if cellar_source.present?
|
|
|
|
"sha256 cellar: #{cellar_source}, #{tag}: #{digest_source}"
|
|
|
|
else
|
|
|
|
"sha256 #{tag}: #{digest_source}"
|
|
|
|
end
|
|
|
|
|
|
|
|
offending_node(sha256_node)
|
|
|
|
problem "`sha256` should use new syntax" do |corrector|
|
|
|
|
corrector.replace(sha256_node.source_range, sha256_line)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# This cop audits the indentation of the bottle tags in the `bottle` block in formulae.
|
2023-02-20 18:10:59 -08:00
|
|
|
class BottleTagIndentation < FormulaCop
|
2021-01-28 12:36:44 -08:00
|
|
|
extend AutoCorrector
|
|
|
|
|
2024-07-07 15:18:29 -04:00
|
|
|
sig { override.params(formula_nodes: FormulaNodes).void }
|
|
|
|
def audit_formula(formula_nodes)
|
|
|
|
bottle_node = find_block(formula_nodes.body_node, :bottle)
|
2021-01-28 12:36:44 -08:00
|
|
|
return if bottle_node.nil?
|
|
|
|
|
|
|
|
sha256_nodes = find_method_calls_by_name(bottle_node.body, :sha256)
|
|
|
|
|
|
|
|
max_tag_column = 0
|
|
|
|
sha256_nodes.each do |sha256_node|
|
|
|
|
sha256_hash = sha256_node.last_argument
|
|
|
|
tag_column = T.let(sha256_hash.pairs.last.source_range.column, Integer)
|
|
|
|
|
|
|
|
max_tag_column = tag_column if tag_column > max_tag_column
|
|
|
|
end
|
|
|
|
# This must be in a separate loop to make sure max_tag_column is truly the maximum
|
|
|
|
sha256_nodes.each do |sha256_node| # rubocop:disable Style/CombinableLoops
|
|
|
|
sha256_hash = sha256_node.last_argument
|
|
|
|
hash = sha256_hash.pairs.last
|
|
|
|
tag_column = hash.source_range.column
|
|
|
|
|
|
|
|
next if tag_column == max_tag_column
|
|
|
|
|
|
|
|
offending_node(hash)
|
|
|
|
problem "Align bottle tags" do |corrector|
|
2021-09-30 10:13:43 +01:00
|
|
|
new_line = (" " * (max_tag_column - tag_column)) + hash.source
|
2021-01-28 12:36:44 -08:00
|
|
|
corrector.replace(hash.source_range, new_line)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# This cop audits the indentation of the sha256 digests in the`bottle` block in formulae.
|
2023-02-20 18:10:59 -08:00
|
|
|
class BottleDigestIndentation < FormulaCop
|
2021-01-28 12:36:44 -08:00
|
|
|
extend AutoCorrector
|
|
|
|
|
2024-07-07 15:18:29 -04:00
|
|
|
sig { override.params(formula_nodes: FormulaNodes).void }
|
|
|
|
def audit_formula(formula_nodes)
|
|
|
|
bottle_node = find_block(formula_nodes.body_node, :bottle)
|
2021-01-28 12:36:44 -08:00
|
|
|
return if bottle_node.nil?
|
|
|
|
|
|
|
|
sha256_nodes = find_method_calls_by_name(bottle_node.body, :sha256)
|
|
|
|
|
|
|
|
max_digest_column = 0
|
|
|
|
sha256_nodes.each do |sha256_node|
|
|
|
|
sha256_hash = sha256_node.last_argument
|
|
|
|
digest_column = T.let(sha256_hash.pairs.last.value.source_range.column, Integer)
|
|
|
|
|
|
|
|
max_digest_column = digest_column if digest_column > max_digest_column
|
|
|
|
end
|
|
|
|
# This must be in a separate loop to make sure max_digest_column is truly the maximum
|
|
|
|
sha256_nodes.each do |sha256_node| # rubocop:disable Style/CombinableLoops
|
|
|
|
sha256_hash = sha256_node.last_argument
|
|
|
|
hash = sha256_hash.pairs.last.value
|
|
|
|
digest_column = hash.source_range.column
|
|
|
|
|
|
|
|
next if digest_column == max_digest_column
|
|
|
|
|
|
|
|
offending_node(hash)
|
|
|
|
problem "Align bottle digests" do |corrector|
|
2021-09-30 10:13:43 +01:00
|
|
|
new_line = (" " * (max_digest_column - digest_column)) + hash.source
|
2021-01-28 12:36:44 -08:00
|
|
|
corrector.replace(hash.source_range, new_line)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# This cop audits the order of the `bottle` block in formulae.
|
2023-02-20 18:10:59 -08:00
|
|
|
class BottleOrder < FormulaCop
|
2021-01-28 12:36:44 -08:00
|
|
|
extend AutoCorrector
|
|
|
|
|
2024-07-07 15:18:29 -04:00
|
|
|
sig { override.params(formula_nodes: FormulaNodes).void }
|
|
|
|
def audit_formula(formula_nodes)
|
|
|
|
bottle_node = find_block(formula_nodes.body_node, :bottle)
|
2021-01-28 12:36:44 -08:00
|
|
|
return if bottle_node.nil?
|
|
|
|
return if bottle_node.child_nodes.blank?
|
|
|
|
|
|
|
|
non_sha256_nodes = []
|
|
|
|
sha256_nodes = []
|
|
|
|
|
|
|
|
bottle_block_method_calls = if bottle_node.child_nodes.last.begin_type?
|
|
|
|
bottle_node.child_nodes.last.child_nodes
|
|
|
|
else
|
|
|
|
[bottle_node.child_nodes.last]
|
|
|
|
end
|
|
|
|
|
|
|
|
bottle_block_method_calls.each do |node|
|
|
|
|
if node.method_name == :sha256
|
|
|
|
sha256_nodes << node
|
|
|
|
else
|
|
|
|
non_sha256_nodes << node
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-03-18 16:10:43 +08:00
|
|
|
arm64_macos_nodes = []
|
|
|
|
intel_macos_nodes = []
|
|
|
|
arm64_linux_nodes = []
|
|
|
|
intel_linux_nodes = []
|
2021-01-28 12:36:44 -08:00
|
|
|
|
|
|
|
sha256_nodes.each do |node|
|
|
|
|
version = sha256_bottle_tag node
|
2025-03-18 16:10:43 +08:00
|
|
|
if version == :arm64_linux
|
|
|
|
arm64_linux_nodes << node
|
|
|
|
elsif version.to_s.start_with?("arm64")
|
|
|
|
arm64_macos_nodes << node
|
|
|
|
elsif version.to_s.end_with?("_linux")
|
|
|
|
intel_linux_nodes << node
|
2021-01-28 12:36:44 -08:00
|
|
|
else
|
2025-03-18 16:10:43 +08:00
|
|
|
intel_macos_nodes << node
|
2021-01-28 12:36:44 -08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-03-18 16:10:43 +08:00
|
|
|
sorted_nodes = arm64_macos_nodes + intel_macos_nodes + arm64_linux_nodes + intel_linux_nodes
|
|
|
|
return if sha256_order(sha256_nodes) == sha256_order(sorted_nodes)
|
2021-01-28 12:36:44 -08:00
|
|
|
|
2021-02-04 13:34:37 -05:00
|
|
|
offending_node(bottle_node)
|
|
|
|
problem "ARM bottles should be listed before Intel bottles" do |corrector|
|
|
|
|
lines = ["bottle do"]
|
|
|
|
lines += non_sha256_nodes.map { |node| " #{node.source}" }
|
2025-03-18 16:10:43 +08:00
|
|
|
lines += arm64_macos_nodes.map { |node| " #{node.source}" }
|
|
|
|
lines += intel_macos_nodes.map { |node| " #{node.source}" }
|
|
|
|
lines += arm64_linux_nodes.map { |node| " #{node.source}" }
|
|
|
|
lines += intel_linux_nodes.map { |node| " #{node.source}" }
|
2021-02-04 13:34:37 -05:00
|
|
|
lines << " end"
|
|
|
|
corrector.replace(bottle_node.source_range, lines.join("\n"))
|
|
|
|
end
|
2021-01-28 12:36:44 -08:00
|
|
|
end
|
|
|
|
|
2025-02-01 23:54:35 +00:00
|
|
|
sig { params(nodes: T::Array[RuboCop::AST::SendNode]).returns(T::Array[T.any(String, Symbol)]) }
|
2021-01-28 12:36:44 -08:00
|
|
|
def sha256_order(nodes)
|
|
|
|
nodes.map do |node|
|
|
|
|
sha256_bottle_tag node
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-02-01 23:54:35 +00:00
|
|
|
sig { params(node: AST::SendNode).returns(T.any(String, Symbol)) }
|
2021-01-28 12:36:44 -08:00
|
|
|
def sha256_bottle_tag(node)
|
|
|
|
hash_pair = node.last_argument.pairs.last
|
|
|
|
if hash_pair.key.sym_type?
|
|
|
|
hash_pair.key.value
|
|
|
|
else
|
|
|
|
hash_pair.value.value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|