@rushstack/operation-graph 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Operation.js.map +1 -1
- package/lib/OperationExecutionManager.js.map +1 -1
- package/lib/OperationGroupRecord.js.map +1 -1
- package/lib/OperationStatus.js +1 -1
- package/lib/OperationStatus.js.map +1 -1
- package/lib/Stopwatch.js.map +1 -1
- package/lib/WatchLoop.d.ts.map +1 -1
- package/lib/WatchLoop.js +4 -0
- package/lib/WatchLoop.js.map +1 -1
- package/lib/WorkQueue.d.ts.map +1 -1
- package/lib/WorkQueue.js +6 -0
- package/lib/WorkQueue.js.map +1 -1
- package/lib/calculateCriticalPath.js.map +1 -1
- package/package.json +2 -2
package/lib/Operation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Operation.js","sourceRoot":"","sources":["../src/Operation.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError, type ITerminal } from '@rushstack/node-core-library';\n\nimport { Stopwatch } from './Stopwatch';\nimport type {\n IOperationRunner,\n IOperationRunnerContext,\n IOperationState,\n IOperationStates\n} from './IOperationRunner';\nimport type { OperationError } from './OperationError';\nimport { OperationStatus } from './OperationStatus';\n\n/**\n * Options for constructing a new Operation.\n * @beta\n */\nexport interface IOperationOptions {\n /**\n * The name of this operation, for logging.\n */\n name?: string | undefined;\n\n /**\n * The group that this operation belongs to. Will be used for logging and duration tracking.\n */\n groupName?: string | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n runner?: IOperationRunner | undefined;\n\n /**\n * The weight used by the scheduler to determine order of execution.\n */\n weight?: number | undefined;\n}\n\n/**\n * Information provided to `executeAsync` by the `OperationExecutionManager`.\n *\n * @beta\n */\nexport interface IExecuteOperationContext extends Omit<IOperationRunnerContext, 'isFirstRun' | 'requestRun'> {\n /**\n * Function to invoke before execution of an operation, for logging.\n */\n beforeExecute(operation: Operation, state: IOperationState): void;\n\n /**\n * Function to invoke after execution of an operation, for logging.\n */\n afterExecute(operation: Operation, state: IOperationState): void;\n\n /**\n * Function used to schedule the concurrency-limited execution of an operation.\n *\n * Will return OperationStatus.Aborted if execution is aborted before the task executes.\n */\n queueWork(workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus>;\n\n /**\n * A callback to the overarching orchestrator to request that the operation be invoked again.\n * Used in watch mode to signal that inputs have changed.\n */\n requestRun?: (requestor?: string) => void;\n\n /**\n * Terminal to write output to.\n */\n terminal: ITerminal;\n}\n\n/**\n * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the\n * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose\n * implementation manages the actual process of running a single operation.\n *\n * The graph of `Operation` instances will be cloned into a separate execution graph after processing.\n *\n * @beta\n */\nexport class Operation implements IOperationStates {\n /**\n * A set of all dependencies which must be executed before this operation is complete.\n */\n public readonly dependencies: Set<Operation> = new Set<Operation>();\n /**\n * A set of all operations that wait for this operation.\n */\n public readonly consumers: Set<Operation> = new Set<Operation>();\n /**\n * If specified, the name of a grouping to which this Operation belongs, for logging start and end times.\n */\n public readonly groupName: string | undefined;\n /**\n * The name of this operation, for logging.\n */\n public readonly name: string | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n public runner: IOperationRunner | undefined = undefined;\n\n /**\n * This number represents how far away this Operation is from the furthest \"root\" operation (i.e.\n * an operation with no consumers). This helps us to calculate the critical path (i.e. the\n * longest chain of projects which must be executed in order, thereby limiting execution speed\n * of the entire operation tree.\n *\n * This number is calculated via a memoized depth-first search, and when choosing the next\n * operation to execute, the operation with the highest criticalPathLength is chosen.\n *\n * Example:\n * (0) A\n * \\\\\n * (1) B C (0) (applications)\n * \\\\ /|\\\\\n * \\\\ / | \\\\\n * (2) D | X (1) (utilities)\n * | / \\\\\n * |/ \\\\\n * (2) Y Z (2) (other utilities)\n *\n * All roots (A & C) have a criticalPathLength of 0.\n * B has a score of 1, since A depends on it.\n * D has a score of 2, since we look at the longest chain (e.g D-\\>B-\\>A is longer than D-\\>C)\n * X has a score of 1, since the only package which depends on it is A\n * Z has a score of 2, since only X depends on it, and X has a score of 1\n * Y has a score of 2, since the chain Y-\\>X-\\>C is longer than Y-\\>C\n *\n * The algorithm is implemented in AsyncOperationQueue.ts as calculateCriticalPathLength()\n */\n public criticalPathLength: number | undefined = undefined;\n\n /**\n * The weight for this operation. This scalar is the contribution of this operation to the\n * `criticalPathLength` calculation above. Modify to indicate the following:\n * - `weight` === 1: indicates that this operation has an average duration\n * - `weight` > 1: indicates that this operation takes longer than average and so the scheduler\n * should try to favor starting it over other, shorter operations. An example might be an operation that\n * bundles an entire application and runs whole-program optimization.\n * - `weight` < 1: indicates that this operation takes less time than average and so the scheduler\n * should favor other, longer operations over it. An example might be an operation to unpack a cached\n * output, or an operation using NullOperationRunner, which might use a value of 0.\n */\n public weight: number;\n\n /**\n * The state of this operation the previous time a manager was invoked.\n */\n public lastState: IOperationState | undefined = undefined;\n\n /**\n * The current state of this operation\n */\n public state: IOperationState | undefined = undefined;\n\n /**\n * A cached execution promise for the current OperationExecutionManager invocation of this operation.\n */\n private _promise: Promise<OperationStatus> | undefined = undefined;\n\n /**\n * If true, then a run of this operation is currently wanted.\n * This is used to track state from the `requestRun` callback passed to the runner.\n */\n private _runPending: boolean = true;\n\n public constructor(options?: IOperationOptions) {\n this.groupName = options?.groupName;\n this.runner = options?.runner;\n this.weight = options?.weight || 1;\n this.name = options?.name;\n }\n\n public addDependency(dependency: Operation): void {\n this.dependencies.add(dependency);\n dependency.consumers.add(this);\n }\n\n public deleteDependency(dependency: Operation): void {\n this.dependencies.delete(dependency);\n dependency.consumers.delete(this);\n }\n\n public reset(): void {\n // Reset operation state\n this.lastState = this.state;\n\n this.state = {\n status: this.dependencies.size > 0 ? OperationStatus.Waiting : OperationStatus.Ready,\n hasBeenRun: this.lastState?.hasBeenRun ?? false,\n error: undefined,\n stopwatch: new Stopwatch()\n };\n\n this._promise = undefined;\n this._runPending = true;\n }\n\n /**\n * @internal\n */\n public async _executeAsync(context: IExecuteOperationContext): Promise<OperationStatus> {\n const { state } = this;\n if (!state) {\n throw new Error(`Operation state has not been initialized.`);\n }\n\n if (!this._promise) {\n this._promise = this._executeInnerAsync(context, state);\n }\n\n return this._promise;\n }\n\n private async _executeInnerAsync(\n context: IExecuteOperationContext,\n rawState: IOperationState\n ): Promise<OperationStatus> {\n const state: IOperationState = rawState;\n const { runner } = this;\n\n const dependencyResults: PromiseSettledResult<OperationStatus>[] = await Promise.allSettled(\n Array.from(this.dependencies, (dependency: Operation) => dependency._executeAsync(context))\n );\n\n const { abortSignal, requestRun, queueWork } = context;\n\n if (abortSignal.aborted) {\n state.status = OperationStatus.Aborted;\n return state.status;\n }\n\n for (const result of dependencyResults) {\n if (\n result.status === 'rejected' ||\n result.value === OperationStatus.Blocked ||\n result.value === OperationStatus.Failure\n ) {\n state.status = OperationStatus.Blocked;\n return state.status;\n }\n }\n\n state.status = OperationStatus.Ready;\n\n const innerContext: IOperationRunnerContext = {\n abortSignal,\n isFirstRun: !state.hasBeenRun,\n requestRun: requestRun\n ? () => {\n switch (this.state?.status) {\n case OperationStatus.Waiting:\n case OperationStatus.Ready:\n case OperationStatus.Executing:\n // If current status has not yet resolved to a fixed value,\n // re-executing this operation does not require a full rerun\n // of the operation graph. Simply mark that a run is requested.\n\n // This variable is on the Operation instead of the\n // containing closure to deal with scenarios in which\n // the runner hangs on to an old copy of the callback.\n this._runPending = true;\n return;\n\n case OperationStatus.Blocked:\n case OperationStatus.Aborted:\n case OperationStatus.Failure:\n case OperationStatus.NoOp:\n case OperationStatus.Success:\n // The requestRun callback is assumed to remain constant\n // throughout the lifetime of the process, so it is safe\n // to capture here.\n return requestRun(this.name);\n default:\n // This line is here to enforce exhaustiveness\n const currentStatus: undefined = this.state?.status;\n throw new InternalError(`Unexpected status: ${currentStatus}`);\n }\n }\n : undefined\n };\n\n // eslint-disable-next-line require-atomic-updates\n state.status = await queueWork(async (): Promise<OperationStatus> => {\n // Redundant variable to satisfy require-atomic-updates\n const innerState: IOperationState = state;\n\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n return innerState.status;\n }\n\n context.beforeExecute(this, innerState);\n\n innerState.stopwatch.start();\n innerState.status = OperationStatus.Executing;\n // Mark that the operation has been started at least once.\n innerState.hasBeenRun = true;\n\n while (this._runPending) {\n this._runPending = false;\n try {\n // We don't support aborting in the middle of a runner's execution.\n innerState.status = runner ? await runner.executeAsync(innerContext) : OperationStatus.NoOp;\n } catch (error) {\n innerState.status = OperationStatus.Failure;\n innerState.error = error as OperationError;\n }\n\n // Since runner.executeAsync is async, a change could have occurred that requires re-execution\n // This operation is still active, so can re-execute immediately, rather than forcing a whole\n // new execution pass.\n\n // As currently written, this does mean that if a job is scheduled with higher priority while\n // this operation is still executing, it will still wait for this retry. This may not be desired\n // and if it becomes a problem, the retry loop will need to be moved outside of the `queueWork` call.\n // This introduces complexity regarding tracking of timing and start/end logging, however.\n\n if (this._runPending) {\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n break;\n } else {\n context.terminal.writeLine(`Immediate rerun requested. Executing.`);\n }\n }\n }\n\n state.stopwatch.stop();\n context.afterExecute(this, state);\n\n return state.status;\n }, /* priority */ this.criticalPathLength ?? 0);\n\n return state.status;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Operation.js","sourceRoot":"","sources":["../src/Operation.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError, type ITerminal } from '@rushstack/node-core-library';\n\nimport { Stopwatch } from './Stopwatch';\nimport type {\n IOperationRunner,\n IOperationRunnerContext,\n IOperationState,\n IOperationStates\n} from './IOperationRunner';\nimport type { OperationError } from './OperationError';\nimport { OperationStatus } from './OperationStatus';\n\n/**\n * Options for constructing a new Operation.\n * @beta\n */\nexport interface IOperationOptions {\n /**\n * The name of this operation, for logging.\n */\n name?: string | undefined;\n\n /**\n * The group that this operation belongs to. Will be used for logging and duration tracking.\n */\n groupName?: string | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n runner?: IOperationRunner | undefined;\n\n /**\n * The weight used by the scheduler to determine order of execution.\n */\n weight?: number | undefined;\n}\n\n/**\n * Information provided to `executeAsync` by the `OperationExecutionManager`.\n *\n * @beta\n */\nexport interface IExecuteOperationContext extends Omit<IOperationRunnerContext, 'isFirstRun' | 'requestRun'> {\n /**\n * Function to invoke before execution of an operation, for logging.\n */\n beforeExecute(operation: Operation, state: IOperationState): void;\n\n /**\n * Function to invoke after execution of an operation, for logging.\n */\n afterExecute(operation: Operation, state: IOperationState): void;\n\n /**\n * Function used to schedule the concurrency-limited execution of an operation.\n *\n * Will return OperationStatus.Aborted if execution is aborted before the task executes.\n */\n queueWork(workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus>;\n\n /**\n * A callback to the overarching orchestrator to request that the operation be invoked again.\n * Used in watch mode to signal that inputs have changed.\n */\n requestRun?: (requestor?: string) => void;\n\n /**\n * Terminal to write output to.\n */\n terminal: ITerminal;\n}\n\n/**\n * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the\n * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose\n * implementation manages the actual process of running a single operation.\n *\n * The graph of `Operation` instances will be cloned into a separate execution graph after processing.\n *\n * @beta\n */\nexport class Operation implements IOperationStates {\n /**\n * A set of all dependencies which must be executed before this operation is complete.\n */\n public readonly dependencies: Set<Operation> = new Set<Operation>();\n /**\n * A set of all operations that wait for this operation.\n */\n public readonly consumers: Set<Operation> = new Set<Operation>();\n /**\n * If specified, the name of a grouping to which this Operation belongs, for logging start and end times.\n */\n public readonly groupName: string | undefined;\n /**\n * The name of this operation, for logging.\n */\n public readonly name: string | undefined;\n\n /**\n * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of\n * running the operation.\n */\n public runner: IOperationRunner | undefined = undefined;\n\n /**\n * This number represents how far away this Operation is from the furthest \"root\" operation (i.e.\n * an operation with no consumers). This helps us to calculate the critical path (i.e. the\n * longest chain of projects which must be executed in order, thereby limiting execution speed\n * of the entire operation tree.\n *\n * This number is calculated via a memoized depth-first search, and when choosing the next\n * operation to execute, the operation with the highest criticalPathLength is chosen.\n *\n * Example:\n * (0) A\n * \\\\\n * (1) B C (0) (applications)\n * \\\\ /|\\\\\n * \\\\ / | \\\\\n * (2) D | X (1) (utilities)\n * | / \\\\\n * |/ \\\\\n * (2) Y Z (2) (other utilities)\n *\n * All roots (A & C) have a criticalPathLength of 0.\n * B has a score of 1, since A depends on it.\n * D has a score of 2, since we look at the longest chain (e.g D-\\>B-\\>A is longer than D-\\>C)\n * X has a score of 1, since the only package which depends on it is A\n * Z has a score of 2, since only X depends on it, and X has a score of 1\n * Y has a score of 2, since the chain Y-\\>X-\\>C is longer than Y-\\>C\n *\n * The algorithm is implemented in AsyncOperationQueue.ts as calculateCriticalPathLength()\n */\n public criticalPathLength: number | undefined = undefined;\n\n /**\n * The weight for this operation. This scalar is the contribution of this operation to the\n * `criticalPathLength` calculation above. Modify to indicate the following:\n * - `weight` === 1: indicates that this operation has an average duration\n * - `weight` > 1: indicates that this operation takes longer than average and so the scheduler\n * should try to favor starting it over other, shorter operations. An example might be an operation that\n * bundles an entire application and runs whole-program optimization.\n * - `weight` < 1: indicates that this operation takes less time than average and so the scheduler\n * should favor other, longer operations over it. An example might be an operation to unpack a cached\n * output, or an operation using NullOperationRunner, which might use a value of 0.\n */\n public weight: number;\n\n /**\n * The state of this operation the previous time a manager was invoked.\n */\n public lastState: IOperationState | undefined = undefined;\n\n /**\n * The current state of this operation\n */\n public state: IOperationState | undefined = undefined;\n\n /**\n * A cached execution promise for the current OperationExecutionManager invocation of this operation.\n */\n private _promise: Promise<OperationStatus> | undefined = undefined;\n\n /**\n * If true, then a run of this operation is currently wanted.\n * This is used to track state from the `requestRun` callback passed to the runner.\n */\n private _runPending: boolean = true;\n\n public constructor(options?: IOperationOptions) {\n this.groupName = options?.groupName;\n this.runner = options?.runner;\n this.weight = options?.weight || 1;\n this.name = options?.name;\n }\n\n public addDependency(dependency: Operation): void {\n this.dependencies.add(dependency);\n dependency.consumers.add(this);\n }\n\n public deleteDependency(dependency: Operation): void {\n this.dependencies.delete(dependency);\n dependency.consumers.delete(this);\n }\n\n public reset(): void {\n // Reset operation state\n this.lastState = this.state;\n\n this.state = {\n status: this.dependencies.size > 0 ? OperationStatus.Waiting : OperationStatus.Ready,\n hasBeenRun: this.lastState?.hasBeenRun ?? false,\n error: undefined,\n stopwatch: new Stopwatch()\n };\n\n this._promise = undefined;\n this._runPending = true;\n }\n\n /**\n * @internal\n */\n public async _executeAsync(context: IExecuteOperationContext): Promise<OperationStatus> {\n const { state } = this;\n if (!state) {\n throw new Error(`Operation state has not been initialized.`);\n }\n\n if (!this._promise) {\n this._promise = this._executeInnerAsync(context, state);\n }\n\n return this._promise;\n }\n\n private async _executeInnerAsync(\n context: IExecuteOperationContext,\n rawState: IOperationState\n ): Promise<OperationStatus> {\n const state: IOperationState = rawState;\n const { runner } = this;\n\n const dependencyResults: PromiseSettledResult<OperationStatus>[] = await Promise.allSettled(\n Array.from(this.dependencies, (dependency: Operation) => dependency._executeAsync(context))\n );\n\n const { abortSignal, requestRun, queueWork } = context;\n\n if (abortSignal.aborted) {\n state.status = OperationStatus.Aborted;\n return state.status;\n }\n\n for (const result of dependencyResults) {\n if (\n result.status === 'rejected' ||\n result.value === OperationStatus.Blocked ||\n result.value === OperationStatus.Failure\n ) {\n state.status = OperationStatus.Blocked;\n return state.status;\n }\n }\n\n state.status = OperationStatus.Ready;\n\n const innerContext: IOperationRunnerContext = {\n abortSignal,\n isFirstRun: !state.hasBeenRun,\n requestRun: requestRun\n ? () => {\n switch (this.state?.status) {\n case OperationStatus.Waiting:\n case OperationStatus.Ready:\n case OperationStatus.Executing:\n // If current status has not yet resolved to a fixed value,\n // re-executing this operation does not require a full rerun\n // of the operation graph. Simply mark that a run is requested.\n\n // This variable is on the Operation instead of the\n // containing closure to deal with scenarios in which\n // the runner hangs on to an old copy of the callback.\n this._runPending = true;\n return;\n\n case OperationStatus.Blocked:\n case OperationStatus.Aborted:\n case OperationStatus.Failure:\n case OperationStatus.NoOp:\n case OperationStatus.Success:\n // The requestRun callback is assumed to remain constant\n // throughout the lifetime of the process, so it is safe\n // to capture here.\n return requestRun(this.name);\n default:\n // This line is here to enforce exhaustiveness\n const currentStatus: undefined = this.state?.status;\n throw new InternalError(`Unexpected status: ${currentStatus}`);\n }\n }\n : undefined\n };\n\n // eslint-disable-next-line require-atomic-updates\n state.status = await queueWork(async (): Promise<OperationStatus> => {\n // Redundant variable to satisfy require-atomic-updates\n const innerState: IOperationState = state;\n\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n return innerState.status;\n }\n\n context.beforeExecute(this, innerState);\n\n innerState.stopwatch.start();\n innerState.status = OperationStatus.Executing;\n // Mark that the operation has been started at least once.\n innerState.hasBeenRun = true;\n\n while (this._runPending) {\n this._runPending = false;\n try {\n // We don't support aborting in the middle of a runner's execution.\n innerState.status = runner ? await runner.executeAsync(innerContext) : OperationStatus.NoOp;\n } catch (error) {\n innerState.status = OperationStatus.Failure;\n innerState.error = error as OperationError;\n }\n\n // Since runner.executeAsync is async, a change could have occurred that requires re-execution\n // This operation is still active, so can re-execute immediately, rather than forcing a whole\n // new execution pass.\n\n // As currently written, this does mean that if a job is scheduled with higher priority while\n // this operation is still executing, it will still wait for this retry. This may not be desired\n // and if it becomes a problem, the retry loop will need to be moved outside of the `queueWork` call.\n // This introduces complexity regarding tracking of timing and start/end logging, however.\n\n if (this._runPending) {\n if (abortSignal.aborted) {\n innerState.status = OperationStatus.Aborted;\n break;\n } else {\n context.terminal.writeLine(`Immediate rerun requested. Executing.`);\n }\n }\n }\n\n state.stopwatch.stop();\n context.afterExecute(this, state);\n\n return state.status;\n }, /* priority */ this.criticalPathLength ?? 0);\n\n return state.status;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationExecutionManager.js","sourceRoot":"","sources":["../src/OperationExecutionManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Async, type ITerminal } from '@rushstack/node-core-library';\n\nimport type { IOperationState } from './IOperationRunner';\nimport type { IExecuteOperationContext, Operation } from './Operation';\nimport { OperationGroupRecord } from './OperationGroupRecord';\nimport { OperationStatus } from './OperationStatus';\nimport { calculateCriticalPathLengths } from './calculateCriticalPath';\nimport { WorkQueue } from './WorkQueue';\n\n/**\n * Options for the current run.\n *\n * @beta\n */\nexport interface IOperationExecutionOptions {\n abortSignal: AbortSignal;\n parallelism: number;\n terminal: ITerminal;\n\n requestRun?: (requestor?: string) => void;\n}\n\n/**\n * A class which manages the execution of a set of tasks with interdependencies.\n * Initially, and at the end of each task execution, all unblocked tasks\n * are added to a ready queue which is then executed. This is done continually until all\n * tasks are complete, or prematurely fails if any of the tasks fail.\n *\n * @beta\n */\nexport class OperationExecutionManager {\n /**\n * The set of operations that will be executed\n */\n private readonly _operations: Operation[];\n /**\n * Group records are metadata-only entities used for tracking the start and end of a set of related tasks.\n * This is the only extent to which the operation graph is aware of Heft phases.\n */\n private readonly _groupRecordByName: Map<string, OperationGroupRecord>;\n /**\n * The total number of non-silent operations in the graph.\n * Silent operations are generally used to simplify the construction of the graph.\n */\n private readonly _trackedOperationCount: number;\n\n public constructor(operations: ReadonlySet<Operation>) {\n const groupRecordByName: Map<string, OperationGroupRecord> = new Map();\n this._groupRecordByName = groupRecordByName;\n\n let trackedOperationCount: number = 0;\n for (const operation of operations) {\n const { groupName } = operation;\n let group: OperationGroupRecord | undefined = undefined;\n if (groupName && !(group = groupRecordByName.get(groupName))) {\n group = new OperationGroupRecord(groupName);\n groupRecordByName.set(groupName, group);\n }\n\n group?.addOperation(operation);\n\n if (!operation.runner?.silent) {\n // Only count non-silent operations\n trackedOperationCount++;\n }\n }\n\n this._trackedOperationCount = trackedOperationCount;\n\n this._operations = calculateCriticalPathLengths(operations);\n\n for (const consumer of operations) {\n for (const dependency of consumer.dependencies) {\n if (!operations.has(dependency)) {\n throw new Error(\n `Operation ${JSON.stringify(consumer.name)} declares a dependency on operation ` +\n `${JSON.stringify(dependency.name)} that is not in the set of operations to execute.`\n );\n }\n }\n }\n }\n\n /**\n * Executes all operations which have been registered, returning a promise which is resolved when all the\n * operations are completed successfully, or rejects when any operation fails.\n */\n public async executeAsync(executionOptions: IOperationExecutionOptions): Promise<OperationStatus> {\n let hasReportedFailures: boolean = false;\n\n const { abortSignal, parallelism, terminal, requestRun } = executionOptions;\n\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n const startedGroups: Set<OperationGroupRecord> = new Set();\n const finishedGroups: Set<OperationGroupRecord> = new Set();\n\n const maxParallelism: number = Math.min(this._operations.length, parallelism);\n const groupRecords: Map<string, OperationGroupRecord> = this._groupRecordByName;\n for (const groupRecord of groupRecords.values()) {\n groupRecord.reset();\n }\n\n for (const operation of this._operations) {\n operation.reset();\n }\n\n terminal.writeVerboseLine(`Executing a maximum of ${maxParallelism} simultaneous tasks...`);\n\n const workQueueAbortController: AbortController = new AbortController();\n abortSignal.addEventListener('abort', () => workQueueAbortController.abort(), { once: true });\n const workQueue: WorkQueue = new WorkQueue(workQueueAbortController.signal);\n\n const executionContext: IExecuteOperationContext = {\n terminal,\n abortSignal,\n\n requestRun,\n\n queueWork: (workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus> => {\n return workQueue.pushAsync(workFn, priority);\n },\n\n beforeExecute: (operation: Operation): void => {\n // Initialize group if uninitialized and log the group name\n const { groupName } = operation;\n const groupRecord: OperationGroupRecord | undefined = groupName\n ? groupRecords.get(groupName)\n : undefined;\n if (groupRecord && !startedGroups.has(groupRecord)) {\n startedGroups.add(groupRecord);\n groupRecord.startTimer();\n terminal.writeLine(` ---- ${groupRecord.name} started ---- `);\n }\n },\n\n afterExecute: (operation: Operation, state: IOperationState): void => {\n const { groupName } = operation;\n const groupRecord: OperationGroupRecord | undefined = groupName\n ? groupRecords.get(groupName)\n : undefined;\n if (groupRecord) {\n groupRecord.setOperationAsComplete(operation, state);\n }\n\n if (state.status === OperationStatus.Failure) {\n // This operation failed. Mark it as such and all reachable dependents as blocked.\n // Failed operations get reported, even if silent.\n // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure.\n const message: string | undefined = state.error?.message;\n if (message) {\n terminal.writeErrorLine(message);\n }\n hasReportedFailures = true;\n }\n\n // Log out the group name and duration if it is the last operation in the group\n if (groupRecord?.finished && !finishedGroups.has(groupRecord)) {\n finishedGroups.add(groupRecord);\n const finishedLoggingWord: string = groupRecord.hasFailures\n ? 'encountered an error'\n : groupRecord.hasCancellations\n ? 'cancelled'\n : 'finished';\n terminal.writeLine(\n ` ---- ${groupRecord.name} ${finishedLoggingWord} (${groupRecord.duration.toFixed(3)}s) ---- `\n );\n }\n }\n };\n\n const workQueuePromise: Promise<void> = Async.forEachAsync(\n workQueue,\n (workFn: () => Promise<void>) => workFn(),\n {\n concurrency: maxParallelism\n }\n );\n\n await Promise.all(this._operations.map((record: Operation) => record._executeAsync(executionContext)));\n\n // Terminate queue execution.\n workQueueAbortController.abort();\n await workQueuePromise;\n\n const finalStatus: OperationStatus =\n this._trackedOperationCount === 0\n ? OperationStatus.NoOp\n : abortSignal.aborted\n ? OperationStatus.Aborted\n : hasReportedFailures\n ? OperationStatus.Failure\n : OperationStatus.Success;\n\n return finalStatus;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OperationExecutionManager.js","sourceRoot":"","sources":["../src/OperationExecutionManager.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAqE;AAIrE,iEAA8D;AAC9D,uDAAoD;AACpD,mEAAuE;AACvE,2CAAwC;AAexC;;;;;;;GAOG;AACH,MAAa,yBAAyB;IAgBpC,YAAmB,UAAkC;QACnD,MAAM,iBAAiB,GAAsC,IAAI,GAAG,EAAE,CAAC;QACvE,IAAI,CAAC,kBAAkB,GAAG,iBAAiB,CAAC;QAE5C,IAAI,qBAAqB,GAAW,CAAC,CAAC;QACtC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;YAChC,IAAI,KAAK,GAAqC,SAAS,CAAC;YACxD,IAAI,SAAS,IAAI,CAAC,CAAC,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;gBAC7D,KAAK,GAAG,IAAI,2CAAoB,CAAC,SAAS,CAAC,CAAC;gBAC5C,iBAAiB,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC1C,CAAC;YAED,KAAK,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;YAE/B,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBAC9B,mCAAmC;gBACnC,qBAAqB,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,IAAI,CAAC,sBAAsB,GAAG,qBAAqB,CAAC;QAEpD,IAAI,CAAC,WAAW,GAAG,IAAA,oDAA4B,EAAC,UAAU,CAAC,CAAC;QAE5D,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,KAAK,MAAM,UAAU,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;gBAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChC,MAAM,IAAI,KAAK,CACb,aAAa,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,sCAAsC;wBAC9E,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,mDAAmD,CACxF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,YAAY,CAAC,gBAA4C;QACpE,IAAI,mBAAmB,GAAY,KAAK,CAAC;QAEzC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,gBAAgB,CAAC;QAE5E,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO,iCAAe,CAAC,OAAO,CAAC;QACjC,CAAC;QAED,MAAM,aAAa,GAA8B,IAAI,GAAG,EAAE,CAAC;QAC3D,MAAM,cAAc,GAA8B,IAAI,GAAG,EAAE,CAAC;QAE5D,MAAM,cAAc,GAAW,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC9E,MAAM,YAAY,GAAsC,IAAI,CAAC,kBAAkB,CAAC;QAChF,KAAK,MAAM,WAAW,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;YAChD,WAAW,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACzC,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QAED,QAAQ,CAAC,gBAAgB,CAAC,0BAA0B,cAAc,wBAAwB,CAAC,CAAC;QAE5F,MAAM,wBAAwB,GAAoB,IAAI,eAAe,EAAE,CAAC;QACxE,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9F,MAAM,SAAS,GAAc,IAAI,qBAAS,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAE5E,MAAM,gBAAgB,GAA6B;YACjD,QAAQ;YACR,WAAW;YAEX,UAAU;YAEV,SAAS,EAAE,CAAC,MAAsC,EAAE,QAAgB,EAA4B,EAAE;gBAChG,OAAO,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC/C,CAAC;YAED,aAAa,EAAE,CAAC,SAAoB,EAAQ,EAAE;gBAC5C,2DAA2D;gBAC3D,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;gBAChC,MAAM,WAAW,GAAqC,SAAS;oBAC7D,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;oBAC7B,CAAC,CAAC,SAAS,CAAC;gBACd,IAAI,WAAW,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;oBACnD,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBAC/B,WAAW,CAAC,UAAU,EAAE,CAAC;oBACzB,QAAQ,CAAC,SAAS,CAAC,SAAS,WAAW,CAAC,IAAI,gBAAgB,CAAC,CAAC;gBAChE,CAAC;YACH,CAAC;YAED,YAAY,EAAE,CAAC,SAAoB,EAAE,KAAsB,EAAQ,EAAE;gBACnE,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC;gBAChC,MAAM,WAAW,GAAqC,SAAS;oBAC7D,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;oBAC7B,CAAC,CAAC,SAAS,CAAC;gBACd,IAAI,WAAW,EAAE,CAAC;oBAChB,WAAW,CAAC,sBAAsB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;gBACvD,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,KAAK,iCAAe,CAAC,OAAO,EAAE,CAAC;oBAC7C,kFAAkF;oBAClF,kDAAkD;oBAClD,gGAAgG;oBAChG,MAAM,OAAO,GAAuB,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC;oBACzD,IAAI,OAAO,EAAE,CAAC;wBACZ,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;oBACnC,CAAC;oBACD,mBAAmB,GAAG,IAAI,CAAC;gBAC7B,CAAC;gBAED,+EAA+E;gBAC/E,IAAI,WAAW,EAAE,QAAQ,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC9D,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBAChC,MAAM,mBAAmB,GAAW,WAAW,CAAC,WAAW;wBACzD,CAAC,CAAC,sBAAsB;wBACxB,CAAC,CAAC,WAAW,CAAC,gBAAgB;4BAC9B,CAAC,CAAC,WAAW;4BACb,CAAC,CAAC,UAAU,CAAC;oBACf,QAAQ,CAAC,SAAS,CAChB,SAAS,WAAW,CAAC,IAAI,IAAI,mBAAmB,KAAK,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAC/F,CAAC;gBACJ,CAAC;YACH,CAAC;SACF,CAAC;QAEF,MAAM,gBAAgB,GAAkB,yBAAK,CAAC,YAAY,CACxD,SAAS,EACT,CAAC,MAA2B,EAAE,EAAE,CAAC,MAAM,EAAE,EACzC;YACE,WAAW,EAAE,cAAc;SAC5B,CACF,CAAC;QAEF,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAiB,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAEvG,6BAA6B;QAC7B,wBAAwB,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,gBAAgB,CAAC;QAEvB,MAAM,WAAW,GACf,IAAI,CAAC,sBAAsB,KAAK,CAAC;YAC/B,CAAC,CAAC,iCAAe,CAAC,IAAI;YACtB,CAAC,CAAC,WAAW,CAAC,OAAO;gBACrB,CAAC,CAAC,iCAAe,CAAC,OAAO;gBACzB,CAAC,CAAC,mBAAmB;oBACrB,CAAC,CAAC,iCAAe,CAAC,OAAO;oBACzB,CAAC,CAAC,iCAAe,CAAC,OAAO,CAAC;QAE9B,OAAO,WAAW,CAAC;IACrB,CAAC;CACF;AAxKD,8DAwKC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Async, type ITerminal } from '@rushstack/node-core-library';\n\nimport type { IOperationState } from './IOperationRunner';\nimport type { IExecuteOperationContext, Operation } from './Operation';\nimport { OperationGroupRecord } from './OperationGroupRecord';\nimport { OperationStatus } from './OperationStatus';\nimport { calculateCriticalPathLengths } from './calculateCriticalPath';\nimport { WorkQueue } from './WorkQueue';\n\n/**\n * Options for the current run.\n *\n * @beta\n */\nexport interface IOperationExecutionOptions {\n abortSignal: AbortSignal;\n parallelism: number;\n terminal: ITerminal;\n\n requestRun?: (requestor?: string) => void;\n}\n\n/**\n * A class which manages the execution of a set of tasks with interdependencies.\n * Initially, and at the end of each task execution, all unblocked tasks\n * are added to a ready queue which is then executed. This is done continually until all\n * tasks are complete, or prematurely fails if any of the tasks fail.\n *\n * @beta\n */\nexport class OperationExecutionManager {\n /**\n * The set of operations that will be executed\n */\n private readonly _operations: Operation[];\n /**\n * Group records are metadata-only entities used for tracking the start and end of a set of related tasks.\n * This is the only extent to which the operation graph is aware of Heft phases.\n */\n private readonly _groupRecordByName: Map<string, OperationGroupRecord>;\n /**\n * The total number of non-silent operations in the graph.\n * Silent operations are generally used to simplify the construction of the graph.\n */\n private readonly _trackedOperationCount: number;\n\n public constructor(operations: ReadonlySet<Operation>) {\n const groupRecordByName: Map<string, OperationGroupRecord> = new Map();\n this._groupRecordByName = groupRecordByName;\n\n let trackedOperationCount: number = 0;\n for (const operation of operations) {\n const { groupName } = operation;\n let group: OperationGroupRecord | undefined = undefined;\n if (groupName && !(group = groupRecordByName.get(groupName))) {\n group = new OperationGroupRecord(groupName);\n groupRecordByName.set(groupName, group);\n }\n\n group?.addOperation(operation);\n\n if (!operation.runner?.silent) {\n // Only count non-silent operations\n trackedOperationCount++;\n }\n }\n\n this._trackedOperationCount = trackedOperationCount;\n\n this._operations = calculateCriticalPathLengths(operations);\n\n for (const consumer of operations) {\n for (const dependency of consumer.dependencies) {\n if (!operations.has(dependency)) {\n throw new Error(\n `Operation ${JSON.stringify(consumer.name)} declares a dependency on operation ` +\n `${JSON.stringify(dependency.name)} that is not in the set of operations to execute.`\n );\n }\n }\n }\n }\n\n /**\n * Executes all operations which have been registered, returning a promise which is resolved when all the\n * operations are completed successfully, or rejects when any operation fails.\n */\n public async executeAsync(executionOptions: IOperationExecutionOptions): Promise<OperationStatus> {\n let hasReportedFailures: boolean = false;\n\n const { abortSignal, parallelism, terminal, requestRun } = executionOptions;\n\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n const startedGroups: Set<OperationGroupRecord> = new Set();\n const finishedGroups: Set<OperationGroupRecord> = new Set();\n\n const maxParallelism: number = Math.min(this._operations.length, parallelism);\n const groupRecords: Map<string, OperationGroupRecord> = this._groupRecordByName;\n for (const groupRecord of groupRecords.values()) {\n groupRecord.reset();\n }\n\n for (const operation of this._operations) {\n operation.reset();\n }\n\n terminal.writeVerboseLine(`Executing a maximum of ${maxParallelism} simultaneous tasks...`);\n\n const workQueueAbortController: AbortController = new AbortController();\n abortSignal.addEventListener('abort', () => workQueueAbortController.abort(), { once: true });\n const workQueue: WorkQueue = new WorkQueue(workQueueAbortController.signal);\n\n const executionContext: IExecuteOperationContext = {\n terminal,\n abortSignal,\n\n requestRun,\n\n queueWork: (workFn: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus> => {\n return workQueue.pushAsync(workFn, priority);\n },\n\n beforeExecute: (operation: Operation): void => {\n // Initialize group if uninitialized and log the group name\n const { groupName } = operation;\n const groupRecord: OperationGroupRecord | undefined = groupName\n ? groupRecords.get(groupName)\n : undefined;\n if (groupRecord && !startedGroups.has(groupRecord)) {\n startedGroups.add(groupRecord);\n groupRecord.startTimer();\n terminal.writeLine(` ---- ${groupRecord.name} started ---- `);\n }\n },\n\n afterExecute: (operation: Operation, state: IOperationState): void => {\n const { groupName } = operation;\n const groupRecord: OperationGroupRecord | undefined = groupName\n ? groupRecords.get(groupName)\n : undefined;\n if (groupRecord) {\n groupRecord.setOperationAsComplete(operation, state);\n }\n\n if (state.status === OperationStatus.Failure) {\n // This operation failed. Mark it as such and all reachable dependents as blocked.\n // Failed operations get reported, even if silent.\n // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure.\n const message: string | undefined = state.error?.message;\n if (message) {\n terminal.writeErrorLine(message);\n }\n hasReportedFailures = true;\n }\n\n // Log out the group name and duration if it is the last operation in the group\n if (groupRecord?.finished && !finishedGroups.has(groupRecord)) {\n finishedGroups.add(groupRecord);\n const finishedLoggingWord: string = groupRecord.hasFailures\n ? 'encountered an error'\n : groupRecord.hasCancellations\n ? 'cancelled'\n : 'finished';\n terminal.writeLine(\n ` ---- ${groupRecord.name} ${finishedLoggingWord} (${groupRecord.duration.toFixed(3)}s) ---- `\n );\n }\n }\n };\n\n const workQueuePromise: Promise<void> = Async.forEachAsync(\n workQueue,\n (workFn: () => Promise<void>) => workFn(),\n {\n concurrency: maxParallelism\n }\n );\n\n await Promise.all(this._operations.map((record: Operation) => record._executeAsync(executionContext)));\n\n // Terminate queue execution.\n workQueueAbortController.abort();\n await workQueuePromise;\n\n const finalStatus: OperationStatus =\n this._trackedOperationCount === 0\n ? OperationStatus.NoOp\n : abortSignal.aborted\n ? OperationStatus.Aborted\n : hasReportedFailures\n ? OperationStatus.Failure\n : OperationStatus.Success;\n\n return finalStatus;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationGroupRecord.js","sourceRoot":"","sources":["../src/OperationGroupRecord.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAA6D;AAI7D,uDAAoD;AACpD,2CAAwC;AAExC;;;;GAIG;AACH,MAAa,oBAAoB;IAU/B,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,YAAmB,IAAY;QAzBd,gBAAW,GAAmB,IAAI,GAAG,EAAE,CAAC;QACjD,yBAAoB,GAAmB,IAAI,GAAG,EAAE,CAAC;QAEjD,oBAAe,GAAc,IAAI,qBAAS,EAAE,CAAC;QAC7C,sBAAiB,GAAY,KAAK,CAAC;QACnC,iBAAY,GAAY,KAAK,CAAC;QAqBpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAEM,YAAY,CAAC,SAAoB;QACtC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAEM,UAAU;QACf,yFAAyF;QACzF,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAEM,sBAAsB,CAAC,SAAoB,EAAE,KAAsB;QACxE,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"OperationGroupRecord.js","sourceRoot":"","sources":["../src/OperationGroupRecord.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAA6D;AAI7D,uDAAoD;AACpD,2CAAwC;AAExC;;;;GAIG;AACH,MAAa,oBAAoB;IAU/B,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,YAAmB,IAAY;QAzBd,gBAAW,GAAmB,IAAI,GAAG,EAAE,CAAC;QACjD,yBAAoB,GAAmB,IAAI,GAAG,EAAE,CAAC;QAEjD,oBAAe,GAAc,IAAI,qBAAS,EAAE,CAAC;QAC7C,sBAAiB,GAAY,KAAK,CAAC;QACnC,iBAAY,GAAY,KAAK,CAAC;QAqBpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAEM,YAAY,CAAC,SAAoB;QACtC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAEM,UAAU;QACf,yFAAyF;QACzF,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAEM,sBAAsB,CAAC,SAAoB,EAAE,KAAsB;QACxE,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,iCAAa,CAAC,aAAa,SAAS,CAAC,IAAI,wBAAwB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,iCAAe,CAAC,OAAO,EAAE,CAAC;YAC7C,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAChC,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,iCAAe,CAAC,OAAO,EAAE,CAAC;YACpD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QAED,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,oBAAoB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IAEM,KAAK;QACV,IAAI,CAAC,oBAAoB,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACtD,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;CACF;AA9DD,oDA8DC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { InternalError } from '@rushstack/node-core-library';\n\nimport type { IOperationState } from './IOperationRunner';\nimport type { Operation } from './Operation';\nimport { OperationStatus } from './OperationStatus';\nimport { Stopwatch } from './Stopwatch';\n\n/**\n * Meta-entity that tracks information about a group of related operations.\n *\n * @beta\n */\nexport class OperationGroupRecord {\n private readonly _operations: Set<Operation> = new Set();\n private _remainingOperations: Set<Operation> = new Set();\n\n private _groupStopwatch: Stopwatch = new Stopwatch();\n private _hasCancellations: boolean = false;\n private _hasFailures: boolean = false;\n\n public readonly name: string;\n\n public get duration(): number {\n return this._groupStopwatch ? this._groupStopwatch.duration : 0;\n }\n\n public get finished(): boolean {\n return this._remainingOperations.size === 0;\n }\n\n public get hasCancellations(): boolean {\n return this._hasCancellations;\n }\n\n public get hasFailures(): boolean {\n return this._hasFailures;\n }\n\n public constructor(name: string) {\n this.name = name;\n }\n\n public addOperation(operation: Operation): void {\n this._operations.add(operation);\n }\n\n public startTimer(): void {\n // Keep this undefined until needed, then start to avoid subsequent calls to startTimer()\n this._groupStopwatch.start();\n }\n\n public setOperationAsComplete(operation: Operation, state: IOperationState): void {\n if (!this._remainingOperations.has(operation)) {\n throw new InternalError(`Operation ${operation.name} is not in the group ${this.name}`);\n }\n\n if (state.status === OperationStatus.Aborted) {\n this._hasCancellations = true;\n } else if (state.status === OperationStatus.Failure) {\n this._hasFailures = true;\n }\n\n this._remainingOperations.delete(operation);\n if (this._remainingOperations.size === 0) {\n this._groupStopwatch.stop();\n }\n }\n\n public reset(): void {\n this._remainingOperations = new Set(this._operations);\n this._groupStopwatch.reset();\n this._hasCancellations = false;\n this._hasFailures = false;\n }\n}\n"]}
|
package/lib/OperationStatus.js
CHANGED
|
@@ -41,5 +41,5 @@ var OperationStatus;
|
|
|
41
41
|
* The operation performed no meaningful work.
|
|
42
42
|
*/
|
|
43
43
|
OperationStatus["NoOp"] = "NO OP";
|
|
44
|
-
})(OperationStatus
|
|
44
|
+
})(OperationStatus || (exports.OperationStatus = OperationStatus = {}));
|
|
45
45
|
//# sourceMappingURL=OperationStatus.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationStatus.js","sourceRoot":"","sources":["../src/OperationStatus.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D;;;GAGG;AACH,IAAY,eAiCX;AAjCD,WAAY,eAAe;IACzB;;OAEG;IACH,kCAAe,CAAA;IACf;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,0CAAuB,CAAA;IACvB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,iCAAc,CAAA;AAChB,CAAC,EAjCW,eAAe,
|
|
1
|
+
{"version":3,"file":"OperationStatus.js","sourceRoot":"","sources":["../src/OperationStatus.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D;;;GAGG;AACH,IAAY,eAiCX;AAjCD,WAAY,eAAe;IACzB;;OAEG;IACH,kCAAe,CAAA;IACf;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,0CAAuB,CAAA;IACvB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,sCAAmB,CAAA;IACnB;;OAEG;IACH,iCAAc,CAAA;AAChB,CAAC,EAjCW,eAAe,+BAAf,eAAe,QAiC1B","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Enumeration defining potential states of an operation\n * @beta\n */\nexport enum OperationStatus {\n /**\n * The Operation is on the queue, ready to execute\n */\n Ready = 'READY',\n /**\n * The Operation is on the queue, waiting for one or more depencies\n */\n Waiting = 'WAITING',\n /**\n * The Operation is currently executing\n */\n Executing = 'EXECUTING',\n /**\n * The Operation completed successfully and did not write to standard output\n */\n Success = 'SUCCESS',\n /**\n * The Operation failed\n */\n Failure = 'FAILURE',\n /**\n * The operation was aborted\n */\n Aborted = 'ABORTED',\n /**\n * The Operation could not be executed because one or more of its dependencies failed\n */\n Blocked = 'BLOCKED',\n /**\n * The operation performed no meaningful work.\n */\n NoOp = 'NO OP'\n}\n"]}
|
package/lib/Stopwatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stopwatch.js","sourceRoot":"","sources":["../src/Stopwatch.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D;;;;;GAKG;AACH,MAAa,SAAS;IAKpB;QACE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,KAAK;QACjB,OAAO,IAAI,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC;IACjC,CAAC;IAED,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACI,KAAK;QACV,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE;
|
|
1
|
+
{"version":3,"file":"Stopwatch.js","sourceRoot":"","sources":["../src/Stopwatch.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D;;;;;GAKG;AACH,MAAa,SAAS;IAKpB;QACE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,KAAK;QACjB,OAAO,IAAI,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC;IACjC,CAAC;IAED,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACI,KAAK;QACV,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACpC,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,IAAI;QACT,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9E,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,KAAK;QACV,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACI,QAAQ;QACb,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACpD,OAAO,wBAAwB,CAAC;QAClC,CAAC;QACD,MAAM,YAAY,GAAW,IAAI,CAAC,QAAQ,CAAC;QAE3C,IAAI,YAAY,GAAG,EAAE,EAAE,CAAC;YACtB,MAAM,OAAO,GAAW,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;YACtD,MAAM,OAAO,GAAW,YAAY,GAAG,IAAI,CAAC;YAE5C,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;QACjG,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;QAC9C,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAW,QAAQ;QACjB,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,OAAO,GAAW,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QAExF,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,IAAW,SAAS;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF;AAlGD,8BAkGC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Represents a typical timer/stopwatch which keeps track\n * of elapsed time in between two events.\n *\n * @public\n */\nexport class Stopwatch {\n private _startTime: number | undefined;\n private _endTime: number | undefined;\n private _running: boolean;\n\n public constructor() {\n this._startTime = undefined;\n this._endTime = undefined;\n this._running = false;\n }\n\n /**\n * Static helper function which creates a stopwatch which is immediately started\n */\n public static start(): Stopwatch {\n return new Stopwatch().start();\n }\n\n public get isRunning(): boolean {\n return this._running;\n }\n\n /**\n * Starts the stopwatch. Note that if end() has been called,\n * reset() should be called before calling start() again.\n */\n public start(): Stopwatch {\n if (this._startTime !== undefined) {\n throw new Error('Call reset() before starting the Stopwatch');\n }\n this._startTime = performance.now();\n this._endTime = undefined;\n this._running = true;\n return this;\n }\n\n /**\n * Stops executing the stopwatch and saves the current timestamp\n */\n public stop(): Stopwatch {\n this._endTime = this._startTime !== undefined ? performance.now() : undefined;\n this._running = false;\n return this;\n }\n\n /**\n * Resets all values of the stopwatch back to the original\n */\n public reset(): Stopwatch {\n this._endTime = this._startTime = undefined;\n this._running = false;\n return this;\n }\n\n /**\n * Displays how long the stopwatch has been executing in a human readable format.\n */\n public toString(): string {\n if (!this._running && this._startTime === undefined) {\n return '0.00 seconds (stopped)';\n }\n const totalSeconds: number = this.duration;\n\n if (totalSeconds > 60) {\n const minutes: number = Math.floor(totalSeconds / 60);\n const seconds: number = totalSeconds % 60.0;\n\n return `${minutes.toFixed(0)} minute${minutes === 1 ? '' : 's'} ${seconds.toFixed(1)} seconds`;\n } else {\n return `${totalSeconds.toFixed(2)} seconds`;\n }\n }\n\n /**\n * Get the duration in seconds.\n */\n public get duration(): number {\n if (this._startTime === undefined) {\n return 0;\n }\n const curTime: number = this._endTime !== undefined ? this._endTime : performance.now();\n\n return (curTime - this._startTime) / 1000.0;\n }\n\n /**\n * Return the start time of the most recent stopwatch run.\n */\n public get startTime(): number | undefined {\n return this._startTime;\n }\n\n /**\n * Return the end time of the most recent stopwatch run.\n */\n public get endTime(): number | undefined {\n return this._endTime;\n }\n}\n"]}
|
package/lib/WatchLoop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WatchLoop.d.ts","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":";AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAEV,OAAO,EAIR,MAAM,kBAAkB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE;;OAEG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B;;OAEG;IACH,YAAY,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,WAAW,IAAI,WAAW,CAAC;IAC/B,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED;;;;GAIG;AACH,qBAAa,SAAU,YAAW,eAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAErD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,kBAAkB,CAA8B;IACxD,OAAO,CAAC,kBAAkB,CAAgC;gBAEvC,OAAO,EAAE,iBAAiB;IAc7C;;OAEG;IACU,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"WatchLoop.d.ts","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":";AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAEV,OAAO,EAIR,MAAM,kBAAkB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE;;OAEG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B;;OAEG;IACH,YAAY,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,WAAW,IAAI,WAAW,CAAC;IAC/B,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C;AAED;;;;GAIG;AACH,qBAAa,SAAU,YAAW,eAAe;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IAErD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,kBAAkB,CAA8B;IACxD,OAAO,CAAC,kBAAkB,CAAgC;gBAEvC,OAAO,EAAE,iBAAiB;IAc7C;;OAEG;IACU,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IAwCpF;;OAEG;IACU,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBjG;;;OAGG;IACU,WAAW,CAAC,IAAI,GAAE,OAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkFhE;;OAEG;IACI,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAU7C;IAEF;;OAEG;IACH,IAAW,WAAW,IAAI,WAAW,CAEpC;IAED;;OAEG;IACH,OAAO,CAAC,aAAa,CAEnB;IAEF;;OAEG;IACH,OAAO,CAAC,MAAM;CAYf"}
|
package/lib/WatchLoop.js
CHANGED
|
@@ -51,6 +51,8 @@ class WatchLoop {
|
|
|
51
51
|
return OperationStatus_1.OperationStatus.Aborted;
|
|
52
52
|
}
|
|
53
53
|
if (!this._outerSignals.has(abortSignal)) {
|
|
54
|
+
// ESLINT: "Promises must be awaited, end with a call to .catch, end with a call to .then ..."
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
54
56
|
(0, node_events_1.once)(abortSignal, 'abort').finally(this._abortCurrent);
|
|
55
57
|
}
|
|
56
58
|
let result = OperationStatus_1.OperationStatus.Ready;
|
|
@@ -140,6 +142,8 @@ class WatchLoop {
|
|
|
140
142
|
status = OperationStatus_1.OperationStatus.Executing;
|
|
141
143
|
try {
|
|
142
144
|
status = await this.runUntilStableAsync(abortController.signal);
|
|
145
|
+
// ESLINT: "Promises must be awaited, end with a call to .catch, end with a call to .then ..."
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
143
147
|
this._requestRunPromise.finally(requestRunFromHost);
|
|
144
148
|
}
|
|
145
149
|
catch (err) {
|
package/lib/WatchLoop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WatchLoop.js","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,6CAAmC;AAEnC,oEAAoE;AAEpE,uDAAoD;AA2CpD;;;;GAIG;AACH,MAAa,SAAS;IAUpB,YAAmB,OAA0B;QA8J7C;;WAEG;QACI,eAAU,GAAiC,CAAC,SAAkB,EAAE,EAAE;YACvE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;gBACvB,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;gBACtC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;gBAC1B,IAAI,IAAI,CAAC,UAAU,EAAE;oBACnB,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;oBACxB,IAAI,CAAC,aAAa,EAAE,CAAC;iBACtB;aACF;YACD,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC,CAAC;QASF;;WAEG;QACK,kBAAa,GAAG,GAAS,EAAE;YACjC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAChC,CAAC,CAAC;QAxLA,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAExB,IAAI,CAAC,gBAAgB,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,8EAA8E;QAC9E,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,kBAAkB,GAAG,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,EAAE;YACpE,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,GAAG,IAAI,OAAO,EAAE,CAAC;IACrC,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,mBAAmB,CAAC,WAAwB;QACvD,IAAI,WAAW,CAAC,OAAO,EAAE;YACvB,OAAO,iCAAe,CAAC,OAAO,CAAC;SAChC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;YACxC,IAAA,kBAAI,EAAC,WAAW,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;SACxD;QAED,IAAI,MAAM,GAAoB,iCAAe,CAAC,KAAK,CAAC;QAEpD,GAAG;YACD,oHAAoH;YACpH,IAAI,WAAW,CAAC,OAAO,EAAE;gBACvB,OAAO,iCAAe,CAAC,OAAO,CAAC;aAChC;YAED,IAAI,CAAC,MAAM,EAAE,CAAC;YAEd,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;YAChC,IAAI;gBACF,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;gBACvB,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;aACjD;YAAC,OAAO,GAAG,EAAE;gBACZ,IAAI,CAAC,CAAC,GAAG,YAAY,wCAAoB,CAAC,EAAE;oBAC1C,MAAM,GAAG,CAAC;iBACX;qBAAM;oBACL,MAAM,GAAG,iCAAe,CAAC,OAAO,CAAC;iBAClC;aACF;oBAAS;gBACR,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;aACzB;SACF,QAAQ,IAAI,CAAC,aAAa,EAAE;QAE7B,0GAA0G;QAC1G,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,iCAAe,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAChE,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,oBAAoB,CAAC,WAAwB,EAAE,SAAqB;QAC/E,IAAI,WAAW,CAAC,OAAO,EAAE;YACvB,OAAO;SACR;QAED,MAAM,YAAY,GAAqB,IAAA,kBAAI,EAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAElE,iDAAiD;QACjD,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE;YAC3B,MAAM,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;YAE5C,SAAS,EAAE,CAAC;YACZ,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC,CAAC;SAC7D;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,WAAW,CAAC,OAAgB,OAAO;QAC9C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,IAAI,eAAe,GAAoB,IAAI,eAAe,EAAE,CAAC;YAE7D,IAAI,oBAAoB,GAAY,IAAI,CAAC;YACzC,IAAI,MAAM,GAAoB,iCAAe,CAAC,KAAK,CAAC;YAEpD,SAAS,kBAAkB,CAAC,SAAkB;gBAC5C,IAAI,oBAAoB,EAAE;oBACxB,OAAO;iBACR;gBAED,oBAAoB,GAAG,IAAI,CAAC;gBAE5B,MAAM,iBAAiB,GAA4B;oBACjD,KAAK,EAAE,YAAY;oBACnB,SAAS;iBACV,CAAC;gBAEF,IAAI,CAAC,IAAK,CAAC,iBAAiB,CAAC,CAAC;YAChC,CAAC;YAED,SAAS,QAAQ;gBACf,MAAM,WAAW,GAAsB;oBACrC,KAAK,EAAE,MAAM;oBACb,MAAM;iBACP,CAAC;gBACF,IAAI,CAAC,IAAK,CAAC,WAAW,CAAC,CAAC;YAC1B,CAAC;YAED,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,OAA+B,EAAE,EAAE;gBAC3D,QAAQ,OAAO,CAAC,OAAO,EAAE;oBACvB,KAAK,MAAM,CAAC,CAAC;wBACX,OAAO,OAAO,EAAE,CAAC;qBAClB;oBAED,KAAK,QAAQ,CAAC,CAAC;wBACb,IAAI,IAAI,CAAC,UAAU,EAAE;4BACnB,eAAe,CAAC,KAAK,EAAE,CAAC;4BACxB,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;4BACxC,0EAA0E;yBAC3E;wBACD,OAAO;qBACR;oBAED,KAAK,KAAK,CAAC,CAAC;wBACV,oBAAoB,GAAG,KAAK,CAAC;wBAE7B,MAAM,GAAG,iCAAe,CAAC,SAAS,CAAC;wBAEnC,IAAI;4BACF,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;4BAChE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;yBACrD;wBAAC,OAAO,GAAG,EAAE;4BACZ,MAAM,GAAG,iCAAe,CAAC,OAAO,CAAC;4BACjC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;yBACpB;gCAAS;4BACR,MAAM,mBAAmB,GAA8B;gCACrD,KAAK,EAAE,eAAe;gCACtB,MAAM;6BACP,CAAC;4BACF,IAAI,CAAC,IAAK,CAAC,mBAAmB,CAAC,CAAC;yBACjC;wBACD,OAAO;qBACR;oBAED,KAAK,MAAM,CAAC,CAAC;wBACX,OAAO,QAAQ,EAAE,CAAC;qBACnB;oBAED,OAAO,CAAC,CAAC;wBACP,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC,CAAC;qBACtE;iBACF;YACH,CAAC,CAAC,CAAC;YAEH,QAAQ,EAAE,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;IAiBD;;OAEG;IACH,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;IACtC,CAAC;IASD;;OAEG;IACK,MAAM;QACZ,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,EAAE;YACxC,IAAI,CAAC,gBAAgB,GAAG,IAAI,eAAe,EAAE,CAAC;SAC/C;QAED,IAAI,IAAI,CAAC,aAAa,EAAE;YACtB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;YAC3B,IAAI,CAAC,kBAAkB,GAAG,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,EAAE;gBACpE,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC;YACpC,CAAC,CAAC,CAAC;SACJ;IACH,CAAC;CACF;AApND,8BAoNC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { once } from 'node:events';\n\nimport { AlreadyReportedError } from '@rushstack/node-core-library';\n\nimport { OperationStatus } from './OperationStatus';\nimport type {\n IAfterExecuteEventMessage,\n IPCHost,\n CommandMessageFromHost,\n ISyncEventMessage,\n IRequestRunEventMessage\n} from './protocol.types';\n\n/**\n * Callbacks for the watch loop.\n *\n * @beta\n */\nexport interface IWatchLoopOptions {\n /**\n * Callback that performs the core work of a single iteration.\n */\n executeAsync: (state: IWatchLoopState) => Promise<OperationStatus>;\n /**\n * Logging callback immediately before execution occurs.\n */\n onBeforeExecute: () => void;\n /**\n * Logging callback when a run is requested (and hasn't already been).\n */\n onRequestRun: (requestor?: string) => void;\n /**\n * Logging callback when a run is aborted.\n */\n onAbort: () => void;\n}\n\n/**\n * The public API surface of the watch loop, for use in the `executeAsync` callback.\n *\n * @beta\n */\nexport interface IWatchLoopState {\n get abortSignal(): AbortSignal;\n requestRun: (requestor?: string) => void;\n}\n\n/**\n * This class implements a watch loop.\n *\n * @beta\n */\nexport class WatchLoop implements IWatchLoopState {\n private readonly _options: Readonly<IWatchLoopOptions>;\n private readonly _outerSignals: WeakSet<AbortSignal>;\n\n private _abortController: AbortController;\n private _isRunning: boolean;\n private _runRequested: boolean;\n private _requestRunPromise: Promise<string | undefined>;\n private _resolveRequestRun!: (requestor?: string) => void;\n\n public constructor(options: IWatchLoopOptions) {\n this._options = options;\n\n this._abortController = new AbortController();\n this._isRunning = false;\n // Always start as true, so that any requests prior to first run are silenced.\n this._runRequested = true;\n this._requestRunPromise = new Promise<string | undefined>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n\n this._outerSignals = new WeakSet();\n }\n\n /**\n * Runs the inner loop until the abort signal is cancelled or a run completes without a new run being requested.\n */\n public async runUntilStableAsync(abortSignal: AbortSignal): Promise<OperationStatus> {\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n if (!this._outerSignals.has(abortSignal)) {\n once(abortSignal, 'abort').finally(this._abortCurrent);\n }\n\n let result: OperationStatus = OperationStatus.Ready;\n\n do {\n // Always check the abort signal first, in case it was aborted in the async tick since the last executeAsync() call.\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n this._reset();\n\n this._options.onBeforeExecute();\n try {\n this._isRunning = true;\n result = await this._options.executeAsync(this);\n } catch (err) {\n if (!(err instanceof AlreadyReportedError)) {\n throw err;\n } else {\n result = OperationStatus.Failure;\n }\n } finally {\n this._isRunning = false;\n }\n } while (this._runRequested);\n\n // Even if the run has finished, if the abort signal was aborted, we should return `Aborted` just in case.\n return abortSignal.aborted ? OperationStatus.Aborted : result;\n }\n\n /**\n * Runs the inner loop until the abort signal is aborted. Will otherwise wait indefinitely for a new run to be requested.\n */\n public async runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise<void> {\n if (abortSignal.aborted) {\n return;\n }\n\n const abortPromise: Promise<unknown> = once(abortSignal, 'abort');\n\n // eslint-disable-next-line no-constant-condition\n while (!abortSignal.aborted) {\n await this.runUntilStableAsync(abortSignal);\n\n onWaiting();\n await Promise.race([this._requestRunPromise, abortPromise]);\n }\n }\n\n /**\n * Sets up an IPC handler that will run the inner loop when it receives a \"run\" message from the host.\n * Runs until receiving an \"exit\" message from the host, or aborts early if an unhandled error is thrown.\n */\n public async runIPCAsync(host: IPCHost = process): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n let abortController: AbortController = new AbortController();\n\n let runRequestedFromHost: boolean = true;\n let status: OperationStatus = OperationStatus.Ready;\n\n function requestRunFromHost(requestor?: string): void {\n if (runRequestedFromHost) {\n return;\n }\n\n runRequestedFromHost = true;\n\n const requestRunMessage: IRequestRunEventMessage = {\n event: 'requestRun',\n requestor\n };\n\n host.send!(requestRunMessage);\n }\n\n function sendSync(): void {\n const syncMessage: ISyncEventMessage = {\n event: 'sync',\n status\n };\n host.send!(syncMessage);\n }\n\n host.on('message', async (message: CommandMessageFromHost) => {\n switch (message.command) {\n case 'exit': {\n return resolve();\n }\n\n case 'cancel': {\n if (this._isRunning) {\n abortController.abort();\n abortController = new AbortController();\n // This will terminate the currently executing `runUntilStableAsync` call.\n }\n return;\n }\n\n case 'run': {\n runRequestedFromHost = false;\n\n status = OperationStatus.Executing;\n\n try {\n status = await this.runUntilStableAsync(abortController.signal);\n this._requestRunPromise.finally(requestRunFromHost);\n } catch (err) {\n status = OperationStatus.Failure;\n return reject(err);\n } finally {\n const afterExecuteMessage: IAfterExecuteEventMessage = {\n event: 'after-execute',\n status\n };\n host.send!(afterExecuteMessage);\n }\n return;\n }\n\n case 'sync': {\n return sendSync();\n }\n\n default: {\n return reject(new Error(`Unexpected command from host: ${message}`));\n }\n }\n });\n\n sendSync();\n });\n }\n\n /**\n * Requests that a new run occur.\n */\n public requestRun: (requestor?: string) => void = (requestor?: string) => {\n if (!this._runRequested) {\n this._options.onRequestRun(requestor);\n this._runRequested = true;\n if (this._isRunning) {\n this._options.onAbort();\n this._abortCurrent();\n }\n }\n this._resolveRequestRun(requestor);\n };\n\n /**\n * The abort signal for the current iteration.\n */\n public get abortSignal(): AbortSignal {\n return this._abortController.signal;\n }\n\n /**\n * Cancels the current iteration (if possible).\n */\n private _abortCurrent = (): void => {\n this._abortController.abort();\n };\n\n /**\n * Resets the abort signal and run request state.\n */\n private _reset(): void {\n if (this._abortController.signal.aborted) {\n this._abortController = new AbortController();\n }\n\n if (this._runRequested) {\n this._runRequested = false;\n this._requestRunPromise = new Promise<string | undefined>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WatchLoop.js","sourceRoot":"","sources":["../src/WatchLoop.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { once } from 'node:events';\n\nimport { AlreadyReportedError } from '@rushstack/node-core-library';\n\nimport { OperationStatus } from './OperationStatus';\nimport type {\n IAfterExecuteEventMessage,\n IPCHost,\n CommandMessageFromHost,\n ISyncEventMessage,\n IRequestRunEventMessage\n} from './protocol.types';\n\n/**\n * Callbacks for the watch loop.\n *\n * @beta\n */\nexport interface IWatchLoopOptions {\n /**\n * Callback that performs the core work of a single iteration.\n */\n executeAsync: (state: IWatchLoopState) => Promise<OperationStatus>;\n /**\n * Logging callback immediately before execution occurs.\n */\n onBeforeExecute: () => void;\n /**\n * Logging callback when a run is requested (and hasn't already been).\n */\n onRequestRun: (requestor?: string) => void;\n /**\n * Logging callback when a run is aborted.\n */\n onAbort: () => void;\n}\n\n/**\n * The public API surface of the watch loop, for use in the `executeAsync` callback.\n *\n * @beta\n */\nexport interface IWatchLoopState {\n get abortSignal(): AbortSignal;\n requestRun: (requestor?: string) => void;\n}\n\n/**\n * This class implements a watch loop.\n *\n * @beta\n */\nexport class WatchLoop implements IWatchLoopState {\n private readonly _options: Readonly<IWatchLoopOptions>;\n private readonly _outerSignals: WeakSet<AbortSignal>;\n\n private _abortController: AbortController;\n private _isRunning: boolean;\n private _runRequested: boolean;\n private _requestRunPromise: Promise<string | undefined>;\n private _resolveRequestRun!: (requestor?: string) => void;\n\n public constructor(options: IWatchLoopOptions) {\n this._options = options;\n\n this._abortController = new AbortController();\n this._isRunning = false;\n // Always start as true, so that any requests prior to first run are silenced.\n this._runRequested = true;\n this._requestRunPromise = new Promise<string | undefined>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n\n this._outerSignals = new WeakSet();\n }\n\n /**\n * Runs the inner loop until the abort signal is cancelled or a run completes without a new run being requested.\n */\n public async runUntilStableAsync(abortSignal: AbortSignal): Promise<OperationStatus> {\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n if (!this._outerSignals.has(abortSignal)) {\n // ESLINT: \"Promises must be awaited, end with a call to .catch, end with a call to .then ...\"\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n once(abortSignal, 'abort').finally(this._abortCurrent);\n }\n\n let result: OperationStatus = OperationStatus.Ready;\n\n do {\n // Always check the abort signal first, in case it was aborted in the async tick since the last executeAsync() call.\n if (abortSignal.aborted) {\n return OperationStatus.Aborted;\n }\n\n this._reset();\n\n this._options.onBeforeExecute();\n try {\n this._isRunning = true;\n result = await this._options.executeAsync(this);\n } catch (err) {\n if (!(err instanceof AlreadyReportedError)) {\n throw err;\n } else {\n result = OperationStatus.Failure;\n }\n } finally {\n this._isRunning = false;\n }\n } while (this._runRequested);\n\n // Even if the run has finished, if the abort signal was aborted, we should return `Aborted` just in case.\n return abortSignal.aborted ? OperationStatus.Aborted : result;\n }\n\n /**\n * Runs the inner loop until the abort signal is aborted. Will otherwise wait indefinitely for a new run to be requested.\n */\n public async runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise<void> {\n if (abortSignal.aborted) {\n return;\n }\n\n const abortPromise: Promise<unknown> = once(abortSignal, 'abort');\n\n // eslint-disable-next-line no-constant-condition\n while (!abortSignal.aborted) {\n await this.runUntilStableAsync(abortSignal);\n\n onWaiting();\n await Promise.race([this._requestRunPromise, abortPromise]);\n }\n }\n\n /**\n * Sets up an IPC handler that will run the inner loop when it receives a \"run\" message from the host.\n * Runs until receiving an \"exit\" message from the host, or aborts early if an unhandled error is thrown.\n */\n public async runIPCAsync(host: IPCHost = process): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n let abortController: AbortController = new AbortController();\n\n let runRequestedFromHost: boolean = true;\n let status: OperationStatus = OperationStatus.Ready;\n\n function requestRunFromHost(requestor?: string): void {\n if (runRequestedFromHost) {\n return;\n }\n\n runRequestedFromHost = true;\n\n const requestRunMessage: IRequestRunEventMessage = {\n event: 'requestRun',\n requestor\n };\n\n host.send!(requestRunMessage);\n }\n\n function sendSync(): void {\n const syncMessage: ISyncEventMessage = {\n event: 'sync',\n status\n };\n host.send!(syncMessage);\n }\n\n host.on('message', async (message: CommandMessageFromHost) => {\n switch (message.command) {\n case 'exit': {\n return resolve();\n }\n\n case 'cancel': {\n if (this._isRunning) {\n abortController.abort();\n abortController = new AbortController();\n // This will terminate the currently executing `runUntilStableAsync` call.\n }\n return;\n }\n\n case 'run': {\n runRequestedFromHost = false;\n\n status = OperationStatus.Executing;\n\n try {\n status = await this.runUntilStableAsync(abortController.signal);\n // ESLINT: \"Promises must be awaited, end with a call to .catch, end with a call to .then ...\"\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._requestRunPromise.finally(requestRunFromHost);\n } catch (err) {\n status = OperationStatus.Failure;\n return reject(err);\n } finally {\n const afterExecuteMessage: IAfterExecuteEventMessage = {\n event: 'after-execute',\n status\n };\n host.send!(afterExecuteMessage);\n }\n return;\n }\n\n case 'sync': {\n return sendSync();\n }\n\n default: {\n return reject(new Error(`Unexpected command from host: ${message}`));\n }\n }\n });\n\n sendSync();\n });\n }\n\n /**\n * Requests that a new run occur.\n */\n public requestRun: (requestor?: string) => void = (requestor?: string) => {\n if (!this._runRequested) {\n this._options.onRequestRun(requestor);\n this._runRequested = true;\n if (this._isRunning) {\n this._options.onAbort();\n this._abortCurrent();\n }\n }\n this._resolveRequestRun(requestor);\n };\n\n /**\n * The abort signal for the current iteration.\n */\n public get abortSignal(): AbortSignal {\n return this._abortController.signal;\n }\n\n /**\n * Cancels the current iteration (if possible).\n */\n private _abortCurrent = (): void => {\n this._abortController.abort();\n };\n\n /**\n * Resets the abort signal and run request state.\n */\n private _reset(): void {\n if (this._abortController.signal.aborted) {\n this._abortController = new AbortController();\n }\n\n if (this._runRequested) {\n this._runRequested = false;\n this._requestRunPromise = new Promise<string | undefined>((resolve) => {\n this._resolveRequestRun = resolve;\n });\n }\n }\n}\n"]}
|
package/lib/WorkQueue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkQueue.d.ts","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOpD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAE9C,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,mBAAmB,CAA6B;gBAErC,WAAW,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"WorkQueue.d.ts","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOpD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAE9C,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,mBAAmB,CAA6B;gBAErC,WAAW,EAAE,WAAW;IAgB7B,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAW3E,SAAS,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAelG,OAAO,CAAC,qBAAqB;CAY9B"}
|
package/lib/WorkQueue.js
CHANGED
|
@@ -15,6 +15,8 @@ class WorkQueue {
|
|
|
15
15
|
: new Promise((resolve) => {
|
|
16
16
|
abortSignal.addEventListener('abort', () => resolve(), { once: true });
|
|
17
17
|
});
|
|
18
|
+
// ESLINT: "An array of Promises may be unintentional."
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
18
20
|
[this._pushPromise, this._resolvePush] = node_core_library_1.Async.getSignal();
|
|
19
21
|
this._resolvePushTimeout = undefined;
|
|
20
22
|
}
|
|
@@ -33,6 +35,8 @@ class WorkQueue {
|
|
|
33
35
|
task: () => task().then(resolve, reject),
|
|
34
36
|
priority
|
|
35
37
|
});
|
|
38
|
+
// ESLINT: "Promises must be awaited, end with a call to .catch, end with a call to .then ..."
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
36
40
|
this._abortPromise.finally(() => resolve(OperationStatus_1.OperationStatus.Aborted));
|
|
37
41
|
this._resolvePushDebounced();
|
|
38
42
|
});
|
|
@@ -42,6 +46,8 @@ class WorkQueue {
|
|
|
42
46
|
this._resolvePushTimeout = setTimeout(() => {
|
|
43
47
|
this._resolvePushTimeout = undefined;
|
|
44
48
|
this._resolvePush();
|
|
49
|
+
// ESLINT: "An array of Promises may be unintentional."
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
45
51
|
[this._pushPromise, this._resolvePush] = node_core_library_1.Async.getSignal();
|
|
46
52
|
});
|
|
47
53
|
}
|
package/lib/WorkQueue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkQueue.js","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAkE;AAElE,uDAAoD;AAOpD,MAAa,SAAS;IASpB,YAAmB,WAAwB;QACzC,8GAA8G;QAC9G,IAAI,CAAC,MAAM,GAAG,IAAI,+BAAW,CAAC,CAAC,CAAa,EAAE,CAAa,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QACzF,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,OAAO;YACtC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE;YACnB,CAAC,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAC5B,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"WorkQueue.js","sourceRoot":"","sources":["../src/WorkQueue.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAAkE;AAElE,uDAAoD;AAOpD,MAAa,SAAS;IASpB,YAAmB,WAAwB;QACzC,8GAA8G;QAC9G,IAAI,CAAC,MAAM,GAAG,IAAI,+BAAW,CAAC,CAAC,CAAa,EAAE,CAAa,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QACzF,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,OAAO;YACtC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE;YACnB,CAAC,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAC5B,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACzE,CAAC,CAAC,CAAC;QAEP,uDAAuD;QACvD,mEAAmE;QACnE,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,yBAAK,CAAC,SAAS,EAAE,CAAC;QAC3D,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;IACvC,CAAC;IAEM,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAe,IAAI,CAAC,MAAM,CAAC,IAAI,EAAG,CAAC;gBAC7C,MAAM,IAAI,CAAC,IAAI,CAAC;YAClB,CAAC;YAED,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAEM,SAAS,CAAC,IAAoC,EAAE,QAAgB;QACrE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;gBACxC,QAAQ;aACT,CAAC,CAAC;YAEH,8FAA8F;YAC9F,mEAAmE;YACnE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,iCAAe,CAAC,OAAO,CAAC,CAAC,CAAC;YAEnE,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,qBAAqB;QAC3B,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9B,IAAI,CAAC,mBAAmB,GAAG,UAAU,CAAC,GAAG,EAAE;gBACzC,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;gBACrC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAEpB,uDAAuD;gBACvD,mEAAmE;gBACnE,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,yBAAK,CAAC,SAAS,EAAE,CAAC;YAC7D,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF;AA/DD,8BA+DC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Async, MinimumHeap } from '@rushstack/node-core-library';\n\nimport { OperationStatus } from './OperationStatus';\n\ninterface IQueueItem {\n task: () => Promise<void>;\n priority: number;\n}\n\nexport class WorkQueue {\n private readonly _queue: MinimumHeap<IQueueItem>;\n private readonly _abortSignal: AbortSignal;\n private readonly _abortPromise: Promise<void>;\n\n private _pushPromise: Promise<void>;\n private _resolvePush: () => void;\n private _resolvePushTimeout: NodeJS.Timeout | undefined;\n\n public constructor(abortSignal: AbortSignal) {\n // Sort by priority descending. Thus the comparator returns a negative number if a has higher priority than b.\n this._queue = new MinimumHeap((a: IQueueItem, b: IQueueItem) => b.priority - a.priority);\n this._abortSignal = abortSignal;\n this._abortPromise = abortSignal.aborted\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n abortSignal.addEventListener('abort', () => resolve(), { once: true });\n });\n\n // ESLINT: \"An array of Promises may be unintentional.\"\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n [this._pushPromise, this._resolvePush] = Async.getSignal();\n this._resolvePushTimeout = undefined;\n }\n\n public async *[Symbol.asyncIterator](): AsyncIterableIterator<() => Promise<void>> {\n while (!this._abortSignal.aborted) {\n while (this._queue.size > 0) {\n const item: IQueueItem = this._queue.poll()!;\n yield item.task;\n }\n\n await Promise.race([this._pushPromise, this._abortPromise]);\n }\n }\n\n public pushAsync(task: () => Promise<OperationStatus>, priority: number): Promise<OperationStatus> {\n return new Promise((resolve, reject) => {\n this._queue.push({\n task: () => task().then(resolve, reject),\n priority\n });\n\n // ESLINT: \"Promises must be awaited, end with a call to .catch, end with a call to .then ...\"\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._abortPromise.finally(() => resolve(OperationStatus.Aborted));\n\n this._resolvePushDebounced();\n });\n }\n\n private _resolvePushDebounced(): void {\n if (!this._resolvePushTimeout) {\n this._resolvePushTimeout = setTimeout(() => {\n this._resolvePushTimeout = undefined;\n this._resolvePush();\n\n // ESLINT: \"An array of Promises may be unintentional.\"\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n [this._pushPromise, this._resolvePush] = Async.getSignal();\n });\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calculateCriticalPath.js","sourceRoot":"","sources":["../src/calculateCriticalPath.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAS3D;;;GAGG;AACH,SAAgB,4BAA4B,CAAkC,UAAuB;IACnG,mEAAmE;IACnE,MAAM,KAAK,GAAQ,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAE1C,kDAAkD;IAClD,MAAM,kBAAkB,GAAW,IAAI,GAAG,EAAE,CAAC;IAC7C,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE;
|
|
1
|
+
{"version":3,"file":"calculateCriticalPath.js","sourceRoot":"","sources":["../src/calculateCriticalPath.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nexport interface ISortableOperation<T extends ISortableOperation<T>> {\n name: string | undefined;\n criticalPathLength?: number | undefined;\n weight: number;\n consumers: Set<T>;\n}\n\n/**\n * For every operation in the input, computes the length of the longest chain of operations that depend on it.\n * This value is stored as `operation.criticalPathLength`.\n */\nexport function calculateCriticalPathLengths<T extends ISortableOperation<T>>(operations: Iterable<T>): T[] {\n // Clone the set of operations as an array, so that we can sort it.\n const queue: T[] = Array.from(operations);\n\n // Create a collection for detecting visited nodes\n const cycleDetectorStack: Set<T> = new Set();\n for (const operation of queue) {\n calculateCriticalPathLength(operation, cycleDetectorStack);\n }\n\n return queue;\n}\n\n/**\n * Calculates the shortest path from `startOperation` to `endOperation`.\n * Used when printing out circular dependencies.\n */\nexport function calculateShortestPath<T extends ISortableOperation<T>>(\n startOperation: T,\n endOperation: T\n): T[] {\n // Map of each operation to the most optimal parent\n const parents: Map<T, T | undefined> = new Map([[endOperation, undefined]]);\n let finalParent: T | undefined;\n\n // Run a breadth-first search to find the shortest path between the start and end operations\n outer: for (const [operation] of parents) {\n for (const consumer of operation.consumers) {\n // Since this is a breadth-first traversal, the first encountered path to a given node\n // will be tied for shortest, so only the first encountered path needs to be tracked\n if (!parents.has(consumer)) {\n parents.set(consumer, operation);\n }\n\n if (consumer === startOperation) {\n finalParent = operation;\n break outer;\n }\n }\n }\n\n if (!finalParent) {\n throw new Error(`Could not find a path from \"${startOperation.name}\" to \"${endOperation.name}\"`);\n }\n\n // Walk back up the path from the end operation to the start operation\n let currentOperation: T = finalParent;\n const path: T[] = [startOperation];\n while (currentOperation !== undefined) {\n path.push(currentOperation);\n currentOperation = parents.get(currentOperation)!;\n }\n return path;\n}\n\n/**\n * Perform a depth-first search to find critical path length to the provided operation.\n * Cycle detection comes at minimal additional cost.\n */\nexport function calculateCriticalPathLength<T extends ISortableOperation<T>>(\n operation: T,\n dependencyChain: Set<T>\n): number {\n if (dependencyChain.has(operation)) {\n // Ensure we have the shortest path to the cycle\n const shortestPath: T[] = calculateShortestPath(operation, operation);\n\n throw new Error(\n 'A cyclic dependency was encountered:\\n ' +\n shortestPath.map((visitedTask) => visitedTask.name).join('\\n -> ')\n );\n }\n\n let { criticalPathLength } = operation;\n\n if (criticalPathLength !== undefined) {\n // This has been visited already\n return criticalPathLength;\n }\n\n criticalPathLength = 0;\n if (operation.consumers.size) {\n dependencyChain.add(operation);\n for (const consumer of operation.consumers) {\n criticalPathLength = Math.max(\n criticalPathLength,\n calculateCriticalPathLength(consumer, dependencyChain)\n );\n }\n dependencyChain.delete(operation);\n }\n // Include the contribution from the current operation\n criticalPathLength += operation.weight ?? 1;\n\n // Record result\n operation.criticalPathLength = criticalPathLength;\n\n // Directly writing operations to an output collection here would yield a topological sorted set\n // However, we want a bit more fine-tuning of the output than just the raw topology\n\n return criticalPathLength;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/operation-graph",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Library for managing and executing operations in a directed acyclic graph.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "dist/operation-graph.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "libraries/operation-graph"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@rushstack/node-core-library": "3.
|
|
14
|
+
"@rushstack/node-core-library": "3.63.0"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@rushstack/heft": "0.62.0",
|