diff options
| -rw-r--r-- | Library/Homebrew/cask/lib/hbc/cli/search.rb | 5 | ||||
| -rw-r--r-- | Library/Homebrew/cask/lib/hbc/dsl/conflicts_with.rb | 19 | ||||
| -rw-r--r-- | Library/Homebrew/cask/lib/hbc/exceptions.rb | 13 | ||||
| -rw-r--r-- | Library/Homebrew/cask/lib/hbc/installer.rb | 17 | ||||
| -rw-r--r-- | Library/Homebrew/cmd/search.rb | 5 | ||||
| -rw-r--r-- | Library/Homebrew/test/cask/conflicts_with_spec.rb | 23 | ||||
| -rw-r--r-- | Library/Homebrew/test/support/fixtures/cask/Casks/with-conflicts-with.rb | 2 | ||||
| -rw-r--r-- | Library/Homebrew/test/utils/github_spec.rb | 30 | ||||
| -rw-r--r-- | Library/Homebrew/utils/github.rb | 78 |
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 |
