blob: 6e30a8251a38124708f43c5e074e11b433201434 [file]
/**
* @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 This script generates the BUILD.bazel file for NodeJS, npm & yarn.
*/
'use strict';
const fs = require('fs');
const path = require('path');
const IS_WINDOWS = TEMPLATED_is_windows;
const NODE_DIR = 'TEMPLATED_node_dir';
const YARN_DIR = 'TEMPLATED_yarn_dir';
const NODE_ACTUAL = 'TEMPLATED_node_actual';
const NPM_ACTUAL = 'TEMPLATED_npm_actual';
const YARN_ACTUAL = 'TEMPLATED_yarn_actual';
if (require.main === module) {
main();
}
function mkdirp(dirname) {
if (!fs.existsSync(dirname)) {
mkdirp(path.dirname(dirname));
fs.mkdirSync(dirname);
}
}
function writeFileSync(filePath, contents) {
mkdirp(path.dirname(filePath));
fs.writeFileSync(filePath, contents);
}
/**
* Main entrypoint.
* Write BUILD file.
*/
function main() {
generateBuildFile()
}
module.exports = { main };
function generateBuildFile() {
// *.pyc files are generated during node-gyp compilation and include
// absolute paths, making them non-hermetic.
// See https://github.com/bazelbuild/rules_nodejs/issues/347
const excludedFiles = ['.md', '.html', '.pyc'];
const nodejsSrcFiles = filterFilesForFilegroup(listFiles(NODE_DIR), [], excludedFiles)
const yarnSrcFiles = filterFilesForFilegroup(listFiles(YARN_DIR), [], excludedFiles)
const binaryExt = IS_WINDOWS ? '.cmd' : '';
const buildFile = `# Generated by node_repositories.bzl
package(default_visibility = ["//visibility:public"])
exports_files([
"run_npm.sh.template",
"bin/node_args.sh",
"${NODE_DIR}/bin/node",
"bin/node${binaryExt}",
"bin/npm${binaryExt}",
"bin/npm_node_repositories${binaryExt}",
"bin/yarn${binaryExt}",
"bin/yarn_node_repositories${binaryExt}",
])
alias(name = "node", actual = "${NODE_ACTUAL}")
alias(name = "npm", actual = "${NPM_ACTUAL}")
alias(name = "yarn", actual = "${YARN_ACTUAL}")
filegroup(
name = "node_runfiles",
srcs = [
${nodejsSrcFiles.map(f => `"${NODE_DIR}/${f}",`).join('\n ')}
${yarnSrcFiles.map(f => `"${YARN_DIR}/${f}",`).join('\n ')}
],
)
`
writeFileSync('BUILD.bazel', buildFile);
}
/**
* Returns an array of all the files under a directory as relative
* paths to the directory.
*/
function listFiles(rootDir, subDir = '') {
const dir = path.posix.join(rootDir, subDir);
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
return [];
}
return fs
.readdirSync(dir)
.reduce((files, file) => {
const fullPath = path.posix.join(dir, file);
const relPath = path.posix.join(subDir, file);
let stat;
try {
stat = fs.statSync(fullPath);
} catch (e) {
throw e;
}
return stat.isDirectory() ? files.concat(listFiles(rootDir, relPath)) :
files.concat(relPath);
}, []);
}
/**
* A filter function for a bazel filegroup.
* @param files array of files to filter
* @param allowedExts list of white listed extensions; if empty, no filter is done on extensions;
* '' empty string denotes to allow files with no extensions, other extensions
* are listed with '.ext' notation such as '.d.ts'.
*/
function filterFilesForFilegroup(files, allowedExts = [], excludedExts = []) {
// Files with spaces (\x20) or unicode characters (<\x20 && >\x7E) are not allowed in
// Bazel runfiles. See https://github.com/bazelbuild/bazel/issues/4327
files = files.filter(f => !f.match(/[^\x21-\x7E]/));
if (allowedExts.length) {
const allowNoExts = allowedExts.includes('');
files = files.filter(f => {
// include files with no extensions if noExt is true
if (allowNoExts && !path.extname(f)) return true;
// filter files in allowedExts
for (const e of allowedExts) {
if (e && f.endsWith(e)) {
return true;
}
}
return false;
})
}
if (excludedExts.length) {
files = files.filter(f => {
// filter out files in excludedExts
for (const e of excludedExts) {
if (e && f.endsWith(e)) {
return false;
}
}
return true;
})
}
return files;
}