Skip to content

Commit 4be4225

Browse files
CopilotMikeMcQuaid
andcommitted
Add Go package support to Brewfile
Co-authored-by: MikeMcQuaid <[email protected]>
1 parent cd84e24 commit 4be4225

File tree

21 files changed

+308
-28
lines changed

21 files changed

+308
-28
lines changed

Library/Homebrew/.rubocop.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ Naming/PredicatePrefix:
2424
- is_32_bit?
2525
- is_64_bit?
2626

27+
Naming/MethodParameterName:
28+
AllowedNames:
29+
- go
30+
2731
# Only enforce documentation for public APIs.
2832
# Checked by the tests.yml syntax job
2933
Style/Documentation:

Library/Homebrew/bundle.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ def whalebrew_installed?
6262
@whalebrew_installed ||= which_formula?("whalebrew")
6363
end
6464

65+
sig { returns(T.nilable(Pathname)) }
66+
def which_go
67+
@which_go ||= which("go", ORIGINAL_PATHS)
68+
end
69+
70+
sig { returns(T::Boolean) }
71+
def go_installed?
72+
@go_installed ||= which_go.present?
73+
end
74+
6575
sig { returns(T::Boolean) }
6676
def cask_installed?
6777
@cask_installed ||= File.directory?("#{HOMEBREW_PREFIX}/Caskroom") &&
@@ -138,7 +148,9 @@ def reset!
138148
@mas_installed = T.let(nil, T.nilable(T::Boolean))
139149
@vscode_installed = T.let(nil, T.nilable(T::Boolean))
140150
@which_vscode = T.let(nil, T.nilable(Pathname))
151+
@which_go = T.let(nil, T.nilable(Pathname))
141152
@whalebrew_installed = T.let(nil, T.nilable(T::Boolean))
153+
@go_installed = T.let(nil, T.nilable(T::Boolean))
142154
@cask_installed = T.let(nil, T.nilable(T::Boolean))
143155
@formula_versions_from_env = T.let(nil, T.nilable(T::Hash[String, String]))
144156
@upgrade_formulae = T.let(nil, T.nilable(T::Array[String]))

Library/Homebrew/bundle/checker.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,13 @@ def find_actionable(entries, exit_on_first_error: false, no_upgrade: false, verb
5959
CheckResult = Struct.new :work_to_be_done, :errors
6060

6161
CHECKS = {
62-
taps_to_tap: "Taps",
63-
casks_to_install: "Casks",
64-
extensions_to_install: "VSCode Extensions",
65-
apps_to_install: "Apps",
66-
formulae_to_install: "Formulae",
67-
formulae_to_start: "Services",
62+
taps_to_tap: "Taps",
63+
casks_to_install: "Casks",
64+
extensions_to_install: "VSCode Extensions",
65+
apps_to_install: "Apps",
66+
formulae_to_install: "Formulae",
67+
formulae_to_start: "Services",
68+
go_packages_to_install: "Go Packages",
6869
}.freeze
6970

7071
def self.check(global: false, file: nil, exit_on_first_error: false, no_upgrade: false, verbose: false)
@@ -137,6 +138,14 @@ def self.formulae_to_start(exit_on_first_error: false, no_upgrade: false, verbos
137138
)
138139
end
139140

141+
def self.go_packages_to_install(exit_on_first_error: false, no_upgrade: false, verbose: false)
142+
require "bundle/go_checker"
143+
Homebrew::Bundle::Checker::GoChecker.new.find_actionable(
144+
@dsl.entries,
145+
exit_on_first_error:, no_upgrade:, verbose:,
146+
)
147+
end
148+
140149
def self.reset!
141150
require "bundle/cask_dumper"
142151
require "bundle/formula_dumper"

Library/Homebrew/bundle/commands/dump.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ module Dump
1010
sig {
1111
params(global: T::Boolean, file: T.nilable(String), describe: T::Boolean, force: T::Boolean,
1212
no_restart: T::Boolean, taps: T::Boolean, formulae: T::Boolean, casks: T::Boolean,
13-
mas: T::Boolean, whalebrew: T::Boolean, vscode: T::Boolean).void
13+
mas: T::Boolean, whalebrew: T::Boolean, vscode: T::Boolean, go: T::Boolean).void
1414
}
1515
def self.run(global:, file:, describe:, force:, no_restart:, taps:, formulae:, casks:, mas:, whalebrew:,
16-
vscode:)
16+
vscode:, go:)
1717
Homebrew::Bundle::Dumper.dump_brewfile(
1818
global:, file:, describe:, force:, no_restart:, taps:, formulae:, casks:, mas:, whalebrew:, vscode:,
19+
go:
1920
)
2021
end
2122
end

