Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev-cmd/edit: suggest tapping core repositories if untapped #15740

Merged
merged 1 commit into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Library/Homebrew/cask/cask_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def self.can_load?(ref)

def initialize(token, from_json: nil)
@token = token.sub(%r{^homebrew/(?:homebrew-)?cask/}i, "")
@path = CaskLoader.default_path(token)
@path = CaskLoader.default_path(@token)
Copy link
Member Author

Choose a reason for hiding this comment

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

Fixes an issue where args in the form "user/repo/name" wouldn't be handled properly.

@from_json = from_json
end

Expand Down
15 changes: 11 additions & 4 deletions Library/Homebrew/cli/named_args.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,9 @@ def to_resolved_formulae_to_casks(only: parent&.only_formula_or_cask)
def to_paths(only: parent&.only_formula_or_cask, recurse_tap: false)
@to_paths ||= {}
@to_paths[only] ||= downcased_unique_named.flat_map do |name|
path = Pathname(name)
if File.exist?(name)
Pathname(name)
path
elsif name.count("/") == 1 && !name.start_with?("./", "/")
tap = Tap.fetch(name)

Expand All @@ -248,10 +249,16 @@ def to_paths(only: parent&.only_formula_or_cask, recurse_tap: false)

paths = []

paths << formula_path if formula_path.exist?
paths << cask_path if cask_path.exist?
if formula_path.exist? ||
(!CoreTap.instance.installed? && Homebrew::API::Formula.all_formulae.key?(path.basename))
paths << formula_path
end
if cask_path.exist? ||
(!CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(path.basename))
paths << cask_path
end

paths.empty? ? Pathname(name) : paths
paths.empty? ? path : paths
end
end.uniq.freeze
end
Expand Down
76 changes: 45 additions & 31 deletions Library/Homebrew/dev-cmd/edit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ module Homebrew
def edit_args
Homebrew::CLI::Parser.new do
description <<~EOS
Open a <formula> or <cask> in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
or open the Homebrew repository for editing if no formula is provided.
Open a <formula>, <cask> or <tap> in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
or open the Homebrew repository for editing if no argument is provided.
EOS

switch "--formula", "--formulae",
Expand All @@ -24,7 +24,7 @@ def edit_args

conflicts "--formula", "--cask"

named_args [:formula, :cask], without_api: true
named_args [:formula, :cask, :tap], without_api: true
Copy link
Member Author

Choose a reason for hiding this comment

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

This command hasn't advertised that it handles tap arguments too, until now.

end
end

Expand All @@ -50,42 +50,56 @@ def edit
[HOMEBREW_REPOSITORY]
end
else
edit_api_message_displayed = T.let(false, T::Boolean)
args.named.to_paths.select do |path|
next path if path.exist?
core_formula_path = path.fnmatch?("**/homebrew-core/Formula/**.rb", File::FNM_DOTMATCH)
core_cask_path = path.fnmatch?("**/homebrew-cask/Casks/**.rb", File::FNM_DOTMATCH)
core_formula_tap = path == CoreTap.instance.path
core_cask_tap = path == CoreCaskTap.instance.path

not_exist_message = if args.cask?
"#{path.basename(".rb")} doesn't exist on disk."
else
"#{path} doesn't exist on disk."
if path.exist?
if (core_formula_path || core_cask_path || core_formula_tap || core_cask_tap) &&
!edit_api_message_displayed &&
!Homebrew::EnvConfig.no_install_from_api? &&
!Homebrew::EnvConfig.no_env_hints?
opoo <<~EOS
Unless `HOMEBREW_NO_INSTALL_FROM_API` is set when running `brew install`,
it will ignore any locally edited #{(core_cask_path || core_cask_tap) ? "casks" : "formulae"}.
EOS
edit_api_message_displayed = true
end
next path
end

message = if args.cask?
<<~EOS
#{not_exist_message}
Run #{Formatter.identifier("brew create --cask --set-name #{path.basename(".rb")} $URL")} \
to create a new cask!
EOS
name = path.basename(".rb").to_s

