-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add task extension #690
add task extension #690
Conversation
331f04f
to
165ae98
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very nice in general!!
I did a first pass but I think we need to design this a bit more.
I'll do a second pass later.
|
||
const pty = require("node-pty"); | ||
|
||
export const TerminalProcessOptions = Symbol("TerminalProcessOptions"); | ||
export interface TerminalProcessOptions { | ||
command: string, | ||
args?: string[], | ||
options?: object | ||
options?: child.SpawnOptions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct as these are the node-pty options rather than the child_process options.
this.taskWatcher.onTaskOutputEntryFound((event: ITaskOutputEntryFoundEvent) => { | ||
if (ProblemMarker.is(event.entry)) { | ||
// problem marker | ||
this.messageService.info(`Task ${event.taskId} has sent a problem marker`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService | ||
) { | ||
this.taskWatcher.onTaskOutputEntryFound((event: ITaskOutputEntryFoundEvent) => { | ||
if (ProblemMarker.is(event.entry)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we iterate on the marker times and choose a proper handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed this, since we do not yet generate markers in the backend. Will be back as part of the patch that will add parsing/handling of tasks output.
let tasks: string[]; | ||
|
||
tasks = await this.taskServer.getTasks(); | ||
return tasks; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just return await ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
|
||
protected attachTerminal(terminalId: number, taskId: number): void { | ||
const newTerminal = this.terminalWidgetFactory({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use the WidgetManager here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to avoid having the task terminal(s) be managed by the widget manager. e.g. I do not want those terminals to be saved/restored by the frontend (make no sense, I think for tasks).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should expand the widget manager to allow these features and still use it otherwise we're duplicating code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now using widget manager to create the terminal widget for tasks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened issue #776, asking about widget restoration be optional
} else { | ||
// look for command relative to cwd | ||
const resolved_command = FileUri.fsPath(new URI(cwd).resolve(command)); | ||
if (fs.existsSync(resolved_command)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto sync
// Check if task command can be found, if so return its resolved | ||
// absolute path, else returns undefined | ||
private findCommand(command: string, cwd: string): string | undefined { | ||
const systemPath = process.env.PATH; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure this is windows friendly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It depends what you mean. I think it does work to get the system path, to try to find an executable in it. However, in many cases on windows, the command, that here we confirm exists, will just be "cmd.exe" and the real execution target will be passed as a parameter. ex: cmd.exe /c test.bat . In that sense, this is not so windows-friendly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just mean I'm not sure PATH is the env var windows uses.
So you mean if need to test cmd.exe and the destination ? I think we can assume cmd.exe exists no ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can assume that cmd.exe exists. The user could in theory point towards an alternate interpreter. The destination can be a script/executable but can also be an interpreter built-in, like "DIR". So we may not find it as a file in that case, even if we look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed that's just the situation I wanted to avoid.
What if we were to try to run it, and after that if it fails try to narrow down the reason using findCommand?
That way these cases would be avoided most likely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting idea; I like it. This way we at least try to execute the command, even if we can't figure-out exactly what it's calling. If it succeeds, everything is good. If it fails, we dig down to try and see if we can figure-out why it failed, looking into locating the command, maybe in some cases its file parameter(s).
I do not think we avoid the corner cases entirely, however. There will still be cases like : "cmd.exe /c DIZ" that will be hard to pin down: did the user want the "DIR" built-in of cmd.exe and made a typo? Or was he trying to execute a DIZ.bat batch file in cwd?
|
||
const separator = isWindows ? ";" : ":"; | ||
|
||
// just a command without path? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would just be simpler to try it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True. The reason for findCommand() is try to figure-out if the command/script, we're about to try executing, can be found. We could just skip ahead and try to execute it; if it's then found and executed successfully, then no problem. But if it's not found or not successful, it can be difficult to distinguish what happened:
- the command was found and run, but exited with an error status (rc !=0)
- the command was not found (rc != 0)
So, in findCommand() we try to determine if the command/script seems to exist, so that we can more correctly assume that any error is a result of its execution, not of it not having been found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I wish RawProcess/TerminalProcess would take care of that, I know I can know it for RawProcess but I don't think it's possible now for the Terminal.
So OK for now and we'll try to improve that upstream
packages/task/src/node/task.ts
Outdated
export class Task { | ||
protected taskId: number; | ||
protected taskProcess: Process; | ||
// linter: string | undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
packages/task/src/node/task.ts
Outdated
this.taskId = this.taskManager.register(this); | ||
this.taskProcess = process; | ||
|
||
this.taskProcess.onExit(event => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You also need to add ProcessManager.delete(this.taskProcess)
And cleanup the onExit listener.
Maybe this could be doner better in general we need to think about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done both
Could we reuse the format from vs code? (https://code.visualstudio.com/docs/editor/tasks-appendix#_schema-for-tasksjson) It would make it easier for people to switch between vs code and cloud based theia workspaces. |
@svenefftinge Possibly. We do not have, ATM as rich a feature-set as vs code does, w-r to tasks, matchers, etc. So just re-using their format "as-is" might give a false sense of hope that the features will work, and work the same way. But we could try to be more similar, when it makes sense. e.g. ErrorMatcher vs ProblemMatcher. WDYT? |
As close as possible, doesn't really help with the reuse. But can't the |
The current design is based on the assumptions of a single workspace and a fixed storage for user settings. As discussed in other contexts, the TaskConfiguration should be in the frontend based on user-storage service (user level) and file system watch (workspace level). |
b2efb1d
to
fa59126
Compare
3811f8a
to
560aa68
Compare
In this new version I moved the handling of task configuration files to the frontend. The backend server is now a singleton, and it supports multiple clients. All clients that connect are remembered and task-related events are broadcasted to all clients, and includes a context field that is given by the client, when it calls run() . Currently the client uses its current WS root URI string as context. It filters received events and only show them to the user when the event's context matches their own. This way multiple clients, using a same WS simultaneously, can each show their respective users, e.g. that a specific task has just been started. The user(s) that did not start the task in their client will then have the option of "attaching" to the task, opening a terminal to see the task's output so far, going back to the beginning, if it stays within reasonable limits, and see new outputs as they happen. I have not yet added the user-level configuration; that can be done in a separate issue. TODO now:
TODO later:
|
560aa68
to
a402b12
Compare
packages/task/src/browser/index.ts
Outdated
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
*/ | ||
|
||
export * from './task-frontend-module'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be exported. is it needed anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed - removed.
|
||
import { inject, injectable } from "inversify"; | ||
import { TaskService } from './task-service'; | ||
import { ITaskInfo } from '../common/task-protocol'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The I
prefix is now against the code guidelines... in favor of noprefix and Impl suffix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct - Renamed all I*
packages/task/package-lock.json
Outdated
@@ -0,0 +1,17 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not happen... unless there's 2 conflicting versions.
I deleted that file, redid a yarn and only got a modified yarn.lock
So this file should be removed from git.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct - the dependency in there is not longer used. File removed.
if (this.task.processId) { | ||
// reset focus on the previously active element. | ||
this.activeElement.focus(); | ||
// this.taskService.run(this.taskLabel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left over ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed left-over line
})); | ||
} | ||
|
||
init(client: TaskConfigurationClient) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be setClient
? like the others
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed method
resolve(command); | ||
return; | ||
} else { | ||
const uri = new URI(cwd).resolve(command); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I get this it's absolute, and it doesn't exist but we will check for cwd/absolutepath ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, this looks like dead code; if a command with an absolute path is not found, there's not much more we can do. Removed.
} | ||
} else { | ||
// look for command relative to cwd | ||
const resolved_command = FileUri.fsPath(new URI(cwd).resolve(command)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About CWD should it default to workspaceRoot somewhere? I don't think it makes sense to use the process.cwd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the refactorings to support multiple clients, the Task backend server has become stateless, with regards to the workspace being used (it used to be that each client would get it's own instance of the Task server, that would know what the WS Root was). The backend doesn't know which workspace(s) are being used.
Instead, each task configuration defines what "CWD" should be used by that task. The F-E will replace the symbolic value "$workspace" by its value, if found in the task configuration's cwd. In the end, that same CWD value is used to create the process, used by the task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update: now cwd defaults to the WS Root, unless otherwise defined in the task configuration (set by frontend).
return; | ||
} else { | ||
// should cover Unix and Windows cases | ||
const separator = /;|:/; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:
is valid as a linux file we should check for isWindows and select 1 separator only.
You can use: https://nodejs.org/api/path.html#path_path_delimiter
➜ ~ touch ab:cd
➜ ~ ls -la ./ab:cd
-rw-r--r-- 1 eantotr eusers 0 Dec 4 14:22 ./ab:cd
➜ ~ touch abc;cd
➜ ~ ls -l ab*
-rw-r--r-- 1 eantotr eusers 0 Dec 4 14:23 abc
-rw-r--r-- 1 eantotr eusers 0 Dec 4 14:22 ab:cd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I didn't know about path.delimiter. Since we get that value from node, I think it already takes into account which platform we are on.
Done (except handling the case where there is a ":" used within a directory in the system path - Sorry, if you do that, you deserve for your executable not to be found ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
except handling the case where there is a ":" used within a directory in the system path - Sorry, if you do that, you deserve for your executable not to be found
That won't happen since I guess on windows you can't create a file or directory with :
like you can't do a file /dir with ;
in linux ?
echo tasking... %%x | ||
@REM sleep for ~1s | ||
@REM see: https://stackoverflow.com/questions/735285/how-to-wait-in-a-batch-script | ||
ping 192.0.2.2 -n 1 -w 1000> nul |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
weird IP why not 127.0.0.1 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The answer is in the link above: basically this is garanteed, by definition, to be an address that can't be assigned. So we are certain that no one will answer and that we will spend the "1000" ms waiting. So basically a poor man's "sleep". If we used 127.0.0.1, it would answer immediately and not wait for 1000ms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right OK!
packages/task/todo.txt
Outdated
@@ -0,0 +1,22 @@ | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove leave in github
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
packages/task/package.json
Outdated
"@theia/process": "^0.2.3", | ||
"@theia/terminal": "^0.2.3", | ||
"@theia/workspace": "^0.2.3", | ||
"require-strip-json-comments": "^1.0.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought jsonc-parser
ended up being used by modifying the webpack config file? If that is also used it's fine though.
Also if you really use jsonc-parser
, shouldn't that dependency be specifically mentionned in the task package.json?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@epatpol I think you were looking at the previous version? This is no longer in there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if you really use jsonc-parser, shouldn't that dependency be specifically mentionned in the task package.json?
It's added in the latest version
.theia/tasks.json
Outdated
@@ -0,0 +1,73 @@ | |||
{ | |||
// Some sample Theia development tasks | |||
"tasks": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like having a sample tasks.json but maybe the sample config should be in the package README? Or the supplied sample tasks should be commented out? I'm not sure master should have default tasks when starting theia. Maybe having a package README which would describe a sample task and go in details about every attributes? Or simply a link to vscode's page on the task.json file attributes if they're very similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestions. I removed the example tasks.json and added a README, in which I list the example tasks.
008cdc3
to
923bfba
Compare
.theia/tasks.json
Outdated
// comment | ||
"tasks": [ | ||
{ | ||
"label": "workspace: failing task", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these test tasks? Shouldn't they go into some test-resource forlder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, they are example / manual test tasks. At Patrick's suggestion, I deleted that file and instead added the task configurations as examples, to the README.md for the extension.
protected taskService: TaskService | ||
) { | ||
super(); | ||
this.activeElement = window.document.activeElement as HTMLElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already done generally in https://github.com/theia-ide/theia/blob/87825f441613cbd5caf145a6b80d8a358d3995da/packages/monaco/src/browser/monaco-quick-open-service.ts#L45
Didn't it work for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem to make much difference, either way, in this case. If we do proceed to create or attach to a task, we may not want to restore the previous focus anyway, and focus on the new terminal. Removed.
return false; | ||
} | ||
// reset focus on the previously active element. | ||
this.activeElement.focus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
protected taskService: TaskService | ||
) { | ||
super(); | ||
this.activeElement = window.document.activeElement as HTMLElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed too
} | ||
if (this.task.processId) { | ||
// reset focus on the previously active element. | ||
this.activeElement.focus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dito
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed too
} | ||
|
||
run(task: TaskOptions, ctx?: string): Promise<TaskInfo> { | ||
return this.doRun(task, ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why delegate to doRun
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No good reason any more -> removed run(), renamed doRun() to run().
} | ||
|
||
protected doRun(options: TaskOptions, ctx?: string): Promise<TaskInfo> { | ||
return new Promise<TaskInfo>(async (resolve, reject) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary outer promise, async/await?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactored to use async/await
// because the executable or script was not found, or if it was found, ran, and exited | ||
// unsuccessfully. So here we look to see if it seems we can find a file of that name that | ||
// is likely to be the one we want, before attemting to execute it. | ||
this.findCommand(command, cwd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we do findCommand
? Aren't the error message from the process factories good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, not so much. It's difficult to distinguish between the cases where a script or binary is found and executed, with an abnormal exit, versus the script/binary not being found at all (I think because of limitations in node-pty). Maybe we should enhance node-pty?
context: ctx | ||
}); | ||
|
||
const toDispose = new DisposableCollection(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like there is always only one disposable in the collection so we could remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
processId: (options.processType === 'raw') ? proc.id : undefined, | ||
command: cmd, | ||
label: options.label, | ||
ctx: ctx === undefined ? '' : ctx |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we extract the translation to a method and use it also from here https://github.com/theia-ide/theia/pull/690/files#diff-fccfd5a001011db19d656ecd3d66d03dR67
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea - done
}); | ||
} | ||
|
||
protected hasWatchedFileChanged(changes: FileChange[]): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a marker for @akosyakov #942
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should not use the watcher server in the frontend, it is the impl details of FileSystemWatcher
, the watcher takes care of servers and reconnection to them if a connection is down as well as preserving watching.
I am working on PR which will add an optional callback to FileSystemWatcher.watch(uri): Promise<Disposable>
that you can pass it to avoid dispatching changes to other clients.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akosyakov ok, I will update this code accordingly, when your PR is ready.
9208917
to
3946915
Compare
7096689
to
87592a3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just nits, OK with the changes
export class TaskConfigurations implements Disposable { | ||
|
||
protected readonly toDispose = new DisposableCollection(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
protected readonly toDispose = new DisposableCollection(); | ||
|
||
protected tasksMap = new Map<string, TaskOptions>(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
} | ||
} else { | ||
this.logger.info(`Config file tasks.json does not exist under ${rootUri}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to warn ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be normal that the user doesn't have one...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, tasks.json presence is optional. done
|
||
if (await this.fileSystem.exists(cfgFile)) { | ||
return cfgFile; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing else { return Promise.resolve(undefined) }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following previous changes, this is no longer applicable (method no longer async now that it only computes the potential task config file URI)
} | ||
} | ||
|
||
protected async getConfigFile(rootDir: string): Promise<string | undefined> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would separate the existance from getConfigFile like:
getConfigFileURI
then in code inline this.filesystem.exits(getConfigFileURI(rootDir))
but just a nit.. do as you want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not - done.
* @param command command name to look-for | ||
* @param cwd current working directory | ||
*/ | ||
private async findCommand(command: string, cwd: string): Promise<string | undefined> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected ?
@injectable() | ||
export class QuickOpenTask implements QuickOpenModel { | ||
|
||
private items: QuickOpenItem[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
} | ||
} | ||
|
||
private filterDuplicates(tasks: TaskOptions[]): TaskOptions[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
widget.start(terminalId); | ||
} | ||
|
||
private isEventForThisClient(context: string | undefined): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. BTW, I noticed in general that we tend not to explicitly mark methods as "public". I was doing it in this class, so I removed these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK yes that's still a gray zone to me.
}; | ||
} | ||
|
||
private onTaskCreatedEmitter = new Emitter<TaskInfo>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
87592a3
to
22972ca
Compare
@hexa00 Thanks for the second review pass. Let's see if the unit tests still pass! |
Git issue during Windows tests again - will slightly modify PR and push again, to trigger new tests |
22972ca
to
cf3e405
Compare
almost this time - electron test failure |
f9268df
to
f0aaa2f
Compare
ok, the Windows tests finally went went through. @svenefftinge I plan to rebase this on the latest master and merge probably on Monday morning, Montreal time. Please let me know if you have objections. |
f0aaa2f
to
c2143cd
Compare
This extension provides the means to execute scripts or executables, from a frontend client, in the backend. Tasks life cycle events are send from the backend to the frontend clients, whenever a task is created or terminates. A task client can ask the backend for the list of tasks that are currently running. We support having multiple frontend task clients that are using the same backend task server. Each client uses its workspace root as context parameter, in all its communications with the backend. Whenever the backend sends notifications to its clients, the original client context is sent along. It's then up-to the clients to determine if they are interested in the event, given its context, and show it to the user or not. This mechanism makes it possible for multiple clients, opened on the same workspace, to all get the notifications related to all tasks that execute from that workspace. At the same time, clients can ignore tasks that are run from another workspace. Fixes #686 Signed-off-by: Marc Dumais <[email protected]>
c2143cd
to
d986b8c
Compare
) { | ||
this.toDispose.push(watcherServer); | ||
|
||
watcherServer.setClient({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marcdumais it is bogus, there is only one FileSystemWatcherServer
which is used in FileSystemWatcher
. With this change, either FileSystemWatcher
or TaskConfiguration
won't receive changes.
Fixes #686
Signed-off-by: Marc Dumais [email protected]