fix(ngcc): correctly invalidate cache when moving/removing files/directories (#35106)

One particular scenario where this was causing problems was when the
[BackupFileCleaner][1] restored a file (such as a `.d.ts` file) by
[moving the backup file][2] to its original location, but the modified
content was kept in the cache.

[1]: https://github.com/angular/angular/blob/4d36b2f6e/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts#L54
[2]: https://github.com/angular/angular/blob/4d36b2f6e/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts#L61

Fixes #35095

PR Close #35106
This commit is contained in:
George Kalpakas 2020-02-02 16:03:34 +02:00 committed by Miško Hevery
parent 3c30474417
commit 523c785e8f
5 changed files with 267 additions and 46 deletions

View File

@ -0,0 +1,50 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* **Usage:**
* ```sh
* node mock-ngcc-version-marker <entry-point> <mock-ngcc-version>
*
* # Example:
* # node mock-ngcc-version-marker @angular/material/button 3.0.0
* ```
*
* Ngcc marks entry-points as processed by adding marker properties in their `package.json`. It uses
* a version as a marker in order to be able to distinguish entry-points processed by a different
* ngcc version (e.g. an older version after an update) and perform the necessary clean-up.
*
* This script replaces the ngcc version marker in an entry-point's `package.json` to make it appear
* as if it were processed by a different version of ngcc. This allows testing the clean-up logic
* without the overhead of actually installing a different ngcc version, compiling the dependencies,
* then installing the current version and compiling again.
*/
const {writeFileSync} = require('fs');
const {basename} = require('path');
const entryPointName = process.argv[2];
const mockNgccVersion = process.argv[3];
const actualNgccVersion = require('@angular/compiler-cli/package.json').version;
if (!entryPointName || !mockNgccVersion) {
throw new Error(
'Missing required argument(s).\n' +
`Usage: node ${basename(__filename)} <entry-point> <mock-ngcc-version>\n`);
}
const entryPointPkgJsonPath = require.resolve(`${entryPointName}/package.json`);
const entryPointPkgJson = require(entryPointPkgJsonPath);
const processedMarkers = entryPointPkgJson.__processed_by_ivy_ngcc__;
Object.keys(processedMarkers).forEach(key => processedMarkers[key] = mockNgccVersion);
writeFileSync(entryPointPkgJsonPath, JSON.stringify(entryPointPkgJson, null, 2));
console.log(
`Successfully mocked ngcc version marker in '${entryPointName}': ` +
`${actualNgccVersion} --> ${mockNgccVersion}`);

View File

@ -3,7 +3,7 @@
# Do not immediately exit on error to allow the `assertSucceeded` function to handle the error. # Do not immediately exit on error to allow the `assertSucceeded` function to handle the error.
# #
# NOTE: # NOTE:
# Each statement should be followed by an `assertSucceeded`/`assertFailed` or `exit 1` statement. # Each statement should be followed by an `assert*` or `exit 1` statement.
set +e -x set +e -x
PATH=$PATH:$(npm bin) PATH=$PATH:$(npm bin)
@ -22,6 +22,26 @@ function assertSucceeded {
fi fi
} }
function assertEquals {
local value1=$1;
local value2=$2;
if [[ "$value1" != "$value2" ]]; then
echo "FAIL: Expected '$value1' to equal '$value2'."
exit 1;
fi
}
function assertNotEquals {
local value1=$1;
local value2=$2;
if [[ "$value1" == "$value2" ]]; then
echo "FAIL: Expected '$value1' not to equal '$value2'."
exit 1;
fi
}
ngcc --help ngcc --help
assertSucceeded "Expected 'ngcc --help' to succeed." assertSucceeded "Expected 'ngcc --help' to succeed."
@ -140,6 +160,27 @@ assertSucceeded "Expected 'ngcc' to log 'Compiling'."
assertSucceeded "Expected 'ngcc' to not add trailing commas to factory function parameters in UMD." assertSucceeded "Expected 'ngcc' to not add trailing commas to factory function parameters in UMD."
# Can it correctly clean up and re-compile when dependencies are already compiled by a different version?
readonly actualNgccVersion=`node --print "require('@angular/compiler-cli/package.json').version"`
readonly mockNgccVersion="3.0.0"
# Mock the ngcc version marker on a package to make it appear as if it is compiled by a different ngcc version.
node mock-ngcc-version-marker @angular/material/button $mockNgccVersion
assertSucceeded "Expected to successfully mock the 'ngcc' version marker in '@angular/material/button'."
assertEquals $mockNgccVersion `node --print "require('@angular/material/button/package.json').__processed_by_ivy_ngcc__.main"`
assertEquals 1 `cat node_modules/@angular/material/button/button.d.ts | grep 'import \* as ɵngcc0' | wc -l`
# Re-compile packages (which requires cleaning up those compiled by a different ngcc version).
# (Use sync mode to ensure all tasks share the same `CachedFileSystem` instance.)
ngcc --no-async --properties main
assertSucceeded "Expected 'ngcc' to successfully re-compile the packages."
# Ensure previously compiled packages were correctly cleaned up (i.e. no multiple
# `import ... ɵngcc0` statements) and re-compiled by the current ngcc version.
assertEquals $actualNgccVersion `node --print "require('@angular/material/button/package.json').__processed_by_ivy_ngcc__.main"`
assertEquals 1 `cat node_modules/@angular/material/button/button.d.ts | grep 'import \* as ɵngcc0' | wc -l`
# Can it compile `@angular/platform-server` in UMD + typings without errors? # Can it compile `@angular/platform-server` in UMD + typings without errors?
# (The CLI prefers the `main` property (which maps to UMD) over `module` when compiling `@angular/platform-server`. # (The CLI prefers the `main` property (which maps to UMD) over `module` when compiling `@angular/platform-server`.
# See https://github.com/angular/angular-cli/blob/e36853338/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/server.ts#L34) # See https://github.com/angular/angular-cli/blob/e36853338/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/server.ts#L34)
@ -151,6 +192,7 @@ assertSucceeded "Expected 'ngcc' to log 'Compiling'."
ngcc --properties main --target @angular/platform-server ngcc --properties main --target @angular/platform-server
assertSucceeded "Expected 'ngcc' to successfully compile '@angular/platform-server' (main)." assertSucceeded "Expected 'ngcc' to successfully compile '@angular/platform-server' (main)."
# Can it be safely run again (as a noop)? # Can it be safely run again (as a noop)?
# And check that it logged skipping compilation as expected # And check that it logged skipping compilation as expected
ngcc -l debug | grep 'Skipping' ngcc -l debug | grep 'Skipping'

