Merge pull request #4316 from reitermarkus/merge-search

Merge `brew cask search` into `brew search`.
This commit is contained in:
Markus Reiter 2018-06-18 21:31:33 +02:00 committed by GitHub
commit 25542d7398
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 150 additions and 235 deletions

View File

@ -16,14 +16,15 @@ require "pathname"
HOMEBREW_LIBRARY_PATH = Pathname.new(__FILE__).realpath.parent
require "English"
unless $LOAD_PATH.include?(HOMEBREW_LIBRARY_PATH.to_s)
$LOAD_PATH.unshift(HOMEBREW_LIBRARY_PATH.to_s)
end
unless $LOAD_PATH.include?("#{HOMEBREW_LIBRARY_PATH}/cask/lib")
$LOAD_PATH.unshift("#{HOMEBREW_LIBRARY_PATH}/cask/lib")
end
unless $LOAD_PATH.include?(HOMEBREW_LIBRARY_PATH.to_s)
$LOAD_PATH.unshift(HOMEBREW_LIBRARY_PATH.to_s)
end
require "global"
begin

View File

@ -15,13 +15,11 @@ require "hbc/download"
require "hbc/download_strategy"
require "hbc/exceptions"
require "hbc/installer"
require "hbc/config"
require "hbc/macos"
require "hbc/pkg"
require "hbc/staged"
require "hbc/system_command"
require "hbc/topological_hash"
require "hbc/url"
require "hbc/utils"
require "hbc/verify"
require "hbc/version"

View File

@ -1,4 +1,5 @@
require "hbc/cask_loader"
require "hbc/config"
require "hbc/dsl"
require "hbc/metadata"
require "searchable"

View File

@ -2,6 +2,9 @@ require "optparse"
require "shellwords"
require "extend/optparse"
require "hbc/config"
require "hbc/cli/options"
require "hbc/cli/abstract_command"
@ -18,7 +21,6 @@ require "hbc/cli/install"
require "hbc/cli/list"
require "hbc/cli/outdated"
require "hbc/cli/reinstall"
require "hbc/cli/search"
require "hbc/cli/style"
require "hbc/cli/uninstall"
require "hbc/cli/upgrade"

View File

@ -1,9 +1,11 @@
require_relative "options"
require "search"
module Hbc
class CLI
class AbstractCommand
include Options
include Homebrew::Search
option "--[no-]binaries", :binaries, true
option "--debug", :debug, false
@ -50,7 +52,7 @@ module Hbc
end
def suggestion_message(cask_token)
matches, = Search.search(cask_token)
matches = search_casks(cask_token)
if matches.one?
"Did you mean “#{matches.first}”?"

View File

@ -1,53 +0,0 @@
require "search"
module Hbc
class CLI
class Search < AbstractCommand
extend Homebrew::Search
def run
if args.empty?
puts Formatter.columns(CLI.nice_listing(Cask.map(&:qualified_token)))
else
results = self.class.search(*args)
self.class.render_results(*results)
end
end
def self.search(*arguments)
query = arguments.join(" ")
string_or_regex = query_regexp(query)
local_results = search_casks(string_or_regex)
remote_matches = search_taps(query, silent: true)[:casks]
[local_results, remote_matches, query]
end
def self.render_results(partial_matches, remote_matches, search_term)
unless $stdout.tty?
puts [*partial_matches, *remote_matches]
return
end
if partial_matches.empty? && remote_matches.empty?
puts "No Cask found for \"#{search_term}\"."
return
end
unless partial_matches.empty?
ohai "Matches"
puts Formatter.columns(partial_matches)
end
return if remote_matches.empty?
ohai "Remote Matches"
puts Formatter.columns(remote_matches)
end
def self.help
"searches all known Casks"
end
end
end
end

View File

@ -1,3 +1,5 @@
require "hbc/utils"
require "hbc/container/base"
require "hbc/container/air"
require "hbc/container/bzip2"

View File

