in internal/npm_install/generate_build_file.ts [329:436]
async function generatePackageBuildFiles(pkg: Dep) {
// If a BUILD file was shipped with the package we should symlink the generated BUILD file
// instead of append its contents to the end of the one we were going to generate.
// https://github.com/bazelbuild/rules_nodejs/issues/2131
let buildFilePath: string|undefined;
if (pkg._files.includes('BUILD')) buildFilePath = 'BUILD';
if (pkg._files.includes('BUILD.bazel')) buildFilePath = 'BUILD.bazel';
const nodeModules = nodeModulesFolder();
// Recreate the pkg dir inside the node_modules folder
const nodeModulesPkgDir = `${nodeModules}/${pkg._dir}`;
// Check if the current package dep dir is a symlink (which happens when we
// install a node_module with link:)
const isPkgDirASymlink = await fs.lstat(nodeModulesPkgDir)
.then(stat => stat.isSymbolicLink())
.catch(constant(false));
// Mark build file as one to symlink instead of generate as the package dir is a symlink, we
// have a BUILD file and the pkg is written inside the workspace
const symlinkBuildFile =
isPkgDirASymlink && buildFilePath && !config.generate_local_modules_build_files;
// Log if a BUILD file was expected but was not found
if (isPkgDirASymlink && !buildFilePath && !config.generate_local_modules_build_files) {
console.log(`[yarn_install/npm_install]: package ${
nodeModulesPkgDir} is local symlink and as such a BUILD file for it is expected but none was found. Please add one at ${
await fs.realpath(nodeModulesPkgDir)}`);
}
// The following won't be used in a symlink build file case
let buildFile = config.exports_directories_only ?
printPackageExportsDirectories(pkg) :
printPackageLegacy(pkg);
if (buildFilePath) {
buildFile = buildFile + '\n' +
await fs.readFile(path.join(nodeModules, pkg._dir, buildFilePath), 'utf-8');
} else {
buildFilePath = 'BUILD.bazel';
}
// if the dependency doesn't appear in the given package.json file, and the 'strict_visibility' flag is set
// on the npm_install / yarn_install rule, then set the visibility to be limited internally to the @repo workspace
// if the dependency is listed, set it as public
// if the flag is false, then always set public visibility
const visibility = !pkg._directDependency && config.strict_visibility ?
config.limited_visibility :
PUBLIC_VISIBILITY;
// If the package didn't ship a bin/BUILD file, generate one.
if (!pkg._files.includes('bin/BUILD.bazel') && !pkg._files.includes('bin/BUILD')) {
const binBuildFile = printPackageBin(pkg);
if (binBuildFile.length) {
await writeFile(
path.posix.join(pkg._dir, 'bin', 'BUILD.bazel'), generateBuildFileHeader(visibility) + binBuildFile);
}
}
// If there's an index.bzl in the package then copy all the package's files
// other than the BUILD file which we'll write below.
// (maybe we shouldn't copy .js though, since it belongs under node_modules?)
const hasIndexBzl = pkg._files.includes('index.bzl')
if (hasIndexBzl) {
await pkg._files.filter(f => f !== 'BUILD' && f !== 'BUILD.bazel').reduce(async (prev, file) => {
if (/^node_modules[/\\]/.test(file)) {
// don't copy over nested node_modules
return;
}
// don't support rootPath here?
let destFile = path.posix.join(pkg._dir, file);
const basename = path.basename(file);
const basenameUc = basename.toUpperCase();
// Bazel BUILD files from npm distribution would have been renamed earlier with a _ prefix so
// we restore the name on the copy
if (basenameUc === '_BUILD' || basenameUc === '_BUILD.BAZEL') {
destFile = path.posix.join(path.dirname(destFile), basename.substr(1));
}
const src = path.posix.join(nodeModules, pkg._dir, file);
await prev;
await mkdirp(path.dirname(destFile));
await fs.copyFile(src, destFile);
}, Promise.resolve());
}
const indexFile = printIndexBzl(pkg);
if (indexFile.length) {
await writeFile(path.posix.join(pkg._dir, hasIndexBzl ? 'private' : '', 'index.bzl'), indexFile);
const buildContent = `
# For integration testing
exports_files(["index.bzl"])
`;
if (hasIndexBzl) {
await writeFile(path.posix.join(pkg._dir, 'private', 'BUILD.bazel'), buildContent);
} else {
buildFile += buildContent;
}
}
if (!symlinkBuildFile) {
await writeFile(
path.posix.join(pkg._dir, buildFilePath), generateBuildFileHeader(visibility) + buildFile);
} else {
const realPathBuildFileForPkg =
await fs.realpath(path.posix.join(nodeModulesPkgDir, buildFilePath));
await createFileSymlink(realPathBuildFileForPkg, path.posix.join(pkg._dir, buildFilePath));
}
}