if (tap_match = Regexp.new(HOMEBREW_TAP_DIR_REGEX.source + /$/.source).match(path.to_s))
Copy link
Member

Choose a reason for hiding this comment

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

Identifying the tap from a path seems like something we can extract to a method somewhere.

Copy link
Member Author

Choose a reason for hiding this comment

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

Any location in particular?

raise TapUnavailableError, CoreTap.instance.name if core_formula_tap
raise TapUnavailableError, CoreCaskTap.instance.name if core_cask_tap

raise TapUnavailableError, "#{tap_match[:user]}/#{tap_match[:repo]}"
elsif args.cask? || core_cask_path
if !CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(name)
command = "brew tap --force #{CoreCaskTap.instance.name}"
action = "tap #{CoreCaskTap.instance.name}"
else
command = "brew create --cask --set-name #{name} $URL"
action = "create a new cask"
end
elsif core_formula_path && !CoreTap.instance.installed? && Homebrew::API::Formula.all_formulae.key?(name)
command = "brew tap --force #{CoreTap.instance.name}"
action = "tap #{CoreTap.instance.name}"
else
<<~EOS
#{not_exist_message}
Run #{Formatter.identifier("brew create --set-name #{path.basename} $URL")} \
to create a new formula!
EOS
command = "brew create --set-name #{name} $URL"
action = "create a new formula"
end
raise UsageError, message
end.presence
end

if !Homebrew::EnvConfig.no_install_from_api? && !Homebrew::EnvConfig.no_env_hints?
paths.each do |path|
next if !path.fnmatch?("**/homebrew-core/Formula/*.rb") && !path.fnmatch?("**/homebrew-cask/Casks/*.rb")

opoo <<~EOS
Unless `HOMEBREW_NO_INSTALL_FROM_API` is set when running
`brew install`, it will ignore your locally edited formula.
message = <<~EOS
#{name} doesn't exist on disk.
Run #{Formatter.identifier(command)} to #{action}!
EOS
break
end
raise UsageError, message
end.presence
end

if args.print_path?
Expand Down
16 changes: 13 additions & 3 deletions Library/Homebrew/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,19 @@ class TapUnavailableError < RuntimeError
def initialize(name)
@name = name

super <<~EOS
No available tap #{name}.
EOS
message = "No available tap #{name}.\n"
if [CoreTap.instance.name, CoreCaskTap.instance.name].include?(name)
command = "brew tap --force #{name}"
message += <<~EOS
Run #{Formatter.identifier(command)} to tap #{name}!
EOS
else
command = "brew tap-new #{name}"
message += <<~EOS
Run #{Formatter.identifier(command)} to create a new #{name} tap!
EOS
end
super message.freeze
end
end

Expand Down
3 changes: 2 additions & 1 deletion Library/Homebrew/formulary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,8 @@ def self.tap_paths(name, taps = Tap)
end

def self.find_formula_in_tap(name, tap)
filename = "#{name}.rb"
filename = name.dup
filename << ".rb" unless filename.end_with?(".rb")

Tap.formula_files_by_name(tap).fetch(filename, tap.formula_dir/filename)
end
Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/test/exceptions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class Baz < Formula; end
describe TapUnavailableError do
subject { described_class.new("foo") }

its(:to_s) { is_expected.to eq("No available tap foo.\n") }
its(:to_s) { is_expected.to eq("No available tap foo.\nRun brew tap-new foo to create a new foo tap!\n") }
end

describe TapAlreadyTappedError do
Expand Down
1 change: 1 addition & 0 deletions completions/bash/brew
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ _brew_edit() {
esac
__brew_complete_formulae
__brew_complete_casks
__brew_complete_tapped
}