View File

@ -19,9 +19,10 @@
version "9.0.0-rc.1" version "9.0.0-rc.1"
dependencies: dependencies:
canonical-path "1.0.0" canonical-path "1.0.0"
chokidar "^2.1.1" chokidar "^3.0.0"
convert-source-map "^1.5.1" convert-source-map "^1.5.1"
dependency-graph "^0.7.2" dependency-graph "^0.7.2"
fs-extra "4.0.2"
magic-string "^0.25.0" magic-string "^0.25.0"
minimist "^1.2.0" minimist "^1.2.0"
reflect-metadata "^0.1.2" reflect-metadata "^0.1.2"
@ -154,6 +155,14 @@ anymatch@^2.0.0:
micromatch "^3.1.4" micromatch "^3.1.4"
normalize-path "^2.1.1" normalize-path "^2.1.1"
anymatch@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
aproba@^1.0.3: aproba@^1.0.3:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@ -248,11 +257,6 @@ async-each@^1.0.0:
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
integrity sha1-GdOGodntxufByF04iu28xW0zYC0= integrity sha1-GdOGodntxufByF04iu28xW0zYC0=
async-each@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735"
integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg==
async-limiter@~1.0.0: async-limiter@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
@ -348,6 +352,11 @@ binary-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==
binary-extensions@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
blob@0.0.5: blob@0.0.5:
version "0.0.5" version "0.0.5"
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
@ -377,7 +386,7 @@ braces@^1.8.2:
preserve "^0.2.0" preserve "^0.2.0"
repeat-element "^1.1.2" repeat-element "^1.1.2"
braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: braces@^2.3.0, braces@^2.3.1:
version "2.3.2" version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
@ -393,6 +402,13 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2" split-string "^3.0.2"
to-regex "^3.0.1" to-regex "^3.0.1"
braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
browser-sync-client@^2.26.2: browser-sync-client@^2.26.2:
version "2.26.2" version "2.26.2"
resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.26.2.tgz#dd0070c80bdc6d9021e89f7837ee70ed0a8acf91" resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.26.2.tgz#dd0070c80bdc6d9021e89f7837ee70ed0a8acf91"
@ -560,24 +576,20 @@ chokidar@^2.0.4:
optionalDependencies: optionalDependencies:
fsevents "^1.2.2" fsevents "^1.2.2"
chokidar@^2.1.1: chokidar@^3.0.0:
version "2.1.5" version "3.3.1"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
dependencies: dependencies:
anymatch "^2.0.0" anymatch "~3.1.1"
async-each "^1.0.1" braces "~3.0.2"
braces "^2.3.2" glob-parent "~5.1.0"
glob-parent "^3.1.0" is-binary-path "~2.1.0"
inherits "^2.0.3" is-glob "~4.0.1"
is-binary-path "^1.0.0" normalize-path "~3.0.0"
is-glob "^4.0.0" readdirp "~3.3.0"
normalize-path "^3.0.0"
path-is-absolute "^1.0.0"
readdirp "^2.2.1"
upath "^1.1.1"
optionalDependencies: optionalDependencies:
fsevents "^1.2.7" fsevents "~2.1.2"
chownr@^1.0.1: chownr@^1.0.1:
version "1.1.1" version "1.1.1"
@ -1119,6 +1131,13 @@ fill-range@^4.0.0:
repeat-string "^1.6.1" repeat-string "^1.6.1"
to-regex-range "^2.1.0" to-regex-range "^2.1.0"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
finalhandler@1.1.0: finalhandler@1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5"
@ -1201,6 +1220,15 @@ fs-extra@3.0.1:
jsonfile "^3.0.0" jsonfile "^3.0.0"
universalify "^0.1.0" universalify "^0.1.0"
fs-extra@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b"
integrity sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-minipass@^1.2.5: fs-minipass@^1.2.5:
version "1.2.5" version "1.2.5"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
@ -1221,13 +1249,10 @@ fsevents@^1.2.2:
nan "^2.9.2" nan "^2.9.2"
node-pre-gyp "^0.10.0" node-pre-gyp "^0.10.0"
fsevents@^1.2.7: fsevents@~2.1.2:
version "1.2.7" version "2.1.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
dependencies:
nan "^2.9.2"
node-pre-gyp "^0.10.0"
gauge@~2.7.3: gauge@~2.7.3:
version "2.7.4" version "2.7.4"
@ -1295,6 +1320,13 @@ glob-parent@^3.1.0:
is-glob "^3.1.0" is-glob "^3.1.0"
path-dirname "^1.0.0" path-dirname "^1.0.0"
glob-parent@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
dependencies:
is-glob "^4.0.1"
glob@^7.0.3, glob@^7.0.5, glob@^7.0.6: glob@^7.0.3, glob@^7.0.5, glob@^7.0.6:
version "7.1.3" version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
@ -1488,7 +1520,7 @@ inflight@^1.0.4:
once "^1.3.0" once "^1.3.0"
wrappy "1" wrappy "1"
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
@ -1534,6 +1566,13 @@ is-binary-path@^1.0.0:
dependencies: dependencies:
binary-extensions "^1.0.0" binary-extensions "^1.0.0"
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-buffer@^1.1.5: is-buffer@^1.1.5:
version "1.1.6" version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@ -1645,6 +1684,13 @@ is-glob@^4.0.0:
dependencies: dependencies:
is-extglob "^2.1.1" is-extglob "^2.1.1"
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
is-number-like@^1.0.3: is-number-like@^1.0.3:
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/is-number-like/-/is-number-like-1.0.8.tgz#2e129620b50891042e44e9bbbb30593e75cfbbe3" resolved "https://registry.yarnpkg.com/is-number-like/-/is-number-like-1.0.8.tgz#2e129620b50891042e44e9bbbb30593e75cfbbe3"
@ -1671,6 +1717,11 @@ is-number@^4.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-path-cwd@^1.0.0: is-path-cwd@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@ -1810,6 +1861,13 @@ jsonfile@^3.0.0:
optionalDependencies: optionalDependencies:
graceful-fs "^4.1.6" graceful-fs "^4.1.6"
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
jsprim@^1.2.2: jsprim@^1.2.2:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@ -2189,7 +2247,7 @@ normalize-path@^2.0.1, normalize-path@^2.1.1:
dependencies: dependencies:
remove-trailing-separator "^1.0.1" remove-trailing-separator "^1.0.1"
normalize-path@^3.0.0: normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@ -2479,6 +2537,11 @@ performance-now@^2.1.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
picomatch@^2.0.4, picomatch@^2.0.7:
version "2.2.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
pify@^2.0.0: pify@^2.0.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@ -2520,7 +2583,7 @@ process-nextick-args@~2.0.0:
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
"protractor@file:../../node_modules/protractor": "protractor@file:../../node_modules/protractor":
version "5.4.2" version "5.4.3"
dependencies: dependencies:
"@types/q" "^0.0.32" "@types/q" "^0.0.32"
"@types/selenium-webdriver" "^3.0.0" "@types/selenium-webdriver" "^3.0.0"
@ -2640,7 +2703,7 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@~2.3.6:
string_decoder "~1.1.1" string_decoder "~1.1.1"
util-deprecate "~1.0.1" util-deprecate "~1.0.1"
readdirp@^2.0.0, readdirp@^2.2.1: readdirp@^2.0.0:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
@ -2649,6 +2712,13 @@ readdirp@^2.0.0, readdirp@^2.2.1:
micromatch "^3.1.10" micromatch "^3.1.10"
readable-stream "^2.0.2" readable-stream "^2.0.2"
readdirp@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
dependencies:
picomatch "^2.0.7"
reflect-metadata@^0.1.2: reflect-metadata@^0.1.2:
version "0.1.12" version "0.1.12"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2"
@ -3276,6 +3346,13 @@ to-regex-range@^2.1.0:
is-number "^3.0.0" is-number "^3.0.0"
repeat-string "^1.6.1" repeat-string "^1.6.1"
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
to-regex@^3.0.1, to-regex@^3.0.2: to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
@ -3317,7 +3394,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
"typescript@file:../../node_modules/typescript": "typescript@file:../../node_modules/typescript":
version "3.6.4" version "3.7.4"
ua-parser-js@0.7.17: ua-parser-js@0.7.17:
version "0.7.17" version "0.7.17"
@ -3362,11 +3439,6 @@ upath@^1.0.5:
resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==
upath@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
urix@^0.1.0: urix@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"

