|
6 | 6 | * found in the LICENSE file at https://angular.io/license
|
7 | 7 | */
|
8 | 8 | import { experimental, json, logging } from '@angular-devkit/core';
|
9 |
| -import { Observable } from 'rxjs'; |
| 9 | +import { Observable, from } from 'rxjs'; |
| 10 | +import { switchMap } from 'rxjs/operators'; |
10 | 11 | import { Schema as RealBuilderInput, Target as RealTarget } from './input-schema';
|
11 | 12 | import { Schema as RealBuilderOutput } from './output-schema';
|
12 | 13 | import { Schema as RealBuilderProgress, State as BuilderProgressState } from './progress-schema';
|
@@ -211,6 +212,11 @@ export interface BuilderContext {
|
211 | 212 | * @param status Update the status string. If omitted the status string is not modified.
|
212 | 213 | */
|
213 | 214 | reportProgress(current: number, total?: number, status?: string): void;
|
| 215 | + |
| 216 | + /** |
| 217 | + * Add teardown logic to this Context, so that when it's being stopped it will execute teardown. |
| 218 | + */ |
| 219 | + addTeardown(teardown: () => (Promise<void> | void)): void; |
214 | 220 | }
|
215 | 221 |
|
216 | 222 |
|
@@ -268,3 +274,41 @@ export function targetFromTargetString(str: string): Target {
|
268 | 274 | ...(tuple[2] !== undefined) && { configuration: tuple[2] },
|
269 | 275 | };
|
270 | 276 | }
|
| 277 | + |
| 278 | +/** |
| 279 | + * Schedule a target, and forget about its run. This will return an observable of outputs, that |
| 280 | + * as a a teardown will stop the target from running. This means that the Run object this returns |
| 281 | + * should not be shared. |
| 282 | + * |
| 283 | + * The reason this is not part of the Context interface is to keep the Context as normal form as |
| 284 | + * possible. This is really an utility that people would implement in their project. |
| 285 | + * |
| 286 | + * @param context The context of your current execution. |
| 287 | + * @param target The target to schedule. |
| 288 | + * @param overrides Overrides that are used in the target. |
| 289 | + * @param scheduleOptions Additional scheduling options. |
| 290 | + */ |
| 291 | +export function scheduleTargetAndForget( |
| 292 | + context: BuilderContext, |
| 293 | + target: Target, |
| 294 | + overrides?: json.JsonObject, |
| 295 | + scheduleOptions?: ScheduleOptions, |
| 296 | +): Observable<BuilderOutput> { |
| 297 | + let resolve: (() => void) | null = null; |
| 298 | + const promise = new Promise<void>(r => resolve = r); |
| 299 | + context.addTeardown(() => promise); |
| 300 | + |
| 301 | + return from(context.scheduleTarget(target, overrides, scheduleOptions)).pipe( |
| 302 | + switchMap(run => new Observable<BuilderOutput>(observer => { |
| 303 | + const subscription = run.output.subscribe(observer); |
| 304 | + |
| 305 | + return () => { |
| 306 | + subscription.unsubscribe(); |
| 307 | + // We can properly ignore the floating promise as it's a "reverse" promise; the teardown |
| 308 | + // is waiting for the resolve. |
| 309 | + // tslint:disable-next-line:no-floating-promises |
| 310 | + run.stop().then(resolve); |
| 311 | + }; |
| 312 | + })), |
| 313 | + ); |
| 314 | +} |
0 commit comments