refactor(ngcc): abstract work orchestration/execution behind an interface (#32427)
This change does not alter the current behavior, but makes it easier to introduce new types of `Executors` , for example to do the required work in parallel (on multiple processes). Inspired by/Based on @alxhub's prototype: alxhub/angular@cb631bdb1 PR Close #32427
This commit is contained in:
parent
3d9dd6df0e
commit
5c213e5474
@ -20,12 +20,21 @@ export type CompileFn = (task: Task) => void;
|
|||||||
/** The type of the function that creates the `CompileFn` function used to process tasks. */
|
/** The type of the function that creates the `CompileFn` function used to process tasks. */
|
||||||
export type CreateCompileFn = (onTaskCompleted: TaskCompletedCallback) => CompileFn;
|
export type CreateCompileFn = (onTaskCompleted: TaskCompletedCallback) => CompileFn;
|
||||||
|
|
||||||
|
/** Options related to the orchestration/execution of tasks. */
|
||||||
|
export interface ExecutionOptions {
|
||||||
|
compileAllFormats: boolean;
|
||||||
|
propertiesToConsider: string[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the function that orchestrates and executes the required work (i.e. analyzes the
|
* A class that orchestrates and executes the required work (i.e. analyzes the entry-points,
|
||||||
* entry-points, processes the resulting tasks, does book-keeping and validates the final outcome).
|
* processes the resulting tasks, does book-keeping and validates the final outcome).
|
||||||
*/
|
*/
|
||||||
export type ExecuteFn =
|
export interface Executor {
|
||||||
(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn) => void;
|
execute(
|
||||||
|
analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn,
|
||||||
|
options: ExecutionOptions): void;
|
||||||
|
}
|
||||||
|
|
||||||
/** Represents metadata related to the processing of an entry-point. */
|
/** Represents metadata related to the processing of an entry-point. */
|
||||||
export interface EntryPointProcessingMetadata {
|
export interface EntryPointProcessingMetadata {
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* @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 {Logger} from '../logging/logger';
|
||||||
|
import {PackageJsonUpdater} from '../writing/package_json_updater';
|
||||||
|
|
||||||
|
import {AnalyzeEntryPointsFn, CreateCompileFn, ExecutionOptions, Executor} from './api';
|
||||||
|
import {checkForUnprocessedEntryPoints, onTaskCompleted} from './utils';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Executor` that processes all tasks serially and completes synchronously.
|
||||||
|
*/
|
||||||
|
export class SingleProcessExecutor implements Executor {
|
||||||
|
constructor(private logger: Logger, private pkgJsonUpdater: PackageJsonUpdater) {}
|
||||||
|
|
||||||
|
execute(
|
||||||
|
analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn,
|
||||||
|
options: ExecutionOptions): void {
|
||||||
|
this.logger.debug(`Running ngcc on ${this.constructor.name}.`);
|
||||||
|
|
||||||
|
const {processingMetadataPerEntryPoint, tasks} = analyzeEntryPoints();
|
||||||
|
const compile = createCompileFn(
|
||||||
|
(task, outcome) =>
|
||||||
|
onTaskCompleted(this.pkgJsonUpdater, processingMetadataPerEntryPoint, task, outcome));
|
||||||
|
|
||||||
|
// Process all tasks.
|
||||||
|
for (const task of tasks) {
|
||||||
|
const processingMeta = processingMetadataPerEntryPoint.get(task.entryPoint.path) !;
|
||||||
|
|
||||||
|
// If we only need one format processed and we already have one for the corresponding
|
||||||
|
// entry-point, skip the task.
|
||||||
|
if (!options.compileAllFormats && processingMeta.hasAnyProcessedFormat) continue;
|
||||||
|
|
||||||
|
compile(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for entry-points for which we could not process any format at all.
|
||||||
|
checkForUnprocessedEntryPoints(processingMetadataPerEntryPoint, options.propertiesToConsider);
|
||||||
|
}
|
||||||
|
}
|
59
packages/compiler-cli/ngcc/src/execution/utils.ts
Normal file
59
packages/compiler-cli/ngcc/src/execution/utils.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* @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 {resolve} from '../../../src/ngtsc/file_system';
|
||||||
|
import {markAsProcessed} from '../packages/build_marker';
|
||||||
|
import {PackageJsonFormatProperties} from '../packages/entry_point';
|
||||||
|
import {PackageJsonUpdater} from '../writing/package_json_updater';
|
||||||
|
|
||||||
|
import {EntryPointProcessingMetadata, Task, TaskProcessingOutcome} from './api';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper function for checking for unprocessed entry-points (i.e. entry-points for which we could
|
||||||
|
* not process any format at all).
|
||||||
|
*/
|
||||||
|
export const checkForUnprocessedEntryPoints =
|
||||||
|
(processingMetadataPerEntryPoint: Map<string, EntryPointProcessingMetadata>,
|
||||||
|
propertiesToConsider: string[]): void => {
|
||||||
|
const unprocessedEntryPointPaths =
|
||||||
|
Array.from(processingMetadataPerEntryPoint.entries())
|
||||||
|
.filter(([, processingMeta]) => !processingMeta.hasAnyProcessedFormat)
|
||||||
|
.map(([entryPointPath]) => `\n - ${entryPointPath}`)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
if (unprocessedEntryPointPaths) {
|
||||||
|
throw new Error(
|
||||||
|
'Failed to compile any formats for the following entry-points (tried ' +
|
||||||
|
`${propertiesToConsider.join(', ')}): ${unprocessedEntryPointPaths}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A helper function for handling a task's being completed. */
|
||||||
|
export const onTaskCompleted =
|
||||||
|
(pkgJsonUpdater: PackageJsonUpdater,
|
||||||
|
processingMetadataPerEntryPoint: Map<string, EntryPointProcessingMetadata>, task: Task,
|
||||||
|
outcome: TaskProcessingOutcome, ): void => {
|
||||||
|
const {entryPoint, formatPropertiesToMarkAsProcessed, processDts} = task;
|
||||||
|
const processingMeta = processingMetadataPerEntryPoint.get(entryPoint.path) !;
|
||||||
|
processingMeta.hasAnyProcessedFormat = true;
|
||||||
|
|
||||||
|
if (outcome === TaskProcessingOutcome.Processed) {
|
||||||
|
const packageJsonPath = resolve(entryPoint.path, 'package.json');
|
||||||
|
const propsToMarkAsProcessed: PackageJsonFormatProperties[] =
|
||||||
|
[...formatPropertiesToMarkAsProcessed];
|
||||||
|
|
||||||
|
if (processDts) {
|
||||||
|
processingMeta.hasProcessedTypings = true;
|
||||||
|
propsToMarkAsProcessed.push('typings');
|
||||||
|
}
|
||||||
|
|
||||||
|
markAsProcessed(
|
||||||
|
pkgJsonUpdater, entryPoint.packageJson, packageJsonPath, propsToMarkAsProcessed);
|
||||||
|
}
|
||||||
|
};
|
@ -16,12 +16,13 @@ import {ModuleResolver} from './dependencies/module_resolver';
|
|||||||
import {UmdDependencyHost} from './dependencies/umd_dependency_host';
|
import {UmdDependencyHost} from './dependencies/umd_dependency_host';
|
||||||
import {DirectoryWalkerEntryPointFinder} from './entry_point_finder/directory_walker_entry_point_finder';
|
import {DirectoryWalkerEntryPointFinder} from './entry_point_finder/directory_walker_entry_point_finder';
|
||||||
import {TargetedEntryPointFinder} from './entry_point_finder/targeted_entry_point_finder';
|
import {TargetedEntryPointFinder} from './entry_point_finder/targeted_entry_point_finder';
|
||||||
import {AnalyzeEntryPointsFn, CreateCompileFn, EntryPointProcessingMetadata, ExecuteFn, Task, TaskProcessingOutcome} from './execution/api';
|
import {AnalyzeEntryPointsFn, CreateCompileFn, EntryPointProcessingMetadata, Executor, Task, TaskProcessingOutcome} from './execution/api';
|
||||||
|
import {SingleProcessExecutor} from './execution/single_process_executor';
|
||||||
import {ConsoleLogger, LogLevel} from './logging/console_logger';
|
import {ConsoleLogger, LogLevel} from './logging/console_logger';
|
||||||
import {Logger} from './logging/logger';
|
import {Logger} from './logging/logger';
|
||||||
import {hasBeenProcessed, markAsProcessed} from './packages/build_marker';
|
import {hasBeenProcessed, markAsProcessed} from './packages/build_marker';
|
||||||
import {NgccConfiguration} from './packages/configuration';
|
import {NgccConfiguration} from './packages/configuration';
|
||||||
import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, PackageJsonFormatProperties, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point';
|
import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point';
|
||||||
import {makeEntryPointBundle} from './packages/entry_point_bundle';
|
import {makeEntryPointBundle} from './packages/entry_point_bundle';
|
||||||
import {Transformer} from './packages/transformer';
|
import {Transformer} from './packages/transformer';
|
||||||
import {PathMappings} from './utils';
|
import {PathMappings} from './utils';
|
||||||
@ -189,56 +190,11 @@ export function mainNgcc(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// The function for actually planning and getting the work done.
|
// The executor for actually planning and getting the work done.
|
||||||
const execute: ExecuteFn =
|
const executor = getExecutor(logger, pkgJsonUpdater);
|
||||||
(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn) => {
|
const execOpts = {compileAllFormats, propertiesToConsider};
|
||||||
const {processingMetadataPerEntryPoint, tasks} = analyzeEntryPoints();
|
|
||||||
const compile = createCompileFn((task, outcome) => {
|
|
||||||
const {entryPoint, formatPropertiesToMarkAsProcessed, processDts} = task;
|
|
||||||
const processingMeta = processingMetadataPerEntryPoint.get(entryPoint.path) !;
|
|
||||||
processingMeta.hasAnyProcessedFormat = true;
|
|
||||||
|
|
||||||
if (outcome === TaskProcessingOutcome.Processed) {
|
return executor.execute(analyzeEntryPoints, createCompileFn, execOpts);
|
||||||
const packageJsonPath = fileSystem.resolve(entryPoint.path, 'package.json');
|
|
||||||
const propsToMarkAsProcessed: PackageJsonFormatProperties[] =
|
|
||||||
[...formatPropertiesToMarkAsProcessed];
|
|
||||||
|
|
||||||
if (processDts) {
|
|
||||||
processingMeta.hasProcessedTypings = true;
|
|
||||||
propsToMarkAsProcessed.push('typings');
|
|
||||||
}
|
|
||||||
|
|
||||||
markAsProcessed(
|
|
||||||
pkgJsonUpdater, entryPoint.packageJson, packageJsonPath, propsToMarkAsProcessed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Process all tasks.
|
|
||||||
for (const task of tasks) {
|
|
||||||
const processingMeta = processingMetadataPerEntryPoint.get(task.entryPoint.path) !;
|
|
||||||
|
|
||||||
// If we only need one format processed and we already have one for the corresponding
|
|
||||||
// entry-point, skip the task.
|
|
||||||
if (!compileAllFormats && processingMeta.hasAnyProcessedFormat) continue;
|
|
||||||
|
|
||||||
compile(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for entry-points for which we could not process any format at all.
|
|
||||||
const unprocessedEntryPointPaths =
|
|
||||||
Array.from(processingMetadataPerEntryPoint.entries())
|
|
||||||
.filter(([, processingMeta]) => !processingMeta.hasAnyProcessedFormat)
|
|
||||||
.map(([entryPointPath]) => `\n - ${entryPointPath}`)
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
if (unprocessedEntryPointPaths) {
|
|
||||||
throw new Error(
|
|
||||||
'Failed to compile any formats for the following entry-points (tried ' +
|
|
||||||
`${propertiesToConsider.join(', ')}): ${unprocessedEntryPointPaths}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return execute(analyzeEntryPoints, createCompileFn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureSupportedProperties(properties: string[]): EntryPointJsonProperty[] {
|
function ensureSupportedProperties(properties: string[]): EntryPointJsonProperty[] {
|
||||||
@ -270,6 +226,10 @@ function getFileWriter(
|
|||||||
new InPlaceFileWriter(fs);
|
new InPlaceFileWriter(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getExecutor(logger: Logger, pkgJsonUpdater: PackageJsonUpdater): Executor {
|
||||||
|
return new SingleProcessExecutor(logger, pkgJsonUpdater);
|
||||||
|
}
|
||||||
|
|
||||||
function getEntryPoints(
|
function getEntryPoints(
|
||||||
fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, logger: Logger,
|
fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, logger: Logger,
|
||||||
resolver: DependencyResolver, config: NgccConfiguration, basePath: AbsoluteFsPath,
|
resolver: DependencyResolver, config: NgccConfiguration, basePath: AbsoluteFsPath,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user