Skip to content

Commit 01c110c

Browse files
committed
windows-compatible runfiles
1 parent defc644 commit 01c110c

3 files changed

Lines changed: 60 additions & 17 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
2626
git_repository(
2727
name = "build_bazel_rules_nodejs",
2828
remote = "https://github.com/bazelbuild/rules_nodejs.git",
29-
tag = "0.0.1", # check for the latest tag when you install
29+
tag = "0.1.0", # check for the latest tag when you install
3030
)
3131

3232
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")

‎internal/node_launcher.sh‎

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,25 @@
1616
set -e
1717

1818
# Launcher for NodeJS applications.
19-
# Find our runfiles tree. We need this to launch node with the correct
19+
# Find our runfiles manifest. We need this to launch node with the correct
2020
# entry point.
2121
#
2222
# Call this program X. X was generated by a genrule and may be invoked
2323
# in many ways:
2424
# 1a) directly by a user, with $0 in the output tree
2525
# 1b) via 'bazel run' (similar to case 1a)
26-
# 2) directly by a user, with $0 in X's runfiles tree
26+
# 2) directly by a user, with $0 in X's runfiles manifest
2727
# 3) by another program Y which has a data dependency on X, with $0 in Y's
28-
# runfiles tree
28+
# runfiles manifest
2929
# 4a) via 'bazel test'
3030
# 4b) case 3 in the context of a test
3131
# 5a) by a genrule cmd, with $0 in the output tree
3232
# 6a) case 3 in the context of a genrule
3333
#
34-
# For case 1, $0 will be a regular file, and the runfiles tree will be
34+
# For case 1, $0 will be a regular file, and the runfiles manifest will be
3535
# at $0.runfiles.
3636
# For case 2 or 3, $0 will be a symlink to the file seen in case 1.
37-
# For case 4, $TEST_SRCDIR should already be set to the runfiles tree by
37+
# For case 4, $TEST_SRCDIR should already be set to the runfiles manifest by
3838
# blaze.
3939
# Case 5a is handled like case 1.
4040
# Case 6a is handled like case 3.
@@ -46,16 +46,16 @@ esac
4646

4747
if [[ -n "$TEST_SRCDIR" ]]; then
4848
# Case 4, bazel has identified runfiles for us.
49-
RUNFILES="$TEST_SRCDIR"
49+
RUNFILES="${TEST_SRCDIR}_manifest"
5050
else
5151
while true; do
5252
if [[ -e "$self.runfiles" ]]; then
53-
RUNFILES="$self.runfiles"
53+
RUNFILES="$self.runfiles_manifest"
5454
break
5555
fi
5656

5757
if [[ $self == *.runfiles/* ]]; then
58-
RUNFILES="${self%%.runfiles/*}.runfiles"
58+
RUNFILES="${self%%.runfiles/*}.runfiles_manifest"
5959
# don't break; this is a last resort for case 6b
6060
fi
6161

@@ -92,4 +92,21 @@ done
9292
# Note: for debugging it is useful to see what files are actually present, eg:
9393
# find . -name thingImLookingFor
9494

95-
exec "${RUNFILES}/TEMPLATED_node" "${NODE_OPTIONS[@]}" "${RUNFILES}/TEMPLATED_script_path" "${ARGS[@]}"
95+
# Lookup the real paths from the runfiles manifest with no dependency on posix
96+
while read line; do
97+
declare -a PARTS=($line)
98+
if [ "${PARTS[0]}" == "TEMPLATED_node" ]; then
99+
readonly node="${PARTS[1]}"
100+
elif [ "${PARTS[0]}" == "TEMPLATED_script_path" ]; then
101+
readonly script="${PARTS[1]}"
102+
fi
103+
done < ${RUNFILES}
104+
if [ -z "${node}" ]; then
105+
echo "Failed to find node binary TEMPLATED_node in manifest ${RUNFILES}"
106+
exit 1
107+
fi
108+
if [ -z "${script}" ]; then
109+
echo "Failed to find script TEMPLATED_script_path in manifest ${RUNFILES}"
110+
exit 1
111+
fi
112+
exec "${node}" "${NODE_OPTIONS[@]}" "${script}" "${ARGS[@]}"

‎internal/node_loader.js‎

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
*/
2424
'use strict';
2525
var path = require('path');
26+
var fs = require('fs');
27+
var readline = require('readline');
2628

2729
/**
2830
* The module roots as pairs of a RegExp to match the require path, and a
@@ -56,8 +58,28 @@ function resolveToModuleRoot(path) {
5658
return null;
5759
}
5860

59-
function runfilesDir() {
60-
return process.env.RUNFILES || process.env.TEST_SRCDIR;
61+
/**
62+
* The runfiles manifest maps from short_path
63+
* https://docs.bazel.build/versions/master/skylark/lib/File.html#short_path
64+
* to the actual location on disk where the file can be read.
65+
*/
66+
const runfilesManifest = Object.create(null);
67+
function loadRunfilesManifest(manifestPath) {
68+
return new Promise((resolve, reject) => {
69+
try {
70+
const input = fs.createReadStream(manifestPath, {encoding: 'utf-8'});
71+
const manifest = readline.createInterface({input});
72+
manifest.on('line', line => {
73+
if (!line) return;
74+
const [runfilesPath, realPath] = line.split(" ");
75+
runfilesManifest[runfilesPath] = realPath;
76+
}).on('close', () => {
77+
resolve(runfilesManifest);
78+
});
79+
} catch (e) {
80+
reject(e);
81+
}
82+
});
6183
}
6284

6385
var originalResolveFilename = module.constructor._resolveFilename;
@@ -66,10 +88,12 @@ module.constructor._resolveFilename =
6688
var failedResolutions = [];
6789
var resolveLocations = [
6890
request,
69-
path.join(runfilesDir(), request),
70-
path.join(
71-
runfilesDir(), 'TEMPLATED_workspace_name', 'TEMPLATED_label_package',
72-
'node_modules', request),
91+
runfilesManifest[request],
92+
// Join on forward slash, because even on Windows the runfiles_manifest
93+
// file is written with forward slash.
94+
runfilesManifest[[
95+
'TEMPLATED_workspace_name', 'TEMPLATED_label_package',
96+
'node_modules', request].join('/')],
7397
];
7498
for (var location of resolveLocations) {
7599
try {
@@ -100,7 +124,9 @@ if (require.main === module) {
100124
// NB: entry_point below is replaced during the build process.
101125
var mainScript = process.argv[1] = 'TEMPLATED_entry_point';
102126
try {
103-
module.constructor._load(mainScript, this, /*isMain=*/true);
127+
loadRunfilesManifest(process.env.RUNFILES).then(mf => {
128+
module.constructor._load(mainScript, this, /*isMain=*/true);
129+
});
104130
} catch (e) {
105131
console.error('failed to load main ', e.stack || e);
106132
process.exit(1);

0 commit comments

Comments
 (0)