Skip to content

Commit 086d0b6

Browse files
committed
Made runfiles resolution consistent to other rules
Ported the wrapper script for Python into Ruby
1 parent 4af8637 commit 086d0b6

File tree

3 files changed

+132
-26
lines changed

3 files changed

+132
-26
lines changed

ruby/private/binary.bzl

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ load(
55
_transitive_deps = "transitive_deps",
66
)
77

8+
def _to_manifest_path(ctx, file):
9+
if file.short_path.startswith("../"):
10+
return file.short_path[3:]
11+
else:
12+
return ("%s/%s" % (ctx.workspace_name, file.short_path))
13+
814
def _ruby_binary_impl(ctx):
915
sdk = ctx.toolchains[TOOLCHAIN_TYPE_NAME].ruby_runtime
1016
interpreter = sdk.interpreter[DefaultInfo].files_to_run.executable
11-
init_files = [f for t in sdk.init_files for f in t.files.to_list()]
12-
init_flags = " ".join(["-r${PATH_PREFIX}%s" % f.short_path for f in init_files])
1317

1418
main = ctx.file.main
1519
if not main:
@@ -20,30 +24,28 @@ def _ruby_binary_impl(ctx):
2024
break
2125
if not main:
2226
fail(
23-
("main must be present unless the name of the rule matches to one " +
24-
"of the srcs"),
27+
("main must be present unless the name of the rule matches to " +
28+
"one of the srcs"),
2529
"main",
2630
)
2731

2832
executable = ctx.actions.declare_file(ctx.attr.name)
2933
deps = _transitive_deps(
3034
ctx,
31-
extra_files = init_files + [interpreter, executable],
32-
extra_deps = sdk.init_files + [sdk.interpreter],
35+
extra_files = [interpreter, executable],
36+
extra_deps = [sdk.interpreter],
3337
)
3438

3539
rubyopt = reversed(deps.rubyopt.to_list())
36-
rubyopt += ["-I${PATH_PREFIX}%s" % inc for inc in deps.incpaths.to_list()]
3740

3841
ctx.actions.expand_template(
3942
template = ctx.file._wrapper_template,
4043
output = executable,
4144
substitutions = {
4245
"{interpreter}": interpreter.short_path,
43-
"{init_flags}": init_flags,
44-
"{rubyopt}": " ".join(rubyopt),
45-
"{main}": main.short_path,
46-
"{workspace_name}": ctx.label.workspace_name or ctx.workspace_name,
46+
"{loadpaths}": repr(deps.incpaths.to_list()),
47+
"{rubyopt}": repr(rubyopt),
48+
"{main}": repr(_to_manifest_path(ctx, main)),
4749
},
4850
is_executable = True,
4951
)

ruby/private/binary_wrapper.tpl

Lines changed: 117 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,117 @@
1-
#!/bin/sh
2-
3-
if [ -n "${RUNFILES_DIR+x}" ]; then
4-
PATH_PREFIX=$RUNFILES_DIR/{workspace_name}/
5-
elif [ -s `dirname $0`/../../MANIFEST ]; then
6-
PATH_PREFIX=`cd $(dirname $0); pwd`/
7-
elif [ -d $0.runfiles ]; then
8-
PATH_PREFIX=`cd $0.runfiles; pwd`/{workspace_name}/
9-
else
10-
echo "WARNING: it does not look to be at the .runfiles directory" >&2
11-
exit 1
12-
fi
13-
14-
$PATH_PREFIX{interpreter} --disable-gems {init_flags} {rubyopt} -I${PATH_PREFIX} {main} "$@"
1+
#!/usr/bin/env ruby
2+
3+
# Ruby-port of the Bazel's wrapper script for Python
4+
5+
# Copyright 2017 The Bazel Authors. All rights reserved.
6+
# Copyright 2019 BazelRuby Authors. All rights reserved.
7+
#
8+
# Licensed under the Apache License, Version 2.0 (the "License");
9+
# you may not use this file except in compliance with the License.
10+
# You may obtain a copy of the License at
11+
#
12+
# http://www.apache.org/licenses/LICENSE-2.0
13+
#
14+
# Unless required by applicable law or agreed to in writing, software
15+
# distributed under the License is distributed on an "AS IS" BASIS,
16+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
# See the License for the specific language governing permissions and
18+
# limitations under the License.
19+
#
20+
21+
require 'rbconfig'
22+
23+
def find_runfiles
24+
stub_filename = File.absolute_path($0)
25+
runfiles = "#{stub_filename}.runfiles"
26+
loop do
27+
case
28+
when File.directory?(runfiles)
29+
return runfiles
30+
when %r!(.*\.runfiles)/.*!o =~ stub_filename
31+
return $1
32+
when File.symlink?(stub_filename)
33+
target = File.readlink(stub_filename)
34+
stub_filename = File.absolute_path(target, File.dirname(stub_filename))
35+
else
36+
break
37+
end
38+
end
39+
raise "Cannot find .runfiles directory for #{$0}"
40+
end
41+
42+
def create_loadpath_entries(custom, runfiles)
43+
[runfiles] + custom.map {|path| File.join(runfiles, path) }
44+
end
45+
46+
def get_repository_imports(runfiles)
47+
Dir.children(runfiles).map {|d|
48+
File.join(runfiles, d)
49+
}.select {|d|
50+
File.directory? d
51+
}
52+
end
53+
54+
# Finds the runfiles manifest or the runfiles directory.
55+
def runfiles_envvar(runfiles)
56+
# If this binary is the data-dependency of another one, the other sets
57+
# RUNFILES_MANIFEST_FILE or RUNFILES_DIR for our sake.
58+
manifest = ENV['RUNFILES_MANIFEST_FILE']
59+
if manifest
60+
return ['RUNFILES_MANIFEST_FILE', manifest]
61+
end
62+
63+
dir = ENV['RUNFILES_DIR']
64+
if dir
65+
return ['RUNFILES_DIR', dir]
66+
end
67+
68+
# Look for the runfiles "output" manifest, argv[0] + ".runfiles_manifest"
69+
manifest = runfiles + '_manifest'
70+
if File.exists?(manifest)
71+
return ['RUNFILES_MANIFEST_FILE', manifest]
72+
end
73+
74+
# Look for the runfiles "input" manifest, argv[0] + ".runfiles/MANIFEST"
75+
manifest = File.join(runfiles, 'MANIFEST')
76+
if File.exists?(manifest)
77+
return ['RUNFILES_DIR', manifest]
78+
end
79+
80+
# If running in a sandbox and no environment variables are set, then
81+
# Look for the runfiles next to the binary.
82+
if runfiles.end_with?('.runfiles') and File.directory?(runfiles)
83+
return ['RUNFILES_DIR', runfiles]
84+
end
85+
end
86+
87+
def find_ruby_binary
88+
File.join(
89+
RbConfig::CONFIG['bindir'],
90+
RbConfig::CONFIG['ruby_install_name'],
91+
)
92+
end
93+
94+
def main(args)
95+
custom_loadpaths = {loadpaths}
96+
runfiles = find_runfiles
97+
98+
loadpaths = create_loadpath_entries(custom_loadpaths, runfiles)
99+
loadpaths += get_repository_imports(runfiles)
100+
loadpaths += ENV['RUBYLIB'].split(':') if ENV.key?('RUBYLIB')
101+
ENV['RUBYLIB'] = loadpaths.join(':')
102+
103+
runfiles_envkey, runfiles_envvalue = runfiles_envvar(runfiles)
104+
ENV[runfiles_envkey] = runfiles_envvalue if runfiles_envkey
105+
106+
ruby_program = find_ruby_binary
107+
108+
main = {main}
109+
main = File.join(runfiles, main)
110+
rubyopt = {rubyopt}
111+
exec(ruby_program, '--disable-gems', *rubyopt, main, *args)
112+
# TODO(yugui) Support windows
113+
end
114+
115+
if __FILE__ == $0
116+
main(ARGV)
117+
end

ruby/private/tools/deps.bzl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ def transitive_deps(ctx, extra_files = [], extra_deps = []):
3838
transitive_files = depset(transitive = deps.data_files),
3939
collect_data = True,
4040
)
41+
workspace = ctx.label.workspace_name or ctx.workspace_name
4142
includes = [
42-
paths.join(ctx.label.workspace_root, inc)
43+
paths.join(workspace, inc)
4344
for inc in ctx.attr.includes
4445
]
4546
return struct(

0 commit comments

Comments
 (0)