Skip to content

Commit c5d091a

Browse files
committed
Refactor/typecheck create and formula_creator
1 parent 85d48da commit c5d091a

3 files changed

Lines changed: 84 additions & 76 deletions

File tree

Library/Homebrew/dev-cmd/create.rb

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def create_formula
183183
:zig
184184
end
185185

186-
fc = FormulaCreator.new(
186+
formula_creator = FormulaCreator.new(
187187
url: args.named.fetch(0),
188188
name: args.set_name,
189189
version: args.set_version,
@@ -193,50 +193,52 @@ def create_formula
193193
fetch: !args.no_fetch?,
194194
head: args.HEAD?,
195195
)
196+
196197
# ask for confirmation if name wasn't passed explicitly
197198
if args.set_name.blank?
198-
print "Formula name [#{fc.name}]: "
199-
fc.name = __gets || fc.name
199+
print "Formula name [#{formula_creator.name}]: "
200+
confirmed_name = __gets.presence
201+
formula_creator.name = confirmed_name if confirmed_name.present?
200202
end
201203

202-
fc.verify
204+
formula_creator.verify_tap_available!
203205

204206
# Check for disallowed formula, or names that shadow aliases,
205207
# unless --force is specified.
206208
unless args.force?
207-
if (reason = MissingFormula.disallowed_reason(T.must(fc.name)))
209+
if (reason = MissingFormula.disallowed_reason(formula_creator.name))
208210
odie <<~EOS
209-
The formula '#{fc.name}' is not allowed to be created.
211+
The formula '#{formula_creator.name}' is not allowed to be created.
210212
#{reason}
211213
If you really want to create this formula use `--force`.
212214
EOS
213215
end
214216

215217
Homebrew.with_no_api_env do
216-
if Formula.aliases.include? fc.name
217-
realname = Formulary.canonical_name(fc.name)
218+
if Formula.aliases.include?(formula_creator.name)
219+
realname = Formulary.canonical_name(formula_creator.name)
218220
odie <<~EOS
219-
The formula '#{realname}' is already aliased to '#{fc.name}'.
221+
The formula '#{realname}' is already aliased to '#{formula_creator.name}'.
220222
Please check that you are not creating a duplicate.
221223
To force creation use `--force`.
222224
EOS
223225
end
224226
end
225227
end
226228

227-
path = fc.write_formula!
229+
path = formula_creator.write_formula!
228230

229231
formula = Homebrew.with_no_api_env do
230232
CoreTap.instance.clear_cache
231-
Formula[T.must(fc.name)]
233+
Formula[formula_creator.name]
232234
end
233235
PyPI.update_python_resources! formula, ignore_non_pypi_packages: true if args.python?
234236

235237
puts <<~EOS
236238
Please audit and test formula before submitting:
237-
HOMEBREW_NO_INSTALL_FROM_API=1 brew audit --new #{fc.name}
238-
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug #{fc.name}
239-
HOMEBREW_NO_INSTALL_FROM_API=1 brew test #{fc.name}
239+
HOMEBREW_NO_INSTALL_FROM_API=1 brew audit --new #{formula_creator.name}
240+
HOMEBREW_NO_INSTALL_FROM_API=1 brew install --build-from-source --verbose --debug #{formula_creator.name}
241+
HOMEBREW_NO_INSTALL_FROM_API=1 brew test #{formula_creator.name}
240242
EOS
241243
path
242244
end

Library/Homebrew/formula_creator.rb

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# typed: true # rubocop:todo Sorbet/StrictSigil
1+
# typed: strict
22
# frozen_string_literal: true
33

44
require "digest"
@@ -7,10 +7,10 @@
77
module Homebrew
88
# Class for generating a formula from a template.
99
class FormulaCreator
10-
sig { returns(T.nilable(String)) }
10+
sig { returns(String) }
1111
attr_accessor :name
1212

13-
sig { returns(T.nilable(Version)) }
13+
sig { returns(Version) }
1414
attr_reader :version
1515

1616
sig { returns(T::Boolean) }
@@ -22,55 +22,66 @@ class FormulaCreator
2222
}
2323
def initialize(url:, name: nil, version: nil, tap: nil, mode: nil, license: nil, fetch: false, head: false)
2424
@url = url
25-
@name = name.presence
26-
@version = T.let(Version.new(version), T.nilable(Version)) if version.present?
27-
@tap = T.let(Tap.fetch(tap.presence || "homebrew/core"), Tap)
28-
@mode = T.let(mode.presence, T.nilable(Symbol))
29-
@license = T.let(license.presence, T.nilable(String))
30-
@fetch = fetch
31-
@head = head
32-
33-
parse_url
34-
end
3525

