Skip to content

cmd/search: resolve error with regex#21811

Open
samford wants to merge 1 commit intomainfrom
search-resolve-error-with-regex
Open

cmd/search: resolve error with regex#21811
samford wants to merge 1 commit intomainfrom
search-resolve-error-with-regex

Conversation

@samford
Copy link
Member

@samford samford commented Mar 23, 2026


  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same change?
  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests (excluding integration tests) for your changes? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) with your changes locally?

  • AI was used to generate or assist with generating this PR. Please specify below how you used AI to help you, and what steps you have taken to manually verify the changes.

When a regex string like /jq/ is provided to brew search, it can sometimes produce an error like "Error: /opt/homebrew/opt//jq/ is not a valid keg". So far I've only seen this with a very small number of installed formulae (I only stumbled upon this by chance). I'm not sure why some regexes trigger this and others don't but it traces back to the Formulary.path call in MissingFormula.deleted_reason. Either way, MissingFormula.reason shouldn't be called when the query value is a regex string, so this adds a guard to prevent it.

When a regex string like `/jq/` is provided to `brew search`, it can
sometimes produce an error like "Error: /opt/homebrew/opt//jq/ is not
a valid keg". So far I've only seen this with a very small number of
installed formulae (I only stumbled upon this by chance). I'm not
sure why some regexes trigger this and others don't but it traces
back to the `Formulary.path` call in `MissingFormula.deleted_reason`.
Either way, `MissingFormula.reason` shouldn't be called when the
`query` value is a regex string, so this adds a guard to prevent it.
Copilot AI review requested due to automatic review settings March 23, 2026 19:04
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an error path in brew search when the user provides a regex query (e.g. /jq/), by preventing missing-formula lookup logic from running on regex-literal queries.

Changes:

  • Skip MissingFormula.reason when the search query is a /.../ regex literal.
  • Avoid triggering Formulary.path/keg-path resolution for regex queries when printing “missing formula” help.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

sig { params(query: String, found_matches: T::Boolean).void }
def print_missing_formula_help(query, found_matches)
return unless $stdout.tty?
return if query.start_with?("/") && query.end_with?("/")
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex-query guard duplicates the detection logic in Search.query_regexp (which currently uses %r{^/(.*)/$}). To avoid future divergence (e.g., if regex query syntax changes), consider using the same pattern here or extracting a shared helper/predicate for “query is a regex literal” and calling that from both places.

Suggested change
return if query.start_with?("/") && query.end_with?("/")
return if Search.query_regexp(query)

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed this is a good idea.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a regex constant [used in both places] be sufficient or is a method the preferred approach?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either is fine.

Comment on lines 156 to 162
sig { params(query: String, found_matches: T::Boolean).void }
def print_missing_formula_help(query, found_matches)
return unless $stdout.tty?
return if query.start_with?("/") && query.end_with?("/")

reason = MissingFormula.reason(query, silent: true)
return if reason.nil?
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change fixes a user-visible crash path for regex searches (e.g. brew search /jq/) by skipping MissingFormula.reason, but there’s no test asserting this behavior. Please add a spec (likely in Library/Homebrew/test/cmd/search_spec.rb) that stubs $stdout.tty? to true and verifies MissingFormula.reason is not invoked for /.../ queries, so the regression can’t reappear silently.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A non-integration spec for this seems nice.

Copy link
Member

@MikeMcQuaid MikeMcQuaid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Good once comments addressed.

sig { params(query: String, found_matches: T::Boolean).void }
def print_missing_formula_help(query, found_matches)
return unless $stdout.tty?
return if query.start_with?("/") && query.end_with?("/")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed this is a good idea.

Comment on lines 156 to 162
sig { params(query: String, found_matches: T::Boolean).void }
def print_missing_formula_help(query, found_matches)
return unless $stdout.tty?
return if query.start_with?("/") && query.end_with?("/")

reason = MissingFormula.reason(query, silent: true)
return if reason.nil?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A non-integration spec for this seems nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants