Skip to content

Commit

Permalink
Improve documentation for TaskAPI
Browse files Browse the repository at this point in the history
Fixes #8694
Signed-off-by: Tobias Ortmayr <tortmayr@eclipsesource.com>
Contributed on behalf of STMicroelectronics
  • Loading branch information
tortmayr committed Nov 4, 2020
1 parent fb3694b commit 1ad7f09
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 20 deletions.
106 changes: 100 additions & 6 deletions packages/task/src/browser/task-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,79 @@ import { WaitUntilEvent, Emitter } from '@theia/core/lib/common/event';

export const TaskContribution = Symbol('TaskContribution');

/** Allows to contribute custom Task Resolvers, Task Providers. */
/**
* A {@link TaskContribution} allows to contribute custom {@link TaskResolver}s and/or {@link TaskProvider}s.
*
* ### Example usage
* ```typescript
* @injectable()
* export class ProcessTaskContribution implements TaskContribution {
*
* @inject(ProcessTaskResolver)
* protected readonly processTaskResolver: ProcessTaskResolver;
*
* registerResolvers(resolvers: TaskResolverRegistry): void {
* resolvers.register('process', this.processTaskResolver);
* resolvers.register('shell', this.processTaskResolver);
* }
* }
* ```
*/
export interface TaskContribution {
/**
* Register task resolvers using the given `TaskResolverRegistry`.
* @param resolvers the task resolver registry.
*/
registerResolvers?(resolvers: TaskResolverRegistry): void;
/**
* Register task providers using the given `TaskProviderRegistry`.
* @param resolvers the task provider registry.
*/
registerProviders?(providers: TaskProviderRegistry): void;
}

/**
* A {@link TaskResolver} is used to preprocess/resolve a task before sending
* it to the Task Server. For instance, the resolver can be used to add missing information to the configuration
* (e.g default values for optional parameters).
*/
export interface TaskResolver {
/** Resolves a Task Configuration before sending it for execution to the Task Server. */
/**
* Resolves a `TaskConfiguration` before sending it for execution to the `TaskServer` (Backend).
* @param taskConfig the configuration that should be resolved.
*
* @returns a promise of the resolved `TaskConfiguration`.
*/

resolveTask(taskConfig: TaskConfiguration): Promise<TaskConfiguration>;
}

/**
* A {@link TaskProvider} can be used to define the set of tasks that should
* be provided to the system. i.e. that are available for the user to run.
*/
export interface TaskProvider {
/** Returns the Task Configurations which are provides programmatically to the system. */
/**
* Retrieves the task configurations which are provided programmatically to the system.
*
* @returns a promise of the provided tasks configurations.
*/
provideTasks(): Promise<TaskConfiguration[]>;
}

/**
* The {@link TaskResolverRegistry} is the common component for registration and provision of
* {@link TaskResolver}s. Theia will collect all {@link TaskContribution}s and invoke {@link TaskContribution#registerResolvers}
* for each contribution.
*/
@injectable()
export class TaskResolverRegistry {

protected readonly onWillProvideTaskResolverEmitter = new Emitter<WaitUntilEvent>();
/**
* Emit when the registry provides a registered resolver. i.e. when the {@link TaskResolverRegistry#getResolver}
* function is called.
*/
readonly onWillProvideTaskResolver = this.onWillProvideTaskResolverEmitter.event;

protected resolvers: Map<string, TaskResolver>;
Expand All @@ -50,24 +103,47 @@ export class TaskResolverRegistry {
this.resolvers = new Map();
}

/** Registers the given Task Resolver to resolve the Task Configurations of the specified type. */
/**
* Registers the given {@link TaskResolver} to resolve the `TaskConfiguration` of the specified type.
* If there is already a `TaskResolver` registered for the specified type the registration will
* be overwritten with the new value.
* @param type the task configuration type for which the given resolver should be registered.
* @param resolver the task resolver that should be registered.
*
* @returns a `Disposable` that can be invoked to unregister the given resolver
*/
register(type: string, resolver: TaskResolver): Disposable {
this.resolvers.set(type, resolver);
return {
dispose: () => this.resolvers.delete(type)
};
}

/**
* Retrieves the {@link TaskResolver} registered for the given type task configuration type.
* @param type the task configuration type
*
* @returns a promise of the registered `TaskResolver` or `undefined` if no resolver is registered for the given type.
*/
async getResolver(type: string): Promise<TaskResolver | undefined> {
await WaitUntilEvent.fire(this.onWillProvideTaskResolverEmitter, {});
return this.resolvers.get(type);
}
}