36-
sig { void }
37-
def verify
38-
raise TapUnavailableError, @tap.name unless @tap.installed?
39-
end
40-
41-
sig { void }
42-
def parse_url
43-
@name ||= begin
44-
stem = Pathname.new(@url).stem
45-
name = if stem.start_with? "index.cgi"
26+
if name.blank?
27+
stem = Pathname.new(url).stem
28+
name = if stem.start_with?("index.cgi") && stem.include?("=")
4629
# special cases first
4730
# gitweb URLs e.g. http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary
4831
stem.rpartition("=").last
49-
elsif @url =~ %r{github\.com/\S+/(\S+)/(archive|releases)/}
32+
elsif url =~ %r{github\.com/\S+/(\S+)/(archive|releases)/}
5033
# e.g. https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz
51-
Regexp.last_match(1)
34+
T.must(Regexp.last_match(1))
5235
else
5336
# e.g. http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz
5437
pathver = Version.parse(stem).to_s
5538
stem.sub(/[-_.]?#{Regexp.escape(pathver)}$/, "")
5639
end
5740
odebug "name from url: #{name}"
58-
name
5941
end
42+
@name = T.let(name, String)
43+
44+
version = if version.present?
45+
Version.new(version)
46+
else
47+
Version.detect(url)
48+
end
49+
@version = T.let(version, Version)
6050

61-
@version ||= Version.detect(@url)
51+
tap = if tap.blank?
52+
CoreTap.instance
53+
else
54+
Tap.fetch(tap)
55+
end
56+
@tap = T.let(tap, Tap)
6257

63-
case @url
58+
@mode = T.let(mode.presence, T.nilable(Symbol))
59+
@license = T.let(license.presence, T.nilable(String))
60+
@fetch = fetch
61+
62+
case url
6463
when %r{github\.com/(\S+)/(\S+)\.git}
65-
@head = true
64+
head = true
6665
user = Regexp.last_match(1)
67-
repo = Regexp.last_match(2)
68-
@github = GitHub.repository(user, repo) if @fetch
66+
repository = Regexp.last_match(2)
67+
github = GitHub.repository(user, repository) if fetch
6968
when %r{github\.com/(\S+)/(\S+)/(archive|releases)/}
7069
user = Regexp.last_match(1)
71-
repo = Regexp.last_match(2)
72-
@github = GitHub.repository(user, repo) if @fetch
70+
repository = Regexp.last_match(2)
71+
github = GitHub.repository(user, repository) if fetch
7372
end
73+
@head = head
74+
@github = T.let(github, T.untyped)
75+
76+
@sha256 = T.let(nil, T.nilable(String))
77+
@desc = T.let(nil, T.nilable(String))
78+
@homepage = T.let(nil, T.nilable(String))
79+
@license = T.let(nil, T.nilable(String))
80+
end
81+
82+
sig { void }
83+
def verify_tap_available!
84+
raise TapUnavailableError, @tap.name unless @tap.installed?
7485
end
7586

7687
sig { returns(Pathname) }
@@ -114,6 +125,8 @@ def write_formula!
114125
path
115126
end
116127

128+
private
129+
117130
sig { params(name: String).returns(String) }
118131
def latest_versioned_formula(name)
119132
name_prefix = "#{name}@"

Library/Homebrew/test/formula_creator_spec.rb

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,41 @@
66
describe ".new" do
77
tests = {
88
"generic tarball URL": {
9-
url: "http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz",
10-
expected: {
11-
name: "synscan",
12-
version: "5.02",
13-
},
9+
url: "http://digit-labs.org/files/tools/synscan/releases/synscan-5.02.tar.gz",
10+
name: "synscan",
11+
version: "5.02",
1412
},
1513
"gitweb URL": {
16-
url: "http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary",
17-
expected: {
18-
name: "libzipper",
19-
},
14+
url: "http://www.codesrc.com/gitweb/index.cgi?p=libzipper.git;a=summary",
15+
name: "libzipper",
2016
},
2117
"GitHub repo URL": {
22-
url: "https://github.com/abitrolly/lapce.git",
23-
expected: {
24-
name: "lapce",
25-
head: true,
26-
},
18+
url: "https://github.com/abitrolly/lapce.git",
19+
name: "lapce",
20+
head: true,
2721
},
2822
"GitHub archive URL": {
29-
url: "https://github.com/abitrolly/lapce/archive/v0.3.0.tar.gz",
30-
expected: {
31-
name: "lapce",
32-
version: "0.3.0",
33-
},
23+
url: "https://github.com/abitrolly/lapce/archive/v0.3.0.tar.gz",
24+
name: "lapce",
25+
version: "0.3.0",
3426
},
3527
"GitHub download URL": {
36-
url: "https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz",
37-
expected: {
38-
name: "stella",
39-
version: "6.7",
40-
},
28+
url: "https://github.com/stella-emu/stella/releases/download/6.7/stella-6.7-src.tar.xz",
29+
name: "stella",
30+
version: "6.7",
4131
},
4232
}
4333

4434
tests.each do |description, test|
4535
it "parses #{description}" do
46-
fc = described_class.new(url: test.fetch(:url))
47-
ex = test.fetch(:expected)
48-
expect(fc.name).to eq(ex[:name]) if ex.key?(:name)
49-
expect(fc.version).to eq(ex[:version]) if ex.key?(:version)
50-
expect(fc.head).to eq(ex[:head]) if ex.key?(:head)
36+
formula_creator = described_class.new(url: test.fetch(:url))
37+
expect(formula_creator.name).to eq(test.fetch(:name))
38+
if (version = test[:version])
39+
expect(formula_creator.version).to eq(version)
40+
else
41+
expect(formula_creator.version).to be_null
42+
end
43+
expect(formula_creator.head).to eq(test.fetch(:head, false))
5144
end
5245
end
5346
end

0 commit comments

Comments
 (0)