Merge pull request #11308 from nandahkrishna/rename-brew-man
Rename `brew man` to `brew generate-manpages`
This commit is contained in:
		
						commit
						0ed2f6423f
					
				
							
								
								
									
										2
									
								
								.github/workflows/update-manpage.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/update-manpage.yml
									
									
									
									
										vendored
									
									
								
							@ -56,7 +56,7 @@ jobs:
 | 
			
		||||
            brew update-maintainers
 | 
			
		||||
          fi
 | 
			
		||||
 | 
			
		||||
          if brew man --fail-if-not-changed; then
 | 
			
		||||
          if brew generate-man-completions --fail-if-not-changed; then
 | 
			
		||||
            git add "$GITHUB_WORKSPACE/README.md" \
 | 
			
		||||
                    "$GITHUB_WORKSPACE/docs/Manpage.md" \
 | 
			
		||||
                    "$GITHUB_WORKSPACE/manpages/brew.1" \
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
#     compare with already documented commands.
 | 
			
		||||
# - For other changes: Edit this file.
 | 
			
		||||
#
 | 
			
		||||
# When done, regenerate the completions by running `brew man`.
 | 
			
		||||
# When done, regenerate the completions by running `brew generate-man-completions`.
 | 
			
		||||
%>
 | 
			
		||||
# Bash completion script for brew(1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
#     compare with already documented commands.
 | 
			
		||||
# - For other changes: Edit this file.
 | 
			
		||||
#
 | 
			
		||||
# When done, regenerate the completions by running `brew man`.
 | 
			
		||||
# When done, regenerate the completions by running `brew generate-man-completions`.
 | 
			
		||||
%>
 | 
			
		||||
# Fish shell completions for Homebrew
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
#     compare with already documented commands.
 | 
			
		||||
# - For other changes: Edit this file.
 | 
			
		||||
#
 | 
			
		||||
# When done, regenerate the completions by running `brew man`.
 | 
			
		||||
# When done, regenerate the completions by running `brew generate-man-completions`.
 | 
			
		||||
%>
 | 
			
		||||
#compdef brew
 | 
			
		||||
#autoload
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										264
									
								
								Library/Homebrew/dev-cmd/generate-man-completions.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								Library/Homebrew/dev-cmd/generate-man-completions.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,264 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "formula"
 | 
			
		||||
require "erb"
 | 
			
		||||
require "ostruct"
 | 
			
		||||
require "cli/parser"
 | 
			
		||||
