Skip to content

Commit aeeaf88

Browse files
authored
Merge pull request #68 from badsyntax/tasks-enhancements
Add feature to run task with custom args
2 parents 9d3b101 + af3249c commit aeeaf88

File tree

4 files changed

+109
-60
lines changed

4 files changed

+109
-60
lines changed

package.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@
8686
"dark": "resources/dark/continue.svg"
8787
}
8888
},
89+
{
90+
"command": "gradle.runTaskWithArgs",
91+
"title": "Run Task With Args"
92+
},
8993
{
9094
"command": "gradle.stopTask",
9195
"title": "Stop Task",
@@ -104,15 +108,15 @@
104108
},
105109
{
106110
"command": "gradle.explorerFlat",
107-
"title": "Show flat list",
111+
"title": "Show Flat List",
108112
"icon": {
109113
"light": "resources/light/list-flat.svg",
110114
"dark": "resources/dark/list-flat.svg"
111115
}
112116
},
113117
{
114118
"command": "gradle.explorerTree",
115-
"title": "Show tree",
119+
"title": "Show Tree",
116120
"icon": {
117121
"light": "resources/light/list-tree.svg",
118122
"dark": "resources/dark/list-tree.svg"
@@ -129,6 +133,10 @@
129133
"command": "gradle.runTask",
130134
"when": "false"
131135
},
136+
{
137+
"command": "gradle.runTaskWithArgs",
138+
"when": "false"
139+
},
132140
{
133141
"command": "gradle.stopTask",
134142
"when": "false"
@@ -164,6 +172,10 @@
164172
"command": "gradle.runTask",
165173
"when": "view == gradle-tree-view && viewItem == task"
166174
},
175+
{
176+
"command": "gradle.runTaskWithArgs",
177+
"when": "view == gradle-tree-view && viewItem == task"
178+
},
167179
{
168180
"command": "gradle.runTask",
169181
"when": "view == gradle-tree-view && viewItem == task",

src/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ function registerCommands(
9595
treeDataProvider
9696
)
9797
);
98+
context.subscriptions.push(
99+
vscode.commands.registerCommand(
100+
'gradle.runTaskWithArgs',
101+
treeDataProvider.runTaskWithArgs,
102+
treeDataProvider
103+
)
104+
);
98105
context.subscriptions.push(
99106
vscode.commands.registerCommand(
100107
'gradle.stopTask',
@@ -132,6 +139,7 @@ function registerCommands(
132139

133140
export interface ExtensionApi {
134141
outputChannel: vscode.OutputChannel;
142+
treeDataProvider: GradleTasksTreeDataProvider | undefined;
135143
}
136144

137145
export async function activate(
@@ -158,7 +166,7 @@ export async function activate(
158166
);
159167
}
160168
}
161-
return { outputChannel };
169+
return { outputChannel, treeDataProvider };
162170
}
163171

164172
export function deactivate(): void {}

src/gradleView.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
// GradleTaskDefinition,
66
isWorkspaceFolder,
77
invalidateTasksCache,
8-
enableTaskDetection
8+
enableTaskDetection,
9+
cloneTask
910
} from './tasks';
1011

1112
function getTaskExecution(task: vscode.Task) {
@@ -146,11 +147,7 @@ class NoTasksTreeItem extends vscode.TreeItem {
146147
export class GradleTasksTreeDataProvider
147148
implements vscode.TreeDataProvider<vscode.TreeItem> {
148149
private taskItemsPromise: Thenable<vscode.Task[]> = Promise.resolve([]);
149-
private taskTree:
150-
| WorkspaceTreeItem[]
151-
// | GradleBuildFileTreeItem[]
152-
| NoTasksTreeItem[]
153-
| null = null;
150+
private taskTree: WorkspaceTreeItem[] | NoTasksTreeItem[] | null = null;
154151
private _onDidChangeTreeData: vscode.EventEmitter<vscode.TreeItem | null> = new vscode.EventEmitter<vscode.TreeItem | null>();
155152
readonly onDidChangeTreeData: vscode.Event<vscode.TreeItem | null> = this
156153
._onDidChangeTreeData.event;
@@ -188,6 +185,21 @@ export class GradleTasksTreeDataProvider
188185
}
189186
}
190187

188+
async runTaskWithArgs(taskItem: GradleTaskTreeItem) {
189+
if (taskItem && taskItem.task) {
190+
const args = await vscode.window.showInputBox({
191+
placeHolder: 'For example: --all',
192+
ignoreFocusOut: true
193+
});
194+
if (args !== undefined) {
195+
const task = await cloneTask(taskItem!.task, args.split(' '));
196+
if (task) {
197+
vscode.tasks.executeTask(task);
198+
}
199+
}
200+
}
201+
}
202+
191203
stopTask(taskItem: GradleTaskTreeItem) {
192204
if (taskItem && taskItem.task) {
193205
const execution = getTaskExecution(taskItem.task);
@@ -268,7 +280,7 @@ export class GradleTasksTreeDataProvider
268280

269281
private buildTaskTree(
270282
tasks: vscode.Task[]
271-
): WorkspaceTreeItem[] /* | GradleBuildFileTreeItem[]*/ | NoTasksTreeItem[] {
283+
): WorkspaceTreeItem[] | NoTasksTreeItem[] {
272284
const workspaceTreeItems: Map<String, WorkspaceTreeItem> = new Map();
273285
const projectTreeItems: Map<String, ProjectTreeItem> = new Map();
274286
const groupTreeItems: Map<String, GroupTreeItem> = new Map();

src/tasks.ts

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ export interface GradleTaskDefinition extends vscode.TaskDefinition {
3333

3434
let autoDetectOverride: boolean = false;
3535
let cachedTasks: Promise<vscode.Task[]> | undefined;
36-
let refreshProcess: cp.ChildProcessWithoutNullStreams | undefined;
36+
let gradleTasksProcess: cp.ChildProcessWithoutNullStreams | undefined;
3737

3838
export function enableTaskDetection() {
3939
autoDetectOverride = true;
4040
}
4141

4242
export function killRefreshProcess() {
43-
if (refreshProcess) {
44-
refreshProcess.kill();
43+
if (gradleTasksProcess) {
44+
gradleTasksProcess.kill();
4545
}
4646
}
4747

@@ -133,23 +133,22 @@ export class GradleTaskProvider implements vscode.TaskProvider {
133133
return emptyTasks;
134134
}
135135

136-
const tasks: vscode.Task[] = [];
137-
138-
for (const gradleProject of gradleProjects) {
139-
for (const gradleTask of gradleProject.tasks) {
140-
tasks.push(
141-
await createTask(
142-
gradleTask,
143-
folder!,
144-
command,
145-
rootProject.name,
146-
vscode.Uri.file(gradleProject.buildFile)
136+
return gradleProjects.reduce(
137+
(allTasks: vscode.Task[], gradleProject: GradleProject) => {
138+
return allTasks.concat(
139+
gradleProject.tasks.map(gradleTask =>
140+
createTaskFromGradleTask(
141+
gradleTask,
142+
folder!,
143+
command,
144+
rootProject.name,
145+
vscode.Uri.file(gradleProject.buildFile)
146+
)
147147
)
148148
);
149-
}
150-
}
151-
152-
return tasks;
149+
},
150+
[]
151+
);
153152
}
154153

155154
private async getProjectsFromGradle(
@@ -164,7 +163,7 @@ export class GradleTaskProvider implements vscode.TaskProvider {
164163
const command = getTasksScriptCommand();
165164
const cwd = this.context.asAbsolutePath('lib');
166165
const args = [folder.uri.fsPath, tempFile];
167-
return spawn(command, args, { cwd }, this.outputChannel)
166+
return executeGradleTasksCommand(command, args, { cwd }, this.outputChannel)
168167
.then(() => fs.promises.readFile(tempFile, 'utf8'))
169168
.finally(async () => {
170169
this.statusBarItem.hide();
@@ -221,35 +220,21 @@ export function getTasksScriptCommand(): string {
221220
}
222221
}
223222

224-
export async function createTask(
225-
gradleTask: GradleTask,
223+
export function createTaskFromDefinition(
224+
definition: vscode.TaskDefinition,
226225
folder: vscode.WorkspaceFolder,
227-
command: string,
228-
rootProject: string,
229-
buildFile: vscode.Uri
230-
): Promise<vscode.Task> {
231-
function getCommandLine(task: string): string {
232-
return `"${command}" ${task}`;
233-
}
234-
235-
const friendlyTaskName = gradleTask.path.replace(/^:/, '');
236-
const definition: GradleTaskDefinition = {
237-
type: 'gradle',
238-
script: friendlyTaskName,
239-
description: gradleTask.description,
240-
group: (gradleTask.group || 'other').toLowerCase(),
241-
project: gradleTask.project,
242-
buildFile: buildFile.fsPath,
243-
rootProject
244-
};
226+
cmd: string,
227+
args: string[] = []
228+
) {
229+
const crossShellCmd = `"${cmd}"`;
245230
const cwd = folder.uri.fsPath;
246-
const cmd = getCommandLine(definition.script);
231+
const allArgs = [definition.script, ...args];
247232
const task = new vscode.Task(
248233
definition,
249234
folder,
250235
definition.script,
251236
'gradle',
252-
new vscode.ShellExecution(cmd, { cwd }),
237+
new vscode.ShellExecution(crossShellCmd, allArgs, { cwd }),
253238
['$gradle']
254239
);
255240
task.presentationOptions = {
@@ -260,6 +245,39 @@ export async function createTask(
260245
return task;
261246
}
262247

248+
export function createTaskFromGradleTask(
249+
gradleTask: GradleTask,
250+
folder: vscode.WorkspaceFolder,
251+
command: string,
252+
rootProject: string,
253+
buildFile: vscode.Uri,
254+
shellArgs: string[] = []
255+
): vscode.Task {
256+
const friendlyTaskName = gradleTask.path.replace(/^:/, '');
257+
const definition: GradleTaskDefinition = {
258+
type: 'gradle',
259+
script: friendlyTaskName,
260+
description: gradleTask.description,
261+
group: (gradleTask.group || 'other').toLowerCase(),
262+
project: gradleTask.project,
263+
buildFile: buildFile.fsPath,
264+
rootProject
265+
};
266+
return createTaskFromDefinition(definition, folder, command, shellArgs);
267+
}
268+
269+
export async function cloneTask(
270+
task: vscode.Task,
271+
args: string[] = []
272+
): Promise<vscode.Task | undefined> {
273+
const folder = task.scope as vscode.WorkspaceFolder;
274+
const command = await getGradleWrapperCommandFromPath(folder.uri.fsPath);
275+
if (!command) {
276+
return undefined;
277+
}
278+
return createTaskFromDefinition(task.definition, folder, command, args);
279+
}
280+
263281
export async function hasGradleProject(): Promise<boolean> {
264282
const folders = vscode.workspace.workspaceFolders;
265283
if (!folders) {
@@ -296,34 +314,33 @@ export function parseGradleProjects(buffer: Buffer | string): GradleProject[] {
296314
function debugCommand(
297315
command: string,
298316
args: ReadonlyArray<string>,
299-
options: cp.SpawnOptionsWithoutStdio,
300317
outputChannel: vscode.OutputChannel
301318
) {
302319
const message = `Executing: ${command} ${args.join(' ')}`;
303320
outputChannel.appendLine(message);
304321
}
305322

306-
export function spawn(
323+
export function executeGradleTasksCommand(
307324
command: string,
308325
args: ReadonlyArray<string> = [],
309326
options: cp.SpawnOptionsWithoutStdio = {},
310327
outputChannel: vscode.OutputChannel
311328
): Promise<string> {
312-
debugCommand(command, args, options, outputChannel);
329+
debugCommand(command, args, outputChannel);
313330
return new Promise((resolve, reject) => {
314-
refreshProcess = cp.spawn(command, args, options);
315-
refreshProcess.stdout.on('data', (buffer: Buffer) =>
331+
gradleTasksProcess = cp.spawn(command, args, options);
332+
gradleTasksProcess.stdout.on('data', (buffer: Buffer) =>
316333
outputChannel.append(buffer.toString())
317334
);
318-
refreshProcess.stderr.on('data', (buffer: Buffer) =>
335+
gradleTasksProcess.stderr.on('data', (buffer: Buffer) =>
319336
outputChannel.append(buffer.toString())
320337
);
321-
refreshProcess.on('error', reject);
322-
refreshProcess.on('exit', (code: number) => {
338+
gradleTasksProcess.on('error', reject);
339+
gradleTasksProcess.on('exit', (code: number) => {
323340
if (code === 0) {
324341
resolve();
325342
} else {
326-
reject();
343+
reject(new Error(`Process exited with code ${code}`));
327344
}
328345
});
329346
});

0 commit comments

Comments
 (0)