"Fossies" - the Fresh Open Source Software Archive

Member "angular-cli-8.3.23/packages/angular_devkit/build_angular/src/browser/action-cache.ts" (15 Jan 2020, 6900 Bytes) of package /linux/www/angular-cli-8.3.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "action-cache.ts": 8.3.21_vs_8.3.22.

    1 /**
    2  * @license
    3  * Copyright Google Inc. All Rights Reserved.
    4  *
    5  * Use of this source code is governed by an MIT-style license that can be
    6  * found in the LICENSE file at https://angular.io/license
    7  */
    8 import { createHash } from 'crypto';
    9 import * as findCacheDirectory from 'find-cache-dir';
   10 import * as fs from 'fs';
   11 import { manglingDisabled } from '../utils/mangle-options';
   12 import { CacheKey, ProcessBundleOptions, ProcessBundleResult } from '../utils/process-bundle';
   13 
   14 const cacache = require('cacache');
   15 const cacheDownlevelPath = findCacheDirectory({ name: 'angular-build-dl' });
   16 const packageVersion = require('../../package.json').version;
   17 
   18 // Workaround Node.js issue prior to 10.16 with copyFile on macOS
   19 // https://github.com/angular/angular-cli/issues/15544 & https://github.com/nodejs/node/pull/27241
   20 let copyFileWorkaround = false;
   21 if (process.platform === 'darwin') {
   22   const version = process.versions.node.split('.').map(part => Number(part));
   23   if (version[0] < 10 || version[0] === 11 || (version[0] === 10 && version[1] < 16)) {
   24     copyFileWorkaround = true;
   25   }
   26 }
   27 
   28 export interface CacheEntry {
   29   path: string;
   30   size: number;
   31   integrity?: string;
   32 }
   33 
   34 export class BundleActionCache {
   35   constructor(private readonly integrityAlgorithm?: string) {}
   36 
   37   static copyEntryContent(entry: CacheEntry | string, dest: fs.PathLike): void {
   38     if (copyFileWorkaround) {
   39       try {
   40         fs.unlinkSync(dest);
   41       } catch {}
   42     }
   43 
   44     fs.copyFileSync(
   45       typeof entry === 'string' ? entry : entry.path,
   46       dest,
   47       fs.constants.COPYFILE_FICLONE,
   48     );
   49     if (process.platform !== 'win32') {
   50       // The cache writes entries as readonly and when using copyFile the permissions will also be copied.
   51       // See: https://github.com/npm/cacache/blob/073fbe1a9f789ba42d9a41de7b8429c93cf61579/lib/util/move-file.js#L36
   52       fs.chmodSync(dest, 0o644);
   53     }
   54   }
   55 
   56   generateBaseCacheKey(content: string): string {
   57     // Create base cache key with elements:
   58     // * package version - different build-angular versions cause different final outputs
   59     // * code length/hash - ensure cached version matches the same input code
   60     const algorithm = this.integrityAlgorithm || 'sha1';
   61     const codeHash = createHash(algorithm)
   62       .update(content)
   63       .digest('base64');
   64     let baseCacheKey = `${packageVersion}|${content.length}|${algorithm}-${codeHash}`;
   65     if (manglingDisabled) {
   66       baseCacheKey += '|MD';
   67     }
   68 
   69     return baseCacheKey;
   70   }
   71 
   72   generateCacheKeys(action: ProcessBundleOptions): string[] {
   73     // Postfix added to sourcemap cache keys when vendor, hidden sourcemaps are present
   74     // Allows non-destructive caching of both variants
   75     const sourceMapVendorPostfix = action.sourceMaps && action.vendorSourceMaps ? '|vendor' : '';
   76 
   77     // sourceMappingURL is added at the very end which causes the code to be the same when sourcemaps are enabled/disabled
   78     // When using hiddenSourceMaps we can omit the postfix since sourceMappingURL will not be added.
   79     // When having sourcemaps a hashed file and non hashed file can have the same content. But the sourceMappingURL will differ.
   80     const sourceMapPostFix = action.sourceMaps && !action.hiddenSourceMaps ? `|sourcemap|${action.filename}` : '';
   81 
   82     const baseCacheKey = this.generateBaseCacheKey(action.code);
   83 
   84     // Determine cache entries required based on build settings
   85     const cacheKeys: string[] = [];
   86 
   87     // If optimizing and the original is not ignored, add original as required
   88     if (!action.ignoreOriginal) {
   89       cacheKeys[CacheKey.OriginalCode] = baseCacheKey + sourceMapPostFix + '|orig';
   90 
   91       // If sourcemaps are enabled, add original sourcemap as required
   92       if (action.sourceMaps) {
   93         cacheKeys[CacheKey.OriginalMap] = baseCacheKey + sourceMapVendorPostfix + '|orig-map';
   94       }
   95     }
   96 
   97     // If not only optimizing, add downlevel as required
   98     if (!action.optimizeOnly) {
   99       cacheKeys[CacheKey.DownlevelCode] = baseCacheKey + sourceMapPostFix + '|dl';
  100 
  101       // If sourcemaps are enabled, add downlevel sourcemap as required
  102       if (action.sourceMaps) {
  103         cacheKeys[CacheKey.DownlevelMap] = baseCacheKey + sourceMapVendorPostfix + '|dl-map';
  104       }
  105     }
  106 
  107     return cacheKeys;
  108   }
  109 
  110   async getCacheEntries(cacheKeys: (string | undefined)[]): Promise<(CacheEntry | null)[] | false> {
  111     // Attempt to get required cache entries
  112     const cacheEntries = [];
  113     for (const key of cacheKeys) {
  114       if (key) {
  115         const entry = await cacache.get.info(cacheDownlevelPath, key);
  116         if (!entry) {
  117           return false;
  118         }
  119         cacheEntries.push({
  120           path: entry.path,
  121           size: entry.size,
  122           integrity: entry.metadata && entry.metadata.integrity,
  123         });
  124       } else {
  125         cacheEntries.push(null);
  126       }
  127     }
  128 
  129     return cacheEntries;
  130   }
  131 
  132   async getCachedBundleResult(action: ProcessBundleOptions): Promise<ProcessBundleResult | null> {
  133     const entries = action.cacheKeys && await this.getCacheEntries(action.cacheKeys);
  134     if (!entries) {
  135       return null;
  136     }
  137 
  138     const result: ProcessBundleResult = { name: action.name };
  139 
  140     let cacheEntry = entries[CacheKey.OriginalCode];
  141     if (cacheEntry) {
  142       result.original = {
  143         filename: action.filename,
  144         size: cacheEntry.size,
  145         integrity: cacheEntry.integrity,
  146       };
  147 
  148       BundleActionCache.copyEntryContent(cacheEntry, result.original.filename);
  149 
  150       cacheEntry = entries[CacheKey.OriginalMap];
  151       if (cacheEntry) {
  152         result.original.map = {
  153           filename: action.filename + '.map',
  154           size: cacheEntry.size,
  155         };
  156 
  157         BundleActionCache.copyEntryContent(cacheEntry, result.original.filename + '.map');
  158       }
  159     } else if (!action.ignoreOriginal) {
  160       // If the original wasn't processed (and therefore not cached), add info
  161       result.original = {
  162         filename: action.filename,
  163         size: Buffer.byteLength(action.code, 'utf8'),
  164         map:
  165           action.map === undefined
  166             ? undefined
  167             : {
  168                 filename: action.filename + '.map',
  169                 size: Buffer.byteLength(action.map, 'utf8'),
  170               },
  171       };
  172     }
  173 
  174     cacheEntry = entries[CacheKey.DownlevelCode];
  175     if (cacheEntry) {
  176       result.downlevel = {
  177         filename: action.filename.replace(/\-es20\d{2}/, '-es5'),
  178         size: cacheEntry.size,
  179         integrity: cacheEntry.integrity,
  180       };
  181 
  182       BundleActionCache.copyEntryContent(cacheEntry, result.downlevel.filename);
  183 
  184       cacheEntry = entries[CacheKey.DownlevelMap];
  185       if (cacheEntry) {
  186         result.downlevel.map = {
  187           filename: action.filename.replace(/\-es20\d{2}/, '-es5') + '.map',
  188           size: cacheEntry.size,
  189         };
  190 
  191         BundleActionCache.copyEntryContent(cacheEntry, result.downlevel.filename + '.map');
  192       }
  193     }
  194 
  195     return result;
  196   }
  197 }