mirror of
https://github.com/ivuorinen/homebrew-tap.git
synced 2026-02-05 17:46:13 +00:00
chore: fixes, several improvements and refactorings (#2)
* chore: fixes * chore: rubocop fixes, linting, etc. * chore: switching to use `brew style` only * chore: use `brew style` for linting, skip example formulae in ci.yml * chore(lint): fixes, additions and tweaks
This commit is contained in:
@@ -1,27 +1,36 @@
|
||||
#!/usr/bin/env ruby
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'json'
|
||||
require 'fileutils'
|
||||
require 'pathname'
|
||||
require 'date'
|
||||
require "json"
|
||||
require "fileutils"
|
||||
require "pathname"
|
||||
require "date"
|
||||
|
||||
# Simple polyfill for Homebrew extensions
|
||||
class String
|
||||
def blank?
|
||||
# Polyfill implementation to avoid external dependencies
|
||||
nil? || empty? # rubocop:disable Homebrew/Blank
|
||||
end
|
||||
end
|
||||
|
||||
# Parser class for extracting metadata from Homebrew formulae
|
||||
class FormulaParser
|
||||
FORMULA_DIR = File.expand_path('../Formula', __dir__)
|
||||
OUTPUT_DIR = File.expand_path('../docs/_data', __dir__)
|
||||
OUTPUT_FILE = File.join(OUTPUT_DIR, 'formulae.json')
|
||||
FORMULA_DIR = File.expand_path("../Formula", __dir__).freeze
|
||||
OUTPUT_DIR = File.expand_path("../docs/_data", __dir__).freeze
|
||||
OUTPUT_FILE = File.join(OUTPUT_DIR, "formulae.json").freeze
|
||||
|
||||
# Regex patterns for safe extraction without code evaluation
|
||||
PATTERNS = {
|
||||
class_name: /^class\s+(\w+)\s+<\s+Formula/,
|
||||
desc: /^\s*desc\s+["']([^"']+)["']/,
|
||||
homepage: /^\s*homepage\s+["']([^"']+)["']/,
|
||||
url: /^\s*url\s+["']([^"']+)["']/,
|
||||
version: /^\s*version\s+["']([^"']+)["']/,
|
||||
sha256: /^\s*sha256\s+["']([a-f0-9]{64})["']/i,
|
||||
license: /^\s*license\s+["']([^"']+)["']/,
|
||||
depends_on: /^\s*depends_on\s+["']([^"']+)["']/
|
||||
desc: /^\s*desc\s+["']([^"']+)["']/,
|
||||
homepage: /^\s*homepage\s+["']([^"']+)["']/,
|
||||
url: /^\s*url\s+["']([^"']+)["']/,
|
||||
version: /^\s*version\s+["']([^"']+)["']/,
|
||||
sha256: /^\s*sha256\s+["']([a-f0-9]{64})["']/i,
|
||||
license: /^\s*license\s+["']([^"']+)["']/,
|
||||
depends_on: /^\s*depends_on\s+["']([^"']+)["']/,
|
||||
}.freeze
|
||||
|
||||
def self.run
|
||||
@@ -42,41 +51,49 @@ class FormulaParser
|
||||
end
|
||||
|
||||
def parse_all_formulae
|
||||
formula_files.map { |file| parse_formula(file) }.compact.sort_by { |f| f[:name] }
|
||||
formula_files.filter_map { |file| parse_formula(file) }.sort_by { |f| f[:name] }
|
||||
end
|
||||
|
||||
def formula_files
|
||||
Dir.glob(File.join(FORMULA_DIR, '**', '*.rb'))
|
||||
Dir.glob(File.join(FORMULA_DIR, "**", "*.rb"))
|
||||
end
|
||||
|
||||
def parse_formula(file_path)
|
||||
content = File.read(file_path)
|
||||
class_name = extract_value(content, :class_name)
|
||||
|
||||
return nil unless class_name
|
||||
return unless class_name
|
||||
|
||||
formula_name = convert_class_name_to_formula_name(class_name)
|
||||
|
||||
return nil if formula_name.nil? || formula_name.empty?
|
||||
return if formula_name.blank?
|
||||
|
||||
{
|
||||
name: formula_name,
|
||||
class_name: class_name,
|
||||
description: extract_value(content, :desc),
|
||||
homepage: extract_value(content, :homepage),
|
||||
url: extract_value(content, :url),
|
||||
version: extract_version(content),
|
||||
sha256: extract_value(content, :sha256),
|
||||
license: extract_value(content, :license),
|
||||
dependencies: extract_dependencies(content),
|
||||
file_path: Pathname.new(file_path).relative_path_from(Pathname.new(FORMULA_DIR)).to_s,
|
||||
last_modified: format_time_iso8601(File.mtime(file_path))
|
||||
}
|
||||
rescue StandardError => e
|
||||
build_formula_metadata(content, file_path, formula_name, class_name)
|
||||
rescue => e
|
||||
warn "⚠️ Error parsing #{file_path}: #{e.message}"
|
||||
nil
|
||||
end
|
||||
|
||||
def build_formula_metadata(content, file_path, formula_name, class_name)
|
||||
{
|
||||
name: formula_name,
|
||||
class_name: class_name,
|
||||
description: extract_value(content, :desc),
|
||||
homepage: extract_value(content, :homepage),
|
||||
url: extract_value(content, :url),
|
||||
version: extract_version(content),
|
||||
sha256: extract_value(content, :sha256),
|
||||
license: extract_value(content, :license),
|
||||
dependencies: extract_dependencies(content),
|
||||
file_path: calculate_relative_path(file_path),
|
||||
last_modified: format_time_iso8601(File.mtime(file_path)),
|
||||
}
|
||||
end
|
||||
|
||||
def calculate_relative_path(file_path)
|
||||
Pathname.new(file_path).relative_path_from(Pathname.new(FORMULA_DIR)).to_s
|
||||
end
|
||||
|
||||
def extract_value(content, pattern_key)
|
||||
match = content.match(PATTERNS[pattern_key])
|
||||
match&.[](1)
|
||||
@@ -88,7 +105,7 @@ class FormulaParser
|
||||
return explicit if explicit
|
||||
|
||||
url = extract_value(content, :url)
|
||||
return nil unless url
|
||||
return unless url
|
||||
|
||||
# Common version patterns in URLs
|
||||
url.match(/v?(\d+(?:\.\d+)+)/)&.[](1)
|
||||
@@ -99,25 +116,25 @@ class FormulaParser
|
||||
end
|
||||
|
||||
def convert_class_name_to_formula_name(class_name)
|
||||
return nil unless class_name
|
||||
return unless class_name
|
||||
|
||||
# Convert CamelCase to kebab-case
|
||||
class_name
|
||||
.gsub(/([a-z\d])([A-Z])/, '\1-\2')
|
||||
.gsub(/([a-z\d])([A-Z])/, "\1-\2")
|
||||
.downcase
|
||||
end
|
||||
|
||||
def format_time_iso8601(time)
|
||||
# Format time manually for compatibility
|
||||
time.strftime('%Y-%m-%dT%H:%M:%S%z').gsub(/(\d{2})(\d{2})$/, '\1:\2')
|
||||
time.strftime("%Y-%m-%dT%H:%M:%S%z").gsub(/(\d{2})(\d{2})$/, "\1:\2")
|
||||
end
|
||||
|
||||
def write_json_output(formulae)
|
||||
output = {
|
||||
tap_name: 'ivuorinen/tap',
|
||||
generated_at: format_time_iso8601(Time.now),
|
||||
tap_name: "ivuorinen/tap",
|
||||
generated_at: format_time_iso8601(Time.now),
|
||||
formulae_count: formulae.length,
|
||||
formulae: formulae
|
||||
formulae: formulae,
|
||||
}
|
||||
|
||||
File.write(OUTPUT_FILE, JSON.pretty_generate(output))
|
||||
|
||||
Reference in New Issue
Block a user