Skip to content

Commit

Permalink
chore: parallelize link creation in linker
Browse files Browse the repository at this point in the history
  • Loading branch information
soldair authored and alexeagle committed Sep 11, 2019
1 parent 14003a0 commit ab7d707
Showing 1 changed file with 47 additions and 17 deletions.
64 changes: 47 additions & 17 deletions internal/linker/link_node_modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,21 @@ Include as much of the build output as you can without disclosing anything confi
`);
}

function symlink(target: string, path: string) {
if (fs.existsSync(path)) {
async function symlink(target: string, path: string) {
log_verbose(`symlink( ${path} -> ${target} )`);
// Use junction on Windows since symlinks require elevated permissions.
// We only link to directories so junctions work for us.
try{
await fs.promises.symlink(target, path, 'junction');
} catch(e){
if(e.code !== 'ENOENT'){
throw e;
}
// We assume here that the path is already linked to the correct target.
// Could add some logic that asserts it here, but we want to avoid an extra
// filesystem access so we should only do it under some kind of strict mode.
return;
}
log_verbose(`symlink( ${path} -> ${target} )`);
// Use junction on Windows since symlinks require elevated permissions.
// We only link to directories so junctions work for us.
fs.symlinkSync(target, path, 'junction');

if (VERBOSE_LOGS) {
// Be verbose about creating a bad symlink
// Maybe this should fail in production as well, but again we want to avoid
Expand Down Expand Up @@ -157,11 +161,25 @@ export class Runfiles {
// TypeScript lib.es5.d.ts has a mistake: JSON.parse does accept Buffer.
declare global {
interface JSON {
parse(b: Buffer): any;
parse(b: {toString:()=>string}): any;
}
}

// There is no fs.promises.exists function because
// node core is of the opinion that exists is always too racey to rely on.
async function exists(p:string){
try{
await fs.promises.stat(p)
return true;
} catch(e){
if(e.code === 'ENOENT'){
return false;
}
throw e;
}
}

export function main(args: string[], runfiles: Runfiles) {
export async function main(args: string[], runfiles: Runfiles) {
if (!args || args.length < 1)
throw new Error('link_node_modules.js requires one argument: modulesManifest path');

Expand Down Expand Up @@ -189,37 +207,49 @@ export function main(args: string[], runfiles: Runfiles) {
}

// Create the $pwd/node_modules directory that node will resolve from
symlink(rootDir, 'node_modules');
await symlink(rootDir, 'node_modules');
process.chdir(rootDir);

// Symlinks to packages need to reach back to the workspace/runfiles directory
const workspaceRelative = path.relative('.', workspaceDir);
const runfilesRelative = runfiles.dir ? path.relative('.', runfiles.dir) : undefined;

// Now add symlinks to each of our first-party packages so they appear under the node_modules tree
for (const m of Object.keys(modules)) {
const links = []

const linkModule = async (name:string,modulePath:string)=>{
let target: string|undefined;

// Look in the runfiles first
// TODO: this could be a method in the Runfiles class
if (runfiles.manifest) {
target = runfiles.lookupDirectory(modules[m]);
target = runfiles.lookupDirectory(modulePath);
} else if (runfilesRelative) {
target = path.join(runfilesRelative, modules[m]);
target = path.join(runfilesRelative, modulePath);
}

// It sucks that we have to do a FS call here.
// TODO: could we know which packages are statically linked??
if (!target || !fs.existsSync(target)) {
if (!target || !await exists(target)) {
// Try the execroot
target = path.join(workspaceRelative, toWorkspaceDir(modules[m]));
target = path.join(workspaceRelative, toWorkspaceDir(modulePath));
}
symlink(target, m);

await symlink(target, name);
}

for (const m of Object.keys(modules)) {
links.push(linkModule(m,modules[m]))
}

await Promise.all(links);

return 0;
}

if (require.main === module) {
process.exitCode = main(process.argv.slice(2), new Runfiles());
(async ()=>{
process.exitCode = await main(process.argv.slice(2), new Runfiles());
})();
}

0 comments on commit ab7d707

Please sign in to comment.