Library/Homebrew/bundle/commands/list.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ module Commands
1010
module List
1111
sig {
1212
params(global: T::Boolean, file: T.nilable(String), formulae: T::Boolean, casks: T::Boolean,
13-
taps: T::Boolean, mas: T::Boolean, whalebrew: T::Boolean, vscode: T::Boolean).void
13+
taps: T::Boolean, mas: T::Boolean, whalebrew: T::Boolean, vscode: T::Boolean,
14+
go: T::Boolean).void
1415
}
15-
def self.run(global:, file:, formulae:, casks:, taps:, mas:, whalebrew:, vscode:)
16+
def self.run(global:, file:, formulae:, casks:, taps:, mas:, whalebrew:, vscode:, go:)
1617
parsed_entries = Brewfile.read(global:, file:).entries
1718
Homebrew::Bundle::Lister.list(
1819
parsed_entries,
19-
formulae:, casks:, taps:, mas:, whalebrew:, vscode:,
20+
formulae:, casks:, taps:, mas:, whalebrew:, vscode:, go:,
2021
)
2122
end
2223
end

Library/Homebrew/bundle/dsl.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ def vscode(name)
8383
@entries << Entry.new(:vscode, name)
8484
end
8585

86+
sig { params(name: String).void }
87+
def go(name)
88+
@entries << Entry.new(:go, name)
89+
end
90+
8691
def tap(name, clone_target = nil, options = {})
8792
raise "name(#{name.inspect}) should be a String object" unless name.is_a? String
8893
if clone_target && !clone_target.is_a?(String)

Library/Homebrew/bundle/dumper.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,17 @@ module Dumper
2424
mas: T::Boolean,
2525
whalebrew: T::Boolean,
2626
vscode: T::Boolean,
27+
go: T::Boolean,
2728
).returns(String)
2829
}
29-
def self.build_brewfile(describe:, no_restart:, formulae:, taps:, casks:, mas:, whalebrew:, vscode:)
30+
def self.build_brewfile(describe:, no_restart:, formulae:, taps:, casks:, mas:, whalebrew:, vscode:, go:)
3031
require "bundle/tap_dumper"
3132
require "bundle/formula_dumper"
3233
require "bundle/cask_dumper"
3334
require "bundle/mac_app_store_dumper"
3435
require "bundle/whalebrew_dumper"
3536
require "bundle/vscode_extension_dumper"
37+
require "bundle/go_dumper"
3638

