Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/cakeMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function activate(context: vscode.ExtensionContext): void {
// Register the debug command.
context.subscriptions.push(
vscode.commands.registerCommand('cake.debug', async () => {
installCakeDebugCommand();
installCakeDebugCommand(context);
})
);
// Register the build file command.
Expand Down Expand Up @@ -211,7 +211,8 @@ function _registerCodeLens(
installCakeRunTaskCommand(
taskName,
fileName,
getExtensionSettings()
getExtensionSettings(),
context
);
}
)
Expand All @@ -232,7 +233,8 @@ function _registerCodeLens(
installCakeDebugTaskCommand(
taskName,
fileName,
getExtensionSettings()
getExtensionSettings(),
context
);
}
)
Expand Down
7 changes: 4 additions & 3 deletions src/codeLens/cakeDebugTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import {
window,
debug,
workspace,
DebugConfiguration
DebugConfiguration,
ExtensionContext
} from 'vscode';
import { ensureNotDirty, installCakeToolIfNeeded } from './shared';
import { getPlatformSettingsValue, ICodeLensDebugTaskSettings, IExtensionSettings } from '../extensionSettings';

export class CakeDebugTask {
constructor() {}
constructor(private context: ExtensionContext) {}

private _getDebuggerConfig(
taskName: string,
Expand Down Expand Up @@ -54,7 +55,7 @@ export class CakeDebugTask {
}

await ensureNotDirty(fileName);
await installCakeToolIfNeeded(settings);
await installCakeToolIfNeeded(settings, this.context);

const workspaceFolder = workspace.workspaceFolders[0];
const debuggerConfig = await this._getDebuggerConfig(taskName, fileName, debugConfig);
Expand Down
6 changes: 4 additions & 2 deletions src/codeLens/cakeDebugTaskCommand.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { ExtensionContext } from 'vscode';
import { IExtensionSettings } from '../extensionSettings';
import { CakeDebugTask } from './cakeDebugTask';

export async function installCakeDebugTaskCommand(
taskName: string,
fileName: string,
debugConfig: IExtensionSettings
debugConfig: IExtensionSettings,
context: ExtensionContext
) {
const debugTask = new CakeDebugTask();
const debugTask = new CakeDebugTask(context);
debugTask.debug(taskName, fileName, debugConfig);
}
6 changes: 4 additions & 2 deletions src/codeLens/cakeRunTaskCommand.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { ExtensionContext } from 'vscode';
import { getPlatformSettingsValue, IExtensionSettings } from '../extensionSettings';
import { TerminalExecutor } from '../shared/utils';
import { ensureNotDirty, installCakeToolIfNeeded } from './shared';

export async function installCakeRunTaskCommand(
taskName: string,
fileName: string,
settings: IExtensionSettings
settings: IExtensionSettings,
context: ExtensionContext
) {
await ensureNotDirty(fileName);
await installCakeToolIfNeeded(settings);
await installCakeToolIfNeeded(settings, context);

let buildCommand = getPlatformSettingsValue(settings.taskRunner.launchCommand);
buildCommand = `${buildCommand} \"${fileName}\" --target=\"${taskName}\" --verbosity=${settings.taskRunner.verbosity}`;
Expand Down
21 changes: 9 additions & 12 deletions src/codeLens/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { workspace } from 'vscode';
import { ExtensionContext, workspace } from 'vscode';
import { CakeTool } from '../debug/cakeTool';
import { IExtensionSettings } from '../extensionSettings';
import { logError, logInfo } from '../shared/log';
Expand All @@ -21,18 +21,15 @@ export async function ensureNotDirty(fileName: string) : Promise<void> {
logInfo("Saved file before running task...", true);
}

export async function installCakeToolIfNeeded(settings: IExtensionSettings) {
export async function installCakeToolIfNeeded(settings: IExtensionSettings, context: ExtensionContext) {
if(settings.codeLens.installNetTool) {
const cakeTool = new CakeTool();
const isInstalled = await cakeTool.isInstalled();
if(!isInstalled){
try {
await cakeTool.install();
}
catch (ex) {
logError("Error installing Cake .NET Tool", true);
logError(ex);
}
const cakeTool = new CakeTool(context);
try {
await cakeTool.ensureInstalled();
}
catch (ex) {
logError("Error installing Cake .NET Tool", true);
logError(ex);
}
}
}
20 changes: 7 additions & 13 deletions src/debug/cakeDebugCommand.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { window, workspace } from 'vscode';
import { ExtensionContext, window, workspace } from 'vscode';
import * as fs from 'fs';
import { CakeDebug } from './cakeDebug';
import { CakeTool } from './cakeTool';

export async function installCakeDebugCommand(hideWarning?: boolean): Promise<boolean> {
export async function installCakeDebugCommand(context: ExtensionContext, hideWarning?: boolean): Promise<boolean> {
// Check if there is an open folder in workspace
if (workspace.rootPath === undefined) {
window.showErrorMessage('You have not yet opened a folder.');
Expand All @@ -20,7 +20,7 @@ export async function installCakeDebugCommand(hideWarning?: boolean): Promise<bo
}

const isCakeTool = selection === 'Cake.Tool';
const result = await (isCakeTool ? installCakeTool() : installCakeDebug());
const result = await (isCakeTool ? installCakeTool(context) : installCakeDebug());
const messages = {
advice: isCakeTool ?
'Cake Debug Dependencies correctly installed globally.' :
Expand Down Expand Up @@ -64,14 +64,8 @@ export async function installCakeDebug(): Promise<IInstallResult> {
return { installed: result, advice: true };
}

async function installCakeTool(): Promise<IInstallResult> {
const tool = new CakeTool();

const alreadyInstalled = await tool.isInstalled();
if(alreadyInstalled){
return { installed: true, advice: false };
}

const result = await tool.install();
return { installed: result, advice: true };
async function installCakeTool(context: ExtensionContext): Promise<IInstallResult> {
const tool = new CakeTool(context);
const installationModified = await tool.ensureInstalled();
return { installed: true, advice: installationModified };
}
121 changes: 111 additions & 10 deletions src/debug/cakeTool.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,56 @@
import { spawn } from 'child_process';
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
import { window, Memento, ExtensionContext } from 'vscode';
import { Version } from '../shared/version';

export class CakeTool {

public isInstalled(): Thenable<boolean> {

private static readonly skipVersionKey = "cake.tool.skipversion";
private memento: Memento;

constructor(context: ExtensionContext) {
this.memento = context.workspaceState;
}

private getCakeVersionFromProc(proc: ChildProcessWithoutNullStreams): Promise<Version|null> {
return new Promise((resolve, reject) => {
// TODO: Do we need to check the version?! Update it?!
const proc = spawn('dotnet', ['tool', 'list', '--global']);
let found = false;

const regex = new RegExp(/^cake\.tool\s+([\d\.]+(-\S+)?)/im); // https://regex101.com/r/nC8uxu/2
let ver: Version|null = null;
proc.on('error', (error) => {
reject(error);
});

proc.stdout.on('data', (data: Buffer) => {
if(found) { return; }
if(ver !== null){
return;
}
const txt = data.toString();
found = txt.toLowerCase().indexOf('cake.tool') > -1;
const match = regex.exec(txt);
if(match) {
ver = Version.parse(match[1])
}
});

proc.on('close', () => {
resolve(found);
resolve(ver);
});
});
}

public async getAvailableVersion(): Promise<Version|null> {
const proc = spawn('dotnet', ['tool', 'search', 'cake.tool']);
const ver = await this.getCakeVersionFromProc(proc);
return ver;
}

/**
* returns the currently installed version, or null if no version is installed.
*/
public async getInstalledVersion(): Promise<Version|null> {
const proc = spawn('dotnet', ['tool', 'list', '--global']);
const ver = await this.getCakeVersionFromProc(proc);
return ver;
}

public install(): Thenable<boolean> {
return new Promise((resolve, reject) => {
const proc = spawn('dotnet', ['tool', 'install', 'Cake.Tool', '--global']);
Expand All @@ -37,4 +64,78 @@ export class CakeTool {
});
});
}

public update(): Thenable<boolean> {
return new Promise((resolve, reject) => {
const proc = spawn('dotnet', ['tool', 'update', 'Cake.Tool', '--global']);

proc.on('error', (error) => {
reject(error);
});

proc.on('close', () => {
resolve(true);
});
});
}

/**
* ensures Cake.Tool is installed,
* asking for an update, if a newer version is available.
* @returns `true`, if Cake.Tool was actively installed or updated. `false` if Cake.Tool was already installed and up-to-date.
*/
public async ensureInstalled(): Promise<boolean> {
const installedVersion = await this.getInstalledVersion();

if(installedVersion === null) {
await this.install();
return true;
}

const availableVersion = await this.getAvailableVersion();
if(availableVersion === null) {
// cake.tool is installed, but we were unable to detect if it's the newest version
// probably ok..
return false;
}

if(installedVersion.greaterThan(availableVersion, true)) {
return false;
}

// ask for updates or skip
if(await this.shouldSkipVersionUpdate(availableVersion)) {
return false;
}

const answers = {
yes: 'Yes',
no: 'No',
notThisVersion: 'No, and do not ask again for this version.'
}

const selection = await window.showQuickPick([answers.yes, answers.no, answers.notThisVersion], {
placeHolder: `Cake.Tool version ${availableVersion.toString()} is available. Update now?`
});

if(selection !== answers.yes) {
if(selection === answers.notThisVersion){
await this.storeVersionToSkip(availableVersion);
}

return false;
}

await this.update();
return true;
}

private async shouldSkipVersionUpdate(v: Version) : Promise<boolean> {
const verToSkip = await this.memento.get<string>(CakeTool.skipVersionKey);
return v.toString() === verToSkip;
}

private async storeVersionToSkip(v: Version) : Promise<void> {
await this.memento.update(CakeTool.skipVersionKey, v.toString());
}
}
Loading