mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

Homebrew's actually ended up using a fair few gems. While we want to avoid Bundler at runtime (and this PR still does that, in fact uses Bundler even less at runtime than it did before) writing our own version to use at build-time seems redundant.
124 lines
4.1 KiB
Ruby
124 lines
4.1 KiB
Ruby
#: * `man` [`--fail-if-changed`]:
|
|
#: Generate Homebrew's manpages.
|
|
#:
|
|
#: If `--fail-if-changed` is passed, the command will return a failing
|
|
#: status code if changes are detected in the manpage outputs.
|
|
#: This can be used for CI to be notified when the manpages are out of date.
|
|
#: Additionally, the date used in new manpages will match those in the existing
|
|
#: manpages (to allow comparison without factoring in the date).
|
|
|
|
require "formula"
|
|
require "erb"
|
|
require "ostruct"
|
|
|
|
module Homebrew
|
|
module_function
|
|
|
|
SOURCE_PATH = HOMEBREW_LIBRARY_PATH/"manpages"
|
|
TARGET_MAN_PATH = HOMEBREW_REPOSITORY/"manpages"
|
|
TARGET_DOC_PATH = HOMEBREW_REPOSITORY/"docs"
|
|
|
|
def man
|
|
raise UsageError unless ARGV.named.empty?
|
|
|
|
if ARGV.flag? "--link"
|
|
odie "`brew man --link` is now done automatically by `brew update`."
|
|
end
|
|
|
|
regenerate_man_pages
|
|
|
|
if system "git", "-C", HOMEBREW_REPOSITORY, "diff", "--quiet", "docs/Manpage.md", "manpages"
|
|
puts "No changes to manpage output detected."
|
|
elsif ARGV.include?("--fail-if-changed")
|
|
Homebrew.failed = true
|
|
end
|
|
end
|
|
|
|
def regenerate_man_pages
|
|
Homebrew.run_bundler_if_needed!
|
|
|
|
markup = build_man_page
|
|
convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md")
|
|
convert_man_page(markup, TARGET_MAN_PATH/"brew.1")
|
|
|
|
cask_markup = (SOURCE_PATH/"brew-cask.1.md").read
|
|
convert_man_page(cask_markup, TARGET_MAN_PATH/"brew-cask.1")
|
|
end
|
|
|
|
def path_glob_commands(glob)
|
|
Pathname.glob(glob)
|
|
.sort_by { |source_file| sort_key_for_path(source_file) }
|
|
.map do |source_file|
|
|
source_file.read.lines
|
|
.grep(/^#:/)
|
|
.map { |line| line.slice(2..-1) }
|
|
.join
|
|
end.reject { |s| s.strip.empty? || s.include?("@hide_from_man_page") }
|
|
end
|
|
|
|
def build_man_page
|
|
template = (SOURCE_PATH/"brew.1.md.erb").read
|
|
variables = OpenStruct.new
|
|
|
|
variables[:commands] = path_glob_commands("#{HOMEBREW_LIBRARY_PATH}/cmd/*.{rb,sh}")
|
|
variables[:developer_commands] = path_glob_commands("#{HOMEBREW_LIBRARY_PATH}/dev-cmd/*.{rb,sh}")
|
|
readme = HOMEBREW_REPOSITORY/"README.md"
|
|
variables[:lead_maintainer] = readme.read[/(Homebrew's lead maintainer .*\.)/, 1]
|
|
.gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
|
|
variables[:maintainers] = readme.read[/(Homebrew's current maintainers .*\.)/, 1]
|
|
.gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
|
|
variables[:former_maintainers] = readme.read[/(Former maintainers .*\.)/, 1]
|
|
.gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
|
|
|
|
ERB.new(template, nil, ">").result(variables.instance_eval { binding })
|
|
end
|
|
|
|
def sort_key_for_path(path)
|
|
# Options after regular commands (`~` comes after `z` in ASCII table).
|
|
path.basename.to_s.sub(/\.(rb|sh)$/, "").sub(/^--/, "~~")
|
|
end
|
|
|
|
def convert_man_page(markup, target)
|
|
manual = target.basename(".1")
|
|
organisation = "Homebrew"
|
|
|
|
# Set the manpage date to the existing one if we're checking for changes.
|
|
# This avoids the only change being e.g. a new date.
|
|
date = if ARGV.include?("--fail-if-changed") &&
|
|
target.extname == ".1" && target.exist?
|
|
/"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
|
|
Date.parse("#{$1} #{$2} #{$3}")
|
|
else
|
|
Date.today
|
|
end
|
|
date = date.strftime("%Y-%m-%d")
|
|
|
|
shared_args = %W[
|
|
--pipe
|
|
--organization=#{organisation}
|
|
--manual=#{target.basename(".1")}
|
|
--date=#{date}
|
|
]
|
|
|
|
format_flag, format_desc = target_path_to_format(target)
|
|
|
|
puts "Writing #{format_desc} to #{target}"
|
|
Utils.popen(["ronn", format_flag] + shared_args, "rb+") do |ronn|
|
|
ronn.write markup
|
|
ronn.close_write
|
|
ronn_output = ronn.read
|
|
ronn_output.gsub!(%r{</?var>}, "`") if format_flag == "--markdown"
|
|
target.atomic_write ronn_output
|
|
end
|
|
end
|
|
|
|
def target_path_to_format(target)
|
|
case target.basename
|
|
when /\.md$/ then ["--markdown", "markdown"]
|
|
when /\.\d$/ then ["--roff", "man page"]
|
|
else
|
|
odie "Failed to infer output format from '#{target.basename}'."
|
|
end
|
|
end
|
|
end
|