build(bazel): clean up pathing in aio build tooling

Make use of process.env.RUNFILES.
This commit is contained in:
Derek Cormier 2022-09-22 14:15:08 -07:00 committed by Joey Perrott
parent 885d74f204
commit e4b82cea26
12 changed files with 216 additions and 53 deletions

View file

@ -25,6 +25,9 @@ http_archive(
http_archive(
name = "build_bazel_rules_nodejs",
patches = [
"//:tools/bazel-repo-patches/rules_nodejs__b02128b178.patch",
],
sha256 = "b011d6206e4e76696eda8287618a2b6375ff862317847cdbe38f8d0cd206e9ce",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.6.0/rules_nodejs-5.6.0.tar.gz"],
)

View file

@ -291,7 +291,6 @@ architect(
nodejs_binary(
name = "docs-watch",
chdir = package_name(),
data = APPLICATION_FILES + [
"//aio/scripts:fast-serve-and-watch",
] + select({
@ -301,9 +300,6 @@ nodejs_binary(
enable_linker = True,
entry_point = "//aio/scripts:fast-serve-and-watch.js",
env = {
# Tell dgeni packages where the project root is since we used chdir
"PROJECT_ROOT": "../",
# Have the authors package output its low-fi dgeni build
# to a different directory in the runfiles tree because bazel
# write-protects original dgeni runfiles. Then in angular.json

View file

@ -121,10 +121,7 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}):
# Generate example boilerplate
npm_package_bin(
name = "boilerplate",
args = ["add", native.package_name()],
env = {
"BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH": "$(@D)",
},
args = ["add", native.package_name(), "$(@D)"],
data = [":files"],
output_dir = True,
tool = "//aio/tools/examples:example-boilerplate",

View file

@ -3,7 +3,7 @@ import path from 'node:path';
import sh from 'shelljs';
import treeKill from 'tree-kill';
const RUNFILES_ROOT = path.resolve('.');
const RUNFILES_ROOT = path.resolve(process.env.RUNFILES, 'angular');
sh.set('-e');

View file

@ -8,6 +8,7 @@ EXAMPLE_BOILERPLATE_SRCS = [
"example-boilerplate.js",
"constants.js",
"//aio/tools/examples/shared",
"//aio/content/examples",
]
EXAMPLE_BOILERPLATE_DEPS = [

View file

@ -1,12 +1,14 @@
const path = require('canonical-path');
// Bazel sets the environment variable BUILD_WORKSPACE_DIRECTORY when calling bazel run,
// which points to the root of the source tree. When running create-example we want to
// point to the source tree. In build and test cases we want to point to the output tree.
exports.PROJECT_ROOT = process.env.BUILD_WORKSPACE_DIRECTORY || path.resolve(__dirname, '../../../');
exports.EXAMPLES_BASE_PATH = path.resolve(this.PROJECT_ROOT, 'aio', 'content', 'examples');
exports.SHARED_PATH = path.resolve(this.PROJECT_ROOT, 'aio', 'tools', 'examples', 'shared');
exports.RUNFILES_ROOT = path.resolve(process.env.RUNFILES, 'angular');
exports.getExamplesBasePath = function(root) {
return path.join(root, 'aio', 'content', 'examples');
}
exports.getSharedPath = function(root) {
return path.join(root, 'aio', 'tools', 'examples', 'shared');
}
exports.EXAMPLE_CONFIG_FILENAME = 'example-config.json';
exports.STACKBLITZ_CONFIG_FILENAME = 'stackblitz.json';
exports.BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH = process.env.BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH || process.env.TEST_TMPDIR;

View file

@ -5,9 +5,16 @@ const path = require('canonical-path');
const shelljs = require('shelljs');
const yargs = require('yargs');
const buildozer = require('@bazel/buildozer');
const {EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, PROJECT_ROOT, SHARED_PATH, STACKBLITZ_CONFIG_FILENAME} =
const {RUNFILES_ROOT, getExamplesBasePath, getSharedPath, EXAMPLE_CONFIG_FILENAME, STACKBLITZ_CONFIG_FILENAME} =
require('./constants');
// BUILD_WORKSPACE_DIRECTORY is set by Bazel when calling `bazel run` and points to the
// root of the source tree (e.g., for creating a new example in the source tree). Otherwise,
// we are in a test so use the runfiles root.
const PROJECT_ROOT = path.resolve(process.env.BUILD_WORKSPACE_DIRECTORY || RUNFILES_ROOT);
const EXAMPLES_BASE_PATH = getExamplesBasePath(PROJECT_ROOT);
const SHARED_PATH = getSharedPath(PROJECT_ROOT);
const BASIC_SOURCE_PATH = path.resolve(SHARED_PATH, 'example-scaffold');
shelljs.set('-e');

View file

@ -4,7 +4,11 @@ const ignore = require('ignore');
const path = require('canonical-path');
const shelljs = require('shelljs');
const yargs = require('yargs');
const {EXAMPLES_BASE_PATH, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, EXAMPLE_CONFIG_FILENAME, SHARED_PATH} = require('./constants');
const {RUNFILES_ROOT, getExamplesBasePath, getSharedPath, EXAMPLE_CONFIG_FILENAME} = require('./constants');
const PROJECT_ROOT = RUNFILES_ROOT;
const EXAMPLES_BASE_PATH = getExamplesBasePath(PROJECT_ROOT);
const SHARED_PATH = getSharedPath(PROJECT_ROOT);
const BOILERPLATE_BASE_PATH = path.resolve(SHARED_PATH, 'boilerplate');
const BOILERPLATE_CLI_PATH = path.resolve(BOILERPLATE_BASE_PATH, 'cli');
@ -14,7 +18,7 @@ class ExampleBoilerPlate {
/**
* Add boilerplate files to an example
*/
add(exampleFolder) {
add(exampleFolder, outputDir) {
const gitignore = ignore().add(fs.readFileSync(path.resolve(BOILERPLATE_BASE_PATH, '.gitignore'), 'utf8'));
const exampleConfig = this.loadJsonFile(path.resolve(exampleFolder, EXAMPLE_CONFIG_FILENAME));
@ -31,22 +35,21 @@ class ExampleBoilerPlate {
const boilerPlateType = exampleConfig.projectType || 'cli';
const boilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, boilerPlateType);
const outputPath = BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH;
shelljs.mkdir('-p', outputPath);
shelljs.mkdir('-p', outputDir);
// All example types other than `cli` and `systemjs` are based on `cli`. Copy over the `cli`
// boilerplate files first.
// (Some of these files might be later overwritten by type-specific files.)
if (boilerPlateType !== 'cli' && boilerPlateType !== 'systemjs') {
this.copyDirectoryContents(BOILERPLATE_CLI_PATH, outputPath, isPathIgnored);
this.copyDirectoryContents(BOILERPLATE_CLI_PATH, outputDir, isPathIgnored);
}
// Copy the type-specific boilerplate files.
this.copyDirectoryContents(boilerPlateBasePath, outputPath, isPathIgnored);
this.copyDirectoryContents(boilerPlateBasePath, outputDir, isPathIgnored);
// Copy the common boilerplate files (unless explicitly not used).
if (exampleConfig.useCommonBoilerplate !== false) {
this.copyDirectoryContents(BOILERPLATE_COMMON_PATH, outputPath, isPathIgnored);
this.copyDirectoryContents(BOILERPLATE_COMMON_PATH, outputDir, isPathIgnored);
}
}
@ -80,7 +83,7 @@ class ExampleBoilerPlate {
main() {
yargs.usage('$0 <cmd> [args]')
.command('add', 'add the boilerplate to each example', yrgs => this.add(yrgs.argv._[1]))
.command('add <exampleDir> <outputDir>', 'create boilerplate for an example', yrgs => this.add(yrgs.argv._[1], yrgs.argv._[2]))
.command('list-overrides', 'list all the boilerplate files that have been overridden in examples', () => this.listOverrides())
.demandCommand(1, 'Please supply a command from the list above')
.argv;

View file

@ -3,12 +3,18 @@ const fs = require('fs-extra');
const glob = require('glob');
const shelljs = require('shelljs');
const {BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, EXAMPLES_BASE_PATH} = require("./constants");
const {RUNFILES_ROOT, getExamplesBasePath, getSharedPath} = require("./constants");
const PROJECT_ROOT = RUNFILES_ROOT;
const EXAMPLES_BASE_PATH = getExamplesBasePath(PROJECT_ROOT);
const SHARED_PATH = getSharedPath(PROJECT_ROOT);
const exampleBoilerPlate = require('./example-boilerplate');
const outputDir = process.env.TEST_TMPDIR; // Bazel-provided temp dir
describe('example-boilerplate tool', () => {
describe('add', () => {
const sharedDir = path.resolve(__dirname, 'shared');
const sharedDir = SHARED_PATH;
const exampleFolder = 'a';
beforeEach(() => {
@ -21,12 +27,12 @@ describe('example-boilerplate tool', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.returnValue({ projectType: 'systemjs' });
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
expect(exampleBoilerPlate.copyDirectoryContents).toHaveBeenCalledTimes(2);
expect(exampleBoilerPlate.copyDirectoryContents.calls.allArgs()).toEqual([
[`${boilerplateDir}/systemjs`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/common`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/systemjs`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/common`, outputDir, jasmine.any(Function)],
]);
});
@ -34,12 +40,12 @@ describe('example-boilerplate tool', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.returnValue({ projectType: 'cli' });
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
expect(exampleBoilerPlate.copyDirectoryContents).toHaveBeenCalledTimes(2);
expect(exampleBoilerPlate.copyDirectoryContents.calls.allArgs()).toEqual([
[`${boilerplateDir}/cli`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/common`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/cli`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/common`, outputDir, jasmine.any(Function)],
]);
});
@ -47,12 +53,12 @@ describe('example-boilerplate tool', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.returnValue({});
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
expect(exampleBoilerPlate.copyDirectoryContents).toHaveBeenCalledTimes(2);
expect(exampleBoilerPlate.copyDirectoryContents.calls.allArgs()).toEqual([
[`${boilerplateDir}/cli`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/common`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/cli`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/common`, outputDir, jasmine.any(Function)],
]);
});
@ -60,13 +66,13 @@ describe('example-boilerplate tool', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.returnValue({ projectType: 'i18n' });
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
expect(exampleBoilerPlate.copyDirectoryContents).toHaveBeenCalledTimes(3);
expect(exampleBoilerPlate.copyDirectoryContents.calls.allArgs()).toEqual([
[`${boilerplateDir}/cli`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/i18n`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/common`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/cli`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/i18n`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/common`, outputDir, jasmine.any(Function)],
]);
});
@ -74,13 +80,13 @@ describe('example-boilerplate tool', () => {
const boilerplateDir = path.resolve(sharedDir, 'boilerplate');
exampleBoilerPlate.loadJsonFile.and.returnValue({ projectType: 'universal' });
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
expect(exampleBoilerPlate.copyDirectoryContents).toHaveBeenCalledTimes(3);
expect(exampleBoilerPlate.copyDirectoryContents.calls.allArgs()).toEqual([
[`${boilerplateDir}/cli`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/universal`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/common`, BAZEL_EXAMPLE_BOILERPLATE_OUTPUT_PATH, jasmine.any(Function)],
[`${boilerplateDir}/cli`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/universal`, outputDir, jasmine.any(Function)],
[`${boilerplateDir}/common`, outputDir, jasmine.any(Function)],
]);
});
@ -90,7 +96,7 @@ describe('example-boilerplate tool', () => {
'overrideBoilerplate': [ 'c/d' ]
});
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
const isPathIgnored = exampleBoilerPlate.copyDirectoryContents.calls.first().args[2];
expect(isPathIgnored(`${boilerplateDir}/cli/a/b`)).toBe(false);
@ -98,7 +104,7 @@ describe('example-boilerplate tool', () => {
});
it('should try to load the example config file', () => {
exampleBoilerPlate.add(exampleFolder);
exampleBoilerPlate.add(exampleFolder, outputDir);
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledTimes(1);
expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve(`${exampleFolder}/example-config.json`));
});

View file

@ -5,9 +5,10 @@ const { readdirSync } = require('fs');
// directory (TEST_TMPDIR) that bazel provides for tests.
const BAZEL_OUTPUT_PATH = process.env.BAZEL_DGENI_OUTPUT_PATH || process.env.TEST_TMPDIR;
// During a bazel build this script executes in the execroot, so assume
// the root is the current directory unless overridden.
const PROJECT_ROOT = resolve(process.env.PROJECT_ROOT || '.');
// The current directory is always the correct project root. During a build, this evalutates
// to the exec root. During the "fast-serve" bazel run mode, it resolves to the runfiles root
// of the fast serve binary.
const PROJECT_ROOT = resolve('.');
const AIO_PATH = resolve(PROJECT_ROOT, 'aio');
const TEMPLATES_PATH = resolve(AIO_PATH, 'tools/transforms/templates');
@ -26,4 +27,3 @@ function requireFolder(dirname, folderPath) {
.map(p => require(resolve(absolutePath, p)));
}
module.exports = { BAZEL_OUTPUT_PATH, PROJECT_ROOT, AIO_PATH, TEMPLATES_PATH, API_TEMPLATES_PATH, CONTENTS_PATH, GUIDE_EXAMPLES_PATH, SRC_PATH, OUTPUT_PATH, DOCS_OUTPUT_PATH, API_SOURCE_PATH, requireFolder };

View file

@ -0,0 +1,148 @@
diff --git internal/node/launcher.sh internal/node/launcher.sh
index d0e8df9..a830907 100755
--- internal/node/launcher.sh
+++ internal/node/launcher.sh
@@ -14,7 +14,7 @@
# limitations under the License.
# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix)
-function isWindows {
+function is_windows {
case "$(uname -s)" in
CYGWIN*) local IS_WINDOWS=1 ;;
MINGW*) local IS_WINDOWS=1 ;;
@@ -29,14 +29,13 @@ function isWindows {
# It helps to normalizes paths when running on Windows.
#
# Example:
-# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -> /c/users/xuser/_bazel_xuser/7q7kkv32/execroot/a/b/c
-function normalizeWindowsPath {
- # Apply the followings paths transformations to normalize paths on Windows
- # -process driver letter
- # -convert path separator
- # -lowercase everything
- echo $(sed -e 's#^\(.\):#/\L\1#' -e 's#\\#/#g' -e 's/[A-Z]/\L&/g' <<< "$1")
- return
+# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -> /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C
+function normalize_windows_path {
+ # Apply the followings paths transformations to normalize paths on Windows
+ # -process driver letter
+ # -convert path separator
+ sed -e 's#^\(.\):#/\L\1#' -e 's#\\#/#g' <<< "$1"
+ return
}
# --- begin runfiles.bash initialization v2 ---
@@ -73,51 +72,71 @@ source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
# blaze.
# Case 5a is handled like case 1.
# Case 6a is handled like case 3.
-if [[ -n "${RUNFILES_MANIFEST_ONLY:-}" ]]; then
- # Windows only has a manifest file instead of symlinks.
- if [[ $(isWindows) -eq "1" ]]; then
- # If Windows normalizing the path and case insensitive removing the `/MANIFEST` part of the path
- NORMALIZED_RUNFILES_MANIFEST_FILE_PATH=$(normalizeWindowsPath $RUNFILES_MANIFEST_FILE)
- RUNFILES=$(sed 's|\/MANIFEST$||i' <<< $NORMALIZED_RUNFILES_MANIFEST_FILE_PATH)
- else
- RUNFILES=${RUNFILES_MANIFEST_FILE%/MANIFEST}
- fi
-elif [[ -n "${TEST_SRCDIR:-}" ]]; then
- # Case 4, bazel has identified runfiles for us.
- RUNFILES="${TEST_SRCDIR:-}"
-else
- case "$0" in
- /*) self="$0" ;;
- *) self="$PWD/$0" ;;
- esac
- while true; do
- if [[ -e "$self.runfiles" ]]; then
- RUNFILES="$self.runfiles"
- break
- fi
-
- if [[ $self == *.runfiles/* ]]; then
- RUNFILES="${self%%.runfiles/*}.runfiles"
- # don't break; this is a last resort for case 6b
+if [ "${TEST_SRCDIR:-}" ]; then
+ # Case 4, bazel has identified runfiles for us.
+ if [ "$(is_windows)" -eq "1" ]; then
+ # If Windows, normalize the path
+ RUNFILES=$(normalize_windows_path "$TEST_SRCDIR")
+ else
+ RUNFILES="$TEST_SRCDIR"
fi
-
- if [[ ! -L "$self" ]]; then
- break;
+elif [ "${RUNFILES_MANIFEST_FILE:-}" ]; then
+ if [ "$(is_windows)" -eq "1" ]; then
+ # If Windows, normalize the path
+ NORMALIZED_RUNFILES_MANIFEST_FILE=$(normalize_windows_path "$RUNFILES_MANIFEST_FILE")
+ else
+ NORMALIZED_RUNFILES_MANIFEST_FILE="$RUNFILES_MANIFEST_FILE"
fi
-
- readlink="$(readlink "$self")"
- if [[ "$readlink" = /* ]]; then
- self="$readlink"
+ if [[ "${NORMALIZED_RUNFILES_MANIFEST_FILE}" == *.runfiles_manifest ]]; then
+ # Newer versions of Bazel put the manifest besides the runfiles with the suffix .runfiles_manifest.
+ # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the
+ # runfiles directory and named my_binary.runfiles_manifest
+ RUNFILES=${NORMALIZED_RUNFILES_MANIFEST_FILE%_manifest}
+ elif [[ "${NORMALIZED_RUNFILES_MANIFEST_FILE}" == */MANIFEST ]]; then
+ # Older versions of Bazel put the manifest file named MANIFEST in the runfiles directory
+ RUNFILES=${NORMALIZED_RUNFILES_MANIFEST_FILE%/MANIFEST}
else
- # resolve relative symlink
- self="${self%%/*}/$readlink"
+ echo "\n>>>> FAIL: Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE. <<<<\n\n" >&2
+ exit 1
fi
- done
-
- if [[ -z "$RUNFILES" ]]; then
- echo " >>>> FAIL: RUNFILES environment variable is not set. <<<<" >&2
- exit 1
- fi
+else
+ case "$0" in
+ /*) self="$0" ;;
+ *) self="$PWD/$0" ;;
+ esac
+ while true; do
+ if [ -e "$self.runfiles" ]; then
+ RUNFILES="$self.runfiles"
+ break
+ fi
+
+ if [[ "$self" == *.runfiles/* ]]; then
+ RUNFILES="${self%%.runfiles/*}.runfiles"
+ # don't break; this is a last resort for case 6b
+ fi
+
+ if [ ! -L "$self" ]; then
+ break;
+ fi
+
+ readlink="$(readlink "$self")"
+ if [[ "$readlink" == /* ]]; then
+ self="$readlink"
+ else
+ # resolve relative symlink
+ self="${self%%/*}/$readlink"
+ fi
+ done
+
+ if [ -z "${RUNFILES:-}" ]; then
+ echo "\n>>>> FAIL: RUNFILES environment variable is not set. <<<<\n\n" >&2
+ exit 1
+ fi
+fi
+if [ "${RUNFILES:0:1}" != "/" ]; then
+ # Ensure RUNFILES set above is an absolute path. It may be a path relative
+ # to the PWD in case where RUNFILES_MANIFEST_FILE is used above.
+ RUNFILES="$PWD/$RUNFILES"
fi
export RUNFILES
# --- end RUNFILES initialization ---

View file

@ -25,8 +25,8 @@ export async function resolve(specifier, context, defaultResolve) {
return defaultResolve(specifier, context, defaultResolve);
}
const runfilesWorkspaceRoot = path.resolve(process.env.RUNFILES_DIR || path.join(process.env.RUNFILES, 'angular'));
const nodeModules = path.join(runfilesWorkspaceRoot, process.env.NODE_MODULES_WORKSPACE_NAME, 'node_modules');
const runfilesRoot = path.resolve(process.env.RUNFILES, 'angular');
const nodeModules = path.join(runfilesRoot, process.env.NODE_MODULES_WORKSPACE_NAME, 'node_modules');
const packageImport = parsePackageImport(specifier);
const pathToNodeModule = path.join(nodeModules, packageImport.packageName);