diff --git a/Library/Homebrew/brew.rb b/Library/Homebrew/brew.rb index c453938981..0abb8d37b1 100644 --- a/Library/Homebrew/brew.rb +++ b/Library/Homebrew/brew.rb @@ -78,8 +78,8 @@ begin # - no arguments are passed # - if cmd is Cask, let Cask handle the help command instead if (empty_argv || help_flag) && cmd != "cask" - require "cmd/help" - Homebrew.help cmd, empty_argv: empty_argv + require "help" + Homebrew::Help.help cmd, empty_argv: empty_argv # `Homebrew.help` never returns, except for external/unknown commands. end @@ -119,8 +119,8 @@ begin exec HOMEBREW_BREW_FILE, cmd, *ARGV end rescue UsageError => e - require "cmd/help" - Homebrew.help cmd, usage_error: e.message + require "help" + Homebrew::Help.help cmd, usage_error: e.message rescue SystemExit => e onoe "Kernel.exit" if ARGV.verbose? && !e.success? $stderr.puts e.backtrace if ARGV.debug? diff --git a/Library/Homebrew/cmd/--cache.rb b/Library/Homebrew/cmd/--cache.rb index 2c407cefe0..9298bdb455 100644 --- a/Library/Homebrew/cmd/--cache.rb +++ b/Library/Homebrew/cmd/--cache.rb @@ -1,10 +1,10 @@ #: * `--cache`: #: Display Homebrew's download cache. See also `HOMEBREW_CACHE`. #: -#: * `--cache` : +#: * `--cache` [`--build-from-source`|`-s`] [`--force-bottle`] : #: Display the file or directory used to cache . -require "cmd/fetch" +require "fetch" module Homebrew module_function @@ -14,7 +14,7 @@ module Homebrew puts HOMEBREW_CACHE else ARGV.formulae.each do |f| - if fetch_bottle?(f) + if Fetch.fetch_bottle?(f) puts f.bottle.cached_download else puts f.cached_download diff --git a/Library/Homebrew/cmd/fetch.rb b/Library/Homebrew/cmd/fetch.rb index f150d8f16a..c518600e9c 100644 --- a/Library/Homebrew/cmd/fetch.rb +++ b/Library/Homebrew/cmd/fetch.rb @@ -23,6 +23,7 @@ #: installation. require "formula" +require "fetch" module Homebrew module_function @@ -46,7 +47,7 @@ module Homebrew f.print_tap_action verb: "Fetching" fetched_bottle = false - if fetch_bottle?(f) + if Fetch.fetch_bottle?(f) begin fetch_formula(f.bottle) rescue Interrupt @@ -73,14 +74,6 @@ module Homebrew end end - def fetch_bottle?(f) - return true if ARGV.force_bottle? && f.bottle - return false unless f.bottle && f.pour_bottle? - return false if ARGV.build_formula_from_source?(f) - return false unless f.bottle.compatible_cellar? - true - end - def fetch_resource(r) puts "Resource: #{r.name}" fetch_fetchable r diff --git a/Library/Homebrew/cmd/help.rb b/Library/Homebrew/cmd/help.rb index fa5727816e..84d28ab358 100644 --- a/Library/Homebrew/cmd/help.rb +++ b/Library/Homebrew/cmd/help.rb @@ -1,91 +1,7 @@ -HOMEBREW_HELP = <<~EOS.freeze - Example usage: - brew search [TEXT|/REGEX/] - brew info [FORMULA...] - brew install FORMULA... - brew update - brew upgrade [FORMULA...] - brew uninstall FORMULA... - brew list [FORMULA...] - - Troubleshooting: - brew config - brew doctor - brew install --verbose --debug FORMULA - - Contributing: - brew create [URL [--no-fetch]] - brew edit [FORMULA...] - - Further help: - brew commands - brew help [COMMAND] - man brew - https://docs.brew.sh -EOS - -# NOTE Keep the lenth of vanilla --help less than 25 lines! -# This is because the default Terminal height is 25 lines. Scrolling sucks -# and concision is important. If more help is needed we should start -# specialising help like the gem command does. -# NOTE Keep lines less than 80 characters! Wrapping is just not cricket. -# NOTE The reason the string is at the top is so 25 lines is easy to measure! - -require "commands" +require "help" module Homebrew - module_function - def help(cmd = nil, flags = {}) - # Resolve command aliases and find file containing the implementation. - if cmd - cmd = HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd) - path = Commands.path(cmd) - path ||= which("brew-#{cmd}") - path ||= which("brew-#{cmd}.rb") - end - - # Display command-specific (or generic) help in response to `UsageError`. - if (error_message = flags[:usage_error]) - $stderr.puts path ? command_help(path) : HOMEBREW_HELP - $stderr.puts - onoe error_message - exit 1 - end - - # Handle `brew` (no arguments). - if flags[:empty_argv] - $stderr.puts HOMEBREW_HELP - exit 1 - end - - # Handle `brew (-h|--help|--usage|-?|help)` (no other arguments). - if cmd.nil? - puts HOMEBREW_HELP - exit 0 - end - - # Resume execution in `brew.rb` for unknown commands. - return if path.nil? - - # Display help for internal command (or generic help if undocumented). - puts command_help(path) - exit 0 - end - - def command_help(path) - help_lines = command_help_lines(path) - if help_lines.empty? - opoo "No help text in: #{path}" if ARGV.homebrew_developer? - HOMEBREW_HELP - else - help_lines.map do |line| - line.sub(/^ \* /, "#{Tty.bold}brew#{Tty.reset} ") - .gsub(/`(.*?)`/, "#{Tty.bold}\\1#{Tty.reset}") - .gsub(%r{<([^\s]+?://[^\s]+?)>}) { |url| Formatter.url(url) } - .gsub(/<(.*?)>/, "#{Tty.underline}\\1#{Tty.reset}") - .gsub("@hide_from_man_page", "") - end.join.strip - end + Help.help(cmd, flags) end end diff --git a/Library/Homebrew/cmd/install.rb b/Library/Homebrew/cmd/install.rb index 21ea88193a..4b699474e1 100644 --- a/Library/Homebrew/cmd/install.rb +++ b/Library/Homebrew/cmd/install.rb @@ -68,11 +68,10 @@ #: creating patches to the software. require "missing_formula" -require "diagnostic" require "cmd/search" require "formula_installer" -require "hardware" require "development_tools" +require "install" module Homebrew module_function @@ -238,7 +237,7 @@ module Homebrew end return if formulae.empty? - perform_preinstall_checks + Install.perform_preinstall_checks formulae.each do |f| Migrator.migrate_if_needed(f) @@ -298,47 +297,6 @@ module Homebrew end end - def check_ppc - case Hardware::CPU.type - when :ppc - abort <<~EOS - Sorry, Homebrew does not support your computer's CPU architecture. - For PPC support, see: https://github.com/mistydemeo/tigerbrew - EOS - end - end - - def check_writable_install_location - raise "Cannot write to #{HOMEBREW_CELLAR}" if HOMEBREW_CELLAR.exist? && !HOMEBREW_CELLAR.writable_real? - raise "Cannot write to #{HOMEBREW_PREFIX}" unless HOMEBREW_PREFIX.writable_real? || HOMEBREW_PREFIX.to_s == "/usr/local" - end - - def check_development_tools - checks = Diagnostic::Checks.new - checks.fatal_development_tools_checks.each do |check| - out = checks.send(check) - next if out.nil? - ofail out - end - exit 1 if Homebrew.failed? - end - - def check_cellar - FileUtils.mkdir_p HOMEBREW_CELLAR unless File.exist? HOMEBREW_CELLAR - rescue - raise <<~EOS - Could not create #{HOMEBREW_CELLAR} - Check you have permission to write to #{HOMEBREW_CELLAR.parent} - EOS - end - - def perform_preinstall_checks - check_ppc - check_writable_install_location - check_development_tools if DevelopmentTools.installed? - check_cellar - end - def install_formula(f) f.print_tap_action build_options = f.build diff --git a/Library/Homebrew/cmd/link.rb b/Library/Homebrew/cmd/link.rb index 5afb19ed61..a412ca2f52 100644 --- a/Library/Homebrew/cmd/link.rb +++ b/Library/Homebrew/cmd/link.rb @@ -26,7 +26,7 @@ module Homebrew mode.dry_run = true if ARGV.dry_run? ARGV.kegs.each do |keg| - keg_only = keg_only?(keg.rack) + keg_only = Formulary.keg_only?(keg.rack) if HOMEBREW_PREFIX.to_s == "/usr/local" && keg_only && keg.name.start_with?("openssl", "libressl") opoo <<~EOS @@ -87,10 +87,4 @@ module Homebrew puts " #{Utils::Shell.prepend_path_in_profile(opt/"bin")}" if bin.directory? puts " #{Utils::Shell.prepend_path_in_profile(opt/"sbin")}" if sbin.directory? end - - def keg_only?(rack) - Formulary.from_rack(rack).keg_only? - rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError - false - end end diff --git a/Library/Homebrew/cmd/style.rb b/Library/Homebrew/cmd/style.rb index 7487c51214..5a050d1cd0 100644 --- a/Library/Homebrew/cmd/style.rb +++ b/Library/Homebrew/cmd/style.rb @@ -21,6 +21,7 @@ require "json" require "open3" +require "style" module Homebrew module_function @@ -53,153 +54,6 @@ module Homebrew NewFormulaAudit] end - Homebrew.failed = check_style_and_print(target, options) - end - - # Checks style for a list of files, printing simple RuboCop output. - # Returns true if violations were found, false otherwise. - def check_style_and_print(files, options = {}) - check_style_impl(files, :print, options) - end - - # Checks style for a list of files, returning results as a RubocopResults - # object parsed from its JSON output. - def check_style_json(files, options = {}) - check_style_impl(files, :json, options) - end - - def check_style_impl(files, output_type, options = {}) - fix = options[:fix] - - Homebrew.install_gem_setup_path! "rubocop", HOMEBREW_RUBOCOP_VERSION - require "rubocop" - require_relative "../rubocops" - - args = %w[ - --force-exclusion - ] - if fix - args << "--auto-correct" - else - args << "--parallel" - end - - if ARGV.include?("--rspec") - Homebrew.install_gem! "rubocop-rspec" - args += %w[--require rubocop-rspec] - end - - if options[:except_cops] - options[:except_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") } - cops_to_exclude = options[:except_cops].select do |cop| - RuboCop::Cop::Cop.registry.names.include?(cop) || - RuboCop::Cop::Cop.registry.departments.include?(cop.to_sym) - end - - args << "--except" << cops_to_exclude.join(",") unless cops_to_exclude.empty? - elsif options[:only_cops] - options[:only_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") } - cops_to_include = options[:only_cops].select do |cop| - RuboCop::Cop::Cop.registry.names.include?(cop) || - RuboCop::Cop::Cop.registry.departments.include?(cop.to_sym) - end - - if cops_to_include.empty? - odie "RuboCops #{options[:only_cops].join(",")} were not found" - end - - args << "--only" << cops_to_include.join(",") - end - - if files.nil? - config_file = ARGV.include?("--rspec") ? ".rubocop-rspec.yml" : ".rubocop.yml" - args << "--config" << HOMEBREW_LIBRARY_PATH/config_file - args << HOMEBREW_LIBRARY_PATH - else - args << "--config" << HOMEBREW_LIBRARY/".rubocop_audit.yml" - args += files - end - - cache_env = { "XDG_CACHE_HOME" => "#{HOMEBREW_CACHE}/style" } - - case output_type - when :print - args << "--debug" if ARGV.debug? - args << "--display-cop-names" if ARGV.include? "--display-cop-names" - args << "--format" << "simple" if files - system(cache_env, "rubocop", "_#{HOMEBREW_RUBOCOP_VERSION}_", *args) - !$CHILD_STATUS.success? - when :json - json, _, status = Open3.capture3(cache_env, "rubocop", "_#{HOMEBREW_RUBOCOP_VERSION}_", "--format", "json", *args) - # exit status of 1 just means violations were found; other numbers mean - # execution errors. - # exitstatus can also be nil if RuboCop process crashes, e.g. due to - # native extension problems. - # JSON needs to be at least 2 characters. - if !(0..1).cover?(status.exitstatus) || json.to_s.length < 2 - raise "Error running `rubocop --format json #{args.join " "}`" - end - RubocopResults.new(JSON.parse(json)) - else - raise "Invalid output_type for check_style_impl: #{output_type}" - end - end - - class RubocopResults - def initialize(json) - @metadata = json["metadata"] - @file_offenses = {} - json["files"].each do |f| - next if f["offenses"].empty? - file = File.realpath(f["path"]) - @file_offenses[file] = f["offenses"].map { |x| RubocopOffense.new(x) } - end - end - - def file_offenses(path) - @file_offenses[path.to_s] - end - end - - class RubocopOffense - attr_reader :severity, :message, :corrected, :location, :cop_name - - def initialize(json) - @severity = json["severity"] - @message = json["message"] - @cop_name = json["cop_name"] - @corrected = json["corrected"] - @location = RubocopLineLocation.new(json["location"]) - end - - def severity_code - @severity[0].upcase - end - - def to_s(options = {}) - if options[:display_cop_name] - "#{severity_code}: #{location.to_short_s}: #{cop_name}: #{message}" - else - "#{severity_code}: #{location.to_short_s}: #{message}" - end - end - end - - class RubocopLineLocation - attr_reader :line, :column, :length - - def initialize(json) - @line = json["line"] - @column = json["column"] - @length = json["length"] - end - - def to_s - "#{line}: col #{column} (#{length} chars)" - end - - def to_short_s - "#{line}: col #{column}" - end + Homebrew.failed = Style.check_style_and_print(target, options) end end diff --git a/Library/Homebrew/cmd/switch.rb b/Library/Homebrew/cmd/switch.rb index b0ac32626e..1393e3052f 100644 --- a/Library/Homebrew/cmd/switch.rb +++ b/Library/Homebrew/cmd/switch.rb @@ -3,7 +3,6 @@ require "formula" require "keg" -require "cmd/link" module Homebrew module_function @@ -53,7 +52,7 @@ module Homebrew keg = Keg.new(rack/version) # Link new version, if not keg-only - if keg_only?(rack) + if Formulary.keg_only?(rack) keg.optlink puts "Opt link created for #{keg}" else diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index 340037a2ba..9023451013 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -17,7 +17,8 @@ #: If are given, upgrade only the specified brews (unless they #: are pinned; see `pin`, `unpin`). -require "cmd/install" +require "install" +require "formula_installer" require "cleanup" require "development_tools" @@ -27,7 +28,7 @@ module Homebrew def upgrade FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed? - Homebrew.perform_preinstall_checks + Install.perform_preinstall_checks odisabled "'brew upgrade --all'", "'brew upgrade'" if ARGV.include?("--all") diff --git a/Library/Homebrew/dev-cmd/audit.rb b/Library/Homebrew/dev-cmd/audit.rb index 61cede8f27..2352fd0b4f 100644 --- a/Library/Homebrew/dev-cmd/audit.rb +++ b/Library/Homebrew/dev-cmd/audit.rb @@ -43,7 +43,7 @@ require "utils/curl" require "extend/ENV" require "formula_cellar_checks" require "cmd/search" -require "cmd/style" +require "style" require "date" require "missing_formula" require "digest" @@ -116,7 +116,7 @@ module Homebrew options[:display_cop_names] = args.display_cop_names? # Check style in a single batch run up front for performance - style_results = check_style_json(files, options) + style_results = Style.check_style_json(files, options) new_formula_problem_lines = [] ff.sort.each do |f| diff --git a/Library/Homebrew/fetch.rb b/Library/Homebrew/fetch.rb new file mode 100644 index 0000000000..ca060a36c3 --- /dev/null +++ b/Library/Homebrew/fetch.rb @@ -0,0 +1,13 @@ +module Homebrew + module Fetch + module_function + + def fetch_bottle?(f) + return true if ARGV.force_bottle? && f.bottle + return false unless f.bottle && f.pour_bottle? + return false if ARGV.build_formula_from_source?(f) + return false unless f.bottle.compatible_cellar? + true + end + end +end diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index eab57183bc..112b296dc4 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -298,6 +298,13 @@ module Formulary end end + # Return whether given rack is keg-only + def self.keg_only?(rack) + Formulary.from_rack(rack).keg_only? + rescue FormulaUnavailableError, TapFormulaAmbiguityError, TapFormulaWithOldnameAmbiguityError + false + end + # Return a Formula instance for the given keg. # It will auto resolve formula's spec when requested spec is nil def self.from_keg(keg, spec = nil, alias_path: nil) diff --git a/Library/Homebrew/help.rb b/Library/Homebrew/help.rb new file mode 100644 index 0000000000..76ddbb79e9 --- /dev/null +++ b/Library/Homebrew/help.rb @@ -0,0 +1,93 @@ +HOMEBREW_HELP = <<~EOS.freeze + Example usage: + brew search [TEXT|/REGEX/] + brew info [FORMULA...] + brew install FORMULA... + brew update + brew upgrade [FORMULA...] + brew uninstall FORMULA... + brew list [FORMULA...] + + Troubleshooting: + brew config + brew doctor + brew install --verbose --debug FORMULA + + Contributing: + brew create [URL [--no-fetch]] + brew edit [FORMULA...] + + Further help: + brew commands + brew help [COMMAND] + man brew + https://docs.brew.sh +EOS + +# NOTE Keep the length of vanilla --help less than 25 lines! +# This is because the default Terminal height is 25 lines. Scrolling sucks +# and concision is important. If more help is needed we should start +# specialising help like the gem command does. +# NOTE Keep lines less than 80 characters! Wrapping is just not cricket. +# NOTE The reason the string is at the top is so 25 lines is easy to measure! + +require "commands" + +module Homebrew + module Help + module_function + + def help(cmd = nil, flags = {}) + # Resolve command aliases and find file containing the implementation. + if cmd + cmd = HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd) + path = Commands.path(cmd) + path ||= which("brew-#{cmd}") + path ||= which("brew-#{cmd}.rb") + end + + # Display command-specific (or generic) help in response to `UsageError`. + if (error_message = flags[:usage_error]) + $stderr.puts path ? command_help(path) : HOMEBREW_HELP + $stderr.puts + onoe error_message + exit 1 + end + + # Handle `brew` (no arguments). + if flags[:empty_argv] + $stderr.puts HOMEBREW_HELP + exit 1 + end + + # Handle `brew (-h|--help|--usage|-?|help)` (no other arguments). + if cmd.nil? + puts HOMEBREW_HELP + exit 0 + end + + # Resume execution in `brew.rb` for unknown commands. + return if path.nil? + + # Display help for internal command (or generic help if undocumented). + puts command_help(path) + exit 0 + end + + def command_help(path) + help_lines = command_help_lines(path) + if help_lines.empty? + opoo "No help text in: #{path}" if ARGV.homebrew_developer? + HOMEBREW_HELP + else + help_lines.map do |line| + line.sub(/^ \* /, "#{Tty.bold}brew#{Tty.reset} ") + .gsub(/`(.*?)`/, "#{Tty.bold}\\1#{Tty.reset}") + .gsub(%r{<([^\s]+?://[^\s]+?)>}) { |url| Formatter.url(url) } + .gsub(/<(.*?)>/, "#{Tty.underline}\\1#{Tty.reset}") + .gsub("@hide_from_man_page", "") + end.join.strip + end + end + end +end diff --git a/Library/Homebrew/install.rb b/Library/Homebrew/install.rb new file mode 100644 index 0000000000..f426db2b09 --- /dev/null +++ b/Library/Homebrew/install.rb @@ -0,0 +1,54 @@ +require "diagnostic" +require "fileutils" +require "hardware" +require "development_tools" + +module Homebrew + module Install + module_function + + def check_ppc + case Hardware::CPU.type + when :ppc + abort <<~EOS + Sorry, Homebrew does not support your computer's CPU architecture. + For PPC support, see: https://github.com/mistydemeo/tigerbrew + EOS + end + end + + def check_writable_install_location + if HOMEBREW_CELLAR.exist? && !HOMEBREW_CELLAR.writable_real? + raise "Cannot write to #{HOMEBREW_CELLAR}" + end + prefix_writable = HOMEBREW_PREFIX.writable_real? || HOMEBREW_PREFIX.to_s == "/usr/local" + raise "Cannot write to #{HOMEBREW_PREFIX}" unless prefix_writable + end + + def check_development_tools + checks = Diagnostic::Checks.new + checks.fatal_development_tools_checks.each do |check| + out = checks.send(check) + next if out.nil? + ofail out + end + exit 1 if Homebrew.failed? + end + + def check_cellar + FileUtils.mkdir_p HOMEBREW_CELLAR unless File.exist? HOMEBREW_CELLAR + rescue + raise <<~EOS + Could not create #{HOMEBREW_CELLAR} + Check you have permission to write to #{HOMEBREW_CELLAR.parent} + EOS + end + + def perform_preinstall_checks + check_ppc + check_writable_install_location + check_development_tools if DevelopmentTools.installed? + check_cellar + end + end +end diff --git a/Library/Homebrew/style.rb b/Library/Homebrew/style.rb new file mode 100644 index 0000000000..acd3be45c1 --- /dev/null +++ b/Library/Homebrew/style.rb @@ -0,0 +1,152 @@ +module Homebrew + module Style + module_function + + # Checks style for a list of files, printing simple RuboCop output. + # Returns true if violations were found, false otherwise. + def check_style_and_print(files, options = {}) + check_style_impl(files, :print, options) + end + + # Checks style for a list of files, returning results as a RubocopResults + # object parsed from its JSON output. + def check_style_json(files, options = {}) + check_style_impl(files, :json, options) + end + + def check_style_impl(files, output_type, options = {}) + fix = options[:fix] + + Homebrew.install_gem_setup_path! "rubocop", HOMEBREW_RUBOCOP_VERSION + require "rubocop" + require "rubocops" + + args = %w[ + --force-exclusion + ] + if fix + args << "--auto-correct" + else + args << "--parallel" + end + + if ARGV.include?("--rspec") + Homebrew.install_gem! "rubocop-rspec" + args += %w[--require rubocop-rspec] + end + + if options[:except_cops] + options[:except_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") } + cops_to_exclude = options[:except_cops].select do |cop| + RuboCop::Cop::Cop.registry.names.include?(cop) || + RuboCop::Cop::Cop.registry.departments.include?(cop.to_sym) + end + + args << "--except" << cops_to_exclude.join(",") unless cops_to_exclude.empty? + elsif options[:only_cops] + options[:only_cops].map! { |cop| RuboCop::Cop::Cop.registry.qualified_cop_name(cop.to_s, "") } + cops_to_include = options[:only_cops].select do |cop| + RuboCop::Cop::Cop.registry.names.include?(cop) || + RuboCop::Cop::Cop.registry.departments.include?(cop.to_sym) + end + + if cops_to_include.empty? + odie "RuboCops #{options[:only_cops].join(",")} were not found" + end + + args << "--only" << cops_to_include.join(",") + end + + if files.nil? + config_file = ARGV.include?("--rspec") ? ".rubocop-rspec.yml" : ".rubocop.yml" + args << "--config" << HOMEBREW_LIBRARY_PATH/config_file + args << HOMEBREW_LIBRARY_PATH + else + args << "--config" << HOMEBREW_LIBRARY/".rubocop_audit.yml" + args += files + end + + cache_env = { "XDG_CACHE_HOME" => "#{HOMEBREW_CACHE}/style" } + + case output_type + when :print + args << "--debug" if ARGV.debug? + args << "--display-cop-names" if ARGV.include? "--display-cop-names" + args << "--format" << "simple" if files + system(cache_env, "rubocop", "_#{HOMEBREW_RUBOCOP_VERSION}_", *args) + !$CHILD_STATUS.success? + when :json + json, _, status = Open3.capture3(cache_env, "rubocop", "_#{HOMEBREW_RUBOCOP_VERSION}_", "--format", "json", *args) + # exit status of 1 just means violations were found; other numbers mean + # execution errors. + # exitstatus can also be nil if RuboCop process crashes, e.g. due to + # native extension problems. + # JSON needs to be at least 2 characters. + if !(0..1).cover?(status.exitstatus) || json.to_s.length < 2 + raise "Error running `rubocop --format json #{args.join " "}`" + end + RubocopResults.new(JSON.parse(json)) + else + raise "Invalid output_type for check_style_impl: #{output_type}" + end + end + + class RubocopResults + def initialize(json) + @metadata = json["metadata"] + @file_offenses = {} + json["files"].each do |f| + next if f["offenses"].empty? + file = File.realpath(f["path"]) + @file_offenses[file] = f["offenses"].map { |x| RubocopOffense.new(x) } + end + end + + def file_offenses(path) + @file_offenses[path.to_s] + end + end + + class RubocopOffense + attr_reader :severity, :message, :corrected, :location, :cop_name + + def initialize(json) + @severity = json["severity"] + @message = json["message"] + @cop_name = json["cop_name"] + @corrected = json["corrected"] + @location = RubocopLineLocation.new(json["location"]) + end + + def severity_code + @severity[0].upcase + end + + def to_s(options = {}) + if options[:display_cop_name] + "#{severity_code}: #{location.to_short_s}: #{cop_name}: #{message}" + else + "#{severity_code}: #{location.to_short_s}: #{message}" + end + end + end + + class RubocopLineLocation + attr_reader :line, :column, :length + + def initialize(json) + @line = json["line"] + @column = json["column"] + @length = json["length"] + end + + def to_s + "#{line}: col #{column} (#{length} chars)" + end + + def to_short_s + "#{line}: col #{column}" + end + end + end +end diff --git a/Library/Homebrew/test/cmd/style_spec.rb b/Library/Homebrew/test/cmd/style_spec.rb index ec0eccdff1..c8ccbfbac8 100644 --- a/Library/Homebrew/test/cmd/style_spec.rb +++ b/Library/Homebrew/test/cmd/style_spec.rb @@ -25,7 +25,7 @@ describe "brew style" do end EOS - rubocop_result = Homebrew.check_style_json([formula]) + rubocop_result = Homebrew::Style.check_style_json([formula]) expect(rubocop_result.file_offenses(formula.realpath.to_s).map(&:message)) .to include("Extra empty line detected at class body beginning.") diff --git a/docs/Manpage.md b/docs/Manpage.md index cf94d6ede4..fe58e52db5 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -597,7 +597,7 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note * `--cache`: Display Homebrew's download cache. See also `HOMEBREW_CACHE`. - * `--cache` `formula`: + * `--cache` [`--build-from-source`|`-s`] [`--force-bottle`] `formula`: Display the file or directory used to cache `formula`. * `--cellar`: diff --git a/manpages/brew-cask.1 b/manpages/brew-cask.1 index 1b2c9fae75..efe64e5988 100644 --- a/manpages/brew-cask.1 +++ b/manpages/brew-cask.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BREW\-CASK" "1" "May 2018" "Homebrew" "brew-cask" +.TH "BREW\-CASK" "1" "June 2018" "Homebrew" "brew-cask" . .SH "NAME" \fBbrew\-cask\fR \- a friendly binary installer for macOS diff --git a/manpages/brew.1 b/manpages/brew.1 index ac0c4b8e85..ee8c04b94a 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BREW" "1" "May 2018" "Homebrew" "brew" +.TH "BREW" "1" "June 2018" "Homebrew" "brew" . .SH "NAME" \fBbrew\fR \- The missing package manager for macOS @@ -610,7 +610,7 @@ By default, \fBuses\fR shows usage of \fIformulae\fR by stable builds\. To find Display Homebrew\'s download cache\. See also \fBHOMEBREW_CACHE\fR\. . .TP -\fB\-\-cache\fR \fIformula\fR +\fB\-\-cache\fR [\fB\-\-build\-from\-source\fR|\fB\-s\fR] [\fB\-\-force\-bottle\fR] \fIformula\fR Display the file or directory used to cache \fIformula\fR\. . .TP