gembrew 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +41 -11
- data/lib/gembrew/config.rb +83 -1
- data/lib/gembrew/docker_check.rb +2 -0
- data/lib/gembrew/generator.rb +17 -6
- data/lib/gembrew/github_archive_store.rb +51 -0
- data/lib/gembrew/initializer.rb +10 -0
- data/lib/gembrew/reporter.rb +1 -0
- data/lib/gembrew/resolver.rb +62 -8
- data/lib/gembrew/templates/formula.rb.erb +24 -6
- data/lib/gembrew/templates/gembrew.yml.erb +17 -2
- data/lib/gembrew/templates/test.yml +65 -0
- data/lib/gembrew/version.rb +1 -1
- data/lib/gembrew.rb +1 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fe9b9cc5e9535cca862d2adf23aa7887bf0608fa14104d8aa7c3db046358ac61
|
|
4
|
+
data.tar.gz: 7242264cbf2fa6c438445dd180ec73fec06c37513a5d67889ac47dddb748985b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 412fd3b8bc7d1d92ae3358902eacb1e89d6d5a1c2eee5fbb21512b6ea549d1035e438d45855ee8091eda01b9f92f22603c8a089324e82485bafcb124afe4723c
|
|
7
|
+
data.tar.gz: 5fdb7789ec71ce6838cdc82973765441ada2a2c100b9b73ac121c1d3e8aaa77885477d61b578336e6a92b78fc72e6a3acb0bac3cea9be8a2937a8c7710302919
|
data/README.md
CHANGED
|
@@ -20,16 +20,21 @@ gembrew build
|
|
|
20
20
|
gembrew check
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
`init` creates a tap repository containing `README.md`, `gembrew/`,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
`init` creates a tap repository containing `README.md`, `gembrew/`, `Formula/`,
|
|
24
|
+
and a GitHub Actions workflow that styles, audits, installs, tests, and checks
|
|
25
|
+
the linkage of every formula on Linux and macOS. It accepts an empty directory
|
|
26
|
+
or an existing tap containing `Formula/`.
|
|
27
|
+
Supplying a gem name also creates its first configuration. The gem name is
|
|
28
|
+
optional, so `gembrew init` can prepare an empty tap or add Gembrew to an
|
|
29
|
+
existing one. Existing README and workflow files are never overwritten.
|
|
28
30
|
|
|
29
31
|
For example, `gembrew init example` generates:
|
|
30
32
|
|
|
31
33
|
```text
|
|
32
34
|
README.md
|
|
35
|
+
.github/
|
|
36
|
+
workflows/
|
|
37
|
+
test.yml
|
|
33
38
|
gembrew/
|
|
34
39
|
example.yml
|
|
35
40
|
Formula/
|
|
@@ -64,15 +69,16 @@ generate just one:
|
|
|
64
69
|
gembrew build example
|
|
65
70
|
```
|
|
66
71
|
|
|
67
|
-
The required settings are `gem` and exactly one of `test`
|
|
72
|
+
The required settings are `gem`, `version`, `source`, and exactly one of `test`
|
|
73
|
+
or `test_from_file`.
|
|
68
74
|
The output defaults to `Formula/NAME.rb`, where `NAME` is the configuration
|
|
69
75
|
filename. Relative paths are resolved from the tap root.
|
|
70
76
|
|
|
71
77
|
```yaml
|
|
72
78
|
gem: example
|
|
73
|
-
|
|
74
|
-
# Optional published gem version. The latest stable version is used by default.
|
|
75
79
|
version: "1.2.3"
|
|
80
|
+
source:
|
|
81
|
+
type: rubygems
|
|
76
82
|
|
|
77
83
|
# Optional gem metadata overrides:
|
|
78
84
|
desc: Example command-line application
|
|
@@ -80,6 +86,11 @@ homepage: https://example.com
|
|
|
80
86
|
license: MIT
|
|
81
87
|
executable: example
|
|
82
88
|
|
|
89
|
+
# Optional additional Homebrew formula dependencies:
|
|
90
|
+
dependencies:
|
|
91
|
+
- bash
|
|
92
|
+
- libffi :system_on_macos
|
|
93
|
+
|
|
83
94
|
# Optional output override. The default for gembrew/example.yml is shown here.
|
|
84
95
|
output: Formula/example.rb
|
|
85
96
|
|
|
@@ -90,6 +101,23 @@ test: |-
|
|
|
90
101
|
# test_from_file: support/test.rb
|
|
91
102
|
```
|
|
92
103
|
|
|
104
|
+
Tag a dependency with `:system_on_macos` when macOS provides it and Homebrew
|
|
105
|
+
should install its formula only on other platforms.
|
|
106
|
+
|
|
107
|
+
To build the root gem from a GitHub tag while continuing to fetch its
|
|
108
|
+
dependencies from RubyGems, use:
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
source:
|
|
112
|
+
type: github
|
|
113
|
+
repo: owner/repository
|
|
114
|
+
# tag: v1.2.3
|
|
115
|
+
# gemspec: example.gemspec
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The tag defaults to `vVERSION`; the gemspec path defaults to
|
|
119
|
+
`GEMNAME.gemspec`.
|
|
120
|
+
|
|
93
121
|
Gembrew resolves the generic Ruby dependency graph and generates a Homebrew
|
|
94
122
|
`resource` for every runtime dependency. Original `.gem` archives are reused
|
|
95
123
|
from RubyGems' local cache when available. Downloaded archives are retained in
|
|
@@ -109,6 +137,7 @@ brew style example
|
|
|
109
137
|
brew audit --new --online example
|
|
110
138
|
brew install --build-from-source example
|
|
111
139
|
brew test example
|
|
140
|
+
brew linkage --test example
|
|
112
141
|
```
|
|
113
142
|
|
|
114
143
|
To test a published tap without mounting the local repository, open a pristine
|
|
@@ -125,9 +154,10 @@ gembrew check
|
|
|
125
154
|
```
|
|
126
155
|
|
|
127
156
|
This rebuilds every configured formula, then runs Homebrew style, online audit,
|
|
128
|
-
source installation,
|
|
129
|
-
Use `gembrew check example` to check only one formula.
|
|
130
|
-
directly; the tap does not need generated container
|
|
157
|
+
source installation, the formula test, and linkage validation in disposable
|
|
158
|
+
Homebrew containers. Use `gembrew check example` to check only one formula.
|
|
159
|
+
Gembrew invokes Docker directly; the tap does not need generated container
|
|
160
|
+
support files.
|
|
131
161
|
|
|
132
162
|
## Contributing / Support
|
|
133
163
|
|
data/lib/gembrew/config.rb
CHANGED
|
@@ -4,9 +4,14 @@ require 'gembrew/error'
|
|
|
4
4
|
|
|
5
5
|
module Gembrew
|
|
6
6
|
class Config
|
|
7
|
+
Dependency = Data.define(:name, :tags) do
|
|
8
|
+
def system_on_macos? = tags.include? :system_on_macos
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
DEPENDENCY_TAGS = %w[:system_on_macos].freeze
|
|
7
12
|
DIRECTORY = 'gembrew'
|
|
8
13
|
ALLOWED_KEYS = %w[
|
|
9
|
-
gem version output desc homepage license executable test test_from_file
|
|
14
|
+
gem version source output desc homepage license executable dependencies test test_from_file
|
|
10
15
|
].freeze
|
|
11
16
|
|
|
12
17
|
attr_reader :path, :project_path
|
|
@@ -41,12 +46,21 @@ module Gembrew
|
|
|
41
46
|
def name = path.basename('.yml').to_s
|
|
42
47
|
def gem_name = data.fetch('gem').to_s
|
|
43
48
|
def version = data['version']&.to_s
|
|
49
|
+
def source = data.fetch('source')
|
|
50
|
+
def source_type = source.fetch('type')
|
|
51
|
+
def source_repo = source['repo']
|
|
52
|
+
def source_tag = source['tag'] || "v#{version}"
|
|
53
|
+
def source_gemspec = source['gemspec'] || "#{gem_name}.gemspec"
|
|
44
54
|
def output_path = (project_path/(data['output'] || "Formula/#{name}.rb")).expand_path
|
|
45
55
|
def description = data['desc']
|
|
46
56
|
def homepage = data['homepage']
|
|
47
57
|
def license = data['license']
|
|
48
58
|
def executable = data['executable']
|
|
49
59
|
|
|
60
|
+
def dependencies
|
|
61
|
+
@dependencies ||= data.fetch('dependencies', []).map { |value| parse_dependency value }
|
|
62
|
+
end
|
|
63
|
+
|
|
50
64
|
def test_body
|
|
51
65
|
@test_body ||= if data.has_key?('test')
|
|
52
66
|
data.fetch('test').to_s
|
|
@@ -77,6 +91,10 @@ module Gembrew
|
|
|
77
91
|
raise Error, "Unknown configuration keys: #{unknown_keys.join(', ')}" if unknown_keys.any?
|
|
78
92
|
|
|
79
93
|
require_value 'gem'
|
|
94
|
+
require_value 'version'
|
|
95
|
+
require_value 'source'
|
|
96
|
+
validate_source
|
|
97
|
+
validate_dependencies
|
|
80
98
|
|
|
81
99
|
return unless data.has_key?('test') == data.has_key?('test_from_file')
|
|
82
100
|
|
|
@@ -87,5 +105,69 @@ module Gembrew
|
|
|
87
105
|
value = data[key]
|
|
88
106
|
raise Error, "#{key} is required" if value.nil? || value.to_s.empty?
|
|
89
107
|
end
|
|
108
|
+
|
|
109
|
+
def validate_source
|
|
110
|
+
raise Error, 'source must be a mapping' unless source.is_a?(Hash)
|
|
111
|
+
|
|
112
|
+
validate_source_keys
|
|
113
|
+
case source['type']&.to_s
|
|
114
|
+
when 'rubygems' then validate_rubygems_source
|
|
115
|
+
when 'github' then validate_github_source
|
|
116
|
+
else raise Error, 'source.type must be github or rubygems'
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def validate_source_keys
|
|
121
|
+
unknown_keys = source.keys - %w[type repo tag gemspec]
|
|
122
|
+
raise Error, "Unknown source keys: #{unknown_keys.join(', ')}" if unknown_keys.any?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def validate_rubygems_source
|
|
126
|
+
extra_keys = source.keys - ['type']
|
|
127
|
+
raise Error, "source.#{extra_keys.first} is only valid for GitHub sources" if extra_keys.any?
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def validate_github_source
|
|
131
|
+
repo = source['repo']&.to_s
|
|
132
|
+
raise Error, 'source.repo is required for GitHub sources' if repo.nil? || repo.empty?
|
|
133
|
+
raise Error, 'source.repo must be in owner/repository form' unless repo.match?(%r{\A[^/\s]+/[^/\s]+\z})
|
|
134
|
+
|
|
135
|
+
validate_relative_source_path 'gemspec' if source.has_key?('gemspec')
|
|
136
|
+
raise Error, 'source.tag must not be empty' if source.has_key?('tag') && source['tag'].to_s.empty?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def validate_relative_source_path(key)
|
|
140
|
+
value = source[key].to_s
|
|
141
|
+
path = Pathname(value)
|
|
142
|
+
valid = !value.empty? && !path.absolute? && path.each_filename.none?('..')
|
|
143
|
+
raise Error, "source.#{key} must be a relative path within the archive" unless valid
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def validate_dependencies
|
|
147
|
+
return unless data.has_key?('dependencies')
|
|
148
|
+
|
|
149
|
+
raise Error, 'dependencies must be a sequence' unless data['dependencies'].is_a?(Array)
|
|
150
|
+
|
|
151
|
+
dependencies
|
|
152
|
+
names = dependencies.map(&:name)
|
|
153
|
+
duplicate = names.find { |name| names.count(name) > 1 }
|
|
154
|
+
raise Error, "dependency #{duplicate.inspect} is specified more than once" if duplicate
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def parse_dependency(value)
|
|
158
|
+
raise Error, 'each dependency must be a name followed by optional tags' unless value.is_a?(String)
|
|
159
|
+
|
|
160
|
+
values = value.split
|
|
161
|
+
name = values.shift
|
|
162
|
+
unless name && !name.start_with?(':')
|
|
163
|
+
raise Error, 'dependency name must be a non-empty string'
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
invalid_tag = values.find { |tag| !tag.is_a?(String) || !DEPENDENCY_TAGS.include?(tag) }
|
|
167
|
+
raise Error, "unknown dependency tag: #{invalid_tag.inspect}" if invalid_tag
|
|
168
|
+
raise Error, "dependency #{name.inspect} has duplicate tags" unless values.uniq.length == values.length
|
|
169
|
+
|
|
170
|
+
Dependency.new(name:, tags: values.map { |tag| tag.delete_prefix(':').to_sym }.freeze)
|
|
171
|
+
end
|
|
90
172
|
end
|
|
91
173
|
end
|
data/lib/gembrew/docker_check.rb
CHANGED
data/lib/gembrew/generator.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Gembrew
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def call
|
|
14
|
-
resolution = resolver.resolve(config.gem_name, config.version)
|
|
14
|
+
resolution = resolver.resolve(config.gem_name, config.version, source: config.source)
|
|
15
15
|
output_path = config.output_path
|
|
16
16
|
output_path.dirname.mkpath
|
|
17
17
|
output_path.write renderer.render(formula_data(resolution))
|
|
@@ -35,14 +35,25 @@ module Gembrew
|
|
|
35
35
|
|
|
36
36
|
def metadata(spec)
|
|
37
37
|
{
|
|
38
|
-
description:
|
|
39
|
-
homepage:
|
|
40
|
-
license:
|
|
41
|
-
executable:
|
|
42
|
-
|
|
38
|
+
description: config.description || spec.summary,
|
|
39
|
+
homepage: config.homepage || inferred_homepage(spec),
|
|
40
|
+
license: config.license || spec.license || spec.licenses.first,
|
|
41
|
+
executable: config.executable || spec.executables.first || spec.name,
|
|
42
|
+
source_type: config.source_type,
|
|
43
|
+
source_repo: config.source_repo,
|
|
44
|
+
source_tag: config.source_tag,
|
|
45
|
+
source_gemspec: config.source_gemspec,
|
|
46
|
+
dependencies: formula_dependencies,
|
|
47
|
+
test_body: config.test_body,
|
|
43
48
|
}
|
|
44
49
|
end
|
|
45
50
|
|
|
51
|
+
def formula_dependencies
|
|
52
|
+
([Config::Dependency.new(name: 'ruby', tags: [])] + config.dependencies)
|
|
53
|
+
.uniq(&:name)
|
|
54
|
+
.sort_by(&:name)
|
|
55
|
+
end
|
|
56
|
+
|
|
46
57
|
def formula_name(gem_name)
|
|
47
58
|
gem_name.split(/[-_]/).map(&:capitalize).join
|
|
48
59
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'open3'
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'gembrew/error'
|
|
5
|
+
require 'gembrew/reporter'
|
|
6
|
+
|
|
7
|
+
module Gembrew
|
|
8
|
+
class GithubArchiveStore
|
|
9
|
+
def initialize(cache_path:, reporter: Reporter.new, command_runner: nil)
|
|
10
|
+
@cache_path = Pathname(cache_path)
|
|
11
|
+
@reporter = reporter
|
|
12
|
+
@command_runner = command_runner || method(:run_command)
|
|
13
|
+
@cache_path.mkpath
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fetch(repository, tag)
|
|
17
|
+
name = repository.tr '/', '-'
|
|
18
|
+
path = @cache_path/"#{name}-#{tag.tr '/', '-'}.tar.gz"
|
|
19
|
+
if path.file? && !path.empty?
|
|
20
|
+
reporter.archive :github_cache, repository, tag
|
|
21
|
+
return path
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
reporter.archive :downloading, repository, tag
|
|
25
|
+
url = "https://github.com/#{repository}/archive/refs/tags/#{tag}.tar.gz"
|
|
26
|
+
command_runner.call 'curl', '--fail', '--location', '--silent', '--show-error',
|
|
27
|
+
'--output', path.to_s, url, chdir: @cache_path
|
|
28
|
+
raise Error, "GitHub archive is empty: #{url}" unless path.file? && !path.empty?
|
|
29
|
+
|
|
30
|
+
path
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def extract(archive, destination)
|
|
34
|
+
destination = Pathname(destination)
|
|
35
|
+
destination.mkpath
|
|
36
|
+
command_runner.call 'tar', '-xzf', archive.to_s, '-C', destination.to_s, chdir: destination
|
|
37
|
+
destination
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
attr_reader :reporter, :command_runner
|
|
43
|
+
|
|
44
|
+
def run_command(*command, chdir:)
|
|
45
|
+
result, status = Open3.capture2e(*command, chdir: chdir.to_s)
|
|
46
|
+
raise Error, result unless status.success?
|
|
47
|
+
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/gembrew/initializer.rb
CHANGED
|
@@ -20,6 +20,8 @@ module Gembrew
|
|
|
20
20
|
formula_path.mkpath
|
|
21
21
|
config_directory.mkpath
|
|
22
22
|
readme_path.write render_readme unless readme_path.exist?
|
|
23
|
+
workflow_path.dirname.mkpath
|
|
24
|
+
workflow_path.write workflow_template.read unless workflow_path.exist?
|
|
23
25
|
Adder.new(gem_name, project_path: project_path).call if gem_name
|
|
24
26
|
|
|
25
27
|
project_path
|
|
@@ -39,6 +41,14 @@ module Gembrew
|
|
|
39
41
|
project_path/'README.md'
|
|
40
42
|
end
|
|
41
43
|
|
|
44
|
+
def workflow_path
|
|
45
|
+
project_path/'.github/workflows/test.yml'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def workflow_template
|
|
49
|
+
Pathname(__dir__)/'templates/test.yml'
|
|
50
|
+
end
|
|
51
|
+
|
|
42
52
|
def entries
|
|
43
53
|
@entries ||= project_path.children.reject { |path| path.basename.to_s == '.git' }
|
|
44
54
|
end
|
data/lib/gembrew/reporter.rb
CHANGED
data/lib/gembrew/resolver.rb
CHANGED
|
@@ -6,6 +6,7 @@ require 'rubygems/package'
|
|
|
6
6
|
require 'tmpdir'
|
|
7
7
|
require 'gembrew/archive_store'
|
|
8
8
|
require 'gembrew/error'
|
|
9
|
+
require 'gembrew/github_archive_store'
|
|
9
10
|
require 'gembrew/reporter'
|
|
10
11
|
|
|
11
12
|
module Gembrew
|
|
@@ -15,21 +16,22 @@ module Gembrew
|
|
|
15
16
|
class Resolver
|
|
16
17
|
attr_reader :cache_root
|
|
17
18
|
|
|
18
|
-
def initialize(cache_root: nil, reporter: Reporter.new, command_runner: nil, archive_store: nil
|
|
19
|
+
def initialize(cache_root: nil, reporter: Reporter.new, command_runner: nil, archive_store: nil,
|
|
20
|
+
github_archive_store: nil)
|
|
19
21
|
@cache_root = Pathname(cache_root || default_cache_root)
|
|
20
22
|
@reporter = reporter
|
|
21
23
|
@command_runner = command_runner || method(:run_command)
|
|
22
24
|
@archive_store = archive_store || ArchiveStore.new(
|
|
23
25
|
cache_path: @cache_root/'gems', reporter: reporter, command_runner: @command_runner
|
|
24
26
|
)
|
|
27
|
+
@github_archive_store = github_archive_store
|
|
25
28
|
temporary_root.mkpath
|
|
26
29
|
end
|
|
27
30
|
|
|
28
|
-
def resolve(name, version
|
|
31
|
+
def resolve(name, version, source:)
|
|
29
32
|
Dir.mktmpdir('build-', temporary_root.to_s) do |directory|
|
|
30
33
|
temporary = Pathname(directory)
|
|
31
|
-
root_archive =
|
|
32
|
-
root_spec = Gem::Package.new(root_archive.to_s).spec
|
|
34
|
+
root_archive, root_spec = root_source name, version, source, temporary
|
|
33
35
|
dependencies = dependency_specs(lock(root_spec, temporary), root_spec)
|
|
34
36
|
|
|
35
37
|
reporter.collecting dependencies.length
|
|
@@ -45,6 +47,57 @@ module Gembrew
|
|
|
45
47
|
|
|
46
48
|
attr_reader :reporter, :command_runner, :archive_store
|
|
47
49
|
|
|
50
|
+
def github_archive_store
|
|
51
|
+
@github_archive_store ||= GithubArchiveStore.new(
|
|
52
|
+
cache_path: cache_root/'github', reporter: reporter, command_runner: command_runner
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def root_source(name, version, source_config, temporary)
|
|
57
|
+
return rubygems_root_source(name, version, temporary) if source_config.fetch('type') == 'rubygems'
|
|
58
|
+
|
|
59
|
+
github_root_source name, version, source_config, temporary
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def rubygems_root_source(name, version, temporary)
|
|
63
|
+
archive = archive_store.fetch(name, version, temporary)
|
|
64
|
+
[archive, Gem::Package.new(archive.to_s).spec]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def github_root_source(name, version, source_config, temporary)
|
|
68
|
+
repository = source_config.fetch('repo')
|
|
69
|
+
tag = source_config['tag'] || "v#{version}"
|
|
70
|
+
gemspec_path = source_config['gemspec'] || "#{name}.gemspec"
|
|
71
|
+
archive = github_archive_store.fetch repository, tag
|
|
72
|
+
root = github_project_root archive, temporary
|
|
73
|
+
spec = load_github_spec root/gemspec_path, gemspec_path
|
|
74
|
+
validate_github_spec spec, name, version
|
|
75
|
+
|
|
76
|
+
[archive, spec]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def github_project_root(archive, temporary)
|
|
80
|
+
extracted = github_archive_store.extract archive, temporary/'source'
|
|
81
|
+
roots = extracted.children.select(&:directory?)
|
|
82
|
+
raise Error, 'Expected one project directory in the GitHub archive' unless roots.one?
|
|
83
|
+
|
|
84
|
+
roots.first
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def load_github_spec(gemspec, gemspec_path)
|
|
88
|
+
raise Error, "Gemspec not found in GitHub archive: #{gemspec_path}" unless gemspec.file?
|
|
89
|
+
|
|
90
|
+
spec = Dir.chdir(gemspec.dirname) { Gem::Specification.load(gemspec.basename.to_s) }
|
|
91
|
+
raise Error, "Could not load gemspec from GitHub archive: #{gemspec_path}" unless spec
|
|
92
|
+
|
|
93
|
+
spec
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def validate_github_spec(spec, name, version)
|
|
97
|
+
raise Error, "Gemspec name #{spec.name} does not match configured gem #{name}" unless spec.name == name
|
|
98
|
+
raise Error, "GitHub gemspec version #{spec.version} does not match #{version}" unless spec.version == Gem::Version.new(version)
|
|
99
|
+
end
|
|
100
|
+
|
|
48
101
|
def resource(spec, temporary, index, total)
|
|
49
102
|
archive = archive_store.fetch spec.name, spec.version, temporary, index: index, total: total
|
|
50
103
|
Resource.new spec.name, spec.version.to_s, Digest::SHA256.file(archive).hexdigest
|
|
@@ -62,10 +115,11 @@ module Gembrew
|
|
|
62
115
|
def lock(root_spec, temporary)
|
|
63
116
|
gemfile = temporary/'Gemfile'
|
|
64
117
|
lockfile = temporary/'Gemfile.lock'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
gem #{
|
|
68
|
-
|
|
118
|
+
dependencies = root_spec.runtime_dependencies.map do |dependency|
|
|
119
|
+
requirements = dependency.requirement.requirements.map { |operator, version| "#{operator} #{version}" }
|
|
120
|
+
"gem #{dependency.name.inspect}, #{requirements.map(&:inspect).join(', ')}"
|
|
121
|
+
end
|
|
122
|
+
gemfile.write([[%[source "https://rubygems.org"]], dependencies, ['']].flatten.join("\n"))
|
|
69
123
|
|
|
70
124
|
reporter.resolving root_spec.name, root_spec.version
|
|
71
125
|
command_runner.call(
|
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
# Generated by Gembrew: https://github.com/dannyben/gembrew
|
|
2
|
-
# Manual edits are not recommended. Update gembrew/*.yml and regenerate with:
|
|
3
|
-
# gem install gembrew
|
|
4
|
-
# gembrew build
|
|
5
|
-
|
|
6
1
|
class <%= formula_name %> < Formula
|
|
7
2
|
desc <%= description.inspect %>
|
|
8
3
|
homepage <%= homepage.inspect %>
|
|
4
|
+
<% if source_type == 'github' -%>
|
|
5
|
+
url "https://github.com/<%= source_repo %>/archive/refs/tags/<%= source_tag %>.tar.gz"
|
|
6
|
+
<% else -%>
|
|
9
7
|
url "https://rubygems.org/downloads/<%= gem_name %>-<%= version %>.gem"
|
|
8
|
+
<% end -%>
|
|
10
9
|
sha256 "<%= sha256 %>"
|
|
11
10
|
license <%= license.inspect %>
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
<% formula_dependencies = dependencies.reject(&:system_on_macos?) -%>
|
|
13
|
+
<% macos_dependencies = dependencies.select(&:system_on_macos?) -%>
|
|
14
|
+
<% formula_dependencies.each do |dependency| -%>
|
|
15
|
+
depends_on <%= dependency.name.inspect %>
|
|
16
|
+
<% end -%>
|
|
17
|
+
<% if formula_dependencies.any? && macos_dependencies.any? -%>
|
|
18
|
+
|
|
19
|
+
<% end -%>
|
|
20
|
+
<% macos_dependencies.each do |dependency| -%>
|
|
21
|
+
uses_from_macos <%= dependency.name.inspect %>
|
|
22
|
+
<% end -%>
|
|
14
23
|
<% resources.each do |resource| -%>
|
|
15
24
|
|
|
16
25
|
resource <%= resource.name.inspect %> do
|
|
@@ -27,8 +36,17 @@ class <%= formula_name %> < Formula
|
|
|
27
36
|
"--ignore-dependencies", "--install-dir", libexec, "--no-document"
|
|
28
37
|
end
|
|
29
38
|
|
|
39
|
+
<% if source_type == 'github' -%>
|
|
40
|
+
system "gem", "build", "<%= source_gemspec %>"
|
|
41
|
+
system "gem", "install", "--ignore-dependencies", "<%= gem_name %>-#{version}.gem",
|
|
42
|
+
"--install-dir", libexec, "--no-document"
|
|
43
|
+
<% else -%>
|
|
30
44
|
system "gem", "install", cached_download,
|
|
31
45
|
"--ignore-dependencies", "--install-dir", libexec, "--no-document"
|
|
46
|
+
<% end -%>
|
|
47
|
+
|
|
48
|
+
rm libexec.glob("extensions/*/*/*/mkmf.log")
|
|
49
|
+
deuniversalize_machos if OS.mac?
|
|
32
50
|
|
|
33
51
|
(bin/<%= executable.inspect %>).write_env_script libexec/"bin/<%= executable %>", GEM_HOME: ENV.fetch("GEM_HOME")
|
|
34
52
|
end
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
gem: <%= gem_name %>
|
|
2
|
+
version: "" # required
|
|
3
|
+
|
|
4
|
+
# Required source. Use the published RubyGem:
|
|
5
|
+
source:
|
|
6
|
+
type: rubygems
|
|
7
|
+
|
|
8
|
+
# Or replace the source above with a GitHub tag archive:
|
|
9
|
+
# source:
|
|
10
|
+
# type: github
|
|
11
|
+
# repo: owner/repository # required for GitHub
|
|
12
|
+
# tag: v1.2.3 # optional; defaults to vVERSION
|
|
13
|
+
# gemspec: <%= gem_name %>.gemspec # optional; defaults to GEMNAME.gemspec
|
|
2
14
|
|
|
3
15
|
test: |-
|
|
4
16
|
system bin/"<%= gem_name %>", "--version"
|
|
5
17
|
|
|
6
|
-
# Optional overrides:
|
|
7
|
-
# version: "1.2.3"
|
|
18
|
+
# Optional metadata and formula overrides:
|
|
8
19
|
# desc: Example command-line application
|
|
9
20
|
# homepage: https://example.com
|
|
10
21
|
# license: MIT
|
|
11
22
|
# executable: <%= gem_name %>
|
|
23
|
+
# output: Formula/<%= gem_name %>.rb
|
|
24
|
+
# dependencies:
|
|
25
|
+
# - bash
|
|
26
|
+
# - libffi :system_on_macos
|
|
12
27
|
|
|
13
28
|
# To load the Homebrew test body from a Ruby file, replace `test` above with:
|
|
14
29
|
# test_from_file: support/test.rb
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Test Formulae
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
name: ${{ matrix.os }}
|
|
17
|
+
runs-on: ${{ matrix.os }}
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
os:
|
|
22
|
+
- ubuntu-latest
|
|
23
|
+
- macos-latest
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Set up Homebrew
|
|
27
|
+
id: set-up-homebrew
|
|
28
|
+
uses: Homebrew/actions/setup-homebrew@fd832223f9f99ebf0244dd20658680e5d4aca049 # 2026.08.03.2
|
|
29
|
+
|
|
30
|
+
- name: Cache Homebrew Bundler gems
|
|
31
|
+
id: cache
|
|
32
|
+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
33
|
+
with:
|
|
34
|
+
path: ${{ steps.set-up-homebrew.outputs.gems-path }}
|
|
35
|
+
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
|
|
36
|
+
restore-keys: ${{ runner.os }}-rubygems-
|
|
37
|
+
|
|
38
|
+
- name: Install Homebrew Bundler gems
|
|
39
|
+
if: steps.cache.outputs.cache-hit != 'true'
|
|
40
|
+
run: brew install-bundler-gems
|
|
41
|
+
|
|
42
|
+
- name: Test formulae
|
|
43
|
+
shell: bash
|
|
44
|
+
env:
|
|
45
|
+
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
46
|
+
run: |
|
|
47
|
+
shopt -s nullglob
|
|
48
|
+
formulae=(Formula/*.rb)
|
|
49
|
+
|
|
50
|
+
if (( ${#formulae[@]} == 0 )); then
|
|
51
|
+
echo "No formulae found in Formula/"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
for formula in "${formulae[@]}"; do
|
|
56
|
+
formula_name="${formula##*/}"
|
|
57
|
+
formula_name="${formula_name%.rb}"
|
|
58
|
+
|
|
59
|
+
brew style "$formula"
|
|
60
|
+
brew audit --new --online "$formula_name"
|
|
61
|
+
brew install --build-from-source "$formula_name"
|
|
62
|
+
brew test "$formula_name"
|
|
63
|
+
brew linkage --test "$formula_name"
|
|
64
|
+
brew uninstall "$formula_name"
|
|
65
|
+
done
|
data/lib/gembrew/version.rb
CHANGED
data/lib/gembrew.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gembrew
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Danny Ben Shitrit
|
|
@@ -77,6 +77,7 @@ files:
|
|
|
77
77
|
- lib/gembrew/docker_shell.rb
|
|
78
78
|
- lib/gembrew/error.rb
|
|
79
79
|
- lib/gembrew/generator.rb
|
|
80
|
+
- lib/gembrew/github_archive_store.rb
|
|
80
81
|
- lib/gembrew/initializer.rb
|
|
81
82
|
- lib/gembrew/renderer.rb
|
|
82
83
|
- lib/gembrew/reporter.rb
|
|
@@ -84,6 +85,7 @@ files:
|
|
|
84
85
|
- lib/gembrew/templates/README.md.erb
|
|
85
86
|
- lib/gembrew/templates/formula.rb.erb
|
|
86
87
|
- lib/gembrew/templates/gembrew.yml.erb
|
|
88
|
+
- lib/gembrew/templates/test.yml
|
|
87
89
|
- lib/gembrew/version.rb
|
|
88
90
|
homepage: https://github.com/DannyBen/gembrew
|
|
89
91
|
licenses:
|