refactor(ivy): ngcc - extract file writing out into a class (#29092)
This is in preparation of having different file writing strategies. PR Close #29092
This commit is contained in:
parent
a827bc2e3a
commit
849b327986
@ -18,6 +18,8 @@ import {EntryPointFormat, EntryPointJsonProperty, SUPPORTED_FORMAT_PROPERTIES, g
|
|||||||
import {makeEntryPointBundle} from './packages/entry_point_bundle';
|
import {makeEntryPointBundle} from './packages/entry_point_bundle';
|
||||||
import {EntryPointFinder} from './packages/entry_point_finder';
|
import {EntryPointFinder} from './packages/entry_point_finder';
|
||||||
import {Transformer} from './packages/transformer';
|
import {Transformer} from './packages/transformer';
|
||||||
|
import {FileWriter} from './writing/file_writer';
|
||||||
|
import {InPlaceFileWriter} from './writing/in_place_file_writer';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,6 +64,7 @@ export function mainNgcc({basePath, targetEntryPointPath,
|
|||||||
const host = new DependencyHost();
|
const host = new DependencyHost();
|
||||||
const resolver = new DependencyResolver(host);
|
const resolver = new DependencyResolver(host);
|
||||||
const finder = new EntryPointFinder(resolver);
|
const finder = new EntryPointFinder(resolver);
|
||||||
|
const fileWriter = getFileWriter();
|
||||||
|
|
||||||
const absoluteTargetEntryPointPath = targetEntryPointPath ?
|
const absoluteTargetEntryPointPath = targetEntryPointPath ?
|
||||||
AbsoluteFsPath.from(resolve(basePath, targetEntryPointPath)) :
|
AbsoluteFsPath.from(resolve(basePath, targetEntryPointPath)) :
|
||||||
@ -116,7 +119,8 @@ export function mainNgcc({basePath, targetEntryPointPath,
|
|||||||
compiledFormats.size === 0);
|
compiledFormats.size === 0);
|
||||||
if (bundle) {
|
if (bundle) {
|
||||||
console.warn(`Compiling ${entryPoint.name} : ${property} as ${format}`);
|
console.warn(`Compiling ${entryPoint.name} : ${property} as ${format}`);
|
||||||
transformer.transform(bundle);
|
const transformedFiles = transformer.transform(bundle);
|
||||||
|
fileWriter.writeBundle(entryPoint, bundle, transformedFiles);
|
||||||
compiledFormats.add(formatPath);
|
compiledFormats.add(formatPath);
|
||||||
} else {
|
} else {
|
||||||
console.warn(
|
console.warn(
|
||||||
@ -139,3 +143,7 @@ export function mainNgcc({basePath, targetEntryPointPath,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFileWriter(): FileWriter {
|
||||||
|
return new InPlaceFileWriter();
|
||||||
|
}
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {dirname} from 'canonical-path';
|
|
||||||
import {existsSync, writeFileSync} from 'fs';
|
|
||||||
import {mkdir, mv} from 'shelljs';
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CompiledFile, DecorationAnalyzer} from '../analysis/decoration_analyzer';
|
import {CompiledFile, DecorationAnalyzer} from '../analysis/decoration_analyzer';
|
||||||
@ -22,7 +19,6 @@ import {Esm5Renderer} from '../rendering/esm5_renderer';
|
|||||||
import {EsmRenderer} from '../rendering/esm_renderer';
|
import {EsmRenderer} from '../rendering/esm_renderer';
|
||||||
import {FileInfo, Renderer} from '../rendering/renderer';
|
import {FileInfo, Renderer} from '../rendering/renderer';
|
||||||
|
|
||||||
import {EntryPoint} from './entry_point';
|
|
||||||
import {EntryPointBundle} from './entry_point_bundle';
|
import {EntryPointBundle} from './entry_point_bundle';
|
||||||
|
|
||||||
|
|
||||||
@ -54,8 +50,9 @@ export class Transformer {
|
|||||||
/**
|
/**
|
||||||
* Transform the source (and typings) files of a bundle.
|
* Transform the source (and typings) files of a bundle.
|
||||||
* @param bundle the bundle to transform.
|
* @param bundle the bundle to transform.
|
||||||
|
* @returns information about the files that were transformed.
|
||||||
*/
|
*/
|
||||||
transform(bundle: EntryPointBundle): void {
|
transform(bundle: EntryPointBundle): FileInfo[] {
|
||||||
const isCore = bundle.isCore;
|
const isCore = bundle.isCore;
|
||||||
const reflectionHost = this.getHost(isCore, bundle);
|
const reflectionHost = this.getHost(isCore, bundle);
|
||||||
|
|
||||||
@ -69,8 +66,7 @@ export class Transformer {
|
|||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
||||||
moduleWithProvidersAnalyses);
|
moduleWithProvidersAnalyses);
|
||||||
|
|
||||||
// Write out all the transformed files.
|
return renderedFiles;
|
||||||
renderedFiles.forEach(file => this.writeFile(file));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getHost(isCore: boolean, bundle: EntryPointBundle): NgccReflectionHost {
|
getHost(isCore: boolean, bundle: EntryPointBundle): NgccReflectionHost {
|
||||||
@ -122,15 +118,6 @@ export class Transformer {
|
|||||||
return {decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
return {decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
||||||
moduleWithProvidersAnalyses};
|
moduleWithProvidersAnalyses};
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(file: FileInfo): void {
|
|
||||||
mkdir('-p', dirname(file.path));
|
|
||||||
const backPath = file.path + '.bak';
|
|
||||||
if (existsSync(file.path) && !existsSync(backPath)) {
|
|
||||||
mv(file.path, backPath);
|
|
||||||
}
|
|
||||||
writeFileSync(file.path, file.contents, 'utf8');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
19
packages/compiler-cli/ngcc/src/writing/file_writer.ts
Normal file
19
packages/compiler-cli/ngcc/src/writing/file_writer.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
import {EntryPoint} from '../packages/entry_point';
|
||||||
|
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
||||||
|
import {FileInfo} from '../rendering/renderer';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for writing out the transformed files to disk.
|
||||||
|
*/
|
||||||
|
export interface FileWriter {
|
||||||
|
writeBundle(entryPoint: EntryPoint, bundle: EntryPointBundle, transformedFiles: FileInfo[]): void;
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {dirname} from 'canonical-path';
|
||||||
|
import {existsSync, writeFileSync} from 'fs';
|
||||||
|
import {mkdir, mv} from 'shelljs';
|
||||||
|
|
||||||
|
import {EntryPoint} from '../packages/entry_point';
|
||||||
|
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
||||||
|
import {FileInfo} from '../rendering/renderer';
|
||||||
|
|
||||||
|
import {FileWriter} from './file_writer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This FileWriter overwrites the transformed file, in-place, while creating
|
||||||
|
* a back-up of the original file with an extra `.bak` extension.
|
||||||
|
*/
|
||||||
|
export class InPlaceFileWriter implements FileWriter {
|
||||||
|
writeBundle(_entryPoint: EntryPoint, _bundle: EntryPointBundle, transformedFiles: FileInfo[]) {
|
||||||
|
transformedFiles.forEach(file => this.writeFileAndBackup(file));
|
||||||
|
}
|
||||||
|
protected writeFileAndBackup(file: FileInfo): void {
|
||||||
|
mkdir('-p', dirname(file.path));
|
||||||
|
const backPath = file.path + '.__ivy_ngcc_bak';
|
||||||
|
if (existsSync(backPath)) {
|
||||||
|
throw new Error(
|
||||||
|
`Tried to overwrite ${backPath} with an ngcc back up file, which is disallowed.`);
|
||||||
|
}
|
||||||
|
if (existsSync(file.path)) {
|
||||||
|
mv(file.path, backPath);
|
||||||
|
}
|
||||||
|
writeFileSync(file.path, file.contents, 'utf8');
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ jasmine_node_test(
|
|||||||
"//tools/testing:node_no_angular",
|
"//tools/testing:node_no_angular",
|
||||||
"@npm//canonical-path",
|
"@npm//canonical-path",
|
||||||
"@npm//convert-source-map",
|
"@npm//convert-source-map",
|
||||||
|
"@npm//shelljs",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {existsSync, readFileSync} from 'fs';
|
||||||
|
import * as mockFs from 'mock-fs';
|
||||||
|
|
||||||
|
import {EntryPoint} from '../../src/packages/entry_point';
|
||||||
|
import {EntryPointBundle} from '../../src/packages/entry_point_bundle';
|
||||||
|
import {InPlaceFileWriter} from '../../src/writing/in_place_file_writer';
|
||||||
|
|
||||||
|
function createMockFileSystem() {
|
||||||
|
mockFs({
|
||||||
|
'/package/path': {
|
||||||
|
'top-level.js': 'ORIGINAL TOP LEVEL',
|
||||||
|
'folder-1': {
|
||||||
|
'file-1.js': 'ORIGINAL FILE 1',
|
||||||
|
'file-2.js': 'ORIGINAL FILE 2',
|
||||||
|
},
|
||||||
|
'folder-2': {
|
||||||
|
'file-3.js': 'ORIGINAL FILE 3',
|
||||||
|
'file-4.js': 'ORIGINAL FILE 4',
|
||||||
|
},
|
||||||
|
'already-backed-up.js.__ivy_ngcc_bak': 'BACKED UP',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreRealFileSystem() {
|
||||||
|
mockFs.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('InPlaceFileWriter', () => {
|
||||||
|
beforeEach(createMockFileSystem);
|
||||||
|
afterEach(restoreRealFileSystem);
|
||||||
|
|
||||||
|
it('should write all the FileInfo to the disk', () => {
|
||||||
|
const fileWriter = new InPlaceFileWriter();
|
||||||
|
fileWriter.writeBundle({} as EntryPoint, {} as EntryPointBundle, [
|
||||||
|
{path: '/package/path/top-level.js', contents: 'MODIFIED TOP LEVEL'},
|
||||||
|
{path: '/package/path/folder-1/file-1.js', contents: 'MODIFIED FILE 1'},
|
||||||
|
{path: '/package/path/folder-2/file-4.js', contents: 'MODIFIED FILE 4'},
|
||||||
|
{path: '/package/path/folder-3/file-5.js', contents: 'NEW FILE 5'},
|
||||||
|
]);
|
||||||
|
expect(readFileSync('/package/path/top-level.js', 'utf8')).toEqual('MODIFIED TOP LEVEL');
|
||||||
|
expect(readFileSync('/package/path/folder-1/file-1.js', 'utf8')).toEqual('MODIFIED FILE 1');
|
||||||
|
expect(readFileSync('/package/path/folder-1/file-2.js', 'utf8')).toEqual('ORIGINAL FILE 2');
|
||||||
|
expect(readFileSync('/package/path/folder-2/file-3.js', 'utf8')).toEqual('ORIGINAL FILE 3');
|
||||||
|
expect(readFileSync('/package/path/folder-2/file-4.js', 'utf8')).toEqual('MODIFIED FILE 4');
|
||||||
|
expect(readFileSync('/package/path/folder-3/file-5.js', 'utf8')).toEqual('NEW FILE 5');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create backups of all files that previously existed', () => {
|
||||||
|
const fileWriter = new InPlaceFileWriter();
|
||||||
|
fileWriter.writeBundle({} as EntryPoint, {} as EntryPointBundle, [
|
||||||
|
{path: '/package/path/top-level.js', contents: 'MODIFIED TOP LEVEL'},
|
||||||
|
{path: '/package/path/folder-1/file-1.js', contents: 'MODIFIED FILE 1'},
|
||||||
|
{path: '/package/path/folder-2/file-4.js', contents: 'MODIFIED FILE 4'},
|
||||||
|
{path: '/package/path/folder-3/file-5.js', contents: 'NEW FILE 5'},
|
||||||
|
]);
|
||||||
|
expect(readFileSync('/package/path/top-level.js.__ivy_ngcc_bak', 'utf8'))
|
||||||
|
.toEqual('ORIGINAL TOP LEVEL');
|
||||||
|
expect(readFileSync('/package/path/folder-1/file-1.js.__ivy_ngcc_bak', 'utf8'))
|
||||||
|
.toEqual('ORIGINAL FILE 1');
|
||||||
|
expect(existsSync('/package/path/folder-1/file-2.js.__ivy_ngcc_bak')).toBe(false);
|
||||||
|
expect(existsSync('/package/path/folder-2/file-3.js.__ivy_ngcc_bak')).toBe(false);
|
||||||
|
expect(readFileSync('/package/path/folder-2/file-4.js.__ivy_ngcc_bak', 'utf8'))
|
||||||
|
.toEqual('ORIGINAL FILE 4');
|
||||||
|
expect(existsSync('/package/path/folder-3/file-5.js.__ivy_ngcc_bak')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if the backup file already exists', () => {
|
||||||
|
const fileWriter = new InPlaceFileWriter();
|
||||||
|
expect(
|
||||||
|
() => fileWriter.writeBundle(
|
||||||
|
{} as EntryPoint, {} as EntryPointBundle,
|
||||||
|
[
|
||||||
|
{path: '/package/path/already-backed-up.js', contents: 'MODIFIED BACKED UP'},
|
||||||
|
]))
|
||||||
|
.toThrowError(
|
||||||
|
'Tried to overwrite /package/path/already-backed-up.js.__ivy_ngcc_bak with an ngcc back up file, which is disallowed.');
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user