Skip to content

Commit

Permalink
define Task CommandOptions and move "cwd" into it
Browse files Browse the repository at this point in the history
- "cwd" (i.e., the current working directory) is currently defined directly under Task, which is inconsistent from the VS Code Task schema. In this pull request "cwd" is moved into the "options" as part of the CommandOptions.
- part of eclipse-theia#5516

Signed-off-by: elaihau <[email protected]>
  • Loading branch information
elaihau committed Jun 24, 2019
1 parent 1bce999 commit 8949f13
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 64 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Breaking changes:
- [debug] align commands with VS Code [#5102](https://github.com/theia-ide/theia/issues/5102)
- `debug.restart` renamed to `workbench.action.debug.restart`
- [preferences] renamed overridenPreferenceName to overriddenPreferenceName
- [task] `cwd`, which used to be defined directly under `Task`, is moved into `Task.options` object

## v0.7.0

Expand Down
2 changes: 1 addition & 1 deletion packages/cpp/src/browser/cpp-task-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class CppTaskProvider implements TaskContribution, TaskProvider, TaskReso
type: 'shell',
command,
args,
cwd: task.config.directory,
options: { cwd: task.config.directory }
};
return resolver.resolveTask(resolvedTask);
}
Expand Down
6 changes: 4 additions & 2 deletions packages/plugin-ext/src/api/plugin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,10 @@ export interface LanguagesContributionMain {
export interface CommandProperties {
command: string;
args?: string[];
options?: { [key: string]: any };
options?: {
cwd?: string;
[key: string]: any
};
}

export interface TaskDto {
Expand All @@ -1014,7 +1017,6 @@ export interface TaskExecutionDto {

export interface ProcessTaskDto extends TaskDto, CommandProperties {
windows?: CommandProperties;
cwd?: string;
}

export interface LanguagesExt {
Expand Down
6 changes: 2 additions & 4 deletions packages/plugin-ext/src/plugin/type-converters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ describe('Type converters:', () => {
scope: undefined,
command,
args,
cwd,
options: {},
options: { cwd },
additionalProperty
};

Expand All @@ -212,8 +211,7 @@ describe('Type converters:', () => {
scope: undefined,
command,
args,
cwd,
options: {}
options: { cwd }
};

const pluginTaskWithCommandLine: theia.Task = {
Expand Down
11 changes: 6 additions & 5 deletions packages/plugin-ext/src/plugin/type-converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ export function toTask(taskDto: TaskDto): theia.Task {
throw new Error('Task should be provided for converting');
}

const { type, label, source, scope, command, args, options, windows, cwd, ...properties } = taskDto;
const { type, label, source, scope, command, args, options, windows, ...properties } = taskDto;
const result = {} as theia.Task;
result.name = label;
result.source = source;
Expand Down Expand Up @@ -674,7 +674,6 @@ export function fromProcessExecution(execution: theia.ProcessExecution, processT

const options = execution.options;
if (options) {
processTaskDto.cwd = options.cwd;
processTaskDto.options = options;
}
return processTaskDto;
Expand All @@ -683,7 +682,6 @@ export function fromProcessExecution(execution: theia.ProcessExecution, processT
export function fromShellExecution(execution: theia.ShellExecution, processTaskDto: ProcessTaskDto): ProcessTaskDto {
const options = execution.options;
if (options) {
processTaskDto.cwd = options.cwd;
processTaskDto.options = getShellExecutionOptions(options);
}

Expand Down Expand Up @@ -720,7 +718,6 @@ export function getProcessExecution(processTaskDto: ProcessTaskDto): theia.Proce

const options = processTaskDto.options;
execution.options = options ? options : {};
execution.options.cwd = processTaskDto.cwd;

return execution;
}
Expand All @@ -730,7 +727,6 @@ export function getShellExecution(processTaskDto: ProcessTaskDto): theia.ShellEx

const options = processTaskDto.options;
execution.options = options ? options : {};
execution.options.cwd = processTaskDto.cwd;
execution.args = processTaskDto.args;

execution.command = processTaskDto.command;
Expand Down Expand Up @@ -783,6 +779,11 @@ export function getShellExecutionOptions(options: theia.ShellExecutionOptions):
result['shellArgs'] = shellArgs;
}

const cwd = options.cwd;
if (cwd) {
Object.assign(result, { cwd });
}

return result;
}

Expand Down
33 changes: 24 additions & 9 deletions packages/task/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ Each task configuration looks like this:
{
"label": "Test task - list workspace files recursively",
"type": "shell",
"cwd": "${workspaceFolder}",
"command": "ls",
"args": [
"-alR"
],
"options": {
"cwd": "${workspaceFolder}",

},
"windows": {
"command": "cmd.exe",
"args": [
Expand All @@ -29,12 +32,16 @@ Each task configuration looks like this:

*type*: determines what type of process will be used to execute the task. Can be "process" or "shell". "Shell" processes' output can be shown in Theia's frontend, in a terminal widget. If type set as "process" then task will be run without their output being shown.

*cwd*: the current working directory, in which the task's command will execute. This is the equivalent of doing a "cd" to that directory, on the command-line, before running the command. This can contain the variable *${workspaceFolder}*, which will be replaced at execution time by the path of the current workspace. If left undefined, will by default be set to workspace root.

*command*: the actual command or script to execute. The command can have no path (e.g. "ls") if it can be found in the system path. Else it can have an absolute path, in which case there is no confusion. Or it can have a relative path, in which case it will be interpreted to be relative to cwd. e.g. "./task" would be interpreted to mean a script or binary called "task", right under the workspace root directory.

*args*: a list of strings, each one being one argument to pass to the command.

*options*: the command options used when the command is executed. This is the place to provide the
- *cwd*: the current working directory, in which the task's command will execute. This is the equivalent of doing a "cd" to that directory, on the command-line, before running the command. This can contain the variable *${workspaceFolder}*, which will be replaced at execution time by the path of the current workspace. If left undefined, will by default be set to workspace root.
- *env*: the environment of the executed program or shell. If omitted the parent process' environment is used.
- *shell*: configuration of the shell when task type is `shell`, where users can specify the shell to use with *shell*, and the arguments to be passed to the shell executable to run in command mode with *args*.


*windows*: by default, *command* and *args* above are used on all platforms. However it's not always possible to express a task in the same way, both on Unix and Windows. The command and/or arguments may be different, for example. If a task needs to work on both Linux/MacOS and Windows, it can be better to have two separate process options. If *windows* is defined, it will be used instead of *command* and *args*, when a task is executed on a Windows backend.

Here is a sample tasks.json that can be used to test tasks. Just add this content under the theia source directory, in directory `.theia`:
Expand All @@ -45,13 +52,15 @@ Here is a sample tasks.json that can be used to test tasks. Just add this conten
{
"label": "[Task] short running test task (~3s)",
"type": "shell",
"cwd": "${workspaceFolder}/packages/task/src/node/test-resources/",
"command": "./task",
"args": [
"1",
"2",
"3"
],
"options": {
"cwd": "${workspaceFolder}/packages/task/src/node/test-resources/"
},
"windows": {
"command": "cmd.exe",
"args": [
Expand All @@ -64,9 +73,11 @@ Here is a sample tasks.json that can be used to test tasks. Just add this conten
{
"label": "[Task] long running test task (~300s)",
"type": "shell",
"cwd": "${workspaceFolder}/packages/task/src/node/test-resources/",
"command": "./task-long-running",
"args": [],
"options": {
"cwd": "${workspaceFolder}/packages/task/src/node/test-resources/"
},
"windows": {
"command": "cmd.exe",
"args": [
Expand All @@ -78,11 +89,13 @@ Here is a sample tasks.json that can be used to test tasks. Just add this conten
{
"label": "[Task] recursively list files from workspace root",
"type": "shell",
"cwd": "${workspaceFolder}",
"command": "ls",
"args": [
"-alR"
],
"options": {
"cwd": "${workspaceFolder}"
},
"windows": {
"command": "cmd.exe",
"args": [
Expand All @@ -95,22 +108,24 @@ Here is a sample tasks.json that can be used to test tasks. Just add this conten
{
"label": "[Task] Echo a string",
"type": "shell",
"cwd": "${workspaceFolder}",
"command": "bash",
"args": [
"-c",
"echo 1 2 3"
]
],
"options": {
"cwd": "${workspaceFolder}"
}
}
]
}
```

## Variables substitution
The variables are supported in the following properties, using `${variableName}` syntax:
- `cwd`
- `command`
- `args`
- `options.cwd`
- `windows.command`
- `windows.args`

Expand Down
16 changes: 10 additions & 6 deletions packages/task/src/browser/process/process-task-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,22 @@ export class ProcessTaskResolver implements TaskResolver {
throw new Error('Unsupported task configuration type.');
}

const options = { context: new URI(taskConfig._source).withScheme('file') };
const variableResolverOptions = { context: new URI(taskConfig._source).withScheme('file') };
const processTaskConfig = taskConfig as ProcessTaskConfiguration;
const result: ProcessTaskConfiguration = {
...processTaskConfig,
command: await this.variableResolverService.resolve(processTaskConfig.command, options),
args: processTaskConfig.args ? await this.variableResolverService.resolveArray(processTaskConfig.args, options) : undefined,
command: await this.variableResolverService.resolve(processTaskConfig.command, variableResolverOptions),
args: processTaskConfig.args ? await this.variableResolverService.resolveArray(processTaskConfig.args, variableResolverOptions) : undefined,
windows: processTaskConfig.windows ? {
command: await this.variableResolverService.resolve(processTaskConfig.windows.command, options),
args: processTaskConfig.windows.args ? await this.variableResolverService.resolveArray(processTaskConfig.windows.args, options) : undefined,
command: await this.variableResolverService.resolve(processTaskConfig.windows.command, variableResolverOptions),
args: processTaskConfig.windows.args ? await this.variableResolverService.resolveArray(processTaskConfig.windows.args, variableResolverOptions) : undefined,
options: processTaskConfig.windows.options
} : undefined,
cwd: await this.variableResolverService.resolve(processTaskConfig.cwd || '${workspaceFolder}', options)
options: {
cwd: await this.variableResolverService.resolve(processTaskConfig.options && processTaskConfig.options.cwd || '${workspaceFolder}', variableResolverOptions),
env: processTaskConfig.options && processTaskConfig.options.env,
shell: processTaskConfig.options && processTaskConfig.options.shell
}
};
return result;
}
Expand Down
39 changes: 34 additions & 5 deletions packages/task/src/browser/task-schema-updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ const taskConfigurationSchema: IJSONSchema = {
default: 'shell',
description: 'Determines what type of process will be used to execute the task. Only shell types will have output shown on the user interface'
},
cwd: {
type: 'string',
description: 'The directory in which the command will be executed'
},
command: {
type: 'string',
description: 'The actual command or script to execute'
Expand All @@ -92,9 +88,42 @@ const taskConfigurationSchema: IJSONSchema = {
type: 'string'
}
},
options: {
type: 'object',
description: 'The command options used when the command is executed',
properties: {
cwd: {
type: 'string',
description: 'The directory in which the command will be executed',
default: '${workspaceFolder}'
},
env: {
type: 'object',
description: 'The environment of the executed program or shell. If omitted the parent process\' environment is used'
},
shell: {
type: 'object',
description: 'Configuration of the shell when task type is `shell`',
properties: {
executable: {
type: 'string',
description: 'The shell to use'
},
args: {
type: 'array',
description: `The arguments to be passed to the shell executable to run in command mode
(e.g ['-c'] for bash or ['/S', '/C'] for cmd.exe)`,
items: {
type: 'string'
}
}
}
}
}
},
windows: {
type: 'object',
'description': 'Windows specific command configuration overrides command and args',
description: 'Windows specific command configuration overrides command and args',
properties: {
command: {
type: 'string',
Expand Down
43 changes: 33 additions & 10 deletions packages/task/src/common/process/task-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,42 @@ import { ApplicationError } from '@theia/core/lib/common/application-error';

export type ProcessType = 'shell' | 'process';

export interface CommandOptions {
/**
* The 'current working directory' the task will run in. Can be a uri-as-string
* or plain string path. If the cwd is meant to be somewhere under the workspace,
* one can use the variable `${workspaceFolder}`, which will be replaced by its path,
* at runtime. If not specified, defaults to the workspace root.
* ex: cwd: '${workspaceFolder}/foo'
*/
cwd?: string;

/**
* The environment of the executed program or shell. If omitted the parent process' environment is used.
*/
env?: { [key: string]: string | undefined; };

/**
* Configuration of the shell when task type is `shell`
*/
shell?: {
/**
* The shell to use.
*/
executable: string;

/**
* The arguments to be passed to the shell executable to run in command mode
* (e.g ['-c'] for bash or ['/S', '/C'] for cmd.exe).
*/
args?: string[];
};
}

export interface CommandProperties<T = string> {
readonly command: string;
readonly args?: T[];
readonly options?: object;
readonly options?: CommandOptions;
}

/** Configuration of a Task that may be run as a process or a command inside a shell. */
Expand All @@ -33,15 +65,6 @@ export interface ProcessTaskConfiguration<T = string> extends TaskConfiguration,
* Windows version of CommandProperties. Used in preference on Windows, if defined.
*/
readonly windows?: CommandProperties<T>;

/**
* The 'current working directory' the task will run in. Can be a uri-as-string
* or plain string path. If the cwd is meant to be somewhere under the workspace,
* one can use the variable `${workspaceFolder}`, which will be replaced by its path,
* at runtime. If not specified, defaults to the workspace root.
* ex: cwd: '${workspaceFolder}/foo'
*/
readonly cwd?: string;
}

export interface ProcessTaskInfo extends TaskInfo {
Expand Down
Loading

0 comments on commit 8949f13

Please sign in to comment.