Repository navigation
Expand file tree
/
Copy pathnode_loader.js
More file actions
177 lines (163 loc) · 5.57 KB
/
Copy pathnode_loader.js
File metadata and controls
177 lines (163 loc) · 5.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/**
* @license
* Copyright 2017 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Patched NodeJS module loader for bazel. This template is
* expanded to contain module name -> path mappings and then patches the
* NodeJS require() function to substitute the appropriate paths.
*
* @see https://github.com/nodejs/node/blob/master/lib/module.js
*/
'use strict';
var path = require('path');
var fs = require('fs');
/**
* The module roots as pairs of a RegExp to match the require path, and a
* module_root to substitute for the require path.
* @type {!Array<{module_name: RegExp, module_root: string}>}
*/
var MODULE_ROOTS = [TEMPLATED_module_roots];
/**
* Array of bootstrap modules that need to be loaded before the entry point.
*/
var BOOTSTRAP = [TEMPLATED_bootstrap];
function resolveToModuleRoot(path) {
if (!path) {
throw new Error('resolveToModuleRoot missing path: ' + path);
}
var match;
var lengthOfMatch = 0;
var matchedEntry;
for (var i = 0; i < MODULE_ROOTS.length; i++) {
var m = MODULE_ROOTS[i];
var p = path.replace(m.module_name, m.module_root);
// Longest regex wins when multiple match
var len = m.module_name.toString().length;
if (p !== path && len > lengthOfMatch) {
lengthOfMatch = len;
match = p;
matchedEntry = m;
}
}
if (match) {
return match;
}
return null;
}
/**
* The runfiles manifest maps from short_path
* https://docs.bazel.build/versions/master/skylark/lib/File.html#short_path
* to the actual location on disk where the file can be read.
*
* In a sandboxed execution, it does not exist. In that case, runfiles must be
* resolved from a symlink tree under the runfiles dir.
* See https://github.com/bazelbuild/bazel/issues/3726
*/
function loadRunfilesManifest(manifestPath) {
// If the manifest doesn't exist, we're not running on Windows, and don't need it.
if (!fs.existsSync(manifestPath)) {
return;
}
const result = Object.create(null);
const input = fs.readFileSync(manifestPath, {encoding: 'utf-8'});
for (const line of input.split("\n")) {
if (!line) continue;
const [runfilesPath, realPath] = line.split(" ");
result[runfilesPath] = realPath;
}
return result;
}
const runfilesManifest = loadRunfilesManifest(process.env.RUNFILES_MANIFEST_FILE);
function resolveRunfiles(...pathSegments) {
// Remove any empty strings from pathSegments
pathSegments = pathSegments.filter(segment => segment);
const defaultPath = path.join(process.env.RUNFILES, ...pathSegments);
if (runfilesManifest) {
// Join on forward slash, because even on Windows the runfiles_manifest file
// is written with forward slash.
const runfilesEntry = pathSegments.join('/');
// Add .js as a workaround for https://github.com/bazelbuild/rules_nodejs/issues/25
return runfilesManifest[runfilesEntry] || runfilesManifest[runfilesEntry + '.js'] || defaultPath;
}
return defaultPath;
}
var originalResolveFilename = module.constructor._resolveFilename;
module.constructor._resolveFilename =
function(request, parent) {
var failedResolutions = [];
var resolveLocations = [
request,
resolveRunfiles(request),
resolveRunfiles(
'TEMPLATED_user_workspace_name', 'TEMPLATED_label_package',
'node_modules', request),
];
// Additional search path in case the build is across workspaces.
// See comment in node.bzl.
if ('TEMPLATED_label_workspace_name') {
resolveLocations.push(
resolveRunfiles(
'TEMPLATED_label_workspace_name', 'TEMPLATED_label_package',
'node_modules', request)
);
}
for (var location of resolveLocations) {
try {
return originalResolveFilename(location, parent);
} catch (e) {
failedResolutions.push(location);
}
}
var moduleRoot = resolveToModuleRoot(request);
if (moduleRoot) {
var moduleRootInRunfiles = resolveRunfiles(moduleRoot);
try {
var filename = module.constructor._findPath(moduleRootInRunfiles, []);
if (!filename) {
throw new Error(`No file ${request} found in module root ${moduleRoot}`);
}
return filename;
} catch (e) {
console.error(`Failed to findPath for ${moduleRootInRunfiles}`);
throw e;
}
}
var error = new Error(`Cannot find module '${request}'\n looked in:` +
failedResolutions.map(r => '\n ' + r));
error.code = 'MODULE_NOT_FOUND';
throw error;
}
// Load all bootstrap modules before loading the entrypoint.
for (var i = 0; i < BOOTSTRAP.length; i++) {
try {
module.constructor._load(BOOTSTRAP[i], this);
} catch (e) {
console.error('bootstrap failure ' + e.stack || e);
process.exit(1);
}
}
if (require.main === module) {
// Set the actual entry point in the arguments list.
// argv[0] == node, argv[1] == entry point.
// NB: entry_point below is replaced during the build process.
var mainScript = process.argv[1] = 'TEMPLATED_entry_point';
try {
module.constructor._load(mainScript, this, /*isMain=*/true);
} catch (e) {
console.error('failed to load main ', e.stack || e);
process.exit(1);
}
}