require "completions"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  extend T::Sig
 | 
			
		||||
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
  SOURCE_PATH = (HOMEBREW_LIBRARY_PATH/"manpages").freeze
 | 
			
		||||
  TARGET_MAN_PATH = (HOMEBREW_REPOSITORY/"manpages").freeze
 | 
			
		||||
  TARGET_DOC_PATH = (HOMEBREW_REPOSITORY/"docs").freeze
 | 
			
		||||
 | 
			
		||||
  sig { returns(CLI::Parser) }
 | 
			
		||||
  def generate_man_completions_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
      description <<~EOS
 | 
			
		||||
        Generate Homebrew's manpages and shell completions.
 | 
			
		||||
      EOS
 | 
			
		||||
      switch "--fail-if-not-changed",
 | 
			
		||||
             description: "Return a failing status code if no changes are detected in the manpage outputs. "\
 | 
			
		||||
                          "This can be used to notify CI 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)."
 | 
			
		||||
      named_args :none
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def generate_man_completions
 | 
			
		||||
    args = generate_man_completions_args.parse
 | 
			
		||||
 | 
			
		||||
    Commands.rebuild_internal_commands_completion_list
 | 
			
		||||
    regenerate_man_pages(preserve_date: args.fail_if_not_changed?, quiet: args.quiet?)
 | 
			
		||||
    Completions.update_shell_completions!
 | 
			
		||||
 | 
			
		||||
    diff = system_command "git", args: [
 | 
			
		||||
      "-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "docs/Manpage.md", "manpages", "completions"
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    return unless diff.status.success?
 | 
			
		||||
 | 
			
		||||
    puts "No changes to manpage or completions output detected."
 | 
			
		||||
    Homebrew.failed = true if args.fail_if_not_changed?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def regenerate_man_pages(preserve_date:, quiet:)
 | 
			
		||||
    Homebrew.install_bundler_gems!
 | 
			
		||||
 | 
			
		||||
    markup = build_man_page(quiet: quiet)
 | 
			
		||||
    convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md", preserve_date: preserve_date)
 | 
			
		||||
    markup = I18n.transliterate(markup, locale: :en)
 | 
			
		||||
    convert_man_page(markup, TARGET_MAN_PATH/"brew.1", preserve_date: preserve_date)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build_man_page(quiet:)
 | 
			
		||||
    template = (SOURCE_PATH/"brew.1.md.erb").read
 | 
			
		||||
    variables = OpenStruct.new
 | 
			
		||||
 | 
			
		||||
    variables[:commands] = generate_cmd_manpages(Commands.internal_commands_paths)
 | 
			
		||||
    variables[:developer_commands] = generate_cmd_manpages(Commands.internal_developer_commands_paths)
 | 
			
		||||
    variables[:official_external_commands] =
 | 
			
		||||
      generate_cmd_manpages(Commands.official_external_commands_paths(quiet: quiet))
 | 
			
		||||
    variables[:global_cask_options] = global_cask_options_manpage
 | 
			
		||||
    variables[:global_options] = global_options_manpage
 | 
			
		||||
    variables[:environment_variables] = env_vars_manpage
 | 
			
		||||
 | 
			
		||||
    readme = HOMEBREW_REPOSITORY/"README.md"
 | 
			
		||||
    variables[:lead] =
 | 
			
		||||
      readme.read[/(Homebrew's \[Project Leader.*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:plc] =
 | 
			
		||||
      readme.read[/(Homebrew's \[Project Leadership Committee.*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:tsc] =
 | 
			
		||||
      readme.read[/(Homebrew's \[Technical Steering Committee.*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:linux] =
 | 
			
		||||
      readme.read[/(Homebrew's Linux maintainers .*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:maintainers] =
 | 
			
		||||
      readme.read[/(Homebrew's other current maintainers .*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:alumni] =
 | 
			
		||||
      readme.read[/(Former maintainers .*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
 | 
			
		||||
    ERB.new(template, trim_mode: ">").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, preserve_date:)
 | 
			
		||||
    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 preserve_date && target.extname == ".1" && target.exist?
 | 
			
		||||
      /"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
 | 
			
		||||
      Date.parse("#{Regexp.last_match(1)} #{Regexp.last_match(2)} #{Regexp.last_match(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
 | 
			
		||||
      odie "Got no output from ronn!" if ronn_output.blank?
 | 
			
		||||
      case format_flag
 | 
			
		||||
      when "--markdown"
 | 
			
		||||
        ronn_output = ronn_output.gsub(%r{<var>(.*?)</var>}, "*`\\1`*")
 | 
			
		||||
                                 .gsub(/\n\n\n+/, "\n\n")
 | 
			
		||||
                                 .gsub(/^(- `[^`]+`):/, "\\1") # drop trailing colons from definition lists
 | 
			
		||||
                                 .gsub(/(?<=\n\n)([\[`].+):\n/, "\\1\n<br>") # replace colons with <br> on subcommands
 | 
			
		||||
      when "--roff"
 | 
			
		||||
        ronn_output = ronn_output.gsub(%r{<code>(.*?)</code>}, "\\fB\\1\\fR")
 | 
			
		||||
                                 .gsub(%r{<var>(.*?)</var>}, "\\fI\\1\\fR")
 | 
			
		||||
                                 .gsub(/(^\[?\\fB.+): /, "\\1\n    ")
 | 
			
		||||
      end
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
  def generate_cmd_manpages(cmd_paths)
 | 
			
		||||
    man_page_lines = []
 | 
			
		||||
 | 
			
		||||
    # preserve existing manpage order
 | 
			
		||||
    cmd_paths.sort_by(&method(:sort_key_for_path))
 | 
			
		||||
             .each do |cmd_path|
 | 
			
		||||
      cmd_man_page_lines = if (cmd_parser = CLI::Parser.from_cmd_path(cmd_path))
 | 
			
		||||
        next if cmd_parser.hide_from_man_page
 | 
			
		||||
 | 
			
		||||
        cmd_parser_manpage_lines(cmd_parser).join
 | 
			
		||||
      else
 | 
			
		||||
        cmd_comment_manpage_lines(cmd_path)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      man_page_lines << cmd_man_page_lines
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    man_page_lines.compact.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def cmd_parser_manpage_lines(cmd_parser)
 | 
			
		||||
    lines = [format_usage_banner(cmd_parser.usage_banner_text)]
 | 
			
		||||
    lines += cmd_parser.processed_options.map do |short, long, _, desc|
 | 
			
		||||
      if long.present?
 | 
			
		||||
        next if Homebrew::CLI::Parser.global_options.include?([short, long, desc])
 | 
			
		||||
        next if Homebrew::CLI::Parser.global_cask_options.any? do |_, option, description:, **|
 | 
			
		||||
                  [long, "#{long}="].include?(option) && description == desc
 | 
			
		||||
                end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      generate_option_doc(short, long, desc)
 | 
			
		||||
    end.reject(&:blank?)
 | 
			
		||||
    lines
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def cmd_comment_manpage_lines(cmd_path)
 | 
			
		||||
    comment_lines = cmd_path.read.lines.grep(/^#:/)
 | 
			
		||||
    return if comment_lines.empty?
 | 
			
		||||
    return if comment_lines.first.include?("@hide_from_man_page")
 | 
			
		||||
 | 
			
		||||
    lines = [format_usage_banner(comment_lines.first).chomp]
 | 
			
		||||
    comment_lines.slice(1..-1)
 | 
			
		||||
                 .each do |line|
 | 
			
		||||
      line = line.slice(4..-2)
 | 
			
		||||
      unless line
 | 
			
		||||
        lines.last << "\n"
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Omit the common global_options documented separately in the man page.
 | 
			
		||||
      next if line.match?(/--(debug|help|quiet|verbose) /)
 | 
			
		||||
 | 
			
		||||
      # Format one option or a comma-separated pair of short and long options.
 | 
			
		||||
      lines << line.gsub(/^ +(-+[a-z-]+), (-+[a-z-]+) +/, "* `\\1`, `\\2`:\n  ")
 | 
			
		||||
                   .gsub(/^ +(-+[a-z-]+) +/, "* `\\1`:\n  ")
 | 
			
		||||
    end
 | 
			
		||||
    lines.last << "\n"
 | 
			
		||||
    lines
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(String) }
 | 
			
		||||
  def global_cask_options_manpage
 | 
			
		||||
    lines = ["These options are applicable to the `install`, `reinstall`, and `upgrade` " \
 | 
			
		||||
             "subcommands with the `--cask` flag.\n"]
 | 
			
		||||
    lines += Homebrew::CLI::Parser.global_cask_options.map do |_, long, description:, **|
 | 
			
		||||
      generate_option_doc(nil, long.chomp("="), description)
 | 
			
		||||
    end
 | 
			
		||||
    lines.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(String) }
 | 
			
		||||
  def global_options_manpage
 | 
			
		||||
    lines = ["These options are applicable across multiple subcommands.\n"]
 | 
			
		||||
    lines += Homebrew::CLI::Parser.global_options.map do |short, long, desc|
 | 
			
		||||
      generate_option_doc(short, long, desc)
 | 
			
		||||
    end
 | 
			
		||||
    lines.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(String) }
 | 
			
		||||
  def env_vars_manpage
 | 
			
		||||
    lines = Homebrew::EnvConfig::ENVS.flat_map do |env, hash|
 | 
			
		||||
      entry = "- `#{env}`:\n  <br>#{hash[:description]}\n"
 | 
			
		||||
      default = hash[:default_text]
 | 
			
		||||
      default ||= "`#{hash[:default]}`." if hash[:default]
 | 
			
		||||
      entry += "\n\n  *Default:* #{default}\n" if default
 | 
			
		||||
 | 
			
		||||
      entry
 | 
			
		||||
    end
 | 
			
		||||
    lines.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def generate_option_doc(short, long, desc)
 | 
			
		||||
    comma = (short && long) ? ", " : ""
 | 
			
		||||
    <<~EOS
 | 
			
		||||
      * #{format_short_opt(short)}#{comma}#{format_long_opt(long)}:
 | 
			
		||||
        #{desc}
 | 
			
		||||
    EOS
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_short_opt(opt)
 | 
			
		||||
    "`#{opt}`" unless opt.nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_long_opt(opt)
 | 
			
		||||
    "`#{opt}`" unless opt.nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_usage_banner(usage_banner)
 | 
			
		||||
    usage_banner&.sub(/^(#: *\* )?/, "### ")
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@ -1,21 +1,11 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "formula"
 | 
			
		||||
require "erb"
 | 
			
		||||
require "ostruct"
 | 
			
		||||
require "cli/parser"
 | 
			
		||||
require "completions"
 | 
			
		||||
 | 
			
		||||
module Homebrew
 | 
			
		||||
  extend T::Sig
 | 
			
		||||
 | 
			
		||||
  module_function
 | 
			
		||||
 | 
			
		||||
  SOURCE_PATH = (HOMEBREW_LIBRARY_PATH/"manpages").freeze
 | 
			
		||||
  TARGET_MAN_PATH = (HOMEBREW_REPOSITORY/"manpages").freeze
 | 
			
		||||
  TARGET_DOC_PATH = (HOMEBREW_REPOSITORY/"docs").freeze
 | 
			
		||||
 | 
			
		||||
  sig { returns(CLI::Parser) }
 | 
			
		||||
  def man_args
 | 
			
		||||
    Homebrew::CLI::Parser.new do
 | 
			
		||||
@ -28,237 +18,19 @@ module Homebrew
 | 
			
		||||
                          "the date used in new manpages will match those in the existing manpages (to allow "\
 | 
			
		||||
                          "comparison without factoring in the date)."
 | 
			
		||||
      named_args :none
 | 
			
		||||
 | 
			
		||||
      hide_from_man_page!
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def man
 | 
			
		||||
    odeprecated "`brew man`", "`brew generate-man-completions`"
 | 
			
		||||
 | 
			
		||||
    args = man_args.parse
 | 
			
		||||
    cmd = ["generate-man-completions"]
 | 
			
		||||
    cmd << "--fail-if-not-changed" if args.fail_if_not_changed?
 | 
			
		||||
 | 
			
		||||
    Commands.rebuild_internal_commands_completion_list
 | 
			
		||||
    regenerate_man_pages(preserve_date: args.fail_if_not_changed?, quiet: args.quiet?)
 | 
			
		||||
    Completions.update_shell_completions!
 | 
			
		||||
 | 
			
		||||
    diff = system_command "git", args: [
 | 
			
		||||
      "-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "docs/Manpage.md", "manpages", "completions"
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    return unless diff.status.success?
 | 
			
		||||
 | 
			
		||||
    puts "No changes to manpage or completions output detected."
 | 
			
		||||
    Homebrew.failed = true if args.fail_if_not_changed?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def regenerate_man_pages(preserve_date:, quiet:)
 | 
			
		||||
    Homebrew.install_bundler_gems!
 | 
			
		||||
 | 
			
		||||
    markup = build_man_page(quiet: quiet)
 | 
			
		||||
    convert_man_page(markup, TARGET_DOC_PATH/"Manpage.md", preserve_date: preserve_date)
 | 
			
		||||
    markup = I18n.transliterate(markup, locale: :en)
 | 
			
		||||
    convert_man_page(markup, TARGET_MAN_PATH/"brew.1", preserve_date: preserve_date)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build_man_page(quiet:)
 | 
			
		||||
    template = (SOURCE_PATH/"brew.1.md.erb").read
 | 
			
		||||
    variables = OpenStruct.new
 | 
			
		||||
 | 
			
		||||
    variables[:commands] = generate_cmd_manpages(Commands.internal_commands_paths)
 | 
			
		||||
    variables[:developer_commands] = generate_cmd_manpages(Commands.internal_developer_commands_paths)
 | 
			
		||||
    variables[:official_external_commands] =
 | 
			
		||||
      generate_cmd_manpages(Commands.official_external_commands_paths(quiet: quiet))
 | 
			
		||||
    variables[:global_cask_options] = global_cask_options_manpage
 | 
			
		||||
    variables[:global_options] = global_options_manpage
 | 
			
		||||
    variables[:environment_variables] = env_vars_manpage
 | 
			
		||||
 | 
			
		||||
    readme = HOMEBREW_REPOSITORY/"README.md"
 | 
			
		||||
    variables[:lead] =
 | 
			
		||||
      readme.read[/(Homebrew's \[Project Leader.*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:plc] =
 | 
			
		||||
      readme.read[/(Homebrew's \[Project Leadership Committee.*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:tsc] =
 | 
			
		||||
      readme.read[/(Homebrew's \[Technical Steering Committee.*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:linux] =
 | 
			
		||||
      readme.read[/(Homebrew's Linux maintainers .*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:maintainers] =
 | 
			
		||||
      readme.read[/(Homebrew's other current maintainers .*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
    variables[:alumni] =
 | 
			
		||||
      readme.read[/(Former maintainers .*\.)/, 1]
 | 
			
		||||
            .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1')
 | 
			
		||||
 | 
			
		||||
    ERB.new(template, trim_mode: ">").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, preserve_date:)
 | 
			
		||||
    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 preserve_date && target.extname == ".1" && target.exist?
 | 
			
		||||
      /"(\d{1,2})" "([A-Z][a-z]+) (\d{4})" "#{organisation}" "#{manual}"/ =~ target.read
 | 
			
		||||
      Date.parse("#{Regexp.last_match(1)} #{Regexp.last_match(2)} #{Regexp.last_match(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
 | 
			
		||||
      odie "Got no output from ronn!" if ronn_output.blank?
 | 
			
		||||
      case format_flag
 | 
			
		||||
      when "--markdown"
 | 
			
		||||
        ronn_output = ronn_output.gsub(%r{<var>(.*?)</var>}, "*`\\1`*")
 | 
			
		||||
                                 .gsub(/\n\n\n+/, "\n\n")
 | 
			
		||||
                                 .gsub(/^(- `[^`]+`):/, "\\1") # drop trailing colons from definition lists
 | 
			
		||||
                                 .gsub(/(?<=\n\n)([\[`].+):\n/, "\\1\n<br>") # replace colons with <br> on subcommands
 | 
			
		||||
      when "--roff"
 | 
			
		||||
        ronn_output = ronn_output.gsub(%r{<code>(.*?)</code>}, "\\fB\\1\\fR")
 | 
			
		||||
                                 .gsub(%r{<var>(.*?)</var>}, "\\fI\\1\\fR")
 | 
			
		||||
                                 .gsub(/(^\[?\\fB.+): /, "\\1\n    ")
 | 
			
		||||
      end
 | 
			
		||||
      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
 | 
			
		||||
 | 
			
		||||
  def generate_cmd_manpages(cmd_paths)
 | 
			
		||||
    man_page_lines = []
 | 
			
		||||
 | 
			
		||||
    # preserve existing manpage order
 | 
			
		||||
    cmd_paths.sort_by(&method(:sort_key_for_path))
 | 
			
		||||
             .each do |cmd_path|
 | 
			
		||||
      cmd_man_page_lines = if (cmd_parser = CLI::Parser.from_cmd_path(cmd_path))
 | 
			
		||||
        next if cmd_parser.hide_from_man_page
 | 
			
		||||
 | 
			
		||||
        cmd_parser_manpage_lines(cmd_parser).join
 | 
			
		||||
      else
 | 
			
		||||
        cmd_comment_manpage_lines(cmd_path)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      man_page_lines << cmd_man_page_lines
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    man_page_lines.compact.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def cmd_parser_manpage_lines(cmd_parser)
 | 
			
		||||
    lines = [format_usage_banner(cmd_parser.usage_banner_text)]
 | 
			
		||||
    lines += cmd_parser.processed_options.map do |short, long, _, desc|
 | 
			
		||||
      if long.present?
 | 
			
		||||
        next if Homebrew::CLI::Parser.global_options.include?([short, long, desc])
 | 
			
		||||
        next if Homebrew::CLI::Parser.global_cask_options.any? do |_, option, description:, **|
 | 
			
		||||
                  [long, "#{long}="].include?(option) && description == desc
 | 
			
		||||
                end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      generate_option_doc(short, long, desc)
 | 
			
		||||
    end.reject(&:blank?)
 | 
			
		||||
    lines
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def cmd_comment_manpage_lines(cmd_path)
 | 
			
		||||
    comment_lines = cmd_path.read.lines.grep(/^#:/)
 | 
			
		||||
    return if comment_lines.empty?
 | 
			
		||||
    return if comment_lines.first.include?("@hide_from_man_page")
 | 
			
		||||
 | 
			
		||||
    lines = [format_usage_banner(comment_lines.first).chomp]
 | 
			
		||||
    comment_lines.slice(1..-1)
 | 
			
		||||
                 .each do |line|
 | 
			
		||||
      line = line.slice(4..-2)
 | 
			
		||||
      unless line
 | 
			
		||||
        lines.last << "\n"
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Omit the common global_options documented separately in the man page.
 | 
			
		||||
      next if line.match?(/--(debug|help|quiet|verbose) /)
 | 
			
		||||
 | 
			
		||||
      # Format one option or a comma-separated pair of short and long options.
 | 
			
		||||
      lines << line.gsub(/^ +(-+[a-z-]+), (-+[a-z-]+) +/, "* `\\1`, `\\2`:\n  ")
 | 
			
		||||
                   .gsub(/^ +(-+[a-z-]+) +/, "* `\\1`:\n  ")
 | 
			
		||||
    end
 | 
			
		||||
    lines.last << "\n"
 | 
			
		||||
    lines
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(String) }
 | 
			
		||||
  def global_cask_options_manpage
 | 
			
		||||
    lines = ["These options are applicable to the `install`, `reinstall`, and `upgrade` " \
 | 
			
		||||
             "subcommands with the `--cask` flag.\n"]
 | 
			
		||||
    lines += Homebrew::CLI::Parser.global_cask_options.map do |_, long, description:, **|
 | 
			
		||||
      generate_option_doc(nil, long.chomp("="), description)
 | 
			
		||||
    end
 | 
			
		||||
    lines.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(String) }
 | 
			
		||||
  def global_options_manpage
 | 
			
		||||
    lines = ["These options are applicable across multiple subcommands.\n"]
 | 
			
		||||
    lines += Homebrew::CLI::Parser.global_options.map do |short, long, desc|
 | 
			
		||||
      generate_option_doc(short, long, desc)
 | 
			
		||||
    end
 | 
			
		||||
    lines.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  sig { returns(String) }
 | 
			
		||||
  def env_vars_manpage
 | 
			
		||||
    lines = Homebrew::EnvConfig::ENVS.flat_map do |env, hash|
 | 
			
		||||
      entry = "- `#{env}`:\n  <br>#{hash[:description]}\n"
 | 
			
		||||
      default = hash[:default_text]
 | 
			
		||||
      default ||= "`#{hash[:default]}`." if hash[:default]
 | 
			
		||||
      entry += "\n\n  *Default:* #{default}\n" if default
 | 
			
		||||
 | 
			
		||||
      entry
 | 
			
		||||
    end
 | 
			
		||||
    lines.join("\n")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def generate_option_doc(short, long, desc)
 | 
			
		||||
    comma = (short && long) ? ", " : ""
 | 
			
		||||
    <<~EOS
 | 
			
		||||
      * #{format_short_opt(short)}#{comma}#{format_long_opt(long)}:
 | 
			
		||||
        #{desc}
 | 
			
		||||
    EOS
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_short_opt(opt)
 | 
			
		||||
    "`#{opt}`" unless opt.nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_long_opt(opt)
 | 
			
		||||
    "`#{opt}`" unless opt.nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def format_usage_banner(usage_banner)
 | 
			
		||||
    usage_banner&.sub(/^(#: *\* )?/, "### ")
 | 
			
		||||
    brew_rb = (HOMEBREW_LIBRARY_PATH/"brew.rb").resolved_path
 | 
			
		||||
    system ENV["HOMEBREW_RUBY_PATH"], brew_rb, *cmd
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,8 @@
 | 
			
		||||
# - For environment variables: Edit `Library/Homebrew/env_config.rb`.
 | 
			
		||||
# - For other changes: Edit this file.
 | 
			
		||||
#
 | 
			
		||||
# When done, regenerate the man page and its HTML version by running `brew man`.
 | 
			
		||||
# When done, regenerate the man page and its HTML version by running
 | 
			
		||||
# `brew generate-man-completions`.
 | 
			
		||||
%>
 | 
			
		||||
brew(1) -- The Missing Package Manager for macOS (or Linux)
 | 
			
		||||
===========================================================
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
# typed: false
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require "cmd/shared_examples/args_parse"
 | 
			
		||||
 | 
			
		||||
describe "brew generate-man-completions" do
 | 
			
		||||
  it_behaves_like "parseable arguments"
 | 
			
		||||
end
 | 
			
		||||
@ -911,6 +911,23 @@ _brew_formula() {
 | 
			
		||||
  __brew_complete_formulae
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_brew_generate_man_completions() {
 | 
			
		||||
  local cur="${COMP_WORDS[COMP_CWORD]}"
 | 
			
		||||
  case "${cur}" in
 | 
			
		||||
    -*)
 | 
			
		||||
      __brewcomp "
 | 
			
		||||
      --debug
 | 
			
		||||
      --fail-if-not-changed
 | 
			
		||||
      --help
 | 
			
		||||
      --quiet
 | 
			
		||||
      --verbose
 | 
			
		||||
      "
 | 
			
		||||
      return
 | 
			
		||||
      ;;
 | 
			
		||||
    *)
 | 
			
		||||
  esac
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_brew_gist_logs() {
 | 
			
		||||
  local cur="${COMP_WORDS[COMP_CWORD]}"
 | 
			
		||||
  case "${cur}" in
 | 
			
		||||
@ -2439,6 +2456,7 @@ _brew() {
 | 
			
		||||
    extract) _brew_extract ;;
 | 
			
		||||
    fetch) _brew_fetch ;;
 | 
			
		||||
    formula) _brew_formula ;;
 | 
			
		||||
    generate-man-completions) _brew_generate_man_completions ;;
 | 
			
		||||
    gist-logs) _brew_gist_logs ;;
 | 
			
		||||
    home) _brew_home ;;
 | 
			
		||||
    homepage) _brew_homepage ;;
 | 
			
		||||
 | 
			
		||||
@ -671,6 +671,14 @@ __fish_brew_complete_arg 'formula' -l verbose -d 'Make some output more verbose'
 | 
			
		||||
__fish_brew_complete_arg 'formula' -a '(__fish_brew_suggest_formulae_all)'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__fish_brew_complete_cmd 'generate-man-completions' 'Generate Homebrew\'s manpages'
 | 
			
		||||
__fish_brew_complete_arg 'generate-man-completions' -l debug -d 'Display any debugging information'
 | 
			
		||||
__fish_brew_complete_arg 'generate-man-completions' -l fail-if-not-changed -d 'Return a failing status code if no changes are detected in the manpage outputs. This can be used to notify CI 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)'
 | 
			
		||||
__fish_brew_complete_arg 'generate-man-completions' -l help -d 'Show this message'
 | 
			
		||||
__fish_brew_complete_arg 'generate-man-completions' -l quiet -d 'Make some output more quiet'
 | 
			
		||||
__fish_brew_complete_arg 'generate-man-completions' -l verbose -d 'Make some output more verbose'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__fish_brew_complete_cmd 'gist-logs' 'Upload logs for a failed build of formula to a new Gist'
 | 
			
		||||
__fish_brew_complete_arg 'gist-logs' -l debug -d 'Display any debugging information'
 | 
			
		||||
__fish_brew_complete_arg 'gist-logs' -l help -d 'Show this message'
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,7 @@ extract
 | 
			
		||||
fetch
 | 
			
		||||
formula
 | 
			
		||||
formulae
 | 
			
		||||
generate-man-completions
 | 
			
		||||
gist-logs
 | 
			
		||||
help
 | 
			
		||||
home
 | 
			
		||||
 | 
			
		||||
@ -162,6 +162,7 @@ __brew_internal_commands() {
 | 
			
		||||
    'fetch:Download a bottle (if available) or source packages for formulae and binaries for casks'
 | 
			
		||||
    'formula:Display the path where formula is located'
 | 
			
		||||
    'formulae:List all locally installable formulae including short names'
 | 
			
		||||
    'generate-man-completions:Generate Homebrew'\''s manpages'
 | 
			
		||||
    'gist-logs:Upload logs for a failed build of formula to a new Gist'
 | 
			
		||||
    'home:Open a formula or cask'\''s homepage in a browser, or open Homebrew'\''s own homepage if no argument is provided'
 | 
			
		||||
    'info:Display brief statistics for your Homebrew installation'
 | 
			
		||||
@ -831,6 +832,16 @@ _brew_formula() {
 | 
			
		||||
    '*::formula:__brew_formulae'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# brew generate-man-completions
 | 
			
		||||
_brew_generate_man_completions() {
 | 
			
		||||
  _arguments \
 | 
			
		||||
    '--debug[Display any debugging information]' \
 | 
			
		||||
    '--fail-if-not-changed[Return a failing status code if no changes are detected in the manpage outputs. This can be used to notify CI 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)]' \
 | 
			
		||||
    '--help[Show this message]' \
 | 
			
		||||
    '--quiet[Make some output more quiet]' \
 | 
			
		||||
    '--verbose[Make some output more verbose]'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# brew gist-logs
 | 
			
		||||
_brew_gist_logs() {
 | 
			
		||||
  _arguments \
 | 
			
		||||
 | 
			
		||||
@ -1059,6 +1059,13 @@ a formula from a tap that is not `homebrew/core` use its fully-qualified form of
 | 
			
		||||
 | 
			
		||||
Display the path where *`formula`* is located.
 | 
			
		||||
 | 
			
		||||
### `generate-man-completions` [*`--fail-if-not-changed`*]
 | 
			
		||||
 | 
			
		||||
Generate Homebrew's manpages.
 | 
			
		||||
 | 
			
		||||
* `--fail-if-not-changed`:
 | 
			
		||||
  Return a failing status code if no changes are detected in the manpage outputs. This can be used to notify CI 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).
 | 
			
		||||
 | 
			
		||||
### `install-bundler-gems`
 | 
			
		||||
 | 
			
		||||
Install Homebrew's Bundler gems.
 | 
			
		||||
@ -1111,13 +1118,6 @@ casks to check is taken from `HOMEBREW_LIVECHECK_WATCHLIST` or
 | 
			
		||||
* `--cask`:
 | 
			
		||||
  Only check casks.
 | 
			
		||||
 | 
			
		||||
### `man` [*`--fail-if-not-changed`*]
 | 
			
		||||
 | 
			
		||||
Generate Homebrew's manpages.
 | 
			
		||||
 | 
			
		||||
* `--fail-if-not-changed`:
 | 
			
		||||
  Return a failing status code if no changes are detected in the manpage outputs. This can be used to notify CI 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).
 | 
			
		||||
 | 
			
		||||
### `pr-automerge` [*`options`*]
 | 
			
		||||
 | 
			
		||||
Find pull requests that can be automatically merged using `brew pr-publish`.
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,3 @@
 | 
			
		||||
# Manual pages
 | 
			
		||||
 | 
			
		||||
This directory contains the generated Homebrew man pages from the `brew man` command. This command creates the output from the `CLI::Parser` definitions in files, sections extracted from the repository's `README.md` and `brew.1.md.erb`.
 | 
			
		||||
This directory contains the generated Homebrew man pages from the `brew generate-man-completions` command. This command creates the output from the `CLI::Parser` definitions in files, sections extracted from the repository's `README.md` and `brew.1.md.erb`.
 | 
			
		||||
 | 
			
		||||
@ -1480,6 +1480,13 @@ Overwrite the destination formula if it already exists\.
 | 
			
		||||
.SS "\fBformula\fR \fIformula\fR [\.\.\.]"
 | 
			
		||||
Display the path where \fIformula\fR is located\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBgenerate\-man\-completions\fR [\fI\-\-fail\-if\-not\-changed\fR]"
 | 
			
		||||
Generate Homebrew\'s manpages\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-fail\-if\-not\-changed\fR
 | 
			
		||||
Return a failing status code if no changes are detected in the manpage outputs\. This can be used to notify CI 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)\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBinstall\-bundler\-gems\fR"
 | 
			
		||||
Install Homebrew\'s Bundler gems\.
 | 
			
		||||
.
 | 
			
		||||
@ -1551,13 +1558,6 @@ Only check formulae\.
 | 
			
		||||
\fB\-\-cask\fR
 | 
			
		||||
Only check casks\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBman\fR [\fI\-\-fail\-if\-not\-changed\fR]"
 | 
			
		||||
Generate Homebrew\'s manpages\.
 | 
			
		||||
.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\-fail\-if\-not\-changed\fR
 | 
			
		||||
Return a failing status code if no changes are detected in the manpage outputs\. This can be used to notify CI 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)\.
 | 
			
		||||
.
 | 
			
		||||
.SS "\fBpr\-automerge\fR [\fIoptions\fR]"
 | 
			
		||||
Find pull requests that can be automatically merged using \fBbrew pr\-publish\fR\.
 | 
			
		||||
.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user