View File

@ -72,12 +72,16 @@ export class CachedFileSystem implements FileSystem {
moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void {
this.delegate.moveFile(from, to); this.delegate.moveFile(from, to);
this.existsCache.set(from, false); this.existsCache.set(from, false);
this.existsCache.set(to, true);
if (this.readFileCache.has(from)) { if (this.readFileCache.has(from)) {
this.readFileCache.set(to, this.readFileCache.get(from)); this.readFileCache.set(to, this.readFileCache.get(from));
this.readFileCache.delete(from); this.readFileCache.delete(from);
} else {
this.readFileCache.delete(to);
} }
this.existsCache.set(to, true);
} }
ensureDir(path: AbsoluteFsPath): void { ensureDir(path: AbsoluteFsPath): void {
@ -90,10 +94,18 @@ export class CachedFileSystem implements FileSystem {
removeDeep(path: AbsoluteFsPath): void { removeDeep(path: AbsoluteFsPath): void {
this.delegate.removeDeep(path); this.delegate.removeDeep(path);
// Clear out all children of this directory from the exists cache.
// Clear out this directory and all its children from the `exists` cache.
for (const p of this.existsCache.keys()) { for (const p of this.existsCache.keys()) {
if (p.startsWith(path)) { if (p.startsWith(path)) {
this.existsCache.set(path, false); this.existsCache.set(p, false);
}
}
// Clear out this directory and all its children from the `readFile` cache.
for (const p of this.readFileCache.keys()) {
if (p.startsWith(path)) {
this.readFileCache.delete(p);
} }
} }
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {CachedFileSystem} from '../src/cached_file_system'; import {CachedFileSystem} from '../src/cached_file_system';
import {absoluteFrom, setFileSystem} from '../src/helpers'; import {absoluteFrom, join, setFileSystem} from '../src/helpers';
import {NodeJSFileSystem} from '../src/node_js_file_system'; import {NodeJSFileSystem} from '../src/node_js_file_system';
import {AbsoluteFsPath, FileSystem} from '../src/types'; import {AbsoluteFsPath, FileSystem} from '../src/types';
@ -236,7 +236,7 @@ describe('CachedFileSystem', () => {
expect(readFileSpy).toHaveBeenCalledWith(abcPath); expect(readFileSpy).toHaveBeenCalledWith(abcPath);
}); });
it('should update the `to` "readFile" cache', () => { it('should update the `to` "readFile" cache (if `from` was cached)', () => {
spyOn(delegate, 'moveFile'); spyOn(delegate, 'moveFile');
const readFileSpy = spyOn(delegate, 'readFile'); const readFileSpy = spyOn(delegate, 'readFile');
@ -252,6 +252,24 @@ describe('CachedFileSystem', () => {
expect(fs.readFile(xyzPath)).toEqual('abc content'); expect(fs.readFile(xyzPath)).toEqual('abc content');
expect(readFileSpy).not.toHaveBeenCalled(); expect(readFileSpy).not.toHaveBeenCalled();
}); });
it('should delete the `to` "readFile" cache (if `from` was not cached)', () => {
spyOn(delegate, 'moveFile');
const readFileSpy = spyOn(delegate, 'readFile');
// Fill the xyz "readFile" cache
readFileSpy.and.returnValue('xyz content');
fs.readFile(xyzPath);
readFileSpy.calls.reset();
// Move the file
fs.moveFile(abcPath, xyzPath);
// Show that the cache was not hit for the xyz file
readFileSpy.and.returnValue('abc content');
expect(fs.readFile(xyzPath)).toBe('abc content');
expect(readFileSpy).toHaveBeenCalledWith(xyzPath);
});
}); });
describe('ensureDir()', () => { describe('ensureDir()', () => {
@ -281,14 +299,41 @@ describe('CachedFileSystem', () => {
}); });
it('should update the exists cache', () => { it('should update the exists cache', () => {
spyOn(delegate, 'writeFile');
spyOn(delegate, 'removeDeep'); spyOn(delegate, 'removeDeep');
const existsSpy = spyOn(delegate, 'exists').and.returnValue(true); const existsSpy = spyOn(delegate, 'exists').and.returnValue(true);
expect(fs.exists(abcPath)).toBe(true); expect(fs.exists(abcPath)).toBe(true);
existsSpy.calls.reset(); existsSpy.calls.reset();
// Create a file inside `/a/b/c`.
const abcdPath = join(abcPath, 'd');
fs.writeFile(abcdPath, 'content');
expect(fs.exists(abcdPath)).toBe(true);
expect(existsSpy).not.toHaveBeenCalled();
// Remove the `/a/b/c` directory and ensure it is removed from cache (along with its content).
fs.removeDeep(abcPath); fs.removeDeep(abcPath);
expect(fs.exists(abcPath)).toBeFalsy(); expect(fs.exists(abcPath)).toBeFalsy();
expect(fs.exists(abcdPath)).toBeFalsy();
expect(existsSpy).not.toHaveBeenCalled(); expect(existsSpy).not.toHaveBeenCalled();
}); });
it('should update the readFile cache', () => {
spyOn(delegate, 'writeFile');
spyOn(delegate, 'removeDeep');
spyOn(delegate, 'lstat').and.throwError('ENOENT: no such file or directory');
const readFileSpy = spyOn(delegate, 'readFile');
// Create a file inside `/a/b/c`.
const abcdPath = join(abcPath, 'd');
fs.writeFile(abcdPath, 'content from cache');
expect(fs.readFile(abcdPath)).toBe('content from cache');
expect(readFileSpy).not.toHaveBeenCalled();
// Remove the `/a/b/c` directory and ensure it is removed from cache (along with its content).
fs.removeDeep(abcPath);
expect(() => fs.readFile(abcdPath)).toThrowError('ENOENT: no such file or directory');
expect(() => fs.readFile(abcPath)).toThrowError('ENOENT: no such file or directory');
});
}); });
}); });