deploy: current vibn theia state
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled

Made-with: Cursor
This commit is contained in:
2026-02-27 12:01:08 -08:00
commit 8bb5110148
3782 changed files with 640947 additions and 0 deletions

View File

@@ -0,0 +1,265 @@
// *****************************************************************************
// Copyright (C) 2017 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { inject, injectable, named } from '@theia/core/shared/inversify';
import { Disposable, DisposableCollection, ILogger } from '@theia/core/lib/common/';
import {
TaskClient,
TaskExitedEvent,
TaskInfo,
TaskServer,
TaskConfiguration,
TaskOutputProcessedEvent,
RunTaskOption,
BackgroundTaskEndedEvent
} from '../common';
import { TaskManager } from './task-manager';
import { TaskRunnerRegistry } from './task-runner';
import { Task } from './task';
import { ProcessTask } from './process/process-task';
import { ProblemCollector } from './task-problem-collector';
import { CustomTask } from './custom/custom-task';
@injectable()
export class TaskServerImpl implements TaskServer, Disposable {
/** Task clients, to send notifications-to. */
protected clients: TaskClient[] = [];
/** Map of task id and task disposable */
protected readonly toDispose = new Map<number, DisposableCollection>();
/** Map of task id and task background status. */
// Currently there is only one property ('isActive'), but in the future we may want to store more properties
protected readonly backgroundTaskStatusMap = new Map<number, { 'isActive': boolean }>();
@inject(ILogger) @named('task')
protected readonly logger: ILogger;
@inject(TaskManager)
protected readonly taskManager: TaskManager;
@inject(TaskRunnerRegistry)
protected readonly runnerRegistry: TaskRunnerRegistry;
/** task context - {task id - problem collector} */
private problemCollectors: Map<string, Map<number, ProblemCollector>> = new Map();
dispose(): void {
for (const toDispose of this.toDispose.values()) {
toDispose.dispose();
}
this.toDispose.clear();
this.backgroundTaskStatusMap.clear();
}
protected disposeByTaskId(taskId: number): void {
if (this.toDispose.has(taskId)) {
this.toDispose.get(taskId)!.dispose();
this.toDispose.delete(taskId);
}
if (this.backgroundTaskStatusMap.has(taskId)) {
this.backgroundTaskStatusMap.delete(taskId);
}
}
async getTasks(context?: string): Promise<TaskInfo[]> {
const taskInfo: TaskInfo[] = [];
const tasks = this.taskManager.getTasks(context);
if (tasks !== undefined) {
for (const task of tasks) {
taskInfo.push(await task.getRuntimeInfo());
}
}
this.logger.debug(`getTasks(): about to return task information for ${taskInfo.length} tasks`);
return Promise.resolve(taskInfo);
}
async run(taskConfiguration: TaskConfiguration, ctx?: string, option?: RunTaskOption): Promise<TaskInfo> {
const runner = taskConfiguration.executionType ?
this.runnerRegistry.getRunner(taskConfiguration.type, taskConfiguration.executionType) :
this.runnerRegistry.getRunner(taskConfiguration.type);
const task = await runner.run(taskConfiguration, ctx);
if (!this.toDispose.has(task.id)) {
this.toDispose.set(task.id, new DisposableCollection());
}
if (taskConfiguration.isBackground && !this.backgroundTaskStatusMap.has(task.id)) {
this.backgroundTaskStatusMap.set(task.id, { 'isActive': false });
}
this.toDispose.get(task.id)!.push(
task.onExit(event => {
this.taskManager.delete(task);
this.fireTaskExitedEvent(event, task);
this.removedCachedProblemCollector(event.ctx || '', event.taskId);
this.disposeByTaskId(event.taskId);
})
);
const resolvedMatchers = option && option.customization ? option.customization.problemMatcher || [] : [];
if (resolvedMatchers.length > 0) {
this.toDispose.get(task.id)!.push(
task.onOutput(event => {
let collector: ProblemCollector | undefined = this.getCachedProblemCollector(event.ctx || '', event.taskId);
if (!collector) {
collector = new ProblemCollector(resolvedMatchers);
this.cacheProblemCollector(event.ctx || '', event.taskId, collector);
}
const problems = collector.processLine(event.line);
if (problems.length > 0) {
this.fireTaskOutputProcessedEvent({
taskId: event.taskId,
config: taskConfiguration,
ctx: event.ctx,
problems
});
}
if (taskConfiguration.isBackground) {
const backgroundTaskStatus = this.backgroundTaskStatusMap.get(event.taskId)!;
if (!backgroundTaskStatus.isActive) {
// Get the 'activeOnStart' value of the problem matcher 'background' property
const activeOnStart = collector.isTaskActiveOnStart();
if (activeOnStart) {
backgroundTaskStatus.isActive = true;
} else {
const isBeginsPatternMatch = collector.matchBeginMatcher(event.line);
if (isBeginsPatternMatch) {
backgroundTaskStatus.isActive = true;
}
}
}
if (backgroundTaskStatus.isActive) {
const isEndsPatternMatch = collector.matchEndMatcher(event.line);
// Mark ends pattern as matches, only after begins pattern matches
if (isEndsPatternMatch) {
this.fireBackgroundTaskEndedEvent({
taskId: event.taskId,
ctx: event.ctx
});
}
}
}
})
);
}
this.toDispose.get(task.id)!.push(task);
const taskInfo = await task.getRuntimeInfo();
this.fireTaskCreatedEvent(taskInfo);
return taskInfo;
}
async getRegisteredTaskTypes(): Promise<string[]> {
return this.runnerRegistry.getRunnerTypes();
}
async customExecutionComplete(id: number, exitCode: number | undefined): Promise<void> {
const task = this.taskManager.get(id) as CustomTask;
await task.callbackTaskComplete(exitCode);
}
protected fireTaskExitedEvent(event: TaskExitedEvent, task?: Task): void {
this.logger.debug(log => log('task has exited:', event));
if (task instanceof ProcessTask) {
this.clients.forEach(client => {
client.onDidEndTaskProcess(event);
});
}
this.clients.forEach(client => {
client.onTaskExit(event);
});
}
protected fireTaskCreatedEvent(event: TaskInfo, task?: Task): void {
this.logger.debug(log => log('task created:', event));
this.clients.forEach(client => {
client.onTaskCreated(event);
});
if (task && task instanceof ProcessTask) {
this.clients.forEach(client => {
client.onDidStartTaskProcess(event);
});
}
}
protected fireTaskOutputProcessedEvent(event: TaskOutputProcessedEvent): void {
this.clients.forEach(client => client.onDidProcessTaskOutput(event));
}
protected fireBackgroundTaskEndedEvent(event: BackgroundTaskEndedEvent): void {
this.clients.forEach(client => client.onBackgroundTaskEnded(event));
}
/** Kill task for a given id. Rejects if task is not found */
async kill(id: number): Promise<void> {
const taskToKill = this.taskManager.get(id);
if (taskToKill !== undefined) {
this.logger.info(`Killing task id ${id}`);
return taskToKill.kill();
} else {
this.logger.info(`Could not find task to kill, task id ${id}. Already terminated?`);
return Promise.reject(new Error(`Could not find task to kill, task id ${id}. Already terminated?`));
}
}
/** Adds a client to this server */
setClient(client: TaskClient): void {
this.logger.debug('a client has connected - adding it to the list:');
this.clients.push(client);
}
/** Removes a client, from this server */
disconnectClient(client: TaskClient): void {
this.logger.debug('a client has disconnected - removed from list:');
const idx = this.clients.indexOf(client);
if (idx > -1) {
this.clients.splice(idx, 1);
}
}
private getCachedProblemCollector(ctx: string, taskId: number): ProblemCollector | undefined {
if (this.problemCollectors.has(ctx)) {
return this.problemCollectors.get(ctx)!.get(taskId);
}
}
private cacheProblemCollector(ctx: string, taskId: number, problemCollector: ProblemCollector): void {
if (this.problemCollectors.has(ctx)) {
if (!this.problemCollectors.get(ctx)!.has(taskId)) {
this.problemCollectors.get(ctx)!.set(taskId, problemCollector);
}
} else {
const forNewContext = new Map<number, ProblemCollector>();
forNewContext.set(taskId, problemCollector);
this.problemCollectors.set(ctx, forNewContext);
}
}
private removedCachedProblemCollector(ctx: string, taskId: number): void {
if (this.problemCollectors.has(ctx) && this.problemCollectors.get(ctx)!.has(taskId)) {
this.problemCollectors.get(ctx)!.delete(taskId);
}
}
}