@ -2,6 +2,9 @@ require "locale"
require "hbc/artifact"
require "hbc/caskroom"
require "hbc/exceptions"
require "hbc/dsl/appcast"
require "hbc/dsl/base"
require "hbc/dsl/caveats"
@ -16,6 +19,8 @@ require "hbc/dsl/uninstall_postflight"
require "hbc/dsl/uninstall_preflight"
require "hbc/dsl/version"
require "hbc/url"
module Hbc
class DSL
ORDINARY_ARTIFACT_CLASSES = [

View File

@ -52,38 +52,41 @@ module Homebrew
return
end
if args.remaining.empty?
if args.remaining.empty? && !args.desc?
puts Formatter.columns(Formula.full_names.sort)
elsif args.desc?
query = args.remaining.join(" ")
string_or_regex = query_regexp(query)
Descriptions.search(string_or_regex, :desc).print
elsif args.remaining.first =~ HOMEBREW_TAP_FORMULA_REGEX
query = args.remaining.first
return
end
results = begin
[Formulary.factory(query).name]
rescue FormulaUnavailableError
_, _, name = query.split("/", 3)
remote_results = search_taps(name)
[*remote_results[:formulae], *remote_results[:casks]].sort
query = args.remaining.join(" ")
string_or_regex = query_regexp(query)
if args.desc?
search_descriptions(string_or_regex)
else
remote_results = search_taps(query, silent: true)
local_formulae = search_formulae(string_or_regex)
remote_formulae = remote_results[:formulae]
all_formulae = local_formulae + remote_formulae
local_casks = search_casks(string_or_regex)
remote_casks = remote_results[:casks]
all_casks = local_casks + remote_casks
if all_formulae.any?
ohai "Formulae"
puts Formatter.columns(all_formulae)
end
puts Formatter.columns(results) unless results.empty?
else
query = args.remaining.join(" ")
string_or_regex = query_regexp(query)
local_results = search_formulae(string_or_regex)
puts Formatter.columns(local_results.sort) unless local_results.empty?
remote_results = search_taps(query)
tap_results = [*remote_results[:formulae], *remote_results[:casks]].sort
puts Formatter.columns(tap_results) unless tap_results.empty?
if all_casks.any?
puts if all_formulae.any?
ohai "Casks"
puts Formatter.columns(all_casks)
end
if $stdout.tty?
count = local_results.length + tap_results.length
count = all_formulae.count + all_casks.count
ohai "Searching blacklisted, migrated and deleted formulae..."
if reason = MissingFormula.reason(query, silent: true)
if count.positive?
puts
@ -91,7 +94,7 @@ module Homebrew
end
puts reason
elsif count.zero?
puts "No formula found for #{query.inspect}."
puts "No formula or cask found for #{query.inspect}."
GitHub.print_pull_requests_matching(query)
end
end

View File

@ -1,4 +1,5 @@
require "compat/hbc/cask_loader"
require "compat/hbc/cli/search"
require "compat/hbc/cli/update"
require "compat/hbc/cache"
require "compat/hbc/caskroom"

View File

@ -1,4 +1,4 @@
require "cask/lib/hbc/cli/options"
require "hbc/cli/options"
module Hbc
class CLI

View File

@ -0,0 +1,21 @@
require "hbc/cli/abstract_command"
require "cmd/search"
module Hbc
class CLI
module Compat
class Search < AbstractCommand
def run
odeprecated "`brew cask search`", "`brew search`"
Homebrew.search(args)
end
def self.visible
false
end
end
end
prepend Compat
end
end

View File

@ -1,10 +1,10 @@
require "cask/lib/hbc/cli/abstract_command"
require "hbc/cli/abstract_command"
module Hbc
class CLI
module Compat
class Update < AbstractCommand
def self.run(*_ignored)
def run
odisabled "`brew cask update`", "`brew update`"
end

View File

@ -47,4 +47,7 @@ unless defined? HOMEBREW_LIBRARY_PATH
end
# Load path used by standalone scripts to access the Homebrew code base
HOMEBREW_LOAD_PATH = HOMEBREW_LIBRARY_PATH
HOMEBREW_LOAD_PATH = [
HOMEBREW_LIBRARY_PATH,
HOMEBREW_LIBRARY_PATH/"cask/lib",
].join(File::PATH_SEPARATOR)

View File

@ -8,6 +8,6 @@ module Homebrew
module_function
def ruby
exec ENV["HOMEBREW_RUBY_PATH"], "-I#{HOMEBREW_LIBRARY_PATH}", "-rglobal", "-rdev-cmd/irb", *ARGV
exec ENV["HOMEBREW_RUBY_PATH"], "-I", HOMEBREW_LOAD_PATH, "-rglobal", "-rdev-cmd/irb", *ARGV
end
end

View File

@ -0,0 +1,43 @@
require "hbc/cask"
require "hbc/cask_loader"
module Homebrew
module Search
module Extension
def search_descriptions(string_or_regex)
super
puts
ohai "Casks"
Hbc::Cask.to_a.extend(Searchable)
.search(string_or_regex, &:name)
.each do |cask|
puts "#{Tty.bold}#{cask.token}:#{Tty.reset} #{cask.name.join(", ")}"
end
end
def search_casks(string_or_regex)
if string_or_regex.is_a?(String) && string_or_regex.match?(HOMEBREW_TAP_CASK_REGEX)
return begin
[Hbc::CaskLoader.load(string_or_regex).token]
rescue Hbc::CaskUnavailableError
[]
end
end
results = Hbc::Cask.search(string_or_regex, &:token).sort_by(&:token)
results.map do |cask|
if cask.installed?
pretty_installed(cask.token)
else
cask.token
end
end
end
end
prepend Extension
end
end

View File

@ -0,0 +1 @@
require "extend/os/mac/search" if OS.mac?

View File

@ -1,5 +1,4 @@
require "searchable"
require "hbc/cask"
module Homebrew
module Search
@ -13,7 +12,16 @@ module Homebrew
raise "#{query} is not a valid regex."
end
def search_descriptions(string_or_regex)
ohai "Formulae"
Descriptions.search(string_or_regex, :desc).print
end
def search_taps(query, silent: false)
if query.match?(Regexp.union(HOMEBREW_TAP_FORMULA_REGEX, HOMEBREW_TAP_CASK_REGEX))
_, _, query = query.split("/", 3)
end
results = { formulae: [], casks: [] }
return results if ENV["HOMEBREW_NO_GITHUB_API"]
@ -40,7 +48,7 @@ module Homebrew
tap = Tap.fetch(match["repository"]["full_name"])
full_name = "#{tap.name}/#{name}"
next if tap.installed? && !match["path"].start_with?("Casks/")
next if tap.installed?
if match["path"].start_with?("Casks/")
results[:casks] = [*results[:casks], full_name].sort
@ -53,8 +61,13 @@ module Homebrew
end
def search_formulae(string_or_regex)
# Use stderr to avoid breaking parsed output
$stderr.puts Formatter.headline("Searching local taps...", color: :blue)
if string_or_regex.is_a?(String) && string_or_regex.match?(HOMEBREW_TAP_FORMULA_REGEX)
return begin
[Formulary.factory(string_or_regex).name]
rescue FormulaUnavailableError
[]
end
end
aliases = Formula.alias_full_names
results = (Formula.full_names + aliases)
@ -81,16 +94,10 @@ module Homebrew
end.compact
end
def search_casks(string_or_regex)
results = Hbc::Cask.search(string_or_regex, &:token).sort_by(&:token)
results.map do |cask|
if cask.installed?
pretty_installed(cask.token)
else
cask.token
end
end
def search_casks(_string_or_regex)
[]
end
end
end
require "extend/os/search"

View File

@ -1,123 +0,0 @@
require_relative "shared_examples/invalid_option"
describe Hbc::CLI::Search, :cask do
before do
allow(Tty).to receive(:width).and_return(0)
end
it_behaves_like "a command that handles invalid options"
it "lists the available Casks that match the search term" do
allow(GitHub).to receive(:search_code).and_return([])
expect {
Hbc::CLI::Search.run("local")
}.to output(<<~EOS).to_stdout.as_tty
==> Matches
local-caffeine
local-transmission
EOS
end
it "outputs a plain list when stdout is not a TTY" do
allow(GitHub).to receive(:search_code).and_return([])
expect {
Hbc::CLI::Search.run("local")
}.to output(<<~EOS).to_stdout
local-caffeine
local-transmission
EOS
end
it "returns matches even when online search failed" do
allow(GitHub).to receive(:search_code).and_raise(GitHub::Error.new("reason"))
expect {
Hbc::CLI::Search.run("local")
}.to output(<<~EOS).to_stdout
local-caffeine
local-transmission
EOS
.and output(/^Warning: Error searching on GitHub: reason/).to_stderr
end
it "shows that there are no Casks matching a search term that did not result in anything" do
expect {
Hbc::CLI::Search.run("foo-bar-baz")
}.to output(<<~EOS).to_stdout.as_tty
No Cask found for "foo-bar-baz".
EOS
end
it "doesn't output anything to non-TTY stdout when there are no matches" do
allow(GitHub).to receive(:search_code).and_return([])
expect { Hbc::CLI::Search.run("foo-bar-baz") }
.to not_to_output.to_stdout
.and not_to_output.to_stderr
end
it "lists all Casks available offline with no search term" do
allow(GitHub).to receive(:search_code).and_raise(GitHub::Error.new("reason"))
expect { Hbc::CLI::Search.run }
.to output(/local-caffeine/).to_stdout.as_tty
.and not_to_output.to_stderr
end
it "ignores hyphens in search terms" do
expect {
Hbc::CLI::Search.run("lo-cal-caffeine")
}.to output(/local-caffeine/).to_stdout.as_tty
end
it "ignores hyphens in Cask tokens" do
expect {
Hbc::CLI::Search.run("localcaffeine")
}.to output(/local-caffeine/).to_stdout.as_tty
end
it "accepts multiple arguments" do
expect {
Hbc::CLI::Search.run("local caffeine")
}.to output(/local-caffeine/).to_stdout.as_tty
end
it "accepts a regexp argument" do
expect {
Hbc::CLI::Search.run("/^local-c[a-z]ffeine$/")
}.to output(<<~EOS).to_stdout.as_tty
==> Matches
local-caffeine
EOS
end
it "returns both exact and partial matches" do
expect {
Hbc::CLI::Search.run("test-opera")
}.to output(<<~EOS).to_stdout.as_tty
==> Matches
test-opera
test-opera-mail
EOS
end
it "does not search the Tap name" do
expect {
Hbc::CLI::Search.run("caskroom")
}.to output(<<~EOS).to_stdout.as_tty
No Cask found for "caskroom".
EOS
end
it "highlights installed packages" do
Hbc::CLI::Install.run("local-caffeine")
expect {
Hbc::CLI::Search.run("local-caffeine")
}.to output(<<~EOS).to_stdout.as_tty
==> Matches
local-caffeine
EOS
end
end

View File

@ -15,7 +15,6 @@ describe "brew search", :integration_test do
it "supports searching by name" do
expect { brew "search", "testball" }
.to output(/testball/).to_stdout
.and output(/Searching/).to_stderr
.and be_a_success
end
@ -31,7 +30,6 @@ describe "brew search", :integration_test do
expect { brew "search", "homebrew/cask/firefox" }
.to output(/firefox/).to_stdout
.and output(/Searching/).to_stderr
.and be_a_success
end

View File

@ -14,8 +14,8 @@ require "rubocop"
require "rubocop/rspec/support"
require "find"
$LOAD_PATH.unshift(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew"))
$LOAD_PATH.unshift(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/cask/lib"))
$LOAD_PATH.unshift(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew"))
$LOAD_PATH.unshift(File.expand_path("#{ENV["HOMEBREW_LIBRARY"]}/Homebrew/test/support/lib"))
require "global"

View File

@ -83,9 +83,7 @@ RSpec.shared_context "integration test" do
@ruby_args ||= begin
ruby_args = [
"-W0",
"-I", "#{HOMEBREW_LIBRARY_PATH}/test/support/lib",
"-I", HOMEBREW_LIBRARY_PATH.to_s,
"-I", "#{HOMEBREW_LIBRARY_PATH}/cask/lib",
"-I", HOMEBREW_LOAD_PATH,
"-rconfig"
]
if ENV["HOMEBREW_TESTS_COVERAGE"]

View File

@ -15,7 +15,11 @@ end
# Paths pointing into the Homebrew code base that persist across test runs
HOMEBREW_LIBRARY_PATH = Pathname.new(File.expand_path("../../..", __dir__))
HOMEBREW_SHIMS_PATH = HOMEBREW_LIBRARY_PATH.parent+"Homebrew/shims"
HOMEBREW_LOAD_PATH = [File.expand_path(__dir__), HOMEBREW_LIBRARY_PATH].join(":")
HOMEBREW_LOAD_PATH = [
File.expand_path(__dir__),
HOMEBREW_LIBRARY_PATH,
HOMEBREW_LIBRARY_PATH.join("cask/lib"),
].join(File::PATH_SEPARATOR)
# Paths redirected to a temporary directory and wiped at the end of the test run
HOMEBREW_PREFIX = Pathname.new(TEST_TMPDIR).join("prefix")

View File

@ -16,6 +16,7 @@ require "time"
def require?(path)
return false if path.nil?
require path
true
rescue LoadError => e
# we should raise on syntax errors but not if the file doesn't exist.
raise unless e.message.include?(path)