Skip to content

Commit a391ccf

Browse files
authored
Upstream changes from Selenium's fork (#118)
* Allow to symlink additional files for ruby_bundle() * Allow to use ruby_bundle() without Gemfile.lock * Fix host Ruby runtime crash on Fedora 34 * Fix host Ruby runtime loading on Windows * Fix host Ruby runtime loading for JRuby on Linux * Do not register local gems within ruby_bundle() * Support JRuby gem loading * fixup! Allow to use ruby_bundle() without Gemfile.lock
1 parent 67a6b31 commit a391ccf

File tree

6 files changed

+73
-24
lines changed

6 files changed

+73
-24
lines changed

README.adoc

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,16 @@ ruby_bundle(
143143
# You can specify more than one bundle in the WORKSPACE file
144144
ruby_bundle(
145145
name = "bundle_app_shopping",
146-
gemfile = "//apps/shopping:Gemfile",
147-
gemfile_lock = "//apps/shopping:Gemfile.lock",
146+
gemfile = "//:apps/shopping/Gemfile",
147+
gemfile_lock = "//:apps/shopping/Gemfile.lock",
148+
)
149+
150+
# You can also install from Gemfile using `gemspec`.
151+
ruby_bundle(
152+
name = "bundle_gemspec",
153+
srcs = ["//:lib/my_gem/my_gem.gemspec"],
154+
gemfile = "//:lib/my_gem/Gemfile",
155+
gemfile_lock = "//:lib/my_gem/Gemfile.lock",
148156
)
149157
----
150158

@@ -477,6 +485,7 @@ ruby_bundle(
477485
bundler_version = "2.1.4",
478486
includes = {},
479487
excludes = {},
488+
srcs = [],
480489
vendor_cache = False,
481490
ruby_sdk = "@org_ruby_lang_ruby_toolchain",
482491
ruby_interpreter = "@org_ruby_lang_ruby_toolchain//:ruby",
@@ -497,12 +506,17 @@ A unique name for this rule.
497506
The `Gemfile` which Bundler runs with.
498507

499508
|`gemfile_lock` a|
500-
`Label, required`
509+
`Label, optional`
501510

502511
The `Gemfile.lock` which Bundler runs with.
503512

504513
NOTE: This rule never updates the `Gemfile.lock`. It is your responsibility to generate/update `Gemfile.lock`
505514

515+
|`srcs` a|
516+
`List of Labels, optional`
517+
518+
List of additional files required for Bundler to install gems. This could usually include `*.gemspec` files.
519+
506520
|`vendor_cache` a|
507521
`Bool, optional`
508522

@@ -529,10 +543,6 @@ List of glob patterns per gem to be excluded from the library. Keys are the name
529543
|===
530544

531545

532-
==== Limitations
533-
534-
Installing using a `Gemfile` that uses the `gemspec` keyword is not currently supported.
535-
536546
==== Conventions
537547

538548
`ruby_bundle` creates several targets that can be used downstream. In the examples below we assume that your `ruby_bundle` has a name `app_bundle`:

ruby/private/bundle/create_bundle_build_file.rb

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,28 @@
6060

6161
# For ordinary gems, this path is like 'lib/ruby/3.0.0/gems/rspec-3.10.0'.
6262
# For gems with native extension installed via prebuilt packages, the last part of this path can
63-
# contain an OS-specific suffix like 'grpc-1.38.0-universal-darwin' or 'grpc-1.38.0-x86_64-linux'
63+
# contain an OS-specific suffix like 'grpc-1.38.0-universal-darwin' or 'grpc-1.38.0-x86_64-linux'
6464
# instead of 'grpc-1.38.0'.
65-
#
66-
# Since OS platform is unlikely to change between Bazel builds on the same machine,
65+
#
66+
# Since OS platform is unlikely to change between Bazel builds on the same machine,
6767
# `#{gem_name}-#{gem_version}*` would be sufficient to narrow down matches to at most one.
68+
#
69+
# Library path differs across implementations as `lib/ruby` on MRI and `lib/jruby` on JRuby.
6870
GEM_PATH = ->(ruby_version, gem_name, gem_version) do
69-
Dir.glob("lib/ruby/#{ruby_version}/gems/#{gem_name}-#{gem_version}*").first
71+
Dir.glob("lib/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{ruby_version}/gems/#{gem_name}-#{gem_version}*").first
7072
end
7173

7274
# For ordinary gems, this path is like 'lib/ruby/3.0.0/specifications/rspec-3.10.0.gemspec'.
7375
# For gems with native extension installed via prebuilt packages, the last part of this path can
74-
# contain an OS-specific suffix like 'grpc-1.38.0-universal-darwin.gemspec' or
76+
# contain an OS-specific suffix like 'grpc-1.38.0-universal-darwin.gemspec' or
7577
# 'grpc-1.38.0-x86_64-linux.gemspec' instead of 'grpc-1.38.0.gemspec'.
7678
#
7779
# Since OS platform is unlikely to change between Bazel builds on the same machine,
7880
# `#{gem_name}-#{gem_version}*.gemspec` would be sufficient to narrow down matches to at most one.
81+
#
82+
# Library path differs across implementations as `lib/ruby` on MRI and `lib/jruby` on JRuby.
7983
SPEC_PATH = ->(ruby_version, gem_name, gem_version) do
80-
Dir.glob("lib/ruby/#{ruby_version}/specifications/#{gem_name}-#{gem_version}*.gemspec").first
84+
Dir.glob("lib/#{RbConfig::CONFIG['RUBY_INSTALL_NAME']}/#{ruby_version}/specifications/#{gem_name}-#{gem_version}*.gemspec").first
8185
end
8286

8387
require 'bundler'
@@ -247,6 +251,9 @@ def remove_bundler_version!
247251
end
248252

249253
def register_gem(spec, template_out, bundle_lib_paths, bundle_binaries)
254+
# Do not register local gems
255+
return if spec.source.path?
256+
250257
gem_path = GEM_PATH[ruby_version, spec.name, spec.version]
251258
spec_path = SPEC_PATH[ruby_version, spec.name, spec.version]
252259
base_dir = "lib/ruby/#{ruby_version}"

ruby/private/bundle/def.bzl

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,20 @@ def install_bundler(runtime_ctx, bundler_version):
114114
)
115115

116116
def bundle_install(runtime_ctx, previous_result):
117+
cwd = runtime_ctx.ctx.path(".")
118+
bundler_args = [
119+
"install",
120+
"--binstubs={}".format(cwd.get_child(BUNDLE_BIN_PATH)),
121+
"--path={}".format(cwd.get_child(BUNDLE_PATH)),
122+
"--standalone",
123+
"--gemfile={}".format(runtime_ctx.ctx.attr.gemfile.name),
124+
]
125+
if runtime_ctx.ctx.attr.gemfile_lock:
126+
bundler_args += ["--deployment", "--frozen"]
127+
117128
result = run_bundler(
118129
runtime_ctx,
119-
[
120-
"install",
121-
"--binstubs={}".format(BUNDLE_BIN_PATH),
122-
"--path={}".format(BUNDLE_PATH),
123-
"--deployment",
124-
"--standalone",
125-
"--frozen",
126-
],
130+
bundler_args,
127131
previous_result,
128132
)
129133

@@ -133,6 +137,11 @@ def bundle_install(runtime_ctx, previous_result):
133137
return result
134138

135139
def generate_bundle_build_file(runtime_ctx, previous_result):
140+
if runtime_ctx.ctx.attr.gemfile_lock:
141+
gemfile_lock = runtime_ctx.ctx.attr.gemfile_lock.name
142+
else:
143+
gemfile_lock = "{}.lock".format(runtime_ctx.ctx.attr.gemfile.name)
144+
136145
# Create the BUILD file to expose the gems to the WORKSPACE
137146
# USAGE: ./create_bundle_build_file.rb BUILD.bazel Gemfile.lock repo-name [excludes-json] workspace-name
138147
args = [
@@ -142,7 +151,7 @@ def generate_bundle_build_file(runtime_ctx, previous_result):
142151
"bundler/lib",
143152
SCRIPT_BUILD_FILE_GENERATOR, # The template used to created bundle file
144153
"BUILD.bazel", # Bazel build file (can be empty)
145-
"Gemfile.lock", # Gemfile.lock where we list all direct and transitive dependencies
154+
gemfile_lock, # Gemfile.lock where we list all direct and transitive dependencies
146155
runtime_ctx.ctx.name, # Name of the target
147156
repr(runtime_ctx.ctx.attr.includes),
148157
repr(runtime_ctx.ctx.attr.excludes),
@@ -154,15 +163,18 @@ def generate_bundle_build_file(runtime_ctx, previous_result):
154163
fail("build file generation failed: %s%s" % (result.stdout, result.stderr))
155164

156165
def _ruby_bundle_impl(ctx):
157-
ctx.symlink(ctx.attr.gemfile, "Gemfile")
158-
ctx.symlink(ctx.attr.gemfile_lock, "Gemfile.lock")
166+
ctx.symlink(ctx.attr.gemfile, ctx.attr.gemfile.name)
167+
if ctx.attr.gemfile_lock:
168+
ctx.symlink(ctx.attr.gemfile_lock, ctx.attr.gemfile_lock.name)
159169
if ctx.attr.vendor_cache:
160170
ctx.symlink(
161171
ctx.path(str(ctx.path(ctx.attr.gemfile).dirname) + "/vendor"),
162172
ctx.path("vendor"),
163173
)
164174
ctx.symlink(ctx.attr._create_bundle_build_file, SCRIPT_BUILD_FILE_GENERATOR)
165175
ctx.symlink(ctx.attr._install_bundler, SCRIPT_INSTALL_GEM)
176+
for src in ctx.attr.srcs:
177+
ctx.symlink(src, src.name)
166178

167179
bundler_version = ctx.attr.bundler_version
168180

ruby/private/constants.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ BUNDLE_ATTRS = {
7979
"gemfile_lock": attr.label(
8080
allow_single_file = True,
8181
),
82+
"srcs": attr.label_list(
83+
allow_files = True,
84+
),
8285
"vendor_cache": attr.bool(
8386
doc = "Symlink the vendor directory into the Bazel build space, this allows Bundler to access vendored Gems",
8487
),

ruby/private/toolchains/repository_context.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def ruby_repository_context(repository_ctx, interpreter_path):
4545
rel_interpreter_path = str(interpreter_path)
4646
if rel_interpreter_path.startswith("/"):
4747
rel_interpreter_path = rel_interpreter_path[1:]
48+
elif rel_interpreter_path.startswith("C:/"):
49+
rel_interpreter_path = rel_interpreter_path[3:]
4850

4951
return struct(
5052
# Location of the interpreter

ruby/private/toolchains/ruby_runtime.bzl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ def _relativate(path):
3232
# TODO(yugui) support windows
3333
if path.startswith("/"):
3434
return path[1:]
35+
elif path.startswith("C:/"):
36+
return path[3:]
3537
else:
3638
return path
3739

@@ -44,6 +46,19 @@ def _list_libdirs(ruby):
4446

4547
def _install_dirs(ctx, ruby, *names):
4648
paths = sorted([ruby.rbconfig(ruby, name) for name in names])
49+
50+
# JRuby reports some of the directories as nulls.
51+
paths = [path for path in paths if path]
52+
53+
# Sometimes we end up with the same directory multiple times
54+
# so make sure paths are unique by converting it to set.
55+
# For example, this is what we have on Fedora 34:
56+
# $ ruby -rrbconfig -e "p RbConfig::CONFIG['rubyhdrdir']"
57+
# "/usr/include"
58+
# $ ruby -rrbconfig -e "p RbConfig::CONFIG['rubyarchhdrdir']"
59+
# "/usr/include"
60+
paths = depset(paths).to_list()
61+
4762
rel_paths = [_relativate(path) for path in paths]
4863
for i, (path, rel_path) in enumerate(zip(paths, rel_paths)):
4964
if not _is_subpath(path, paths[:i]):

0 commit comments

Comments
 (0)