/**
* The {@link TaskProviderRegistry} is the common component for registration and provision of
* {@link TaskProvider}s. Theia will collect all {@link TaskContribution}s and invoke {@link TaskContribution#registerProviders}
* for each contribution.
*/
@injectable()
export class TaskProviderRegistry {

protected readonly onWillProvideTaskProviderEmitter = new Emitter<WaitUntilEvent>();
/**
* Emit when the registry provides a registered task provider. i.e. when the {@link TaskProviderRegistry#getProvider}
* function is called.
*/
readonly onWillProvideTaskProvider = this.onWillProvideTaskProviderEmitter.event;

protected providers: Map<string, TaskProvider>;
Expand All @@ -77,7 +153,13 @@ export class TaskProviderRegistry {
this.providers = new Map();
}

/** Registers the given Task Provider to return Task Configurations of the specified type. */
/**
* Registers the given {@link TaskProvider} for task configurations of the specified type
* @param type the task configuration type for which the given provider should be registered.
* @param provider the `TaskProvider` that should be registered.
*
* @returns a `Disposable` that can be invoked to unregister the given resolver.
*/
register(type: string, provider: TaskProvider, handle?: number): Disposable {
const key = handle === undefined ? type : `${type}::${handle}`;
this.providers.set(key, provider);
Expand All @@ -86,12 +168,24 @@ export class TaskProviderRegistry {
};
}

/**
* Retrieves the {@link TaskProvider} registered for the given type task configuration type.
* If there is already a `TaskProvider` registered for the specified type the registration will
* be overwritten with the new value.
* @param type the task configuration type.
*
* @returns a promise of the registered `TaskProvider`` or `undefined` if no provider is registered for the given type.
*/
async getProvider(type: string): Promise<TaskProvider | undefined> {
await WaitUntilEvent.fire(this.onWillProvideTaskProviderEmitter, {});
return this.providers.get(type);
}

/** Returns all registered Task Providers. */
/**
* Retrieve all registered {@link TaskProvider}s.
*
* @returns a promise of all registered {@link TaskProvider}s.
*/
async getProviders(): Promise<TaskProvider[]> {
await WaitUntilEvent.fire(this.onWillProvideTaskProviderEmitter, {});
return [...this.providers.values()];
Expand Down
34 changes: 31 additions & 3 deletions packages/task/src/node/task-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { Task } from './task';

// inspired by process-manager.ts

/**
* The {@link TaskManager} is the common component responsible for managing running tasks.
*/
@injectable()
export class TaskManager implements BackendApplicationContribution {

Expand All @@ -29,12 +32,23 @@ export class TaskManager implements BackendApplicationContribution {
protected readonly tasksPerCtx: Map<string, Task[]> = new Map();
/** each task has this unique task id, for this back-end */
protected id: number = -1;
/**
* Emit when a registered task is deleted.
*/
protected readonly deleteEmitter = new Emitter<number>();

constructor(
@inject(ILogger) @named('task') protected readonly logger: ILogger
) { }

/**
* Registers a new task (in the given context if present). Each registered
* task is considered to be currently running.
* @param task the new task.
* @param ctx the provided context.
*
* @returns the registration id for the given task.
*/
register(task: Task, ctx?: string): number {
const id = ++this.id;
this.tasks.set(id, task);
Expand All @@ -51,13 +65,22 @@ export class TaskManager implements BackendApplicationContribution {
return id;
}

/**
* Try to retrieve the registered task for the given id.
* @param id the task registration id.
*
* @returns the task or `undefined` if no task was registered for the given id.
*/
get(id: number): Task | undefined {
return this.tasks.get(id);
}

/**
* Returns all running tasks. If a context is provided, filter-down to
* only tasks started from that context
* only tasks started from that context.
* @param ctx the task execution context.
*
* @returns all running tasks for the given context or `undefined` if no tasks are registered for the given context.
*/
getTasks(ctx?: string): Task[] | undefined {
if (!ctx) {
Expand All @@ -69,7 +92,10 @@ export class TaskManager implements BackendApplicationContribution {
}
}

/** Deletes a task from the task manager */
/**
* Delete the given task from the task manager.
* @param task the task to delete.
*/
delete(task: Task): void {
this.tasks.delete(task.id);

Expand All @@ -88,7 +114,9 @@ export class TaskManager implements BackendApplicationContribution {
return this.deleteEmitter.event;
}

/** When the application stops, clean-up all ongoing tasks */
/**
* Is triggered on application stop to cleanup all ongoing tasks.
*/
onStop(): void {
this.tasks.forEach((task: Task, id: number) => {
this.logger.debug(`Task Backend application: onStop(): cleaning task id: ${id}`);
Expand Down
49 changes: 42 additions & 7 deletions packages/task/src/node/task-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,36 @@ import { TaskConfiguration } from '../common/task-protocol';

export const TaskRunnerContribution = Symbol('TaskRunnerContribution');

/** Allows to contribute custom Task Runners. */
/** The {@link TaskRunnerContribution} can be used to contribute custom {@link TaskRunner}s. */
export interface TaskRunnerContribution {
/**
* Register custom runners using the given {@link TaskRunnerRegistry}.
* @param runners the common task runner registry.
*/
registerRunner(runners: TaskRunnerRegistry): void;
}

export const TaskRunner = Symbol('TaskRunner');
/** A Task Runner knows how to run and kill a Task of a particular type. */
/**
* A {@link TaskRunner} knows how to run a task configuration of a particular type.
*/
export interface TaskRunner {
/** Runs a task based on the given task configuration. */
run(taskConfig: TaskConfiguration, ctx?: string): Promise<Task>;
/**
* Runs a task based on the given `TaskConfiguration`.
* @param taskConfig the task configuration that should be executed.
* @param ctx the execution context.
*
* @returns a promise of the (currently running) {@link Task}.
*/
run(tskConfig: TaskConfiguration, ctx?: string): Promise<Task>;
}

/**
* The {@link TaskRunnerRegistry} is the common component for the registration and provisioning of
* {@link TaskRunner}s. Theia will collect all {@link TaskRunner}s and invoke {@link TaskRunnerContribution#registerRunner}
* for each contribution. The `TaskServer` will use the runners provided by this registry to execute `TaskConfiguration`s that
* have been triggered by the user.
*/
@injectable()
export class TaskRunnerRegistry {

Expand All @@ -49,21 +67,38 @@ export class TaskRunnerRegistry {
this.runners = new Map();
this.defaultRunner = this.processTaskRunner;
}

/** Registers the given Task Runner to execute the Tasks of the specified type. */
/**
* Registers the given {@link TaskRunner} to execute Tasks of the specified type.
* If there is already a {@link TaskRunner} registered for the specified type the registration will
* be overwritten with the new value.
* @param type the task type for which the given runner should be registered.
* @param runner the task runner that should be registered.
*
* @returns a `Disposable` that can be invoked to unregister the given runner.
*/
registerRunner(type: string, runner: TaskRunner): Disposable {
this.runners.set(type, runner);
return {
dispose: () => this.runners.delete(type)
};
}

/** Returns a Task Runner registered for the specified Task type or a default Task Runner if none. */
/**
* Retrieves the {@link TaskRunner} registered for the specified Task type.
* @param type the task type.
*
* @returns the registered {@link TaskRunner} or a default runner if none is registered for the specified type.
*/
getRunner(type: string): TaskRunner {
const runner = this.runners.get(type);
return runner ? runner : this.defaultRunner;
}

/**
* Derives all task types for which a {@link TaskRunner} is registered.
*
* @returns all derived task types.
*/
getRunnerTypes(): string[] {
return [...this.runners.keys()];
}
Expand Down
26 changes: 22 additions & 4 deletions packages/task/src/node/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,23 @@ import { injectable } from 'inversify';
import { ILogger, Disposable, DisposableCollection, Emitter, Event, MaybePromise } from '@theia/core/lib/common/';
import { TaskManager } from './task-manager';
import { TaskInfo, TaskExitedEvent, TaskConfiguration, TaskOutputEvent } from '../common/task-protocol';

/**
* Represents the options used for running a task.
*/
export interface TaskOptions {
/** The task label */
label: string;
/** The task configuration which should be executed */
config: TaskConfiguration;
/** The optional execution context */
context?: string;
}

/**
* A {@link Task} represents the execution state of a `TaskConfiguration`.
* Implementing classes have to call the {@link Task#fireOutputLine} function
* whenever a new output occurs during the execution.
*/
@injectable()
export abstract class Task implements Disposable {

Expand All @@ -45,7 +55,11 @@ export abstract class Task implements Disposable {
this.toDispose.push(this.outputEmitter);
}

/** Terminates the task. */
/**
* Terminate this task.
*
* @returns a promise that resolves once the task has been properly terminated.
*/
abstract kill(): Promise<void>;

get onExit(): Event<TaskExitedEvent> {
Expand All @@ -64,8 +78,12 @@ export abstract class Task implements Disposable {
protected fireOutputLine(event: TaskOutputEvent): void {
this.outputEmitter.fire(event);
}

/** Returns runtime information about task. */
/**
* Retrieves the runtime information about this task.
* The runtime information computation may happen asynchronous.
*
* @returns (a promise of) the runtime information as `TaskInfo`.
*/
abstract getRuntimeInfo(): MaybePromise<TaskInfo>;

get id(): number {
Expand Down

0 comments on commit 1ad7f09

Please sign in to comment.