3739
content = []
3840
content << TapDumper.dump if taps
@@ -41,6 +43,7 @@ def self.build_brewfile(describe:, no_restart:, formulae:, taps:, casks:, mas:,
4143
content << MacAppStoreDumper.dump if mas
4244
content << WhalebrewDumper.dump if whalebrew
4345
content << VscodeExtensionDumper.dump if vscode
46+
content << GoDumper.dump if go
4447
"#{content.reject(&:empty?).join("\n")}\n"
4548
end
4649

@@ -57,13 +60,14 @@ def self.build_brewfile(describe:, no_restart:, formulae:, taps:, casks:, mas:,
5760
mas: T::Boolean,
5861
whalebrew: T::Boolean,
5962
vscode: T::Boolean,
63+
go: T::Boolean,
6064
).void
6165
}
6266
def self.dump_brewfile(global:, file:, describe:, force:, no_restart:, formulae:, taps:, casks:, mas:,
63-
whalebrew:, vscode:)
67+
whalebrew:, vscode:, go:)
6468
path = brewfile_path(global:, file:)
6569
can_write_to_brewfile?(path, force:)
66-
content = build_brewfile(describe:, no_restart:, taps:, formulae:, casks:, mas:, whalebrew:, vscode:)
70+
content = build_brewfile(describe:, no_restart:, taps:, formulae:, casks:, mas:, whalebrew:, vscode:, go:)
6771
write_file path, content
6872
end
6973

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
module Homebrew
5+
module Bundle
6+
module Checker
7+
class GoChecker < Homebrew::Bundle::Checker::Base
8+
PACKAGE_TYPE = :go
9+
PACKAGE_TYPE_NAME = "Go Package"
10+
11+
sig { params(package: String, no_upgrade: T::Boolean).returns(String) }
12+
def failure_reason(package, no_upgrade:)
13+
"#{PACKAGE_TYPE_NAME} #{package} needs to be installed."
14+
end
15+
16+
sig { params(package: String, no_upgrade: T::Boolean).returns(T::Boolean) }
17+
def installed_and_up_to_date?(package, no_upgrade: false)
18+
require "bundle/go_installer"
19+
Homebrew::Bundle::GoInstaller.package_installed?(package)
20+
end
21+
end
22+
end
23+
end
24+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
module Homebrew
5+
module Bundle
6+
module GoDumper
7+
sig { void }
8+
def self.reset!
9+
@packages = nil
10+
end
11+
12+
sig { returns(T::Array[String]) }
13+
def self.packages
14+
@packages ||= T.let(nil, T.nilable(T::Array[String]))
15+
@packages ||= if Bundle.go_installed?
16+
go = Bundle.which_go
17+
gobin = `#{go} env GOBIN`.chomp
18+
gopath = `#{go} env GOPATH`.chomp
19+
bin_dir = gobin.empty? ? "#{gopath}/bin" : gobin
20+
21+
return [] unless File.directory?(bin_dir)
22+
23+
binaries = Dir.glob("#{bin_dir}/*").select { |f| File.executable?(f) && !File.directory?(f) }
24+
25+
binaries.filter_map do |binary|
26+
output = `#{go} version -m "#{binary}" 2>/dev/null`
27+
next if output.empty?
28+
29+
# Parse the output to find the path line
30+
# Format: "\tpath\tgithub.com/user/repo"
31+
lines = output.split("\n")
32+
path_line = lines.find { |line| line.strip.start_with?("path\t") }
33+
next unless path_line
34+
35+
# Extract the package path (second field after splitting by tab)
36+
# The line format is: "\tpath\tgithub.com/user/repo"
37+
parts = path_line.split("\t")
38+
parts[2]&.strip if parts.length >= 3
39+
end.compact.uniq
40+
else
41+
[]
42+
end
43+
end
44+
45+
sig { returns(String) }
46+
def self.dump
47+
packages.map { |name| "go \"#{name}\"" }.join("\n")
48+
end
49+
end
50+
end
51+
end
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# typed: true # rubocop:todo Sorbet/StrictSigil
2+
# frozen_string_literal: true
3+
4+
module Homebrew
5+
module Bundle
6+
module GoInstaller
7+
def self.reset!
8+
@installed_packages = nil
9+
end
10+
11+
def self.preinstall!(name, verbose: false, **_options)
12+
unless Bundle.go_installed?
13+
puts "Installing go. It is not currently installed." if verbose
14+
Bundle.brew("install", "--formula", "go", verbose:)
15+
raise "Unable to install #{name} package. Go installation failed." unless Bundle.go_installed?
16+
end
17+
18+
if package_installed?(name)
19+
puts "Skipping install of #{name} Go package. It is already installed." if verbose
20+
return false
21+
end
22+
23+
true
24+
end
25+
26+
def self.install!(name, preinstall: true, verbose: false, force: false, **_options)
27+
return true unless preinstall
28+
29+
puts "Installing #{name} Go package. It is not currently installed." if verbose
30+
31+
go = Bundle.which_go
32+
return false unless Bundle.system go.to_s, "install", "#{name}@latest", verbose: verbose
33+
34+
installed_packages << name
35+
true
36+
end
37+
38+
def self.package_installed?(package)
39+
installed_packages.include? package
40+
end
41+
42+
def self.installed_packages
43+
require "bundle/go_dumper"
44+
@installed_packages ||= Homebrew::Bundle::GoDumper.packages
45+
end
46+
end
47+
end
48+
end

0 commit comments

Comments
 (0)