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:
2025-09-23 11:29:53 +03:00
committed by GitHub
parent 310ac4946a
commit 6dc9a170cc
16 changed files with 678 additions and 472 deletions

247
scripts/serve.rb Normal file → Executable file
View File

@@ -1,22 +1,146 @@
#!/usr/bin/env ruby
# typed: strict
# frozen_string_literal: true
require 'webrick'
require 'fileutils'
require_relative 'parse_formulas'
require_relative 'build_site'
require "webrick"
require "fileutils"
require_relative "parse_formulas"
require_relative "build_site"
# Simple development server for the homebrew tap documentation
# Module for handling file watching and change detection
module FileWatcher
def start_file_watcher
Thread.new do
last_mtime = max_mtime
rebuild_pending = false
watched_files = watched_files_count
puts "👀 Watching #{watched_files} files for changes..."
loop do
sleep 1
current_mtime = max_mtime
next if should_skip_rebuild?(current_mtime, last_mtime, rebuild_pending)
rebuild_pending = true
handle_file_change(last_mtime)
last_mtime = perform_rebuild_with_debounce
rebuild_pending = false
puts "✅ Rebuild complete"
rescue => e
puts "⚠️ File watcher error: #{e.message}"
puts "📍 Backtrace: #{e.backtrace.first(3).join(", ")}"
rebuild_pending = false
sleep 2
puts "🔄 File watcher continuing..."
end
end
end
def watched_files_count
all_watched_files.count { |file| !File.directory?(file) }
end
def find_changed_file(since_mtime)
all_watched_files.find do |file|
File.exist?(file) && !File.directory?(file) && File.mtime(file) > since_mtime
end
end
def all_watched_files
[
formula_files,
theme_files,
template_files,
style_and_script_files,
asset_files,
build_script_files,
config_files,
].flatten.compact.uniq
end
def max_mtime
all_watched_files
.select { |file| File.exist?(file) && !File.directory?(file) }
.map { |file| File.mtime(file) }
.max || Time.at(0)
end
private
def should_skip_rebuild?(current_mtime, last_mtime, rebuild_pending)
current_mtime <= last_mtime || rebuild_pending
end
def handle_file_change(last_mtime)
changed_file = find_changed_file(last_mtime)
puts "📝 Changed: #{changed_file}" if changed_file
puts "🔄 Rebuilding in 1 second..."
end
def perform_rebuild_with_debounce
sleep 1 # Debounce: wait for additional changes
final_mtime = max_mtime
puts "🔨 Building site..."
build_site
final_mtime
end
def formula_files
Dir.glob(File.expand_path("../Formula/**/*.rb", __dir__))
end
def theme_files
Dir.glob(File.expand_path("../theme/**/*", __dir__))
end
def template_files
[
Dir.glob(File.expand_path("../theme/*.erb", __dir__)),
Dir.glob(File.expand_path("../theme/_*.erb", __dir__)),
Dir.glob(File.expand_path("../theme/*.html.erb", __dir__)),
Dir.glob(File.expand_path("../theme/_*.html.erb", __dir__)),
].flatten
end
def style_and_script_files
[
Dir.glob(File.expand_path("../theme/*.css", __dir__)),
Dir.glob(File.expand_path("../theme/*.js", __dir__)),
].flatten
end
def asset_files
Dir.glob(File.expand_path("../theme/assets/**/*", __dir__))
end
def build_script_files
[
File.expand_path("../scripts/parse_formulas.rb", __dir__),
File.expand_path("../scripts/build_site.rb", __dir__),
]
end
def config_files
[File.expand_path("../Makefile", __dir__)]
end
end
# Development server with file watching for homebrew tap documentation
class DevServer
def self.serve(port: 4000, host: 'localhost')
include FileWatcher
def self.serve(port: 4000, host: "localhost")
new(port: port, host: host).start
end
def initialize(port: 4000, host: 'localhost')
def initialize(port: 4000, host: "localhost")
@port = port
@host = host
@site_dir = File.expand_path('../docs', __dir__)
@docs_dir = File.expand_path('../docs', __dir__)
@site_dir = File.expand_path("../docs", __dir__)
@docs_dir = File.expand_path("../docs", __dir__)
end
def start
@@ -43,128 +167,45 @@ class DevServer
def start_server
server = WEBrick::HTTPServer.new(
Port: @port,
Host: @host,
Port: @port,
Host: @host,
DocumentRoot: @site_dir,
Logger: WEBrick::Log.new($stderr, WEBrick::Log::INFO),
AccessLog: [[
Logger: WEBrick::Log.new($stderr, WEBrick::Log::INFO),
AccessLog: [[
$stderr,
WEBrick::AccessLog::COMBINED_LOG_FORMAT
]]
WEBrick::AccessLog::COMBINED_LOG_FORMAT,
]],
)
# Handle Ctrl+C gracefully
trap('INT') do
trap("INT") do
puts "\n👋 Stopping server..."
server.shutdown
end
# Add custom mime types if needed
server.config[:MimeTypes]['json'] = 'application/json'
server.config[:MimeTypes]["json"] = "application/json"
# Add auto-rebuild on file changes (simple polling)
start_file_watcher
server.start
end
def start_file_watcher
Thread.new do
last_mtime = get_max_mtime
rebuild_pending = false
watched_files = get_watched_files_count
puts "👀 Watching #{watched_files} files for changes..."
loop do
sleep 1
current_mtime = get_max_mtime
if current_mtime > last_mtime && !rebuild_pending
rebuild_pending = true
changed_file = find_changed_file(last_mtime)
puts "📝 Changed: #{changed_file}" if changed_file
puts "🔄 Rebuilding in 1 second..."
# Debounce: wait for additional changes
sleep 1
# Check if more changes occurred during debounce period
final_mtime = get_max_mtime
puts "🔨 Building site..."
build_site
last_mtime = final_mtime
rebuild_pending = false
puts "✅ Rebuild complete"
end
end
end
end
def get_watched_files_count
files = get_all_watched_files
files.select { |f| File.exist?(f) && !File.directory?(f) }.count
end
def find_changed_file(since_time)
files = get_all_watched_files
files.select { |f| File.exist?(f) && !File.directory?(f) }
.find { |f| File.mtime(f) > since_time }
&.sub(File.expand_path('..', __dir__) + '/', '')
end
def get_all_watched_files
[
# Watch Formula files for changes
Dir.glob(File.expand_path('../Formula/**/*.rb', __dir__)),
# Watch all theme files including partials
Dir.glob(File.expand_path('../theme/**/*', __dir__)),
# Specifically watch for erb templates and partials
Dir.glob(File.expand_path('../theme/*.erb', __dir__)),
Dir.glob(File.expand_path('../theme/_*.erb', __dir__)),
Dir.glob(File.expand_path('../theme/*.html.erb', __dir__)),
Dir.glob(File.expand_path('../theme/_*.html.erb', __dir__)),
# Watch CSS and JS
Dir.glob(File.expand_path('../theme/*.css', __dir__)),
Dir.glob(File.expand_path('../theme/*.js', __dir__)),
# Watch assets directory
Dir.glob(File.expand_path('../theme/assets/**/*', __dir__)),
# Watch build scripts for changes
[File.expand_path('../scripts/parse_formulas.rb', __dir__)],
[File.expand_path('../scripts/build_site.rb', __dir__)],
# Watch Makefile
[File.expand_path('../Makefile', __dir__)]
].flatten.compact.uniq
end
def get_max_mtime
files_to_watch = get_all_watched_files
# Filter out non-existent files and directories, get modification times
existing_files = files_to_watch.select { |f| File.exist?(f) && !File.directory?(f) }
if existing_files.empty?
Time.at(0)
else
existing_files.map { |f| File.mtime(f) }.max
end
end
end
# Command line interface
if __FILE__ == $PROGRAM_NAME
# Check for --list-watched flag
if ARGV.include?('--list-watched')
if ARGV.include?("--list-watched")
server = DevServer.new
files = server.send(:get_all_watched_files).select { |f| File.exist?(f) && !File.directory?(f) }
files = server.all_watched_files.select { |f| File.exist?(f) && !File.directory?(f) }
puts "📋 Watching #{files.count} files:"
files.sort.each { |f| puts " - #{f.sub(File.expand_path('..', __dir__) + '/', '')}" }
files.sort.each { |f| puts " - #{f.sub("#{File.expand_path("..", __dir__)}/", "")}" }
exit 0
end
port = ARGV[0]&.to_i || 4000
host = ARGV[1] || 'localhost'
host = ARGV[1] || "localhost"
DevServer.serve(port: port, host: host)
end