diff --git a/.circleci/config.yml b/.circleci/config.yml index d5260de92469..702fdf1e1bc0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,10 +13,8 @@ var_2: &docker-firefox-image circleci/node:12.9.1-browsers # **Note**: When updating the beginning of the cache key, also update the cache key to match # the new cache key prefix. This allows us to take advantage of CircleCI's fallback caching. # Read more here: https://circleci.com/docs/2.0/caching/#restoring-cache. -var_3: &cache_key v4-ng-mat-{{ checksum "tools/bazel/postinstall-patches.js" }}-{{ checksum "WORKSPACE" }}-{{ checksum "yarn.lock" }} -# We want to invalidate the cache if the postinstall patches change. In order to apply new -# patches, a clean version of the node modules is needed. -var_4: &cache_fallback_key v4-ng-mat-{{ checksum "tools/bazel/postinstall-patches.js" }}- +var_3: &cache_key v4-ng-mat-{{ checksum "WORKSPACE" }}-{{ checksum "yarn.lock" }} +var_4: &cache_fallback_key v4-ng-mat- # Settings common to each job var_5: &job_defaults diff --git a/WORKSPACE b/WORKSPACE index 92a205ba754f..b74782fa6687 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,7 +1,4 @@ -workspace( - name = "angular_material", - managed_directories = {"@npm": ["node_modules"]}, -) +workspace(name = "angular_material") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") @@ -45,10 +42,20 @@ node_repositories( yarn_install( name = "npm", - # We add the postinstall patches file here so that Yarn will rerun whenever - # the patches script changes. - data = ["//:tools/bazel/postinstall-patches.js"], + # Ensure that all resources are available when the "postinstall" or "preinstall" scripts + # are executed in the Bazel sandbox. + data = [ + "//:angular-tsconfig.json", + "//:tools/bazel/flat_module_factory_resolution.patch", + "//:tools/bazel/manifest_externs_hermeticity.patch", + "//:tools/bazel/postinstall-patches.js", + "//:tools/npm/check-npm.js", + ], package_json = "//:package.json", + # Temporarily disable node_modules symlinking until the fix for + # https://github.com/bazelbuild/bazel/issues/8487 makes it into a + # future Bazel release + symlink_node_modules = False, yarn_lock = "//:yarn.lock", ) diff --git a/package.json b/package.json index 8c518db87ddf..d6a60166a4ef 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "yarn": ">= 1.19.1" }, "scripts": { - "postinstall": "node tools/bazel/postinstall-patches.js && ngcc --properties main --create-ivy-entry-points", + "postinstall": "node --preserve-symlinks --preserve-symlinks-main tools/bazel/postinstall-patches.js && ngcc --properties main --create-ivy-entry-points", "build": "node ./scripts/build-packages-dist.js", "bazel:buildifier": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,output-group,package-name,package-on-top,redefined-variable,repository-name,same-origin-load,string-iteration,unused-variable,unsorted-dict-items,out-of-order-load", "bazel:format-lint": "yarn -s bazel:buildifier --lint=warn --mode=check", diff --git a/tools/bazel/postinstall-patches.js b/tools/bazel/postinstall-patches.js index c4ce39b5e148..f8099e1e9553 100644 --- a/tools/bazel/postinstall-patches.js +++ b/tools/bazel/postinstall-patches.js @@ -8,18 +8,18 @@ const shelljs = require('shelljs'); const path = require('path'); const fs = require('fs'); -/** - * Version of the post install patch. Needs to be incremented when patches - * have been added or removed. - */ -const PATCH_VERSION = 1; - /** Path to the project directory. */ const projectDir = path.join(__dirname, '../..'); shelljs.set('-e'); shelljs.cd(projectDir); +// Do not apply postinstall patches when running "postinstall" outside. The +// "generate_build_file.js" file indicates that we run in Bazel managed node modules. +if (!shelljs.test('-e', 'generate_build_file.js')) { + return; +} + // Workaround for https://github.com/angular/angular/issues/18810. shelljs.exec('ngc -p angular-tsconfig.json'); @@ -69,7 +69,7 @@ searchAndReplace( const hasFlatModuleBundle = fs.existsSync(filePath.replace('.d.ts', '.metadata.json')); if ((filePath.includes('node_modules/') || !hasFlatModuleBundle) && $1`, 'node_modules/@angular/compiler-cli/src/transformers/compiler_host.js'); -applyPatch(path.join(__dirname, './flat_module_factory_resolution.patch')); +shelljs.cat(path.join(__dirname, './flat_module_factory_resolution.patch')).exec('patch -p0'); // The three replacements below ensure that metadata files can be read by NGC and // that metadata files are collected as Bazel action inputs. searchAndReplace( @@ -90,7 +90,7 @@ searchAndReplace( 'node_modules/@angular/bazel/src/ng_module.bzl'); // Workaround for: https://github.com/bazelbuild/rules_nodejs/issues/1208. -applyPatch(path.join(__dirname, './manifest_externs_hermeticity.patch')); +shelljs.cat(path.join(__dirname, './manifest_externs_hermeticity.patch')).exec('patch -p0'); // Workaround for using Ngcc with "--create-ivy-entry-points". This is a special // issue for our repository since we want to run Ivy by default in the module resolution, @@ -136,34 +136,12 @@ shelljs.rm('-rf', [ 'node_modules/rxjs/Subscription.*', ]); -/** - * Applies the given patch if not done already. Throws if the patch does - * not apply cleanly. - */ -function applyPatch(patchFile) { - const patchMarkerFileName = `${path.basename(patchFile)}.patch_marker`; - const patchMarkerPath = path.join(projectDir, 'node_modules/', patchMarkerFileName); - - if (hasFileBeenPatched(patchMarkerPath)) { - return; - } - - writePatchMarker(patchMarkerPath); - shelljs.cat(patchFile).exec('patch -p0'); -} - /** * Reads the specified file and replaces matches of the search expression - * with the given replacement. Throws if no changes were made and the - * patch has not been applied yet. + * with the given replacement. Throws if no changes were made. */ function searchAndReplace(search, replacement, relativeFilePath) { const filePath = path.join(projectDir, relativeFilePath); - - if (hasFileBeenPatched(filePath)) { - return; - } - const originalContent = fs.readFileSync(filePath, 'utf8'); const newFileContent = originalContent.replace(search, replacement); @@ -171,18 +149,5 @@ function searchAndReplace(search, replacement, relativeFilePath) { throw Error(`Could not perform replacement in: ${filePath}.`); } - writePatchMarker(filePath); fs.writeFileSync(filePath, newFileContent, 'utf8'); } - -/** Marks the specified file as patched. */ -function writePatchMarker(filePath) { - shelljs.echo(PATCH_VERSION).to(`${filePath}.patch_marker`); -} - -/** Checks if the given file has been patched. */ -function hasFileBeenPatched(filePath) { - const markerFilePath = `${filePath}.patch_marker`; - return shelljs.test('-e', markerFilePath) && - shelljs.cat(markerFilePath).toString().trim() === `${PATCH_VERSION}`; -}