_brew_environment() {
Expand Down
3 changes: 2 additions & 1 deletion completions/fish/brew.fish
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ __fish_brew_complete_arg 'dr' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_arg 'dr' -a '(__fish_brew_suggest_diagnostic_checks)'


__fish_brew_complete_cmd 'edit' 'Open a formula or cask in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the Homebrew repository for editing if no formula is provided'
__fish_brew_complete_cmd 'edit' 'Open a formula, cask or tap in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the Homebrew repository for editing if no argument is provided'
__fish_brew_complete_arg 'edit' -l cask -d 'Treat all named arguments as casks'
__fish_brew_complete_arg 'edit' -l debug -d 'Display any debugging information'
__fish_brew_complete_arg 'edit' -l formula -d 'Treat all named arguments as formulae'
Expand All @@ -680,6 +680,7 @@ __fish_brew_complete_arg 'edit' -l quiet -d 'Make some output more quiet'
__fish_brew_complete_arg 'edit' -l verbose -d 'Make some output more verbose'
__fish_brew_complete_arg 'edit; and not __fish_seen_argument -l cask -l casks' -a '(__fish_brew_suggest_formulae_all)'
__fish_brew_complete_arg 'edit; and not __fish_seen_argument -l formula -l formulae' -a '(__fish_brew_suggest_casks_all)'
__fish_brew_complete_arg 'edit' -a '(__fish_brew_suggest_taps_installed)'


__fish_brew_complete_cmd 'environment' 'Summarise Homebrew\'s build environment as a plain list'
Expand Down
6 changes: 4 additions & 2 deletions completions/zsh/_brew
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ __brew_internal_commands() {
'dispatch-build-bottle:Build bottles for these formulae with GitHub Actions'
'docs:Open Homebrew'\''s online documentation (https://docs.brew.sh) in a browser'
'doctor:Check your system for potential problems'
'edit:Open a formula or cask in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the Homebrew repository for editing if no formula is provided'
'edit:Open a formula, cask or tap in the editor set by `EDITOR` or `HOMEBREW_EDITOR`, or open the Homebrew repository for editing if no argument is provided'
'extract:Look through repository history to find the most recent version of formula and create a copy in tap'
'fetch:Download a bottle (if available) or source packages for formulae and binaries for casks'
'formula:Display the path where formula is located'
Expand Down Expand Up @@ -853,7 +853,9 @@ _brew_edit() {
'*::formula:__brew_formulae' \
- cask \
'(--formula)--cask[Treat all named arguments as casks]' \
'*::cask:__brew_casks'
'*::cask:__brew_casks' \
- tap \
'*::tap:__brew_any_tap'
}

# brew environment
Expand Down
6 changes: 3 additions & 3 deletions docs/Manpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -1240,10 +1240,10 @@ Build bottles for these formulae with GitHub Actions.
* `--linux-wheezy`:
Use Debian Wheezy container for building the bottle on Linux.

### `edit` [*`options`*] [*`formula`*|*`cask`* ...]
### `edit` [*`options`*] [*`formula`*|*`cask`*|*`tap`* ...]

Open a *`formula`* or *`cask`* in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
or open the Homebrew repository for editing if no formula is provided.
Open a *`formula`*, *`cask`* or *`tap`* in the editor set by `EDITOR` or `HOMEBREW_EDITOR`,
or open the Homebrew repository for editing if no argument is provided.

* `--formula`:
Treat all named arguments as formulae.
Expand Down
4 changes: 2 additions & 2 deletions manpages/brew.1
Original file line number Diff line number Diff line change
Expand Up @@ -1804,8 +1804,8 @@ Dispatch bottle for Linux (using self\-hosted runner)\.
\fB\-\-linux\-wheezy\fR
Use Debian Wheezy container for building the bottle on Linux\.
.
.SS "\fBedit\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR \.\.\.]"
Open a \fIformula\fR or \fIcask\fR in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no formula is provided\.
.SS "\fBedit\fR [\fIoptions\fR] [\fIformula\fR|\fIcask\fR|\fItap\fR \.\.\.]"
Open a \fIformula\fR, \fIcask\fR or \fItap\fR in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no argument is provided\.
.
.TP
\fB\-\-formula\fR
Expand Down