aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Library/Homebrew/cask/lib/hbc/cli/search.rb5
-rw-r--r--Library/Homebrew/cask/lib/hbc/dsl/conflicts_with.rb19
-rw-r--r--Library/Homebrew/cask/lib/hbc/exceptions.rb13
-rw-r--r--Library/Homebrew/cask/lib/hbc/installer.rb17
-rw-r--r--Library/Homebrew/cmd/search.rb5
-rw-r--r--Library/Homebrew/test/cask/conflicts_with_spec.rb23
-rw-r--r--Library/Homebrew/test/support/fixtures/cask/Casks/with-conflicts-with.rb2
-rw-r--r--Library/Homebrew/test/utils/github_spec.rb30
-rw-r--r--Library/Homebrew/utils/github.rb78
9 files changed, 128 insertions, 64 deletions
diff --git a/Library/Homebrew/cask/lib/hbc/cli/search.rb b/Library/Homebrew/cask/lib/hbc/cli/search.rb
index 643d18d55..e89dced92 100644
--- a/Library/Homebrew/cask/lib/hbc/cli/search.rb
+++ b/Library/Homebrew/cask/lib/hbc/cli/search.rb
@@ -15,8 +15,9 @@ module Hbc
end
def self.search_remote(query)
- matches = GitHub.search_code("user:caskroom", "path:Casks", "filename:#{query}", "extension:rb")
- [*matches].map do |match|
+ matches = GitHub.search_code(user: "caskroom", path: "Casks",
+ filename: query, extension: "rb")
+ matches.map do |match|
tap = Tap.fetch(match["repository"]["full_name"])
next if tap.installed?
"#{tap.name}/#{File.basename(match["path"], ".rb")}"
diff --git a/Library/Homebrew/cask/lib/hbc/dsl/conflicts_with.rb b/Library/Homebrew/cask/lib/hbc/dsl/conflicts_with.rb
index 948348239..dfaa55a5c 100644
--- a/Library/Homebrew/cask/lib/hbc/dsl/conflicts_with.rb
+++ b/Library/Homebrew/cask/lib/hbc/dsl/conflicts_with.rb
@@ -10,25 +10,20 @@ module Hbc
:java,
]
- attr_accessor(*VALID_KEYS)
- attr_accessor :pairs
+ attr_reader *VALID_KEYS
def initialize(pairs = {})
@pairs = pairs
+
+ VALID_KEYS.each do |key|
+ instance_variable_set("@#{key}", Set.new)
+ end
+
pairs.each do |key, value|
raise "invalid conflicts_with key: '#{key.inspect}'" unless VALID_KEYS.include?(key)
- writer_method = "#{key}=".to_sym
- send(writer_method, value)
+ instance_variable_set("@#{key}", instance_variable_get("@#{key}").merge([*value]))
end
end
-
- def to_yaml
- @pairs.to_yaml
- end
-
- def to_s
- @pairs.inspect
- end
end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/exceptions.rb b/Library/Homebrew/cask/lib/hbc/exceptions.rb
index 1a246be65..f7f9e43b6 100644
--- a/Library/Homebrew/cask/lib/hbc/exceptions.rb
+++ b/Library/Homebrew/cask/lib/hbc/exceptions.rb
@@ -17,6 +17,19 @@ module Hbc
end
end
+ class CaskConflictError < AbstractCaskErrorWithToken
+ attr_reader :conflicting_cask
+
+ def initialize(token, conflicting_cask)
+ super(token)
+ @conflicting_cask = conflicting_cask
+ end
+
+ def to_s
+ "Cask '#{token}' conflicts with '#{conflicting_cask}'."
+ end
+ end
+
class CaskUnavailableError < AbstractCaskErrorWithToken
def to_s
"Cask '#{token}' is unavailable" << (reason.empty? ? "." : ": #{reason}")
diff --git a/Library/Homebrew/cask/lib/hbc/installer.rb b/Library/Homebrew/cask/lib/hbc/installer.rb
index 53210ed4b..37cc4e561 100644
--- a/Library/Homebrew/cask/lib/hbc/installer.rb
+++ b/Library/Homebrew/cask/lib/hbc/installer.rb
@@ -86,6 +86,8 @@ module Hbc
raise CaskAlreadyInstalledError, @cask
end
+ check_conflicts
+
print_caveats
fetch
uninstall_existing_cask if @reinstall
@@ -98,6 +100,21 @@ module Hbc
puts summary
end
+ def check_conflicts
+ return unless @cask.conflicts_with
+
+ @cask.conflicts_with.cask.each do |conflicting_cask|
+ begin
+ conflicting_cask = CaskLoader.load(conflicting_cask)
+ if conflicting_cask.installed?
+ raise CaskConflictError.new(@cask, conflicting_cask)
+ end
+ rescue CaskUnavailableError
+ next # Ignore conflicting Casks that do not exist.
+ end
+ end
+ end
+
def reinstall
odebug "Hbc::Installer#reinstall"
@reinstall = true
diff --git a/Library/Homebrew/cmd/search.rb b/Library/Homebrew/cmd/search.rb
index 53767e75f..0718a3af4 100644
--- a/Library/Homebrew/cmd/search.rb
+++ b/Library/Homebrew/cmd/search.rb
@@ -109,8 +109,9 @@ module Homebrew
$stderr.puts Formatter.headline("Searching taps on GitHub...", color: :blue)
valid_dirnames = ["Formula", "HomebrewFormula", "Casks", "."].freeze
- matches = GitHub.search_code("user:Homebrew", "user:caskroom", "filename:#{query}", "extension:rb")
- [*matches].map do |match|
+ matches = GitHub.search_code(user: ["Homebrew", "caskroom"], filename: query, extension: "rb")
+
+ matches.map do |match|
dirname, filename = File.split(match["path"])
next unless valid_dirnames.include?(dirname)
tap = Tap.fetch(match["repository"]["full_name"])
diff --git a/Library/Homebrew/test/cask/conflicts_with_spec.rb b/Library/Homebrew/test/cask/conflicts_with_spec.rb
new file mode 100644
index 000000000..0dc51cb2d
--- /dev/null
+++ b/Library/Homebrew/test/cask/conflicts_with_spec.rb
@@ -0,0 +1,23 @@
+describe "conflicts_with", :cask do
+ describe "conflicts_with cask" do
+ let(:local_caffeine) {
+ Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/local-caffeine.rb")
+ }
+
+ let(:with_conflicts_with) {
+ Hbc::CaskLoader.load_from_file(TEST_FIXTURE_DIR/"cask/Casks/with-conflicts-with.rb")
+ }
+
+ it "installs the dependency of a Cask and the Cask itself", :focus do
+ Hbc::Installer.new(local_caffeine).install
+
+ expect(local_caffeine).to be_installed
+
+ expect {
+ Hbc::Installer.new(with_conflicts_with).install
+ }.to raise_error(Hbc::CaskConflictError, "Cask 'with-conflicts-with' conflicts with 'local-caffeine'.")
+
+ expect(with_conflicts_with).not_to be_installed
+ end
+ end
+end
diff --git a/Library/Homebrew/test/support/fixtures/cask/Casks/with-conflicts-with.rb b/Library/Homebrew/test/support/fixtures/cask/Casks/with-conflicts-with.rb
index ab3631743..13d1fc4fc 100644
--- a/Library/Homebrew/test/support/fixtures/cask/Casks/with-conflicts-with.rb
+++ b/Library/Homebrew/test/support/fixtures/cask/Casks/with-conflicts-with.rb
@@ -5,7 +5,7 @@ cask 'with-conflicts-with' do
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
homepage 'http://example.com/with-conflicts-with'
- conflicts_with formula: 'unar'
+ conflicts_with cask: 'local-caffeine'
app 'Caffeine.app'
end
diff --git a/Library/Homebrew/test/utils/github_spec.rb b/Library/Homebrew/test/utils/github_spec.rb
index 9b539262f..9322898ee 100644
--- a/Library/Homebrew/test/utils/github_spec.rb
+++ b/Library/Homebrew/test/utils/github_spec.rb
@@ -2,12 +2,38 @@ require "utils/github"
describe GitHub do
describe "::search_code", :needs_network do
- it "searches code" do
- results = subject.search_code("repo:Homebrew/brew", "path:/", "filename:readme", "language:markdown")
+ it "queries GitHub code with the passed paramaters" do
+ results = subject.search_code(repo: "Homebrew/brew", path: "/",
+ filename: "readme", language: "markdown")
expect(results.count).to eq(1)
expect(results.first["name"]).to eq("README.md")
expect(results.first["path"]).to eq("README.md")
end
end
+
+ describe "::query_string" do
+ it "builds a query with the given hash parameters formatted as key:value" do
+ query = subject.query_string(user: "Homebrew", repo: "brew")
+ expect(query).to eq("q=user%3AHomebrew+repo%3Abrew&per_page=100")
+ end
+
+ it "adds a variable number of top-level string parameters to the query when provided" do
+ query = subject.query_string("value1", "value2", user: "Homebrew")
+ expect(query).to eq("q=value1+value2+user%3AHomebrew&per_page=100")
+ end
+
+ it "turns array values into multiple key:value parameters" do
+ query = subject.query_string(user: ["Homebrew", "caskroom"])
+ expect(query).to eq("q=user%3AHomebrew+user%3Acaskroom&per_page=100")
+ end
+ end
+
+ describe "::search_issues", :needs_network do
+ it "queries GitHub issues with the passed parameters" do
+ results = subject.search_issues("brew search", repo: "Homebrew/brew", author: "avetamine", is: "closed")
+ expect(results).not_to be_empty
+ expect(results.last["title"]).to eq("brew search : 422 Unprocessable Entity")
+ end
+ end
end
diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb
index 07eea4384..a1cf5fbba 100644
--- a/Library/Homebrew/utils/github.rb
+++ b/Library/Homebrew/utils/github.rb
@@ -133,7 +133,7 @@ module GitHub
def open(url, data: nil, scopes: [].freeze)
# This is a no-op if the user is opting out of using the GitHub API.
- return if ENV["HOMEBREW_NO_GITHUB_API"]
+ return block_given? ? yield({}) : {} if ENV["HOMEBREW_NO_GITHUB_API"]
args = %W[--header application/vnd.github.v3+json --write-out \n%{http_code}]
args += curl_args
@@ -227,72 +227,60 @@ module GitHub
end
end
- def issues_matching(query, qualifiers = {})
- uri = URI.parse("#{API_URL}/search/issues")
- uri.query = build_query_string(query, qualifiers)
- open(uri) { |json| json["items"] }
+ def search_issues(query, **qualifiers)
+ search("issues", query, **qualifiers)
end
def repository(user, repo)
- open(URI.parse("#{API_URL}/repos/#{user}/#{repo}"))
+ open(url_to("repos", user, repo))
end
- def search_code(*params)
- uri = URI.parse("#{API_URL}/search/code")
- uri.query = "q=#{uri_escape(params.join(" "))}"
- open(uri) { |json| json["items"] }
- end
-
- def build_query_string(query, qualifiers)
- s = "q=#{uri_escape(query)}+"
- s << build_search_qualifier_string(qualifiers)
- s << "&per_page=100"
- end
-
- def build_search_qualifier_string(qualifiers)
- {
- repo: "Homebrew/homebrew-core",
- in: "title",
- }.update(qualifiers).map do |qualifier, value|
- "#{qualifier}:#{value}"
- end.join("+")
- end
-
- def uri_escape(query)
- if URI.respond_to?(:encode_www_form_component)
- URI.encode_www_form_component(query)
- else
- require "erb"
- ERB::Util.url_encode(query)
- end
+ def search_code(**qualifiers)
+ search("code", **qualifiers)
end
def issues_for_formula(name, options = {})
tap = options[:tap] || CoreTap.instance
- issues_matching(name, state: "open", repo: "#{tap.user}/homebrew-#{tap.repo}")
+ search_issues(name, state: "open", repo: "#{tap.user}/homebrew-#{tap.repo}")
end
def print_pull_requests_matching(query)
- return [] if ENV["HOMEBREW_NO_GITHUB_API"]
-
- open_or_closed_prs = issues_matching(query, type: "pr")
+ open_or_closed_prs = search_issues(query, type: "pr")
open_prs = open_or_closed_prs.select { |i| i["state"] == "open" }
- if !open_prs.empty?
+ prs = if !open_prs.empty?
puts "Open pull requests:"
- prs = open_prs
- elsif !open_or_closed_prs.empty?
- puts "Closed pull requests:"
- prs = open_or_closed_prs
+ open_prs
else
- return
+ puts "Closed pull requests:" unless open_or_closed_prs.empty?
+ open_or_closed_prs
end
prs.each { |i| puts "#{i["title"]} (#{i["html_url"]})" }
end
def private_repo?(full_name)
- uri = URI.parse("#{API_URL}/repos/#{full_name}")
+ uri = url_to "repos", full_name
open(uri) { |json| json["private"] }
end
+
+ def query_string(*main_params, **qualifiers)
+ params = main_params
+
+ params += qualifiers.flat_map do |key, value|
+ Array(value).map { |v| "#{key}:#{v}" }
+ end
+
+ "q=#{URI.encode_www_form_component(params.join(" "))}&per_page=100"
+ end
+
+ def url_to(*subroutes)
+ URI.parse([API_URL, *subroutes].join("/"))
+ end
+
+ def search(entity, *queries, **qualifiers)
+ uri = url_to "search", entity
+ uri.query = query_string(*queries, **qualifiers)
+ open(uri) { |json| json.fetch("items", []) }
+ end
end