in internal/linker/index.js [276:500]
function main(args, runfiles) {
return __awaiter(this, void 0, void 0, function* () {
if (!args || args.length < 1)
throw new Error('requires one argument: modulesManifest path');
const [modulesManifest] = args;
log_verbose('manifest file:', modulesManifest);
let { workspace, bin, roots, module_sets } = JSON.parse(fs.readFileSync(modulesManifest));
log_verbose('manifest contents:', JSON.stringify({ workspace, bin, roots, module_sets }, null, 2));
roots = roots || {};
module_sets = module_sets || {};
const startCwd = process.cwd().replace(/\\/g, '/');
log_verbose('startCwd:', startCwd);
const execroot = findExecroot(startCwd);
log_verbose('execroot:', execroot ? execroot : 'not found');
const isExecroot = startCwd == execroot;
log_verbose('isExecroot:', isExecroot.toString());
const isBazelRun = !!process.env['BUILD_WORKSPACE_DIRECTORY'];
log_verbose('isBazelRun:', isBazelRun.toString());
if (!isExecroot && execroot) {
process.chdir(execroot);
log_verbose('changed directory to execroot', execroot);
}
function symlinkWithUnlink(target, p, stats = null) {
return __awaiter(this, void 0, void 0, function* () {
if (!path.isAbsolute(target)) {
target = path.resolve(process.cwd(), target);
}
if (stats === null) {
stats = yield gracefulLstat(p);
}
if (runfiles.manifest && execroot && stats !== null && stats.isSymbolicLink()) {
const symlinkPathRaw = gracefulReadlink(p);
if (symlinkPathRaw !== null) {
const symlinkPath = symlinkPathRaw.replace(/\\/g, '/');
if (path.relative(symlinkPath, target) != '' &&
!path.relative(execroot, symlinkPath).startsWith('..')) {
log_verbose(`Out-of-date symlink for ${p} to ${symlinkPath} detected. Target should be ${target}. Unlinking.`);
yield unlink(p);
}
else {
log_verbose(`The symlink at ${p} no longer exists, so no need to unlink it.`);
}
}
}
return symlink(target, p);
});
}
for (const packagePath of Object.keys(roots)) {
const externalWorkspace = roots[packagePath];
let workspaceNodeModules = yield resolveWorkspaceNodeModules(externalWorkspace, startCwd, isExecroot, execroot, runfiles);
if (yield exists(workspaceNodeModules)) {
log_verbose(`resolved ${externalWorkspace} external workspace node modules path to ${workspaceNodeModules}`);
}
else {
workspaceNodeModules = undefined;
}
let primaryNodeModules;
if (packagePath) {
const binNodeModules = path.posix.join(bin, packagePath, 'node_modules');
yield mkdirp(path.dirname(binNodeModules));
if (workspaceNodeModules) {
yield symlinkWithUnlink(workspaceNodeModules, binNodeModules);
primaryNodeModules = workspaceNodeModules;
}
else {
yield mkdirp(binNodeModules);
primaryNodeModules = binNodeModules;
}
if (!isBazelRun) {
const execrootNodeModules = path.posix.join(packagePath, 'node_modules');
yield mkdirp(path.dirname(execrootNodeModules));
yield symlinkWithUnlink(primaryNodeModules, execrootNodeModules);
}
}
else {
const execrootNodeModules = 'node_modules';
if (workspaceNodeModules) {
yield symlinkWithUnlink(workspaceNodeModules, execrootNodeModules);
primaryNodeModules = workspaceNodeModules;
}
else {
yield mkdirp(execrootNodeModules);
primaryNodeModules = execrootNodeModules;
}
}
if (!isExecroot) {
const runfilesNodeModules = path.posix.join(startCwd, packagePath, 'node_modules');
yield mkdirp(path.dirname(runfilesNodeModules));
yield symlinkWithUnlink(primaryNodeModules, runfilesNodeModules);
}
if (process.env['RUNFILES']) {
const stat = yield gracefulLstat(process.env['RUNFILES']);
if (stat && stat.isDirectory()) {
const runfilesNodeModules = path.posix.join(process.env['RUNFILES'], workspace, 'node_modules');
yield mkdirp(path.dirname(runfilesNodeModules));
yield symlinkWithUnlink(primaryNodeModules, runfilesNodeModules);
}
}
}
function isLeftoverDirectoryFromLinker(stats, modulePath) {
return __awaiter(this, void 0, void 0, function* () {
if (runfiles.manifest === undefined) {
return false;
}
if (!stats.isDirectory()) {
return false;
}
let isLeftoverFromPreviousLink = true;
yield visitDirectoryPreserveLinks(modulePath, (childPath, childStats) => __awaiter(this, void 0, void 0, function* () {
if (!childStats.isSymbolicLink()) {
isLeftoverFromPreviousLink = false;
}
}));
return isLeftoverFromPreviousLink;
});
}
function createSymlinkAndPreserveContents(stats, modulePath, target) {
return __awaiter(this, void 0, void 0, function* () {
const tmpPath = `${modulePath}__linker_tmp`;
log_verbose(`createSymlinkAndPreserveContents( ${modulePath} )`);
yield symlink(target, tmpPath);
yield visitDirectoryPreserveLinks(modulePath, (childPath, stat) => __awaiter(this, void 0, void 0, function* () {
if (stat.isSymbolicLink()) {
const targetPath = path.join(tmpPath, path.relative(modulePath, childPath));
log_verbose(`Cloning symlink into temporary created link ( ${childPath} )`);
yield mkdirp(path.dirname(targetPath));
yield symlink(targetPath, yield fs.promises.realpath(childPath));
}
}));
log_verbose(`Removing existing module so that new link can take place ( ${modulePath} )`);
yield unlink(modulePath);
yield fs.promises.rename(tmpPath, modulePath);
});
}
function linkModules(package_path, m) {
return __awaiter(this, void 0, void 0, function* () {
const symlinkIn = package_path ?
path.posix.join(bin, package_path, 'node_modules') :
'node_modules';
if (path.dirname(m.name)) {
yield mkdirp(`${symlinkIn}/${path.dirname(m.name)}`);
}
if (m.link) {
const modulePath = m.link;
let target;
if (isExecroot) {
target = `${startCwd}/${modulePath}`;
}
if (!isExecroot || !existsSync(target)) {
let runfilesPath = modulePath;
if (runfilesPath.startsWith(`${bin}/`)) {
runfilesPath = runfilesPath.slice(bin.length + 1);
}
else if (runfilesPath === bin) {
runfilesPath = '';
}
const externalPrefix = 'external/';
if (runfilesPath.startsWith(externalPrefix)) {
runfilesPath = runfilesPath.slice(externalPrefix.length);
}
else {
runfilesPath = path.posix.join(workspace, runfilesPath);
}
try {
target = runfiles.resolve(runfilesPath);
if (runfiles.manifest && modulePath.startsWith(`${bin}/`)) {
if (!target.match(_BAZEL_OUT_REGEX)) {
const e = new Error(`could not resolve module ${runfilesPath} in output tree`);
e.code = 'MODULE_NOT_FOUND';
throw e;
}
}
}
catch (err) {
target = undefined;
log_verbose(`runfiles resolve failed for module '${m.name}': ${err.message}`);
}
}
if (target && !path.isAbsolute(target)) {
target = path.resolve(process.cwd(), target);
}
const symlinkFile = `${symlinkIn}/${m.name}`;
const stats = yield gracefulLstat(symlinkFile);
const isLeftOver = (stats !== null && (yield isLeftoverDirectoryFromLinker(stats, symlinkFile)));
if (target && (yield exists(target))) {
if (stats !== null && isLeftOver) {
yield createSymlinkAndPreserveContents(stats, symlinkFile, target);
}
else {
yield symlinkWithUnlink(target, symlinkFile, stats);
}
}
else {
if (!target) {
log_verbose(`no symlink target found for module ${m.name}`);
}
else {
log_verbose(`potential target ${target} does not exists for module ${m.name}`);
}
if (isLeftOver) {
yield unlink(symlinkFile);
}
}
}
if (m.children) {
yield Promise.all(m.children.map(m => linkModules(package_path, m)));
}
});
}
const links = [];
for (const package_path of Object.keys(module_sets)) {
const modules = module_sets[package_path];
log_verbose(`modules for package path '${package_path}':\n${JSON.stringify(modules, null, 2)}`);
const moduleHierarchy = reduceModules(modules);
log_verbose(`mapping hierarchy for package path '${package_path}':\n${JSON.stringify(moduleHierarchy)}`);
links.push(...moduleHierarchy.map(m => linkModules(package_path, m)));
}
let code = 0;
yield Promise.all(links).catch(e => {
log_error(e);
code = 1;
});
return code;
});
}